--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/multimodetsy/Multimode/sms/smsbase.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,870 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// AT Command Class for Sms
+// Also contains member functions used by different ATCommands in the GsmTsy.
+//
+//
+
+#include "mSLOGGER.H"
+#include "ATIO.H"
+#include "ATSTD.H"
+#include "mSMSSTOR.H"
+#include "Matstd.h"
+#include "smsbase.H"
+#include "smsutil.h" // for CATSmsUtils
+
+#include <exterror.h> // for KErrGsmSMS... error codes
+
+// Constants
+
+//
+// Macros
+//
+// This macro is used to help keep un-intereting details outside of the main code
+// in this file. The macro uses logging functions and always prefixes writes to the
+// log with the name of the class which is implemented in this file. This macro must
+// only be used by code in this file.
+#ifdef __LOGDEB__
+_LIT8(KLogEntry,"CATSmsCommands::%S\t%S");
+#define LOCAL_LOGTEXT(function,text) {_LIT8(F,function);_LIT8(T,text);LOGTEXT3(KLogEntry,&F,&T);}
+#else
+#define LOCAL_LOGTEXT(function,text)
+#endif
+
+//
+// CATSmsCommands definitions
+//
+
+CATSmsCommands::CATSmsCommands(CATIO* aIo, CTelObject* aTelObject, CATInit* aInit,CPhoneGlobals* aGlobals)
+ :CATCommands(aIo,aTelObject,aInit,aGlobals)
+/**
+ * C++ constructor
+ */
+ {
+ }
+
+CATSmsCommands::~CATSmsCommands()
+/**
+ * C++ destructor
+ */
+ {}
+
+CATSmsCommands::TRequest CATSmsCommands::RequestATCompleted()
+/**
+ * This method is a query function which returns the TRequest value for a request which
+ * has completed, otherwise ENone is returned to denote that no request has completed.
+ *
+ * If this method returns that a request has completed then this method will also
+ * reset the iRequestCompleted flag so that this method that the completion of a
+ * request is reported only once.
+ *
+ * @return The TRequest value of the request that completed, otherwise ENone
+ */
+ {
+ LOCAL_LOGTEXT("RequestATCompleted","enter function");
+ if(iRequestCompleted)
+ {
+ const TRequest tmp(iRequest);
+ iRequest=ENone;
+ iRequestCompleted=EFalse;
+ return tmp;
+ }
+
+ return ENone;
+ }
+
+TBool CATSmsCommands::RequestATActive() const
+ {
+ LOCAL_LOGTEXT("RequestATActive","enter function");
+ return iRequest!=ENone;
+ }
+
+
+void CATSmsCommands::RequestATCommandCancel()
+/**
+ */
+ {
+ LOCAL_LOGTEXT("RequestATCommandCancel","enter function");
+ if(!RequestATActive())
+ return; // There's nothing to do if we're not active
+
+ // Cancel operations
+ LOCAL_LOGTEXT("RequestATCommandCancel","Cancelling...");
+ iRequestCancel=ETrue;
+ }
+
+void CATSmsCommands::InitializeRequestData(TRequest aReq)
+ {
+ LOCAL_LOGTEXT("InitializeRequestData","enter function");
+
+ iRequest=aReq;
+ iRequestStage=0;
+ iRequestCompleted=EFalse;
+ iRequestError=KErrNone;
+ iRequestCancel=EFalse;
+ }
+
+TInt CATSmsCommands::RequestATCommand(TRequest aReq)
+ {
+ LOCAL_LOGTEXT("RequestATCommand","enter function");
+
+ // Ensure we are not allready handling a request
+ if(RequestATActive())
+ {
+ LOCAL_LOGTEXT("RequestATCommand","A request is already in progress, returning KErrInUse");
+ return KErrInUse;
+ }
+
+ //Initialize request data
+ InitializeRequestData(aReq);
+
+ // Handle request
+ TInt ret(KErrNone);
+ const TEventSource nullSource(TEventSource(-1)); // This fiddle is so we can pass a 'null' event source
+
+ switch(aReq)
+ {
+ case EGetSCAFromPhone:
+ ret=GetSCAFromPhone(nullSource);
+ break;
+
+ case ESetSCAInPhone:
+ ret=SetSCAInPhone(nullSource);
+ break;
+
+ case ESetPhoneToCMTMode:
+ ret=SetPhoneToCMTMode(nullSource);
+ break;
+
+ case ESetPhoneToCMTIMode:
+ ret=SetPhoneToCMTIMode(nullSource);
+ break;
+
+ case ENone: // Must not be caught by default case
+ LOCAL_LOGTEXT("RequestATCommand","Request is ENone, so will not do anything");
+ break;
+
+ default:
+ LOCAL_LOGTEXT("RequestATCommand","Unknown request");
+ __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequest));
+ ret=KErrNotSupported;
+ }
+
+ LOCAL_LOGTEXT("RequestATCommand","exit function");
+ return ret;
+ }
+
+
+TInt CATSmsCommands::SetSCAInPhone(const TEventSource& aEventSource)
+/**
+ * Sets phone's default SCA to be that which is stored in iRequestSCA.
+ * IMPORTANT: If this method returns an error then EventSignal will complete our request.
+ * @return Standard KErr... codes
+ */
+ {
+ LOCAL_LOGTEXT("SetSCAInPhone","enter function");
+ __ASSERT_DEBUG(iRequest==ESetSCAInPhone,Panic(EATSmsCommandsWrongRequest));
+
+ TInt ret(KErrNone);
+ switch(iRequestStage)
+ {
+ case EStage0:
+ if(iRequestCancel) // Handle request cancellation, if needed
+ {
+ LOCAL_LOGTEXT("SetSCAInPhone","Request has been cancelled");
+ ret=KErrCancel;
+ }
+ else
+ {
+ // Set the SCA to use as the default in the phone's memory
+ iTxBuffer.Copy(KSmsSetSCCommand);
+ iTxBuffer.Append(KDblQuoteChar);
+ const TInt count(iRequestSCA.iTelNumber.Length());
+ for(TInt i=0;i<count;++i)
+ {
+ if(CATSmsUtils::IsAddressChar(TChar(iRequestSCA.iTelNumber[i])))
+ iTxBuffer.Append(TChar(iRequestSCA.iTelNumber[i]));
+ }
+ iTxBuffer.Append(KDblQuoteChar);
+ iTxBuffer.Append(KCommaChar);
+
+ TUint val;
+ CATSmsUtils::GetTypeOfAddressInDecimal(iRequestSCA,val);
+ iTxBuffer.AppendNum(val,EDecimal);
+
+ iTxBuffer.Append(KCarriageReturn);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+ break;
+
+ case EStage1:
+ HandleWriteCompletion(aEventSource);
+ break;
+
+ case EStage2:
+ // If we did not get an error
+ if(HandleResponseCompletion(aEventSource)==KErrNone)
+ CompleteRequest();
+ else
+ {
+ if(iRequestCancel) // Handle request cancellation, if needed
+ {
+ LOCAL_LOGTEXT("SetSCAInPhone","Request has been cancelled");
+ ret=KErrCancel;
+ }
+ else
+ {
+ // An error occurred
+ // Try to set SCA again, but this time don't use <tosca>
+ // The Motorola Timeport needs this behaviour
+ iTxBuffer.Copy(KSmsSetSCCommand);
+ iTxBuffer.Append(KDblQuoteChar);
+
+ // Prefix phone number with a '+' if it's international
+ if(iRequestSCA.iTypeOfNumber==RMobilePhone::EInternationalNumber)
+ iTxBuffer.Append(KPlusChar);
+
+ const TInt count(iRequestSCA.iTelNumber.Length());
+ for(TInt i=0;i<count;++i)
+ {
+ if(CATSmsUtils::IsAddressChar(TChar(iRequestSCA.iTelNumber[i])))
+ iTxBuffer.Append(TChar(iRequestSCA.iTelNumber[i]));
+ }
+ iTxBuffer.Append(KDblQuoteChar);
+ iTxBuffer.Append(KCarriageReturn);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+ }
+ break;
+
+ case EStage3:
+ HandleWriteCompletion(aEventSource);
+ break;
+
+ case EStage4:
+ if((ret=HandleResponseCompletion(aEventSource))==KErrNone)
+ {
+ // We've finished the request
+ CompleteRequest();
+ }
+ break;
+
+ default:
+ LOCAL_LOGTEXT("SetSCAInPhone","Unknown request stage");
+ __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequestStage));
+ ret=KErrGeneral;
+ }
+
+ ++iRequestStage; // Increment request stage for next iteration
+
+ return ret;
+ }
+
+
+TInt CATSmsCommands::GetSCAFromPhone(const TEventSource& aEventSource)
+/**
+ * Gets phone's default SCA from phone and saves it in iRequestSCA.
+ * IMPORTANT: If this method returns an error then EventSignal will complete our request.
+ * @return Standard KErr... codes
+ */
+ {
+ LOCAL_LOGTEXT("GetSCAFromPhone","enter function");
+ __ASSERT_DEBUG(iRequest==EGetSCAFromPhone,Panic(EATSmsCommandsWrongRequest));
+
+ TInt ret(KErrNone);
+ switch(iRequestStage)
+ {
+ case EStage0:
+ if(iRequestCancel) // Handle request cancellation, if needed
+ {
+ LOCAL_LOGTEXT("GetSCAFromPhone","Request has been cancelled");
+ ret=KErrCancel;
+ }
+ else
+ {
+ // Initialize data
+ iRequestSCA.iTypeOfNumber=RMobilePhone::EUnknownNumber;
+ iRequestSCA.iNumberPlan=RMobilePhone::EUnknownNumberingPlan;
+ iRequestSCA.iTelNumber.Zero();
+
+ // Send SCA request to phone
+ iTxBuffer.Format(KServiceCentreQueryCommand);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+ break;
+
+ case EStage1:
+ HandleWriteCompletion(aEventSource);
+ break;
+
+ case EStage2:
+ ret=HandleResponseCompletion(aEventSource);
+ if(ret!=KErrNone)
+ break;
+
+ // Did the phone have an SCA in default memory
+ ret=ParseRxResultsForCSCAResponse(iRequestSCA);
+ if(ret==KErrNone && iRequestSCA.iTelNumber.Length()>0)
+ {
+ // We've finished the request
+ CompleteRequest();
+ ret=KErrNone;
+ }
+ else
+ {
+ if(iRequestCancel) // Handle request cancellation, if needed
+ {
+ LOCAL_LOGTEXT("GetSCAFromPhone","Request has been cancelled");
+ ret=KErrCancel;
+ }
+ else
+ {
+ // Check if the phone has a SCA after doing a memory refresh
+ iTxBuffer.Format(KServiceCentreQueryCommandWithCRES);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+ }
+ break;
+
+ case EStage3:
+ HandleWriteCompletion(aEventSource);
+ break;
+
+ case EStage4:
+ ret=HandleResponseCompletion(aEventSource);
+ if(ret!=KErrNone)
+ break;
+
+ // Did the phone have an SCA in default memory, if so initialise iRequestSCA
+ ret=ParseRxResultsForCSCAResponse(iRequestSCA);
+ if(ret==KErrNone)
+ {
+ // We've finished the request
+ CompleteRequest();
+ ret=KErrNone;
+ }
+ else
+ {
+ // We do not have an SCA and have exhausted all possibilities ;-(
+ LOCAL_LOGTEXT("GetSCAFromPhone","Have not been able to find an SCA to use");
+
+ //
+ // We have to complete with KErrNone so that the second part of the GetSMSP
+ // retrieval IPC is called. If we do not do this the MSMSMESS file will get
+ // it's iGetSMSPList array out of sync.
+ CompleteRequest();
+ ret=KErrNone;
+ }
+ break;
+
+ default:
+ LOCAL_LOGTEXT("GetSCAFromPhone","Unknown request stage");
+ __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequestStage));
+ ret=KErrGeneral;
+ }
+
+ ++iRequestStage; // Increment request stage for next iteration
+
+ return ret;
+ }
+
+
+TInt CATSmsCommands::SetPhoneToCMTMode(const TEventSource& aEventSource)
+/**
+ * Sets the phone into CMT mode by using 'AT+CNMI=x,2'
+ * IMPORTANT: If this method returns an error then EventSignal will complete our request.
+ * @return Standard KErr... codes
+ */
+ {
+ LOCAL_LOGTEXT("SetPhoneToCMTMode","enter function");
+ __ASSERT_DEBUG(iRequest==ESetPhoneToCMTMode,Panic(EATSmsCommandsWrongRequest));
+
+ TInt ret(KErrNone);
+ switch(iRequestStage)
+ {
+ case EStage0:
+ if(iRequestCancel) // Handle request cancellation, if needed
+ {
+ LOCAL_LOGTEXT("SetPhoneToCMTMode","Request has been cancelled");
+ ret=KErrCancel;
+ }
+ else
+ {
+ // Send 'AT+CNMI=?' to find out phones capabilities
+ iTxBuffer.Format(KGetCNMIConfigCommand);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+ break;
+
+ case EStage1:
+ HandleWriteCompletion(aEventSource);
+ break;
+
+ case EStage2:
+ { // Curly brackets used to scope use of cnmiFirstValue
+ //
+ // If the phone returns ERROR then ignore the error and assume the
+ // CNMI first parameter should be 2
+ TInt cnmiFirstValue(ECnmiMode2);
+ if(HandleResponseCompletion(aEventSource)==KErrNone)
+ {
+ // Parse the response from the phone
+ TRAP(ret,ParseCNMIFirstCapabilityL(cnmiFirstValue));
+ ret=KErrNone; // Ignore errors from ParseCNMIFirstCapabilityL call
+ }
+
+ // Send 'AT+CNMI=x,2' to phone to set it to CMT mode
+ iTxBuffer.Format(KSmsSetCMTMode,cnmiFirstValue);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+ break;
+
+ case EStage3:
+ HandleWriteCompletion(aEventSource);
+ break;
+
+ case EStage4:
+ ret=HandleResponseCompletion(aEventSource);
+ if(ret==KErrNone)
+ {
+ // We have completed our request
+ CompleteRequest();
+ }
+ break;
+
+ default:
+ LOCAL_LOGTEXT("SetPhoneToCMTMode","Unknown request stage");
+ __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequestStage));
+ ret=KErrGeneral;
+ }
+
+ ++iRequestStage; // Increment request stage for next iteration
+
+ return ret;
+ }
+
+
+TInt CATSmsCommands::SetPhoneToCMTIMode(const TEventSource& aEventSource)
+/**
+ * Sets the phone into CMTI mode by using 'AT+CNMI=x,1'
+ * IMPORTANT: If this method returns an error then EventSignal will complete our request.
+ * @return Standard KErr... codes
+ */
+ {
+ LOCAL_LOGTEXT("SetPhoneToCMTIMode","enter function");
+ __ASSERT_DEBUG(iRequest==ESetPhoneToCMTIMode,Panic(EATSmsCommandsWrongRequest));
+
+ TInt ret(KErrNone);
+ switch(iRequestStage)
+ {
+ case EStage0:
+ if(iRequestCancel) // Handle request cancellation, if needed
+ {
+ LOCAL_LOGTEXT("SetPhoneToCMTIMode","Request has been cancelled");
+ ret=KErrCancel;
+ }
+ else
+ {
+ // Send 'AT+CNMI=?' to find out phones capabilities
+ iTxBuffer.Format(KGetCNMIConfigCommand);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+ break;
+
+ case EStage1:
+ HandleWriteCompletion(aEventSource);
+ break;
+
+ case EStage2:
+ { // Curly brackets used to scope use of cnmiFirstValue
+ //
+ // If the phone returned ERROR then ignore the error and assume the
+ // CNMI first parameter should be 2
+ TInt cnmiFirstValue(2);
+ if(HandleResponseCompletion(aEventSource)==KErrNone)
+ {
+ // Parse the response from the phone
+ TRAP(ret,ParseCNMIFirstCapabilityL(cnmiFirstValue));
+ ret=KErrNone; // Ignore errors from ParseCNMIFirstCapabilityL call
+ }
+
+ // Send 'AT+CNMI=x,1' to phone to set it to CMTI mode
+ iTxBuffer.Format(KSmsSetCMTIMode,cnmiFirstValue);
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+ break;
+
+ case EStage3:
+ HandleWriteCompletion(aEventSource);
+ break;
+
+ case EStage4:
+ ret=HandleResponseCompletion(aEventSource);
+ if(ret==KErrNone)
+ {
+ // We have completed our request
+ CompleteRequest();
+ }
+ break;
+
+ default:
+ LOCAL_LOGTEXT("SetPhoneToCMTIMode","Unknown request stage");
+ __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequestStage));
+ ret=KErrGeneral;
+ }
+
+ ++iRequestStage; // Increment request stage for next iteration
+
+ return ret;
+ }
+
+
+
+void CATSmsCommands::CompleteRequest(TInt aError)
+/**
+ * Common code for local AT request functions to complete a request from a derived class.
+ * In the header file smsbase.h the default value for aError ir KErrNone.
+ */
+ {
+ LOCAL_LOGTEXT("CompleteRequest","enter function");
+ iRequestStage=0;
+ iRequestCompleted=ETrue;
+ iRequestError=aError;
+ }
+
+void CATSmsCommands::HandleWriteCompletion(TEventSource aSource)
+/**
+ * Common code for handling a write event from the CATIO class when communicating
+ * with the modem.
+ */
+ {
+ LOCAL_LOGTEXT("HandleWriteCompletion","enter function");
+ __ASSERT_DEBUG(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected));
+ iIo->WriteAndTimerCancel(this);
+ AddCmsErrorExpectString();
+ StandardWriteCompletionHandler(aSource,KATResponseTimeout);
+ }
+
+
+TInt CATSmsCommands::HandleResponseCompletion(TEventSource aSource,TBool aValidateExpectString)
+/**
+ * Common code for handling a read event from the CATIO class when communicating
+ * with the modem. Does some parsing of response to see if 'OK' or 'ERROR' was responded.
+ */
+ {
+ LOCAL_LOGTEXT("HandleResponseCompletion","enter function");
+
+ //
+ // The below is an ASSERT ALWAYS just so that we do not get a WINSCW UREL warning.
+ // The below only needs to be a ASSERT_DEBUG
+ __ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected));
+ iIo->WriteAndTimerCancel(this);
+
+ TInt ret(KErrNone);
+ if(aValidateExpectString)
+ ret=ValidateExpectString(); // This will only check for 'OK' or 'ERROR'
+
+ if(ret!=KErrNone)
+ {
+ //
+ // If we received some kind of error, see if the CMS ERROR stuff can provide
+ // a more meanigful error code
+ ret=ConvertCMSErrorToKErr(CMSErrorValue());
+ }
+
+ RemoveCmsErrorExpectString();
+ RemoveStdExpectStrings();
+ return ret;
+ }
+
+void CATSmsCommands::EventSignal(TEventSource aEventSource)
+/**
+ * Handles events for local AT commands
+ * Will complete request if a handler returns anything other than KErrNone
+ */
+ {
+ LOCAL_LOGTEXT("EventSignal","enter function");
+ TInt error(KErrNone);
+ // Check if a timeout occurred
+ if(aEventSource==ETimeOutCompletion)
+ {
+ LOCAL_LOGTEXT("EventSignal","Timeout event has occurred");
+ iIo->RemoveExpectStrings(this);
+ iIo->WriteAndTimerCancel(this);
+ error=KErrTimedOut;
+ }
+ else
+ {
+ // Dispatch event to appropriate request handler
+ switch(iRequest)
+ {
+ case EGetSCAFromPhone:
+ error=GetSCAFromPhone(aEventSource);
+ break;
+
+ case ESetSCAInPhone:
+ error=SetSCAInPhone(aEventSource);
+ break;
+
+ case ESetPhoneToCMTMode:
+ error=SetPhoneToCMTMode(aEventSource);
+ break;
+
+ case ESetPhoneToCMTIMode:
+ error=SetPhoneToCMTIMode(aEventSource);
+ break;
+
+ case ENone: // Must not be caught by default case
+ break;
+ default:
+ LOCAL_LOGTEXT("EventSignal","Unknown request");
+ __ASSERT_DEBUG(EFalse,Panic(EATSmsCommandsUnknownRequest));
+ }
+ }
+
+ if(error!=KErrNone)
+ CompleteRequest(error);
+ }
+
+
+TBool CATSmsCommands::ComparePrefMem(const TStorageType& aName) const
+ {
+ LOCAL_LOGTEXT("ComparePrefMem","enter function");
+ return iPhoneGlobals->iPhonePrefMem==aName;
+ }
+
+void CATSmsCommands::SetCurrentPrefMem(const TStorageType& aStorageName)
+ {
+ LOCAL_LOGTEXT("SetCurrentPrefMem","enter function");
+ iTxBuffer.Format(KSetPrefMemCommandWithString,&aStorageName,&aStorageName); // Setting both the read and write memory to one and the same store(ME or SM).
+ iIo->Write(this,iTxBuffer);
+ iIo->SetTimeOut(this,KATWriteTimeout);
+ }
+
+
+
+TInt CATSmsCommands::ParseRxResultsForCSCAResponse(RMobilePhone::TMobileAddress& aTelNumber)
+/**
+ * Analyse rx results for a CSCA response and attempt to parse into provided tel.
+ * The actual work is done in DoParseRxResultsForCSCAResponseL. Since this method
+ * can't leave and ParseBufferLC() has to be called and ParseBufferLC() puts something
+ * on the cleanup stack, the "Do" method had to be added.
+ * @return Standard KErr... values
+ */
+ {
+ LOCAL_LOGTEXT("ParseRxResultsForCSCAResponse","enter function");
+ TInt ret(KErrNone);
+ TRAPD(leaveCode,ret = DoParseRxResultsForCSCAResponseL(aTelNumber));
+ if(leaveCode)
+ return leaveCode;
+ else
+ return ret;
+ }
+
+
+TInt CATSmsCommands::DoParseRxResultsForCSCAResponseL(RMobilePhone::TMobileAddress& aTelNumber)
+/**
+ * Analyse rx results for a CSCA response and attempt to parse into provided tel
+ * number object
+ * @return Standard KErr... values
+ */
+ {
+ LOCAL_LOGTEXT("DoParseRxResultsForCSCAResponseL","enter function");
+ TInt ret(KErrNotFound);
+
+ // Parse buffer
+ ParseBufferLC();
+ TDblQueIter<CATParamListEntry> iter(iRxResults);
+
+ // Extract tokens from parser
+ CATParamListEntry* cscaEntry=iter++;
+
+ if((cscaEntry)&&(cscaEntry->iResultPtr == KCSCAResponseString))
+ {
+ CATParamListEntry* telNumberEntry=iter++;
+ if (telNumberEntry)
+ {
+ //
+ // Parse tokens into a TMobileAddress
+ //
+ // Type of number field <tosca> of +CSCA is optional so we have to accomodate for that.
+ // If <tosca> was missing then we subsitute it with a dummy '000' <tosca>.
+ _LIT8(KDummyNumberTypeEntry,"000");
+ CATParamListEntry* numberTypeEntry=iter++;
+ if (!numberTypeEntry)
+ ret=CATSmsUtils::CopyAddressStringToAddressStruct(telNumberEntry->iResultPtr,KDummyNumberTypeEntry,aTelNumber);
+ else
+ ret=CATSmsUtils::CopyAddressStringToAddressStruct(telNumberEntry->iResultPtr,numberTypeEntry->iResultPtr,aTelNumber);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); // ParseBufferLC
+ return ret;
+ }
+
+
+TInt CATSmsCommands::CMSErrorValue()
+/*
+ * Returns the error code decoded from the response string .eg '+CMS ERROR: xxx'.
+ * This functions considers '+CMS ERROR: 500' and 'ERROR' as the error 500.
+ * @return if there was an error the ETSI or KErr error value
+ * @return if there was not an error then KErrNone
+ */
+ {
+ LOCAL_LOGTEXT("CMSErrorValue","enter function");
+ // Locate error string
+ iBuffer.Set(iIo->Buffer());
+ TInt pos=iBuffer.FindF(KERRORResponseString);
+ if (pos==KErrNotFound)
+ return KErrNone; // If we can't find the 'ERROR' string then that means there was not an error ;-)
+
+ // Locate error value
+ // (ie. read in all digits form the first found to the end of the string)
+ const TInt length=iBuffer.Length();
+ pos+=KCMGSResponseStringLength;
+ while(pos<length && !(TChar(iBuffer[pos]).IsDigit()))
+ pos++;
+
+ TInt ret=500; // 500 is the error value for 'undefined'
+ if(pos<length) // Only decode error value if we found some digits
+ {
+ TLex8 lex(iBuffer.Mid(pos));
+ TUint16 val;
+ if(lex.Val(val,EDecimal)==KErrNone)
+ ret=val;
+ }
+
+ LOGTEXT2(_L8("CATSmsCommands::CmsErrorValue\terror = %d"),ret);
+ return ret;
+ }
+
+
+TInt CATSmsCommands::ConvertCMSErrorToKErr(const TInt& aCmsError) const
+ {
+ LOCAL_LOGTEXT("ConvertCMSErrorToKErr","enter function");
+ if(aCmsError==0)
+ return KErrNone;
+
+ return KErrGsmSmsBase-aCmsError;
+ }
+
+
+void CATSmsCommands::ProcessCapsElementL(TDblQueIter<CATParamListEntry>& aIter,TInt32& aCapsMask)
+//
+// Process a single element, i.e. a range or a bracketed list
+//
+ {
+ TInt r=KErrNone;
+_LIT8(KOpenBracket, "(");
+_LIT8(KCloseBracket, ")");
+_LIT8(KDashChar, "-");
+
+ CATParamListEntry* entry=aIter;
+ if(!entry)
+ return;
+
+ aIter++;
+
+ TBool listPresent=EFalse; // Is there a list here?
+ if(entry->iResultPtr==KOpenBracket)
+ {
+ listPresent=ETrue;
+ entry=aIter++;
+ if(!entry)
+ return;
+ }
+
+// Process the element
+ do
+ {
+// It might be a range, signified by a '-'
+ TInt pos=entry->iResultPtr.Find(KDashChar);
+ if(pos!=KErrNotFound)
+ {
+ TInt32 rangeStart;
+ TLex8 rangeStartString(entry->iResultPtr.Left(pos));
+ if((r=rangeStartString.Val(rangeStart))!=KErrNone)
+ User::Leave(r);
+
+ TInt32 rangeEnd;
+ TInt l;
+ if((l=entry->iResultPtr.Length()-pos-1)<=0)
+ User::Leave(KErrGeneral);
+ TLex8 rangeEndString(entry->iResultPtr.Right(l));
+ if((r=rangeEndString.Val(rangeEnd))!=KErrNone)
+ User::Leave(r);
+
+ if((rangeStart<0)||(rangeStart>31)||(rangeEnd<0)||(rangeEnd>31))
+ User::Leave(KErrGeneral);
+
+ for(TInt i=rangeStart;i<(rangeEnd+1);i++)
+ aCapsMask|=(1<<i);
+ }
+// Or it might be the close bracket ')'
+ else if(entry->iResultPtr==KCloseBracket)
+ listPresent=EFalse;
+// Or it might be a single value
+ else
+ {
+ TInt32 value;
+ TLex8 string(entry->iResultPtr);
+ if((r=string.Val(value))!=KErrNone)
+ User::Leave(r);
+
+ if((value<0)||(value>31))
+ User::Leave(KErrGeneral);
+
+ aCapsMask|=(1<<value);
+ }
+ entry=aIter++;
+ }
+ while((listPresent)&&(entry!=NULL));
+ aIter--;
+ }
+
+
+void CATSmsCommands::ParseCNMIFirstCapabilityL(TInt& aHighestValue)
+ {
+ ParseBufferLC(ETrue);
+ TDblQueIter<CATParamListEntry> iter(iRxResults);
+ CATParamListEntry* entry=iter++;
+
+ if((entry==NULL)||(entry->iResultPtr!=KCNMIResponseString))
+ {
+ LOGTEXT(_L8("Error - Cannot find CNMI: string"));
+ User::Leave(KErrNotFound);
+ }
+
+ TInt32 bitmap(0);
+ ProcessCapsElementL(iter,bitmap);
+
+ aHighestValue=ECnmiMode0; // bitmap&0x01 denotes highest value of 0
+
+ if(bitmap&KCapsCnmiMode2)
+ aHighestValue=ECnmiMode2;
+ else if(bitmap&KCapsCnmiMode1) // Mode 1 only set if mode 2 not supported
+ aHighestValue=ECnmiMode1;
+ else if(bitmap&KCapsCnmiMode3) // Only set to mode 3 if this is the only mode supported
+ aHighestValue=ECnmiMode3;
+
+ CleanupStack::PopAndDestroy(); // ParseBufferLC object
+ }