/*****************************************************************************
 * Copyright (C) Gemalto M2M GmbH
 *****************************************************************************
 * Project: IMC-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules RD SW A2
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RilDrv/response.cpp $
 * $Revision: /main/ms-d/174 $
 *     $Date: 2014-06-16 13:44:45 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 5.0
 *****************************************************************************
 * Description:
 *  Gemalto IMC RIL
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RilDrv/response.cpp$ 
 * 
 * /main/ms-d/174   2014-06-16 13:44:45   pmackent 
 * Use RIL_E_FDNRESTRICTED error code if available (IPIS100098571)
 *
 * /main/ms-d/173   2014-01-31 12:04:32   pmackent
 * Add CME-Error 351
 *
 * /main/ms-d/172   2013-10-24 13:41:24   pmackent
 * Preparation to support Windows Embedded Compact 2013
 *
 * /main/ms-d/171   2013-10-01 14:13:17   pmackent
 * Solved problem when a concatenated AT command with an AT+CREG/+CGREG in front fails with an CME error
 *
 * /main/ms-d/170   2013-09-13 09:27:14   pmackent
 * Cell Broadcast for CDMA (IPIS100091379)
 *
 * /main/ms-d/169   2013-06-27 17:50:15   pmackent
 * Workaround for wrong "null" response in EHS5
 *
 * /main/ms-d/168   2013-05-22 10:24:08   pmackent
 * Handle CR LF at EHS5 URCs
 *
 * /main/ms-d/167   2013-05-13 14:12:24   pmackent
 * Optional alternative handling of AT+CDV response (IPIS100087446)
 *
 * /main/ms-d/166   2013-05-08 14:18:13   pmackent
 * Workaround for wrong +CCWA URC in CDMA
 *
 * /main/ms-d/165   2013-05-07 11:00:23   pmackent
 * Corrected parsing of CONNECT responses (IPIS100087236)
 *
 * /main/ms-d/164   2013-05-06 15:16:52   pmackent
 * Change handling of CMS error 313
 *
 * /main/ms-d/163   2013-04-26 09:17:17   pmackent
 * Parsing of CDMA status reports added
 *
 * /main/ms-d/162   2013-03-25 16:09:25   pmackent
 * Handle ^SYSINFO URC
 *
 * /main/ms-d/161   2013-03-25 14:43:09   pmackent
 * Small adaptions for PXS8 multimode
 *
 * /main/ms-d/160   2013-03-20 15:32:08   pmackent
 * Change handling of data calls in CDMA in Windows Mobile (IPIS100085910)
 *
 * /main/ms-d/159   2013-03-13 15:04:28   pmackent
 * Additional debug traces for signal critical error.
 *
 * /main/ms-d/158   2013-03-05 11:33:44   pmackent
 * Handle ^SYSSTART URC for EHS5 Rel2
 *
 * /main/ms-d/157   2013-03-04 13:19:51   pmackent
 * Adaptions for EHS5 1.300
 *
 * /main/ms-d/156   2013-02-26 15:07:47   pmackent
 * Adaptions for EHS5 1.290
 *
 * /main/ms-d/155   2013-02-14 15:18:05   pmackent
 * Fix build error on advanced notifications build option
 *
 * /main/ms-d/154   2013-02-08 09:03:33   pmackent
 * Intel style SAT is now official
 *
 * /main/ms-d/153   2013-02-01 14:24:17   pmackent
 * Handling of OMADM URC
 *
 * /main/ms-d/152   2012-12-12 15:24:18   pmackent
 * Workarounds for bugs in PXS8 2.821
 *
 * /main/ms-d/151   2012-11-30 17:05:56   pmackent
 * Handle "ABORTED" message from the EHS5
 *
 * /main/ms-d/150   2012-11-29 15:31:06   pmackent
 * Adaptions call control for EHS5 under CE6
 *
 * /main/ms-d/149   2012-11-27 13:56:21   pmackent
 * Changed timing for voice call status for the EHS5
 *
 * /main/ms-d/148   2012-11-26 16:27:47   pmackent
 * Mark +STK URCs as URC
 *
 * /main/ms-d/147   2012-11-05 11:04:50   pmackent
 * Workaround for PIN2-state-query working only once
 *
 * /main/ms-d/146   2012-10-30 14:36:22   pmackent
 * Fix call status problems (voice and data) in CDMA on WinCE6/7
 *
 * /main/ms-d/145   2012-08-27 16:18:53   pmackent
 * Handle $QCMTI URC for PXS8 Rel2 customer sample
 *
 * /main/ms-d/144   2012-08-24 10:29:48   pmackent
 * Use CTZU for CDMA
 *
 * /main/ms-d/143   2012-07-17 15:31:12   pmackent
 * Clarify a misleading comment
 *
 * /main/ms-d/142   2012-07-17 14:53:37   pmackent
 * Comply to CE7 warning level 4
 *
 * /main/ms-d/141   2012-06-08 11:43:31   pmackent
 * Workaround for missing ^SLCC: URC at end of call in PXS8
 *
 * /main/ms-d/140   2012-06-05 11:47:42   pmackent
 * Add handling of undocumented CDMA activation URC (IPIS100079730)
 *
 * /main/ms-d/139   2012-04-26 14:33:11   pmackent
 * Fix for skip over CONNECT speed
 *
 * /main/ms-d/138   2012-04-18 13:47:13   ctna0256
 * Introducing PVS8
 * Implementing CDMA-SMS
 * Various CDMA enhancements
 *
 * /main/ms-d/137   2012-02-27 15:28:15   ctna0256
 * Fix for problems detecting +CMT URC
 *
 * /main/ms-d/136   2012-02-24 16:17:46   ctna0256
 * Check for unsolicited CME-32 errors
 *
 * /main/ms-d/135   2012-02-24 14:19:50   ctna0256
 * Ignore DISCONNECT messages
 *
 * /main/ms-d/134   2012-02-22 13:27:04   ctna0256
 * Encapsulate use of Intel AT command set
 *
 * /main/ms-d/133   2012-02-17 11:11:19   ctna0256
 * Filter out multi-line URCs (+CMT:) from within responses
 *
 * /main/ms-d/132   2012-02-14 15:13:12   ctna0256
 * Handle URCs within responses.
 *
 * /main/ms-d/131   2012-02-08 15:15:45   ctna0256
 * Add Intel-style SAT
 *
 * /main/ms-d/129   2012-02-03 15:07:26   ctna0256
 * Move URC parsing functions in separate file
 *
 * /main/ms-d/128   2012-02-02 17:03:49   ctna0256
 * FD phonebook workaround and NITZ URCs for Intel platform
 *
 * /main/ms-d/127   2012-01-31 16:38:48   ctna0256
 * Added support for EHS5
 *
 * /main/ms-d/126   2012-01-24 10:45:40   ctna0256
 * Workaround for missing "+CREG: 1" URC in HC25 (IPIS100076952)
 *
 * /main/ms-d/125   2012-01-20 13:20:35   ctna0256
 * Better handling of SAT Idle Mode Text in case of booting the device (IPIS100077101)
 *
 * /main/ms-d/124   2012-01-17 10:22:24   ctna0256
 * Workaround for wrong indication of "+CIEV: psinfo,6" (IPIS100076880)
 *
 * /main/ms-d/123   2012-01-04 15:36:57   ctna0256
 * Outsource XML configuration to external application.
 * Improve CDMA configuration mode.
 *
 * /main/ms-d/122   2012-01-03 15:46:41   ctna0256
 * Introduce PXS8
 *
 * /main/ms-d/121   2011-11-09 09:21:31   ctna0256
 * Different meaning of ^SHUTDOWN-URC
 *
 * /main/ms-d/120   2011-09-26 13:34:54   ctna0256
 * Comply with CE6 warning level 4
 *
 * /main/ms-d/119   2011-09-12 14:50:36   ctna0256
 * New GPS test mode for PH8 R2
 *
 * /main/ms-d/118   2011-07-20 13:01:40   ctna0256
 * Introduce RIL_NOTIFY_DEVSPECIFIC_NETWORK_REJECT_CAUSE and prevent multiple notifications (IPIS100073123)
 *
 * /main/ms-d/117   2011-07-19 11:37:44   ctna0256
 * Change default for DST for PTCRB approval (IPIS100073836)
 *
 * /main/ms-d/116   2011-07-07 10:31:14   ctna0256
 * Check CEER on CREG:3 (IPIS100073123)
 *
 * /main/ms-d/115   2011-06-17 10:41:03   ctna0256
 * New API for extended registration status (IPIS100073242)
 *
 * /main/ms-d/114   2011-06-10 09:09:13   ctna0256
 * New device specific notification about call release cause (IPIS100073123)
 *
 * /main/ms-d/113   2011-05-30 10:20:18   ctna0256
 * Add handling of ^SGPSE URC
 *
 * /main/ms-d/112   2011-05-30 10:11:43   ctna0256
 * Avoid SLCC on PH8 Rel1
 *
 * /main/ms-d/111   2011-05-30 09:36:10   ctna0256
 * Ignore wrong CREG:0 after CREG:3 (IPIS100073002)
 *
 * /main/ms-d/110   2011-03-17 10:07:44   ctna0256
 * Abort dial attempt for emergency calls after timeout (IPIS100070746)
 *
 * /main/ms-d/109   2011-02-15 15:17:13   ctna0256
 * Merge SCKS-WA registry key from Psion
 *
 * /main/ms-d/108   2010-12-22 14:31:22   ctna0256
 * No auto-reboot after emergency shutdown
 *
 * /main/ms-d/107   2010-12-15 10:44:02   ctna0256
 * Performed lint check
 *
 * /main/ms-d/106   2010-11-26 14:16:18   ctna0256
 * Workaround for needless parameter in COLP URC
 *
 * /main/ms-d/105   2010-11-26 10:01:56   ctna0256
 * Workaround for missing parameter in COLP URC
 *
 * /main/ms-d/104   2010-11-04 15:50:37   ctna0256
 * Support new SCKS value
 *
 * /main/ms-d/103   2010-10-12 11:19:09   ctna0256
 * Optional: show CEER messages
 *
 * /main/ms-d/102   2010-09-08 11:24:33   ctna0256
 * RIL option: automatic GPRS reattach (IPIS100064423)
 *
 * /main/ms-d/101   2010-09-03 10:58:27   ctna0256
 * Add call disconnect notification for CE6
 *
 * /main/ms-d/100   2010-08-20 11:17:33   ctna0256
 * Accept ring from modem port, too.
 *
 * /main/ms-d/99   2010-08-19 14:30:06   ctna0256
 * Implementation A-GPS for PH8
 *
 * /main/ms-d/98   2010-08-18 10:23:26   ctna0450
 * Added Telstra Home-Net workaround
 *
 * /main/ms-d/97   2010-07-14 10:40:45   ctna0256
 * Preparation: CCUG and ACM may not be supported in PH8
 *
 * /main/ms-d/96   2010-07-06 10:00:31   ctna0256
 * Handle case of data only SIM
 *
 * /main/ms-d/95   2010-05-27 15:19:29   ctna0256
 * Handle case 1st call ID not equal 1, but 2nd call ID is.
 *
 * /main/ms-d/94   2010-05-21 14:59:44   ctna0256
 * Fix for renumbered call IDs in multiparty call under CE6
 *
 * /main/ms-d/93   2010-05-07 10:18:33   ctna0256
 * New PPP trace feature needed to find connection problems (IPIS100064425)
 *
 * /main/ms-d/92   2010-05-03 15:11:04   ctna0256
 * Abort AT+COPS on ring (IPIS100064182)
 *
 * /main/ms-d/91   2010-04-23 10:20:51   ctna0256
 * Workaround for increasing call IDs after GPRS
 *
 * /main/ms-d/90   2010-02-24 13:26:02   ctna0256
 * Made CE6 driver comply with radiometrics test
 *
 * /main/ms-d/89   2010-02-03 10:51:09   ctna0256
 * Introduction of WinCE6 support
 *
 * /main/ms-d/88   2009-10-13 08:12:55   ctna0256
 * Remove wrong placed function call
 *
 * /main/ms-d/87   2009-07-28 10:40:46   ctna0256
 * Better handling of the case "suspend during initialization" (IPIS100056850)
 *
 * /main/ms-d/86   2009-07-13 09:34:49   ctna0256
 * Removed unnecessary extern declaration
 *
 * /main/ms-d/85   2009-07-06 09:56:23   ctna0256
 * Workaround for wrong busy tone (IPIS100056689)
 *
 * /main/ms-d/84   2009-05-27 10:05:12   ctna0256
 * Deregister module in PUK blocked state caused by wrong PIN change
 *
 * /main/ms-d/83   2009-04-06 13:45:00   ctna0256
 * Initialize NITZ structure
 *
 * /main/ms-d/82   2009-01-16 12:44:33   ctna0450
 * New mechanism to prevent PPP data from slip into the AT response buffer
 *
 * /main/ms-d/81   2008-12-15 15:32:28   ctna0256
 * Workaround for missing quotationmark in CLIP-URC
 *
 * /main/ms-d/80   2008-12-01 12:02:26   ctna0256
 * Reject incoming video calls automatically
 *
 * /main/ms-d/79   2008-11-25 15:25:55   ctna0256
 * Wrong CME error on "SIM not inserted" for HC25 Rel1
 *
 * /main/ms-d/78   2008-10-21 10:03:01   ctna0256
 * Query status of call meter after unsuccessful dial attempt
 *
 * /main/ms-d/77   2008-08-27 11:39:15   ctna0256
 * Optional filter of Type 0 SMS
 *
 * /main/ms-d/76   2008-08-22 10:26:29   ctna0256
 * Set Cinterion copyright text
 *
 * /main/ms-d/75   2008-08-21 09:35:08   ctna0256
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/74   2008-07-22 15:53:01   mp49210
 * Complience to WM7, Lint and PreFast requirements
 *
 * /main/ms-d/73   2008-06-20 11:49:34   mp49210
 * Solved problem with unusually formated +CCWA-URC
 *
 * /main/ms-d/72   2008-06-20 11:05:50   mp49210
 * Remove unused SIEMENS_MAGNETO define
 *
 * /main/ms-d/71   2008-06-12 15:00:25   mp49210
 * Block writing to phonebook during calls, if there had been an incoming call without number
 *
 * /main/ms-d/70   2008-05-05 10:28:04   mp49210
 * Handling of SIM not inserted after SMS retries (Workaround for CCIN pin for SIM card detection)
 *
 * /main/ms-d/69   2008-04-29 13:38:00   mp49210
 * Workaround for missing simstatus URC.
 * New handling of SIM reset.
 *
 * /main/ms-d/68   2008-04-21 08:07:27   mp49210
 * Prevent possible memory violation
 *
 * /main/ms-d/67   2008-04-03 14:41:49   mp49210
 * Introduction of new debug zones
 *
 * /main/ms-d/66   2008-02-29 16:25:48   mp49210
 * Remove potential use of NULL pointer
 *
 * /main/ms-d/65   2008-02-20 09:28:00   mp49210
 * No shutdown on SHUTDOWN: 6
 *
 * /main/ms-d/64   2008-02-11 09:18:20   mp49210
 * Remove LINT warnings
 *
 * /main/ms-d/63   2008-01-24 15:57:43   kr36712
 * integration GPS for MTLR and emergency call
 *
 * /main/ms-d/62   2008-01-18 10:59:26   mp49210
 * Fix for memory leak for advanced notifications
 *
 * /main/ms-d/60   2008-01-17 15:25:58   mp49210
 * Fix for slow UICC SIMs (wrong SIM not inserted error)
 *
 * /main/ms-d/59   2007-11-21 13:35:07   mp49210
 * Lint compatibility
 *
 * /main/ms-d/58   2007-11-16 10:00:18   mp49210
 * New indication for barring of incoming call
 *
 * /main/ms-d/57   2007-11-15 15:31:47   mp49210
 * New CEER value for barring of incoming call
 *
 * /main/ms-d/56   2007-11-15 11:07:01   mp49210
 * New meaning of CME-error 257
 *
 * /main/ms-d/55   2007-11-14 15:16:22   mp49210
 * Introduction of MTLR
 *
 * /main/ms-d/54   2007-11-14 11:07:55   mp49210
 * IPIS100043595: force MMI response for barred call
 *
 * /main/ms-d/53   2007-11-06 11:33:23   mp49210
 * Added missing CONNECT messages
 *
 * /main/ms-d/52   2007-11-02 15:16:58   mp49210
 * Check SIM/USIM after successful At+CPIN? command only
 *
 * /main/ms-d/51   2007-11-01 14:36:47   mp49210
 * Handle new ^SCRD: URC
 *
 * /main/ms-d/50   2007-10-29 11:23:05   mp49210
 * Removed unnecessary double critical section
 *
 * /main/ms-d/49   2007-10-11 16:23:12   mp49210
 * Introduction of AT^SLCC
 *
 * /main/ms-d/48   2007-10-11 16:18:18   mp49210
 * Workaround for missing comman in CUSD URC
 *
 * /main/ms-d/47   2007-08-10 16:56:05   mp49210
 * IPIS100040302: send AT+CSIM after AT+CPIN?
 *
 * /main/ms-d/46   2007-06-28 09:58:52   mp49210
 * Close handle to threads to prevent handle leaks in memory
 *
 * /main/ms-d/45   2007-06-13 15:16:19   mp49210
 * IPIS100036184: CME-Error 313 is now 312
 *
 * /main/ms-d/44   2007-05-29 09:37:01   mp49210
 * Workaoround for wrong error code to AT+CPIN?
 *
 * /main/ms-d/43   2007-05-25 09:42:42   mp49210
 * IPIS100036418: enter USSD answer mode only if '>' sign appears
 *
 * /main/ms-d/42   2007-05-14 16:07:26   mp49210
 * Handling of insolicited CME errors as USSD messages
 *
 * /main/ms-d/41   2007-05-14 15:02:25   mp49210
 * IPIS100036183: wrong parsing of +CUSD: 1,.. URC solved
 *
 * /main/ms-d/40   2007-05-14 11:34:23   mp49210
 * IPIS100036160: workaround for missing comma in +CLIP URC
 *
 * /main/ms-d/39   2007-05-04 13:37:49   mp49210
 * Workaround for Exit when setting UCS2 during SIM initialization
 *
 * /main/ms-d/38   2007-05-02 10:26:25   mp49210
 * New registry key "NoRoaming Indicator"
 *
 * /main/ms-d/37   2007-04-27 08:33:56   mp49210
 * Removed Lint warnings
 *
 * /main/ms-d/36   2007-04-26 13:46:29   mp49210
 * IPIS100035796: change error code for suppl. services
 *
 * /main/ms-d/35   2007-04-24 15:58:17   mp49210
 * IPIS100035501: introduction of list of networks (registry), where the RIL should not send the roaming status
 *
 * /main/ms-d/34   2007-04-10 15:26:22   mp49210
 * Change SMS index range
 * Query SMSC before wiriting SMS to SIM
 *
 * /main/ms-d/33   2007-03-28 14:23:15   mp49210
 * Workaround for unsolicited 'ERROR' instead of '+CUSD: 4'
 *
 * /main/ms-d/32   2007-03-28 13:48:08   mp49210
 * Remove 'Classic RIL' specific code and comments
 *
 * /main/ms-d/31   2007-03-26 14:57:15   mp49210
 * Minimum difference between +CLIP and AT+CLCC
 *
 * /main/ms-d/30   2007-02-16 10:05:28   mp49210
 * Handle error causes for GCF approval
 *
 * /main/ms-d/29   2007-02-13 09:14:08   mp49210
 * Lint compatibility with Crossbow
 *
 * /main/ms-d/28   2007-02-09 16:02:31   mp49210
 * PreFast compatibility
 *
 * /main/ms-d/27   2007-02-09 15:15:19   mp49210
 * Lint compatibility
 *
 * /main/ms-d/26   2007-02-02 13:38:44   mp49210
 * Removed unused debug prints
 *
 * /main/ms-d/25   2007-01-22 10:34:00   mp49210
 * Change in AT+CUSD character coding
 *
 * /main/ms-d/24   2007-01-19 14:27:37   mp49210
 * Problem with unreliable quotation mark in +CCCM URC
 *
 * /main/ms-d/23   2007-01-09 14:36:10   mp49210
 * Change NITZ-URC to UCS2
 *
 * /main/ms-d/22   2007-01-04 13:46:52   mp49210
 * Introduction of SHUTDOWN: URC
 *
 * /main/ms-d/21   2007-01-03 17:04:25   mp49210
 * Replace +CIEV: sounder with +CIEV: audio
 *
 * /main/ms-d/20   2006-12-27 14:20:06   mp49210
 * Workaround for wrong CME-error at AT+CPBR
 *
 * /main/ms-d/19   2006-12-21 18:26:45   mp49210
 * Changed handling of call states
 *
 * /main/ms-d/18   2006-12-21 17:21:48   mp49210
 * Use new GPRS Auto Attach method
 *
 * /main/ms-d/17   2006-12-20 16:58:02   mp49210
 * New format of +CCCM: URC
 *
 * /main/ms-d/16   2006-12-20 11:32:57   mp49210
 * Report system capabilities for voice+data according AT^SIND=psinfo
 *
 * /main/ms-d/15   2006-12-19 18:13:16   mp49210
 * Some changes for commands used during initialization
 *
 * /main/ms-d/14   2006-12-18 17:46:06   mp49210
 * Introduction of AT^SIND=psinfo
 *
 * /main/ms-d/13   2006-12-15 16:38:49   mp49210
 * Remove AT^SMONG (not available in HC25)
 *
 * /main/ms-d/12   2006-12-14 16:38:21   mp49210
 * New syntax for +CIEV URC
 *
 * /main/ms-d/11   2006-12-04 14:52:53   mp49210
 * No <alpha> parameter for +CMT: in Quinn
 *
 * /main/ms-d/10   2006-11-22 11:44:50   mp49210
 * Workaround for HC25 SMS problems
 *
 * /main/ms-d/9   2006-11-21 09:02:18   mp49210
 * New GPRS auto attach mechanism
 *
 * /main/ms-d/8   2006-11-17 11:19:35   mp49210
 * Introduction of AT^SIND
 *
 * /main/ms-d/7   2006-11-14 14:40:03   wm36264
 * Disposed unused CRilEventLog
 *
 * /main/ms-d/6   2006-11-13 10:05:15   mp49210
 * New PIN2 handling in Quinn
 *
 * /main/ms-d/5   2006-11-10 12:00:11   mp49210
 * Set correct parameter type for multiparty
 *
 * /main/ms-d/4   2006-11-03 13:46:45   wm36264
 * Removed "/RLP" from "CONNECT" responses
 *
 * /main/ms-d/3   2006-11-02 09:37:49   mp49210
 * No AT^SLCC in Quinn
 *
 * /main/ms-d/2   2006-10-31 16:02:31   wm36264
 * Workarounds for missing ^SYSSTART and ^SHUTDOWN urcs
 *
 * /main/ms-d/1   2006-10-25 16:51:31   wm36264
 * First transformation from classic RIL
 *
*/

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

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

#include "precomp.h"
#ifdef RIL_LAST_ERROR
#include "ccoreutl.h"
#endif

extern BOOL g_fCallWaiting;
extern BOOL g_fEmergencyCall;
extern BOOL g_bNeedCallInfoRecheck;
extern DWORD g_dwLastCUSSDCmd;

// For CCWA_AFTER_CRING_TINEOUT workaround: filter out all +CCWA-URC which appear
// within CCWA_AFTER_CRING_TINEOUT ms after +CRING.
#define CCWA_AFTER_CRING_TIMEOUT   200
static DWORD s_dwLastRing = 0;

//
// CME error mapping table
//
static const ERRORMAP g_rgemCMEErrors[] =
{
    { RIL_E_PHONEFAILURE,        0},
    { RIL_E_NOCONNECTION,        1},
    { RIL_E_LINKRESERVED,        2},
    { RIL_E_OPNOTALLOWED,        3},
    { RIL_E_OPNOTSUPPORTED,      4},
    { RIL_E_PHSIMPINREQUIRED,    5},
    { RIL_E_PHFSIMPINREQUIRED,   6},
    { RIL_E_PHFSIMPUKREQUIRED,   7},
    { RIL_E_SIMNOTINSERTED,     10},
    { RIL_E_SIMPINREQUIRED,     11},
    { RIL_E_SIMPUKREQUIRED,     12},
    { RIL_E_SIMFAILURE,         13},
    { RIL_E_SIMBUSY,            14},
    { RIL_E_SIMWRONG,           15},
    { RIL_E_INCORRECTPASSWORD,  16},
    { RIL_E_SIMPIN2REQUIRED,    17},
    { RIL_E_SIMPUK2REQUIRED,    18},
    { RIL_E_MEMORYFULL,         20},
    { RIL_E_INVALIDINDEX,       21},
    { RIL_E_NOTFOUND,           22},
    { RIL_E_MEMORYFAILURE,      23},
    { RIL_E_TEXTSTRINGTOOLONG,  24},
    { RIL_E_INVALIDTEXTSTRING,  25},
    { RIL_E_DIALSTRINGTOOLONG,  26},
    { RIL_E_INVALIDDIALSTRING,  27},
    { RIL_E_NONETWORKSVC,       30},
    { RIL_E_NETWORKTIMEOUT,     31},
    { RIL_E_EMERGENCYONLY,      32},
    { RIL_E_NETWKPINREQUIRED,   40},
    { RIL_E_NETWKPUKREQUIRED,   41},
    { RIL_E_SUBSETPINREQUIRED,  42},
    { RIL_E_SUBSETPUKREQUIRED,  43},
    { RIL_E_SVCPINREQUIRED,     44},
    { RIL_E_SVCPUKREQUIRED,     45},
    { RIL_E_CORPPINREQUIRED,    46},
    { RIL_E_CORPPUKREQUIRED,    47},
// Some of these error messages are not supported by every build.
#if defined(RIL_E_ILLEGALMS)
    { RIL_E_ILLEGALMS,          104},
#endif
#if defined(RIL_E_ILLEGALME)
    { RIL_E_ILLEGALME,          106},
#endif
#if defined(RIL_E_GPRSSERVICENOTALLOWED)
    { RIL_E_GPRSSERVICENOTALLOWED, 107},
#endif
#if defined(RIL_E_PLMNNOTALLOWED)
    { RIL_E_PLMNNOTALLOWED,     111},
#endif
#if defined(RIL_E_LOCATIONAREANOTALLOWED)
    { RIL_E_LOCATIONAREANOTALLOWED, 112},
#endif
#if defined(RIL_E_ROAMINGNOTALLOWEDINTHISLOCATIONAREA)
    { RIL_E_ROAMINGNOTALLOWEDINTHISLOCATIONAREA, 113},
#endif
    { RIL_E_SVCUNSUPPORTED,     132},
    { RIL_E_SVCNOTSUBSCRIBED,   133},
    { RIL_E_NETWKTEMPFAILURE,   134},
#if defined(RIL_E_PDPAUTHENTICATIONFAILURE)
    { RIL_E_PDPAUTHENTICATIONFAILURE, 149},
#endif
#if defined(RIL_E_INVALIDMOBILECLASS)
    { RIL_E_INVALIDMOBILECLASS, 150},
#endif
    { RIL_E_NETWKTEMPFAILURE,   256},
    { RIL_E_OPNOTSUPPORTED,     257},
    { RIL_E_NOTREADY,           258},
    { RIL_E_CANCELLED,          259},
    { RIL_E_INVALIDDIALSTRING,  260},
    { RIL_E_SVCUNSUPPORTED,     261}, // Correct meaning of this error is ss not executed, common reason: service is not supported
    { RIL_E_OPNOTALLOWED,       262},
    { RIL_E_OPNOTALLOWED,       300},
    { RIL_E_OPNOTALLOWED,       304},
#if defined(RIL_E_FDNRESTRICT)
    { RIL_E_FDNRESTRICT,        320},
#else
    { RIL_E_DESTINATIONBARRED,  320},  // Not all versions of Windows Mobile support the RIL_E_FDNRESTRICT error code. This error code generates an appropiate error message on the UI.
#endif
    { RIL_E_NETWKTEMPFAILURE,   351},
    { RIL_E_INVALIDINDEX,       370},
    { RIL_E_NOTREADY,           515},
    { RIL_E_NOTREADY,           767}, // this error can also have the meaning of 'operation not allowed', but usually it means 'ME not ready'
    { RIL_E_SIMBUSY,            769},
    { RIL_E_SIMNOTINSERTED,     770},
};
#define NUM_CMEERRORS       (sizeof(g_rgemCMEErrors) / sizeof(ERRORMAP))


//
// CMS error mapping table
//
static const ERRORMAP g_rgemCMSErrors[] =
{
    { RIL_E_UNASSIGNEDNUMBER,         1},
    { RIL_E_MSGBARREDBYOPERATOR,      8},
    { RIL_E_MSGCALLBARRED,           10},
    { RIL_E_MSGXFERREJECTED,         21},
    { RIL_E_DESTINATIONOUTOFSVC,     27},
    { RIL_E_UNIDENTIFIEDSUBCRIBER,   28},
    { RIL_E_SVCUNSUPPORTED,          29},
    { RIL_E_UNKNOWNSUBSCRIBER,       30},
    { RIL_E_NETWKOUTOFORDER,         38},
    { RIL_E_NETWKTEMPFAILURE,        41},
    { RIL_E_CONGESTION,              42},
    { RIL_E_RESOURCESUNAVAILABLE,    43},
    { RIL_E_SVCNOTSUBSCRIBED,        50},
    { RIL_E_SVCNOTIMPLEMENTED,       69},
    { RIL_E_INVALIDMSGREFERENCE,     81},
    { RIL_E_INVALIDMSG,              95},
    { RIL_E_INVALIDMANDATORYINFO,    96},
    { RIL_E_MSGTYPEUNSUPPORTED,      97},
    { RIL_E_ICOMPATIBLEMSG,          98},
    { RIL_E_INFOELEMENTUNSUPPORTED,  99},
    { RIL_E_PROTOCOLERROR,          111},
    { RIL_E_NETWORKERROR,           127},
    { RIL_E_TELEMATICIWUNSUPPORTED, 128},
    { RIL_E_SMTYPE0UNSUPPORTED,     129},
    { RIL_E_CANTREPLACEMSG,         130},
    { RIL_E_PROTOCOLIDERROR,        143},
    { RIL_E_DCSUNSUPPORTED,         144},
    { RIL_E_MSGCLASSUNSUPPORTED,    145},
    { RIL_E_DCSERROR,               159},
    { RIL_E_CMDCANTBEACTIONED,      160},
    { RIL_E_CMDUNSUPPORTED,         161},
    { RIL_E_CMDERROR,               175},
    { RIL_E_MSGBODYHEADERERROR,     176},
    { RIL_E_SCBUSY,                 192},
    { RIL_E_NOSCSUBSCRIPTION,       193},
    { RIL_E_SCSYSTEMFAILURE,        194},
    { RIL_E_INVALIDADDRESS,         195},
    { RIL_E_DESTINATIONBARRED,      196},
    { RIL_E_REJECTEDDUPLICATE,      197},
    { RIL_E_VPFUNSUPPORTED,         198},
    { RIL_E_VPUNSUPPORTED,          199},
    { RIL_E_SIMMSGSTORAGEFULL,      208},
    { RIL_E_NOSIMMSGSTORAGE,        209},
    { RIL_E_PHONEFAILURE,           210},
    { RIL_E_MEMORYFULL,             211},
    { RIL_E_SIMTOOLKITBUSY,         212},
    { RIL_E_SIMDOWNLOADERROR,       213},
    { RIL_E_PHONEFAILURE,           300},
    { RIL_E_MSGSVCRESERVED,         301},
    { RIL_E_OPNOTALLOWED,           302},
    { RIL_E_OPNOTSUPPORTED,         303},
    { RIL_E_INVALIDMSGPARAM,        304},
    { RIL_E_INVALIDMSGPARAM,        305},
    { RIL_E_SIMNOTINSERTED,         310},
    { RIL_E_SIMPINREQUIRED,         311},
    { RIL_E_PHSIMPINREQUIRED,       312},
    { RIL_E_OPNOTALLOWED,           313},      // The AT documentation says "SIM failure" but actually it just means "operation not allowed"
    { RIL_E_SIMBUSY,                314},
    { RIL_E_SIMWRONG,               315},
    { RIL_E_SIMPUKREQUIRED,         316},
    { RIL_E_SIMPIN2REQUIRED,        317},
    { RIL_E_SIMPUK2REQUIRED,        318},
    { RIL_E_MEMORYFAILURE,          320},
    { RIL_E_INVALIDINDEX,           321},
    { RIL_E_MEMORYFULL,             322},
    { RIL_E_UNKNOWNSCADDRESS,       330},
    { RIL_E_NONETWORKSVC,           331},
    { RIL_E_NETWORKTIMEOUT,         332},
    { RIL_E_MESSAGINGERROR,         512},
    { RIL_E_MESSAGINGERROR,         513},
    { RIL_E_MESSAGINGERROR,         514},
    { RIL_E_NOTREADY,               515},
};
#define NUM_CMSERRORS       (sizeof(g_rgemCMSErrors) / sizeof(ERRORMAP))



#ifdef RIL_ADVANCEDUSSDERRORCAUSES
const CMEERRORCAUSE g_rgUSSDErrors[] =
{
    {300, IDS_USSD_ERROR_RESOURCE_LIMITATION},
    {304, IDS_USSD_ERROR_SYSTEM_FAILURE},
    {305, IDS_USSD_ERROR_DATA_MISSING},
    {306, IDS_USSD_ERROR_UNKNOWN_ALPHABET},
    {307, IDS_USSD_ERROR_UNEXPECTED_DATA_VALUE},
    {308, IDS_USSD_ERROR_UNRECOGNIZED_COMPONENT},
    {309, IDS_USSD_ERROR_MISTYPED_COMPONENT},
    {310, IDS_USSD_ERROR_BADLY_STRUCTURED_COMPONENT},
    {311, IDS_USSD_ERROR_MISTYPED_PARAMETER},
    {312, IDS_USSD_ERROR_INITIATING_RELEASE},
    {313, IDS_USSD_ERROR_INITIATING_RELEASE}
};
#define NUM_USSDERRORCAUSES   (sizeof(g_rgUSSDErrors) / sizeof(CMEERRORCAUSE))
#endif

#ifdef RIL_LAST_ERROR
extern DWORD g_dwLastError;
#endif

//
// Response ctor
//
CResponse::CResponse(COM_PORT_TYPE PortType, CRilHandle *pRilHandle) :
m_dwCode(0),
m_pBlob(NULL),
m_cbBlob(0),
m_fUnsolicited(FALSE),
m_fUnrecognized(FALSE),
m_fPotentialBogusResponse(FALSE),
m_PortType(PortType),
m_iNrCallInfo(0),
m_pRilHandle(pRilHandle)
{
    memset(m_CallInfo, 0, sizeof(RILCALLINFO) * MAX_NUMBERCALLS);
}


//
// copy Response ctor
//
CResponse::CResponse(const CResponse &Rsp) :
m_dwCode(Rsp.m_dwCode),
m_pBlob(NULL),
m_cbBlob(0),
m_fUnsolicited(Rsp.m_fUnsolicited),
m_fUnrecognized(Rsp.m_fUnrecognized),
m_fPotentialBogusResponse(Rsp.m_fPotentialBogusResponse),
m_PortType(Rsp.m_PortType),
m_iNrCallInfo(0),
m_pRilHandle(Rsp.m_pRilHandle)
// CBuffer initialized null.
{
    memset(m_CallInfo, 0, sizeof(RILCALLINFO) * MAX_NUMBERCALLS);
}


//
// Response dtor
//
CResponse::~CResponse()
{
    DeleteBlob();
}


//
// Append data to the response
//
BOOL CResponse::AppendString(LPSTR szString, const UINT cbString, LPCSTR& rszRemainder, UINT& rcbRemainder)
{
    UINT cbNewLength = 0;
    UINT cbOldLength = m_cbLength;
    BOOL fRet = FALSE;

    // Append the new data to the buffer
    if (!Append(szString, cbString))
    {
        goto Error;
    }

    // Parse the data
    if (Parse(cbNewLength))
    {
        m_cbLength = cbNewLength;
#ifdef SUPPORTS_EHSX_R1
        // On Intel-style AT commands there might have been an URC within the
        // response of an AT command. In this case the Pars() function had been
        // rearranged the output in m_szData. This rearranged output has to be
        // given back to the calling function.
        if (URCS_MIGHT_BE_IN_RESPONSE)
            memcpy(szString, m_szData, cbString);
#endif
        rszRemainder = szString + cbNewLength - cbOldLength;
        rcbRemainder = cbString - (UINT)(rszRemainder - szString);
    }
    else
    {
        rszRemainder = NULL;
        rcbRemainder = 0;
    }
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
BOOL CResponse::SetBlob(const void* const pBlob, const UINT cbBlob)
{
    BOOL fRet = FALSE;

    DeleteBlob();

    if (cbBlob)
    {
        m_pBlob = AllocBlob(cbBlob);
        if (!m_pBlob)
        {
            // Critically low on memory
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: No memory for new response blob!")));
            SignalCriticalError();
            goto Error;
        }
        memcpy(m_pBlob, pBlob, cbBlob);
    }

    m_cbBlob = cbBlob;
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
BOOL CResponse::OKToError(HRESULT hr)
{
    return MakeError(hr);
}


//
//
//
BOOL CResponse::MakeError(const HRESULT hrError)
{
    // Get rid of the old blob
    DeleteBlob();

    m_fUnsolicited = FALSE;
    m_dwCode = RIL_RESULT_ERROR;
    return SetBlob((void*)&hrError, sizeof(HRESULT));
}


//
// Parse a response
//
BOOL CResponse::Parse(UINT& rcbNewLength)
{
    DWORD   i;
    // NULL-terminate the response string temporarily
    m_szData[m_cbLength] = '\0';

    // Remove any leading zeroes caused by the module powering on/off
    if(m_cbLength>1 && m_szData[0] == '\0')
    {
        for(i=0;i<m_cbLength;i++)m_szData[i] = m_szData[i+1];
        m_cbLength--;
    }
    // In case there are any \0, we replace them with ' '.
    for(i=0;i<m_cbLength;i++)
    {
        if (m_szData[i] == 0)
        {
            m_szData[i] = ' ';
            RILRetailTraceZone((ZONE_ERROR|ZONE_ATCOMMAND), (TEXT("RilDrv: Unexpected NULL-Byte in response on %s.\r\n"), g_ComManager.GetDebugName(m_PortType)));
        }
    }

    ExtRILRetailTraceZone(ZONE_ATCOMMAND, TEXT("Accumulated response (%s): "), g_ComManager.GetDebugName(m_PortType), m_szData);

#ifdef SUPPORTS_EHSX_R1
    if (URCS_MIGHT_BE_IN_RESPONSE) {
        // Problem with Intel-style URCs: they might show up in the middle of a response.
        FindNotificationInResponse();
    }
#endif

    return (ParseNotification(rcbNewLength)    ||
            ParseOKOrError(TRUE, rcbNewLength) ||
            ParseOKOrError(FALSE, rcbNewLength));
}

#ifdef SUPPORTS_EHSX_R1
//
// IsRelevantURC()
// Intel-style URCs might show up within command responses. This function tells, if
// such an URC is in the 1st line of the buffer.
//
// Parameters:
// szStart [in]: buffer with
// uiLenBuffer [in]: number of characters in the buffer
// puiLenLine [out]: this value will hold the numbers characters in this line,
//                   including the <CR><LF> (independently whether this line
//                   contains an URC or not)
//
// Return value: returns TRUE, if URC has been detected.
//
BOOL CResponse::IsRelevantURC(char *szStart, UINT uiLenBuffer, UINT *puiLenLine) const
{
    UINT uiUrcLines = 1;

    // The following URCs are known to cause problems by coming up within the
    // AT command responses.
    const char *szRelevantURCs[] = {"+STKPRO:", "+STKCNF:", "+XREG:", "+XCIEV:", "+STKCC:", "+CMTI:", "+PBREADY", "+CRING:", "+CLIP:", NULL};
    BOOL bIsURC = FALSE;
    UINT uiURC = 0;

    // If this is an empty line, skip URC detection
    if (szStart[0] == '\r' && szStart[1] == '\n') {
        *puiLenLine = 2;
        return FALSE;
    }

    // Special case: the +CMT: URC is followed by a 2nd line containing
    // the content of the message.
    if (uiLenBuffer > 5 && strncmp(szStart, "+CMT:", 5) == 0) {
        bIsURC = TRUE;
        uiUrcLines = 2;
    }
    else {
        // Check for all URCs which might appear in the middle of a response.
        while (szRelevantURCs[uiURC] != NULL) {
            UINT uiLenURC;

            uiLenURC = strlen(szRelevantURCs[uiURC]);
            if (uiLenURC< uiLenBuffer && strncmp(szStart, szRelevantURCs[uiURC], uiLenURC) == 0) {
                bIsURC = TRUE;
                break;
            }
            uiURC++;
        }
    }

    // Count numbers of bytes for URC. Notica, that an URC can have more than 1 line.
    *puiLenLine = 0;
    while (uiUrcLines > 0) {
        // Count bytes until the <CR><LF> has been found or the end of the string has been reached.
        while(*puiLenLine < uiLenBuffer) {
            if (szStart[*puiLenLine] == '\r' && szStart[*puiLenLine+1] == '\n') {
                *puiLenLine += 2;
                break;
            }
            *puiLenLine += 1;
        }
        uiUrcLines--;
    }

    return bIsURC;
}

//
// FindNotificationInResponse()
// Intel-style modules may put URCs within the responses to AT commannds (either
// between the lines of a multi-line output or between the response line and the
// OK). This function will detect such a problem with the responses currently held
// in the buffer. If this is the case, it will rearrange the lines, so that all
// URCs are at the beginning of the buffer followed by all the AT responses.
//
void CResponse::FindNotificationInResponse()
{
    char *pszTmpURC = NULL;
    char *pszTmpResponse = NULL;
    UINT uiPos =  0;
    BOOL fOnlyURCs = TRUE;        // TRUE means, that there are no response lines in the buffer
    BOOL fURCinResponse = FALSE;  // TRUE means, that there is at least one URC in the buffer

    // Allocate buffer hold all URC lines
    pszTmpURC = (char *)AllocBlob(m_cbLength+1);
    if (pszTmpURC == NULL) goto Error;
    memset(pszTmpURC,0, m_cbLength+1);
    // Allocate buffer to hold all response lines
    pszTmpResponse = (char *)AllocBlob(m_cbLength+1);
    if (pszTmpResponse == NULL) goto Error;
    memset(pszTmpResponse,0, m_cbLength+1);

    // Skip through all lines in the buffer.
    while (uiPos < m_cbLength) {
        UINT uiLenLine = 0;

        if (IsRelevantURC(m_szData + uiPos, m_cbLength - uiPos, &uiLenLine)) {
            // This is an URC, add this line to the URC buffer
            memcpy(pszTmpURC+strlen(pszTmpURC), m_szData + uiPos, uiLenLine);
            if (!fOnlyURCs)
                fURCinResponse = TRUE;
        }
        else {
            // This is not an URC, add the line to the response buffer.
            memcpy(pszTmpResponse+strlen(pszTmpResponse), m_szData + uiPos, uiLenLine);
            // If this line contains more than the CR+LF, this is a
            // real response line.
            if (uiLenLine > 2)
                fOnlyURCs = FALSE;
        }
        uiPos += uiLenLine;
    }

    // The output needs to be rearragenged, if there are URCs in the buffer, which
    // follows non-empty response lines. If there are only URCs in the buffer or
    // all URCs are in front of the response lines, it is not necessary to rearrange
    // anything.
    if (fURCinResponse) {
        // Write URCs from temporary buffer in main buffer.
        memcpy(m_szData, pszTmpURC, strlen(pszTmpURC));
        // Append the response lines to the main buffer.
        memcpy(m_szData+strlen(pszTmpURC), pszTmpResponse, strlen(pszTmpResponse));
        ExtRILRetailTraceZone(ZONE_ATCOMMAND, TEXT("Rearranged response (%s): "), g_ComManager.GetDebugName(m_PortType), m_szData);
    }

Error:
    if (pszTmpURC != NULL) FreeBlob(pszTmpURC);
    if (pszTmpResponse != NULL) FreeBlob(pszTmpResponse);
}
#endif

//
//
//
BOOL CResponse::ParseOKOrError(const BOOL fOK, UINT& rcbNewLength)
{
    LPCSTR szPointer = m_szData;
    LPCSTR szCode = (fOK ? "OK\r\n" : "ERROR\r\n");
    HRESULT hrError;
    BOOL fRet;

    for (;;)
    {
        // First search in the beginning of the response
        fRet = MatchStringBeginning(szPointer, szCode, szPointer);
        if (fRet && '\n' != *szPointer)
        {
            // We found "<code><CR>" not followed by <LF> in the beginning of the response
            break;
        }
        else
        {
            // Now search elsewhere in the response
            fRet = MatchStringAnywhere(szPointer, szCode, szPointer);
            if (!fRet && fOK)
            {
                // We didn't find "<code><CR>"
                break;
            }
            if (!fRet && !fOK)
            {
                // We also have to look for an +CME ERROR: 100, which means the command was
                // aborted in the middle of a response.
                fRet = MatchStringAnywhere(szPointer, "+CME ERROR: 100\r\n", szPointer);
                if (!fRet)
                {
                    // We also didn't find "+CME ERROR: 100<CR>"
                    break;
                }
                else if ('\n' != *szPointer)
                {
                    break;
                }
            }
            else if ('\n' != *szPointer && ('\n' == *(szPointer - (fOK?4:8)) || '\r' == *(szPointer - (fOK?4:8))))
            {
                // We found "<code><CR><LF>"  not followed by <LF> and preceded by <LF> or <CR>
                break;
            }
        }
    }
    if (!fRet && fOK)
    {
        // If that didn't succeed either, see if we got an SMS intermediary prompt
        // we'll treat this as an OK for now, but this will cause the command thread
        // to send down the second part of the command which will be the SMS PDU
        fRet = MatchStringBeginning(m_szData, "\r\n> ", szPointer);
        // Sometime the HC25 prints out an extra <CRLF>
        if (!fRet)
            fRet = MatchStringBeginning(m_szData, "\r\n\r\n> ", szPointer);
    }
    if (!fRet && fOK)
    {
        // If we couldn't find the numeric OK or ERROR, try looking for the special OK response
        fRet = MatchStringAnywhere(m_szData, "\r\nOK\r\n", szPointer);
    }

    if (fRet)
    {
        m_fUnsolicited = FALSE;
        m_dwCode = (fOK ? RIL_RESULT_OK : RIL_RESULT_ERROR);
        rcbNewLength = szPointer - m_szData;

        if (!fOK)
        {
            // For error responses, we have additional info -- error code
            hrError = E_FAIL;
            if (!SetBlob((void*)&hrError, sizeof(HRESULT)))
            {
                fRet = FALSE;
                goto Error;
            }
        }
    }

    Error:
    return fRet;
}


//
//
//
BOOL CResponse::ParseRadioSysstart(LPCSTR& rszPointer)
{
    RILEQUIPMENTSTATE res;
    BOOL              fFlightMode = FALSE;

    if (MatchStringAnywhere(rszPointer, "AIRPLANE MODE", rszPointer))
    {
        fFlightMode = TRUE;
    }
    if (!FindRspPostfix(rszPointer, rszPointer))
    {
        return FALSE;
    }
    // Walk back over the <CR><LF>
    rszPointer -= 2;

    if (g_PowerManager.SysstartFinished(&res, fFlightMode))
    {
        m_fUnsolicited = TRUE;

        m_dwCode = RIL_NOTIFY_RADIOEQUIPMENTSTATECHANGED;
        if (!SetBlob((void*)&res, sizeof(RILEQUIPMENTSTATE)))
        {
            return FALSE;
        }
    }

    return TRUE;
}


//
//
//
BOOL CResponse::ParseRadioShutdown(LPCSTR& /*rszPointer*/)
{
    RILEQUIPMENTSTATE res;

    if (!g_PowerManager.ShutdownFinished(&res))
    {
        // something went utterly wrong
        (void)g_PowerManager.ForcePowerOff();
        return FALSE;
    }
    else
    {
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_RADIOEQUIPMENTSTATECHANGED;
        if (!SetBlob((void*)&res, sizeof(RILEQUIPMENTSTATE)))
        {
            return FALSE;
        }
    }

    return TRUE;
}


struct RESPONSEV1VSV0 {
    char szV1String[20];
    UINT uiV0Code;
};

BOOL CResponse::SearchV1Response(LPCSTR& szPointer, UINT *uiRetCode) const
{
    BOOL bFound = FALSE;
    LPCSTR szOriginal = szPointer;
    LPCSTR szTmp;
    INT iSpeed;
    const RESPONSEV1VSV0 V0vsV1[] = {
        {"RING",            2 }, // Ring detected
        {"NO CARRIER",      3 }, // Link not established or disconnected
        {"NO DIALTONE",     6 }, // No dial tone, dialling impossible, wrong mode
        {"BUSY",            7 }, // Remote station busy
        {"NO ANSWER",       8 }, // Remote party doesn't respond (CSD only)
        {"CONNECT",         1 }, // Link established
        {"DISCONNECT",     99 }  // May be sent by the EHS5 Rel1
    };
    UINT i;

    for (i=0; i<(sizeof(V0vsV1) / sizeof(RESPONSEV1VSV0)); i++)
    {
        if (MatchStringBeginning(szPointer, V0vsV1[i].szV1String, szPointer))
        {
            *uiRetCode = V0vsV1[i].uiV0Code;
            bFound = TRUE;
            break;
        }
    }

    if (bFound && *uiRetCode == 2)
        s_dwLastRing = GetTickCount();

    // The "CONNECT" response may have parameters.
    if (bFound && *uiRetCode == 1) {
        // Accept only complete CONNECT responses
        if (MatchStringAnywhere(szPointer, "\r", szTmp)) {
            // Some speed values must be mapped to special response causes.
            iSpeed = atoi(szPointer);
            switch (iSpeed) {
                case 2400:
                    *uiRetCode = 47;
                    break;
                case 4800:
                    *uiRetCode = 48;
                    break;
                case 9600:
                    *uiRetCode = 49;
                    break;
                case 14400:
                    *uiRetCode = 50;
                    break;
                case 28800:
                    *uiRetCode = 51;
                    break;
                case 57600:
                    *uiRetCode = 52;
                    break;
                case 64000:
                    *uiRetCode = 53;
                    break;
                default:
                    *uiRetCode = 1;
            }

            // Skip over speed value and other parameters.
            if (MatchStringAnywhere(szPointer, "\r", szPointer))
                szPointer--;   // Don't skip over the <CR>.
        }
        else {
            // Incomplete response must be ignored.
            szPointer = szOriginal;
            bFound = FALSE;
        }
    }
    return bFound;
}

void CResponse::UpdateCallStatusAfterRing(DWORD dwCallType) const
{
    EnterCriticalSection(&g_CallInfoSection);
    if (g_iNrCallInfo <= 0 && SUPPORTS_SLCC && !AVOID_SLCC)
    {
#ifdef RILDRV_CE6
        RILCALLINFO oCallInfo;
#endif
        // Rare timing condition: the +CRING-URC usually shows up 50ms before the corresponding ^SLCC-URC.
        // We treat this case like the ATD, since there are also some ms between the OK and the ^SLCC-URC.
        g_LastATD = GetTickCount();

        memset(&g_CallInfo[0], 0x00, sizeof(RILCALLINFO));
        g_CallInfo[0].cbSize  = sizeof(RILCALLINFO);
        g_CallInfo[0].raAddress.cbSize = sizeof(RILADDRESS);
        g_CallInfo[0].dwID = 1;
        g_CallInfo[0].dwParams |= RIL_PARAM_CI_ID;
        g_CallInfo[0].dwDirection = RIL_CALLDIR_INCOMING;
        g_CallInfo[0].dwParams |= RIL_PARAM_CI_DIRECTION;
        g_CallInfo[0].dwStatus = RIL_CALLSTAT_INCOMING;
        g_CallInfo[0].dwParams |= RIL_PARAM_CI_STATUS;
        g_CallInfo[0].dwType = dwCallType;
        g_CallInfo[0].dwParams |= RIL_PARAM_CI_TYPE;
        g_CallInfo[0].dwMultiparty = RIL_CALL_SINGLEPARTY;
        g_CallInfo[0].dwParams |= RIL_PARAM_CI_MULTIPARTY;
        g_iNrCallInfo = 1;
        g_iIdxForFirstCall = -1;
        g_bNeedCallInfoRecheck = TRUE;
#ifdef RILDRV_CE6
        memcpy(&oCallInfo, &g_CallInfo[0], sizeof(RILCALLINFO));
        oCallInfo.dwParams &= ~RIL_PARAM_CI_STATUS;
        oCallInfo.dwParams |= RIL_PARAM_CI_CPISTATUS;
        oCallInfo.dwStatus = RIL_CPISTAT_NEW_INCOMING;
        (void)m_pRilHandle->BroadcastRealBlobNotification(RIL_NOTIFY_CALLPROGRESSINFO, (LPVOID)&oCallInfo, sizeof(RILCALLINFO));
#endif
    }
    LeaveCriticalSection(&g_CallInfoSection);
}

BOOL CResponse::IsUrcOrResponse(LPCSTR szPointer) const
{
    BOOL fIsURC = TRUE;
    const char *szDummy;
    UINT uiDummy;

    if (MatchStringBeginning(szPointer, "+CREG: ", szDummy) ||
         MatchStringBeginning(szPointer, "+CGREG: ", szDummy)) {
        if (!ParseUInt(szDummy, TRUE, uiDummy, szDummy)) goto Error;
        if (MatchStringBeginning(szDummy, ",\"", szDummy)) goto Error;
        if (!MatchStringBeginning(szDummy, ",", szDummy)) goto Error;
        fIsURC = FALSE;
    }
    if (MatchStringBeginning(szPointer, "^SCKS: ", szDummy)) {
        if (!ParseUInt(szDummy, TRUE, uiDummy, szDummy)) goto Error;
        if (!MatchStringBeginning(szDummy, ",", szDummy)) goto Error;
        fIsURC = FALSE;
    }

Error:
    return fIsURC;
}

//
//
//
BOOL CResponse::ParseNotification(UINT& rcbNewLength)
{
    LPCSTR szPointer = m_szData;
    BOOL fExpectCRLF = TRUE;
    BOOL fExpectNothing = FALSE;
    BOOL fRet = FALSE;
    UINT uiV0Code;
    LPCSTR szDummyParsing;

    // Parse "<prefix>"
    if (!ParseRspPrefix(szPointer, szPointer))
    {
        goto Error;
    }
    if (MatchStringBeginning(szPointer, "+++", szPointer) &&
        MatchStringAnywhere(szPointer, "NO CARRIER", szPointer))
    {
        // Special case for "+++" followed by NO CARRIER
        m_fUnsolicited = FALSE;
        m_dwCode = RIL_RESULT_NOCARRIER;
        fExpectCRLF = TRUE;
    }
    if (MatchStringAnywhere(szPointer, "AGPS READY: SEND FILE ...", szDummyParsing))
    {
        // This is not an URC, but it has to trigger the AGPS upload. So no
        // parsing will be done here, just the upload is triggered.
        g_GpsHandling.TriggerAGPSUpload();
    }
    if (!IsUrcOrResponse(szPointer)) goto SkipParsing;
    if (g_dwLastCUSSDCmd > 0 && (GetTickCount() - g_dwLastCUSSDCmd) < USSD_TIMEOUT && !m_pRilHandle->FWaitingForRsp() && MatchStringBeginning(szPointer, "ERROR\r\n", szPointer))
    {
        RILSUPSERVICEDATA* prssd = NULL;
        UINT cbStruct;

        // Unsolicited 'ERROR' is in reality a '+CUSD: 4' URC.
        prssd = (RILSUPSERVICEDATA*)AllocBlob(sizeof(RILSUPSERVICEDATA));
        if (!prssd)
            goto Error;
        cbStruct = sizeof(RILSUPSERVICEDATA);
        prssd->cbSize = cbStruct;
        prssd->dwStatus = RIL_SUPSVCDATASTATUS_UNSUPPORTED;
        prssd->dwParams = RIL_PARAM_SSDI_STATUS;

        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_SUPSERVICEDATA;
        if (!SetBlob((void*)prssd, cbStruct))
        {
            goto Error;
        }
        szPointer = szPointer - 2;     // Skip back to lask <cr><lf>
        g_dwLastCUSSDCmd = 0;  // Sometimes the module generates multiple error messages for one request, so we have to reset this value.
    }
    else if (SearchV1Response(szPointer, &uiV0Code))
    {
        if (!ParseV25Response(uiV0Code))
        {
            goto Error;
        }
        fExpectCRLF = TRUE;
    }
    else if (MatchStringBeginning(szPointer, "+CIEV: ", szPointer))
    {
        if (!ParseIndicatorEventValue(szPointer))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "^SCKS: ", szPointer))
    {
        if (!ParseSIMCardStatus(szPointer, TRUE))
        {
           goto Error;
        }
        ResetSecurityStates();
    }
    else if (MatchStringBeginning(szPointer, "^SCRD: ", szPointer))
    {
        if (!ParseSIMCardStatus(szPointer, FALSE))
        {
           goto Error;
        }
    }
#ifdef RIL_ENABLE_ALS
    else if (MatchStringBeginning(szPointer, "^SALS: ", szPointer))
    {
        if (!ParseALSStatusStatus(szPointer))
        {
           goto Error;
        }
    }
#endif
    else if (MatchStringBeginning(szPointer, "^SREG: ", szPointer))
    {
        if (!ParseCdmaRegistrationStatus(szPointer))
        {
            goto Error;
        }
        // In case we did register the advanced registration status, we have to switch
        // back to the normal mode as soon we are registered to a network (or, at least,
        // start attempting).
        if (g_fReportLocationUpdateAsRegistrationState && (g_dwRegStatus==RIL_REGSTAT_HOME || g_dwRegStatus==RIL_REGSTAT_ROAMING || g_dwRegStatus==RIL_REGSTAT_ATTEMPTING))
        {
            g_fReportLocationUpdateAsRegistrationState = FALSE;
        }
        if (g_dwRegStatus == RIL_REGSTAT_HOME)
        {
            m_pRilHandle->GetForceHomeNet()->NotifyRegistered();
        }
    }
    else if (MatchStringBeginning(szPointer, "+CREG: ", szPointer))
    {
        if (!ParseRegistrationStatus(szPointer, RIL_NOTIFY_REGSTATUSCHANGED))
        {
            goto Error;
        }
        // Reset radio technologiy cache, if radio lost registration.
        if (g_dwRegStatus != RIL_REGSTAT_HOME && g_dwRegStatus != RIL_REGSTAT_ROAMING)
            m_pRilHandle->ResetNetworkTechnologyState();
        // In case we did register the advanced registration status, we have to switch
        // back to the normal mode as soon we are registered to a network (or, at least,
        // start attempting).
        if (g_fReportLocationUpdateAsRegistrationState && (g_dwRegStatus==RIL_REGSTAT_HOME || g_dwRegStatus==RIL_REGSTAT_ROAMING || g_dwRegStatus==RIL_REGSTAT_ATTEMPTING))
        {
            g_fReportLocationUpdateAsRegistrationState = FALSE;
        }
        if (g_dwRegStatus == RIL_REGSTAT_HOME)
        {
            m_pRilHandle->GetForceHomeNet()->NotifyRegistered();
        }
    }
    else if (MatchStringBeginning(szPointer, "+CGREG: ", szPointer))
    {
        if (!ParseRegistrationStatus(szPointer, RIL_NOTIFY_GPRSREGSTATUSCHANGED))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CRING: ", szPointer))
    {
        DWORD dwCallType = RIL_CALLTYPE_UNKNOWN;

        // Ring notification
        if (!ParseExtRing(szPointer, &dwCallType))
        {
            goto Error;
        }
        s_dwLastRing = GetTickCount();
        if (SHOULD_WAIT_AFTER_LAST_VOICECMD)
            g_dwLastVoiceCmd = GetTickCount();
        if (COPS1_MAY_HANG_ON_INCOMING_CALL) {
            // Check if an AT+COPS=0 or AT+COPS=1 command is running. If this
            // is the case, it must be aborted.
            CCommand *pRunningCmd;

            pRunningCmd = m_pRilHandle->GetCurrentCommand();
            if (pRunningCmd != NULL) {
                if (pRunningCmd->GetAPIID() == APIID_REGISTERONNETWORK)
                    m_pRilHandle->AbortRunningCommand();
            }
        }
        UpdateCallStatusAfterRing(dwCallType);
    }
    else if (MatchStringBeginning(szPointer, "+CR: ", szPointer))
    {
        // Connection service notification
        if (!ParseServiceInfo(szPointer))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CLIP: ", szPointer))
    {
        // Caller ID notification
        if (!ParseRemotePartyInfo(szPointer, TRUE))
        {
            goto Error;
        }
        g_dwLastCLIPURC = GetTickCount();
    }
    else if (MatchStringBeginning(szPointer, "+COLP: \r\n", szPointer) || MatchStringBeginning(szPointer, "+COLP: \",128\r\n", szPointer))
    {
        // We just ignore these empty '+COLP:' URCs which occasinally show up and have no meaning.
        if (strlen(m_pRilHandle->GetLastDialedNumber())!=0)
        {
            RILREMOTEPARTYINFO rrpi ;

            memset(&rrpi,0,sizeof(rrpi)); // zero struct
            rrpi.cbSize = sizeof(RILREMOTEPARTYINFO);
            rrpi.dwParams = RIL_PARAM_RPI_ADDRESS;
            rrpi.raAddress.dwType = RIL_CALLTYPE_UNKNOWN;
            (void)_snwprintfz(rrpi.raAddress.wszAddress, MAXLENGTH_ADDRESS, L"%S", m_pRilHandle->GetLastDialedNumber());
            rrpi.raAddress.dwType = RIL_ADDRTYPE_UNKNOWN;
            rrpi.raAddress.dwParams = RIL_PARAM_A_TYPE;

            m_dwCode = RIL_NOTIFY_DIALEDID;
            if (!SetBlob((void*)&rrpi, sizeof(RILREMOTEPARTYINFO)))
            {
                goto Error;
            }
#ifdef RIL_INDICATE_COLP
            if (m_pRilHandle->DisplayAdvancedNotifications())
            {
                WCHAR wszText[MAX_RESOURCE_STRING_LEN];
                CNotificationData* pnd = NULL;
                RILSUPSERVICEDATA *prssd;
                UINT cbStruct;

                if (LoadString((HINSTANCE)hInstance, IDS_INDICATION_COLP, wszText, MAX_RESOURCE_STRING_LEN) > 0)
                {
                    WCHAR wszOut[MAX_RESOURCE_STRING_LEN];

                    (void)_snwprintfz(wszOut, MAX_RESOURCE_STRING_LEN, wszText, m_pRilHandle->GetLastDialedNumber());
                    cbStruct = sizeof(RILSUPSERVICEDATA) + (wcslen(wszOut) * sizeof(WCHAR)) + sizeof(WCHAR);
                    prssd = (RILSUPSERVICEDATA*)AllocBlob(cbStruct);
                    if (prssd != NULL)
                    {
                        memcpy(prssd->pbData, (BYTE *)wszOut, (wcslen(wszOut) * sizeof(WCHAR)) + sizeof(WCHAR));
                        prssd->dwParams = RIL_PARAM_SSDI_DATA;
                        prssd->dwStatus = RIL_SUPSVCDATASTATUS_UNSUPPORTED;
                        prssd->dwParams |= RIL_PARAM_SSDI_STATUS;
                        prssd->cbSize = cbStruct;
                        pnd = new CNotificationData;
                        if (pnd)
                        {
                            if (pnd->InitFromRealBlob(RIL_NOTIFY_SUPSERVICEDATA, (void*)prssd, prssd->cbSize))
                                m_pRilHandle->BroadcastNotification(pnd);
                            else
                                delete pnd;
                        }
                        FreeBlob(prssd);
                    }
                }
            }
#endif
            m_pRilHandle->DeleteLastDialedNumber();
        }
        m_fUnsolicited = TRUE;
        szPointer = szPointer - 2;
    }
    else if (MatchStringBeginning(szPointer, "+COLP: ", szPointer))
    {
        // Called ID notification
        if (!ParseRemotePartyInfo(szPointer, FALSE))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CCWA: ", szPointer))
    {
        // Call Waiting notification
        if (!ParseCallWaitingInfo(szPointer))
        {
            goto Error;
        }
        if (WRONG_CCWA_AFTER_RING_IN_CDMA && GetTickCount() - s_dwLastRing < CCWA_AFTER_CRING_TIMEOUT && m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
            // The module might let the +CRING URC be followed by an invalid +CCWA URC
            // which must not be reported to the OS.
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Suppressing invalid +CCWA-URC.\r\n")));
            m_dwCode = 0;
            DeleteBlob();
        }
        else {
            g_fCallWaiting = TRUE;
        }
    }
    else if (MatchStringBeginning(szPointer, "^SCWA:\r\n", szPointer))
    {
        // This URC should never show up: it appears, when a call was waiting, while the
        // module was not ready, and the caller hung up, before out radio module was
        // able to indicate this call. Since it is now too late to do anything about it,
        // there is no need to indicate this event.
        m_fUnsolicited = TRUE;
        szPointer = szPointer - 2;
    }
    else if (MatchStringBeginning(szPointer, "+CSSU: ", szPointer))
    {
        // Unsolicited Supplementary Service notification
        if (!ParseUnsolicitedSSInfo(szPointer))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CSSI: ", szPointer))
    {
        // Intermediate Supplementary Service notification
        if (!ParseIntermediateSSInfo(szPointer))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CCCM: ", szPointer))
    {
        // Current Call Meter notification
        if (!ParseCallMeter(szPointer))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CMT: ", szPointer))
    {
        // SMS-DELIVER notification
        if (m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
            // Normally incomming CDMA messages are stored to the ME storage,
            // but MMS can be deliverd with a +CMT URC in CDMA.
            if (!ParseCdmaMessage(szPointer, RIL_NOTIFY_MESSAGE))
            {
                goto Error;
            }
            // An acknowledgment is not necessary in CDMA.
        }
        else {
            if (!ParseMessage(szPointer, RIL_NOTIFY_MESSAGE))
            {
                goto Error;
            }
            // Send an automatic SMS acknowledgement.
            (void)SetEvent(g_hAckSMSEvent);
        }
    }
    else if (MatchStringBeginning(szPointer, "+CBM: ", szPointer))
    {
        // Broadcast notification
        if (m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
            if (!ParseCdmaMessage(szPointer, RIL_NOTIFY_BCMESSAGE))
            {
                goto Error;
            }
        }
        else {
            if (!ParseMessage(szPointer, RIL_NOTIFY_BCMESSAGE))
            {
                goto Error;
            }
        }
    }
    else if (MatchStringBeginning(szPointer, "$QCBM: ", szPointer))
    {
        // Handle CDMA Cell Broadcast notification.
        if (!ParseCdmaQCBMessage(szPointer))
        {
            goto Error;
        }
        else {
            fExpectNothing = TRUE;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CDS: ", szPointer))
    {
        // SMS-STATUS-REPORT notification
        if (m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
            if (!ParseCdmaMessage(szPointer, RIL_NOTIFY_STATUSMESSAGE))
            {
                goto Error;
            }
        }
        else {
            if (!ParseMessage(szPointer, RIL_NOTIFY_STATUSMESSAGE))
            {
                goto Error;
            }
            // Send an automatic SMS acknowledgement.
            (void)SetEvent(g_hAckSMSEvent);
        }
    }
    else if (MatchStringBeginning(szPointer, "+CMTI: ", szPointer) || MatchStringBeginning(szPointer, "$QCMTI: ", szPointer))
    {
        // Some customer sample firmware versions might use $QCMTI instead of +CMTI
        if (m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
            // CDMA: message has been stored in the ME memory. Windows Mobile
            // doesn't know the concept of an ME memory, sp the RIL has to handle
            // this case.
            if (!ParseCdmaMessageInMemory(szPointer))
            {
                goto Error;
            }
        }
        else {
            // GSM: message has been arrived and is stored on the SIM
            if (!ParseMessageInSim(szPointer, RIL_NOTIFY_MESSAGE_IN_SIM, m_pRilHandle->IsSMSURCInitPhase()))
            {
                goto Error;
            }
        }
    }
    else if (MatchStringBeginning(szPointer, "+CBMI: ", szPointer))
    {
        if (!ParseMessageInSim(szPointer, RIL_NOTIFY_BCMESSAGE_IN_SIM))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CDSI: ", szPointer))
    {
        if (!ParseMessageInSim(szPointer, RIL_NOTIFY_STATUSMESSAGE_IN_SIM))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CUSD: ", szPointer))
    {
        // USSD notification
        if (!ParseUSSDInfo(szPointer, fExpectNothing))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CTZU:", szPointer))
    {
        // The RIL doesn't need this URC, because the necessary information already comes with the "+CIEV: nitz" URC.
        if (FindRspPostfix(szPointer, szPointer))
        {
            // This kind of URC can be ignored, since it contains no info of interest
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SLCC: ", szPointer))
    {
        // Handle SLCC Call List
        if (!ParseCallListNotification(szPointer))
        {
            goto Error;
        }
        m_pRilHandle->SignalCallStateChange();
    }
    else if (MatchStringBeginning(szPointer, "^SSTN: ", szPointer))
    {
        // Unhandled SIM Toolkit command notification
        if (!m_pRilHandle->GetSimToolkit()->ParseNotification(szPointer))
        {
            goto Error;
        }
        // Don't set m_fUnsolicited = TRUE because SAT is handled separetely in it's own thread!
    }
    else if (MatchStringBeginning(szPointer, "^SYSSTART", szPointer))
    {
        if (!ParseRadioSysstart(szPointer))
        {
            goto Error;
        }
        rcbNewLength = szPointer - m_szData; // Skip past the ^SYSSTART URC
        fRet = TRUE;
        goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SYSLOADING", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // The RIL doesn't need to do any action, so the rest of the URC can be ignored.
        {
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SYSINFO", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // The RIL doesn't need to do any action, so the rest of the URC can be ignored.
        {
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SHUTDOWN:", szPointer) || MatchStringBeginning(szPointer, "SHUTDOWN:", szPointer))
    {
        BOOL bShutdown = FALSE;

        // Some Shutdown-URCs are only warnings, so we have to parse the parameter.
        if (!ParseExtendedShutdown(szPointer, bShutdown))
        {
            goto Error;
        }
        if (bShutdown)
        {
            // In case this not a warning URC, we have to shut down the module.
            if (!ParseRadioShutdown(szPointer))
            {
                goto Error;
            }
        }
        fRet = TRUE;
        m_fUnsolicited = TRUE;
        rcbNewLength = szPointer - m_szData; // Skip past the ^SHUTDOWN: URC
    }
    else if (MatchStringBeginning(szPointer, "^SHUTDOWN\r\n", szPointer))
    {
        if (!ParseRadioShutdown(szPointer))
        {
            goto Error;
        }
        rcbNewLength = szPointer - m_szData; // Skip past the ^SHUTDOWN URC
        fRet = TRUE;
        goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SBC: ", szPointer))
    {
        LPCSTR szDummy;
        DWORD dwNotification = 0;
        DWORD dwNotificationParameter = 0;

        // The ^SBC: URC anounces am upcomming emergency shoutdown due to
        // proplems with the power supply.
        // The best way to deal with this is gracefull shutdown of the radio module.
        // This URC will show up on every multiplexer channel. To prevent to generate
        // multiple shutdown events, we will only look for the one on the URC channel.

        if (MatchStringAnywhere(szPointer, "Undervoltage", szDummy))
        {
            dwNotification = RIL_NOTIFY_DEVSPECIFIC_EMERG_SHUTDOWN;
            dwNotificationParameter = EMERG_SHUTDOWN_UNDERVOLTAGE;
        }
        else if (MatchStringAnywhere(szPointer, "Overvoltage shutdown", szDummy))
        {
            dwNotification = RIL_NOTIFY_DEVSPECIFIC_EMERG_SHUTDOWN;
            dwNotificationParameter = EMERG_SHUTDOWN_OVERVOLTAGE;
        }
        else if (MatchStringAnywhere(szPointer, "Overvoltage warning", szDummy))
        {
            dwNotification = RIL_NOTIFY_DEVSPECIFIC_EMERG_SHUTDOWN_WARN;
            dwNotificationParameter = EMERG_SHUTDOWN_OVERVOLTAGE;
        }

        if (FindRspPostfix(szPointer, szPointer))
        {
            if (m_PortType == DATA_PORT && dwNotification != 0)
            {
                (void)m_pRilHandle->BroadcastDWORDBlobNotification(dwNotification, dwNotificationParameter);

                if (dwNotification == RIL_NOTIFY_DEVSPECIFIC_EMERG_SHUTDOWN)
                {
                    DWORD dwDoShutdown = 1;

#ifdef RIL_RADIO_RESILIENCE
                    // If a shutdown due to over/under voltage is announced, don't perform a reboot at shutdown.
                    g_dwRebootEmergencyStatus = dwNotificationParameter;
#endif
                    if (dwNotificationParameter == EMERG_SHUTDOWN_OVERVOLTAGE)
                        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ForceOvervoltageShutdown"), &dwDoShutdown);
                    if (dwNotificationParameter == EMERG_SHUTDOWN_UNDERVOLTAGE)
                        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ForceUndervoltageShutdown"), &dwDoShutdown);
                    if (dwDoShutdown == 1)
                        (void)g_PowerManager.EnterEquipmentState(NULL, RIL_EQSTATE_MINIMUM);
                }
            }
        }
        m_fUnsolicited = FALSE;
        rcbNewLength = szPointer - m_szData; // Skip past the ^SBC URC
        fRet = TRUE;
        goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SCTM_A: ", szPointer) || MatchStringBeginning(szPointer, "^SCTM_B: ", szPointer))
    {
        // The ^SCTM: URC anounces am upcomming emergency shoutdown or an warning.
        // This URC will show up on every multiplexer channel. To prevent to generate
        // multiple shutdown events, we will only look for the one on the URC channel.
        INT iParam;

        if (ParseTemperatureWarning(szPointer, iParam))
        {
            if (m_PortType == URC_PORT)
            {
                BOOL fShutdown;
                DWORD dwReason = EMERG_SHUTDOWN_NONE;

                if (iParam < 0)
                    dwReason = EMERG_SHUTDOWN_UNDERTEMPERATURE;
                else if (iParam > 0)
                    dwReason = EMERG_SHUTDOWN_OVERTEMPERATURE;

                // Reasons -2 and 2 indicate an immediate shutdown.
                fShutdown = ((iParam==-2 || iParam==2)?TRUE:FALSE);

#ifdef RIL_RADIO_RESILIENCE
                // If a shutdown due to over/under temperature is announced, don't perform a
                // reboot at shutdown.
                if (fShutdown)
                    g_dwRebootEmergencyStatus = dwReason;          // Temperature shutdown is coming, no automatic reboots
                else
                    g_dwRebootEmergencyStatus = EMERG_SHUTDOWN_NONE;      // Temperature normal (again), reboots are possible
#endif
                if (fShutdown)
                {
                    DWORD dwDoShutdown = 0;

                    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ForceTemperatureShutdown"), &dwDoShutdown))
                        dwDoShutdown = 1;
                    if (dwDoShutdown != 1)
                        fShutdown = FALSE;
                }

                (void)m_pRilHandle->BroadcastDWORDBlobNotification(fShutdown ? RIL_NOTIFY_DEVSPECIFIC_EMERG_SHUTDOWN : RIL_NOTIFY_DEVSPECIFIC_EMERG_SHUTDOWN_WARN, dwReason);

                if (fShutdown)
                    (void)g_PowerManager.ForcePowerOff();
            }
        }
        m_fUnsolicited = TRUE;
        rcbNewLength = szPointer - m_szData; // Skip past the ^SCTM URC
        fRet = TRUE;
        goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SGPSMT", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // Rest of the URC is of no interest for the RIL
        {
            m_fUnsolicited = TRUE;
            m_dwCode = RIL_NOTIFY_DEVSPECIFIC_GPS_MTLR;
            (void)SetBlob(NULL, 0);
            (void)g_GpsHandling.SwitchGpsStatePassive(TRUE);
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SGPSLR", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // Rest of the URC is of no interest for the RIL
        {
            m_fUnsolicited = TRUE;
            (void)g_GpsHandling.SwitchGpsStatePassive(FALSE);
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SGPSE:", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // The RIL doesn't need to do any action, so the rest of the URC can be ignored.
        {
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "ACTIVATION:", szPointer))
    {
        // CDMA activation will give the status as a free text (for example "success")
        if (!ParseCdmaActivation(szPointer))
        {
            goto Error;
        }
        fRet = TRUE;
        m_fUnsolicited = TRUE;
        rcbNewLength = szPointer - m_szData; // Skip past the rest of the activation URC
    }
    else if (MatchStringBeginning(szPointer, "OMADM:", szPointer))
    {
        // OMADM operations might be announced with a free text (for example "HFA Process Started")
        if (!ParseOMADMNotification(szPointer))
        {
            goto Error;
        }
        fRet = TRUE;
        m_fUnsolicited = TRUE;
        rcbNewLength = szPointer - m_szData; // Skip past the rest of the activation URC
    }
    else if (MatchStringBeginning(szPointer, "+PBREADY", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // There are no parameters to this URC.
        {
            // This is the IMC equivalent to the "+CIEV: simstatus,5" URC.
            g_iCurrentSIMStatus = 5;
            m_pRilHandle->SignalInternalSIMReady();
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "^SXCALLSTAT:", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // The content of the URC is not relevant for the RIL.
        {
            // To find out everything about the new call status, the RIL starts this
            // thread which calls AT+CLCC.
            CloseHandle(CreateThread(NULL, 0, ReCheckCallStatusThreadProc, (LPVOID)m_pRilHandle, 0, 0));
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "+CTZV: ", szPointer))
    {
        // Handle CTZV (NITZ) notification.
        if (!ParseTimeZoneNotification(szPointer))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+CTZDST: ", szPointer))
    {
        // Handle CTZDST (NITZ) notification.
        if (!ParseDayLightSavingNotification(szPointer))
        {
            goto Error;
        }
    }
    else if (MatchStringBeginning(szPointer, "+XNITZINFO:", szPointer))
    {
        // The RIL doesn't need this URC, because the necessary information already comes with the +CTZV URC.
        if (FindRspPostfix(szPointer, szPointer))
        {
            // This kind of URC can be ignored, since it contains no info of interest
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
	else if (MatchStringBeginning(szPointer, "+NITZINFO:", szPointer))
	{
		if (FindRspPostfix(szPointer, szPointer))
        {
            // This kind of URC can be ignored, since it contains no info of interest
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
	}
	else if (MatchStringBeginning(szPointer, "^SSCTN:", szPointer))
	{
		if (FindRspPostfix(szPointer, szPointer))
        {
            // This kind of URC can be ignored, since it contains no info of interest
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
	}
	else if (MatchStringBeginning(szPointer, "^SRADC:", szPointer))
	{
		if (FindRspPostfix(szPointer, szPointer))
        {
            // This kind of URC can be ignored, since it contains no info of interest
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
	}
#ifdef SUPPORTS_EHSX_R1
    else if (MatchStringBeginning(szPointer, "+XCALLSTAT:", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // The content of the URC is not relevant for the RIL.
        {
            // To find out everything about the new call status, the RIL starts this
            // thread which calls AT+CLCC.
            CloseHandle(CreateThread(NULL, 0, ReCheckCallStatusThreadProc, (LPVOID)m_pRilHandle, 0, 0));
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "+XCIEV:,", szPointer))
    {
        if (FindRspPostfix(szPointer, szPointer))   // The RIL doesn't need to do any action, so the rest of the URC can be ignored.
        {
            // This kind of URC can be ignored, since it contains no info of interest
            m_fUnsolicited = TRUE;
            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (MatchStringBeginning(szPointer, "+XCIEV: ", szPointer))
    {
        // Handle XIEV rssi/batt info
        if (!ParseXCievNotification(szPointer))
        {
            goto Error;
        }
        else {
            fExpectNothing = TRUE;
        }
    }
    else if (MatchStringBeginning(szPointer, "+XREG: ", szPointer))
    {
        // Handle XREG registration status
        if (!ParseXregNotification(szPointer))
        {
            goto Error;
        }
        else {
            fExpectNothing = TRUE;
        }
    }
#endif
    else if (MatchStringBeginning(szPointer, "+STKPRO: ", szPointer))
    {
        // Intel style SAT proactive command notification
        if (!m_pRilHandle->GetSimToolkit()->ParseNotificationSTKPRO(szPointer))
        {
            goto Error;
        }
        m_fUnsolicited = TRUE;
    }
    else if (MatchStringBeginning(szPointer, "+STKCNF: ", szPointer))
    {
        // Intel style SAT proactive session status notification
        if (!m_pRilHandle->GetSimToolkit()->ParseNotificationSTKCNF(szPointer))
        {
            goto Error;
        }
        m_fUnsolicited = TRUE;
    }
    else if (MatchStringBeginning(szPointer, "+STKCC: ", szPointer))
    {
        // Intel style SAT call control notification
        if (!m_pRilHandle->GetSimToolkit()->ParseNotificationSTKCC(szPointer))
        {
            goto Error;
        }
        m_fUnsolicited = TRUE;
    }
    else {
        goto SkipParsing;
    }
    goto ParsingCompleted;
SkipParsing:
    if (ILLEGAL_NULL_STRING_IN_RESPONSE && MatchStringAnywhere(szPointer, "null", szPointer))
    {
        // Bug in EHS5: sometimes the module prints out "null". This might be
        // a misprinted URC or a misprinted "ERROR".
        if (FindRspPostfix(szPointer, szPointer))
        {
            // Check, if there is currently a command active.
            if (m_pRilHandle->GetCurrentCommand() == NULL) {
                // This kind of URC must be ignored.
                m_fUnsolicited = TRUE;
            }
            else {
                HRESULT hrError = E_FAIL;

                // This is probably a misprinted error message to the running command.
                m_fUnsolicited = FALSE;
                m_dwCode = RIL_RESULT_ERROR;
                if (!SetBlob((void*)&hrError, sizeof(HRESULT)))
                {
                    goto Error;
                }
            }

            // Walk back over the <CR><LF>
            szPointer -= 2;
        }
        else
            goto Error;
    }
    else if (SPECIAL_RESULT_FOR_ABORT && MatchStringAnywhere(szPointer, "ABORTED\r\n", szPointer)) {
        // The EHS5 might use "ABORTED" instead of "+CME ERROR: 100".
        HRESULT hrError = RIL_E_CMDERROR;

        m_fUnsolicited = FALSE;
        m_dwCode = RIL_RESULT_ERROR;
        if (!SetBlob((void*)&hrError, sizeof(HRESULT)))
        {
            goto Error;
        }
        // Walk back over the <CR><LF>
        szPointer -= 2;
#ifdef RIL_LAST_ERROR
        g_dwLastError = MAKELONG(100, RADIO_CMEERROR);
#endif
    }
    else if (MatchStringAnywhere(szPointer, "+CME ERROR: ", szPointer))
    {
        // Extended error result
        UINT nCode;

        if (!ParseExtError(szPointer, g_rgemCMEErrors, NUM_CMEERRORS, nCode, FALSE))
        {
            goto Error;
        }
        else
        {
#ifdef RIL_ADVANCEDUSSDERRORCAUSES
            if (m_pRilHandle->DisplayAdvancedNotifications())
            {
                // Some error code only show up with special GCF conditions during GCF approval.
                UINT uiText = 0;
                INT iIdx;

                for (iIdx = 0; iIdx < (INT)NUM_USSDERRORCAUSES; iIdx++)
                {
                    if (g_rgUSSDErrors[iIdx].dwCMEError == nCode)
                    {
                        uiText = g_rgUSSDErrors[iIdx].uiErrorText;
                        break;
                    }
                }
                if (uiText != 0)
                {
                    CNotificationData* pnd = NULL;
                    RILSUPSERVICEDATA *prssd;
                    UINT cbStruct;
                    WCHAR wszText[MAX_RESOURCE_STRING_LEN];

                    if (LoadString((HINSTANCE)hInstance, uiText, wszText, MAX_RESOURCE_STRING_LEN) > 0)
                    {
                        cbStruct = sizeof(RILSUPSERVICEDATA) + (wcslen(wszText) * sizeof(WCHAR)) + sizeof(WCHAR);
                        prssd = (RILSUPSERVICEDATA*)AllocBlob(cbStruct);
                        if (prssd != NULL)
                        {
                            memcpy(prssd->pbData, (BYTE *)wszText, (wcslen(wszText) * sizeof(WCHAR)) + sizeof(WCHAR));
                            prssd->dwParams = RIL_PARAM_SSDI_DATA;
                            prssd->dwStatus = RIL_SUPSVCDATASTATUS_UNSUPPORTED;
                            prssd->dwParams |= RIL_PARAM_SSDI_STATUS;
                            prssd->cbSize = cbStruct;
                            pnd = new CNotificationData;
                            if (pnd)
                            {
                                if (pnd->InitFromRealBlob(RIL_NOTIFY_SUPSERVICEDATA, (void*)prssd, prssd->cbSize))
                                    m_pRilHandle->BroadcastNotification(pnd);
                                else
                                    delete pnd;
                            }
                            FreeBlob(prssd);
                        }
                    }
                }
            }
#endif
            if (nCode == 10 || (nCode == 13 && WRONG_CME_ERROR_FOR_NO_SIM))
            {
                BOOL bSendSIMType = TRUE;
                // "+CME ERROR: 10" means "SIM not inserted", so we should update the SIM type.
                // Since thie error code might be false, we have to check, if the sending command
                // is expecting an error.
                if (m_pRilHandle->FWaitingForRsp() && POSSIBLE_WRONG_SIMNOTINSTERTED_ERROR)
                {
                    CCommand *pCmd = m_pRilHandle->GetCurrentCommand();

                    if (pCmd != NULL)
                    {
                        if ((DWORD)pCmd->GetCMET() == (DWORD)g_CMET_CPINWithSIM)
                            bSendSIMType = FALSE;
                    }
                }
                if (bSendSIMType)
                    m_pRilHandle->SetCurrentSIMType(SIMTYPE_NOT_INSERTED);
            }

            if (UNSOL_CME_ERROR_32 && nCode == 32 && !m_pRilHandle->FWaitingForRsp()) {
                // An unsolicited +CME ERROR: 32 appears, when a call cannot be
                // established, because there is some kind of call barring. The
                // following thread will find out about it by using AT+CEER
                CloseHandle(CreateThread(NULL, 0, ACMMaxThreadProc, (LPVOID)m_pRilHandle, 0, 0));
            }

            // An +CME ERROR: 132, 134, 261 or 263 within the USSD timeout period of an AT+CUSD
            // command is an unsolisticated result indicating, that the last USSD code is not
            // supported by the network.
            if ((nCode == 132 || nCode == 134 || nCode == 261 || nCode == 263 || nCode == 100 || nCode == 304) && g_dwLastCUSSDCmd > 0 && (GetTickCount() -g_dwLastCUSSDCmd) < USSD_TIMEOUT && !m_pRilHandle->FWaitingForRsp())
            {
#ifndef RIL_ADVANCEDUSSDERRORCAUSES
                CNotificationData* pnd = NULL;
                RILSUPSERVICEDATA* prssd = NULL;
                UINT cbStruct;

                // Unsolicited 'ERROR' is in reality a '+CUSD: 4' URC.
                prssd = (RILSUPSERVICEDATA*)AllocBlob(sizeof(RILSUPSERVICEDATA));
                if (prssd != NULL) {
                    cbStruct = sizeof(RILSUPSERVICEDATA);
                    prssd->cbSize = cbStruct;
                    prssd->dwStatus = RIL_SUPSVCDATASTATUS_UNSUPPORTED;
                    prssd->dwParams = RIL_PARAM_SSDI_STATUS;

                    pnd = new CNotificationData;
                    if (pnd)
                    {
                        if (pnd->InitFromRealBlob(RIL_NOTIFY_SUPSERVICEDATA, (void*)prssd, prssd->cbSize))
                            m_pRilHandle->BroadcastNotification(pnd);
                        else
                            delete pnd;
                    }
                    FreeBlob(prssd);
                }
#endif
                g_dwLastCUSSDCmd = 0;  // Sometimes the module generates multiple error messages for one request, so we have to reset this value.
            }
        }
#ifdef RIL_LAST_ERROR
        g_dwLastError = MAKELONG(nCode, RADIO_CMEERROR);
#endif
    }
    else if (MatchStringAnywhere(szPointer, "+CMS ERROR: ", szPointer))
    {
        // Extended error result
        UINT nCode;
        if (!ParseExtError(szPointer, g_rgemCMSErrors, NUM_CMSERRORS, nCode, FALSE))
        {
            goto Error;
        }
#ifdef RIL_LAST_ERROR
        g_dwLastError = MAKELONG(nCode, RADIO_CMSERROR);
#endif
    }
    else
    {
        goto Error;
    }

ParsingCompleted:
    if (!fExpectNothing)
    {
        if (fExpectCRLF)
        {
            if (!ParseRspPostfix(szPointer, szPointer))
            {
                goto Error;
            }
        }
        else if (!MatchStringBeginning(szPointer, "\r", szPointer))
        {
            goto Error;
        }
    }
    rcbNewLength = szPointer - m_szData;
    fRet = TRUE;
#ifdef RILDRV_CE6
    // Special problem with Windows CE6: when a CDMA data connection
    // is established, the module only sends a "CONNECT" message, but
    // no ^SLCC URC. Therefore no call progress notifications were
    // sent until now. The TAPI expects two notification, one with
    // "new outgoing" and one with "connected". The RIL must sent
    // them now before any other notification is sent.
    if (m_dwCode == RIL_NOTIFY_CONNECT && m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
        RILCALLINFO oCallInfo;

        memset(&oCallInfo, 0, sizeof(RILCALLINFO));
        LeaveCriticalSection(&g_CallInfoSection);
        oCallInfo.cbSize = sizeof(RILCALLINFO);
        oCallInfo.raAddress.cbSize = sizeof(RILADDRESS);
        oCallInfo.dwParams = RIL_PARAM_CI_ID|RIL_PARAM_CI_DIRECTION|RIL_PARAM_CI_CPISTATUS|RIL_PARAM_CI_TYPE|RIL_PARAM_CI_MULTIPARTY|RIL_PARAM_CI_ADDRESS;
        oCallInfo.dwID = 9;
        oCallInfo.dwDirection = RIL_CALLDIR_OUTGOING;
        // First send "new outgoing"
        oCallInfo.dwStatus = RIL_CPISTAT_NEW_OUTGOING;
        oCallInfo.dwType = RIL_CALLTYPE_DATA;
        oCallInfo.dwMultiparty = RIL_CALL_SINGLEPARTY;
        if (strlen(m_pRilHandle->GetLastDialedNumber()) > 0)
            (void)StringToRILAddress(m_pRilHandle->GetLastDialedNumber(), 128, oCallInfo.raAddress);
        else
            (void)StringToRILAddress(CDMA_DATACONNECTION, 128, oCallInfo.raAddress);
        (void)m_pRilHandle->BroadcastRealBlobNotification(RIL_NOTIFY_CALLPROGRESSINFO, (LPVOID)&oCallInfo, sizeof(RILCALLINFO));
        // Second notification "connected"
        oCallInfo.dwStatus = RIL_CPISTAT_CONNECTED;
        (void)m_pRilHandle->BroadcastRealBlobNotification(RIL_NOTIFY_CALLPROGRESSINFO, (LPVOID)&oCallInfo, sizeof(RILCALLINFO));
    }
#endif
    Error:
    if (!fRet)
    {
        if (m_fPotentialBogusResponse)
        {
            // Heuristic used is to parse everything up to the first CR.
            if (MatchStringAnywhere(szPointer, "\r", szPointer))
            {
                // If the CR is followed by a LF, then consume that, too.
                (void)MatchStringBeginning(szPointer, "\n", szPointer);

                // If what was just parsed is followed by a simple v.25ter response,
                // then consume that as well.
                if (MatchStringBeginning(szPointer+1, "\r", szPointer))
                {
                    (void)MatchStringBeginning(szPointer, "\n", szPointer);
                }

                // The drawback with the preceding heuristic is that two
                // consecutive responses could be consumed, the second one
                // being potentially valid.

                // Whatever is parsed here should be treated as unrecognized
                m_fUnrecognized = TRUE;

                rcbNewLength = szPointer - m_szData;
                fRet = TRUE;
            }
        }

        // Blow away a blob we may have allocated
        DeleteBlob();
    }

    m_fPotentialBogusResponse = FALSE;

    return fRet;
}

//
//
//
BOOL CResponse::ParseV25Response(const UINT nResponseCode)
{
    RILRINGINFO rri; memset(&rri,0,sizeof(rri)); // zero struct
    RILCONNECTINFO rci; memset(&rci,0,sizeof(rci)); // zero struct
    BOOL fRet = FALSE;
    CCommand *pCmd = NULL;

    // NOTE: if IMSI can ever be shorter than 3 characters, this code won't help us
    if (!nResponseCode || 99 < nResponseCode)
    {
        // This can't be a response code
        goto Error;
    }

    switch (nResponseCode)
    {
    case 2:
        // In order not to generate multiple RING signals, we accept RING
        // from our URC port only.
        if (m_PortType == URC_PORT) {
            g_fEmergencyCall = FALSE;
            (void)g_GpsHandling.SwitchGpsStatePassive(FALSE);
            m_fUnsolicited = TRUE;
            m_dwCode = RIL_NOTIFY_RING;
            rri.cbSize = sizeof(RILRINGINFO);
            rri.dwCallType = RIL_CALLTYPE_UNKNOWN;
            rri.dwParams |= RIL_PARAM_RI_CALLTYPE;
            UpdateCallStatusAfterRing(RIL_CALLTYPE_VOICE);
            if (!SetBlob((void*)&rri, sizeof(RILRINGINFO)))
            {
                goto Error;
            }
        }
        m_pRilHandle->SignalCallStateChange();
        break;

    case 3:
        g_fEmergencyCall = FALSE;
        (void)g_GpsHandling.SwitchGpsStatePassive(FALSE);
        m_fUnsolicited = FALSE;
        m_dwCode = RIL_RESULT_NOCARRIER;
#ifdef RILDRV_CE6
        if (g_iLastIdxDisconnected > 0)
            SendDisconnectNotification(m_pRilHandle, m_dwCode);
        else if (AVOID_SLCC)
            g_dwLastDisconnectCause = m_dwCode;
#endif
        if (m_PortType == URC_PORT && SUPPORTS_ADVICE_OF_CHARGE)
            CloseHandle(CreateThread(NULL, 0, ACMMaxThreadProc, (LPVOID)m_pRilHandle, 0, 0));
        if (MISSING_SLCC_AT_CALLEND)
            CloseHandle(CreateThread(NULL, 0, ReCheckCallStatusThreadProc, (LPVOID)m_pRilHandle, 0, 0));
        m_pRilHandle->SignalCallStateChange();
        break;

    case 6:
        g_fEmergencyCall = FALSE;
        (void)g_GpsHandling.SwitchGpsStatePassive(FALSE);
        m_fUnsolicited = FALSE;
        m_dwCode = RIL_RESULT_NODIALTONE;
#ifdef RILDRV_CE6
        if (AVOID_SLCC)
            g_dwLastDisconnectCause = m_dwCode;
#endif
        if (m_PortType == URC_PORT && SUPPORTS_ADVICE_OF_CHARGE)
            CloseHandle(CreateThread(NULL, 0, ACMMaxThreadProc, (LPVOID)m_pRilHandle, 0, 0));
        if (MISSING_SLCC_AT_CALLEND)
            CloseHandle(CreateThread(NULL, 0, ReCheckCallStatusThreadProc, (LPVOID)m_pRilHandle, 0, 0));
        m_pRilHandle->SignalCallStateChange();
        break;

    case 7:
        g_fEmergencyCall = FALSE;
        (void)g_GpsHandling.SwitchGpsStatePassive(FALSE);
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_RESULT_BUSY;
#ifdef RILDRV_CE6
        if (g_iLastIdxDisconnected > 0)
            SendDisconnectNotification(m_pRilHandle, m_dwCode);
        else if (AVOID_SLCC)
            g_dwLastDisconnectCause = m_dwCode;
#endif
        if (MISSING_SLCC_AT_CALLEND)
            CloseHandle(CreateThread(NULL, 0, ReCheckCallStatusThreadProc, (LPVOID)m_pRilHandle, 0, 0));
        m_pRilHandle->SignalCallStateChange();
        break;

    case 8:
        g_fEmergencyCall = FALSE;
        (void)g_GpsHandling.SwitchGpsStatePassive(FALSE);
        m_fUnsolicited = FALSE;
        m_pRilHandle->SetVoiceCallDialing(FALSE);
        m_dwCode = RIL_RESULT_NOANSWER;
#ifdef RILDRV_CE6
        if (AVOID_SLCC)
            g_dwLastDisconnectCause = m_dwCode;
#endif
        if (MISSING_SLCC_AT_CALLEND)
            CloseHandle(CreateThread(NULL, 0, ReCheckCallStatusThreadProc, (LPVOID)m_pRilHandle, 0, 0));
        break;

    case 10:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 300;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 11:
    case 12:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 1200;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 13:
    case 47:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 2400;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 14:
    case 48:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 4800;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 15:
    case 49:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 9600;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 50:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 14400;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 51:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 28800;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 52:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 57600;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 53:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        rci.dwBaudRate = 64000;
        rci.dwParams |= RIL_PARAM_CNI_BAUDRATE;
        break;

    case 99:
        // No action needed.
        m_fUnsolicited = TRUE;
        m_dwCode = 0;
        break;

    case 0:
    case 4:
    case 9:
        goto Error;

    case 1:

        pCmd = m_pRilHandle->GetCurrentCommand();
        if (pCmd != NULL && pCmd->GetAPIID() == APIID_UPLOAD_AGPS) {
            m_fUnsolicited = FALSE;
            m_dwCode = RIL_RESULT_OK;
            break;
        }
        else if (pCmd != NULL && pCmd->GetAPIID() == APIID_DELETE_AGPS) {
            m_fUnsolicited = FALSE;
            break;
        }
        // Fall through to default
    default:
        m_fUnsolicited = TRUE;
        m_dwCode = RIL_NOTIFY_CONNECT;
        break;
    }

    // For data connections, set up the associated RILCONNECTINFO structure
    if (RIL_NOTIFY_CONNECT == m_dwCode)
    {
        rci.cbSize = sizeof(RILCONNECTINFO);
        rci.dwCallType = RIL_CALLTYPE_DATA;
        rci.dwParams |= RIL_PARAM_CNI_CALLTYPE;
        if (!SetBlob((void*)&rci, sizeof(RILCONNECTINFO)))
        {
            goto Error;
        }
    }
    fRet = TRUE;

    Error:
    return fRet;
}

//
// Comparison routine used for binary search below
//
static int _cdecl BSCompareErrors(const void* pElem1, const void* pElem2)
{
    DWORD dwCode1 = ((ERRORMAP*)pElem1)->dwCode;
    DWORD dwCode2 = ((ERRORMAP*)pElem2)->dwCode;
    int iRet;

    if (dwCode1 < dwCode2)
    {
        iRet = -1;
    }
    else if (dwCode1 == dwCode2)
    {
        iRet = 0;
    }
    else
    {
        iRet = 1;
    }
    return iRet;
}

//
// This function sends a call state changed notification with a delay.
//
static DWORD WINAPI SendCSThreadProc(LPVOID pVoid)
{
    CRilHandle* pHandle;

    pHandle = (CRilHandle *)pVoid;
    Sleep(200);
    (void)pHandle->BroadcastRealBlobNotification(RIL_NOTIFY_CALLSTATECHANGED, NULL, 0);
    return 0;
}

//
//
//
BOOL CResponse::ParseExtError(LPCSTR& rszPointer, const ERRORMAP* const rgemMap, const UINT nMapEntries, UINT &nCode, BOOL fSigned)
{
    HRESULT hrError;
    ERRORMAP emKey;
    ERRORMAP* pemFound;
    LPCSTR szDummy;
    BOOL fRet = FALSE;

    // Look for a "<cr>" to make sure we got the whole number
    if (!MatchStringAnywhere(rszPointer, "\r", szDummy))
    {
        // This isn't a complete error notification -- no need to parse it
        goto Error;
    }

    if (fSigned)
        fRet = ParseIntAsUInt(rszPointer, nCode, rszPointer);
    else
        fRet = ParseUInt(rszPointer, FALSE, nCode, rszPointer);

    if (!fRet)
    {
        // We failed parsing
        ParseJunk(1, rszPointer);
        fRet = TRUE;
        goto Error;
    }

    emKey.dwCode = nCode;
    pemFound = (ERRORMAP*)bsearch(&emKey, rgemMap, nMapEntries, sizeof(ERRORMAP), BSCompareErrors);
    hrError = (pemFound ? pemFound->hrError : E_FAIL);

    if (hrError == RIL_E_DESTINATIONBARRED)         // The MMI doesn't recognize this error code, if it is not followed by a call state changed notification
        CloseHandle(CreateThread(NULL, 0, SendCSThreadProc, (LPVOID)m_pRilHandle, 0, 0));  // This thread sends a call state changed notification

    m_fUnsolicited = FALSE;
    m_dwCode = RIL_RESULT_ERROR;
    if (!SetBlob((void*)&hrError, sizeof(HRESULT)))
    {
        goto Error;
    }
    fRet = TRUE;

    Error:
    return fRet;
}

//
//
//
void CResponse::ParseJunk(UINT nCRLFs, LPCSTR& rszPointer)
{
    LPCSTR szPointerTmp = rszPointer;

    UINT i;

    // Try to match all the CRLFs we should have
    for (i = 0; i < nCRLFs; i++)
    {
        if (!MatchStringAnywhere(szPointerTmp, "\r\n", szPointerTmp))
        {
            break;
        }
    }

    // Back up over the last <CR><LF> iff we found one
    if (szPointerTmp > (rszPointer+2))
    {
        rszPointer = szPointerTmp-2;
    }

    m_fUnrecognized = TRUE;

}


//
//
//
BOOL CResponse::ParseOKOrErrorData(CCommand*& rpCmd, BOOL fCmdOk)
{
    HRESULT hr;
    BOOL fRet = FALSE;

    if (rpCmd->ResultHandlerAvailable(fCmdOk))
    {
        if (fCmdOk)
        {
            DeleteBlob();
        }

        hr = rpCmd->CallResultHandler(m_dwCode, GetData(), m_pBlob, m_cbBlob);

        if (FAILED(hr))
        {
            if (!OKToError(hr))
            {
                goto Error;
            }
        }
    }
    else
    {
        DWORD dwCode;
        void*  pDummyBlob;
        UINT   uiDummyBlob;

        // Ensure that possible other result handler is deleted to avoid having it called later
        dwCode = (fCmdOk ? RIL_RESULT_OK : RIL_RESULT_ERROR);
        (void)rpCmd->CallResultHandler(dwCode, GetData(), pDummyBlob, uiDummyBlob);
    }
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
HRESULT CResponse::GetError(void) const
{
    HRESULT hr = S_OK;

    // Make sure this response is an error
    if (RIL_RESULT_ERROR != m_dwCode)
    {
        goto Error;
    }

    // Make sure the blob contains an HRESULT
    if (sizeof(HRESULT) != m_cbBlob)
    {
        goto Error;
    }

    // Extract the HRESULT
    hr = *(HRESULT*)m_pBlob;

    Error:
    return hr;
}


//
//
//
CNotificationData::CNotificationData()
: m_dwCode(0),
m_pBlob(NULL),
m_cbBlob(0),
m_fInited(FALSE),
m_fDelayedInitFromRsp(FALSE)
{
}


//
//
//
CNotificationData::~CNotificationData()
{
    (void)FreeBlob(m_pBlob);
    m_pBlob = NULL;
    m_cbBlob = 0;
    m_dwCode = 0;
    m_fInited = FALSE;
    m_fDelayedInitFromRsp = FALSE;
}


//
//
//
BOOL CNotificationData::InitFromDWORDBlob(const DWORD dwCode, const DWORD dwBlob)
{
    BOOL fRet = FALSE;

    m_dwCode = dwCode;
    m_cbBlob = sizeof(DWORD);
    m_pBlob = (void*)AllocBlob(m_cbBlob);
    if (!m_pBlob)
    {
        goto Error;
    }
    memcpy(m_pBlob, &dwBlob, m_cbBlob);
    m_fInited = TRUE;
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
BOOL CNotificationData::InitFromRealBlob(const DWORD dwCode, const void* const pBlob, UINT cbBlob)
{
    BOOL fRet = FALSE;

    m_dwCode = dwCode;
    if (cbBlob)
    {
        m_cbBlob = cbBlob;
        m_pBlob = AllocBlob(m_cbBlob);
        if (!m_pBlob)
        {
            goto Error;
        }
        memcpy(m_pBlob, pBlob, m_cbBlob);
    }
    m_fInited = TRUE;
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
BOOL CNotificationData::FinishInitFromRspBlob(const CResponse& rRsp)
{
    void* pBlob;
    UINT cbBlob;
    BOOL fRet = FALSE;

    rRsp.GetBlob(pBlob, cbBlob);

    if (cbBlob)
    {
        m_cbBlob = cbBlob;
        m_pBlob = AllocBlob(m_cbBlob);
        if (!m_pBlob)
        {
            goto Error;
        }
        memcpy(m_pBlob, pBlob, m_cbBlob);
    }

    // Turn off delayed init flag
    m_fDelayedInitFromRsp = FALSE;
    m_fInited = TRUE;
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
BOOL CNotificationData::DelayInitFromRspBlob(const DWORD dwCode)
{
    m_dwCode = dwCode;
    m_fDelayedInitFromRsp = TRUE;
    return TRUE;
}

HRESULT FindCMEErrorCode(UINT nCMEError)
{
    HRESULT hrError = E_FAIL;
    ERRORMAP emKey;
    ERRORMAP* pemFound;

    emKey.dwCode = nCMEError;
    pemFound = (ERRORMAP*)bsearch(&emKey, g_rgemCMEErrors, NUM_CMEERRORS, sizeof(ERRORMAP), BSCompareErrors);
    hrError = (pemFound ? pemFound->hrError : E_FAIL);

    return hrError;
}


