diff -r 6b1d113cdff3 -r 6638e7f4bd8f telephonyserverplugins/multimodetsy/Multimode/sms/smsbase.cpp --- a/telephonyserverplugins/multimodetsy/Multimode/sms/smsbase.cpp Mon May 03 13:37:20 2010 +0300 +++ b/telephonyserverplugins/multimodetsy/Multimode/sms/smsbase.cpp Thu May 06 15:10:38 2010 +0100 @@ -1,870 +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 // 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;iWrite(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 - // 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;iWrite(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 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 of +CSCA is optional so we have to accomodate for that. - // If was missing then we subsitute it with a dummy '000' . - _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& 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<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< 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 - } +// 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 // 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;iWrite(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 + // 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;iWrite(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 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 of +CSCA is optional so we have to accomodate for that. + // If was missing then we subsitute it with a dummy '000' . + _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& 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<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< 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 + }