// 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
}