/*****************************************************************************
 * Copyright (C) Gemalto M2M GmbH
 *****************************************************************************
 * Project: IMC-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules RD SW A2
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RilDrv/FirmwareUpdate.cpp $
 * $Revision: /main/ms-d/25 $
 *     $Date: 2014-02-06 14:30:16 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 5.0
 *****************************************************************************
 * Description:
 *  Gemalto IMC RIL
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RilDrv/FirmwareUpdate.cpp$ 
 * 
 * /main/ms-d/25   2014-02-06 14:30:16   pmackent 
 * Case insensitive module type check for firmware update (IPIS100094615)
 *
 * /main/ms-d/24   2013-07-23 13:21:31   pmackent
 * Ensure character set setting on autostart config
 *
 * /main/ms-d/23   2013-07-01 11:18:59   pmackent
 * Ensure to erase blocks only once after firmware update
 *
 * /main/ms-d/22   2013-06-27 16:00:12   pmackent
 * Adaptions for EHS5 Rel1->Rel2 update
 *
 * /main/ms-d/21   2013-04-22 16:12:13   pmackent
 * Work on workarounds for AT+COPS/<AcT> and AT^SJDL/ATE
 *
 * /main/ms-d/20   2013-04-05 09:58:48   pmackent
 * Remove unused variable
 *
 * /main/ms-d/19   2013-04-05 09:53:36   pmackent
 * Finish EHS5 Java midlet update
 * Add RHA-API for bootloader pin on EHS5
 *
 * /main/ms-d/18   2013-03-26 10:17:40   pmackent
 * Remove compiler warnings in CE6
 *
 * /main/ms-d/17   2013-03-15 14:09:05   pmackent
 * Start introducing Java update for EHS5
 *
 * /main/ms-d/16   2013-03-05 11:33:36   pmackent
 * Handle ^SYSSTART URC for EHS5 Rel2
 *
 * /main/ms-d/15   2013-02-14 15:18:00   pmackent
 * Fix build error on advanced notifications build option
 *
 * /main/ms-d/14   2012-12-13 10:54:09   pmackent
 * Added additional string copy function to avoid unnecessary compiler warning
 *
 * /main/ms-d/13   2012-12-13 10:09:00   pmackent
 * Removed unused variables
 *
 * /main/ms-d/12   2012-12-07 13:40:21   pmackent
 * Chage default value of "FWUpdateCheckModuleType"
 *
 * /main/ms-d/11   2012-12-07 11:36:02   pmackent
 * Check module type of firmware file (IPIS100083958)
 *
 * /main/ms-d/10   2012-11-27 11:49:23   pmackent
 * Remove CE6 warnings
 *
 * /main/ms-d/9   2012-11-26 15:21:29   pmackent
 * Adapt firmware update process for EHS5
 *
 * /main/ms-d/8   2012-10-24 11:38:23   pmackent
 * Configure delay before start firmware update
 *
 * /main/ms-d/7   2011-10-17 11:32:41   ctna0256
 * Remove case sensitivity for firmware file name check
 *
 * /main/ms-d/6   2011-10-11 14:21:03   ctna0256
 * Reg Key to disable firmware update
 *
 * /main/ms-d/5   2011-09-29 13:08:24   ctna0256
 * Wait for shutdown after update
 *
 * /main/ms-d/4   2011-09-26 13:34:30   ctna0256
 * Comply with CE6 warning level 4
 *
 * /main/ms-d/3   2011-09-09 14:17:46   ctna0256
 * New notifications for audio/firmware update (IPIS100074854)
 *
 * /main/ms-d/2   2011-03-09 14:24:40   ctna0256
 * Run code analysis on Windows CE7
 *
 * /main/ms-d/1   2010-11-26 10:12:01   ctna0256
 * Introducing firmware update for PH8
 *
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2010 Gemalto M2M GmbH
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

#include "precomp.h"
#include <stdio.h>
#include <malloc.h>

#ifndef _PREFAST_
#pragma warning(disable: 4068)
#endif

// The constants of the firmware update process depend on the chipset n use.
static DWORD s_iFWUConstSet = 0;

// EHS5 only: set to TRUE, if a firmware update has been performed. This might
// require erasing the blocks first thing after reboot.
static BOOL s_fEraseBlocks = FALSE;

//////////////////////////////////////////////////////////////////////////////
//
// Functions from CRilHandle, related to firmware update.
//
//////////////////////////////////////////////////////////////////////////////

//
// Get timeouts and number of retries for opening USB ports. There are special
// timeout values needed for the first start of an EHS5 after firmware update.
//
void CRilHandle::GetPortOpenTimeouts(DWORD *pdwMaxOpenAttempts, DWORD *pdwOpenTimeout) const
{
    *pdwMaxOpenAttempts = DEFAULT_PORT_RETRIES;
    *pdwOpenTimeout = DEFAULT_PORT_TIMEOUT;

    if (s_fEraseBlocks) {
        // EHS5: Now the module will erase its blocks to build the new structure
        // after firmware update. This may take some time.
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Extended open timeouts after firmware update.\r\n")));
        *pdwOpenTimeout = DEFAULT_PORT_TIMEOUT;
        *pdwMaxOpenAttempts = REBUILD_FFS_TIMEOUT / DEFAULT_PORT_TIMEOUT;
    }
    else {
        // Get default timeouts from the registry.
        if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("MaxOpenAttempts"), pdwMaxOpenAttempts)) {
            *pdwMaxOpenAttempts = DEFAULT_PORT_RETRIES;
        }
        if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("OpenTimeout"), pdwOpenTimeout)) {
            *pdwOpenTimeout = DEFAULT_PORT_TIMEOUT;
        }
    }
}

//
// This function checks, if there is a firmware file available and compares its version
// with the current version. It checks not only the revision but also the A-revision.
// Supported firmware file formats: *.USF and *.UUSF
//
// Format of the firmware file name:
//     <Name>_R<Revision>_A<A-Revision>.{USF|UUSF}
//  <Name>: name of the module or free text (key "FWUpdateCheckModuleType")
//  <Revision>: Revision number like the output of ATI
//  <A-Revision>: A-Revision number like the output of ATI1
//  Example: PH8_R00.380_A01.000.00.USF
//
// Parameter:
//      bForceDownload [in]: if set to TRUE, the RIL won't check the current version and start download directly.
//      pbNeedRestart [out]: is set to TRUE if a restart of the module is now necessary
//
// Return: TRUE: latest firmware is already present, no further action necessary.
//         FALSE: shutdown necessary, either because of an error (pbNeedRestart == FALSE), or if restart is needed (pbNeedRestart == TRUE)
//
BOOL CRilHandle::TestForValidFirmware(COM_PORT_TYPE PortType, BOOL bForceDownload, BOOL *pbNeedRestart)
{
    BOOL fRet = TRUE;
    BOOL fFirmwareFileFound = FALSE;
    WCHAR wszSearchPath[MAX_PATH];
    WCHAR wszFileName[MAX_PATH];
    DWORD dwDownloadFail = 0;
    DWORD dwDownloadDisable = 0;

    *pbNeedRestart = FALSE;

    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("LastDownloadFailed"), &dwDownloadFail);
    if (dwDownloadFail > MAX_FIRMWARE_DOWNLOAD_ATTEMPTS) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Too many firmware download attempts.\r\n")));
        goto Error;
    }
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FirmwareDownloadDisable"), &dwDownloadDisable);
    if (dwDownloadDisable == 1) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Firmware download disabled.\r\n")));
        goto Error;
    }
    memset(wszSearchPath, 0, sizeof(wszSearchPath));
    memset(wszFileName, 0, sizeof(wszFileName));
    if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DefaultFirmwareSearchPath"), wszSearchPath, MAX_PATH)) {
        fFirmwareFileFound = GetConfigFilename(wszFileName, MAX_PATH, L"*.usf", wszSearchPath);
        if (!fFirmwareFileFound)
            fFirmwareFileFound = GetConfigFilename(wszFileName, MAX_PATH, L"*.uusf", wszSearchPath);
        if (fFirmwareFileFound)
        {
            BOOL fDoUpdate = TRUE;

            if (!bForceDownload)
                fDoUpdate = CompareFirmwareFileVersion(PortType, wszFileName);
            if (fDoUpdate) {
                CFirmwareUpdate *pUpdate;

                pUpdate = new CFirmwareUpdate;
                if (pUpdate == NULL)
                    goto Error;

                if (bForceDownload)
                    Sleep(WAIT_BEFORE_START_BOOTLOADER);     // The bootloader mode is used, there is a pause necessary
                else
                    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Firmware file with different version available.\r\n")));

                // Set registry key for unsuccessful download. This is done before the update is started, because
                // the download might be interupted by a complete powerloss of the device, so the RIL won't be
                // able to set this key after the PerformFirmwareUpdate() returned. If the update is successful, the
                // RIL will set this key to 0.
                (void)SetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("LastDownloadFailed"), dwDownloadFail + 1);

                // Perform firmware download
                if (!pUpdate->PerformFirmwareUpdate(this, PortType, wszFileName, bForceDownload)) {
                    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Unsuccessfull update attempt.\r\n")));
                }
                else {
                    // Firmware update succeeded, log success in registry.
                    (void)SetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("LastDownloadFailed"), 0);
                    (void)SetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("LastDownloadFile"), wszFileName);
                }
                Sleep(WAIT_AFTER_FIRMWARE_UPDATE);
                *pbNeedRestart = TRUE;
                fRet = FALSE;
                delete pUpdate;
            }
        }
		else
		{
			RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: usr file not found! \r\n")));
		}
    }
Error:
    return fRet;
}

//
// Checks, if a firmware file has to be loaded into the module.
// See description of function TestForValidFirmware() on how the
// filename of the firmware file has to be formated.
//
// Parameters:
//      wszFileName [in]: firmware file (full path name)
//
// Return value: TRUE, if a firmware update is necessary
BOOL CRilHandle::CompareFirmwareFileVersion(COM_PORT_TYPE PortType, WCHAR *wszFileName)
{
    DWORD dwTimeout;
    WCHAR wszLastFirmwareFile[MAX_PATH];
    WCHAR wszFileNameUpper[MAX_PATH];
    BOOL fNewVersion = FALSE;
    char szResponse[MAX_ATCMD_LEN];
    char *pszRevision = NULL;
    char *pszARevision = NULL;

    // To make the comparision case insensitive, use upper case only.
    (void)wcsncpy(wszFileNameUpper, wszFileName, MAX_PATH);
    wszFileNameUpper[MAX_PATH - 1] = 0;
    (void)_wcsupr(wszFileNameUpper);

    // First check, if the given file was already laoded into the module.
    if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("LastDownloadFile"), wszLastFirmwareFile, MAX_PATH)) {
        if (wcscmp(wszLastFirmwareFile, wszFileNameUpper) == 0) {
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Firmware file already loaded into module.\r\n")));
            goto Error;
        }
    }

    // Check full module version (revision and a-revision).
    dwTimeout = GetPreMuxInitTimeout();
    memset(szResponse, 0, sizeof(szResponse));
    if (!ExSendATCmdGetRsp(PortType, "ATI1\r", szResponse, sizeof(szResponse), dwTimeout, 0)) {
      goto Error;
    }

    pszRevision = strstr(szResponse, "REVISION");
    pszARevision = strstr(szResponse, "A-REVISION");
    if (pszARevision == NULL) {
        // With the EHS5 the A-Revision is not always availabel. Use "00.000.00" for
        // missing A-Revision.
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Cannot get A-Revision, assume \"00.000.00\".\r\n")));
        memset(szResponse, 0, sizeof(szResponse));
        if (!ExSendATCmdGetRsp(PortType, "ATI\r", szResponse, sizeof(szResponse), dwTimeout, 0)) {
          goto Error;
        }
        pszRevision = strstr(szResponse, "REVISION");
        pszARevision = "A-REVISION 00.000.00";
    }
    if (pszRevision != NULL && pszARevision != NULL) {
        WCHAR wszRevString[MAX_PATH];

        (void)_snwprintfz(wszRevString, MAX_PATH, L"_R%.6S_A%.9S", pszRevision+9, pszARevision+11);
        if (wcsstr(wszFileNameUpper, wszRevString) == NULL)
            fNewVersion = TRUE;
    }
    if (fNewVersion) {
        DWORD dwCheckModuleType = 0;

        // Firmware for update found. Now check, if this firmware file is really
        // for the correct module type. This check is optional.
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FWUpdateCheckModuleType"), &dwCheckModuleType);
        if (dwCheckModuleType == 1) {
            char szModuleType[MAX_PATH];
            WCHAR wszModuleType[MAX_PATH];

            fNewVersion = FALSE;
            memset(szResponse, 0, sizeof(szResponse));
            memset(wszModuleType, 0, sizeof(wszModuleType));
            memset(szModuleType, 0, sizeof(szModuleType));
            (void)wcsncpyz(wszModuleType, L"", MAX_PATH);  // Bug in code analyzer of Visual Studio 2005 requires this unnecessary string copy.
            if (!ExSendATCmdGetRsp(PortType, "AT+CGMM\r", szResponse, sizeof(szResponse), GetPreMuxInitTimeout(), 1))
            {
                goto Error;
            }
            if (strstr(szResponse, "ERROR") != NULL) {
                // Bug in PXS8: sometimes the AT+CGMM command doesn't work and
                // must be replaced by AT+GMM.
                memset(szResponse, 0, sizeof(szResponse));
                if (!ExSendATCmdGetRsp(PortType, "AT+GMM\r", szResponse, sizeof(szResponse), GetPreMuxInitTimeout(), 1))
                {
                    goto Error;
                }
            }
            if (strstr(szResponse, "OK\r") != NULL && GetModemTypeFromResponse(szResponse, sizeof(szResponse), szModuleType, MAX_PATH) != MODEMTYPE_UNKNOWN) {
                (void)_snwprintfz(wszModuleType, MAX_PATH, L"%S_", szModuleType);
                // Make upper case for comparision in case module type contains lower case letters.
                (void)_wcsupr(wszModuleType);
            }
            if (wcsstr(wszFileNameUpper, wszModuleType) != NULL && wcslen(wszModuleType) > 0) {
                // Firmware file seems to be for the correct module type.
                fNewVersion = TRUE;
            }
            else {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Firmware file \"%s\" not for current module \"%a\".\r\n"), wszFileName, szModuleType));
            }
        }
    }
Error:
    return fNewVersion;
}

//
// EHS5 specific: after a successfull firmware update it is necessary to ensure
// the integrity of the NV item blocks. New bootloader versions will do that
// automatically, for older versions the RIL must delete the old blocks so that
// the module can rebuild them.
//
// Paramater:
//    pbNeedRestart: will be set to TRUE, if a restart is necessary.
//
// Return value: FALSE, if restart is needed, otherwise TRUE.
//
BOOL CRilHandle::EnsureBlockIntegrity(COM_PORT_TYPE PortType, BOOL *pbNeedRestart)
{
    const char *cszBootLoader = "XMM6260_BOOTLOADER_VERSION_1000_";
    char szResponse[MAX_ATCMD_LEN];
    char *pszTmp;
    BOOL fRet = TRUE;

    // Erasing the blocks is only necessary once ofter firmware update.
    *pbNeedRestart = FALSE;
    if (!s_fEraseBlocks) return TRUE;
    s_fEraseBlocks = FALSE;

    // Check bootloader version. New bootloader versions will do all
    // the block update automatically. Not all firmware versions
    // support this command.
    memset(szResponse, 0, sizeof(szResponse));
    if (!ExSendATCmdGetRsp(PortType, "ATI51\r", szResponse, sizeof(szResponse), GetPreMuxInitTimeout(), 1)) {
        goto Error;
    }
    pszTmp = strstr(szResponse, cszBootLoader);
    if (pszTmp != NULL) {
        // Check boot
        INT iBootloader;

        iBootloader = atoi(pszTmp + strlen(cszBootLoader));
        if (iBootloader >= MIN_V2_BOOTLOADER) return TRUE;
    }

    // This is an old bootloader. The RIL will erase the blocks, so that the
    // module can rebuild them in the new structure. Not all firmware
    // versions support this option.
    memset(szResponse, 0, sizeof(szResponse));
    if (ExSendATCmdGetRsp(PortType, "AT^SBNW=\"NV\",2\r", szResponse, sizeof(szResponse), GetPreMuxInitTimeout(PREMUX_TIMEOUTS_SBNW), 1)) {
        if (strstr(szResponse, "OK") != NULL) {
            // After erasing the blocks the module will reset.
            *pbNeedRestart = TRUE;
            fRet = FALSE;
        }
    }


Error:
    return fRet;
}

//
// Compares file name of Java midlet in file with the one in the module.
// If they don't match or there is no midlet in the module, an update is
// necessary.
//
// Parameters:
// wszJadFileName: name of file in Windows Mobile
// szJavaFileName: name of file in module
//
// Return: TRUE: latest Java midlet is already present, no further action necessary.
//
/*
BOOL CRilHandle::IsJavaMidletUpToDate(WCHAR *wszJadFileName, char *szJavaFileName)
{
    char szJadFileName[MAX_PATH];
    char *pszCmp1, *pszCmp2;

    // No Java midlet in module: update is necessary
    if (strlen(szJavaFileName) == 0) return FALSE;

    // Convert UCS2 parameter to ASCII
    (void)_snprintfz(szJadFileName, MAX_PATH, "%S", wszJadFileName);

    // Extract file name from Windows path (text after last "\")
    pszCmp1 = strrchr(szJadFileName, '\\');
    if (pszCmp1 == NULL) pszCmp1 = szJadFileName;
    else pszCmp1++;

    // Extract file name form module's file path (text after last "/")
    pszCmp2 = strrchr(szJavaFileName, '/');
    if (pszCmp2 == NULL) pszCmp2 = szJavaFileName;
    else pszCmp2++;

    // Compare file names.
    return strcmp(pszCmp1, pszCmp2) == 0;
}
*/
//
// Checks, which Java midlet is currently in the module. If there is also a Java
// file in the file systgem it checks if there is an update necessary.
//
// Parameters:
// PortType [in]: AT channel on which should be used
// pbNeedRestart [out]: Is set to TRUE, if the Java midlet has been
//
// Return: TRUE: latest Java midlet is already present, no further action necessary.
//         FALSE: shutdown necessary, either because of an error (pbNeedRestart == FALSE), or if restart is needed (pbNeedRestart == TRUE)
//
BOOL CRilHandle::TestForValidJavaMidlet(COM_PORT_TYPE PortType, BOOL *pbNeedRestart)
{
    CFirmwareUpdate *pUpdate = NULL;
    BOOL fRet = TRUE;
    DWORD dwTimeout;
    char szResponse[MAX_ATCMD_LEN];
    const char *szRsp;
    char szJavaFileName[MAX_ATCMD_LEN];
    char szJavaMidletName[MAX_ATCMD_LEN];
    WCHAR wszSearchPath[MAX_PATH];
    WCHAR wszConfigFileName[MAX_PATH];
    ActionParamList* aplMIDlet = NULL;
    ATCmdList* atCmdList = NULL;

    // If we reached this point, the blocks have been already erased.
    s_fEraseBlocks = FALSE;

    // Check full module version.
    dwTimeout = GetPreMuxInitTimeout();
    memset(szResponse, 0, sizeof(szResponse));
    if (!ExSendATCmdGetRsp(PortType, "AT^SJAM=4\r", szResponse, sizeof(szResponse), dwTimeout, 0)) {
      goto Error;
    }
    szRsp = szResponse;
    // Parse "<prefix>^SJAM: <JavaFileName>,<JavaMidletName>,..."
    if (!ParseRspPrefix(szRsp, szRsp)                   ||
        !MatchStringBeginning(szRsp, "^SJAM:", szRsp)  ||
        !ParseString(szRsp, szJavaFileName, MAX_ATCMD_LEN, szRsp)          ||
        !MatchStringBeginning(szRsp, ",", szRsp)        ||
        !ParseString(szRsp, szJavaMidletName, MAX_ATCMD_LEN, szRsp)) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: no Java midlet in module.\r\n")));
        memset(szJavaFileName, 0, MAX_ATCMD_LEN);
        memset(szJavaMidletName, 0, MAX_ATCMD_LEN);
    }

    if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DefaultFirmwareSearchPath"), wszSearchPath, MAX_PATH)) {
        BOOL fConfigFileFound;
        
        fConfigFileFound = GetConfigFilename(wszConfigFileName, MAX_PATH, L"SWUPConfigurations.cfg", wszSearchPath);
        if (!fConfigFileFound) // No File found for update.
            goto Error;
					
		
		aplMIDlet = (ActionParamList*)malloc(sizeof(ActionParamList));
		if(NULL == aplMIDlet)
		{
			//RILTrace(ZONE_ERROR, "midlet action param list malloc fail");
			RILRetailTraceZone(ZONE_ERROR, (TEXT("midlet action param list malloc fail.\n")));
			return FALSE;
		}
		memset(aplMIDlet, 0, sizeof(ActionParamList));
		aplMIDlet->nAmount = 0;
		aplMIDlet->head = NULL;
		aplMIDlet->tail = NULL;
		
		atCmdList = (ATCmdList*)malloc(sizeof(ATCmdList));
		if(NULL == atCmdList)
        {
			RILRetailTraceZone(ZONE_ERROR, (TEXT("AT cmd list malloc fail.\n")));
			fRet = FALSE;
			goto Error;
		}
		memset(atCmdList, 0, sizeof(atCmdList));
		atCmdList->nAmount = 0;
		atCmdList->head = NULL;
		atCmdList->tail = NULL;
		
		pUpdate = new CFirmwareUpdate;
        if (pUpdate == NULL)
		{
            fRet = FALSE;
			goto Error;
		}	
		pUpdate->OpenConfigurationFile((WCHAR *)wszConfigFileName,aplMIDlet,atCmdList);
		
		ActionParamItem* api = aplMIDlet->head;
		
		ATCmdListItem* atc = atCmdList->head;
		
		while(api != NULL)
		{
			if(api->nOperateType & 7)
			
			{
				if(pUpdate->PerformJavaMidletUpdate(this, PortType, api->strTargetName,api->strOperationParam,api->nOperateType))
				{
					if (RESTART_AFTER_JAVA_UPDATE) 
					{
					*pbNeedRestart = TRUE;
					fRet = FALSE;
					}
				}
				else
				{
					fRet = FALSE;
					goto Error;
				}
			}
			else
			{
			
				if(!pUpdate->TransferFile(this, PortType, api->strTargetName,api->strOperationParam,api->nOperateType))
				{
					return FALSE;
				}
			}
			api = api->next;
		}
		
		while(atc != NULL)
		{
		    char szResponse[MAX_ATCMD_LEN];
			memset(szResponse, 0, sizeof(szResponse));
			if (!this->ExSendATCmdGetRsp(PortType, atc->atCmd, szResponse, sizeof(szResponse), dwTimeout, 0)) {
			    fRet = FALSE;
			    goto Error;
			}
			atc = atc->next;
		}
		
		if (aplMIDlet != NULL) 
		{
		    aplMIDlet = NULL;
		    free(aplMIDlet);
		}
        if (atCmdList != NULL) 
		{
		    free(atCmdList);
			atCmdList = NULL;
		}
			
    }

Error:

    if (pUpdate != NULL) delete pUpdate;
    if (aplMIDlet != NULL) free(aplMIDlet);
    if (atCmdList != NULL) free(atCmdList);
    return fRet;
}


//////////////////////////////////////////////////////////////////////////////
//
// Functions from CFirmwareUpdate class.
//
//////////////////////////////////////////////////////////////////////////////


//
// Performs a firmware update. This function is ported from the gWinSwup application for Windows XP.
//
// Parameters:
//    pRILHandle [in]: handle to RIL
//    PortType [in]: RIL port where to perform update
//    wszFileName [in]: file with USF/UUSF firmware file
//    fNoFirmwareMode [in]: use special mode if no firmware or invalid is present im module (bootloader mode)
//
//  Return: TRUE on success.
//
BOOL CFirmwareUpdate::PerformFirmwareUpdate(CRilHandle *pRILHandle, COM_PORT_TYPE PortType, WCHAR *wszFileName, BOOL fNoFirmwareMode)
{
    CNotificationData* pnd = NULL;
    const char *pszDownloadCommand = "AT^SFDL\r";
    BOOL fSuccess = FALSE;
    char szResponse[MAX_ATCMD_LEN];
    INT iBlock, iBlockMax;          // Number of blocks in firmware file (currenty updated, total number)
    INT iLastProgress = 0;        // Last position of progress bar
    INT iTry, iMaxTry;              // Number of tries (current, maximum)
    BOOL bAbort = FALSE;            // Indicates, the update process had been aborted due to errors
    WORD wBufferLen;
    DWORD dwWaitBeforeStart;
    char szCmd[MAX_ATCMD_LEN];

    // There are different sets of constants depend on the chipset used in the module.
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FWUpdateConstantsSet"), &s_iFWUConstSet);
    dwWaitBeforeStart = WAIT_BEFORE_START;

    // The "wait before start" delay might need to be increased to 4000ms for the AHS3.
    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FWUpdateWaitBeforeStart"), &dwWaitBeforeStart))
        dwWaitBeforeStart = WAIT_BEFORE_START;

    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Starting firmware download.\r\n")));
    m_iPortType = PortType;
    m_hFile = CreateFile(wszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (m_hFile == INVALID_HANDLE_VALUE)
    {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Cannot open %s.\r\n"), wszFileName));
        goto Error;
    }
#ifdef RIL_INDICATE_FIRMWAREUPDATE
    SendTextToMMI(pRILHandle, IDS_INDICATION_FDL_START);
#endif
    pnd = new CNotificationData;
    if (pnd)
    {
        // Send string including terminating '\0'.
        if (pnd->InitFromRealBlob(RIL_NOTIFY_DEVSPECIFIC_FW_UPDATE_START, (void*)wszFileName, (2*wcslen(wszFileName))+sizeof(WCHAR)))
            pRILHandle->BroadcastNotification(pnd);
        else
            delete pnd;
    }

    iBlockMax = CountBlocks();

    iBlock = 0;

    // -----------------------------------------------------------------------------------
    // Everythings prepared, now the update starts
    // -----------------------------------------------------------------------------------
    memset(szResponse, 0, sizeof(szResponse));
    if (fNoFirmwareMode) {
        // If the module is in bootloader-mode you cannot rely, that the module will respond on
        // the download command.
        (void)pRILHandle->ExSendATCommand(PortType, pszDownloadCommand);
    }
    else {
        // Modules with Java: deactivate autostart, otherwise the old Java midlet would
        // start with the new firmware.
        if (FIRMWARE_UPDATE_WITH_JAVA) {
            WCHAR wszPassword[MAX_PATH];

            // The deactivation of the Java midlet might require a password. As default this
            // password is blank in current versions of the EHS5. If a password is needed
            // for future versions, it can be set with this registry key.
            if (!GetRegistrySZ(HKEY_LOCAL_MACHINE, RIL_AUDIO_CONFIG_KEY, TEXT("JavaMidletPassword"), wszPassword, MAX_PATH)) {
                // No password as deault
                wszPassword[0] = 0;
            }
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CSCS=\"GSM\";^SCFG=\"Userware/Autostart\",\"%S\",\"0\"\r", wszPassword);
            (void)pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(), 0);
        }
        if (!pRILHandle->ExSendATCmdGetRsp(PortType, pszDownloadCommand, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(), 0)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Cannot send AT^SFDL.\r\n")));
            goto Error;
        }
    }

    // USB: if we update via USB the module becomes inaccessible for a brief period of time.
    // Usually device drivers like the Windows driver need to be closed for this period.

    // close com port
    (void)g_ComManager.CloseBasePort();
    // wait for download mode after reset
    Sleep(dwWaitBeforeStart);

    // Open serial interface.
    iTry = 0;
    iMaxTry = MAX_START_ACK_TRIES;

    while (iTry < iMaxTry)
    {
        iTry ++;
        if (g_ComManager.OpenBasePort())
        {
            break;
        }
        Sleep(WAIT_AFTER_REOPEN);

        if (iTry >= iMaxTry)  {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Cannot open COM-Port.\r\n")));
            goto Error;
        }
    }

    if (s_iFWUConstSet == 1) {
        // Intel chipset: wait for start acknowledgement.
        for (;;) {
            BYTE bStartAck;
            if (!SerGetchTimeout(&bStartAck, BLOCK_TIMEOUT)) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Timeout waiting for 1st ACK before swup start")));
                goto Error;
            }
            if ((bStartAck != '\r') && (bStartAck != '\n')) {
                if (bStartAck != ANSWER_OK) {
                    WCHAR wszMsg[100];
                    (void)_snwprintfz(wszMsg, 100, L"RilDrv: Received wrong response 0x%02x before swup start", bStartAck);
                    RILRetailTraceZone(ZONE_ERROR, (wszMsg));
                    goto Error;
                }
                else {
                     break;
                }
            }
        }
    }

    // Now send the whole new firmware block by block.
    // For details of this process please refer to the "Firmware Update" application note.
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Firmware download in progress.\r\n")));
    iBlock = 0;
    while (!bAbort && ReadBlock(m_bBuffer, &wBufferLen))
    {
        BOOL    bRetry;
        int     iRetries = 0;

        // Generate progress notification only if it differs from the last one.
        if (iLastProgress != 100 * iBlock / iBlockMax) {
            iLastProgress = 100 * iBlock / iBlockMax;
            pRILHandle->BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_FW_UPDATE_PROGRESS,  iLastProgress);
        }

        while (!bAbort)
        {
            bRetry = FALSE;

            Sleep(WAIT_BEFORE_BLOCK_LEN);
            SerWrite((BYTE *)&wBufferLen, sizeof(WORD));
            Sleep(WAIT_AFTER_BLOCK_LEN);
            SerWrite(m_bBuffer, wBufferLen);

#ifdef RIL_INDICATE_FIRMWAREUPDATE
            SystemIdleTimerReset();
#endif
            while (!bAbort)
            {
                DWORD dwTimeout = BLOCK_TIMEOUT;
                BYTE bAck;

                // The first block might have a special timeout (Intel: erase flash timeout).
                if (iBlock == 0)
                    dwTimeout = ERASE_FLASH_TIMEOUT;

                if (!SerGetchTimeout(&bAck, dwTimeout))
                {
                    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Timeout waiting for response after block no.%d\r\n"), iBlock));
                    bAbort = TRUE;
                }
                else
                {
                    if (bAck == ANSWER_OK)
                        break;
                    else if (bAck == ANSWER_RETRY)
                    {
                        bRetry = TRUE;
                        break;
                    }
                    else if (bAck == ANSWER_BUSY)
                        continue;
                    else
                    {
                        bAbort = TRUE;
                        if (iBlock == 4)   // Error on block 4 usually means: version conflict (downgrades are not possible with gWinswup).
                            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ERROR: fatal response (0x%02x) to block %d, possible version conflict.\r\n"), (int)bAck, iBlock));
                        else if (iBlock == 2)   // Error on block 2 usually means: wrong bootloader (or wrong product release).
                            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ERROR: fatal response (0x%02x) to block %d, possibly wrong bootloader.\r\n"), (int)bAck, iBlock));
                        else
                            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ERROR: unexpected or fatal response (0x%02x) to block %d.\r\n"), (int)bAck, iBlock));
                    }
                }
            }
            if (!bRetry)
                break;

            iRetries++;
            if (iRetries > BLOCK_RETRIES)
            {
                bAbort = TRUE;
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ERROR: too many retries in block %d.\r\n"), iBlock));
            }
        }
        iBlock++;
    }

    if (!bAbort) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Firmware download succeeded.\r\n")));
        fSuccess = TRUE;
    }
Error:
    if (m_hFile != INVALID_HANDLE_VALUE)
        CloseHandle(m_hFile);
    if (fSuccess)
        pRILHandle->BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_FW_UPDATE_PROGRESS,  100);
    pRILHandle->BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_FW_UPDATE_END,  fSuccess ? UPDATE_PROCESS_SUCCESS : UPDATE_PROCESS_ERROR);
#ifdef RIL_INDICATE_FIRMWAREUPDATE
    SendTextToMMI(pRILHandle, fSuccess ? IDS_INDICATION_FDL_END : IDS_INDICATION_FDL_ERROR);
#endif

    if (fSuccess) {
        DWORD dwAutoShutdownTimeout = 5000;
        DWORD dwStartTime = GetTickCount();

        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FWUpdateAutoShutdownTimeout"), &dwAutoShutdownTimeout);

        // After a successful download the radio does some internal reconfiguration
        // and then shuts down automatically. Wait for the auto shutdown before
        // proceed further.
        while (GetTickCount() - dwStartTime < dwAutoShutdownTimeout) {
            if (!RHA_IsRadioPwrOn()) break;
            Sleep(100);
        }
        if (RHA_IsRadioPwrOn()) {
            // Some firmware versions don't shut down automatically after update.
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: module didn't shut down automatically after FW update\r\n")));
            RHA_RadioPwrOff();
        }

        if (s_iFWUConstSet == 1) {
            // EHS5 specific:erase blocks as first action after restart.
            s_fEraseBlocks = TRUE;
        }
    }
    return fSuccess;
}


//
// Reads one byte from module (with timeout).
// Function taken from gWinSwup for Windows XP.
//
BOOL CFirmwareUpdate::SerGetchTimeout(BYTE *pbData, DWORD dwTimeout)
{
    DWORD dwTimeStart;
    BOOL fResult = FALSE;
    DWORD dwBytesRead;

    dwTimeStart = GetTickCount();
    while (!fResult)
    {
        Sleep(WAIT_WAITFORTIMEOUT);
        fResult = DOWNST_READFILE(g_ComManager.GetPortHandle(m_iPortType), pbData, 1, &dwBytesRead);
        if (dwBytesRead == 0)
            fResult = FALSE;
        if (GetTickCount() - dwTimeStart >= dwTimeout)
            break;
    }
    return fResult;
}

//
// Writes bytes to the module.
// Function taken from gWinSwup for Windows XP.
//
DWORD CFirmwareUpdate::SerWrite(const BYTE *pbData, DWORD iNr)
{
    DWORD dwNumBytesWritten;

    DOWNST_WRITEFILE(g_ComManager.GetPortHandle(m_iPortType), pbData, iNr, &dwNumBytesWritten);
    return (WORD)dwNumBytesWritten;
}

//
// Counts the number of blocks in the firmware file.
// Function taken from gWinSwup for Windows XP.
//
INT CFirmwareUpdate::CountBlocks()
{
    DWORD   dwPos;
    int     iBlocks;
    WORD    wLen = 0;

    if (m_hFile == INVALID_HANDLE_VALUE)
        return 0;

    dwPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
    SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN);

    iBlocks = 0;
    while (ReadBlock(m_bBuffer, &wLen))
        iBlocks++;

    SetFilePointer(m_hFile, dwPos, NULL, FILE_BEGIN);

    return iBlocks;
}

//
// Reads a block from the firmware file.
// Function taken from gWinSwup for Windows XP.
//
BOOL CFirmwareUpdate::ReadBlock(BYTE *bBuffer, WORD *wBufferLen)
{
    DWORD dwRead = 0;
    BOOL bRet = FALSE;
    WORD wLen = 0;

    if (m_hFile == INVALID_HANDLE_VALUE)
        return FALSE;

    if (ReadFile(m_hFile, &wLen, 2, &dwRead, NULL))
    {
        if (wLen > BLOCK_SIZE)
        {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("Error: maximum block length exceded %d.\n"), wLen));
            return FALSE;
        }
        if (dwRead != 0)
        {
            if (ReadFile(m_hFile, bBuffer, (DWORD)wLen, &dwRead, NULL))
            {
                if (dwRead == (DWORD)wLen)
                {
                    *wBufferLen = wLen;
                    bRet = TRUE;
                }
                else
                {
                    RILRetailTraceZone(ZONE_ERROR, (TEXT("Warning: unexpected end of file detected %d / %d.\n"), dwRead, wLen));
                }
            }
        }
    }
    return bRet;
}

#ifdef RIL_INDICATE_FIRMWAREUPDATE
//
// Sends text as faked USSD to MMI to allow the user to be informed about the update.
//
// Parameters:
//    pRILHandle [in]: Handle to RIL
//    uiTextID [in]: resource ID of the text to be printed out.
//
// Return value: none
void CFirmwareUpdate::SendTextToMMI(CRilHandle *pRILHandle, UINT uiTextID)
{
    WCHAR wszText[MAX_RESOURCE_STRING_LEN];

    if (LoadString((HINSTANCE)hInstance, uiTextID, wszText, MAX_RESOURCE_STRING_LEN) > 0)
    {
        CNotificationData* pnd = NULL;
        RILSUPSERVICEDATA *prssd;
        UINT cbStruct;

        cbStruct = sizeof(RILSUPSERVICEDATA) + (wcslen(wszText) * sizeof(WCHAR)) + sizeof(WCHAR);
        prssd = (RILSUPSERVICEDATA*)AllocBlob(cbStruct);
        if (prssd != NULL)
        {
            memcpy(prssd->pbData, (BYTE *)wszText, (wcslen(wszText) * sizeof(WCHAR)) + sizeof(WCHAR));
            prssd->dwParams = RIL_PARAM_SSDI_DATA;
            prssd->dwStatus = RIL_SUPSVCDATASTATUS_UNSUPPORTED;
            prssd->dwParams |= RIL_PARAM_SSDI_STATUS;
            prssd->cbSize = cbStruct;
            pnd = new CNotificationData;
            if (pnd)
            {
                if (pnd->InitFromRealBlob(RIL_NOTIFY_SUPSERVICEDATA, (void*)prssd, prssd->cbSize))
                    pRILHandle->BroadcastNotification(pnd);
                else
                    delete pnd;
            }
            FreeBlob(prssd);
        }
    }

    return;
}
#endif

//
// Reads the value of a given property from the JAD file.
//
// Parameters:
// szBufferJad [in]: string whith the whole content of the JAD file
// szProperty [in]: property to query
// szJarValue [out]: buffer to place the value of the property.
// nBuffer [in]: size of szJarValue
//
// Return value: TRUE if property is avalable and have been placed in szJarValue
//
BOOL CFirmwareUpdate::GetJadProperty(const char *szBufferJad, const char *szProperty, char *szJarValue, UINT nBuffer)
{
    const char *pszItem;
    const char *pszEnd;

    memset(szJarValue, 0, nBuffer);

    // Is property defined in JAD file?
    pszItem = strstr(szBufferJad, szProperty);
    if (pszItem == NULL) return FALSE;

    // To to value and skip ofer leading white spaces
    pszItem += strlen(szProperty);
    while (*pszItem == ' ' || *pszItem == '\t') pszItem++;
    if(*pszItem == '\0' || *pszItem == '\r' || *pszItem == '\n') return FALSE;

    // Find end of value (new line)
    // There might be Windows style or Linux style line separators
    pszEnd = strchr(pszItem, '\r');
    if (pszEnd == NULL) pszEnd = strchr(pszItem, '\n');
    if (pszEnd == NULL) return FALSE;

    // Is buffer size of szJarValue sufficient to store value?
    if ((UINT)(pszEnd - pszItem) > nBuffer) return FALSE;

    // Store value in szJarValue.
    strncpy(szJarValue, pszItem, pszEnd - pszItem);
    return TRUE;
}
void skipWhiteSpace(char **p_cur)
{
    if (*p_cur == NULL) return;

    while (**p_cur != '\0' && isspace(**p_cur)) {
        (*p_cur)++;
    }
}

static char* findStrConfig(char *pToken,Values *tValues)
{
    char *newline = NULL;
    // Special case: there might be no value because the parameter is
    // supposed to be set to an empty string. In this case there is a
    // new line character present in the token.
    newline = strchr(pToken, ',');
    if (newline != NULL) *newline = '\0';
    strcpy(tValues->strValue[0],pToken);
    // Reinsert newline character in case it has been temporarily removed.
    if (newline != NULL)
    {
	 *newline = ',';
    }

    pToken = ++newline;

    newline = strchr(pToken, ',');
    if (newline != NULL) *newline = '\0';
    strcpy(tValues->strValue[1],pToken);
    if (newline != NULL)
    {
	 *newline = ',';
    }
    pToken = ++newline;

    newline = strchr(pToken, '\n');
    if (newline != NULL) *newline = '\0';
    strcpy(tValues->strValue[2],pToken);
    // Reinsert newline character in case it has been temporarily removed.
    if (newline != NULL)
    {
	 *newline = '\n';
    }
    if(NULL!=++newline)
    	pToken = newline;
    return pToken;
}
BOOL CFirmwareUpdate::OpenConfigurationFile(const WCHAR *wszConfigFilePath, ActionParamList* aplMIDlet, ATCmdList* atCmdList) {
    
    BYTE *pTmp;
	BYTE *pToken;
	char szCmd[MAX_ATCMD_LEN];
	DWORD dwBytesRead;
	BYTE *buffer = NULL;
    int fileSize;
	HANDLE hFile = INVALID_HANDLE_VALUE;
	BOOL fRet = TRUE;

    Values tValues;
    ActionParamItem* api = NULL;
	ATCmdListItem* atc = NULL;
	
	BOOL bIsMidlet, bIsFile, bIsATCmd = FALSE;
	
	// Read whole file in a buffer.
    hFile = CreateFile(wszConfigFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) 
	{
	    fRet = FALSE;
	    goto Error;
	}
    fileSize = GetFileSize(hFile, NULL);
    if (fileSize == 0) goto Error;
    // Allocate a buffer to hold the complete file plus one additional byte.
    // The addional byte is set to 0, to allow the file to be treated as a
    // string.
    buffer = (BYTE *)AllocBlob(fileSize+1);
    if (buffer == NULL) 
	{ 
	    fRet = FALSE;
	    goto Error;
	}
    memset(buffer, 0, fileSize+1);
    dwBytesRead = 0;
    if(!ReadFile(hFile, buffer, fileSize, &dwBytesRead, NULL) || dwBytesRead != fileSize) 
	{
	    fRet = FALSE;
	    goto Error;
	}
    CloseHandle(hFile);
    hFile = INVALID_HANDLE_VALUE;
	
    pTmp=buffer;
    skipWhiteSpace((char **)&pTmp);
		
    while(((pTmp-buffer)<fileSize)&&(pTmp!=NULL))
	{
	    bIsMidlet = FALSE;
		bIsFile = FALSE;
		bIsATCmd = FALSE;
		
        memset(tValues.strValue,'\0',sizeof(tValues.strValue));
		pToken = (BYTE *)strstr((char *)pTmp, "MIDlet-");
		if (pToken == pTmp) 
		    bIsMidlet = TRUE;
			
		pToken = (BYTE *)strstr((char *)pTmp, "File-");
		if (pToken == pTmp) 
		    bIsFile = TRUE;
			
		pToken = (BYTE *)strstr((char *)pTmp, "AT-");
		if (pToken == pTmp) {
		    bIsATCmd = TRUE;
		}
			
		if(bIsMidlet || bIsFile)
		{
			pToken = (BYTE *)strchr((char *)pTmp,':');
			pToken++;
			pTmp = (BYTE *)findStrConfig((char *)pToken,&tValues);
			if(((pTmp-buffer) < fileSize) && (pTmp != NULL))
			{
				skipWhiteSpace((char **)&pTmp);
			}
			api = (ActionParamItem*)malloc(sizeof(ActionParamItem));
			strcpy(api->strTargetName, tValues.strValue[0]);
			strcpy(api->strOperationCmd, tValues.strValue[1]);
			strcpy(api->strOperationParam, tValues.strValue[2]);
				
			if(bIsFile)
			{
				if(strstr(api->strOperationCmd, OPERATION_CMD_FCREATE))
				{
					api->nOperateType = OPERATION_FILE_CREATE;
				}
				if(strstr(api->strOperationCmd, OPERATION_CMD_FSAVE))
				{
					api->nOperateType = OPERATION_FILE_SAVE;
				}
				if(strstr(api->strOperationCmd, OPERATION_CMD_FDELETE))
				{
					api->nOperateType = OPERATION_FILE_DELETE;
				}
			}
			if(bIsMidlet)
			{
				if(strstr(api->strOperationCmd, OPERATION_CMD_INSTALL))
				{
					api->nOperateType = OPERATION_MIDLET_INSTALL;
				}
				if(strstr(api->strOperationCmd, OPERATION_CMD_DEPLOY))
				{
					api->nOperateType = OPERATION_MIDLET_DEPLOY;
				}
				if(strstr(api->strOperationCmd, OPERATION_CMD_SAVE))
				{
					api->nOperateType = OPERATION_MIDLET_SAVE;
				}
			}
			api->next = NULL;
			if(NULL == aplMIDlet->tail)
			{
				aplMIDlet->head = aplMIDlet->tail = api;
			}
			else 
			{
				aplMIDlet->tail->next = api;
				aplMIDlet->tail = api;
			}
		
		}
		
		else if(bIsATCmd)
		{		
		    char *newline = NULL;
			pToken = (BYTE *)strchr((char *)pTmp,':');
			pToken++;
			
			newline = strchr((char *)pToken, '#');
            if (newline != NULL) 
			    *newline = '\0';
            strcpy(szCmd,(char *)pToken);
			
			if (newline != NULL) 
			    *newline = '#';
			
			//Add '\r' at the end of the command.
			newline = strchr(szCmd, '\0');
			*newline = '\r';
			newline++;
			*newline = '\0';
			
			pToken = (BYTE *)strchr((char *)pTmp,'\n');
			
			pTmp = pToken;
			pToken++;
			if(NULL!=pToken)
    	        pTmp = pToken;
    
            atc = (ATCmdListItem*)malloc(sizeof(ATCmdListItem));
			strcpy(atc->atCmd, szCmd);
						
			atc->next = NULL;
			if(NULL == atCmdList->tail)
			{
				atCmdList->head = atCmdList->tail = atc;
			}
			else 
			{
				atCmdList->tail->next = atc;
				atCmdList->tail = atc;
			}	
		}
		
		else
		{
    		pToken = (BYTE *)strchr((char *)pTmp,'\n');
			pTmp = pToken;
			pToken++;
			if(NULL!=pToken)
    	        pTmp = pToken;
		}
	}

Error:
	if (buffer != NULL) FreeBlob(buffer);
    if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
	
    return fRet;
}

//
// Performs the update of the Java midlet. This process invloves:
// Deleting old Java midlet on module
// Deactivate and uninstall old Java midlet
// Transfer new Java midlet to the module
// Install new Java midlet
// Activate autostart for the Java midlet
//
// Parameters:
// pRILHandle [in]: handle to RIL
// PortType [in]: AT port to use for AT commands
// wszJadFileName [in]: File name of new JAD file in Windows
// wszJarFileName [in]: File name of new JAR file in Windows
// szCurrentJavaFileName [in]: File name of currently used Java midlet in module
//
// Return value: TRUE, if the update process has been performed successfully
//
//BOOL CFirmwareUpdate::PerformJavaMidletUpdate(CRilHandle *pRILHandle, COM_PORT_TYPE PortType, WCHAR *wszJadFileName, WCHAR *wszJarFileName, char *szCurrentJavaFileName)
BOOL CFirmwareUpdate::PerformJavaMidletUpdate(CRilHandle *pRILHandle, COM_PORT_TYPE PortType, char *szJadFileName, char *strOperationParam, int operationType)
{
    CNotificationData *pnd;
    const char *cszCRC = "JDL CRC32 0x";
    BOOL fRet = FALSE;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    BYTE *bBufferJar = NULL;
    BYTE *bBufferJad = NULL;
    UINT nFileSizeJar, nFileSizeJad;
    DWORD dwBytesRead;
    DWORD dwTimeout = pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_SBNW);
    char szJarURL[MAX_PATH];
    char szJadURL[MAX_PATH];
    char jarName[MAX_PATH];
    char jadName[MAX_PATH];
	char szResponse[MAX_ENHANCED_INIT_AT_RESPONSE];
    char szCmd[MAX_ATCMD_LEN];
	WCHAR wszSearchPath[MAX_PATH];
	WCHAR wszConfigFileName[MAX_PATH];
    WCHAR wszPassword[MAX_PATH];
    char *pTmp;
	
	skipWhiteSpace(&szJadFileName);
    skipWhiteSpace(&strOperationParam);
    if(strOperationParam[strlen(strOperationParam)-1]=='\r')
        strOperationParam[strlen(strOperationParam)-1]='\0';
		
	GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DefaultFirmwareSearchPath"), wszSearchPath, MAX_PATH);
	
	BOOL fConfigFileFound;        
    fConfigFileFound = pRILHandle->GetConfigFilename(wszConfigFileName, MAX_PATH, L"SWUPConfigurations.cfg", wszSearchPath);
    if (!fConfigFileFound) 
        goto Error;
		
	strcpy(szJadURL, pRILHandle->WcharToChar(wszSearchPath));
	strcat(szJadURL, szJadFileName);
	strcpy(szJarURL, szJadURL);
	szJarURL[strlen(szJarURL) -1] = 'r';

	strcpy(jadName, szJadFileName);
	strcpy(jarName, jadName);
	jarName[strlen(jarName) -1] = 'r';

	RILRetailTraceZone(ZONE_INFO, (TEXT("UpdateMidlet Enter\r\n")));
	
    pnd = new CNotificationData;
    if (pnd)
    {
        // Send string including terminating '\0'.
        if (pnd->InitFromRealBlob(RIL_NOTIFY_DEVSPECIFIC_JAVA_UPDATE_START, (void*)szJadURL, (strlen((const char*)&szJadURL))+sizeof(char)))
            pRILHandle->BroadcastNotification(pnd);
        else
            delete pnd;
    }
	
    // The update of the Java midlet might require a password. As default this
    // password is blank in current versions of the EHS5. If a password is needed
    // for future versions, it can be set with this registry key.
    if (!GetRegistrySZ(HKEY_LOCAL_MACHINE, RIL_AUDIO_CONFIG_KEY, TEXT("JavaMidletPassword"), wszPassword, MAX_PATH)) {
        // No password as deault
        wszPassword[0] = 0;
    }

    // Read whole JAD file in a buffer.
    hFile = CreateFile(pRILHandle->charToWchar((char *)&szJadURL), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) goto Error;
    nFileSizeJad = GetFileSize(hFile, NULL);
    if (nFileSizeJad == 0) goto Error;
    // Allocate a buffer to hold the complete file plus one additional byte.
    // The addional byte is set to 0, to allow the file to be treated as a
    // string.
    bBufferJad = (BYTE *)AllocBlob(nFileSizeJad+1);
    if (bBufferJad == NULL) goto Error;
    memset(bBufferJad, 0, nFileSizeJad+1);
    dwBytesRead = 0;
    if(!ReadFile(hFile, bBufferJad, nFileSizeJad, &dwBytesRead, NULL) || dwBytesRead != nFileSizeJad) goto Error;
    CloseHandle(hFile);
    hFile = INVALID_HANDLE_VALUE;
	
    // Read whole JAR file into a buffer. The buffer might be rather large,
    // but in order to avoid delays during transfer it is better to have the
    // file ready in a buffer.
    hFile = CreateFile(pRILHandle->charToWchar((char *)&szJarURL), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) goto Error;
    nFileSizeJar = GetFileSize(hFile, NULL);
    if (nFileSizeJar == 0) goto Error;
    bBufferJar = (BYTE *)AllocBlob(nFileSizeJar);
    if (bBufferJar == NULL) goto Error;
    dwBytesRead = 0;
    if(!ReadFile(hFile, bBufferJar, nFileSizeJar, &dwBytesRead, NULL) || dwBytesRead != nFileSizeJar) goto Error;
    CloseHandle(hFile);
    hFile = INVALID_HANDLE_VALUE;
	
    // In the JAD file there are all the different properties of the Java midlet.
    // The "URL" property is the one where to store the JAR file.
    if (!GetJadProperty((const char *)bBufferJad, "MIDlet-Jar-URL:", szJarURL, MAX_PATH)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("Error: missing JAR-URL in JAD-file.\n")));
        goto Error;
    }
    (void)strncpyz(szJadURL, szJarURL, MAX_PATH);
    // The URL of the JAD file is the as the one for the JAR file, only with a "d" at the end.
    szJadURL[strlen(szJadURL) - 1] = 'd';

    // Delete old JAD file in module.
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJDL=2,0,\"%s\"\r", jadName);
    memset(szResponse, 0, sizeof(szResponse));
    if (!pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), dwTimeout, 0)) {
		goto Error;
    }
    // Delete old JAR file in module.
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJDL=2,0,\"%s\"\r", jarName);
    memset(szResponse, 0, sizeof(szResponse));
    if (!pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), dwTimeout, 0)) {
		goto Error;
    }
	
    // Deinstall the old Java midlet, if still available.
        // Stop the old midlet. This command will fail if midlet has already been
        // stopped, so an error messsage can be ignored.
	(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJAM=2,\"a:/%s\",\"%S\"\r", jadName, wszPassword);
	memset(szResponse, 0, sizeof(szResponse));
	if (!pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), dwTimeout, 0)) {
		goto Error;
	}
	Sleep(WAIT_BEFORE_START);
	// Remove the old midlet. This command will fail if midlet has already been
	// deleted, so an error messsage can be ignored.
	(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJAM=3,\"a:/%s\",\"%S\"\r", jadName, wszPassword);
	memset(szResponse, 0, sizeof(szResponse));
	if (!pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), dwTimeout, 0)) {
		goto Error;
	}

    // Download JAD file.
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJDL=1,%d,\"%s\"\r", nFileSizeJad, jadName);
    if (!pRILHandle->ExSendATCommand(PortType, szCmd))
        goto Error;
    if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
        goto Error;
    if (!pRILHandle->ExSendBytesLarge(PortType, bBufferJad, nFileSizeJad))
        goto Error;
    memset(szResponse, 0, sizeof(szResponse));
    if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_SJDL), TRUE, TRUE))
        goto Error;
    // Check CRC checksum, if given by module.
    pTmp = strstr(szResponse,cszCRC);
    if (pTmp != NULL) {
        const char *szDummy = NULL;
        UINT uiCRC;
        if (ParseUIntHex(szResponse + strlen(cszCRC), FALSE, uiCRC, szDummy)) {
            if (uiCRC != CalcCrc(bBufferJad, nFileSizeJad)) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: CRC error on JAD file download.\n")));
            }
        }
    }

    if (SJDL_CHANGES_ATE) {
        // The AT^SJDL command might have been enabled the echo.
        memset(szResponse, 0, sizeof(szResponse));
        (void)pRILHandle->ExSendATCmdGetRsp(PortType, "ATE0\r", szResponse, sizeof(szResponse), dwTimeout, 0);
    }

    // Download the JAR file. This might take a while.
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJDL=1,%d,\"%s\"\r", nFileSizeJar, jarName);
    if (!pRILHandle->ExSendATCommand(PortType, szCmd))
        goto Error;
    if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
        goto Error;
    if (!pRILHandle->ExSendBytesLarge(PortType, bBufferJar, nFileSizeJar))
        goto Error;
    memset(szResponse, 0, sizeof(szResponse));
    if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_SJDL), TRUE, TRUE))
        goto Error;
    // Check CRC checksum, if given by module.
    pTmp = strstr(szResponse,cszCRC);
    if (pTmp != NULL) {
        const char *szDummy = NULL;
        UINT uiCRC;
        if (ParseUIntHex(szResponse + strlen(cszCRC), FALSE, uiCRC, szDummy)) {
            if (uiCRC != CalcCrc(bBufferJar, nFileSizeJar)) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: CRC error on JAR file download.\n")));
            }
        }
    }

    if (SJDL_CHANGES_ATE) {
        // The AT^SJDL command might have been enabled the echo.
        memset(szResponse, 0, sizeof(szResponse));
        (void)pRILHandle->ExSendATCmdGetRsp(PortType, "ATE0\r", szResponse, sizeof(szResponse), dwTimeout, 0);
    }
	
    if(operationType == OPERATION_MIDLET_INSTALL || operationType == OPERATION_MIDLET_DEPLOY){
		// Install the new midlet.
		(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJAM=0,\"a:/%s\",\"%S\"\r", jadName, wszPassword);
		
		if (!pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), 2 * dwTimeout, 0)) {
			goto Error;
		}
	}

	if(operationType == OPERATION_MIDLET_INSTALL){
		// Start the new midlet.
		(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJAM=1,\"a:/%s\",\"%S\"\r", jadName, wszPassword);
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), 2 * dwTimeout, 0)) {
			goto Error;
		}
	}
	

	if(strstr(strOperationParam, "a:/")==NULL)
    {
	
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SFSA=copy,\"a:/%s\",\"%s%s\",1,1\r",jadName, strOperationParam, jadName);
		if (!pRILHandle->ExSendATCommand(PortType, szCmd))
			goto Error;
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
			goto Error;
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_DEFAULT), TRUE, TRUE))
			goto Error;

        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SFSA=copy,\"a:/%s\",\"%s%s\",1,1\r",jarName, strOperationParam, jarName);
		if (!pRILHandle->ExSendATCommand(PortType, szCmd))
			goto Error;
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
			goto Error;
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_DEFAULT), TRUE, TRUE))
			goto Error;			
		
		(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SFSA=\"remove\",\"a:/%s\"\r",jarName);
		if (!pRILHandle->ExSendATCommand(PortType, szCmd))
			goto Error;
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
			goto Error;
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_DEFAULT), TRUE, TRUE))
			goto Error;			
			
						
		(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SFSA=\"remove\",\"a:/%s\"\r",jadName);
		if (!pRILHandle->ExSendATCommand(PortType, szCmd))
			goto Error;
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
			goto Error;
		memset(szResponse, 0, sizeof(szResponse));
		if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_DEFAULT), TRUE, TRUE))
			goto Error;			

    }

   if(operationType == OPERATION_MIDLET_INSTALL){
				
		 // The new midlet should print out a ^SYSSTART URC.
		pRILHandle->WaitForSysstart(PortType);

		// Enable autostart of the midlet.
		memset(szResponse, 0, sizeof(szResponse));
		(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CSCS=\"GSM\";^SCFG=\"Userware/Autostart\",\"%S\",\"1\"\r", wszPassword);
		if (!pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), dwTimeout, 0)) {
		  goto Error;
		}
	}

    // Everything has been updated successully.
    fRet = TRUE;

Error:
    // Cleanup all allocated buffers and close all open files.
    if (bBufferJar != NULL) FreeBlob(bBufferJar);
    if (bBufferJad != NULL) FreeBlob(bBufferJad);
    if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);

    if (fRet)
        pRILHandle->BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_JAVA_UPDATE_PROGRESS,  100);
    pRILHandle->BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_JAVA_UPDATE_END,  fRet ? UPDATE_PROCESS_SUCCESS : UPDATE_PROCESS_ERROR);
    return fRet;

}

BOOL CFirmwareUpdate::TransferFile(CRilHandle *pRILHandle, COM_PORT_TYPE PortType, char *strFileName, char *strOperationParam, INT operationType)
{

    char szResponse[MAX_ENHANCED_INIT_AT_RESPONSE];
    char szCmd[MAX_ATCMD_LEN];
    const char *cszCRC = "JDL CRC32 0x";
    WCHAR wszSearchPath[MAX_PATH];
    WCHAR wszConfigFileName[MAX_PATH];
    BOOL ret = FALSE;
    BYTE *buffer = NULL;
    UINT fileSize;
    char fileURL[MAX_PATH];
    char fileName[MAX_PATH];
    WCHAR wszPassword[MAX_PATH];
	BOOL fConfigFileFound;
	HANDLE hFile = INVALID_HANDLE_VALUE;
	DWORD dwBytesRead;
	DWORD dwTimeout = pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_SBNW);
	
    skipWhiteSpace(&strFileName);
    skipWhiteSpace(&strOperationParam);
    if(strOperationParam[strlen(strOperationParam)-1]=='\r')
        strOperationParam[strlen(strOperationParam)-1]='\0';
		
	GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DefaultFirmwareSearchPath"), wszSearchPath, MAX_PATH);

    fConfigFileFound = pRILHandle->GetConfigFilename(wszConfigFileName, MAX_PATH, L"SWUPConfigurations.cfg", wszSearchPath);
    if (!fConfigFileFound) // No File found for update.
        goto Error;
		
	strcpy(fileURL, pRILHandle->WcharToChar(wszSearchPath));

	strcat(fileURL, strFileName);

	strcpy(fileName, strFileName);

	RILRetailTraceZone(ZONE_INFO, (TEXT("TransferFile Enter.\n")));
   
    // The update of the Java midlet might require a password. As default this
    // password is blank in current versions of the EHS5. If a password is needed
    // for future versions, it can be set with this registry key.
    if (!GetRegistrySZ(HKEY_LOCAL_MACHINE, RIL_AUDIO_CONFIG_KEY, TEXT("JavaMidletPassword"), wszPassword, MAX_PATH)) {
        // No password as deault
        wszPassword[0] = 0;
    }
	
	// Read whole file in a buffer.
    hFile = CreateFile(pRILHandle->charToWchar((char *)&fileURL), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) goto Error;
    fileSize = GetFileSize(hFile, NULL);
    if (fileSize == 0) goto Error;
    // Allocate a buffer to hold the complete file plus one additional byte.
    // The addional byte is set to 0, to allow the file to be treated as a
    // string.
    buffer = (BYTE *)AllocBlob(fileSize+1);
    if (buffer == NULL) goto Error;
    memset(buffer, 0, fileSize+1);
    dwBytesRead = 0;
    if(!ReadFile(hFile, buffer, fileSize, &dwBytesRead, NULL) || dwBytesRead != fileSize) goto Error;
    CloseHandle(hFile);
    hFile = INVALID_HANDLE_VALUE;

	// Delete old file in module.
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJDL=2,0,\"%s\"\r", fileName);
    memset(szResponse, 0, sizeof(szResponse));
    if (!pRILHandle->ExSendATCmdGetRsp(PortType, szCmd, szResponse, sizeof(szResponse), dwTimeout, 0)) {
      goto Error;
    }
	Sleep(WAIT_BEFORE_START);
	
    // Download file.
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SJDL=1,%d,\"%s\"\r", fileSize, fileName);
    if (!pRILHandle->ExSendATCommand(PortType, szCmd))
        goto Error;
    if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
        goto Error;
    if (!pRILHandle->ExSendBytesLarge(PortType, buffer, fileSize))
        goto Error;
    memset(szResponse, 0, sizeof(szResponse));
    if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_SJDL), TRUE, TRUE))
        goto Error;
			
	// Check CRC checksum, if given by module.
    char *pTmp;
	pTmp = strstr(szResponse,cszCRC);
    if (pTmp != NULL) {
        const char *szDummy = NULL;
        UINT uiCRC;
        if (ParseUIntHex(szResponse + strlen(cszCRC), FALSE, uiCRC, szDummy)) {
            if (uiCRC != CalcCrc(buffer, fileSize)) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: CRC error on JAR file download.\n")));
            }
        }
    }
	
	RILRetailTraceZone(ZONE_INFO, (TEXT("Transcation of done correctly.\n")));
	
    if (SJDL_CHANGES_ATE) {
        // The AT^SJDL command might have been enabled the echo.
		memset(szResponse, 0, sizeof(szResponse));
        (void)pRILHandle->ExSendATCmdGetRsp(PortType, "ATE0\r", szResponse, sizeof(szResponse), dwTimeout, 0);
    }

    if(operationType == OPERATION_FILE_SAVE){
        if(strstr(strOperationParam, "a:/")==NULL)
        {
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SFSA=copy,\"a:/%s\",\"%s%s\",1,1\r",fileName, strOperationParam, fileName);
            if (!pRILHandle->ExSendATCommand(PortType, szCmd))
				goto Error;
			memset(szResponse, 0, sizeof(szResponse));
			if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
				goto Error;
			memset(szResponse, 0, sizeof(szResponse));
			if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, TRUE, TRUE))
				goto Error;
				
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SFSA=\"remove\",\"a:/%s\"\r",fileName);
            if (!pRILHandle->ExSendATCommand(PortType, szCmd))
				goto Error;
			memset(szResponse, 0, sizeof(szResponse));
			if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), dwTimeout, FALSE, TRUE))
				goto Error;
			memset(szResponse, 0, sizeof(szResponse));
			if (!pRILHandle->ExGetATResponse(PortType, szResponse, sizeof(szResponse), pRILHandle->GetPreMuxInitTimeout(PREMUX_TIMEOUTS_DEFAULT), TRUE, TRUE))
				goto Error;			
			
        }
    }
    // Everything has been updated successully.
    ret = TRUE;

Error:

    // Cleanup all allocated buffers and close all open files.
    if (buffer != NULL) FreeBlob(buffer);
	if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
    return ret;
}



char* CRilHandle::WcharToChar(const wchar_t* wp)
{
	char * str;
	int len = WideCharToMultiByte(CP_ACP, 0, wp, wcslen(wp), NULL, 0, NULL, NULL);
	char	*m_char = new char[len + 1];
	WideCharToMultiByte(CP_ACP, 0, wp, wcslen(wp), m_char, len, NULL, NULL);
	m_char[len] = '\0';
	str = m_char;
	delete m_char;
	return str;
}

WCHAR* CRilHandle::charToWchar(char *s){

	int w_nlen=MultiByteToWideChar(CP_ACP,0,s,-1,NULL,0);

	WCHAR *ret;

	ret=(WCHAR*) malloc(sizeof(WCHAR)*w_nlen);

	memset(ret,0,sizeof(ret));

	MultiByteToWideChar(CP_ACP,0,s,-1,ret,w_nlen);

	return ret;
}
