telephonyserverplugins/multimodetsy/Multimode/sms/smsbase.cpp
branchopencode
changeset 24 6638e7f4bd8f
parent 0 3553901f7fa8
--- 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 <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
-	}
+// 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
+	}