diff -r 000000000000 -r 3553901f7fa8 telephonyserverplugins/multimodetsy/Multimode/sms/smsbase.cpp --- /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 // 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 + }