/*****************************************************************************
 * Copyright (C) Gemalto M2M GmbH
 *****************************************************************************
 * Project: IMC-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules RD SW A2
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RilDrv/rilsimtk_standard.cpp $
 * $Revision: /main/ms-d/61 $
 *     $Date: 2013-06-10 13:10:32 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 5.0
 *****************************************************************************
 * Description:
 *  Gemalto IMC RIL
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RilDrv/rilsimtk_standard.cpp$ 
 * 
 * /main/ms-d/61   2013-06-10 13:10:32   pmackent 
 * Solve deadlock in SAT PLay Tone (IPIS100088390)
 *
 * /main/ms-d/60   2013-02-14 15:17:56   pmackent
 * Fix build error on advanced notifications build option
 *
 * /main/ms-d/59   2013-02-08 09:03:28   pmackent
 * Intel style SAT is now official
 *
 * /main/ms-d/58   2012-10-08 16:18:38   pmackent
 * Comply to Klocwork checks.
 *
 * /main/ms-d/57   2012-09-21 16:39:11   pmackent
 * Use proper defines instead of hardcode numbers.
 *
 * /main/ms-d/56   2012-09-19 15:09:46   pmackent
 * Solve problem with wrong SAT response to 27.22.4.22.1_6(IPIS100082389)
 *
 * /main/ms-d/55   2012-02-22 13:27:19   ctna0256
 * Encapsulate use of Intel AT command set
 *
 * /main/ms-d/54   2012-02-10 12:59:39   ctna0256
 * Store Idle Mode Status in registry (IPIS100077395)
 *
 * /main/ms-d/53   2012-02-08 15:15:54   ctna0256
 * Add Intel-style SAT
 *
 * /main/ms-d/51   2012-02-02 17:04:01   ctna0256
 * FD phonebook workaround and NITZ URCs for Intel platform
 *
 * /main/ms-d/50   2012-01-31 16:39:02   ctna0256
 * Added support for EHS5
 *
 * /main/ms-d/49   2012-01-20 13:20:46   ctna0256
 * Better handling of SAT Idle Mode Text in case of booting the device (IPIS100077101)
 *
 * /main/ms-d/48   2011-12-16 10:42:30   ctna0256
 * Limit length of idle mode text (IPIS100076294)
 *
 * /main/ms-d/47   2011-12-15 13:33:14   ctna0256
 * Reset Idle Mode Text after SIM Refresh (IPIS100076294)
 *
 * /main/ms-d/46   2011-09-21 07:49:01   ctna0256
 * Handle * and # in SAT Setup Call
 *
 * /main/ms-d/45   2011-03-01 11:15:09   ctna0256
 * Introduce define for EF_CSP to improve source code readability
 *
 * /main/ms-d/44   2011-02-28 09:19:33   ctna0256
 * Reset SAT Idle Mode Text on start (IPIS100070301)
 *
 * /main/ms-d/43   2011-02-18 10:28:49   ctna0256
 * Merge automatic SAT response from Classic-RIL
 *
 * /main/ms-d/42   2011-02-02 10:55:24   ctna0256
 * Merge SAT call number handling from Classic-RIL
 *
 * /main/ms-d/41   2011-01-26 16:39:13   ctna0256
 * Changed handling of SAT setup call numbers
 *
 * /main/ms-d/40   2010-12-15 10:44:07   ctna0256
 * Performed lint check
 *
 * /main/ms-d/39   2010-09-22 11:41:47   ctna0256
 * Registry key to set audio gain for SAT play tone
 *
 * /main/ms-d/38   2010-09-07 10:11:53   ctna0256
 * Workaround for missing ^SSTN: 254 URC (IPIS100067413)
 *
 * /main/ms-d/37   2010-02-22 15:43:19   ctna0256
 * Notify MMI about change of MSISDN via SAT (IPIS100062554)
 *
 * /main/ms-d/36   2009-10-07 09:22:31   ctna0256
 * Introduce no-operation command queue
 * Support 2nd alpha identifier in SAT setup call (IPIS100055375)
 *
 * /main/ms-d/35   2009-03-19 10:57:55   ctna0256
 * WM65 capabilities
 *
 * /main/ms-d/34   2009-01-22 10:17:27   ctna0256
 * Optional re-call of RHA_ConfirmAudioMode after RHA_ActivateVoicePath
 *
 * /main/ms-d/33   2008-11-25 09:35:56   ctna0256
 * Better check for phonebook change for 3G SIMs
 *
 * /main/ms-d/32   2008-08-22 10:27:40   ctna0256
 * Set Cinterion copyright text
 *
 * /main/ms-d/31   2008-08-21 09:35:28   ctna0256
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/30   2008-07-22 15:53:08   mp49210
 * Complience to WM7, Lint and PreFast requirements
 *
 * /main/ms-d/29   2008-06-16 10:45:59   mp49210
 * IPIS100048716: respect icon state for automatic SAT play tone start
 *
 * /main/ms-d/28   2008-06-13 09:40:39   mp49210
 * typo in reg-key name removed
 *
 * /main/ms-d/27   2008-06-13 09:36:43   mp49210
 * IPIS100048706: force re-read of phone book after SIM file change
 *
 * /main/ms-d/26   2008-06-12 11:38:30   mp49210
 * Workaround for wrong characters in EONS name
 *
 * /main/ms-d/25   2008-05-15 16:32:18   mp49210
 * Add 'no icon' option to setup menu
 *
 * /main/ms-d/24   2008-04-29 13:38:12   mp49210
 * Workaround for missing simstatus URC.
 * New handling of SIM reset.
 *
 * /main/ms-d/23   2008-04-22 08:08:45   mp49210
 * Report no icons to MMI, if icon support is deactivated
 *
 * /main/ms-d/22   2008-04-21 08:16:52   mp49210
 * Handling of AT&Ts network selection menue change
 *
 * /main/ms-d/21   2008-04-16 15:41:16   mp49210
 * Use correct registry key for delay display text
 *
 * /main/ms-d/20   2008-04-03 14:41:58   mp49210
 * Introduction of new debug zones
 *
 * /main/ms-d/19   2008-04-02 14:11:35   mp49210
 * Lint check
 *
 * /main/ms-d/18   2008-03-31 13:34:49   mp49210
 * IPIS100017065: delay for automatic SAT responses
 * Support of new SSTR parameters
 * Support of 'no icon' option
 *
 * /main/ms-d/17   2008-03-18 11:21:56   mp49210
 * IPIS100045548: workaround for missing SAT SS command im Microsoft's MMI
 *
 * /main/ms-d/16   2008-03-18 09:23:46   mp49210
 * Workaround for SAT setup call "hold calls" command
 *
 * /main/ms-d/15   2008-03-17 10:28:27   mp49210
 * Make SAT setup call workaround module specific
 *
 * /main/ms-d/14   2008-03-14 16:09:36   mp49210
 * IPIS100045647: workaround for handling of SAT setup call while active voice call
 *
 * /main/ms-d/13   2008-02-11 09:18:22   mp49210
 * Remove LINT warnings
 *
 * /main/ms-d/12   2007-12-17 17:25:17   mp49210
 * Merge SAT play tone changes from Classic RIL
 *
 * /main/ms-d/11   2007-12-12 16:17:43   mp49210
 * Merge SAT Setup Call handling from Classic RIL
 *
 * /main/ms-d/10   2007-11-26 10:45:18   mp49210
 * SAT play tone behaviour per compiler swith
 *
 * /main/ms-d/9   2007-11-23 15:27:53   mp49210
 * Compatibility SAT Play Tone to Classic RIL
 *
 * /main/ms-d/8   2007-11-13 10:25:24   mp49210
 * Solved problem with simultanouly OK and ERROR from the module
 *
 * /main/ms-d/7   2007-11-06 13:52:20   mp49210
 * Send <Esc> for empty input string
 *
 * /main/ms-d/6   2007-11-05 08:25:41   mp49210
 * Missing SIM_PARAMs added
 *
 * /main/ms-d/5   2007-07-06 10:13:59   mp49210
 * Lint compatibility
 *
 * /main/ms-d/4   2007-06-27 15:07:08   mp49210
 * Merge from Classic RIL: new parameters for SAT REFRESH command
 *
 * /main/ms-d/3   2007-05-15 09:43:14   mp49210
 * IPIS100036211, IPIS100036212: modified SAT abort command in HC25
 *
 * /main/ms-d/2   2007-02-26 16:10:56   mp49210
 * Move SAT commands to standard port
 *
 * /main/ms-d/1   2006-10-25 16:52:02   wm36264
 * First transformation from classic RIL
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Gemalto M2M GmbH
// Copyright (C) 2006-2008 Siemens AG
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1999  Microsoft Corporation
--*/

#include "precomp.h"
#include <simtkit.h>

// Macros to round values to DWORD boundaries and add them
#define ROUNDTODWORD2(a, b)          (ROUNDTODWORD(a) + ROUNDTODWORD(b))
#define ROUNDTODWORD3(a, b, c)       (ROUNDTODWORD2(a, b) + ROUNDTODWORD(c))
#define ROUNDTODWORD4(a, b, c, d)    (ROUNDTODWORD2(a, b) + ROUNDTODWORD2(c, d))

// Delay for sending the SIM phonebook changed notification
#define DEFAULT_PHONEBOOKCHANGE_DELAY  10000

//////////////////////////////////////////////////////////////////////////////
//
// Thread to activate audio path for SAT Play Tone.
//
//////////////////////////////////////////////////////////////////////////////
#ifdef SAT_PLAY_TONE_OLD_STYLE
static DWORD WINAPI ActivateStkAudioThreadProc(LPVOID lpParameter)
{
  PLAYTONE_THREAD_DATA* pData = (PLAYTONE_THREAD_DATA*)lpParameter;
  char szCmd[MAX_ATCMD_LEN];

  if (pData == NULL)
    return 0;

  // Set audio mode, if necessary.
  pData->pSATHandle->SetSATPlayToneAudioMode();

  // Compatibility to SAT behaviour of MC55: start SAT tone now.
  (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT%s=32,%d\r", pData->fIntelStyle ? "+STKTR" : "^SSTR", pData->fNoIcon ? 4 : 0);
  (void)QueueInternalCmd(HCCMD_STANDARD, pData->pRilHandle, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITENVELOPECMD, 0, 0, 0, NULL);

  delete pData;

  return 0;
}
#endif

//////////////////////////////////////////////////////////////////////////////
//
// Thread which re-checks the status of the enhanced network selection.
//
// Return:
//  always 0
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI ReCheckENSSetting(LPVOID pVoid)
{
    CRilHandle* pHandle = (CRilHandle *)pVoid;

    Sleep(250);     // Give SAT some time to finish its confirmation.

    if (pHandle != NULL)
        pHandle->CheckENSSetting(FALSE);

    return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Thread which send a phonebook changed notification with a delay
//
// Return:
//  always 0
//
//////////////////////////////////////////////////////////////////////////////
static DWORD WINAPI SendPhonebookChangeWithDelay(LPVOID pVoid)
{
    CRilHandle* pHandle = (CRilHandle *)pVoid;
    DWORD dwDelay = 0;

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SATNotifyPhonebookDelay"), &dwDelay))
        dwDelay = DEFAULT_PHONEBOOKCHANGE_DELAY;
    Sleep(dwDelay);     // Give SAT some time to finish its confirmation.

    if (pHandle != NULL && !g_PowerManager.IsRadioOff())
        (void)pHandle->BroadcastDWORDBlobNotification(RIL_NOTIFY_SIM_DATACHANGE, RIL_SIM_DATACHANGE_ALL_SIMPB);

    return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Like SendPhonebookChangeWithDelay() (see above), but for own numbers phonebook
//
// Return:
//  always 0
//
//////////////////////////////////////////////////////////////////////////////
static DWORD WINAPI InitiateReadOwnNumber(LPVOID pVoid)
{
    CRilHandle* pHandle = (CRilHandle *)pVoid;
    DWORD dwDelay = 0;

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SATNotifyPhonebookDelay"), &dwDelay))
        dwDelay = DEFAULT_PHONEBOOKCHANGE_DELAY;
    Sleep(dwDelay);     // Give SAT some time to finish its confirmation.

    if (pHandle != NULL && !g_PowerManager.IsRadioOff())
        (void)pHandle->BroadcastDWORDBlobNotification(RIL_NOTIFY_SIM_DATACHANGE, RIL_SIM_DATACHANGE_MSISDNS);

    return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseRefresh(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails = 0;
UINT               nPathLen = 0;
UINT               nFileNum = 0;
RILSIMTOOLKITCMD*  pSatCmd;
SIMFILEREFRESH*    pSatRefresh;
BOOL               fRet = TRUE;
char               szFileList[MAX_ATCMD_LEN];

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_REFRESH);
  memset(szFileList, 0, MAX_ATCMD_LEN);

  // Parse: "<details>[, <pathLen>, <fileNum>, <fileList>]"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)) {
    fRet = FALSE;
    goto End;
  }
  if (MatchStringBeginning(szRsp, ",", szRsp)) {
    if (!ParseUInt(szRsp, FALSE, nPathLen, szRsp) ||
        !MatchStringBeginning(szRsp, ",", szRsp)  ||
        !ParseUInt(szRsp, FALSE, nFileNum, szRsp) ||
        !MatchStringBeginning(szRsp, ",", szRsp)  ||
        !ParseString(szRsp, szFileList, MAX_ATCMD_LEN, szRsp)) {
      fRet = FALSE;
      goto End;
    }
  }
  if (!ParseRspPostfix(szRsp, szRsp)) {
    fRet = FALSE;
  }

End:
  if (fRet) {
    pSatRefresh = (SIMFILEREFRESH*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatRefresh->dwParams     = SIM_PARAM_FILEREFRESH_FLAGS;
    pSatRefresh->dwFlags      = 0;
    switch (nDetails) {
      case 0:
        pSatRefresh->dwFlags  = SIMFILE_SIMINIT | SIMFILE_FULLFILECHANGE;
        ResetIdleModeText();
        break;
      case 1:
        pSatRefresh->dwFlags  = SIMFILE_FULLFILECHANGE;
        break;
      case 2:
        pSatRefresh->dwFlags  = SIMFILE_SIMINIT | SIMFILE_FULLFILECHANGE;
        ResetIdleModeText();
        break;
      case 3:
        pSatRefresh->dwFlags  = SIMFILE_SIMINIT;
        ResetIdleModeText();
        break;
      case 4:
        pSatRefresh->dwFlags  = SIMFILE_SIMRESET;
        // In case off a full SIM reset the module doesn't require any response
        m_fNoResponse = TRUE;
        ResetIdleModeText();
        break;
      default:
        (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
        fRet = FALSE;
        break;
    }
    pSatRefresh->cbSize = ROUNDTODWORD(sizeof(SIMFILEREFRESH));

    if (nFileNum > 0 && nFileNum < MAX_FILES) {
        BOOL fEONSInitStarted = FALSE;
        BOOL fPhonebookReadInitiated = FALSE;
        INT iPos = 0;
        INT iFile = 0;

        pSatRefresh->dwFileCount = nFileNum;
        pSatRefresh->dwFlags |= SIMFILE_FILECHANGE;
        while (iPos < (INT)strlen(szFileList)) {
            DWORD nFile;

            nFile = (SemiByteCharsToByte(szFileList[iPos], szFileList[iPos+1])*256) + SemiByteCharsToByte(szFileList[iPos+2], szFileList[iPos+3]);
            if (iPos > 0 && nFile == 0x3F00)
                iFile++;
            pSatRefresh->rgdwAddress[iFile] = nFile;

            if (nFile == SIM_EF_CSP)        // File EF_CSP changed: recheck status of network selection menu change
                CloseHandle(CreateThread(NULL, 0, ReCheckENSSetting, (LPVOID)m_pRilDevice, 0, 0));

            if (nFile == EF_PNN || nFile == EF_OPL) {        // File EF_PNN or EF_OPL changed: re-read EONS table
                if (!fEONSInitStarted)
                    (void)m_pRilDevice->GetEons()->ReInit();
                fEONSInitStarted = TRUE;
            }

            if (nFile == 0x6F3A || nFile == 0x5F3A || (nFile >= 0x4F00 && nFile <= 0x4FFF)) {       // File 2G: EF_ADN or 3G: DF_PHONEBOOK or files in phonebook DF changed: force MMI to re-read the SIM phonebook
                if (!fPhonebookReadInitiated)
                    CloseHandle(CreateThread(NULL, 0, SendPhonebookChangeWithDelay, (LPVOID)m_pRilDevice, 0, 0));
                fPhonebookReadInitiated = TRUE;
            }

            if (nFile == 0x6F40)        // File EF_MSISDN changed: own number has been updated and must be read again
                CloseHandle(CreateThread(NULL, 0, InitiateReadOwnNumber, (LPVOID)m_pRilDevice, 0, 0));

            iPos += 4;
        }
    }

    pSatCmd->cbSize += pSatRefresh->cbSize;
    pSatCmd->dwDetailsSize = pSatRefresh->cbSize;
  }
  else {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSetupEventList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nEventList;
RILSIMTOOLKITCMD*  pSatCmd;
SIMEVENTLIST*      pSatEventList;
BYTE*              pEvents;
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_EVENTLIST);

  // Parse: "<details>,<eventlist>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)        ||
      !ParseUInt(szRsp, FALSE, nEventList, szRsp)  ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatEventList = (SIMEVENTLIST*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatEventList->dwParams        = SIM_PARAM_SIMEVENTLIST_ALL;
    pSatEventList->dwEventsSize    = 0;
    pSatEventList->dwEventsOffset  = ROUNDTODWORD(sizeof(SIMEVENTLIST));

    pEvents = (BYTE*)pSatEventList + pSatEventList->dwEventsOffset;
    if (nEventList & 0x0010) { pEvents[pSatEventList->dwEventsSize++] = SIMTKIT_EVENT_USERACTIVITY; }
    if (nEventList & 0x0020) { pEvents[pSatEventList->dwEventsSize++] = SIMTKIT_EVENT_IDLESCREEN; }
    if (nEventList & 0x0100) { pEvents[pSatEventList->dwEventsSize++] = SIMTKIT_EVENT_LANGUAGESELECTION; }
    if (nEventList & 0x0200) { pEvents[pSatEventList->dwEventsSize++] = SIMTKIT_EVENT_BROWSERTERMINATION; }

    pSatEventList->cbSize = ROUNDTODWORD2(sizeof(SIMEVENTLIST), pSatEventList->dwEventsSize);

    pSatCmd->cbSize += pSatEventList->cbSize;
    pSatCmd->dwDetailsSize = pSatEventList->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSetupCall(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nConfIconQualifier, nConfIconId, nSetupIconQualifier, nSetupIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMCALL*           pSatCall;
WCHAR              wszConfirmation[UCS2_LEN + 1], wszNumber[UCS2_LEN + 1], wszSetup[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SETUPCALL);
  m_fIgnoreNextSSTR1632 = FALSE;

  // Parse "<details>,<confirmation text>,<called number>,<call setup text>,<conf icon qual>,<conf icon>,<call setup icon qual>,<call setup icon>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)                  ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUCS2String(szRsp, wszConfirmation, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUCS2String(szRsp, wszNumber, UCS2_LEN, szRsp)        ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUCS2String(szRsp, wszSetup, UCS2_LEN, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUInt(szRsp, FALSE, nConfIconQualifier, szRsp)        ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUInt(szRsp, FALSE, nConfIconId, szRsp)               ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUInt(szRsp, FALSE, nSetupIconQualifier, szRsp)       ||
      !ParseRspParamSeparator(szRsp, szRsp)                      ||
      !ParseUInt(szRsp, FALSE, nSetupIconId, szRsp)              ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatCall = (SIMCALL*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatCall->dwParams = SIM_PARAM_SIMCALL_FLAGS;
    switch (nDetails) {
      case 0:
        pSatCall->dwFlags = SIMCALL_IDLE;
        // Workaround for GCF 27.22.4.13.1 Seq1.6: the module show SIMCALL_IDLE, but expects, that
        // the MMI response with SSTR=16,0, even when a call is active. So the RIL must ignore the next
        // SSTR=16,32 and send SSTR=16,0 instead, when a call is active.
        m_fIgnoreNextSSTR1632 = TRUE;
        break;
      case 1:
        pSatCall->dwFlags = SIMCALL_IDLE | SIMCALL_REDIAL;
        break;
      case 2:
        pSatCall->dwFlags = SIMCALL_HOLDCALLS;
        // Workaround for GCF 27.22.4.13.1 Seq1.7: the module shows SIMCALL_HOLDCALLS, but expects,
        // the MMI response with SSTR=16,0, even when it is not possible to put the call on hold.
        m_fIgnoreNextSSTR1632 = TRUE;
#ifdef RIL_INDICATE_ADDITIONAL_SAT_INFO
          // Additional for GCF 27.22.4.13.1 Seq1.7: MMI shows an expicit message, that the active call
          // will be put on hold (if there is a call).
          if (m_pRilDevice->DisplayAdvancedNotifications() && g_iNrCallInfo != 0)
          {
            WCHAR wszText[MAX_RESOURCE_STRING_LEN];

            if (LoadString((HINSTANCE)hInstance, IDS_INDICATION_SAT_SETUPCALL_HOLD, wszText, MAX_RESOURCE_STRING_LEN) > 0)
            {
              (void)wcsncat(wszConfirmation, wszText, UCS2_LEN);
            }
          }
#endif
        break;
      case 3:
        pSatCall->dwFlags = SIMCALL_HOLDCALLS | SIMCALL_REDIAL;
#ifdef RIL_INDICATE_ADDITIONAL_SAT_INFO
          if (m_pRilDevice->DisplayAdvancedNotifications() && g_iNrCallInfo != 0)
          {
            WCHAR wszText[MAX_RESOURCE_STRING_LEN];

            if (LoadString((HINSTANCE)hInstance, IDS_INDICATION_SAT_SETUPCALL_HOLD, wszText, MAX_RESOURCE_STRING_LEN) > 0)
            {
              (void)wcsncat(wszConfirmation, wszText, UCS2_LEN);
            }
          }
#endif
        break;
      case 4:
        pSatCall->dwFlags = SIMCALL_DISCONNECTCALLS;
#ifdef RIL_INDICATE_ADDITIONAL_SAT_INFO
          if (m_pRilDevice->DisplayAdvancedNotifications() && g_iNrCallInfo != 0)
          {
            WCHAR wszText[MAX_RESOURCE_STRING_LEN];

            if (LoadString((HINSTANCE)hInstance, IDS_INDICATION_SAT_SETUPCALL_DROP, wszText, MAX_RESOURCE_STRING_LEN) > 0)
            {
              (void)wcsncat(wszConfirmation, wszText, UCS2_LEN);
            }
          }
#endif
        break;
      case 5:
        pSatCall->dwFlags = SIMCALL_DISCONNECTCALLS | SIMCALL_REDIAL;
#ifdef RIL_INDICATE_ADDITIONAL_SAT_INFO
          if (m_pRilDevice->DisplayAdvancedNotifications() && g_iNrCallInfo != 0)
          {
            WCHAR wszText[MAX_RESOURCE_STRING_LEN];

            if (LoadString((HINSTANCE)hInstance, IDS_INDICATION_SAT_SETUPCALL_DROP, wszText, MAX_RESOURCE_STRING_LEN) > 0)
            {
              (void)wcsncat(wszConfirmation, wszText, UCS2_LEN);
            }
          }
#endif
        break;
      default:
        pSatCall->dwParams = 0;
        break;
    }
    if (pSatCall->dwParams != 0)
      m_nLastSATSetCallDetail = pSatCall->dwFlags;
    memset(m_wszLastSetupCallName, 0, UCS2_LEN*sizeof(WCHAR));
    if (wcslen(wszConfirmation)) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_TEXTSIZE | SIM_PARAM_SIMCALL_TEXTOFFSET;
      pSatCall->dwTextSize                 = (wcslen(wszConfirmation) + 1) * sizeof(WCHAR);
      pSatCall->dwTextOffset               = ROUNDTODWORD(sizeof(SIMCALL));
      (void)wcscpy((WCHAR*)((BYTE*)pSatCall + pSatCall->dwTextOffset), wszConfirmation);
    }
    if (wcslen(wszNumber)) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_ADDRESSSIZE | SIM_PARAM_SIMCALL_ADDRESSOFFSET |
                                             SIM_PARAM_SIMCALL_ADDRESSTYPE | SIM_PARAM_SIMCALL_NUMPLAN;
      pSatCall->dwAddressSize              = (wcslen(wszNumber) + 1) * sizeof(WCHAR);
      pSatCall->dwAddressOffset            = ROUNDTODWORD2(sizeof(SIMCALL), pSatCall->dwTextSize);
      pSatCall->dwAddressType              = (wszNumber[0] == L'+') ? SIM_ADDRTYPE_INTERNATIONAL : SIM_ADDRTYPE_UNKNOWN;
      pSatCall->dwNumPlan                  = SIM_NUMPLAN_TELEPHONE;
      (void)wcscpy((WCHAR*)((BYTE*)pSatCall + pSatCall->dwAddressOffset), wszNumber);
      if (MUST_USE_SAT_CMD_FOR_SETUP_CALL) {
        (void)_snprintfz(m_szLastSetupCallNo, MAX_ATCMD_LEN, "%S", wszNumber);
        m_fLastSetupCallNo = TRUE;
      }
    }
    if (wcslen(wszSetup)) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_CALLSETUPTEXTSIZE | SIM_PARAM_SIMCALL_CALLSETUPTEXTOFFSET;
      pSatCall->dwCallSetupTextSize        = (wcslen(wszSetup) + 1) * sizeof(WCHAR);
      pSatCall->dwCallSetupTextOffset      = ROUNDTODWORD3(sizeof(SIMCALL), pSatCall->dwTextSize, pSatCall->dwAddressSize);
      (void)wcscpy((WCHAR*)((BYTE*)pSatCall + pSatCall->dwCallSetupTextOffset), wszSetup);
      // If setup text (2nd alpha) is available, store it to be able to display it later (see registry key "SATCallNameOverride")
      (void)wcsncpyz(m_wszLastSetupCallName, wszSetup, UCS2_LEN);
    }
    if (nConfIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_ICONID | SIM_PARAM_SIMCALL_ICONQUALIFIER;
        pSatCall->dwIconIdentifier           = nConfIconId;
        pSatCall->dwIconQualifier            = nConfIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    if (nSetupIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_CALLSETUPICONID | SIM_PARAM_SIMCALL_CALLSETUPICONQUALIFIER;
        pSatCall->dwCallSetupIconIdentifier  = nSetupIconId;
        pSatCall->dwCallSetupIconQualifier   = nSetupIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatCall->cbSize = ROUNDTODWORD4(sizeof(SIMCALL), pSatCall->dwTextSize, pSatCall->dwAddressSize, pSatCall->dwCallSetupTextSize);

    pSatCmd->cbSize += pSatCall->cbSize;
    pSatCmd->dwDetailsSize = pSatCall->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendSS(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMUSSD*           pSatSs;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDSS);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatSs = (SIMUSSD*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatSs->dwParams         |= SIM_PARAM_SIMUSSD_TEXTSIZE | SIM_PARAM_SIMUSSD_TEXTOFFSET;
      pSatSs->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatSs->dwTextOffset      = ROUNDTODWORD(sizeof(SIMUSSD));
      (void)wcscpy((WCHAR*)((BYTE*)pSatSs + pSatSs->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatSs->dwParams         |= SIM_PARAM_SIMUSSD_ICONID | SIM_PARAM_SIMUSSD_ICONQUALIFIER;
        pSatSs->dwIconIdentifier  = nIconId;
        pSatSs->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatSs->cbSize = ROUNDTODWORD2(sizeof(SIMUSSD), pSatSs->dwTextSize);

    pSatCmd->cbSize += pSatSs->cbSize;
    pSatCmd->dwDetailsSize = pSatSs->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendUSSD(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMUSSD*           pSatUssd;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDUSSD);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatUssd = (SIMUSSD*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatUssd->dwParams         |= SIM_PARAM_SIMUSSD_TEXTSIZE | SIM_PARAM_SIMUSSD_TEXTOFFSET;
      pSatUssd->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatUssd->dwTextOffset      = ROUNDTODWORD(sizeof(SIMUSSD));
      (void)wcscpy((WCHAR*)((BYTE*)pSatUssd + pSatUssd->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatUssd->dwParams         |= SIM_PARAM_SIMUSSD_ICONID | SIM_PARAM_SIMUSSD_ICONQUALIFIER;
        pSatUssd->dwIconIdentifier  = nIconId;
        pSatUssd->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatUssd->cbSize = ROUNDTODWORD2(sizeof(SIMUSSD), pSatUssd->dwTextSize);

    pSatCmd->cbSize += pSatUssd->cbSize;
    pSatCmd->dwDetailsSize = pSatUssd->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendSMS(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMSMS*            pSatSms;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDSMS);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatSms = (SIMSMS*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatSms->dwParams         |= SIM_PARAM_SIMSMS_TEXTSIZE | SIM_PARAM_SIMSMS_TEXTOFFSET;
      pSatSms->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatSms->dwTextOffset      = ROUNDTODWORD(sizeof(SIMSMS));
      (void)wcscpy((WCHAR*)((BYTE*)pSatSms + pSatSms->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatSms->dwParams         |= SIM_PARAM_SIMSMS_ICONID | SIM_PARAM_SIMSMS_ICONQUALIFIER;
        pSatSms->dwIconIdentifier  = nIconId;
        pSatSms->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatSms->cbSize = ROUNDTODWORD2(sizeof(SIMSMS), pSatSms->dwTextSize);

    pSatCmd->cbSize += pSatSms->cbSize;
    pSatCmd->dwDetailsSize = pSatSms->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendDTMF(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMSENDDTMF*       pSatDtmf;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDDTMF);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatDtmf = (SIMSENDDTMF*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    if (wcslen(wszText)) {
      pSatDtmf->dwParams         |= SIM_PARAM_SIMSENDDTMF_TEXTSIZE | SIM_PARAM_SIMSENDDTMF_TEXTOFFSET;
      pSatDtmf->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatDtmf->dwTextOffset      = ROUNDTODWORD(sizeof(SIMSENDDTMF));
      (void)wcscpy((WCHAR*)((BYTE*)pSatDtmf + pSatDtmf->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatDtmf->dwParams         |= SIM_PARAM_SIMSENDDTMF_ICONID | SIM_PARAM_SIMSENDDTMF_ICONQUALIFIER;
        pSatDtmf->dwIconIdentifier  = nIconId;
        pSatDtmf->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatDtmf->cbSize = ROUNDTODWORD2(sizeof(SIMSENDDTMF), pSatDtmf->dwTextSize);

    pSatCmd->cbSize += pSatDtmf->cbSize;
    pSatCmd->dwDetailsSize = pSatDtmf->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseLaunchBrowser(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT                 nDetails, nIconQualifier, nIconId, nBrowserId;
RILSIMTOOLKITCMD*    pSatCmd;
SIMLAUNCHBROWSER*    pSatLB;
WCHAR                wszText[UCS2_LEN + 1], wszURL[UCS2_LEN + 1], wszGateway[UCS2_LEN + 1];
WCHAR                wszBearerLst[UCS2_LEN + 1], wszFileRefLst[UCS2_LEN + 1]; //Not supported by module
BOOL                 fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_LAUNCHBROWSER);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>,<browserid>,<url>,<bearerlist>,<filereflist>,<gatewayid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)                ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)        ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)                 ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nBrowserId, szRsp)              ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszURL, UCS2_LEN, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszBearerLst, UCS2_LEN, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszFileRefLst, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUCS2String(szRsp, wszGateway, UCS2_LEN, szRsp)     ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatLB = (SIMLAUNCHBROWSER*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatLB->dwParams            = SIM_PARAM_SIMLAUNCHBROWSER_FLAGS | SIM_PARAM_SIMLAUNCHBROWSER_BROWSERID;
    pSatLB->dwFlags             = nDetails;
    pSatLB->dwBrowserId         = nBrowserId;
    if (wcslen(wszURL)) {
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_URLSIZE | SIM_PARAM_SIMLAUNCHBROWSER_URLOFFSET;
      pSatLB->dwURLSize         = (wcslen(wszURL) + 1) * sizeof(WCHAR);
      pSatLB->dwURLOffset       = ROUNDTODWORD(sizeof(SIMLAUNCHBROWSER));
      (void)wcscpy((WCHAR*)((BYTE*)pSatLB + pSatLB->dwURLOffset), wszURL);
    }else if (GetRegistrySZ(HKEY_LOCAL_MACHINE, TEXT("Comm\\Cellular\\SimToolkit\\LaunchBrowser"), TEXT("DefaultUrl"), wszURL, UCS2_LEN)) {
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit LaunchBrower - Using default URL %s\r\n"), wszURL));
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_URLSIZE | SIM_PARAM_SIMLAUNCHBROWSER_URLOFFSET;
      pSatLB->dwURLSize         = (wcslen(wszURL) + 1) * sizeof(WCHAR);
      pSatLB->dwURLOffset       = ROUNDTODWORD(sizeof(SIMLAUNCHBROWSER));
      (void)wcscpy((WCHAR*)((BYTE*)pSatLB + pSatLB->dwURLOffset), wszURL);
    }
    if (wcslen(wszText)) {
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_TEXTSIZE | SIM_PARAM_SIMLAUNCHBROWSER_TEXTOFFSET;
      pSatLB->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatLB->dwTextOffset      = ROUNDTODWORD2(sizeof(SIMLAUNCHBROWSER), pSatLB->dwURLSize);
      (void)wcscpy((WCHAR*)((BYTE*)pSatLB + pSatLB->dwTextOffset), wszText);
    }
    if (nIconId) {
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_ICONID | SIM_PARAM_SIMLAUNCHBROWSER_ICONQUALIFIER;
      pSatLB->dwIconIdentifier  = nIconId;
      pSatLB->dwIconQualifier   = nIconQualifier;
    }
    pSatLB->cbSize = ROUNDTODWORD3(sizeof(SIMLAUNCHBROWSER), pSatLB->dwURLSize, pSatLB->dwTextSize);

    pSatCmd->cbSize += pSatLB->cbSize;
    pSatCmd->dwDetailsSize = pSatLB->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParsePlayTone(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nTone, nDurationUnit, nDuration, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTONE*           pSatTone;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_PLAYTONE);

  // Parse: "<details>,<"text">,<tone>,<durationunit>,<duration>,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nTone, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nDurationUnit, szRsp)     ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nDuration, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatTone = (SIMTONE*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatTone->dwParams    = SIM_PARAM_SIMTONE_TONE | SIM_PARAM_SIMTONE_DURATION;
    pSatTone->dwTone      = nTone;
    pSatTone->dwDuration  = 0;
    switch (nDurationUnit) {
      case 0:
        pSatTone->dwDuration = nDuration * (60 * 1000);
        break;
      case 1:
        pSatTone->dwDuration = nDuration * 1000;
        break;
      case 2:
        pSatTone->dwDuration = nDuration * 100;
        break;
      default:
        (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
        fRet = FALSE;
        break;
    }
    if (wcslen(wszText)) {
      pSatTone->dwParams         |= SIM_PARAM_SIMTONE_TEXTSIZE | SIM_PARAM_SIMTONE_TEXTOFFSET;
      pSatTone->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatTone->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTONE));
      (void)wcscpy((WCHAR*)((BYTE*)pSatTone + pSatTone->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatTone->dwParams         |= SIM_PARAM_SIMTONE_ICONID | SIM_PARAM_SIMTONE_ICONQUALIFIER;
        pSatTone->dwIconIdentifier  = nIconId;
        pSatTone->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatTone->cbSize = ROUNDTODWORD2(sizeof(SIMTONE), pSatTone->dwTextSize);

    pSatCmd->cbSize += pSatTone->cbSize;
    pSatCmd->dwDetailsSize = pSatTone->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

#ifdef SAT_PLAY_TONE_OLD_STYLE
  if (fRet) {
    PLAYTONE_THREAD_DATA *pData;

    pData = new PLAYTONE_THREAD_DATA;
    if (pData != NULL) {
      pData->pSATHandle = this;
      pData->pRilHandle = m_pRilDevice;
      if (m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
        pData->fNoIcon = TRUE;
      else
        pData->fNoIcon = FALSE;
      pData->fIntelStyle = FALSE;

      (void)CloseHandle(CreateThread(NULL, 0, ActivateStkAudioThreadProc, (LPVOID)pData, 0, NULL));
    }
    else {
      // Fallback for the case the thread cannot be started.
      if (m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
        (void)QueueInternalCmd(HCCMD_STANDARD, m_pRilDevice, "AT^SSTR=32,4\r", CMDOPT_NONE, APIID_SENDSIMTOOLKITENVELOPECMD, 0, 0, 0, NULL);
      else
        (void)QueueInternalCmd(HCCMD_STANDARD, m_pRilDevice, "AT^SSTR=32,0\r", CMDOPT_NONE, APIID_SENDSIMTOOLKITENVELOPECMD, 0, 0, 0, NULL);
    }
  }
#endif

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseDisplayText(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nImmediateResp, nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTEXT*           pSatText;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_DISPLAYTEXT);
  m_nLastSATDisplayTextFlags = 0;

  // Parse: "<details>,<"text">,<immediateresponse>,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nImmediateResp, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams            = SIM_PARAM_SIMTEXT_FLAGS;
    if (nImmediateResp)           { pSatText->dwFlags |= SIMTEXT_IMMEDIATERESPONSE; m_nLastSATDisplayTextFlags = SIMTEXT_IMMEDIATERESPONSE;}
    if (nDetails & 0x01)          { pSatText->dwFlags |= SIMTEXT_HIGHPRIORITY; }
    if (!(nDetails & 0x80))       { pSatText->dwFlags |= SIMTEXT_DELAYCLEAR; }
    if (wcslen(wszText)) {
      pSatText->dwParams         |= SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatText->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatText->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTEXT));
      (void)wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatText->dwParams         |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
        pSatText->dwIconIdentifier  = nIconId;
        pSatText->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

    pSatCmd->cbSize += pSatText->cbSize;
    pSatCmd->dwDetailsSize = pSatText->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseGetInkey(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTEXT*           pSatText;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_GETINKEY);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams = SIM_PARAM_SIMTEXT_FLAGS;
    if (nDetails & 0x04) {
      pSatText->dwFlags |= SIMTEXT_YESNO;
    } else {
      if (!(nDetails & 0x01)) {
        pSatText->dwFlags |= SIMTEXT_KEYPADDIGITS;
      }
      if (!(nDetails & 0x02)) {
        pSatText->dwFlags |= SIMTEXT_GSMDEFAULTALPHABET;
      }
    }
    if (nDetails & 0x80) {
      pSatText->dwFlags |= SIMTEXT_HELPINFO;
    }
    if (wcslen(wszText)) {
      pSatText->dwParams         |= SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatText->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatText->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTEXT));
      (void)wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatText->dwParams         |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
        pSatText->dwIconIdentifier  = nIconId;
        pSatText->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

    pSatCmd->cbSize += pSatText->cbSize;
    pSatCmd->dwDetailsSize = pSatText->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseGetInput(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
UINT               nResponseMin, nResponseMax;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTEXT*           pSatText;
WCHAR              wszText[UCS2_LEN + 1], wszDefaultText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_GETINPUT);

  // Parse: "<details>,<"text">,<responsemin>,<responsemax>,<"defaulttext">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)                 ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nResponseMin, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nResponseMax, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUCS2String(szRsp, wszDefaultText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)           ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)                  ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams               = SIM_PARAM_SIMTEXT_FLAGS;
    if (!(nDetails & 0x01))          { pSatText->dwFlags |= SIMTEXT_KEYPADDIGITS; }
    if (!(nDetails & 0x02))          { pSatText->dwFlags |= SIMTEXT_GSMDEFAULTALPHABET; }
    if (nDetails & 0x04)             { pSatText->dwFlags |= SIMTEXT_NOECHO; }
    if (nDetails & 0x08)             { pSatText->dwFlags |= SIMTEXT_PACKEDRESPONSE; }
    if (nDetails & 0x80)             { pSatText->dwFlags |= SIMTEXT_HELPINFO; }
    pSatText->dwParams              |= SIM_PARAM_SIMTEXT_MINRESPONSE | SIM_PARAM_SIMTEXT_MAXRESPONSE,
    pSatText->dwMinResponse          = nResponseMin;
    pSatText->dwMaxResponse          = nResponseMax;
    if (wcslen(wszText)) {
      pSatText->dwParams            |= SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatText->dwTextSize           = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatText->dwTextOffset         = ROUNDTODWORD(sizeof(SIMTEXT));
      (void)wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwTextOffset), wszText);
    }
    if (wcslen(wszText)) {
      pSatText->dwParams            |= SIM_PARAM_SIMTEXT_DEFAULTTEXTSIZE | SIM_PARAM_SIMTEXT_DEFAULTTEXTOFFSET;
      pSatText->dwDefaultTextSize    = (wcslen(wszDefaultText) + 1) * sizeof(WCHAR);
      pSatText->dwDefaultTextOffset  = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);
      (void)wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwDefaultTextOffset), wszDefaultText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatText->dwParams            |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
        pSatText->dwIconIdentifier     = nIconId;
        pSatText->dwIconQualifier      = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatText->cbSize = ROUNDTODWORD3(sizeof(SIMTEXT), pSatText->dwTextSize, pSatText->dwDefaultTextSize);

    pSatCmd->cbSize += pSatText->cbSize;
    pSatCmd->dwDetailsSize = pSatText->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSelectItem(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               i, nCmd, nNumItems, nDetails, nItem, nDefaultItem;
UINT               nItemIconsPresent, nItemIconsQualifier, nTitleIconQualifier, nTitleIconId;
UINT               nNextActionId, nIconId;
DWORD              dwLen;
RILSIMTOOLKITCMD*  pSatCmd;
SIMMENU*           pSatMenu;
SIMMENUITEM*       pSatItem;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SELECTITEM);

  // Parse Title: "<details>,<numitems>,<"titletext">,<>defaultitem,<itemiconspresent>,<itemiconqualifier>,<titleiconqualifier>,<titleiconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nNumItems, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)     ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nDefaultItem, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsPresent, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconId, szRsp)         ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    // An item list without items is invalid
    if (!nNumItems) {
      (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
      fRet = FALSE;
    } else {
      pSatMenu = (SIMMENU*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

      pSatMenu->dwParams            = SIM_PARAM_SIMMENU_FLAGS | SIM_PARAM_SIMMENU_MENUITEMCOUNT |
                                      SIM_PARAM_SIMMENU_MENUITEMOFFSET | SIM_PARAM_SIMMENU_MENUITEMSIZE;
      if (nDetails & 0x80)          { pSatMenu->dwFlags = SIMMENU_HELPINFO; }
      if (wcslen(wszText)) {
        pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_TEXTSIZE | SIM_PARAM_SIMMENU_TEXTOFFSET;
        pSatMenu->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
        pSatMenu->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENU));
        (void)wcscpy((WCHAR*)((BYTE*)pSatMenu + pSatMenu->dwTextOffset), wszText);
      }
      if (nDefaultItem) {
        pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_DEFAULTITEM;
        pSatMenu->dwDefaultItem     = nDefaultItem;
      }
      if (nTitleIconId) {
        if (m_fApplicationCanDisplayIcons) {
          pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_ICONID | SIM_PARAM_SIMMENU_ICONQUALIFIER;
          pSatMenu->dwIconIdentifier  = nTitleIconId;
          pSatMenu->dwIconQualifier   = nTitleIconQualifier;
        }
        m_fLastCommandIncludedIcon = TRUE;
      }
      pSatMenu->dwMenuItemCount     = nNumItems;
      pSatMenu->dwMenuItemOffset    = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

      pSatMenu->cbSize = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

      pSatItem = (SIMMENUITEM*)((BYTE*)pSatMenu + pSatMenu->dwMenuItemOffset);

      for (i = 0; i < nNumItems; i++) {
        // Parse Item: "^SSTGI: <cmdtype>,<itemid>,"itemtext",<nextactionid>,<iconid>"
        if (!MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)    ||
            !ParseUInt(szRsp, FALSE, nCmd, szRsp)              ||
            !ParseRspParamSeparator(szRsp, szRsp)              ||
            !ParseUInt(szRsp, FALSE, nItem, szRsp)             ||
            !ParseRspParamSeparator(szRsp, szRsp)              ||
            !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
            !ParseRspParamSeparator(szRsp, szRsp)              ||
            !ParseUInt(szRsp, FALSE, nNextActionId, szRsp)     ||
            !ParseRspParamSeparator(szRsp, szRsp)              ||
            !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
            !ParseRspPostfix(szRsp, szRsp)) {
          (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
          fRet = FALSE;
          break;
        }

        dwLen = wcslen(wszText);
        if (dwLen) {
          dwLen = (dwLen + 1) * sizeof(WCHAR);
        }
        if (((BYTE*)pSatItem + ROUNDTODWORD2(sizeof(SIMMENUITEM), dwLen)) >= &(m_bCmdBuffer[SIMTK_MAX_LENGTH])) {
          // Our temporary buffer on the stack is too small
          (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
          fRet = FALSE;
          break;
        }

        pSatItem->dwParams            = SIM_PARAM_SIMMENUITEM_FLAGS | SIM_PARAM_SIMMENUITEM_IDENTIFIER;
        if (nDetails & 0x80)          { pSatItem->dwFlags = SIMMENU_HELPINFO; }
        pSatItem->dwIdentifier        = nItem;
        if (dwLen) {
          pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_TEXTSIZE | SIM_PARAM_SIMMENUITEM_TEXTOFFSET;
          pSatItem->dwTextSize        = dwLen;
          pSatItem->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENUITEM));
          (void)wcscpy((WCHAR*)((BYTE*)pSatItem + pSatItem->dwTextOffset), wszText);
        }
        if (nNextActionId) {
          pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_NEXTACTION;
          pSatItem->dwNextAction      = nNextActionId;
        }
        if (nIconId && nItemIconsPresent) {
          if (m_fApplicationCanDisplayIcons) {
            pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_ICONID | SIM_PARAM_SIMMENUITEM_ICONQUALIFIER;
            pSatItem->dwIconIdentifier  = nIconId;
            pSatItem->dwIconQualifier   = nItemIconsQualifier;
          }
          m_fLastCommandIncludedIcon = TRUE;
        }
        pSatItem->cbSize = ROUNDTODWORD2(sizeof(SIMMENUITEM), pSatItem->dwTextSize);

        pSatMenu->dwMenuItemSize += pSatItem->cbSize;

        pSatItem = (SIMMENUITEM*)((BYTE*)pSatItem + pSatItem->cbSize);
      }
      if (fRet) {
        pSatMenu->cbSize += pSatMenu->dwMenuItemSize;
        pSatCmd->cbSize += pSatMenu->cbSize;
        pSatCmd->dwDetailsSize = pSatMenu->cbSize;
      }
    }
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSetupMenu(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               i, nCmd, nNumItems, nDetails, nItem;
UINT               nItemIconsPresent, nItemIconsQualifier, nTitleIconQualifier, nTitleIconId;
UINT               nNextActionId, nIconId;
DWORD              dwLen;
RILSIMTOOLKITCMD*  pSatCmd;
SIMMENU*           pSatMenu;
SIMMENUITEM*       pSatItem;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SETUPMENU);

  // Parse Title: "<details>,<numitems>,<"titletext">,<itemiconspresent>,<itemiconqualifier>,<titleiconqualifier>,<titleiconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nNumItems, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)     ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsPresent, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconId, szRsp)         ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatMenu = (SIMMENU*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatMenu->dwParams            = SIM_PARAM_SIMMENU_FLAGS | SIM_PARAM_SIMMENU_MENUITEMCOUNT |
                                    SIM_PARAM_SIMMENU_MENUITEMOFFSET | SIM_PARAM_SIMMENU_MENUITEMSIZE;
    if (nDetails & 0x80)          { pSatMenu->dwFlags = SIMMENU_HELPINFO; }
    if (wcslen(wszText)) {
      pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_TEXTSIZE | SIM_PARAM_SIMMENU_TEXTOFFSET;
      pSatMenu->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatMenu->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENU));
      (void)wcscpy((WCHAR*)((BYTE*)pSatMenu + pSatMenu->dwTextOffset), wszText);
    }
    if (nTitleIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_ICONID | SIM_PARAM_SIMMENU_ICONQUALIFIER;
        pSatMenu->dwIconIdentifier  = nTitleIconId;
        pSatMenu->dwIconQualifier   = nTitleIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatMenu->dwMenuItemCount     = nNumItems;
    pSatMenu->dwMenuItemOffset    = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

    pSatMenu->cbSize = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

    pSatItem = (SIMMENUITEM*)((BYTE*)pSatMenu + pSatMenu->dwMenuItemOffset);

    for (i = 0; i < nNumItems; i++) {
      // Parse Item: "^SSTGI: <cmdtype>,<itemid>,"itemtext",<nextactionid>,<iconid>"
      if (!MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)    ||
          !ParseUInt(szRsp, FALSE, nCmd, szRsp)              ||
          !ParseRspParamSeparator(szRsp, szRsp)              ||
          !ParseUInt(szRsp, FALSE, nItem, szRsp)             ||
          !ParseRspParamSeparator(szRsp, szRsp)              ||
          !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
          !ParseRspParamSeparator(szRsp, szRsp)              ||
          !ParseUInt(szRsp, FALSE, nNextActionId, szRsp)     ||
          !ParseRspParamSeparator(szRsp, szRsp)              ||
          !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
          !ParseRspPostfix(szRsp, szRsp)) {
        (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
        fRet = FALSE;
        break;
      }

      dwLen = wcslen(wszText);
      if (dwLen) {
        dwLen = (dwLen + 1) * sizeof(WCHAR);
      }
      if (((BYTE*)pSatItem + ROUNDTODWORD2(sizeof(SIMMENUITEM), dwLen)) >= &(m_bCmdBuffer[SIMTK_MAX_LENGTH])) {
        // Our temporary buffer on the stack is too small
        (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_COMMANDDATA);
        fRet = FALSE;
        break;
      }

      pSatItem->dwParams            = SIM_PARAM_SIMMENUITEM_FLAGS | SIM_PARAM_SIMMENUITEM_IDENTIFIER;
      if (nDetails & 0x80)          { pSatItem->dwFlags = SIMMENU_HELPINFO; }
      pSatItem->dwIdentifier        = nItem;
      if (dwLen) {
        pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_TEXTSIZE | SIM_PARAM_SIMMENUITEM_TEXTOFFSET;
        pSatItem->dwTextSize        = dwLen;
        pSatItem->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENUITEM));
        (void)wcscpy((WCHAR*)((BYTE*)pSatItem + pSatItem->dwTextOffset), wszText);
      }
      if (nNextActionId) {
        pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_NEXTACTION;
        pSatItem->dwNextAction      = nNextActionId;
      }
      if (nIconId && nItemIconsPresent) {
        if (m_fApplicationCanDisplayIcons) {
          pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_ICONID | SIM_PARAM_SIMMENUITEM_ICONQUALIFIER;
          pSatItem->dwIconIdentifier  = nIconId;
          pSatItem->dwIconQualifier   = nItemIconsQualifier;
        }
        m_fLastCommandIncludedIcon = TRUE;
      }
      pSatItem->cbSize = ROUNDTODWORD2(sizeof(SIMMENUITEM), pSatItem->dwTextSize);

      pSatMenu->dwMenuItemSize += pSatItem->cbSize;

      pSatItem = (SIMMENUITEM*)((BYTE*)pSatItem + pSatItem->cbSize);
    }
    if (fRet) {
      pSatMenu->cbSize += pSatMenu->dwMenuItemSize;
      pSatCmd->cbSize += pSatMenu->cbSize;
      pSatCmd->dwDetailsSize = pSatMenu->cbSize;
    }
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseIdleText(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMTEXT*           pSatText;
WCHAR              wszText[UCS2_LEN + 1];
DWORD              dwMaxTextLen = 255;
BOOL               fRet = TRUE;

  // Read maximum text len for Setup Idle Mode Test
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SATmaxIdleModeTextLen"), &dwMaxTextLen);

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SETUPIDLEMODETEXT);
  m_fIgnoreNextSSTR40 = FALSE;

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszText) > dwMaxTextLen && dwMaxTextLen > 0 && dwMaxTextLen < UCS2_LEN) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Shorten Idle Mode Text from %d characters to %d characters"), wcslen(wszText), dwMaxTextLen));
        wszText[dwMaxTextLen] = 0;
    }
    if (wcslen(wszText)) {
      pSatText->dwParams          = SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatText->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatText->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTEXT));
      (void)wcscpy((WCHAR*)((BYTE*)pSatText + pSatText->dwTextOffset), wszText);
      SetIdleModeTextPresent(TRUE);
    }
    else {
      SetIdleModeTextPresent(FALSE);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatText->dwParams         |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
        pSatText->dwIconIdentifier  = nIconId;
        pSatText->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

    pSatCmd->cbSize += pSatText->cbSize;
    pSatCmd->dwDetailsSize = pSatText->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseRunATNotification(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMRUNATCMD*       pSatATCmd;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_RUNATCOMMAND);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatATCmd = (SIMRUNATCMD*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszText)) {
      pSatATCmd->dwParams          = SIM_PARAM_SIMRUNATCMD_TEXTSIZE | SIM_PARAM_SIMRUNATCMD_TEXTOFFSET;
      pSatATCmd->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatATCmd->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTEXT));
      (void)wcscpy((WCHAR*)((BYTE*)pSatATCmd + pSatATCmd->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatATCmd->dwParams         |= SIM_PARAM_SIMRUNATCMD_ICONID | SIM_PARAM_SIMRUNATCMD_ICONQUALIFIER;
        pSatATCmd->dwIconIdentifier  = nIconId;
        pSatATCmd->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatATCmd->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatATCmd->dwTextSize);

    pSatCmd->cbSize += pSatATCmd->cbSize;
    pSatCmd->dwDetailsSize = pSatATCmd->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseLanguageNotification(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails;
RILSIMTOOLKITCMD*  pSatCmd;
SIMLANGUAGE*       pSatLanguage;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_LANGUAGENOTIFICATION);

  // Parse: "<details>,<"text">
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatLanguage = (SIMLANGUAGE*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszText)) {
      pSatLanguage->dwParams          = SIM_PARAM_SIMLANGUAGE_LANGUAGE;
      (void)wcsncpyz(pSatLanguage->lpszLanguage, wszText, MAXLEN_LANGUAGE);
    }
    pSatLanguage->cbSize = ROUNDTODWORD(sizeof(SIMLANGUAGE));

    pSatCmd->cbSize += pSatLanguage->cbSize;
    pSatCmd->dwDetailsSize = pSatLanguage->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseBIPOpenChannelNotification(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMOPENCHANNEL*    pSatOpenChannel;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_OPENCHANNEL);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatOpenChannel = (SIMOPENCHANNEL*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszText)) {
      pSatOpenChannel->dwParams          = SIM_PARAM_SIMOPENCHANNEL_TEXTSIZE| SIM_PARAM_SIMOPENCHANNEL_TEXTOFFSET;
      pSatOpenChannel->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatOpenChannel->dwTextOffset      = ROUNDTODWORD(sizeof(SIMOPENCHANNEL));
      (void)wcscpy((WCHAR*)((BYTE*)pSatOpenChannel + pSatOpenChannel->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatOpenChannel->dwParams         |= SIM_PARAM_SIMOPENCHANNEL_ICONID | SIM_PARAM_SIMOPENCHANNEL_ICONQUALIFIER;
        pSatOpenChannel->dwIconIdentifier  = nIconId;
        pSatOpenChannel->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatOpenChannel->cbSize = ROUNDTODWORD2(sizeof(SIMOPENCHANNEL), pSatOpenChannel->dwTextSize);

    pSatCmd->cbSize += pSatOpenChannel->cbSize;
    pSatCmd->dwDetailsSize = pSatOpenChannel->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseBIPCloseChannelNotification(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMCLOSECHANNEL*   pSatCloseChannel;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_CLOSECHANNEL);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatCloseChannel = (SIMCLOSECHANNEL*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszText)) {
      pSatCloseChannel->dwParams          = SIM_PARAM_SIMTEXT_TEXTSIZE | SIM_PARAM_SIMTEXT_TEXTOFFSET;
      pSatCloseChannel->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatCloseChannel->dwTextOffset      = ROUNDTODWORD(sizeof(SIMCLOSECHANNEL));
      (void)wcscpy((WCHAR*)((BYTE*)pSatCloseChannel + pSatCloseChannel->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatCloseChannel->dwParams         |= SIM_PARAM_SIMTEXT_ICONID | SIM_PARAM_SIMTEXT_ICONQUALIFIER;
        pSatCloseChannel->dwIconIdentifier  = nIconId;
        pSatCloseChannel->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatCloseChannel->cbSize = ROUNDTODWORD2(sizeof(SIMCLOSECHANNEL), pSatCloseChannel->dwTextSize);

    pSatCmd->cbSize += pSatCloseChannel->cbSize;
    pSatCmd->dwDetailsSize = pSatCloseChannel->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseBIPReceiveDataNotification(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMRECEIVEDATA*    pSatReceiveData;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_RECEIVEDATA);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatReceiveData = (SIMRECEIVEDATA*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszText)) {
      pSatReceiveData->dwParams          = SIM_PARAM_SIMRECEIVEDATA_TEXTSIZE | SIM_PARAM_SIMRECEIVEDATA_TEXTOFFSET;
      pSatReceiveData->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatReceiveData->dwTextOffset      = ROUNDTODWORD(sizeof(SIMRECEIVEDATA));
      (void)wcscpy((WCHAR*)((BYTE*)pSatReceiveData + pSatReceiveData->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatReceiveData->dwParams         |= SIM_PARAM_SIMRECEIVEDATA_ICONID | SIM_PARAM_SIMRECEIVEDATA_ICONQUALIFIER;
        pSatReceiveData->dwIconIdentifier  = nIconId;
        pSatReceiveData->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatReceiveData->cbSize = ROUNDTODWORD2(sizeof(SIMRECEIVEDATA), pSatReceiveData->dwTextSize);

    pSatCmd->cbSize += pSatReceiveData->cbSize;
    pSatCmd->dwDetailsSize = pSatReceiveData->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseBIPSendDataNotification(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT               nDetails, nIconQualifier, nIconId;
RILSIMTOOLKITCMD*  pSatCmd;
SIMSENDDATA*       pSatSendData;
WCHAR              wszText[UCS2_LEN + 1];
BOOL               fRet = TRUE;

  (void)PrepareRilCmdStruct(m_bCmdBuffer, &pSatCmd, SIM_NOTIFY_SENDDATA);

  // Parse: "<details>,<"text">,<iconqualifier>,<iconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUCS2String(szRsp, wszText, UCS2_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)              ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    (void)PrepareRilCmdError(pSatCmd, SIM_RESPONSE_ERR_VALUESMISSING);
    fRet = FALSE;
  } else {
    pSatSendData = (SIMSENDDATA*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszText)) {
      pSatSendData->dwParams          = SIM_PARAM_SIMSENDDATA_TEXTSIZE | SIM_PARAM_SIMSENDDATA_TEXTOFFSET;
      pSatSendData->dwTextSize        = (wcslen(wszText) + 1) * sizeof(WCHAR);
      pSatSendData->dwTextOffset      = ROUNDTODWORD(sizeof(SIMSENDDATA));
      (void)wcscpy((WCHAR*)((BYTE*)pSatSendData + pSatSendData->dwTextOffset), wszText);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatSendData->dwParams         |= SIM_PARAM_SIMSENDDATA_ICONID | SIM_PARAM_SIMSENDDATA_ICONQUALIFIER;
        pSatSendData->dwIconIdentifier  = nIconId;
        pSatSendData->dwIconQualifier   = nIconQualifier;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatSendData->cbSize = ROUNDTODWORD2(sizeof(SIMSENDDATA), pSatSendData->dwTextSize);

    pSatCmd->cbSize += pSatSendData->cbSize;
    pSatCmd->dwDetailsSize = pSatSendData->cbSize;
  }

  // Notify the SIM manager of the SAT command
  if (!HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob , m_bCmdBuffer, pSatCmd->cbSize)) {
    fRet = FALSE;
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Thread which sends a SAT command with delay.
//
//////////////////////////////////////////////////////////////////////////////
static DWORD WINAPI SendSATCmdWithDelayThreadProc(LPVOID lpParameter)
{
  SAT_DELAY_THREAD_DATA* pSATData = (SAT_DELAY_THREAD_DATA*)lpParameter;
  RILSIMTOOLKITRSP Rsp;

  if (pSATData == NULL)
    return 0;

  Sleep(pSATData->dwDelay);

  memset(&Rsp, 0, sizeof(RILSIMTOOLKITRSP));
  Rsp.cbSize = sizeof(RILSIMTOOLKITRSP);
  Rsp.dwParams = RIL_PARAM_SIMTKIT_RSP_TYPE | RIL_PARAM_SIMTKIT_RSP_RESPONSE;
  Rsp.dwType = pSATData->dwResponse;
  Rsp.dwResponse = SIM_RESPONSE_OK;
  if (INTEL_STYLE_SAT) {
    if (FAILED(pSATData->pSATHandle->SendCmdResponseIntel(NULL, &Rsp, NULL, 0)))
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: RequeueThreadProc() is not able to send command\r\n")));
  }
  else {
    if (FAILED(pSATData->pSATHandle->SendCmdResponse(NULL, &Rsp, NULL, 0)))
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: RequeueThreadProc() is not able to send command\r\n")));
  }

  delete pSATData;

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Sends a command response with delay. This is needed as a workaround for Microsoft's
// SAT application, which doesn't send certain SAT commands
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::SendCmdResponseWithDelay(CSimToolkitHandling*  pSATHandle, DWORD dwResponse, DWORD dwDelay) const
{
  SAT_DELAY_THREAD_DATA *pSATData = NULL;
  HANDLE hThread;
  BOOL fRet = FALSE;

  if (!pSATHandle)
    goto Error;

  if (dwDelay == 0) {
    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("STKAutoCmdDelay"), &dwDelay))
      dwDelay = SAT_CMD_DELAY_DEFAULT;         // Default timeout is 3 seconds.
  }

  if (dwDelay == 0) {     // If registry key is set to 0, this workaround is disabled.
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SendCmdResponseWithDelay() is disabled\r\n")));
    fRet = TRUE;
    goto Error;
  }

  pSATData = new SAT_DELAY_THREAD_DATA;

  if (pSATData == NULL)
    goto Error;

  pSATData->dwDelay = dwDelay;
  pSATData->dwResponse = dwResponse;
  pSATData->pSATHandle = pSATHandle;

  hThread = CreateThread(NULL, 0, SendSATCmdWithDelayThreadProc, (LPVOID)pSATData, 0, NULL);
  if (!hThread)
     goto Error;
  (void)CloseHandle(hThread);

   fRet = TRUE;

Error:

  if (!fRet && pSATData != NULL)
    delete pSATData;

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to parse the response to a SIM-Toolkit command.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::ParseGetCommand(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
UINT                  nCmd;
CSimToolkitHandling*  pInstance = (CSimToolkitHandling*)pParam;
HRESULT               hr = S_OK;

  pBlob = 0;
  cbBlob = 0;

  if (!pInstance) {
    return E_FAIL;
  }

  pInstance->m_fNoResponse = FALSE;
  pInstance->m_nLastSATSetCallDetail = 0;
  pInstance->m_fLastCommandIncludedIcon = FALSE;
  pInstance->m_fLastSetupCallNo = FALSE;
  memset(pInstance->m_szLastSetupCallNo, 0, MAX_ATCMD_LEN);

  // Parse "<prefix>^SSTGI: <cmdtype>"
  if (!ParseRspPrefix(szRsp, szRsp)                    ||
      !MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)  ||
      !ParseUInt(szRsp, FALSE, nCmd, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)) {
    return E_FAIL;
  }

  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: ParseGetCommand: %d\r\n"), nCmd));

  EnterCriticalSection(&(pInstance->m_csLockBuffer));

  switch (nCmd) {
    case SIMTK_CMD_REFRESH:
      if (!pInstance->ParseRefresh(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - REFRESH command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_EVENTLIST:
      if (!pInstance->ParseSetupEventList(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SETUP_EVENTLIST command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_CALL:
      if (!pInstance->ParseSetupCall(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SETUP CALL command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SEND_SS:
      if (!pInstance->ParseSendSS(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SEND SS command format corrupt\r\n")));
        hr = E_FAIL;
      } else {
        // Because the MMI isn't calling back the RIL with the SAT response we have to generate it on our own
        if (!pInstance->SendCmdResponseWithDelay(pInstance, SIM_NOTIFY_SENDSS)) {
          hr = E_FAIL;
        }
      }
      break;

    case SIMTK_CMD_SEND_USSD:
      if (!pInstance->ParseSendUSSD(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SEND USSD command format corrupt\r\n")));
        hr = E_FAIL;
      } else {
        // Because the MMI isn't calling back the RIL with the SAT response we have to generate it on our own
        if (!pInstance->SendCmdResponseWithDelay(pInstance, SIM_NOTIFY_SENDUSSD)) {
          hr = E_FAIL;
        }
      }
      break;

    case SIMTK_CMD_SEND_SMS:
      if (!pInstance->ParseSendSMS(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SEND SMS command format corrupt\r\n")));
        hr = E_FAIL;
      } else {
        // Because the MMI isn't calling back the RIL with the SAT response we have to generate it on our own
        if (!pInstance->SendCmdResponseWithDelay(pInstance, SIM_NOTIFY_SENDSMS)) {
          hr = E_FAIL;
        }
      }
      break;

    case SIMTK_CMD_SEND_DTMF:
      if (!pInstance->ParseSendDTMF(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SEND DTMF command format corrupt\r\n")));
        hr = E_FAIL;
      } else {
        // To get the MMI handle the DTMF command correctly we have to generate our own success response
        if (!pInstance->SendCmdResponseWithDelay(pInstance, SIM_NOTIFY_SENDDTMF)) {
          hr = E_FAIL;
        }
      }
      break;

    case SIMTK_CMD_LAUNCH_BROWSER:
      if (!pInstance->ParseLaunchBrowser(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - LAUNCH BROWSER command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_PLAY_TONE:
      if (!pInstance->ParsePlayTone(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - PLAY TONE command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_DISPLAY_TEXT:
      if (!pInstance->ParseDisplayText(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit - DISPLAY TEXT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_GET_INKEY:
      if (!pInstance->ParseGetInkey(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit - GET INKEY command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_GET_INPUT:
      if (!pInstance->ParseGetInput(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - GET INPUT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SELECT_ITEM:
      if (!pInstance->ParseSelectItem(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SELECT ITEM command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_MENU:
      if (!pInstance->ParseSetupMenu(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SETUP MENU command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_IDLE_TEXT:
      if (!pInstance->ParseIdleText(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - SETUP IDLETEXT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_RUN_AT_CMD:
      if (!pInstance->ParseRunATNotification(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - RUN AT COMMAND command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_LANGUAGE_NOTIFICATION:
      if (!pInstance->ParseLanguageNotification(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - RUN AT COMMAND command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_OPEN_CHANNEL:
      if (!pInstance->ParseBIPOpenChannelNotification(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - BIP command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_CLOSE_CHANNEL:
      if (!pInstance->ParseBIPCloseChannelNotification(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - BIP command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_RECIEVE_DATA:
      if (!pInstance->ParseBIPReceiveDataNotification(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - BIP command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SEND_DATA:
      if (!pInstance->ParseBIPSendDataNotification(szRsp, pBlob, cbBlob)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - BIP command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_GET_ICON_DATA:
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - Unsupported SAT command: GET ICON DATA\r\n")));
      hr = E_FAIL;
      break;

    default:
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - Unknown SAT command (%i)\r\n"), nCmd));
      hr = E_FAIL;
      break;
  }

  LeaveCriticalSection(&(pInstance->m_csLockBuffer));

  // Check if anything went wrong
  if (FAILED(hr)) {
    // Try to bring the module back into a proper state
    char szCmd[32];
    (void)_snprintfz(szCmd, 32, "AT^SSTR=%d,32\r", nCmd);
    if (!QueueInternalCmd(HCCMD_URCPORT_ONLY, pInstance->m_pRilDevice, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY, ParseRspOK)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - Failed to queue cancel cmd (%i)\r\n"), nCmd));
    }
    if (!QueueInternalCmd(HCCMD_URCPORT_ONLY, pInstance->m_pRilDevice, "AT^SSTR=254\r", CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - Failed to queue quit cmd\r\n")));
    }
  }

  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Send the response to a Sim-Toolkit event.
//
// Params:
//  pHandle    : Pointer to CRilInstanceHandle to be used for the operation.
//  lpbResponse: The response to send to the module.
//  dwSize     : The soze of the response.
//
// Return:
//  S_OK on successs, an error code otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::SendCmdResponse(CRilInstanceHandle* pHandle, const RILSIMTOOLKITRSP* pRsp, LPBYTE pDetails, const DWORD dwDetailsSize) {
SIMTKITRSPITEM*    pItemDetails;
SIMTKITRSPTEXT*    pTextDetails;
LPWSTR             wszText;
BOOL               fEmpty;
DWORD              dwId;
DWORD              dwCmdOpt = CMDOPT_NONE;
DWORD              dwResponse;
UINT               i;
char               szCmd[MAX_ATCMD_LEN];
char               szUCS2[5];
HRESULT            hr = S_OK;
CNotificationData* pnd = NULL;

  // Check some input conditions
  if (!(pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_TYPE) || !(pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_RESPONSE)) {
    return E_INVALIDARG;
  }

  // Check if we have to suppress the response
  if (m_fNoResponse) {
    if (pHandle) {
      if (!QueueCmd(HCCMD_STANDARD, pHandle, NULL, CMDOPT_NOOP, APIID_SENDSIMTOOLKITCMDRESPONSE, NULL, NULL, hr)) {
        return E_FAIL;
      }
      return hr;
    }
    else {
      return S_OK;
    }
  }

  // Check the additional info field
  dwResponse = pRsp->dwResponse;
  if ((pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_ADDITIONALINFO) && (dwResponse == SIM_RESPONSE_ERR_MOBILEUNABLE)) {
    if (pRsp->dwAdditionalInfo == SIM_RESPONSE_ERR_MOBILEUNABLE_SCREENBUSY) {
      dwResponse = SIMTK_RSP_SCREEN_BUSY;
    }
  }

  memset(szCmd, 0, MAX_ATCMD_LEN);
  // Check the command and build up the appropriate response.
  switch (pRsp->dwType) {
    case SIM_NOTIFY_SETUPCALL:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: SETUP CALL command response\r\n")));
      switch (dwResponse) {
        case SIM_RESPONSE_OK:
          // Currently the MMI must handle the call -> simply tell module to terminate SIM session
          dwResponse = SIM_RESPONSE_OK_ENDSESSION;
          break;
        case SIM_RESPONSE_OK_NORESPONSE:
          // For unknown reason the "no response" response is not accepted by module SAT interface
          // -> Tell module that the call has been rejected in this case
          dwResponse = SIM_RESPONSE_ERR_CALLSETUPREJECTED;
          break;
        default:
          // Ignore the rest
          break;
      }
      if (NEW_SAT_SSTR_PARAMETERS && (pRsp->dwParams & RIL_PARAM_SIMTKIT_RSP_ADDITIONALINFO) && pRsp->dwAdditionalInfo == SIM_RESPONSE_ERR_MOBILEUNABLE_BUSYONCALL) {
        // Workaround for GCF 27.22.4.13.1 Seq1.6: the module show SIMCALL_IDLE, but expects, that
        // the MMI response with SSTR=16,0, even when a call is active. So the RIL must ignore the next
        // SSTR=16,32 and send SSTR=16,32,,,2 instead, when a call is active.
        // Workaround for GCF 27.22.4.13.1 Seq1.7: the module shows SIMCALL_HOLDCALLS, but expects,
        // the MMI response with SSTR=16,33,,,0, even when it is not possible to put the call on hold.
        if ((m_fIgnoreNextSSTR1616 && dwResponse == SIM_RESPONSE_OK_ENDSESSION) || (m_fIgnoreNextSSTR1616 && m_fIgnoreNextSSTR1632))
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT\r");           // The AT^SSTR=16,0 command had alrfeady been sent in RILDrv_Dial().
        else if (dwResponse == SIM_RESPONSE_ERR_MOBILEUNABLE && m_nLastSATSetCallDetail == SIMCALL_IDLE)
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=16,32,,,2\r");
        else if (dwResponse == SIM_RESPONSE_ERR_MOBILEUNABLE && m_nLastSATSetCallDetail == SIMCALL_HOLDCALLS)
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=16,33,,,0\r");
        else
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=16,%d\r", dwResponse);
      }
      else {
        // Compose the call setup response
        if ((m_fIgnoreNextSSTR1616 && dwResponse == SIM_RESPONSE_OK_ENDSESSION) || (m_fIgnoreNextSSTR1616 && m_fIgnoreNextSSTR1632))
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT\r");           // The AT^SSTR=16,0 command had alrfeady been sent in RILDrv_Dial().
        else if (m_fIgnoreNextSSTR1632 && dwResponse == SIM_RESPONSE_ERR_MOBILEUNABLE && WA_FOR_SAT_SETUP_CALL_CMD)
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=16,0\r");     // Workaround for GCF: the SAT inside the module isn't able to handle AT^SSTR=16,32 correctly, to the RIL mus send AT^SSTR=16,0 instead.
        else
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=16,%d\r", dwResponse);
      }
      break;

    case SIM_NOTIFY_SELECTITEM:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: SELECT ITEM command response\r\n")));
      // Get the item id if available.
      dwId = 0;
      if (pDetails && (dwDetailsSize == sizeof(SIMTKITRSPITEM))) {
        pItemDetails = (SIMTKITRSPITEM*)pDetails;
        if (pItemDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_ITEM_ID) {
          dwId = pItemDetails->dwId;
        }
      }
      // Check some input conditions
      if ((dwResponse == SIM_RESPONSE_OK) && !dwId) {
        dwResponse = SIM_RESPONSE_ERR_MOBILEUNABLE;
        hr = E_INVALIDARG;
      }
      if (dwResponse == SIM_RESPONSE_OK && m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
        dwResponse = SIMTK_RSP_OK_NO_ICON;

      // Compose the select item response
      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=36,%d,%d\r", dwResponse, dwId);
      break;

    case SIM_NOTIFY_GETINKEY:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: GET INKEY command response\r\n")));
      fEmpty = TRUE;
      // Check that the details has the proper size.
      if (!pDetails || (dwDetailsSize < sizeof(SIMTKITRSPTEXT))) {
        // Send error message
        if (dwResponse == SIM_RESPONSE_OK) {
          dwResponse = SIM_RESPONSE_ERR_MOBILEUNABLE;
        }
        hr = E_INVALIDARG;
      } else {
        pTextDetails = (SIMTKITRSPTEXT*)pDetails;
        if (dwResponse == SIM_RESPONSE_OK && m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
          dwResponse = SIMTK_RSP_OK_NO_ICON;
        // Compose the Input response
        if (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_YESNO) {
          // Yes/no answer
          fEmpty = FALSE;
          if (pTextDetails->dwYesNo) {
            // Send "Y"
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=34,%d,,\"0059\"\r", dwResponse);
          } else {
            // Send "N"
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=34,%d,,\"004E\"\r", dwResponse);
          }
        } else {
          // Check that the details has the proper size.
          if ((pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTOFFSET) &&
              (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTSIZE) &&
              (pTextDetails->dwTextSize >= sizeof(WCHAR))) {
            if (dwDetailsSize < (sizeof(SIMTKITRSPTEXT) + sizeof(WCHAR))) {
              // Send error message
              if (dwResponse == SIM_RESPONSE_OK || dwResponse == SIMTK_RSP_OK_NO_ICON) {
                dwResponse = SIM_RESPONSE_ERR_MOBILEUNABLE;
              }
              hr = E_INVALIDARG;
            } else {
              // Normal answer -> send the key
              wszText = (LPWSTR)((LPBYTE)pTextDetails + pTextDetails->dwTextOffset);
              if (wszText[0]) {
                fEmpty = FALSE;
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=34,%d,,\"%0.4X\"\r", dwResponse, wszText[0]);
              }
            }
          }
        }
      }
      if (fEmpty) {
        // Send an empty string (PTCRB 27.22.4.3.1 requires an <Esc> here)
        if (dwResponse == SIM_RESPONSE_OK || dwResponse == SIMTK_RSP_OK_NO_ICON)
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=34,%d,,\"\\1b\"\r", dwResponse);
        else
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=34,%d\r", dwResponse);
      }
      break;

    case SIM_NOTIFY_GETINPUT:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: GET INPUT command response\r\n")));
      fEmpty = TRUE;
      // Check that the details is the proper size.
      if (!pDetails || (dwDetailsSize < sizeof(SIMTKITRSPTEXT))) {
        // Send error message
        if (dwResponse == SIM_RESPONSE_OK) {
          dwResponse = SIM_RESPONSE_ERR_MOBILEUNABLE;
        }
        hr = E_INVALIDARG;
      } else {
        pTextDetails = (SIMTKITRSPTEXT*)pDetails;
        if (dwResponse == SIM_RESPONSE_OK && m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
          dwResponse = SIMTK_RSP_OK_NO_ICON;
        // Set the text if necessary.
        if ((pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTOFFSET) &&
            (pTextDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_TEXT_TEXTSIZE) &&
            (pTextDetails->dwTextSize > 0)) {
          wszText = (LPWSTR)((LPBYTE)pTextDetails + pTextDetails->dwTextOffset);
          // Compose the Input response
          if (wcslen(wszText)) {
            fEmpty = FALSE;
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=35,%d,,\"", dwResponse);
            for (i = 0; i < min((pTextDetails->dwTextSize / sizeof(WCHAR)), wcslen(wszText)); i++) {
              (void)_snprintfz(szUCS2, 5, "%0.4X", wszText[i]);
              (void)strncat(szCmd, szUCS2, max(0, (MAX_ATCMD_LEN - strlen(szCmd)) - 1));
            }
            (void)strncat(szCmd, "\"\r", max(0, (MAX_ATCMD_LEN - strlen(szCmd)) -1));
          }
        }
      }
      if (fEmpty) {
        // Send an empty string (PTCRB 27.22.4.3.1 requires an <Esc> here)
        if (dwResponse == SIM_RESPONSE_OK || dwResponse == SIMTK_RSP_OK_NO_ICON)
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=35,%d,,\"\\1b\"\r", dwResponse);
        else
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=35,%d\r", dwResponse);
      }
      break;

    case SIM_NOTIFY_PLAYTONE:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: PLAY TONE command response\r\n")));
      if (dwResponse == SIM_RESPONSE_OK && m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
        dwResponse = SIMTK_RSP_OK_NO_ICON;
#ifdef SAT_PLAY_TONE_OLD_STYLE
      if (dwResponse == SIM_RESPONSE_OK || dwResponse == SIMTK_RSP_OK_NO_ICON)
        dwCmdOpt = CMDOPT_NOOP;     // The AT command is already running, so there is no need to send it again.
      else
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=32,%d\r", dwResponse);

      if (dwResponse == SIM_RESPONSE_OK_ENDSESSION) {
        // Special case PLAY TONE command, in case the play tone command is
        // already running, the RIL must not send a new command, instead it must
        // abort the current one.
        CCommand *pCmd;

        if (pHandle)
          pCmd = pHandle->GetDevice()->GetCurrentCommand();
        else
          pCmd = m_pRilDevice->GetCurrentCommand();
        if (pCmd != NULL) {
          char *szRunningCmd;

          szRunningCmd = pCmd->GetCmd();
          if (szRunningCmd != NULL) {
            if (strcmp(szRunningCmd, "AT^SSTR=32,0\r") == 0 || strcmp(szRunningCmd, "AT^SSTR=32,4\r") == 0) {
                dwCmdOpt = CMDOPT_NOOP;
                if (pHandle)
                  pHandle->GetDevice()->AbortRunningCommand();
                else
                  m_pRilDevice->AbortRunningCommand();
            }
          }
        }
      }
#else
      if (dwResponse == SIM_RESPONSE_OK || dwResponse == SIMTK_RSP_OK_NO_ICON)
        SetSATPlayToneAudioMode();     // Set audio mode, if necessary.

      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=32,%d\r", dwResponse);
#endif
      break;

    case SIM_NOTIFY_DISPLAYTEXT:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: DISPLAY TEXT command response\r\n")));
      if (dwResponse == SIM_RESPONSE_OK && m_nLastSATDisplayTextFlags == SIMTEXT_IMMEDIATERESPONSE) {
        DWORD dwDelay = 0;

        if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("STKDisplayTextCmdDelay"), &dwDelay))
          dwDelay = SAT_CMD_DELAY_DEFAULT;         // Default timeout is 3 seconds.

        if (dwDelay == 0) {
          if (dwResponse == SIM_RESPONSE_OK && m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
            dwResponse = SIMTK_RSP_OK_NO_ICON;
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=33,%d\r", dwResponse);
        }
        else {
          (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT\r");
          (void)SendCmdResponseWithDelay(this, SIM_NOTIFY_DISPLAYTEXT, dwDelay);
        }
      }
      else {
        if (dwResponse == SIM_RESPONSE_OK && m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
          dwResponse = SIMTK_RSP_OK_NO_ICON;
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=33,%d\r", dwResponse);
      }
      m_nLastSATDisplayTextFlags  = 0;
      break;

    case SIM_NOTIFY_SETUPIDLEMODETEXT:
       if (m_fIgnoreNextSSTR40) {
         m_fIgnoreNextSSTR40 = FALSE;
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: Response not necessary (%i, %d)\r\n"),  pRsp->dwType, dwResponse));
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT\r");
        //dwCmdOpt = CMDOPT_NOOP;
        pnd = new CNotificationData;
        if (pnd) {
          if (!pnd->InitFromRealBlob(RIL_NOTIFY_SIMTOOLKITSESSIONEND, NULL, 0)) {
            delete pnd;
            pnd = NULL;
          }
        }
        break;
       }
      // Fall through to handler for default command responses.
    case SIM_NOTIFY_REFRESH:
    case SIM_NOTIFY_SETUPMENU:
      // If automatic response mode is active, the RIL already has sent the response,
      // so now the RIL sends only a simple AT instead of the SAT command.
      if (m_fAutomaticSATResponse) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: Response already sent automatically (%i, %d)\r\n"),  pRsp->dwType, dwResponse));
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT\r");
        dwCmdOpt = CMDOPT_NOOP;
        break;
      }
      // The SAT application might give a user response, which doesn't apply here.
      if (dwResponse >= SIM_RESPONSE_OK_ENDSESSION || dwResponse <= SIM_RESPONSE_OK_HELP)
        dwResponse = SIM_RESPONSE_OK;
      // Fall through to handler for default command responses.
    case SIM_NOTIFY_EVENTLIST:
    case SIM_NOTIFY_SENDSS:
    case SIM_NOTIFY_SENDUSSD:
    case SIM_NOTIFY_SENDSMS:
    case SIM_NOTIFY_SENDDTMF:
    case SIM_NOTIFY_LAUNCHBROWSER:
    case SIM_NOTIFY_RUNATCOMMAND:
    case SIM_NOTIFY_LANGUAGENOTIFICATION:
    case SIM_NOTIFY_OPENCHANNEL:
    case SIM_NOTIFY_CLOSECHANNEL:
    case SIM_NOTIFY_SENDDATA:
    case SIM_NOTIFY_RECEIVEDATA:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: Default command response (%i)\r\n"),  pRsp->dwType));
      if (dwResponse == SIM_RESPONSE_OK && m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
        dwResponse = SIMTK_RSP_OK_NO_ICON;
      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=%d,%d\r", pRsp->dwType, dwResponse);
      break;

    case SIM_NOTIFY_SETUPMENU_REPLY:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: SETUP MENU command event\r\n")));
      // Get the item id if available.
      dwId = 0;
      if (pDetails && (dwDetailsSize == sizeof(SIMTKITRSPITEM))) {
        pItemDetails = (SIMTKITRSPITEM*)pDetails;
        if (pItemDetails->dwParams & RIL_PARAM_SIMTKIT_RSP_DETAILS_ITEM_ID) {
          dwId = pItemDetails->dwId;
        }
      }
      // Check some input conditions
      if ((dwResponse != SIM_RESPONSE_OK) && (dwResponse != SIM_RESPONSE_OK_HELP)) {
        return E_INVALIDARG;
      }
      if ((dwResponse == SIM_RESPONSE_OK) && !dwId) {
        return E_INVALIDARG;
      }
      // Compose the select item response
      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=211,%d,%d\r", dwResponse, dwId);
      break;

    case SIM_NOTIFY_ENDSESSION:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: END SESSION command event\r\n")));
      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=254\r");
      break;

    case SIM_NOTIFY_EVENTDOWNLOAD:
    default:
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - Unknown command response (%i)\r\n"), pRsp->dwType));
      return E_NOTIMPL;
  }

  m_fIgnoreNextSSTR1616 = FALSE;
  m_fLastSetupCallNo = FALSE;
  memset(m_szLastSetupCallNo, 0, MAX_ATCMD_LEN);
  if (pHandle) {
    if (!QueueCmdWithRetry(pRsp->dwType==SIM_NOTIFY_PLAYTONE ? HCCMD_STANDARD: HCCMD_URCPORT_ONLY, pHandle, szCmd, dwCmdOpt, APIID_SENDSIMTOOLKITCMDRESPONSE, ParseRspOK, pnd, hr, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY, ParseRspError, this)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - unable to put CCommand into the queue\r\n")));
      return E_FAIL;
    }
  } else {
    if (!QueueInternalCmd(pRsp->dwType==SIM_NOTIFY_PLAYTONE ? HCCMD_STANDARD: HCCMD_URCPORT_ONLY, m_pRilDevice, szCmd, dwCmdOpt, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY, ParseRspOK, ParseRspError, this, pnd)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - unable to put CCommand into the queue\r\n")));
      return E_FAIL;
    }
  }

  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Send a Sim-Toolkit event to the module.
//
// Params:
//  pHandle      : Pointer to CRilInstanceHandle to be used for the operation.
//  dwEvent      : The type of the event
//  pDetails     : The details of the event
//  dwDetailsSize: The size of the event details
//
// Return:
//  S_OK on successs, an error code otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::SendEventDownload(CRilInstanceHandle* pHandle, const DWORD dwEvent, LPBYTE pDetails, const DWORD dwDetailsSize) const {
char          szCmd[MAX_ATCMD_LEN];
SIMLANGUAGE*  pLanguageDetails;
HRESULT       hr = S_OK;

  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit-Event: %d\r\n"), dwEvent));

  // Check the command and build up the appropriate response.
  switch (dwEvent) {
    case SIMTKIT_EVENT_USERACTIVITY:
      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=232\r");
      break;

    case SIMTKIT_EVENT_IDLESCREEN:
      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=233\r");
      break;

    case SIMTKIT_EVENT_LANGUAGESELECTION:
      if (!pDetails || (dwDetailsSize == sizeof(SIMLANGUAGE))) {
        return E_INVALIDARG;
      }
      pLanguageDetails = (SIMLANGUAGE*)pDetails;
      if (!(pLanguageDetails->dwParams & SIM_PARAM_SIMLANGUAGE_LANGUAGE)) {
        return E_INVALIDARG;
      }
      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=235,,,\"%c%c\"\r", (char)(pLanguageDetails->lpszLanguage[0]), (char)(pLanguageDetails->lpszLanguage[1]));
      break;

    case SIMTKIT_EVENT_BROWSERTERMINATION:
      (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=236,,%d\r", 0);
      break;

    default:
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - unknown event (0x%0.2X)\r\n"), dwEvent));
      return E_NOTIMPL;
  }

  if (!QueueCmdWithRetry(HCCMD_URCPORT_ONLY, pHandle, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, NULL, NULL, hr, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: SimToolkit Error - unable to put CCommand into the queue\r\n")));
    return E_FAIL;
  }

  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to fill a structure telling our Sim-Toolkit
// capabilities.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::ParseGetDevCapsNotifications(LPCSTR /*szRsp*/, void*& pBlob, UINT& cbBlob, LPVOID /*pParam*/) {
RILSIMTOOLKITNOTIFYCAPS*  prstnc = NULL;
RILSIMTOOLKITEVENTCAPS*   prstec = NULL;

  pBlob = NULL;
  cbBlob = 0;

  prstnc = (RILSIMTOOLKITNOTIFYCAPS *)AllocBlob(sizeof(RILSIMTOOLKITNOTIFYCAPS));
  if (!prstnc) {
      return E_OUTOFMEMORY;
  }

  memset(prstnc, 0x00, sizeof(RILSIMTOOLKITNOTIFYCAPS));

  prstnc->cbSize                 = sizeof(RILSIMTOOLKITNOTIFYCAPS);
  prstnc->dwParams               = RIL_PARAM_SIMTKN_ALL;

  prstnc->dwSetUpCall            = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwRefresh              = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwSendSS               = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwSendUSSD             = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwSendSMS              = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwSendDTMF             = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;
  prstnc->dwPlayTone             = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwDisplayText          = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwGetInkey             = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwGetInput             = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSelectItem           = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSetupMenu            = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSetupIdleModeText    = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSetupEventList       = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwLaunchBrowser        = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwLocalInfo            = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwMoreTime             = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwPollInterval         = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwPollingOff           = RIL_SIMTKN_NOSUPPORT;
  prstnc->dwOpenChannel          = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;     // Currently not implemented in the PH8, but the RIL is prepared.
  prstnc->dwCloseChannel         = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;     // Currently not implemented in the PH8, but the RIL is prepared.
  prstnc->dwReceiveData          = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;     // Currently not implemented in the PH8, but the RIL is prepared.
  prstnc->dwSendData             = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;     // Currently not implemented in the PH8, but the RIL is prepared.
  prstnc->dwTimerManagement      = RIL_SIMTKN_NOSUPPORT;
#if defined(RIL_PARAM_SIMTKN_RUNATCMD)
  prstnc->dwRunAtCmd             = RIL_SIMTKN_RADIOIMPLEMENTS_NOTIFICATION;     // Currently not implemented in the PH8, but the RIL is prepared.
#endif
#if defined(RIL_PARAM_SIMTKN_GETCHANNELSTATUS)
  prstnc->dwGetChannelStatus     = RIL_SIMTKN_NOSUPPORT;
#endif

  prstnc->dwNotifyFlags          = RIL_CAPS_NOTIFY_SIMTOOLKITCMD        |
                                   // RIL_CAPS_NOTIFY_SIMTOOLKITCALLSETUP  |
                                   RIL_CAPS_NOTIFY_SIMTOOLKITEVENT;

  prstec = &(prstnc->rstecEvents);
  prstec->cbSize                 = sizeof(RILSIMTOOLKITEVENTCAPS);
  prstec->dwParams               = RIL_PARAM_SIMTKE_ALL;

  prstec->dwUserActivity         = RIL_SIMTKN_MEIMPLEMENTS;
  prstec->dwIdleScreen           = RIL_SIMTKN_MEIMPLEMENTS;
  prstec->dwLanguageSelection    = RIL_SIMTKN_MEIMPLEMENTS;
  prstec->dwBrowserTermination   = RIL_SIMTKN_MEIMPLEMENTS;
  prstec->dwMTCall               = RIL_SIMTKN_NOSUPPORT;
  prstec->dwCallConnected        = RIL_SIMTKN_NOSUPPORT;
  prstec->dwCallDisconnected     = RIL_SIMTKN_NOSUPPORT;
  prstec->dwLocationStatus       = RIL_SIMTKN_NOSUPPORT;
  prstec->dwDataAvailable        = RIL_SIMTKN_NOSUPPORT;
  prstec->dwChannelStatus        = RIL_SIMTKN_NOSUPPORT;
  prstec->dwDisplayChange        = RIL_SIMTKN_NOSUPPORT;

  pBlob = (void*)prstnc;
  cbBlob = sizeof(RILSIMTOOLKITNOTIFYCAPS);

  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Prepare and initialize the Sim-Toolkit command structure.
//
// Params:
//  pBuffer: The buffer to be used
//  pRilCmd: Pointer to the Simtoolkit command structure (out)
//  dwType : Type of the Sim-Toolkt command
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::PrepareRilCmdStruct(BYTE* pBuffer, RILSIMTOOLKITCMD** pRilCmd, DWORD dwType) const {
  memset(pBuffer, 0, SIMTK_MAX_LENGTH);

  *pRilCmd = (RILSIMTOOLKITCMD*)pBuffer;

  (*pRilCmd)->dwParams         =  RIL_PARAM_SIMTKIT_CMD_TYPE            |
                                  RIL_PARAM_SIMTKIT_CMD_DETAILS_OFFSET  |
                                  RIL_PARAM_SIMTKIT_CMD_DETAILS_SIZE;
  (*pRilCmd)->dwType           =  dwType;
  (*pRilCmd)->cbSize           =  ROUNDTODWORD(sizeof(RILSIMTOOLKITCMD));
  (*pRilCmd)->dwDetailsOffset  =  ROUNDTODWORD(sizeof(RILSIMTOOLKITCMD));

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Prepare and initialize the Sim-Toolkit command structure in case of an error.
//
// Params:
//  pRilCmd: Pointer to the Simtoolkit command structure
//  dwError: The error to be reported
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::PrepareRilCmdError(RILSIMTOOLKITCMD* pRilCmd, DWORD dwError) const {
  pRilCmd->dwParams        |=    RIL_PARAM_SIMTKIT_CMD_ERROR;
  pRilCmd->dwParams        &=  ~(RIL_PARAM_SIMTKIT_CMD_DETAILS_OFFSET | RIL_PARAM_SIMTKIT_CMD_DETAILS_SIZE);
  pRilCmd->cbSize           =  sizeof(RILSIMTOOLKITCMD);
  pRilCmd->dwDetailsOffset  =  0;
  pRilCmd->dwError          =  dwError;

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Create and send the blob corresponding to the Sim-Toolkit command.
//
// Params:
//  dwNotificationCode: The blob notification code
//  pBlob             : The storage for the blob (out)
//  cbBlob            : The size of the blob (out)
//  pData             : The SAT command to be sent
//  dwSize            : The size of the SAT command
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::HandleBlob(DWORD dwNotificationCode, void*& pBlob, UINT& cbBlob, BYTE* pData, DWORD dwSize) {
  // Allocate the blob
  cbBlob = dwSize;
  pBlob = AllocBlob(cbBlob);
  if (!pBlob) {
    cbBlob = 0;
    return FALSE;
  }

  // Store notify data
  memcpy(pBlob, pData, cbBlob);

  // Trace blob data
  TraceBlob((BYTE*)pBlob, cbBlob);

  // Automatic response mode: event notifications are automatically
  // answered by the RIL.
  if (m_fAutomaticSATResponse && dwNotificationCode == RIL_NOTIFY_SIMTOOLKITEVENT && pData != NULL && dwSize >= sizeof(RILSIMTOOLKITCMD)) {
    RILSIMTOOLKITCMD *pSat;
    char szCmd[MAX_ATCMD_LEN];

    pSat = (RILSIMTOOLKITCMD *)pData;
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit send automatic resonse (dwType = %d)\r\n"), pSat->dwType));
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SSTR=%d,%d\r", pSat->dwType, (m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons) ? 4 : 0);
    (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, m_pRilDevice, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, 0, 0, NULL, ParseRspError, this);
  }

  // Notify the SIM manager of the SAT command
  return m_pRilDevice->BroadcastRealBlobNotification(dwNotificationCode, pBlob, cbBlob);
}

//////////////////////////////////////////////////////////////////////////////
//
// Tests, if number to dialed is the one from the latest SAT Setup Call command.
// In this case this number must not be dialed and the next AT^SSTR=16,16
// shouldn't be send.
//
// Params:
//  szDial: Number to be dialed
//  bNoIcon: Indicates, if "OK, but no Icon was displayed" has to signalled to the SIM
//
// Return:
//  TRUE if number is SAT number, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::SATOverrideNeeded(LPCSTR szDial, BOOL &bNoIcon)
{
    BOOL fRet = FALSE;

    bNoIcon = FALSE;

    if (MUST_USE_SAT_CMD_FOR_SETUP_CALL && m_fLastSetupCallNo) {
        UINT nDigitsInNumber;

        // Microsoft's SAT application may filter all non digits, which is a problem
        // if DTMF tones are included in the number (eg. "+12345678p1234").
        nDigitsInNumber = strspn(m_szLastSetupCallNo, "+0123456789*#");
        if (nDigitsInNumber > 0)
            fRet = (strncmp(m_szLastSetupCallNo, szDial, nDigitsInNumber)==0?TRUE:FALSE);
    }
    else
        fRet = FALSE;

    memset(m_szLastSetupCallNo, 0, MAX_ATCMD_LEN);
    m_fLastSetupCallNo = FALSE;

    if (fRet) {
        m_fIgnoreNextSSTR1616 = TRUE;
        if (m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
          bNoIcon = TRUE;
    }

    return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Problem of Microsoft MMI: when a SAT call is made, the MMI should
// display at least the confirmation text in the dialer environment.
// Since this doesn't happen, the RIL will display this description as
// the phonebook name in the call list to make the Phone application
// display it in addition to the dialed number.
//
// Params:
//  szDial: Number to be dialed
//  wszName: if a name is present, the function will place it here
// uiLenName: max. length of wszName
//
// Return:
//  TRUE if number is SAT number and a SAT name is present, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::SATNameOverrideNeeded(WCHAR *wszDial, WCHAR *wszName, UINT uiLenName) const
{
    UINT nDigitsInNumber;
    BOOL fRet = FALSE;
    char szDial[MAX_ATCMD_LEN];

    if (m_dwSATCallNameOverride == 0)
        return fRet;

    (void)_snprintfz(szDial, MAX_ATCMD_LEN, "%S", wszDial);
    // Microsoft's SAT application may filter all non digits, which is a problem
    // if DTMF tones are included in the number (eg. "+12345678p1234").
    nDigitsInNumber = strspn(m_szLastSetupCallNo, "+0123456789*#");
    if (nDigitsInNumber > 0)
        fRet = (strncmp(m_szLastSetupCallNo, szDial, nDigitsInNumber)==0?TRUE:FALSE);
    if (!fRet && wszDial[0] == (WCHAR)'0') {            // The HC25 sometimes doesn't print a leading '0'
      (void)_snprintfz(szDial, MAX_ATCMD_LEN, "0%S", wszDial);
      fRet = (strncmp(m_szLastSetupCallNo, szDial, MAX_ATCMD_LEN)==0?TRUE:FALSE);
    }

    if (fRet) {
        (void)wcsncpyz(wszName, m_wszLastSetupCallName, uiLenName);
        if (wcslen(wszName) == 0)
            fRet = FALSE;
    }

    return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function indicates, that the module must indicate, that icons have not been displayed.
//
// Return:
//  TRUE if "no icon" modus is currently on.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::SATNoIconModus() const
{
    BOOL fRet = FALSE;

    if (m_fLastCommandIncludedIcon && !m_fApplicationCanDisplayIcons)
      fRet = TRUE;

    return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function triggers the "AT^SSTR successfully executed"-event
//
//////////////////////////////////////////////////////////////////////////////
void CSimToolkitHandling::SATSSTRexecuted()
{
    SetEvent(m_hExecuted_SSTR_Cmd);
}

//////////////////////////////////////////////////////////////////////////////
//
// This function triggers the "abort waiting for ^SSTN-URC"-event
//
//////////////////////////////////////////////////////////////////////////////
void CSimToolkitHandling::SSTN254TimeoutAbort()
{
    SetEvent(m_hSATTimoutAbort);
}

