/*****************************************************************************
 * Copyright (C) Gemalto M2M GmbH
 *****************************************************************************
 * Project: 3G-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules PD SW 1
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RilDrv/rilsimtk_intel.cpp $
 * $Revision: /main/ms-d/8 $
 *     $Date: 2013-06-10 13:10:29 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 6.x
 *****************************************************************************
 * Description:
 *  Cinterion 3G RIL
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RilDrv/rilsimtk_intel.cpp$ 
 * 
 * /main/ms-d/8   2013-06-10 13:10:29   pmackent 
 * Solve deadlock in SAT PLay Tone (IPIS100088390)
 *
 * /main/ms-d/7   2013-03-05 11:29:54   pmackent
 * Workaround for unclear UCS2/GSM coding in +STK URC
 *
 * /main/ms-d/6   2012-11-27 11:49:25   pmackent
 * Remove CE6 warnings
 *
 * /main/ms-d/5   2012-11-26 11:42:51   pmackent
 * Fix problem with +STKCC URC
 *
 * /main/ms-d/4   2012-11-23 16:54:43   pmackent
 * Additional adaptions for EHS5
 *
 * /main/ms-d/3   2012-02-10 12:59:37   ctna0256
 * Store Idle Mode Status in registry (IPIS100077395)
 *
 * /main/ms-d/2   2012-02-09 16:44:12   ctna0256
 * Check for missed SMS with AT+CRSM on EHS5, small bug fixes
 *
 * /main/ms-d/1   2012-02-08 15:11:47   ctna0256
 * Add Intel-style SAT
 *
 *
 *
*/

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

//////////////////////////////////////////////////////////////////////////////
//
// The Intel style module might forget about the registration state after SIM
// reset. This thread checksthe AT+COPS state.
//
// Params:
//  pHandle: pointer to CRilHandle object
//
//////////////////////////////////////////////////////////////////////////////
static DWORD WINAPI ReCheckRegistrationStateThread(LPVOID pVoid)
{
    CRilHandle* pHandle = (CRilHandle *)pVoid;
    DWORD dwCurrentCOPS = g_iLastCOPS;

    // Sleep a little bit to allow the module to print out all the SAT URCs.
    Sleep(1000);

    // Check current COPS status, it might have been reset to 2.
    (void)QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, "AT+COPS?\r", CMDOPT_NONE, APIID_GETCURRENTOPERATOR, 0, 0, 0, ParseGetCurrentOperator);
    if (g_iLastCOPS != dwCurrentCOPS) {
        char szCmd[MAX_ATCMD_LEN];
        INT iAcT = -1;

        switch (g_n2G3GSelection)
        {
            case SELECTION2G3G_GSM_ONLY:
                iAcT = 0;
                break;
            case SELECTION2G3G_UMTS_ONLY:
                iAcT = 2;
                break;
            default:
                iAcT = -1;
        }

        if (dwCurrentCOPS == 0 || dwCurrentCOPS == 2) {
            if (iAcT == -1 || dwCurrentCOPS == 2)
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u\r", dwCurrentCOPS);
            else
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u,2,,%d\r", dwCurrentCOPS, iAcT);
        }

        (void)QueueInternalCmd(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, 0, 2, 3000);
    }

    return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to parse an Intel-style SAT notification.
// Handle the +STKPRO URC giving information about proactive commands from the
// SIM card.
//
// Params:
//  rszPointer: Pointer to the received SAT notification.
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseNotificationSTKPRO(LPCSTR& rszPointer) {
    UINT    nType;
    BOOL    fReturn = FALSE;

    if (!ParseUInt(rszPointer, TRUE, nType, rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKPRO: failed to find value\r\n")));
        return FALSE;
    }
    m_fLastCommandIncludedIcon = FALSE;

    if (nType == 129) {
        // Special case: 129 means "end of session"
        m_pRilDevice->BroadcastRealBlobNotification(RIL_NOTIFY_SIMTOOLKITSESSIONEND, NULL, 0);
        return TRUE;
    }

    switch (nType) {
        case SIMTK_CMD_REFRESH:
            fReturn = ParseSTKRefresh(rszPointer);
            break;
        case SIMTK_CMD_SETUP_EVENTLIST:
            fReturn = ParseSTKSetupEventList(rszPointer);
            break;
        case SIMTK_CMD_SETUP_CALL:
            fReturn = ParseSTKSetupCall(rszPointer);
            break;
        case SIMTK_CMD_SEND_SS:
            fReturn = ParseSTKSendSS(rszPointer);
            break;
        case SIMTK_CMD_SEND_USSD:
            fReturn = ParseSTKSendUSSD(rszPointer);
            break;
        case SIMTK_CMD_SEND_SMS:
            fReturn = ParseSTKSendSMS(rszPointer);
            break;
        case SIMTK_CMD_SEND_DTMF:
            fReturn = ParseSTKSendDTMF(rszPointer);
            break;
        case SIMTK_CMD_LAUNCH_BROWSER:
            fReturn = ParseSTKLaunchBrowser(rszPointer);
            break;
        case SIMTK_CMD_PLAY_TONE:
            fReturn = ParseSTKPlayTone(rszPointer);
            break;
        case SIMTK_CMD_DISPLAY_TEXT:
            fReturn = ParseSTKProDisplayText(rszPointer);
            break;
        case SIMTK_CMD_GET_INKEY:
            fReturn = ParseSTKProGetInkey(rszPointer);
            break;
        case SIMTK_CMD_GET_INPUT:
            fReturn = ParseSTKProGetInput(rszPointer);
            break;
        case SIMTK_CMD_SELECT_ITEM:
            fReturn = ParseSTKProSelectItem(rszPointer);
            break;
        case SIMTK_CMD_SETUP_MENU:
            fReturn = ParseSTKProSetupMenu(rszPointer);
            break;
        case SIMTK_CMD_PROVIDE_LOCAL_INFO:
            fReturn = ParseSTKProLocalInformation(rszPointer);
            break;
        case SIMTK_CMD_SETUP_IDLE_TEXT:
            fReturn = ParseSTKProSetupIdleText(rszPointer);
            break;
        case SIMTK_CMD_RUN_AT_CMD:
            fReturn = ParseSTKProRunATCmd(rszPointer);
            break;
        case SIMTK_CMD_LANGUAGE_NOTIFICATION:
            fReturn = ParseSTKProLanguageNotification(rszPointer);
            break;
        case SIMTK_CMD_OPEN_CHANNEL:
            fReturn = ParseSTKProOpenChannelNotification(rszPointer);
            break;
        default:
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKPRO: unknown STK type (%d)\r\n"), nType));
            fReturn = FALSE;
    }

    if (fReturn) {
        RILSIMTOOLKITCMD *pSat;
        DWORD dwLen;

        pSat = (RILSIMTOOLKITCMD *)m_bCmdBuffer;
        dwLen = pSat->cbSize;

        // Trace blob data
        TraceBlob((BYTE*)m_bCmdBuffer, dwLen);

        // Automatic response mode: event notifications are automatically
        // answered by the RIL.
        if (m_fAutomaticSATResponse) {
            char szCmd[MAX_ATCMD_LEN];

            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit send automatic resonse (dwType = %d)\r\n"), pSat->dwType));
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+STKTR=%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
        fReturn = m_pRilDevice->BroadcastRealBlobNotification(RIL_NOTIFY_SIMTOOLKITEVENT, m_bCmdBuffer, dwLen);
    }
    return fReturn  ;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to parse an Intel-style SAT notification.
// Handle the +STKCC URC giving information about the proactive session status
// of the STK application.
//
// Params:
//  rszPointer: Pointer to the received SAT notification.
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseNotificationSTKCNF(LPCSTR& rszPointer) {
    LPCSTR  szDummy;
    UINT    nCmd = 0;
    UINT    nResult = 0;
    UINT    nAddResult = 0;
    UINT    nSW1 = 0;
    BOOL    fReturn = FALSE;
    BOOL    fFullURC = TRUE;
    DWORD   dwSessionEnd = 0;

    if (CHECK_STKCNF_FOR_MISSING_PARAMS) {
        INT nCommas = 0;
        INT nPos = 0;

        // Count commas in order to find out which kind of URC this is.
        while (*(rszPointer + nPos) != '\0' && *(rszPointer + nPos) != '\r') {
            if (*(rszPointer + nPos) == ',')
                nCommas++;
            nPos++;
        }
        if (nCommas <= 1)
            fFullURC = FALSE;
    }

    if (fFullURC) {
        // Parse: +STKCNF: <proactive_cmd>,<result>,<add_result>,<sw1>
        if (!ParseUIntHex(rszPointer, TRUE, nCmd, rszPointer)        ||
            !ParseRspParamSeparator(rszPointer, rszPointer)          ||
            !ParseUIntHex(rszPointer, FALSE, nResult, rszPointer)    ||
            !ParseRspParamSeparator(rszPointer, rszPointer)          ||
            !ParseUIntHex(rszPointer, FALSE, nAddResult, rszPointer) ||
            !ParseRspParamSeparator(rszPointer, rszPointer)          ||
            !ParseUIntHex(rszPointer, FALSE, nSW1, rszPointer)       ||
            !ParseRspPostfix(rszPointer, szDummy)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKCNF: failed to parse parameters\r\n")));
            goto Error;
        }
    }
    else {
        // Parse: +STKCNF: <sw1>, <result>
        if (!ParseUIntHex(rszPointer, TRUE, nSW1, rszPointer)        ||
            !ParseRspParamSeparator(rszPointer, rszPointer)          ||
            !ParseUIntHex(rszPointer, TRUE, nResult, rszPointer)    ||
            !ParseRspPostfix(rszPointer, szDummy)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKCNF: failed to parse parameters\r\n")));
            goto Error;
        }
    }

    // Unfortunately there is not Intel-equvalent to the "^SSTN: 254" URC, but
    // it looks like that is the parameter SW1 is equal 144 the session has ended.
    // Alternatively it is possible to send the reset after each command with the
    // registry key "SATEndStkSessionAfterEachCommand" set to 1.
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SATEndStkSessionAfterEachCommand"), &dwSessionEnd);
    if (dwSessionEnd == 1 || (nSW1 == 144 && nCmd < 128) || !fFullURC)
        m_pRilDevice->BroadcastRealBlobNotification(RIL_NOTIFY_SIMTOOLKITSESSIONEND, NULL, 0);

    if (nCmd == 1 || !fFullURC) {
        // This is a result of a SIM refresh/reset command which might change
        // the COPS status.
        if (RECHECK_COPS_AFTER_SAT_SIM_RESET)
            CloseHandle(CreateThread(NULL, 0, ReCheckRegistrationStateThread, (LPVOID)m_pRilDevice, 0, 0));
    }

    fReturn = TRUE;

Error:
    return fReturn;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to parse an Intel-style SAT notification.
// Handle the +STKCC URC giving information about call controll related actions
// from the STK application.
//
// Params:
//  rszPointer: Pointer to the received SAT notification.
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseNotificationSTKCC(LPCSTR& rszPointer) {
    LPCSTR  szDummy;
    UINT    nType;
    UINT    nResult;
    UINT    nTon1;
    UINT    nTon2;
    BOOL    fReturn = FALSE;
    WCHAR   wszAlpha[UCS2_LEN];
    char    szNumber[UCS2_LEN];
    char    szNumber2[UCS2_LEN];

    if (!ParseUInt(rszPointer, TRUE, nType, rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKCC: failed to find value (1)\r\n")));
        goto Error;;
    }

    switch (nType) {
        case 1:          // Setup Call
            if (!ParseRspParamSeparator(rszPointer, rszPointer)                ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)               ||
                 !ParseUInt(rszPointer, FALSE, nResult, rszPointer)            ||
                 !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)  ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)               ||
                 !ParseString(rszPointer, szNumber, UCS2_LEN, rszPointer)      ||
                 !ParseRspPostfix(rszPointer, szDummy)) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKCC: failed to parse parameters (SC)\r\n")));
                goto Error;;
            }
            break;
        case 2:          // Send SS
            if (!ParseRspParamSeparator(rszPointer, rszPointer)                ||
                 !ParseUInt(rszPointer, FALSE, nResult, rszPointer)            ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)               ||
                 !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)  ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)               ||
                 !ParseString(rszPointer, szNumber, UCS2_LEN, rszPointer)      ||
                 !ParseRspPostfix(rszPointer, szDummy)) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKCC: failed to parse parameters (SS)\r\n")));
                goto Error;;
            }
            break;
        case 3:          // Send USSD
            if (!ParseRspParamSeparator(rszPointer, rszPointer)                  ||
                 !ParseUInt(rszPointer, FALSE, nResult, rszPointer)              ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
                 !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)    ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
                 !ParseString(rszPointer, szNumber, UCS2_LEN, rszPointer)        ||
                 !ParseRspPostfix(rszPointer, szDummy)) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKCC: failed to parse parameters (USSD)\r\n")));
                goto Error;;
            }
            break;
        case 4:          // End SMS
            if (!ParseRspParamSeparator(rszPointer, rszPointer)                  ||
                 !ParseUInt(rszPointer, FALSE, nResult, rszPointer)              ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
                 !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)    ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
                 !ParseUInt(rszPointer, FALSE, nTon1, rszPointer)                ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
                 !ParseString(rszPointer, szNumber, UCS2_LEN, rszPointer)        ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
                 !ParseUInt(rszPointer, FALSE, nTon2, rszPointer)                ||
                 !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
                 !ParseString(rszPointer, szNumber2, UCS2_LEN, rszPointer)       ||
                 !ParseRspPostfix(rszPointer, szDummy)) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKCC: failed to parse parameters (SMS)\r\n")));
                goto Error;;
            }
            break;
    }

    // Look for the "<postfix>" (don't increase string pointer, postfix is scanned again in global response handler)
    if (!ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseNotificationSTKCC: failed to find postfix\r\n")));
        return fReturn;
    }
    fReturn = TRUE;

Error:
    return fReturn;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Setup Menu notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKRefresh(LPCSTR& rszPointer) {
    UINT               nType = 0;
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMFILEREFRESH*    pSatRefresh;

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

    // Parse: "+STKPRO: 01,[<type>],..." (the last parameters are undocumented)
    if (!ParseRspParamSeparator(rszPointer, rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKRefresh: failed to parse parameters (1)\r\n")));
        return FALSE;
    }
    if (!ParseUInt(rszPointer, FALSE, nType, rszPointer)) nType = 0;
    if (!MatchStringAnywhere(rszPointer, "\r\n", rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKRefresh: failed to parse parameters (2)\r\n")));
        return FALSE;
    }
    rszPointer -= 2;   // Skip back over last <CR><LF>

    pSatRefresh = (SIMFILEREFRESH*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatRefresh->dwParams     = SIM_PARAM_FILEREFRESH_FLAGS;
    pSatRefresh->dwFlags      = 0;      // Unfortunately it is undocumented, what kind of reset this is.
    ResetIdleModeText();

    pSatRefresh->cbSize = ROUNDTODWORD(sizeof(SIMFILEREFRESH));

    pSatCmd->cbSize += pSatRefresh->cbSize;
    pSatCmd->dwDetailsSize = pSatRefresh->cbSize;

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Setup Menu notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKSetupEventList(LPCSTR& rszPointer) {
    UINT               nEventList;
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMEVENTLIST*      pSatEventList;
    LPCSTR             szDummy;
    BYTE*              pEvents;

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

    // Parse: "+STKPRO: 05,<eventlist>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)          ||
        !ParseUInt(rszPointer, FALSE, nEventList, rszPointer)    ||
        !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSetupEventList: failed to parse parameters\r\n")));
        return FALSE;
    }

    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;

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Setup Call notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKSetupCall(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMCALL*           pSatCall;
    LPCSTR             szDummy;
    WCHAR              wszConfirmation[UCS2_LEN];
    WCHAR              wszSetup[UCS2_LEN];
    char               szNumber[UCS2_LEN];
    char               szSubAdddress[UCS2_LEN];
    UINT               nConfIconId;
    UINT               nSetupIconId;
    UINT               nType;

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

    // Parse: "+STKPRO: 16,<number>,<subaddress>,<type>,<alpha1>,<icon1>,<alpha2>,<icon2>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                      ||
         !ParseString(rszPointer, szNumber, UCS2_LEN, rszPointer)            ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                     ||
         !ParseString(rszPointer, szSubAdddress, UCS2_LEN, rszPointer)       ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                     ||
         !ParseUInt(rszPointer, FALSE, nType, rszPointer)                    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                     ||
         !ParseUCS2String(rszPointer, wszConfirmation, UCS2_LEN, rszPointer) ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                     ||
         !ParseUInt(rszPointer, FALSE, nConfIconId, rszPointer)              ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                     ||
         !ParseUCS2String(rszPointer, wszSetup, UCS2_LEN, rszPointer)        ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                     ||
         !ParseUInt(rszPointer, FALSE, nSetupIconId, rszPointer)             ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSetupCall: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatCall = (SIMCALL*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatCall->dwParams = SIM_PARAM_SIMCALL_FLAGS;
    switch (nType) {
      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 (strlen(szNumber)) {
      pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_ADDRESSSIZE | SIM_PARAM_SIMCALL_ADDRESSOFFSET |
                                             SIM_PARAM_SIMCALL_ADDRESSTYPE | SIM_PARAM_SIMCALL_NUMPLAN;
      pSatCall->dwAddressSize              = (strlen(szNumber) + 1) * sizeof(WCHAR);
      pSatCall->dwAddressOffset            = ROUNDTODWORD2(sizeof(SIMCALL), pSatCall->dwTextSize);
      pSatCall->dwAddressType              = (szNumber[0] == '+') ? SIM_ADDRTYPE_INTERNATIONAL : SIM_ADDRTYPE_UNKNOWN;
      pSatCall->dwNumPlan                  = SIM_NUMPLAN_TELEPHONE;
      (void)_snwprintfz((WCHAR*)((BYTE*)pSatCall + pSatCall->dwAddressOffset), pSatCall->dwAddressSize, L"%S", szNumber);
      if (MUST_USE_SAT_CMD_FOR_SETUP_CALL) {
        (void)_snprintfz(m_szLastSetupCallNo, MAX_ATCMD_LEN, "%s", szNumber);
        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;
        pSatCall->dwIconIdentifier           = nConfIconId;
        pSatCall->dwIconQualifier            = 0;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    if (nSetupIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatCall->dwParams                  |= SIM_PARAM_SIMCALL_CALLSETUPICONID;
        pSatCall->dwCallSetupIconIdentifier  = nSetupIconId;
        pSatCall->dwCallSetupIconQualifier   = 0;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatCall->cbSize = ROUNDTODWORD4(sizeof(SIMCALL), pSatCall->dwTextSize, pSatCall->dwAddressSize, pSatCall->dwCallSetupTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Send Supplementary Service notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKSendSS(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMUSSD*           pSatSs;
    LPCSTR             szDummy;
    WCHAR              wszAlpha[UCS2_LEN];
    char               szSS_Data[UCS2_LEN];
    UINT               nIconId;
    UINT               nReferenceNumber;

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

    // Parse: "+STKPRO: 17,<ss_data>,<alpha>,<icon>,<ref>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)               ||
         !ParseString(rszPointer, szSS_Data, UCS2_LEN, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)              ||
         !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer) ||
         !ParseRspParamSeparator(rszPointer, rszPointer)              ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)           ||
         !ParseRspParamSeparator(rszPointer, rszPointer)              ||
         !ParseUInt(rszPointer, FALSE, nReferenceNumber, rszPointer)  ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSendSS: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatSs = (SIMUSSD*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

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

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Send USSD notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKSendUSSD(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMUSSD*           pSatUssd;
    LPCSTR             szDummy;
    WCHAR              wszUSSD[UCS2_LEN];
    WCHAR              wszText[UCS2_LEN];
    UINT               nIconId;
    UINT               nDCS;
    UINT               nReferenceNumber;

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

    // Parse: "+STKPRO: 18,<dcs>,<hex_string>,<alpha>,<icon>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)     ||
         !ParseUInt(rszPointer, FALSE, nDCS, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSendUSSD: failed to parse parameters (1)\r\n")));
        return FALSE;
    }
    if (nDCS == 4) {
        if (!ParseQuotedEncodedString(ENCODING_GSMDEFAULT_HEX, rszPointer, wszUSSD, wszUSSD + UCS2_LEN)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSendUSSD: failed to parse parameters (2)\r\n")));
            return FALSE;
        }
    }
    else if (nDCS == 8) {
        if (!ParseUCS2String(rszPointer, wszUSSD, UCS2_LEN, rszPointer)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSendUSSD: failed to parse parameters (3)\r\n")));
            return FALSE;
        }
    }
    else {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSendUSSD: unknown DCS (%d)\r\n"), nDCS));
        return FALSE;
    }
    if (!ParseRspParamSeparator(rszPointer, rszPointer)              ||
         !ParseUCS2String(rszPointer, wszText, UCS2_LEN, rszPointer) ||
         !ParseRspParamSeparator(rszPointer, rszPointer)             ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)          ||
         !ParseRspParamSeparator(rszPointer, rszPointer)             ||
         !ParseUInt(rszPointer, FALSE, nReferenceNumber, rszPointer) ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSendUSSD: failed to parse parameters (4)\r\n")));
        return FALSE;
    }

    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;
        pSatUssd->dwIconIdentifier  = nIconId;
        pSatUssd->dwIconQualifier   = 0;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatUssd->cbSize = ROUNDTODWORD2(sizeof(SIMUSSD), pSatUssd->dwTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Send SMS notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKSendSMS(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMSMS*            pSatSms;
    LPCSTR             szDummy;
    WCHAR              wszAlpha[UCS2_LEN];
    UINT               nIconId;
    UINT               nReferenceNumber;

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

    // Parse: "+STKPRO: 19,<alpha>,<icon>,<ref>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                  ||
         !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)              ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUInt(rszPointer, FALSE, nReferenceNumber, rszPointer)     ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSendSMS: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatSms = (SIMSMS*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

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

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Send DTMF notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKSendDTMF(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMSENDDTMF*       pSatDtmf;
    LPCSTR             szDummy;
    WCHAR              wszAlpha[UCS2_LEN];
    WCHAR              wszDTMF[UCS2_LEN];
    UINT               nIconId;

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

    // Parse: "+STKPRO: 20,<alpha>,<icon>,<dtmf>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)   ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)             ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                ||
         !ParseUCS2String(rszPointer, wszDTMF, UCS2_LEN, rszPointer)    ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKSendDTMF: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatDtmf = (SIMSENDDTMF*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

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

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Launch Browser notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKLaunchBrowser(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMLAUNCHBROWSER*  pSatLB;
    LPCSTR             szDummy;
    WCHAR              wszAlpha[UCS2_LEN];
    WCHAR              wszURL[UCS2_LEN];
    UINT               nIconId;

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

    // Parse: "+STKPRO: 21,<URL><alpha>,<icon>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                ||
         !ParseUCS2String(rszPointer, wszURL, UCS2_LEN, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)               ||
         !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)  ||
         !ParseRspParamSeparator(rszPointer, rszPointer)               ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)            ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKLaunchBrowser: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatLB = (SIMLAUNCHBROWSER*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatLB->dwParams            = SIM_PARAM_SIMLAUNCHBROWSER_FLAGS | SIM_PARAM_SIMLAUNCHBROWSER_BROWSERID;
    pSatLB->dwFlags             = 0;
    pSatLB->dwBrowserId         = 1;
    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(wszAlpha)) {
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_TEXTSIZE | SIM_PARAM_SIMLAUNCHBROWSER_TEXTOFFSET;
      pSatLB->dwTextSize        = (wcslen(wszAlpha) + 1) * sizeof(WCHAR);
      pSatLB->dwTextOffset      = ROUNDTODWORD2(sizeof(SIMLAUNCHBROWSER), pSatLB->dwURLSize);
      (void)wcscpy((WCHAR*)((BYTE*)pSatLB + pSatLB->dwTextOffset), wszAlpha);
    }
    if (nIconId) {
      pSatLB->dwParams         |= SIM_PARAM_SIMLAUNCHBROWSER_ICONID;
      pSatLB->dwIconIdentifier  = nIconId;
      pSatLB->dwIconQualifier   = 0;
    }
    pSatLB->cbSize = ROUNDTODWORD3(sizeof(SIMLAUNCHBROWSER), pSatLB->dwURLSize, pSatLB->dwTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Play Tone notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKPlayTone(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMTONE*           pSatTone;
    LPCSTR             szDummy;
    WCHAR              wszAlpha[UCS2_LEN];
    UINT               nTone;
    UINT               nUnit;
    UINT               nInterval;
    UINT               nIconId;

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

    // Parse: "+STKPRO: 32,<tone>,<unit>,<interval>,<alpha>,<icon>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                  ||
         !ParseUInt(rszPointer, TRUE, nTone, rszPointer)                 ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUInt(rszPointer, FALSE, nUnit, rszPointer)                ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUInt(rszPointer, FALSE, nInterval, rszPointer)            ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)              ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKPlayTone: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatTone = (SIMTONE*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatTone->dwParams    = SIM_PARAM_SIMTONE_TONE | SIM_PARAM_SIMTONE_DURATION;
    pSatTone->dwTone      = nTone;
    pSatTone->dwDuration  = 0;
    switch (nUnit) {
      case 0:
        pSatTone->dwDuration = nInterval * (60 * 1000);
        break;
      case 1:
        pSatTone->dwDuration = nInterval * 1000;
        break;
      case 2:
        pSatTone->dwDuration = nInterval * 100;
        break;
      default:
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKPlayTone: unknown duration unit (%d)\r\n"), nUnit));
        break;
    }
    if (wcslen(wszAlpha)) {
      pSatTone->dwParams         |= SIM_PARAM_SIMTONE_TEXTSIZE | SIM_PARAM_SIMTONE_TEXTOFFSET;
      pSatTone->dwTextSize        = (wcslen(wszAlpha) + 1) * sizeof(WCHAR);
      pSatTone->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTONE));
      (void)wcscpy((WCHAR*)((BYTE*)pSatTone + pSatTone->dwTextOffset), wszAlpha);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
        pSatTone->dwParams         |= SIM_PARAM_SIMTONE_ICONID;
        pSatTone->dwIconIdentifier  = nIconId;
        pSatTone->dwIconQualifier   = 0;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatTone->cbSize = ROUNDTODWORD2(sizeof(SIMTONE), pSatTone->dwTextSize);

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

#ifdef SAT_PLAY_TONE_OLD_STYLE_INTEL
    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 = TRUE;

      (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+STKTR=32,4\r", CMDOPT_NONE, APIID_SENDSIMTOOLKITENVELOPECMD, 0, 0, 0, NULL);
      else
        (void)QueueInternalCmd(HCCMD_STANDARD, m_pRilDevice, "AT+STKTR=32,0\r", CMDOPT_NONE, APIID_SENDSIMTOOLKITENVELOPECMD, 0, 0, 0, NULL);
    }
#endif

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Display Text notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProDisplayText(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMTEXT*           pSatText;
    LPCSTR             szDummy;
    WCHAR              wszText[UCS2_LEN];
    UINT               nIconId;
    UINT               nDCS;
    UINT               nType;

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

    // Parse: "+STKPRO: 33,<type>,<dcs>,<hex_string>,<icon>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)      ||
         !ParseUInt(rszPointer, FALSE, nType, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)     ||
         !ParseUInt(rszPointer, FALSE, nDCS, rszPointer)     ||
         !ParseRspParamSeparator(rszPointer, rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProDisplayText: failed to parse parameters (1)\r\n")));
        return FALSE;
    }
    if (nDCS == 4) {
        if (!ParseQuotedEncodedString(ENCODING_GSMDEFAULT_HEX, rszPointer, wszText, wszText + UCS2_LEN)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProDisplayText: failed to parse parameters (2)\r\n")));
            return FALSE;
        }
    }
    else if (nDCS == 8) {
        if (!ParseUCS2String(rszPointer, wszText, UCS2_LEN, rszPointer)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProDisplayText: failed to parse parameters (3)\r\n")));
            return FALSE;
        }
    }
    else {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProDisplayText: unknown DCS (%d)\r\n"), nDCS));
        return FALSE;
    }
    if (!ParseRspParamSeparator(rszPointer, rszPointer)        ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)    ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProDisplayText: failed to parse parameters (4)\r\n")));
        return FALSE;
    }

    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams            = SIM_PARAM_SIMTEXT_FLAGS;
    if (nType & 0x01)          { pSatText->dwFlags |= SIMTEXT_HIGHPRIORITY; }
    if (!(nType & 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;
        pSatText->dwIconIdentifier  = nIconId;
        pSatText->dwIconQualifier   = 0;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style Get Inkey notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProGetInkey(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMTEXT*           pSatText;
    LPCSTR             szDummy;
    WCHAR              wszText[UCS2_LEN];
    UINT               nIconId;
    UINT               nDCS;
    UINT               nType;

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

    // Parse: "+STKPRO: 34,<type>,<dcs>,<string>,<icon_id>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)      ||
         !ParseUInt(rszPointer, FALSE, nType, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)     ||
         !ParseUInt(rszPointer, FALSE, nDCS, rszPointer)     ||
         !ParseRspParamSeparator(rszPointer, rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInkey: failed to parse parameters (1)\r\n")));
        return FALSE;
    }
    if (nDCS == 4) {
        if (!ParseQuotedEncodedString(ENCODING_GSMDEFAULT_HEX, rszPointer, wszText, wszText + UCS2_LEN)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInkey: failed to parse parameters (2)\r\n")));
            return FALSE;
        }
    }
    else if (nDCS == 8) {
        if (!ParseUCS2String(rszPointer, wszText, UCS2_LEN, rszPointer)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInkey: failed to parse parameters (3)\r\n")));
            return FALSE;
        }
    }
    else {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInkey: unknown DCS (%d)\r\n"), nDCS));
        return FALSE;
    }
    if (!ParseRspParamSeparator(rszPointer, rszPointer)          ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)    ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInkey: failed to parse parameters (4)\r\n")));
        return FALSE;
    }

    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams = SIM_PARAM_SIMTEXT_FLAGS;
    if (nType & 0x04) {
      pSatText->dwFlags |= SIMTEXT_YESNO;
    } else {
      if (!(nType & 0x01)) {
        pSatText->dwFlags |= SIMTEXT_KEYPADDIGITS;
      }
      if (!(nType & 0x02)) {
        pSatText->dwFlags |= SIMTEXT_GSMDEFAULTALPHABET;
      }
    }
    if (nType & 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;
        pSatText->dwIconIdentifier  = nIconId;
        pSatText->dwIconQualifier   = 0;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style Get Input notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProGetInput(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMTEXT*           pSatText;
    LPCSTR             szDummy;
    WCHAR              wszText[UCS2_LEN];
    WCHAR              wszDefaultText[UCS2_LEN];
    UINT               nIconId;
    UINT               nDCS;
    UINT               nMaxResponseLen;
    UINT               nMinResponseLen;
    UINT               nType;

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

    // Parse: "+STKPRO: 35,<type>,<dcs>,<string>,<max_rsp_len>,<min_rsp_len>,<default_text>,<icon_id>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)      ||
         !ParseUInt(rszPointer, FALSE, nType, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)     ||
         !ParseUInt(rszPointer, FALSE, nDCS, rszPointer)     ||
         !ParseRspParamSeparator(rszPointer, rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInput: failed to parse parameters (1)\r\n")));
        return FALSE;
    }
    if (nDCS == 4) {
        if (!ParseQuotedEncodedString(ENCODING_GSMDEFAULT_HEX, rszPointer, wszText, wszText + UCS2_LEN)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInput: failed to parse parameters (2)\r\n")));
            return FALSE;
        }
    }
    else if (nDCS == 8) {
        if (!ParseUCS2String(rszPointer, wszText, UCS2_LEN, rszPointer)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInput: failed to parse parameters (3)\r\n")));
            return FALSE;
        }
    }
    else {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInput: unknown DCS (%d)\r\n"), nDCS));
        return FALSE;
    }
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                     ||
         !ParseUInt(rszPointer, FALSE, nMaxResponseLen, rszPointer)         ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                    ||
         !ParseUInt(rszPointer, FALSE, nMinResponseLen, rszPointer)         ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                    ||
         !ParseUCS2String(rszPointer, wszDefaultText, UCS2_LEN, rszPointer) ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                    ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)                 ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProGetInput: failed to parse parameters (4)\r\n")));
        return FALSE;
    }

    pSatText = (SIMTEXT*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatText->dwParams               = SIM_PARAM_SIMTEXT_FLAGS;
    if (!(nType & 0x01))          { pSatText->dwFlags |= SIMTEXT_KEYPADDIGITS; }
    if (!(nType & 0x02))          { pSatText->dwFlags |= SIMTEXT_GSMDEFAULTALPHABET; }
    if (nType & 0x04)             { pSatText->dwFlags |= SIMTEXT_NOECHO; }
    if (nType & 0x08)             { pSatText->dwFlags |= SIMTEXT_PACKEDRESPONSE; }
    if (nType & 0x80)             { pSatText->dwFlags |= SIMTEXT_HELPINFO; }
    pSatText->dwParams              |= SIM_PARAM_SIMTEXT_MINRESPONSE | SIM_PARAM_SIMTEXT_MAXRESPONSE,
    pSatText->dwMinResponse          = nMinResponseLen;
    pSatText->dwMaxResponse          = nMaxResponseLen;
    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(wszDefaultText)) {
      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;
        pSatText->dwIconIdentifier     = nIconId;
        pSatText->dwIconQualifier      = 0;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatText->cbSize = ROUNDTODWORD3(sizeof(SIMTEXT), pSatText->dwTextSize, pSatText->dwDefaultTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Select Item notification.
//
// Params:
//  rszPointer: Pointer to the received SAT notification.
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProSelectItem(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd = NULL;
    SIMMENU*           pSatMenu = NULL;
    SIMMENUITEM*       pSatItem = NULL;
    LPCSTR             szDummy;
    WCHAR              wszAlpha[UCS2_LEN];
    WCHAR              wszItemText[UCS2_LEN];
    DWORD              dwLen;
    UINT               nType;
    UINT               nIdemID;
    UINT               nTotalItems;
    UINT               nNextAction;
    UINT               nDefaultItem;
    UINT               nIconID;
    UINT               nIconIdListElement;
    UINT               nIconCounter = 0;
    BOOL               fReturn = FALSE;
    BOOL               fComplete = FALSE;

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

    // Parse through all lines of this multi-line URC until all lines are parsed.
    for (;;) {
        // Parse: +STKPRO: 36,<type>,<alpha>,<idem_id>,<total_items>,<item_text>,<next_action>,<icon_id>,<icon_i_list_element>
        // The part "+STKPRO: 36" has been already parsed at this point.
        if (!ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nType, rszPointer)                ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)    ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nIdemID, rszPointer)              ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nTotalItems, rszPointer)          ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUCS2String(rszPointer, wszItemText, UCS2_LEN, rszPointer) ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nNextAction, rszPointer)          ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nDefaultItem, rszPointer)         ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nIconID, rszPointer)              ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nIconIdListElement, rszPointer)   ||
            !ParseRspPostfix(rszPointer, szDummy)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSelectItem: failed to parse parameters\r\n")));
            fReturn = FALSE;
            break;
        }

        // The SAT menu parameters getting repeated in every line. The RIL uses
        // only the values from the first line.
        if (pSatMenu == NULL) {
            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 (wcslen(wszAlpha)) {
                pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_TEXTSIZE | SIM_PARAM_SIMMENU_TEXTOFFSET;
                pSatMenu->dwTextSize        = (wcslen(wszAlpha) + 1) * sizeof(WCHAR);
                pSatMenu->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENU));
                (void)wcscpy((WCHAR*)((BYTE*)pSatMenu + pSatMenu->dwTextOffset), wszAlpha);
            }
            if (nDefaultItem) {
                pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_DEFAULTITEM;
                pSatMenu->dwDefaultItem     = nDefaultItem;
            }
            if (nIconID) {
                if (m_fApplicationCanDisplayIcons) {
                    pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_ICONID;
                    pSatMenu->dwIconIdentifier  = nIconID;
                    pSatMenu->dwIconQualifier   = 0;
                }
                m_fLastCommandIncludedIcon = TRUE;
            }
            pSatMenu->dwMenuItemCount     = nTotalItems;
            pSatMenu->dwMenuItemOffset    = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

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

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

        dwLen = wcslen(wszItemText);
        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
            fReturn = FALSE;
            break;
        }

        pSatItem->dwParams            = SIM_PARAM_SIMMENUITEM_FLAGS | SIM_PARAM_SIMMENUITEM_IDENTIFIER;
        pSatItem->dwIdentifier        = nIdemID;
        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), wszItemText);
        }
        if (nNextAction) {
            pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_NEXTACTION;
            pSatItem->dwNextAction      = nNextAction;
        }
        if (nIconIdListElement) {
          if (m_fApplicationCanDisplayIcons) {
            pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_ICONID;
            pSatItem->dwIconIdentifier  = nIconIdListElement;
            pSatItem->dwIconQualifier   = 0;
          }
          m_fLastCommandIncludedIcon = TRUE;
        }
        pSatItem->cbSize = ROUNDTODWORD2(sizeof(SIMMENUITEM), pSatItem->dwTextSize);

        pSatMenu->dwMenuItemSize += pSatItem->cbSize;

        pSatItem = (SIMMENUITEM*)((BYTE*)pSatItem + pSatItem->cbSize);

        nIconCounter++;

        if (nIconCounter == nTotalItems) {
            // The comple SAT item list has been parsed now.
            fReturn = TRUE;
            fComplete = TRUE;
            break;
        }
        else {
            UINT nStkCmd;

            if (!ParseRspPrefix(rszPointer, rszPointer)                     ||
                !MatchStringBeginning(rszPointer, "+STKPRO: ", rszPointer)  ||
                !ParseUInt(rszPointer, TRUE, nStkCmd, rszPointer)) {
                 RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSelectItem: failed find next item\r\n")));
                fReturn = FALSE;
                break;
            }
            if (nStkCmd != SIMTK_CMD_SELECT_ITEM) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSelectItem: unexpected proactive command type\r\n")));
                fReturn = FALSE;
                break;
            }
        }

    }

    if (fReturn && !fComplete) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: ParseSTKProSelectItem: incomplete menu, waiting for more information\r\n")));
        // Delete buffer, this function will be called again, if more data is availabe.
        memset(m_bCmdBuffer, 0, SIMTK_MAX_LENGTH);
    }
    if (fComplete) {
      pSatMenu->cbSize += pSatMenu->dwMenuItemSize;
      pSatCmd->cbSize += pSatMenu->cbSize;
      pSatCmd->dwDetailsSize = pSatMenu->cbSize;
    }

    return fReturn;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Setup Menu notification.
//
// Params:
//  rszPointer: Pointer to the received SAT notification.
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProSetupMenu(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd = NULL;
    SIMMENU*           pSatMenu = NULL;
    SIMMENUITEM*       pSatItem = NULL;
    LPCSTR             szDummy;
    WCHAR              wszAlpha[UCS2_LEN];
    WCHAR              wszItemText[UCS2_LEN];
    DWORD              dwLen;
    UINT               nType;
    UINT               nIdemID;
    UINT               nTotalItems;
    UINT               nNextAction;
    UINT               nIconID;
    UINT               nIconIdListElement;
    UINT               nIconCounter = 0;
    BOOL               fReturn = FALSE;
    BOOL               fComplete = FALSE;
    BOOL               fGSM = FALSE;

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

    // Parse through all lines of this multi-line URC until all lines are parsed.
    for (;;) {
        if (UNCLEAR_CODING_ON_SAT) {
            LPCSTR pszTmp = rszPointer;
            char szAlpha[MAX_ATCMD_LEN];

            // Try to find out, if the parameter <alpha> is coded in GSM or UCS2.
            if (ParseRspParamSeparator(pszTmp, pszTmp) &&
                ParseUInt(pszTmp, FALSE, nType, pszTmp) &&
                ParseRspParamSeparator(pszTmp, pszTmp) &&
                ParseString(pszTmp, szAlpha, MAX_ATCMD_LEN, pszTmp)) {
                // Examine the string: if the length cannot be devided by 4, it
                // is not coded in UCS2.
                if (strlen(szAlpha) % 4 != 0) fGSM = TRUE;
                // If the string doesn't completly consists out of hex numbers,
                // it is not coded in UCS2.
                if (strlen(szAlpha) != strspn(szAlpha, "0123456789ABCDEF")) fGSM = TRUE;
            }
        }

        // Parse: +STKPRO: 37,<type>,<alpha>,<idem_id>,<total_items>,<item_text>,<next_action>,<icon_id>,<icon_i_list_element>
        // The part "+STKPRO: 37" has been already parsed at this point.
        if (!ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nType, rszPointer)                ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !(fGSM ? ParseGSMString(rszPointer, wszAlpha, UCS2_LEN, rszPointer)  : ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer))    ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nIdemID, rszPointer)              ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nTotalItems, rszPointer)          ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !(fGSM ? ParseGSMString(rszPointer, wszItemText, UCS2_LEN, rszPointer) : ParseUCS2String(rszPointer, wszItemText, UCS2_LEN, rszPointer)) ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nNextAction, rszPointer)          ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nIconID, rszPointer)              ||
            !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
            !ParseUInt(rszPointer, FALSE, nIconIdListElement, rszPointer)   ||
            !ParseRspPostfix(rszPointer, szDummy)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSetupMenu: failed to parse parameters\r\n")));
            fReturn = FALSE;
            break;
        }

        // The SAT menu parameters getting repeated in every line. The RIL uses
        // only the values from the first line.
        if (pSatMenu == NULL) {
            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 (wcslen(wszAlpha)) {
                pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_TEXTSIZE | SIM_PARAM_SIMMENU_TEXTOFFSET;
                pSatMenu->dwTextSize        = (wcslen(wszAlpha) + 1) * sizeof(WCHAR);
                pSatMenu->dwTextOffset      = ROUNDTODWORD(sizeof(SIMMENU));
                (void)wcscpy((WCHAR*)((BYTE*)pSatMenu + pSatMenu->dwTextOffset), wszAlpha);
            }
            if (nIconID) {
                if (m_fApplicationCanDisplayIcons) {
                    pSatMenu->dwParams         |= SIM_PARAM_SIMMENU_ICONID;
                    pSatMenu->dwIconIdentifier  = nIconID;
                    pSatMenu->dwIconQualifier   = 0;
                }
                m_fLastCommandIncludedIcon = TRUE;
            }
            pSatMenu->dwMenuItemCount     = nTotalItems;
            pSatMenu->dwMenuItemOffset    = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);

            pSatMenu->cbSize = ROUNDTODWORD2(sizeof(SIMMENU), pSatMenu->dwTextSize);
            pSatItem = (SIMMENUITEM*)((BYTE*)pSatMenu + pSatMenu->dwMenuItemOffset);
        }

        dwLen = wcslen(wszItemText);
        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
            fReturn = FALSE;
            break;
        }

        pSatItem->dwParams            = SIM_PARAM_SIMMENUITEM_FLAGS | SIM_PARAM_SIMMENUITEM_IDENTIFIER;
        pSatItem->dwIdentifier        = nIdemID;
        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), wszItemText);
        }
        if (nNextAction) {
            pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_NEXTACTION;
            pSatItem->dwNextAction      = nNextAction;
        }
        if (nIconIdListElement) {
            if (m_fApplicationCanDisplayIcons) {
                pSatItem->dwParams         |= SIM_PARAM_SIMMENUITEM_ICONID;
                pSatItem->dwIconIdentifier  = nIconIdListElement;
                pSatItem->dwIconQualifier   = 0;
            }
            m_fLastCommandIncludedIcon = TRUE;
        }
        pSatItem->cbSize = ROUNDTODWORD2(sizeof(SIMMENUITEM), pSatItem->dwTextSize);

        pSatMenu->dwMenuItemSize += pSatItem->cbSize;

        pSatItem = (SIMMENUITEM*)((BYTE*)pSatItem + pSatItem->cbSize);

        nIconCounter++;

        if (nIconCounter == nTotalItems) {
            // The comple SAT menu has been parsed now.
            fReturn = TRUE;
            fComplete = TRUE;
            break;
        }
        else {
            UINT nStkCmd;

            if (!ParseRspPrefix(rszPointer, rszPointer)                     ||
                !MatchStringBeginning(rszPointer, "+STKPRO: ", rszPointer)  ||
                !ParseUInt(rszPointer, TRUE, nStkCmd, rszPointer)) {
                 RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSetupMenu: failed find next item\r\n")));
                fReturn = FALSE;
                break;
            }
            if (nStkCmd != SIMTK_CMD_SETUP_MENU) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSetupMenu: unexpected proactive command type\r\n")));
                fReturn = FALSE;
                break;
            }
        }

    }

    if (fReturn && !fComplete) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: ParseSTKProSetupMenu: incomplete menu, waiting for more information\r\n")));
        // Delete buffer, this function will be called again, if more data is availabe.
        memset(m_bCmdBuffer, 0, SIMTK_MAX_LENGTH);
    }
    if (fComplete) {
      pSatMenu->cbSize += pSatMenu->dwMenuItemSize;
      pSatCmd->cbSize += pSatMenu->cbSize;
      pSatCmd->dwDetailsSize = pSatMenu->cbSize;
    }

    return fReturn;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Local Information notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProLocalInformation(LPCSTR& rszPointer) {
    UINT               nType;
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMLOCALINFO*      pSatLocalInformation;
    LPCSTR             szDummy;

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

    // Parse: "+STKPRO: 38,<type>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)     ||
        !ParseUInt(rszPointer, FALSE, nType, rszPointer)    ||
        !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProLocalInformation: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatLocalInformation = (SIMLOCALINFO*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    // Unfortunately the module doesn't provide any information Windows Mobile expects.
    pSatLocalInformation->dwParams        = 0;

    pSatLocalInformation->cbSize = ROUNDTODWORD(sizeof(SIMLOCALINFO));

    pSatCmd->cbSize += pSatLocalInformation->cbSize;
    pSatCmd->dwDetailsSize = pSatLocalInformation->cbSize;

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Setup Idle Mode Text notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProSetupIdleText(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMTEXT*           pSatText;
    LPCSTR             szDummy;
    DWORD              dwMaxTextLen = 255;
    WCHAR              wszText[UCS2_LEN];
    UINT               nIconId;
    UINT               nDCS;

    // 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: "+STKPRO: 40,<dcs>,<hex_string>,<icon>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)     ||
         !ParseUInt(rszPointer, FALSE, nDCS, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSetupIdleText: failed to parse parameters (1)\r\n")));
        return FALSE;
    }
    if (nDCS == 4) {
        if (!ParseQuotedEncodedString(ENCODING_GSMDEFAULT_HEX, rszPointer, wszText, wszText + UCS2_LEN)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSetupIdleText: failed to parse parameters (2)\r\n")));
            return FALSE;
        }
    }
    else if (nDCS == 8) {
        if (!ParseUCS2String(rszPointer, wszText, UCS2_LEN, rszPointer)) {
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSetupIdleText: failed to parse parameters (3)\r\n")));
            return FALSE;
        }
    }
    else {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSetupIdleText: unknown DCS (%d)\r\n"), nDCS));
        return FALSE;
    }
    if (!ParseRspParamSeparator(rszPointer, rszPointer)        ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)    ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProSetupIdleText: failed to parse parameters (4)\r\n")));
        return FALSE;
    }

    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;
            pSatText->dwIconIdentifier  = nIconId;
            pSatText->dwIconQualifier   = 0;
        }
        m_fLastCommandIncludedIcon = TRUE;
    }
    pSatText->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatText->dwTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Run AT Command notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProRunATCmd(LPCSTR& rszPointer) {
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMRUNATCMD*       pSatATCmd;
    LPCSTR             szDummy;
    WCHAR              wszAlpha[UCS2_LEN];
    UINT               nType;
    UINT               nIconId;

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

    // Parse: "+STKPRO: 52,<type>,<alpha>,<icon>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                  ||
         !ParseUInt(rszPointer, TRUE, nType, rszPointer)                 ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)              ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProRunATCmd: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatATCmd = (SIMRUNATCMD*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszAlpha)) {
        pSatATCmd->dwParams          = SIM_PARAM_SIMRUNATCMD_TEXTSIZE | SIM_PARAM_SIMRUNATCMD_TEXTOFFSET;
        pSatATCmd->dwTextSize        = (wcslen(wszAlpha) + 1) * sizeof(WCHAR);
        pSatATCmd->dwTextOffset      = ROUNDTODWORD(sizeof(SIMTEXT));
        (void)wcscpy((WCHAR*)((BYTE*)pSatATCmd + pSatATCmd->dwTextOffset), wszAlpha);
    }
    if (nIconId) {
        if (m_fApplicationCanDisplayIcons) {
            pSatATCmd->dwParams         |= SIM_PARAM_SIMRUNATCMD_ICONID;
            pSatATCmd->dwIconIdentifier  = nIconId;
            pSatATCmd->dwIconQualifier   = 0;
        }
        m_fLastCommandIncludedIcon = TRUE;
    }
    pSatATCmd->cbSize = ROUNDTODWORD2(sizeof(SIMTEXT), pSatATCmd->dwTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Language notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProLanguageNotification(LPCSTR& rszPointer) {
    char               szLanguage[UCS2_LEN];
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMLANGUAGE*       pSatLanguage;
    LPCSTR             szDummy;

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

    // Parse: "+STKPRO: 53,<language>"
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                       ||
         !ParseString(rszPointer, szLanguage, UCS2_LEN, rszPointer)    ||
         !ParseRspPostfix(rszPointer, szDummy)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProLanguageNotification: failed to parse parameters\r\n")));
        return FALSE;
    }

    pSatLanguage = (SIMLANGUAGE*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);

    pSatLanguage->dwParams        = SIM_PARAM_SIMLANGUAGE_LANGUAGE;
    (void)_snwprintfz(pSatLanguage->lpszLanguage, MAXLEN_LANGUAGE, L"%S", szLanguage);

    pSatLanguage->cbSize = ROUNDTODWORD(sizeof(SIMLANGUAGE));

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function Intel-style SAT Open Channel notification.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSTKProOpenChannelNotification(LPCSTR& rszPointer) {
    UINT               nCmdQualifier = 0;
    RILSIMTOOLKITCMD*  pSatCmd;
    SIMOPENCHANNEL*    pSatOpenChannel;
    WCHAR              wszAlpha[UCS2_LEN];
    UINT               nIconId;

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

    // Parse: "+STKPRO: 64,<cmd_qualifier>,<alpha>,<icon>,..." (the parameters are not all parsed)
    if (!ParseRspParamSeparator(rszPointer, rszPointer)                  ||
         !ParseUInt(rszPointer, TRUE, nCmdQualifier, rszPointer)         ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUCS2String(rszPointer, wszAlpha, UCS2_LEN, rszPointer)    ||
         !ParseRspParamSeparator(rszPointer, rszPointer)                 ||
         !ParseUInt(rszPointer, FALSE, nIconId, rszPointer)              ||
         !MatchStringAnywhere(rszPointer, "\r\n", rszPointer)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: ParseSTKProRunATCmd: failed to parse parameters\r\n")));
        return FALSE;
    }
    rszPointer -= 2;   // Skip back over last <CR><LF>

    pSatOpenChannel = (SIMOPENCHANNEL*)((BYTE*)pSatCmd + pSatCmd->dwDetailsOffset);
    if (wcslen(wszAlpha)) {
      pSatOpenChannel->dwParams          = SIM_PARAM_SIMOPENCHANNEL_TEXTSIZE| SIM_PARAM_SIMOPENCHANNEL_TEXTOFFSET;
      pSatOpenChannel->dwTextSize        = (wcslen(wszAlpha) + 1) * sizeof(WCHAR);
      pSatOpenChannel->dwTextOffset      = ROUNDTODWORD(sizeof(SIMOPENCHANNEL));
      (void)wcscpy((WCHAR*)((BYTE*)pSatOpenChannel + pSatOpenChannel->dwTextOffset), wszAlpha);
    }
    if (nIconId) {
      if (m_fApplicationCanDisplayIcons) {
          pSatOpenChannel->dwParams         |= SIM_PARAM_SIMOPENCHANNEL_ICONID;
          pSatOpenChannel->dwIconIdentifier  = nIconId;
          pSatOpenChannel->dwIconQualifier   = 0;
      }
      m_fLastCommandIncludedIcon = TRUE;
    }
    pSatOpenChannel->cbSize = ROUNDTODWORD2(sizeof(SIMOPENCHANNEL), pSatOpenChannel->dwTextSize);

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

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Send the response to a Sim-Toolkit event (Intel command set)
//
// 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::SendCmdResponseIntel(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+STKTR=16,32,2\r");
                else if (dwResponse == SIM_RESPONSE_ERR_MOBILEUNABLE && m_nLastSATSetCallDetail == SIMCALL_HOLDCALLS)
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+STKTR=16,33,0\r");
                  else
                  (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+STKTR=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+STKTR=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+STKTR=16,%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_INTEL
            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+STKTR=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+STKTR=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+STKTR=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+STKTR=33,%d\r", dwResponse);
            }
            m_nLastSATDisplayTextFlags  = 0;
            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+STKTR=34,%d,0,0,4,\"59\"\r", dwResponse);
                    } else {
                        // Send "N"
                        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+STKTR=34,%d,0,0,4,\"4E\"\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+STKTR=34,%d,0,0,4,\"%0.2X\"\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+STKTR=34,%d,0,0,4,\"\1B\"\r", dwResponse);
                else
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+STKTR=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+STKTR=35,%d,0,0,4,\"", dwResponse);
                    for (i = 0; i < min((pTextDetails->dwTextSize / sizeof(WCHAR)), wcslen(wszText)); i++) {
                      (void)_snprintfz(szUCS2, 5, "%0.2X", 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+STKTR=35,%d,0,0,4,\"1B\"\r", dwResponse);
                else
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+STKTR=35,%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+STKTR=36,%d,0,0,15,\"%02X\"\r", dwResponse, dwId);
            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;
            }
            // 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_LOCALINFO:
        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+STKTR=%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+STKENV=211,%d,%d\r", dwId, dwResponse == SIM_RESPONSE_OK_HELP ? 1 : 0);
        break;

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

        case SIM_NOTIFY_EVENTDOWNLOAD:
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SimToolkit: EVENT DOWNLOAD 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;
                }
            }
            // Compose the select item response
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+STKENV=214,%d,%d\r", dwResponse, dwId);
            break;

        case SIM_NOTIFY_CALLSETUP:
        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;
}

