BOOL CCapDownload::launch()
{
	CExecCommand cmProcess;
	CString csCmd;

	if (m_csDownloadOn == _T("0"))
	{
		m_pLogger->log(LOG_PRIORITY_DEBUG, _T("DOWNLOAD => Download disabled by server"));
		return TRUE;
	}
	// Launch download tool with agent provided command line args
	csCmd.Format(_T("\"%s\\download.exe\" %s"), getInstallFolder(), AfxGetApp()->m_lpCmdLine);
	if (cmProcess.execNoWait(csCmd, getDataFolder()) != EXEC_SUCCESSFULL)
	{
		m_pLogger->log(LOG_PRIORITY_ERROR, _T("DOWNLOAD => Can't create OCS Inventory NG Download process (%s)"), cmProcess.getOutput());
		return FALSE;
	}
	m_pLogger->log(LOG_PRIORITY_NOTICE, _T("DOWNLOAD => Download and setup tool successfully started"));
	return TRUE;
}
UINT CPackage::executePostCmd( UINT uCommandTimeOut)
{
	CLog *pLog = getOcsLogger();
	CExecCommand cmProcess;
	CString csBuffer;
	HANDLE hToken; 
	TOKEN_PRIVILEGES tkp; 

	// check if there is post command to execute
	if (m_csPostCmd.IsEmpty())
	{
		pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => No post execution command provided for package <%s>"), m_csID);
		return TRUE;
	}
	// Check if post command is REBOOT
	if (m_csPostCmd == OCS_DOWNLOAD_POST_CMD_REBOOT)
	{
		pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Executing post execution command <%s> for package <%s>"), m_csPostCmd, m_csID);
		// Request ability to restart computer
		if (!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unable to request Reboot privilege for package <%s>: %s"), m_csID, LookupError( GetLastError()));
			return FALSE;
		}
		if (!LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid)) 
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unable to request Reboot privilege for package <%s>: %s"), m_csID, LookupError( GetLastError()));
			return FALSE;
		}
		tkp.PrivilegeCount = 1; 
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
		if (!AdjustTokenPrivileges( hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unable to request Reboot privilege for package <%s>: %s"), m_csID, LookupError( GetLastError()));
			return FALSE;
		}
		// Initiate a planned restart to perform application installation.
		if (!InitiateSystemShutdownEx( NULL, _T( "OCS Inventory NG must REBOOT your system after package setup"), 
										uCommandTimeOut, TRUE, TRUE,
										SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED))
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unable to initiate System Reboot after package <%s> execution: %s"), m_csID, LookupError( GetLastError()));
			return FALSE;
		}
		return TRUE;
	}
	// Check if post command is SHUTDOWN
	if (m_csPostCmd == OCS_DOWNLOAD_POST_CMD_SHUTDOWN)
	{
		pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Executing post execution command <%s> for package <%s>"), m_csPostCmd, m_csID);
		// Request ability to shutdown computer
		if (!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unable to request Shutdown privilege for package <%s>: %s"), m_csID, LookupError( GetLastError()));
			return FALSE;
		}
		if (!LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid)) 
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unable to request Shutdown privilege for package <%s>: %s"), m_csID, LookupError( GetLastError()));
			return FALSE;
		}
		tkp.PrivilegeCount = 1; 
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
		if (!AdjustTokenPrivileges( hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unable to request Shutdown privilege for package <%s>: %s"), m_csID, LookupError( GetLastError()));
			return FALSE;
		}
		// Initiate a planned shutdown to perform application installation.
		if (!InitiateSystemShutdownEx( NULL, _T( "OCS Inventory NG must SHUTDOWN your system after package setup"),
										uCommandTimeOut, TRUE, FALSE,
										SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED))
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unable to initiate System Shutdown after package <%s> execution: %s"), m_csID, LookupError( GetLastError()));
			return FALSE;
		}
		return TRUE;
	}
	// Execute default post command
	pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Executing post execution command <%s> for package <%s>"), m_csPostCmd, m_csID);
	// Set command time out in milliseconds
	cmProcess.setTimeout( uCommandTimeOut * 60 * 1000);
	// Execute command and wait only for main process to terminate
	switch (cmProcess.execWait( m_csPostCmd, m_csPath))
	{
	case EXEC_ERROR_START_COMMAND:
		pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to execute post execution command <%s> for package <%s> (%s)"), m_csPostCmd, m_csID, cmProcess.getOutput());
		setDone( ERR_EXECUTE);
		return FALSE;
	case EXEC_ERROR_WAIT_COMMAND:
		pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to get post execution command <%s> result code for package <%s> (%s)"), m_csPostCmd, m_csID, cmProcess.getOutput());
		csBuffer = ERR_EXECUTE_NO_EXIT_CODE;
		return FALSE;
	case EXEC_ERROR_TIMEOUT_COMMAND:
		pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Post execution command <%s> execution reached timeout (%s)"), m_csPostCmd, cmProcess.getOutput());
		csBuffer = ERR_EXECUTE_TIMEOUT;
		return FALSE;
	default:
		pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Package <%s> post execution command successfully executed. Command exit code is <%d>"), m_csID, cmProcess.getExitValue());
		if (cmProcess.getExitValue() != 0)
			// Command result code is not a success
			csBuffer.Format( _T( "%s%d"), ERR_EXIT_CODE, cmProcess.getExitValue());
		else
			csBuffer = CODE_SUCCESS;
		break;
	}
	return TRUE;
}
UINT CPackage::execute( UINT uCommandTimeOut)
{
	CLog *pLog = getOcsLogger();
	CExecCommand cmProcess;
	CString csBuffer;
	UINT	uTry;

	// Check signature before executing package
	if (!checkSignature())
	{
		pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed verifying signature for Package <%s>"), m_csID);
		setDone( ERR_BAD_DIGEST);
		return FALSE;
	}
	// Check if package not crashing all time
	if (!getExecTry( &uTry))
		// Assuming first execution try
		uTry = 0;
	uTry++;
	if (uTry > MAX_ERROR_COUNT)
	{
		pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Max try count (%u) reached while executing Package <%s>"), uTry, m_csID);
		setDone( ERR_EXECUTE_TOO_MANY_TRY);
		return FALSE;
	}
	else
		setExecTry( uTry);
	
	if (m_csAction == OCS_DOWNLOAD_ACTION_LAUNCH)
	{
		// We need to wait for all threads/processes started
		// First, extrac build.zip to tmp folder
		if (!directoryCreate( m_csPath) || !unZip())
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to unzip package <%s> to folder <%s>"), m_csID, m_csPath);
			setDone( ERR_UNZIP);
			return FALSE;
		}
		pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Launching command <%s> for package <%s> on <%s>"), m_csCommand, m_csID, CTime::GetCurrentTime().Format( _T( "%#c")));
		if (m_csCommand.IsEmpty())
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => No command provided for <%s> action of package <%s>"), OCS_DOWNLOAD_ACTION_LAUNCH, m_csID);
			setDone( ERR_BAD_PARAM);
			return FALSE;
		}
		// Set command time out in milliseconds
		cmProcess.setTimeout( uCommandTimeOut * 60 * 1000);
		// Execute command and wait for all childs to terminate
		switch (cmProcess.execWaitForAllChilds( m_csCommand, m_csPath))
		{
		case EXEC_ERROR_START_COMMAND:
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to launch command <%s> for package <%s> (%s)"), m_csCommand, m_csID, cmProcess.getOutput());
			setDone( ERR_EXECUTE);
			return FALSE;
		case EXEC_ERROR_WAIT_COMMAND:
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to get command <%s> result code for package <%s> (%s)"), m_csCommand, m_csID, cmProcess.getOutput());
			csBuffer = ERR_EXECUTE_NO_EXIT_CODE;
			break;
		case EXEC_ERROR_TIMEOUT_COMMAND:
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Command <%s> execution reached timeout on <%s> (%s)"), m_csCommand, CTime::GetCurrentTime().Format( _T( "%#c")), cmProcess.getOutput());
			csBuffer = ERR_EXECUTE_TIMEOUT;
			break;
		default:
			isExecSuccessful( cmProcess.getExitValue(), csBuffer);
			pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Package <%s> successfully launched. Command exit code is <%d>. Package return code is <%s>"), m_csID, cmProcess.getExitValue(), csBuffer);
			break;
		}
		setDone( csBuffer);
		return TRUE;
	}
	if (m_csAction == OCS_DOWNLOAD_ACTION_EXECUTE)
	{
		// We only need to wait for cmmand result
		// First, extrac build.zip to tmp folder
		if (!directoryCreate( m_csPath) || !unZip())
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to unzip package <%s> to folder <%s>"), m_csID, m_csPath);
			setDone( ERR_UNZIP);
			return FALSE;
		}
		pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Executing command <%s> for package <%s> on <%s>"), m_csCommand, m_csID, CTime::GetCurrentTime().Format( _T( "%#c")));
		if (m_csCommand.IsEmpty())
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => No command provided for <%s> action of package <%s>"), OCS_DOWNLOAD_ACTION_EXECUTE, m_csID);
			setDone( ERR_BAD_PARAM);
			return FALSE;
		}
		// Set command time out in milliseconds
		cmProcess.setTimeout( uCommandTimeOut * 60 * 1000);
		// Execute command and wait only for main process to terminate
		switch (cmProcess.execWait( m_csCommand, m_csPath))
		{
		case EXEC_ERROR_START_COMMAND:
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to execute command <%s> for package <%s> (%s)"), m_csCommand, m_csID, cmProcess.getOutput());
			setDone( ERR_EXECUTE);
			return FALSE;
		case EXEC_ERROR_WAIT_COMMAND:
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to get command <%s> result code for package <%s> (%s)"), m_csCommand, m_csID, cmProcess.getOutput());
			csBuffer = ERR_EXECUTE_NO_EXIT_CODE;
			break;
		case EXEC_ERROR_TIMEOUT_COMMAND:
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Command <%s> execution reached timeout on <%s> (%s)"), m_csCommand, CTime::GetCurrentTime().Format( _T( "%#c")), cmProcess.getOutput());
			csBuffer = ERR_EXECUTE_TIMEOUT;
			break;
		default:
			isExecSuccessful( cmProcess.getExitValue(), csBuffer);
			pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Package <%s> successfully executed. Command exit code is <%d>. Package return code is <%s>"), m_csID, cmProcess.getExitValue(), csBuffer);
		}
		setDone( csBuffer, GetUnicodeFromAnsi( cmProcess.getOutput()));
		return TRUE;
	}
	if (m_csAction == OCS_DOWNLOAD_ACTION_STORE)
	{
		// We just want to unzip data to specified folder
		pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Unzipping data to folder <%s> for package <%s> on <%s>"), m_csPath, m_csID, CTime::GetCurrentTime().Format( _T( "%#c")));
		if (m_csPath.IsEmpty())
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => No path provided for <%s> action of package <%s>"), OCS_DOWNLOAD_ACTION_STORE, m_csID);
			setDone( ERR_BAD_PARAM);
			return FALSE;
		}
		if (!directoryCreate( m_csPath) || !unZip())
		{
			pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Failed to unzip package <%s> to folder <%s>"), m_csID, m_csPath);
			setDone( ERR_UNZIP);
			return FALSE;
		}
		pLog->log( LOG_PRIORITY_DEBUG, _T( "PACKAGE => Package <%s> successfully stored to folder <%s>"), m_csID, m_csPath);
		setDone( CODE_SUCCESS);
		return TRUE;
	}
	// Unknown action
	pLog->log( LOG_PRIORITY_WARNING, _T( "PACKAGE => Unknown action <%s> for package <%s>"), m_csAction, m_csID);
	setDone( ERR_BAD_PARAM);
	return FALSE;
}