// Copyright (c) 2001-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:
//

/**
 @file
*/

#include "csimsmsmess.h"
#include <testconfigfileparser.h>
#include "Simlog.h"
#include <etelmm.h>
#include "CSimTsyMode.h"

//macro
#define UNPACK_PCKG(target,source,datatype)  datatype& target=  (*(TPckg<datatype>*)(source))()

const TInt KSmsSettingGranularity=5;	// < Granularity of SMS parameter list arrays.
const TInt KSmsStoreGranularity=2;	// < Granularity of SMS store list array.
const TInt KNoMessageReferenceInCofigurationFile=0;//the reference number returned to the client is 0 if
													//no value is found in the configuration file
			
//
// CSimSmsMessaging
//

void CSimSmsMessaging::CloseSmsObj(TAny* aObj)
/**
 *	A utility function for cleaning up the stack.
 */
	{
	((CObject*)aObj)->Close();
	}

CSimSmsMessaging* CSimSmsMessaging::NewL(CSimPhone* aPhone)
/**
 *	Standard two phase constructor.
 */
	{
	CSimSmsMessaging* smsMess=new(ELeave) CSimSmsMessaging(aPhone);
	TCleanupItem newObjClose(CloseSmsObj,smsMess);
	CleanupStack::PushL(newObjClose);
	smsMess->ConstructL();
	CleanupStack::Pop();
	return smsMess;
	}

CSimSmsMessaging::CSimSmsMessaging(CSimPhone* aPhone)
		: iPhone(aPhone), iSmspBusy(EFalse)
	{}

void CSimSmsMessaging::ConstructL()
/**
 * Retrieve the SMS-related tags from the configuration file.
 *
 * 
 * If there are no constraints any SMS specified in the configuration file and the "incoming SMS event" timer will
 * be started.
 */
    {
    InitializeL();
    }

void CSimSmsMessaging::InitializeL()
	{
	LOGSMS1("Starting to Load and Parse Sms Messaging Config ");
	iRxTimer=CSimTimer::NewL(iPhone);
	iTxTimer=CSimTimer::NewL(iPhone);
	iSmspTimer=CSimTimer::NewL(iPhone);
		
	iSmsRxParameterListGsm=new(ELeave) CArrayFixFlat<TSmsRxParametersGsm>(KSmsSettingGranularity);	
		
		
	FindAndCreateRxAttributesL();
	
	iSmsTxParametersListGsm=new(ELeave) CArrayFixFlat<TSmsTxParametersGsm>(KSmsSettingGranularity);		
			
	FindAndCreateTxAttributesL();
	iSmsStores=new(ELeave) CArrayFixFlat<CSimSmsStore*>(KSmsStoreGranularity);
	FindAndCreateSmsStoresL(iPhone);
	FindAndCreateConstraints();
	iSmspReadAll=new(ELeave) CArrayPtrFlat<CListReadAllAttempt>(KSmsStoreGranularity);
	FindAndCreateSmsParamsL();

	// NOTE - no need to start iRxTimer; this will be started once a EMobileSmsMessagingReceiveMessage
	// request is received and/or Send Sms contrainst satisfied (see CompleteTxPendingReq)
	
	LOGSMS1("Finished parsing SMS Messaging config parameters");
	}


void CSimSmsMessaging::Reset()
    {
 	if(iSmsRxParameterListGsm)
		{
		iSmsRxParameterListGsm->Delete(0,iSmsRxParameterListGsm->Count());
		delete iSmsRxParameterListGsm;
        iSmsRxParameterListGsm = NULL;
		}
		
	if(iSmsTxParametersListGsm)
		{
		iSmsTxParametersListGsm->Delete(0,iSmsTxParametersListGsm->Count());
		delete iSmsTxParametersListGsm;
        iSmsTxParametersListGsm = NULL;
		}
			
    delete iSmspEntries;
    iSmspEntries = NULL;
    
    if (iSmsStores)
        {
        TInt storeCount=iSmsStores->Count();    
        for(TInt i=0;i<storeCount;i++)
            {
            iSmsStores->At(i)->Close();
            }
        delete iSmsStores;
        iSmsStores = NULL;
        }

    if (iSmspReadAll)
        {
        iSmspReadAll->ResetAndDestroy();
        delete iSmspReadAll;
        iSmspReadAll = NULL;
        }
        
    iConstraints.Reset();
    
    iSmsTxCnt = 0;
    iSmsRxCnt = 0;
    iCurrentConstraint = 0;
    iConstraintRxCnt = 0;
    
    iSmspBusy   = EFalse;
    iRxState    = ESmsRxStateIdle;
    iTxState    = ESmsTxStateIdle;
       
    delete iRxTimer;
    iRxTimer = NULL;

    delete iTxTimer;
    iTxTimer = NULL;
    
    delete iSmspTimer;
    iSmspTimer = NULL;
    }

CSimSmsMessaging::~CSimSmsMessaging()
/**
 *	Standard destructor.  Any objects created by the ::ConstructL() function should be destroyed here.
 */
	{
	Reset();
	}

void CSimSmsMessaging::FindAndCreateRxAttributesL()
/**
 * Extract values from the tags
 * SmsRx, SmsRxPeriod, SmsAckNackPause, SmsResumePause, SmsDeliveryReport
 *
 */	{
	TInt ret=KErrNone;
	TInt count=CfgFileSection()->ItemCount(KSmsRx);
	const CTestConfigItem* item=NULL;
	TInt i;
	TSmsRxParametersGsm smsRxParameterGsm;
	
	LOGSMS2("CSimSmsMessaging::FindAndCreateRxAttributesL IN [count=%d]", count);

	// Need to do this *before* entering the loop (so that we know 
	// whether or not to read a delivery report pdu off the config file).
	iSmsControlCaps=RMobileSmsMessaging::TMobileSmsControlCaps(CfgFileSection()->ItemValue(KSmsControlCaps,KDefaultSmsControlCaps));

	for(i=0;i<count;i++)
		{
		item=CfgFileSection()->Item(KSmsRx,i);
		if(!item)
			break;

		TPtrC8 smsPdu,sca;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,smsPdu);
		if(ret!=KErrNone)
			{
			LOGPARSERR("smsPdu",ret,0,&KSmsRx);
			continue;
			}
		else
			{
			smsRxParameterGsm.iPdu.Zero();
			ConvertAsciiSms(smsPdu,smsRxParameterGsm.iPdu);
			}
		
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,sca);
		if(ret!=KErrNone)
			{
			LOGPARSERR("sca",ret,1,&KSmsRx);
			continue;
			}
		else
			{
			smsRxParameterGsm.iSca=sca;
			}
			
		//get delivery report pdu 
		smsRxParameterGsm.iDeliveryReport.Zero(); 	
		if (!(iSmsControlCaps & RMobileSmsMessaging::KCapsReceiveUnstoredClientAck))
			{
			TPtrC8 deliveryReportPdu;
			ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,deliveryReportPdu);
			if( (ret!=KErrNone) && (ret!=KErrGeneral) )
				{
				LOGPARSERR("deliveryReportPdu",ret,2,&KSmsRx);
				}
			else
				{
				if (CSimTsyMode::GetMode() != CSimTsyMode::ECdmaV1)			
					{
  					ConvertAsciiSms(deliveryReportPdu,smsRxParameterGsm.iDeliveryReport); 
  					}

				}
			}

		// add to list of params
		iSmsRxParameterListGsm->AppendL(smsRxParameterGsm);	
	
		}// for
	
	iSmsRxPeriod=CfgFileSection()->ItemValue(KSmsRxPeriod,KDefaultSmsRxPeriod);
	iAckNackCompletePause=CfgFileSection()->ItemValue(KSmsAckNackPause,KDefaultSmsAckNackPause);
	iResumeCompletePause=CfgFileSection()->ItemValue(KSmsResumePause,KDefaultSmsResumePause);

	if (iSmsControlCaps & RMobileSmsMessaging::KCapsReceiveUnstoredClientAck)
		iSmsReceiveMode=RMobileSmsMessaging::EReceiveUnstoredClientAck;
	else iSmsReceiveMode=RMobileSmsMessaging::EReceiveModeUnspecified;
	LOGSMS5("iSmsRxPeriod =%d, iAckNackCompletePause=%d, iResumeCompletePause=%d, iSmsControlCaps=%d",iSmsRxPeriod, iAckNackCompletePause, iResumeCompletePause, iSmsControlCaps); 
	LOGSMS4("iSmsModeCaps =%d, iSmsRxStartDelay = %d, iSmsReceiveMode = %d",iSmsModeCaps , iSmsRxStartDelay, iSmsReceiveMode);	
	LOGSMS2("CSimSmsMessaging::FindAndCreateRxAttributesL OUT [count=%d]", iSmsRxParameterListGsm->Count());	
	}

void CSimSmsMessaging::FindAndCreateTxAttributesL()
/**
 * Extract values from the tags
 * SmsTx, SmsTxPause
 *
 */
	{
	TInt ret=KErrNone;
	TInt count=CfgFileSection()->ItemCount(KSmsTx);
		
	TSmsTxParametersGsm   smsTxParametersGsm;
	
	const CTestConfigItem* item=NULL;
	for(TInt i=0;i<count;i++)
		{
		item=CfgFileSection()->Item(KSmsTx,i);//Tx
		if(!item)
			break;

		//get pdu
		TPtrC8 smsTx;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,smsTx);
		if(ret!=KErrNone)
			{
			LOGPARSERR("smsTx",ret,0,&KSmsTx);
			continue;
			}
		else
			{			
			smsTxParametersGsm.iPdu.Zero();
			ConvertAsciiSms(smsTx,smsTxParametersGsm.iPdu);
			}

		//get Sca
		TPtrC8 sca;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,sca);
		if (ret!=KErrNone)
			{
			LOGPARSERR("sca",ret,1,&KSmsTx);
			continue;
			}
		else
			{			
			smsTxParametersGsm.iSca.Copy(sca);				
			}
			
		//get reference
		TInt reference;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,reference);
		if(ret!=KErrNone)
			{
			LOGPARSERR("reference",ret,2,&KSmsTx);
			smsTxParametersGsm.iRef=KNoMessageReferenceInCofigurationFile;	
			}
		else
			{	
			smsTxParametersGsm.iRef=reference;				
			}
	
		//get submit report pdu
		TPtrC8 submitReportPdu;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,submitReportPdu);
		if(ret!=KErrNone)
			{
			LOGPARSERR("submitReportPdu",ret,3,&KSmsTx);
			continue;
			}
		else
			{			
			smsTxParametersGsm.iSubmitReport.Zero(); 	
			ConvertAsciiSms(submitReportPdu,smsTxParametersGsm.iSubmitReport); 
			}
		
		//get expected error code
		TInt errorCode;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,4,errorCode);
		if(ret!=KErrNone)
			{
			LOGPARSERR("errorCode",ret,4,&KSmsTx);
			continue;
			}
		else
			{		
			smsTxParametersGsm.iExpectedError=errorCode;					
			}		
		
		iSmsTxParametersListGsm->AppendL(smsTxParametersGsm);			

		} //end for SmsTx Tag
	
	iSmsTxPause=CfgFileSection()->ItemValue(KSmsTxPause,KDefaultSmsTxPause);
	}

void CSimSmsMessaging::FindAndCreateConstraints()
/**
 * Extract values from the tags
 * SmsStartRxDelay
 *
 */
	{
	TInt ret=KErrNone;
	TInt count=CfgFileSection()->ItemCount(KSmsStartRxDelay);
	const CTestConfigItem* item=NULL;
	TConstraintEntry constraint;
	for(TInt i=0;i<count;i++)//Rx delay
		{
		item=CfgFileSection()->Item(KSmsStartRxDelay,i);
		if(!item)
			break;
		
		TInt ipc,noBefore,noAfter;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,ipc);//only :SendMessage() is supported
		if(ret!=KErrNone || ipc!=4207)
			{
			LOGPARSERR("ipc",ret,0,&KSmsStartRxDelay);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,noBefore);
		if(ret==KErrNone)
			constraint.iIpcCnt=noBefore;
		else
			{
			LOGPARSERR("noBefore",ret,1,&KSmsStartRxDelay);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,noAfter);
		if(ret==KErrNone)
			constraint.iRxCnt=noAfter;
		else
			{
			LOGPARSERR("noAfter",ret,2,&KSmsStartRxDelay);
			continue;
			}
		
		__ASSERT_ALWAYS(iConstraints.Append(constraint) == KErrNone,SimPanic(EGeneral));
		}
	}

void CSimSmsMessaging::FindAndCreateSmsStoresL(CSimPhone* aPhone)
/**
 *	Creates sms stores as defined in the comfiguation files
 *	Extract values from the tags
 *	SmsStore, SmsStoreEntry, SmsStoreIndividualReqPause, SmsStoreBatchReqPause
 */
	{
	TInt count=CfgFileSection()->ItemCount(KSmsStore);
	const CTestConfigItem* item=NULL;
	TInt ret=KErrNone;

	for(TInt i=0;i<count;i++)
		{
		item=CfgFileSection()->Item(KSmsStore,i);
		if(!item)
			break;

		TPtrC8 storeName;
		TInt maxNumSlots;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,storeName);
		if(ret!=KErrNone)
			{
			LOGPARSERR("storeName",ret,0,&KSmsStore);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,maxNumSlots);
		if(ret!=KErrNone)
			{
			LOGPARSERR("maxNumSlots",ret,1,&KSmsStore);
			continue;
			}

		CSimSmsStore* smsStore=CSimSmsStore::NewL(this,storeName,maxNumSlots,aPhone);
		TCleanupItem newObjClose(CloseSmsObj,smsStore);
		CleanupStack::PushL(newObjClose);
		iSmsStores->AppendL(smsStore);
		CleanupStack::Pop();
		}

	for(TInt j=0;j<iSmsStores->Count();j++)
		{
		iSmsStores->At(j)->PopulateStoreFromConfigFile();
		}
	}

void CSimSmsMessaging::FindAndCreateSmsParamsL()
/**
 *Populates the sms parameter List as defined in the configuration file
 *Extract values from the tags
 *SmsParamEntry, SmsParamEntry, SmsParamBatchReqPause, SmsParamMaxNumSlots
 */
	{
	iSmspEntries= CMobilePhoneSmspList::NewL();

	const TInt maxSlots = CfgFileSection()->ItemValue(KSmspMaxNumSlots ,KDefaultSmspMaxNumSlots);
	iSmspEntries->SetMaxNumberEntries(maxSlots);

	iSmspBatchPause = CfgFileSection()->ItemValue(KSmspBatchReqPause,KDefaultSmspBatchReqPause);

	const TInt numberOfSmspEntries = Min(CfgFileSection()->ItemCount(KSmsParamEntry), maxSlots);
	const CTestConfigItem* item=NULL;
	TInt ret=KErrNone;
	
	for(TInt i=0;i < numberOfSmspEntries;i++)
		{
		item=CfgFileSection()->Item(KSmsParamEntry,i);

		if(!item)
			break;

		RMobileSmsMessaging::TMobileSmspEntryV1 entry = RMobileSmsMessaging::TMobileSmspEntryV1();

		TInt index, pid, dcs, validityPeriod;
		TPtrC8 destAddress, sca, smspName;

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,index);
		if((ret==KErrNone)&&(index < maxSlots))
			entry.iIndex=index;
		else
			{
			LOGPARSERR("index",ret,0,&KSmsParamEntry);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,smspName);
		if(ret==KErrNone)
			entry.iText.Copy(smspName);
		else
			{
			LOGPARSERR("smspName",ret,1,&KSmsParamEntry);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,pid);
		if(ret==KErrNone)
			{
			entry.iProtocolId=TUint8(pid);
			entry.iValidParams |= RMobileSmsMessaging::KProtocolIdIncluded;
			}
		else
			{
			LOGPARSERR("pid",ret,2,&KSmsParamEntry);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,dcs);
		if(ret==KErrNone)
			{
			entry.iDcs=TUint8(dcs);
			entry.iValidParams |= RMobileSmsMessaging::KDcsIncluded;
			}
		else
			{
			LOGPARSERR("dcs",ret,3,&KSmsParamEntry);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,4,validityPeriod);
		if(ret==KErrNone)
			{
			entry.iValidityPeriod=TUint8(validityPeriod);
			entry.iValidParams |= RMobileSmsMessaging::KValidityPeriodIncluded;
			}
		else
			{
			LOGPARSERR("validityPeriod",ret,4,&KSmsParamEntry);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,5,destAddress);
		if(ret==KErrNone)
			{
			RecordDestination(destAddress, entry);
			}
		else
			{
			LOGPARSERR("destAddress",ret,5,&KSmsParamEntry);
			continue;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,6,sca);
		if(ret==KErrNone)
			{
			RecordSca(sca, entry);
			}
		else
			{
			LOGPARSERR("sca",ret,6,&KSmsParamEntry);
			continue;
			}

		iSmspEntries->AddEntryL(entry);
		}
	}

void CSimSmsMessaging::RecordSca(const TDesC8& aAsciiAddr, RMobileSmsMessaging::TMobileSmspEntryV1& aEntry)
/**
 * Used to set the sca number in the smsp
 *
 * @param aAsciiSca Ascii representation of a telephone number such as the one found in the configuration file
 * @param aEntry reference to the actual smspentry in which the sca is going to be recorded
 */
	{
	if(aAsciiAddr.Length()>0)//only support for international numbers
		{
		aEntry.iServiceCentre.iNumberPlan=RMobilePhone::EIsdnNumberPlan;
		aEntry.iServiceCentre.iTypeOfNumber=RMobilePhone::EInternationalNumber;
		aEntry.iServiceCentre.iTelNumber.Copy(aAsciiAddr);
		aEntry.iValidParams |= RMobileSmsMessaging::KSCAIncluded;
		}
	}

void CSimSmsMessaging::RecordDestination(const TDesC8& aAsciiAddr, RMobileSmsMessaging::TMobileSmspEntryV1& aEntry)
/**
 * Used to set the destination number in the smsp
 *
 * @param aAsciiAddr Ascii representation of a telephone number such as the one found in the configuration file
 * @param aEntry reference to the actual smspentry in which the destination is going to be recorded
 */
	{
	if(aAsciiAddr.Length()>0)//only support for international numbers
		{
		aEntry.iDestination.iNumberPlan=RMobilePhone::EIsdnNumberPlan;
		aEntry.iDestination.iTypeOfNumber=RMobilePhone::EInternationalNumber;
		aEntry.iDestination.iTelNumber.Copy(aAsciiAddr);
		aEntry.iValidParams |= RMobileSmsMessaging::KDestinationIncluded;
		}	
	}

#ifdef _DEBUG	// to stop the UREL build warnings
void CSimSmsMessaging::LogRequest(const TBool aEntering, TInt aIpc, TInt aError)
#else
void CSimSmsMessaging::LogRequest(const TBool aEntering, TInt aIpc, TInt /*aError*/)
#endif
/**
 * This method logs client requests to the t_reg.txt
 * @param aDirection Tells if the request is coming into simtsy tsy or completing
 * @param aIpc IPC number of request
 * @param aError Error code that the request has
 */
 	{
	TBuf8<64> ipcBuf;

	switch (aIpc)
		{
		case EEtelServerLoadPhoneModule:
			ipcBuf = _L8("ServerLoadPhoneModule");
			break;

		case EEtelPhoneGetStatus:
			ipcBuf = _L8("PhoneGetStatus");
			break;

		case EEtelPhoneNotifyModemDetected:
			ipcBuf = _L8("PhoneNotifyModemDetected");
			break;
		case EEtelPhoneInitialise:
			ipcBuf = _L8("PhoneInitialise");
			break;
		case EMobileSmsMessagingGetCaps:
			ipcBuf = _L8("GetCaps");
			break;
		case EMobileSmsMessagingGetReceiveMode:
			ipcBuf = _L8("GetReceiveMode");
			break;
		case EMobileSmsMessagingGetMoSmsBearer:
			ipcBuf = _L8("GetMoSmsBearer");
			break;
		case EMobileSmsMessagingEnumerateMessageStores:
			ipcBuf = _L8("EnumerateMessageStores");
			break;
		case EMobileSmsMessagingGetMessageStoreInfo:
			ipcBuf = _L8("GetMessageStoreInfo");
			break;
		case EMobileSmsMessagingGetSmspListPhase2:
			ipcBuf = _L8("GetSmspListPhase2");
			break;
		case EMobileSmsMessagingSetReceiveMode:
			ipcBuf = _L8("SetReceiveMode");
			break;
		case EMobileSmsMessagingSetMoSmsBearer:
			ipcBuf = _L8("SetMoSmsBearer");
			break;
		case EMobileSmsMessagingAckSmsStored:
			ipcBuf = _L8("AckSmsStored");
			break;
		case EMobileSmsMessagingNackSmsStored:
			ipcBuf = _L8("NackSmsStored");
			break;
		case EMobileSmsMessagingResumeSmsReception:
			ipcBuf = _L8("ResumeSmsReception");
			break;
		case EMobileSmsMessagingSendMessage:
			ipcBuf = _L8("SendMessage");
			break;
		case EMobileSmsMessagingGetSmspListPhase1:
			ipcBuf = _L8("GetSmspListPhase1");
			break;
		case EMobileSmsMessagingStoreSmspList:
			ipcBuf = _L8("StoreSmspList");
			break;
		case EMobileSmsMessagingReceiveMessage:
			ipcBuf = _L8("ReceiveMessage");
			break;
		case EMobileSmsMessagingNotifyReceiveModeChange:
			ipcBuf = _L8("NotifyReceiveModeChange");
			break;
		case EMobileSmsMessagingNotifyMoSmsBearerChange:
			ipcBuf = _L8("NotifyMoSmsBearerChange");
			break;
		case EMobileSmsMessagingNotifySmspListChange:
			ipcBuf = _L8("NotifySmspListChange");
			break;
		case EMobileSmsMessagingSetReceiveModeCancel:
			ipcBuf = _L8("SetReceiveModeCancel");
			break;
		case EMobileSmsMessagingNotifyReceiveModeChangeCancel:
			ipcBuf = _L8("NotifyReceiveModeChangeCancel");
			break;
		case EMobileSmsMessagingSetMoSmsBearerCancel:
			ipcBuf = _L8("SetMoSmsBearerCancel");
			break;
		case EMobileSmsMessagingNotifyMoSmsBearerChangeCancel:
			ipcBuf = _L8("NotifyMoSmsBearerChangeCancel");
			break;
		case EMobileSmsMessagingAckSmsStoredCancel:
			ipcBuf = _L8("AckSmsStoredCancel");
			break;
		case EMobileSmsMessagingNackSmsStoredCancel:
			ipcBuf = _L8("NackSmsStoredCancel");
			break;
		case EMobileSmsMessagingResumeSmsReceptionCancel:
			ipcBuf = _L8("ResumeSmsReceptionCancel");
			break;
		case EMobileSmsMessagingSendMessageCancel:
			ipcBuf = _L8("SendMessageCancel");
			break;
		case EMobileSmsMessagingReceiveMessageCancel:
			ipcBuf = _L8("ReceiveMessageCancel");
			break;
		case EMobileSmsMessagingGetMessageStoreInfoCancel:
			ipcBuf = _L8("GetMessageStoreInfoCancel");
			break;
		case EMobileSmsMessagingGetSmspListCancel:
			ipcBuf = _L8("GetSmspListCancel");
			break;
		case EMobileSmsMessagingStoreSmspListCancel:
			ipcBuf = _L8("StoreSmspListCancel");
			break;
		case EMobileSmsMessagingNotifySmspListChangeCancel:
			ipcBuf = _L8("NotifySmspListChangeCancel");
			break;
		default:
			ipcBuf = _L8("OTHER");
			break;
		}

	if (aEntering!=EFalse)
		{
		LOGSMS3(">>%d,CSimSmsMessaging::%S",aIpc, &ipcBuf );
		}
	else
		{
		LOGSMS4("<<%d, CSimSmsMessaging::%S with error %d",aIpc, &ipcBuf, aError);
		}
	}


TInt CSimSmsMessaging::ExtFunc(const TTsyReqHandle aReqHandle,const TInt aIpc, const TDataPackage& aPckg)
/**
 * Sms Read/Send Dispatch Function.
 *
 * If this method returns with an KErr code apart from KErrNone then Etel will 
 * complete and destory the clients request for us. 
 *
 * @param aTsyReqHandle The handle of the request which started the IPC
 * @param aIpc The IPC being requested
 * @param aPackage Package of parameters associated with the IPC
 * @return Standard KErr... codes
 */	{
	TInt ret=KErrNone;//error is only used with LogRequest when at the end of ExtFunc
	LogRequest(ETrue, aIpc, ret);

	switch(aIpc)
		{
	case EMobileSmsMessagingReceiveMessage://4211
		{
		TRAPD(leaveCode, ret = ReceiveMessageL(aReqHandle,aPckg.Des1n(),aPckg.Des2n()));
		if (leaveCode != KErrNone)
			{
			ret = leaveCode;
			}
		}
		break;
		
	case EMobileSmsMessagingGetCaps:
		ret = GetCaps(aReqHandle,aPckg.Des1n());
		break;

	case EMobileSmsMessagingEnumerateMessageStores:
		ret = EnumerateMessagingStores(aReqHandle,aPckg.Des1n());
		break;

	case EMobileSmsMessagingGetMessageStoreInfo:
		ret = GetMessageStoreInfo(aReqHandle,aPckg.Des1n(),aPckg.Des2n());
		break;

	case EMobileSmsMessagingGetReceiveMode:
		ret = GetReceiveMode(aReqHandle,aPckg.Des1n());
		break;
		
	case EMobileSmsMessagingSetReceiveMode:
		ret = SetReceiveMode(aReqHandle,aPckg.Des1n());//4202
		break;

	case EMobileSmsMessagingAckSmsStored:
		ret = AckSmsStored(aReqHandle,aPckg.Des1n(),aPckg.Des2n());
		break;

	case EMobileSmsMessagingNackSmsStored:
		ret = NackSmsStored(aReqHandle,aPckg.Des1n(),aPckg.Des2n());
		break;

	case EMobileSmsMessagingResumeSmsReception:
		ret = ResumeSmsReception(aReqHandle);
		break;

	case EMobileSmsMessagingGetSmspListPhase1:
		ret = GetSmspListPhase1(aReqHandle,aPckg.Des1n(), aPckg.Des2n());
		break;

	case EMobileSmsMessagingGetSmspListPhase2:
		ret = GetSmspListPhase2(aReqHandle,aPckg.Des1n(), aPckg.Des2n());
		break;

	case EMobileSmsMessagingStoreSmspList:
		ret = StoreSmspList(aReqHandle,aPckg.Des1n());
		break;

	case EMobileSmsMessagingSendMessage://4207
		{
		TRAPD(leaveCode, ret = SendMessageL(aReqHandle,aPckg.Des1n(),aPckg.Des2n()));
		if (leaveCode != KErrNone)
			{
			ret = leaveCode;
			}
		}
		break;
	
	//This is used to re-read the configuration without having to restart the TSY
	//For testing purposes
	case EMobileSmsMessagingGetMoSmsBearer:
		//  FALLTHRU

	default:
		ret=KErrNotSupported;
		break;
		}
	LogRequest(EFalse, aIpc, ret);
	return ret;
	}

TBool CSimSmsMessaging::ConstraintEllapsed() const
/**
 * Check if the current contraint has ellapsed - i.e. check that that the number of received SMS
 * messages has reached the expected number for the current constraint.
 * @return ETrue if a constraint has ellapsed
 */
	{
	TBool ellapsed = EFalse;
	if( iConstraints.Count()>0 )
		{
		//check if the number of rx mess has been reached
		ellapsed=(iConstraintRxCnt==iConstraints[iCurrentConstraint].iRxCnt);
		}
	return ellapsed;
	}

TBool CSimSmsMessaging::IpcMatch()
/**
 * Check if the number of Sms sent matches a constraint i.e. the number of messages sent reaches the number
 * of sms to be sent to allow incoming messages to start being simulated.
 * @return ETrue if a match is found
 */
	{
	TInt i;
	TBool constraintEllapsed=ConstraintEllapsed();
	
	// NOTE - call ConstraintEllapsed() before doing loop below as iCurrentConstraint
	// is updated in the loop and so can result in ConstraintEllapsed() giving a 
	// different result
	TInt count = iConstraints.Count(); 
	for(i=0;i<count;++i)
		{
		if(iSmsTxCnt==(iConstraints[i].iIpcCnt))
			{
			iCurrentConstraint=i;
			LOGSMS2("New Constraint : %d", iCurrentConstraint);
			if(i!=0)
				{
				if( !constraintEllapsed )
					{
					LOGSMS1("Panic The constraints are overlapping...Compare test code and config file");
					}
				__ASSERT_ALWAYS(constraintEllapsed!=EFalse,SimPanic(EConstraintsOverlapping));
				}
			return ETrue;
			}
		}
	return EFalse;
	}

CTelObject* CSimSmsMessaging::OpenNewObjectByNameL(const TDesC& aName)
/**
 *
 */
	{
	LOGSMS1(">>CSimSmsMessaging::OpenNewObjectByNameL");
	TBuf8<KMaxName> name;
	name.Copy(aName);		// Do simple 16 bit to 8 bit conversion
	for(TInt i=0;i<iSmsStores->Count();i++)
		{
		if(name.MatchF(iSmsStores->At(i)->Name())==0)
			{
			// Base class open
			(void)iSmsStores->At(i)->Open();
			return iSmsStores->At(i);
			}
		}
	User::Leave(KErrNotFound);
	return NULL;
	}

CTelObject* CSimSmsMessaging::OpenNewObjectL(TDes&)
/**
 *
 */
	{
	User::Leave(KErrNotSupported);
	return NULL;
	}

CTelObject::TReqMode CSimSmsMessaging::ReqModeL(const TInt aIpc)
/**
 *	This function returns the Request Mode for the request with the passed IPC value.
 *	The ETel Server provides a function for returning the standard request modes for
 *	the Core API requests.
 */
	{
	CTelObject::TReqMode ret=0;	

	switch(aIpc)
		{
	case EMobileSmsMessagingReceiveMessage:
		ret=KReqModeRePostImmediately;
		break;

	case EMobileSmsMessagingGetCaps:
	case EMobileSmsMessagingSetReceiveMode:
	case EMobileSmsMessagingGetReceiveMode:
	case EMobileSmsMessagingAckSmsStored:
	case EMobileSmsMessagingNackSmsStored:
	case EMobileSmsMessagingResumeSmsReception:
	case EMobileSmsMessagingEnumerateMessageStores:
	case EMobileSmsMessagingGetMessageStoreInfo:
	case EMobileSmsMessagingSendMessage:
	case EMobileSmsMessagingGetSmspListPhase1:
	case EMobileSmsMessagingGetSmspListPhase2:
	case EMobileSmsMessagingStoreSmspList:
		ret=0;
		break;
	case EMobileSmsMessagingGetMoSmsBearer:
		// FALLTHRU
	default:
		User::Leave(KErrNotSupported);
		break;
		}

	return ret;
	}

TInt CSimSmsMessaging::RegisterNotification(const TInt /*aIpc*/)
/**
	The ETel Server calls this function when the first client makes a notification
	request.  If supported by the underlying protocol controlling the
	signalling stack, this can be used to start requesting updates for the relevant
	service.
*/
	{
	return KErrNone;
	}

TInt CSimSmsMessaging::DeregisterNotification(const TInt /*aIpc*/)
/**
	The ETel Server calls this function when the last client that had previously
	made a notification request closes its ETel Server handle.  If supported by
	the underlying protocol controlling the	signalling stack, this can be used
	to stop requesting updates for the relevant service.
*/
	{
	return KErrNone;
	}

TInt CSimSmsMessaging::NumberOfSlotsL(const TInt /*aIpc*/)
/**
 * Return the number of slots that the ETel Server should allocate for buffering requests
 * of the given IPC number.
 */
	{
	return KDefaultNumberOfSlots;
	}

TInt CSimSmsMessaging::CancelService(const TInt aIpc,const TTsyReqHandle /*aTsyReqHandle*/)
/**
 * Cancel an outstanding request.
 */
	{
	switch(aIpc)
		{
	case EMobileSmsMessagingReceiveMessage:
		ReceiveMessageCancel();
		break;
	case EMobileSmsMessagingSendMessage:
		SendMessageCancel();
		break;
	case EMobileSmsMessagingGetSmspListPhase1:
		StoreSmspListCancel();
		break;
	case EMobileSmsMessagingStoreSmspList:
		GetSmspListCancel();
		break;
	case EMobileSmsMessagingAckSmsStored:
	case EMobileSmsMessagingNackSmsStored:
		AckNackCancel();
		break;
	case EMobileSmsMessagingResumeSmsReception:
		ResumeSmsReceptionCancel();
		break;
// These are actually implemented in a synchronous manner, so there's no cancel to perform.
	case EMobileSmsMessagingSetReceiveMode:
	case EMobileSmsMessagingGetReceiveMode:	
		break;
	default:
		break;
		}
	return KErrNone;
	}

void CSimSmsMessaging::Init()
/**
	This function can be used to perform any necessary synchronous initialisation.
*/
	{
	}

TBool CSimSmsMessaging::CanStartRxEvent() const
/** Check to see if the Rx event can be started. Conditions are that there are no constraints
 * and Rx PDUs have been defined, OR SMS messages have been sent and current constraint has 
 * not ellapsed
 * @return ETrue if the Rx event can be started
 */ 
	{
	TBool canStart = EFalse;
	if( (iConstraints.Count()==0 && iSmsRxParameterListGsm->Count()>0) ||
		(iConstraints.Count()>0 && (iSmsTxCnt == iConstraints[iCurrentConstraint].iIpcCnt) && !ConstraintEllapsed()) )
		{
		// No Constraints listed OR current constraint has not ellapsed
		canStart = ETrue;
		}
	return canStart;	
	}

TInt CSimSmsMessaging::ActionRxEventUnstoredClientAck(TSmsRxEvent aRxEvent)
/**
 *	This function, triggered by sms receive events, manages the stated machine of 
 *  receiving Unstored clientacked sms messages
 *  
 */
	{
	LOGSMS3(">>CSimSmsMessaging::ActionRxEventUnstoredClientAck [iRxState=%d aRxEvent=%d]", iRxState, aRxEvent);
	switch(iRxState)
		{
	case ESmsRxStateIdle:
		{
		if(aRxEvent==ESmsEventPostedRxReq)
			{
			iRxState=ESmsRxStateWaitingForSmsRx;
			if( CanStartRxEvent() )
				{
				// Start the Rx timer to simulate received SMS from network
				StartSmsMtTimer();	
				}
			return KErrNone;
			}
		return KErrGeneral;
		}
	case ESmsRxStateWaitingForSmsRx:
		{
		if(aRxEvent==ESmsEventRxTimer )
			{
			iRxState=ESmsRxStateWaitingForAckNack;
			TInt ret = AttemptSmsRxComplete();	//If successful Etel will repost the request and the state machine may be re-entered
			return ret;
			}
		return KErrGeneral;
		} 
	case ESmsRxStateWaitingForAckNack:
		{
		__ASSERT_ALWAYS(aRxEvent!=ESmsEventRxTimer,SimPanic(EIllegalSmsRxEvent, __LINE__));
		if(aRxEvent==ESmsEventRxAckNack)
			{
			iRxState=ESmsRxStateWaitingForNetworkAckNackResponse;
			if (!iRxTimer->IsActive() && !iRxTimer->Running())
				{
				LOGSMS1(">>CSimSmsMessaging::ActionRxEventUnstoredClientAck Starting Rx Timer");
				iRxTimer->Start(iAckNackCompletePause,this, ETimerIdSmsMessRx);
				}

			return KErrNone;
			}
		else if(aRxEvent==ESmsEventResume)
			{
			return KErrGeneral;
			}
		} break;
	case ESmsRxStateWaitingForNetworkAckNackResponse:
		if(aRxEvent==ESmsEventRxTimer)
			{
			if(iSmsStoreFull)
				iRxState=ESmsRxStateSuspend;
			else if(iSmsRxReqOutstanding)
				{
				iRxState=ESmsRxStateWaitingForSmsRx;
				StartSmsMtTimer();
				}
			else
				{
				iRxState=ESmsRxStateIdle;
				StartSmsMtTimer();
				}
			CompletePendingReq();
			return KErrNone;
			}
		if(aRxEvent==ESmsEventPostedRxReq)
			return KErrNone;
		return KErrGeneral;
	case ESmsRxStateSuspend:
		{
		__ASSERT_ALWAYS(aRxEvent!=ESmsEventRxTimer,SimPanic(EIllegalSmsRxEvent, __LINE__));
		if(aRxEvent==ESmsEventResume)
			{
			iRxState=ESmsRxStateWaitingForNetworkResumeResponse;
			iRxTimer->Start(iResumeCompletePause,this, ETimerIdSmsMessResumeReception);
			return KErrNone;
			}
		return KErrGeneral;
		}
	case ESmsRxStateWaitingForNetworkResumeResponse:
		{
		if(aRxEvent==ESmsEventPostedRxReq)
			return KErrNone;
		return KErrGeneral;
		}
	default:
		return KErrGeneral;
		}
	return KErrNone;
	}

TInt CSimSmsMessaging::ActionRxEventUnstoredPhoneAck(TSmsRxEvent aRxEvent)
/**
 *	This function, triggered by sms receive events, manages the stated machine of 
 *  receiving Unstored Phone acked sms messages
 *  
 */
	{
	LOGSMS3(">> ActionRxEventUnstoredPhoneAck Enter function. Event=%d, State=%d",aRxEvent,iRxState);
	
	TInt ret = KErrGeneral;
	
	switch(iRxState)
		{
	case ESmsRxStateIdle:
		{
		if(aRxEvent==ESmsEventPostedRxReq)
			{
			iRxState=ESmsRxStateWaitingForSmsRx;
			if( CanStartRxEvent() )
				{
				// Start the Rx timer to simulate received SMS from network
				StartSmsMtTimer();	
				}
			ret = KErrNone;
			}
		} break;
	case ESmsRxStateWaitingForSmsRx:
		{
		if(aRxEvent==ESmsEventRxTimer )
			{
			iRxState=ESmsRxStateIdle;
			ret = AttemptSmsRxComplete();	//If successful Etel will repost the request and the state machine may be re-entered
			}
		} break; 
	default: 
		// Do nothing - return default value of KErrGeneral
		break;
		}
	return ret;
	}

TInt CSimSmsMessaging::ActionRxEventStored(TSmsRxEvent aRxEvent)
/**
 *	This function, triggered by sms receive events, manages the stated machine of 
 *  receiving stored Phone acked  sms messages
 *  
 */
	{
	LOGSMS3(">> ActionRxEventStored Enter function. Event=%d, State=%d",aRxEvent,iRxState);
	TInt ret = KErrGeneral;
	
	switch(iRxState)
		{
	case ESmsRxStateIdle:
		{
		if(aRxEvent==ESmsEventPostedRxReq)
			{
			iRxState=ESmsRxStateWaitingForSmsRx;
			if( CanStartRxEvent() )
				{
				// Start the Rx timer to simulate received SMS from network
				StartSmsMtTimer();	
				}
			ret = KErrNone;
			}
		} break;
	case ESmsRxStateWaitingForSmsRx:
		{
		if(aRxEvent==ESmsEventRxTimer )
			{
			iRxState=ESmsRxStateIdle;
			ret = AttemptSmsRxComplete();	//If successful Etel will repost the request and the state machine may be re-entered
			if( ret != KErrNone )
				{
				//the message wasn't stored ->ignore it and re-run the network event
				iRxState=ESmsRxStateWaitingForSmsRx;
				StartSmsMtTimer();
				}
			ret = KErrNone;	
			}
		} break; 
	default: 
		// Do nothing - return default value of KErrGeneral
		break;
		}
	return ret;
	}

TInt CSimSmsMessaging::ReceiveMessageL(const TTsyReqHandle aReqHandle, TDes8* aSmsPdu, TDes8* aParam2)
/**
 * Process a Receive Message request.  This boils down to recording the parameters for later completion.
 * The mode of operation where first an SMS receive request is made and then later an SMS
 * receive event is simulated is supported.  If an SMS receive event is simulated and there is
 * no receive request outstanding, the simulated incoming SMS will be discarded.  This assumption
 * may need to be revisited later.
 */
	{
	if (iSmsRxReqOutstanding!=EFalse)//Check if another client posts the request
		{
		ReqCompleted(aReqHandle, KErrInUse);
		return KErrNone;
		}
	iSmsRxReqHandle=aReqHandle;
	iSmsRxPdu=aSmsPdu;
	RMobileSmsMessaging::TMobileSmsReceiveAttributesV1Pckg* aAttribPckg=(RMobileSmsMessaging::TMobileSmsReceiveAttributesV1Pckg*)aParam2;
	RMobileSmsMessaging::TMobileSmsReceiveAttributesV1& attrib=(*aAttribPckg)();

	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(attrib);
	if(err != KErrNone)
		{
		iPhone->ReqCompleted(aReqHandle, err);
		return KErrNone;
		}

	iSmsRxAttrib=&attrib;
	iSmsRxReqOutstanding=ETrue;
	LOGSMS3(">>ReceiveMessageL. aSmsPdu&=%x, aParam2&=%x",aSmsPdu,iSmsRxAttrib);
	
	//  Print received PDU to simTSY log.
	__ASSERT_ALWAYS(iSmsReceiveMode!=RMobileSmsMessaging::EReceiveModeUnspecified,SimPanic(EMobileSmsMessagingPhoneNotSetToAReceiveMode));
	TInt ret=0;
	switch (iSmsReceiveMode)//swich which state machine to enter
		{
	case RMobileSmsMessaging::EReceiveUnstoredClientAck:
		ret=ActionRxEventUnstoredClientAck(ESmsEventPostedRxReq);
		break;
	case RMobileSmsMessaging::EReceiveUnstoredPhoneAck:
		ret=ActionRxEventUnstoredPhoneAck(ESmsEventPostedRxReq);
		break;
	case RMobileSmsMessaging::EReceiveStored:
		ret=ActionRxEventStored(ESmsEventPostedRxReq);
		break;
	default:
		ret=KErrNotSupported;
		}//end switch

	if(ret==KErrNone)
		{
		
		}
	else
		ReqCompleted(aReqHandle,ret);
	return KErrNone;
	}

void CSimSmsMessaging::ReceiveMessageCancel()
/*
 * Cancel an outstanding Receive Message request.
 */
	{
	if(iSmsRxReqOutstanding)
		{
		iRxTimer->Cancel();
		iSmsRxReqOutstanding=EFalse;
		iRxState=ESmsRxStateIdle;
		ReqCompleted(iSmsRxReqHandle,KErrCancel);
		}
	}

TInt CSimSmsMessaging::AckSmsStored(const TTsyReqHandle aReqHandle,TDes8* aMsg,TDes8* aFullFlagPckg)
/**
 *	In response to an incoming sms message the sms stack Acks/Nacks the message
 *  This function implements the Ack action.
 *  The flag aFullFlagPckg if set informs the SC that the client has no space to store this message
 *  and hence that it should retry once instructed by the ME
 */
	{
	TPckg<TBool>* fullFlagPckg=(TPckg<TBool>*)aFullFlagPckg;
	TBool& fullFlag=(*fullFlagPckg)();

	//  SMS-DELIVER-REPORT TPDU check 
	_LIT8(emptyDesc,"");
	if(aMsg->Compare(emptyDesc) != KErrNone)
		{
		RMobileSmsMessaging::TMobileSmsGsmTpdu reportPdu;
		reportPdu.Zero();
		if (CSimTsyMode::GetMode() != CSimTsyMode::ECdmaV1)
  			{
 			reportPdu = iSmsRxParameterListGsm->At(iSmsRxCnt-1).iDeliveryReport;
  			}

					
		if (reportPdu.Length() > 0)	// check if SMS-DELIVER-REPORT TPDU in config file is present
			{
			if(aMsg->Match(reportPdu)!=0)//check if the transmitted pdu and the one in config file are not identical
				{
				ReqCompleted(aReqHandle,KErrCorrupt);
				return KErrNone;
				}
			}
		}

	iSmsStoreFull=fullFlag;		// Record the "Store Full" status for future state transitions.
	TInt ret=ActionRxEventUnstoredClientAck(ESmsEventRxAckNack);

	// Handle any state transition errors now.  Simulated Ack/Nack failures are not supported yet...
	if(ret!=KErrNone)
		{
		ReqCompleted(aReqHandle,ret);
		return KErrNone;
		}
	iPendingReqHandle=aReqHandle;
	return KErrNone;
	}

TInt CSimSmsMessaging::NackSmsStored(const TTsyReqHandle aReqHandle,TDes8* aMsg,TDes8* aRpCausePckg)
/**
 *	In response to an incoming sms message the sms stack Acks/Nacks the message
 *  This function implements the NAck action.
 *  aRpCausePckg must be filled in with the reason
 */
	{
	TPckg<TInt>* rpCausePckg=(TPckg<TInt>*)aRpCausePckg;
	TInt& rpCause=(*rpCausePckg)();

	//  SMS-DELIVER-REPORT TPDU check 
	_LIT8(emptyDesc,"");
	if(aMsg->Compare(emptyDesc) != KErrNone)
		{
		RMobileSmsMessaging::TMobileSmsGsmTpdu reportPdu;
		reportPdu.Zero();
		if (CSimTsyMode::GetMode() != CSimTsyMode::ECdmaV1)
  			{
  			reportPdu = iSmsRxParameterListGsm->At(iSmsRxCnt-1).iDeliveryReport;
  			}

			
		if (reportPdu.Length() > 0)	// check if SMS-DELIVER-REPORT TPDU in config file is present
			{
			if(aMsg->Match(reportPdu)!=0)//check if the transmitted pdu and the one in config file are not identical
				{
				ReqCompleted(aReqHandle,KErrCorrupt);
				return KErrNone;
				}
			}
		}

	if(rpCause==KErrGsmSMSMemoryCapacityExceeded)
		iSmsStoreFull=ETrue;
	else
		iSmsStoreFull=EFalse;

	TInt ret=ActionRxEventUnstoredClientAck(ESmsEventRxAckNack);

	// Handle any state transition errors now.  Simulated Ack/Nack failures are not supported yet...
	if(ret!=KErrNone)
		{
		ReqCompleted(aReqHandle,ret);
		return KErrNone;
		}

	iPendingReqHandle=aReqHandle;
	return KErrNone;
	}


void CSimSmsMessaging::AckNackCancel()
/*
 * Cancel an outstanding Receive Message request.
 */
	{
	//This method does nothing,, a complex implementation would have to be used to simulate a real tsy
	}


TInt CSimSmsMessaging::ResumeSmsReception(const TTsyReqHandle aReqHandle)
/**
 *  After the sms reception has been suspended(store full), if the client frees some space
 *  the ME will inform the SC that reception can resume
 *
 */
	{
	TInt ret=ActionRxEventUnstoredClientAck(ESmsEventResume);
// In case of state transition error, return the error code.
// Resume failures cannot be simulated by the tsy yet...
	if(ret!=KErrNone)
		{
		ReqCompleted(aReqHandle,ret);
		return KErrNone;
		}
	iPendingReqHandle=aReqHandle;
	return KErrNone;
	}

void CSimSmsMessaging::ResumeSmsReceptionCancel()
	{
	//Does nothing, a complex implementation would have to be used to simulate a real tsy
	}

//**********************************************
//send
//*********************************************


TInt CSimSmsMessaging::ActionTxEvent(TSmsTxEvent aTxEvent)
/**
 *  This function actions the sms message sending state machine. It is triggered by sms sending events
 *
 */
	{
	LOGSMS1(">>ActionTxEvent ");
	switch(iTxState)
	{
	case ESmsTxStateIdle:
		__ASSERT_ALWAYS(aTxEvent!=ESmsEventSubmitReportReceived,SimPanic(EIllegalSmsTxEvent));
		if(aTxEvent==ESmsEventSendReq)
			{
			iTxState=ESmsTxStateWaitingForSubmitReport;
			iTxTimer->Start(iSmsTxPause,this, ETimerIdSmsMessTx);
			}
		break;
	case ESmsTxStateWaitingForSubmitReport:
		__ASSERT_ALWAYS(aTxEvent!=ESmsEventSendReq,SimPanic(EIllegalSmsTxEvent));	
		if(aTxEvent==ESmsEventSubmitReportReceived)
			{
			iTxState=ESmsTxStateIdle;

			PopulateSmsTxAttrib(iSmsTxAttrib);				
			CompleteTxPendingReq(KErrNone);			
			}
		break;
	}
	return KErrNone;
	}

TInt CSimSmsMessaging::SendMessageL(const TTsyReqHandle aReqHandle,TDes8* aSmsPdu,TDes8* aParam2)
/**
 *	This function simulates the transmission of an sms from the ME to the SC.
 *  It returns directly if 
 *  -The Sms message description(SmsTx)tag in the config file specifies that this sms message should return with this error 
 *  -The Pdu is corrupted
 *  Otherwise it start the sms message sending state machine
 * 
 */

	{
    iSmsTxReqHandle=aReqHandle;
    RMobileSmsMessaging::TMobileSmsSendAttributesV1Pckg* aAttribPckg=(RMobileSmsMessaging::TMobileSmsSendAttributesV1Pckg*)aParam2;
	RMobileSmsMessaging::TMobileSmsSendAttributesV1& attrib=(*aAttribPckg)();
		
	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(attrib);
	if(err != KErrNone)
		{
		iPhone->ReqCompleted(aReqHandle, err);
		return KErrNone;
		}
		
	iSmsTxAttrib=&attrib;
#ifdef _DEBUG
		LogTMobileSmsAttributesV1(*iSmsTxAttrib);
#endif // _DEBUG
		

	//check if messages defined in cfg file
	TInt count = 0;	
	count = iSmsTxParametersListGsm->Count();  
	
	if (count<=iSmsTxCnt)
		return KErrTotalLossOfPrecision;

	//check if expected error
	//TInt err = KErrNone;
	err = KErrNone;
	err = iSmsTxParametersListGsm->At(iSmsTxCnt).iExpectedError;		
	if (err!=KErrNone)
		{
		PopulateSmsTxAttrib(iSmsTxAttrib);			
		CompleteTxPendingReq(err);
		return KErrNone;
		}

		//check if a non null pdu is defined in the config file
	RMobileSmsMessaging::TMobileSmsGsmTpdu octetPdu;
	octetPdu = iSmsTxParametersListGsm->At(iSmsTxCnt).iPdu;

	RMobileSmsMessaging::TMobileSmsGsmTpdu pduWith0;
	TUint8 zero=0;
	pduWith0.Append(&zero, 1);
	if(octetPdu!=pduWith0)//if the pdu in config file is 00, skip the pdu check
		{
			if(aSmsPdu->Match(octetPdu)!=0)//check if the transmitted pdu and the one in config file are identical
				{
				CompleteTxPendingReq(KErrCorrupt);
				return KErrNone;
				}
		}	

	ActionTxEvent(ESmsEventSendReq);
	return KErrNone;
	}


void CSimSmsMessaging::SendMessageCancel()
/*
 * Cancel an outstanding send Message request.
 */
	{
	if(iTxState==ESmsTxStateWaitingForSubmitReport)
		{
		iTxTimer->Cancel();
		iTxState=ESmsTxStateIdle;
		CompleteTxPendingReq(KErrCancel);
		}
	}

void CSimSmsMessaging::CompletePendingReq()
	{
	ReqCompleted(iPendingReqHandle,KErrNone);
	}

TInt CSimSmsMessaging::AttemptSmsRxComplete()
/**
 * Complete an outstanding SMS message receive request if one is outstanding.  If there is
 * no request outstanding, the message will be discared.
 * update the constraint count
 */
	{
	LOGSMS1(">>AttemptSmsRxComplete ");

	if (CSimTsyMode::GetMode() != CSimTsyMode::ECdmaV1)
		{
		iConstraintRxCnt++;
		}

	TInt ret=KErrNone;
	if(iSmsRxReqOutstanding)
		{
		if (iSmsReceiveMode==RMobileSmsMessaging::EReceiveStored)
			{
			LOGSMS4(">>Populating SMS Structures. iSmsRxPdu&=%x, iSmsRxAttrib&=%x, iSmsRxCnt=%d.",iSmsRxPdu,iSmsRxAttrib,iSmsRxCnt);
			RMobileSmsStore::TMobileGsmSmsEntryV1 sms;

			*iSmsRxPdu=iSmsRxParameterListGsm->At(iSmsRxCnt).iPdu;
			
			sms.iMsgData=RMobileSmsMessaging::TMobileSmsGsmTpdu(*iSmsRxPdu);
			sms.iServiceCentre.iTelNumber.Copy(iSmsRxParameterListGsm->At(iSmsRxCnt).iSca);
		
			sms.iServiceCentre.iTypeOfNumber=RMobilePhone::EInternationalNumber;//SmsMessaging only deals with international numbers
			sms.iServiceCentre.iNumberPlan=RMobilePhone::EIsdnNumberPlan;
			sms.iMsgStatus=RMobileSmsStore::EStoredMessageUnread;
			ret = iSmsStores->At(0)->StoreIncomingMessage(&sms);//todo if several stores find the right one
			if (ret==KErrNone)
				{
				iSmsRxAttrib->iStore.Copy(iSmsStores->At(0)->Name());
				iSmsRxAttrib->iStoreIndex=sms.iIndex;
				}
			}
		else
			{			
			*iSmsRxPdu = iSmsRxParameterListGsm->At(iSmsRxCnt).iPdu;				
			}

		if (ret==KErrNone)
			{
			iSmsRxReqOutstanding=EFalse;			
			PopulateSmsRxAttrib(iSmsRxParameterListGsm->At(iSmsRxCnt).iSca,iSmsRxAttrib);	
							
			ReqCompleted(iSmsRxReqHandle,ret);
			iSmsRxCnt++;
			}
		}
	return ret;
	}

void CSimSmsMessaging::CompleteTxPendingReq(TInt aError)
/**
 * Complete a SmsTx request and increments the SmsTx counter
 *
 */
	{
	LOGSMS1(">>CompleteTxPendingReq ");
	iSmsTxCnt++;
	if(IpcMatch())
		{
		iConstraintRxCnt=0;
		if( iRxState == ESmsRxStateSuspend )
		    {
		    // A previous rx message was NACKed due memory full and 
		    // SIM TSY is waiting for resume event from client - as
		    // a new message needs to be received, change states
		    // to allow receipt of the message.
		    if( iSmsRxReqOutstanding )
		        {
		        iRxState = ESmsRxStateWaitingForSmsRx;
		        }
		    else
		        {
		        iRxState = ESmsRxStateIdle;
		        }
		    }
		if( iSmsRxReqOutstanding )
			{
			// Client has a pending receive request - safe to start Rx timer
			// to simulate received SMS from network.
			StartSmsMtTimer();
			}
		else
			{
			// No pending client receive request - need to wait for it before
			// simulating received SMS from network.
			LOGSMS1(" - no pending receive req from client - do not start Rx timer");
			}
		}
	ReqCompleted(iSmsTxReqHandle, aError);
	}

void CSimSmsMessaging::StartSmsMtTimer()
	{
	LOGSMS1(">>StartSmsMtTimer ");
	TInt count = 0;
	count = iSmsRxCnt<iSmsRxParameterListGsm->Count();
			
		if(count)		// Check that there are more messages defined in the config file.
			{
			if((iConstraints.Count()==0) ||	(iConstraintRxCnt<iConstraints[iCurrentConstraint].iRxCnt))	// If there are no constraints, or there are constraints and they're not exhausted.
				{
				LOGSMS1(">>StartSmsMtTimer Starting");
				iRxTimer->Start(iSmsRxPeriod,this, ETimerIdSmsMessRx);
				LOGSMS1(">>StartSmsMtTimer Started");
				}
			}
	}


void CSimSmsMessaging::PopulateSmsRxAttrib(const TDesC8& aAsciiScaAddr,RMobileSmsMessaging::TMobileSmsReceiveAttributesV1* aAttrib)
/**
 * Populate the SMS Rx Attributes from an ASCII respresentation, such as that stored in the configuration file.
 * This involves checking the address for a leading '+' character and setting the TON and NPI
 * accordingly.  The address can then be copied into the iTelNumber structure.
 */
	{
	LOGSMS1(">>PopulateSmsRxAttrib, ");
	aAttrib->iOriginator.iTelNumber.SetLength(0);
	
	switch (iSmsReceiveMode)
		{
	case RMobileSmsMessaging::EReceiveUnstoredClientAck:
		aAttrib->iStatus=RMobileSmsMessaging::EMtMessageUnstoredClientAck;
		aAttrib->iStore.SetLength(0);
		aAttrib->iStoreIndex=-1;
		break;
	case RMobileSmsMessaging::EReceiveUnstoredPhoneAck:
		aAttrib->iStatus=RMobileSmsMessaging::EMtMessageUnstoredPhoneAck;
		aAttrib->iStore.SetLength(0);
		aAttrib->iStoreIndex=-1;
		break;
	case RMobileSmsMessaging::EReceiveStored:
		aAttrib->iStatus=RMobileSmsMessaging::EMtMessageStored;
		break;
	
	default:
		break;
		}
	aAttrib->iFlags=RMobileSmsMessaging::KGsmServiceCentre | RMobileSmsMessaging::KSmsDataFormat | RMobileSmsMessaging::KIncomingStatus;
	aAttrib->iDataFormat=RMobileSmsMessaging::EFormatGsmTpdu;

	if(aAsciiScaAddr.Length()>0)
		{
		aAttrib->iGsmServiceCentre.iNumberPlan=RMobilePhone::EIsdnNumberPlan;
		aAttrib->iGsmServiceCentre.iTypeOfNumber=RMobilePhone::EInternationalNumber;
		aAttrib->iGsmServiceCentre.iTelNumber.Copy(aAsciiScaAddr);
		}
	}


void CSimSmsMessaging::PopulateSmsTxAttrib(RMobileSmsMessaging::TMobileSmsAttributesV1* aAttrib)
/**
 * Populate the SMS Tx Attributes for SMS from an ASCII respresentation, such as that stored in the configuration file.
 * - Message Identifier
 * - TL Ack
 */
	{
	if (iSmsModeCaps == RMobileSmsMessaging::KCapsGsmSms)
		{
		RMobileSmsMessaging::TMobileSmsSendAttributesV1* attrib = static_cast<RMobileSmsMessaging::TMobileSmsSendAttributesV1*>(aAttrib);
		attrib->iMsgRef = TUint16(iSmsTxParametersListGsm->At(iSmsTxCnt).iRef);	

		attrib->iFlags = RMobileSmsMessaging::KMessageReference;
		
		if (iSmsControlCaps & RMobileSmsMessaging::KCapsSendWithAck)
			{			
			attrib->iSubmitReport=iSmsTxParametersListGsm->At(iSmsTxCnt).iSubmitReport;
			attrib->iFlags |= RMobileSmsMessaging::KGsmSubmitReport;
			}
		}
	}

void CSimSmsMessaging::PopulateSmsTxAttrib(RMobileSmsMessaging::TMobileSmsSendAttributesV1* aAttrib)
/**
 * Populate the SMS Tx Attributes from an ASCII respresentation, such as that stored in the configuration file.
 * -Message Reference
 * -SUBMIT_REPORT_TPDU
 */
	{
	 aAttrib->iMsgRef = TUint16(iSmsTxParametersListGsm->At(iSmsTxCnt).iRef);
	 aAttrib->iFlags = RMobileSmsMessaging::KMessageReference;
	
	 if (iSmsControlCaps & RMobileSmsMessaging::KCapsSendWithAck)
		{
		aAttrib->iSubmitReport=iSmsTxParametersListGsm->At(iSmsTxCnt).iSubmitReport;
		aAttrib->iFlags |= RMobileSmsMessaging::KGsmSubmitReport;
		}
	}

TInt CSimSmsMessaging::GetCaps(const TTsyReqHandle aReqHandle,TDes8* aPckg)
/**
 * Process a request to retrieve the caps.  Currently, only the KCapsReceiveUnstoredClientAck
 * mode is supported.
 */
	{
	RMobileSmsMessaging::TMobileSmsCapsV1Pckg* capsPckg=(RMobileSmsMessaging::TMobileSmsCapsV1Pckg*)aPckg;
	RMobileSmsMessaging::TMobileSmsCapsV1& caps=(*capsPckg)();

	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(caps);
	if(err != KErrNone)
		{
		iPhone->ReqCompleted(aReqHandle, err);
		return KErrNone;
		}

	 	caps.iSmsMode = RMobileSmsMessaging::KCapsGsmSms;
		
	caps.iSmsControl=iSmsControlCaps;
	ReqCompleted(aReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimSmsMessaging::GetReceiveMode(const TTsyReqHandle aReqHandle,TDes8* aPckg)
/**
 * Process a request to retrieve the current SMS receive mode.  Only the
 * KCapsReceiveUnstoredClientAck mode is supported.
 */
	{
	TPckg<RMobileSmsMessaging::TMobileSmsReceiveMode>* modePckg=(TPckg<RMobileSmsMessaging::TMobileSmsReceiveMode>*)aPckg;
	RMobileSmsMessaging::TMobileSmsReceiveMode& mode=(*modePckg)();
	mode=iSmsReceiveMode;
	ReqCompleted(aReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimSmsMessaging::SetReceiveMode(const TTsyReqHandle aReqHandle,TDes8* aPckg)
/**
 * Process a request to set the current SMS receive mode.  Only the
 * KCapsReceiveUnstoredClientAck mode is supported.
 */
	{
	TPckg<RMobileSmsMessaging::TMobileSmsReceiveMode>* modePckg=(TPckg<RMobileSmsMessaging::TMobileSmsReceiveMode>*)aPckg;
	RMobileSmsMessaging:: TMobileSmsReceiveMode& mode=(*modePckg)();

	TInt result(KErrNone);

	switch (mode)
		{
		case RMobileSmsMessaging::EReceiveUnstoredClientAck:
			{
			if(iSmsControlCaps & RMobileSmsMessaging::KCapsReceiveUnstoredClientAck)
				{
				if ((iRxState==ESmsRxStateIdle) || (iRxState==ESmsRxStateWaitingForSmsRx))//can only change mode in these states
					{
					iSmsReceiveMode=RMobileSmsMessaging::EReceiveUnstoredClientAck;
					ReqCompleted(aReqHandle,KErrNone);
					}
				else 
					{
					if(iSmsReceiveMode==RMobileSmsMessaging::EReceiveUnstoredClientAck)//already in this state
						ReqCompleted(aReqHandle,KErrNone);
					else
						ReqCompleted(aReqHandle,KErrNotSupported);
					}
				}
			else ReqCompleted(aReqHandle,KErrNotSupported); 
			break;
			}

		case RMobileSmsMessaging::EReceiveUnstoredPhoneAck:
			{
			if(iSmsControlCaps & RMobileSmsMessaging:: KCapsReceiveUnstoredPhoneAck)
				{
				if ((iRxState==ESmsRxStateIdle) || (iRxState==ESmsRxStateWaitingForSmsRx))//can only change mode in these states
					{
					iSmsReceiveMode=RMobileSmsMessaging::EReceiveUnstoredPhoneAck;
					ReqCompleted(aReqHandle,KErrNone);
					}
				else
					{
					if (iSmsReceiveMode==RMobileSmsMessaging::EReceiveUnstoredPhoneAck)//already in this state
						ReqCompleted(aReqHandle,KErrNone);
					else
						ReqCompleted(aReqHandle,KErrNotSupported);
					}
				}
			else
				ReqCompleted(aReqHandle,KErrNotSupported); 	
			break;
			}

		case RMobileSmsMessaging::EReceiveStored:
			{
			if(iSmsControlCaps & RMobileSmsMessaging:: KCapsReceiveStored)
				{
				if ((iRxState==ESmsRxStateIdle) || (iRxState==ESmsRxStateWaitingForSmsRx))//can only change mode in these states
					{
					iSmsReceiveMode=RMobileSmsMessaging::EReceiveStored;
					ReqCompleted(aReqHandle,KErrNone);
					}
				else
					{
					if((iSmsReceiveMode==RMobileSmsMessaging::EReceiveStored))//already in this state
						ReqCompleted(aReqHandle,KErrNone);
					else
						ReqCompleted(aReqHandle,KErrNotSupported);
					}
				}
			else ReqCompleted(aReqHandle,KErrNotSupported); 
			break;
			}
		default:
			result = KErrNotSupported;
		}
	
	return result;
	}

TInt CSimSmsMessaging::EnumerateMessagingStores(TTsyReqHandle aReqHandle,TDes8* aPckg)
/**
 * Process a request to retrieve the number of message stores supported.
 * @param aReqHandle	The TSY request handle associated with this request.
 * @param aPckg			The parameter package containing the count variable to be populated and
 *						returned.
 * @return TInt			Standard error value.
 */
	{
	TPckg<TInt>* countPckg=(TPckg<TInt>*)aPckg;
	TInt& count=(*countPckg)();
	count=iSmsStores->Count();
	ReqCompleted(aReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimSmsMessaging::GetMessageStoreInfo(TTsyReqHandle aReqHandle,TDes8* aPckg1, TDes8* aPckg2)
/**
 * Retrieve information about an indexed SMS Message Store.
 * @param aReqHandle	The TSY request handle associated with this request.
 * @param aPckg1		The parameter package containing the index of the SMS Store for which
 *						information is going to be retrieved.
 * @param aPckg2		The parameter package in which the retrieved SMS Store information will
 *						be passed back to the client.
 * @return TInt			Standard error value.
 */
	{
	TPckg<TInt>* indexPckg=(TPckg<TInt>*)aPckg1;
	TInt& index=(*indexPckg)();
	TPckg<RMobilePhoneStore::TMobilePhoneStoreInfoV1>* infoPckg=(TPckg<RMobilePhoneStore::TMobilePhoneStoreInfoV1>*)aPckg2;
	RMobilePhoneStore::TMobilePhoneStoreInfoV1& info=(*infoPckg)();

	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(info);
	if(err != KErrNone)
		{
		iPhone->ReqCompleted(aReqHandle, err);
		return KErrNone;
		}

	if((index<0) || (index>=iSmsStores->Count()))
		{
		ReqCompleted(aReqHandle,KErrArgument);
		return KErrNone;
		}

	info.iType=RMobilePhoneStore::EShortMessageStore;
	info.iTotalEntries=iSmsStores->At(index)->MaxSlots();
	info.iUsedEntries=iSmsStores->At(index)->UsedEntries();
	info.iCaps= iSmsStores->At(index)->StoreCaps();
	info.iName.Copy(iSmsStores->At(index)->Name());
	ReqCompleted(aReqHandle,KErrNone);
	return KErrNone;
	}

TInt CSimSmsMessaging::GetSmspListPhase1(const TTsyReqHandle aTsyReqHandle,
                                            TDes8* aParam1,TDes8* aParam2)
/** Get SMSP List Phase 1 
 *
 * If the GetSmspListPhase1L should leave this method takes care of that and 
 * makes a premature ReqCompleted to the client.
 *
 * @param aTsyReqHandle the request ID 
 * @param aClient The client sends down a handle that is saved together with the 
 *				  list so the list can be returned to the right client in phase 2.
 * @param aBufSiz The size of the retrieved network list. The size is set in 
 * @return error code. 
 */
	{
	if(iSmspBusy==EFalse)
		{
		iSmspBusy=ETrue;
		UNPACK_PCKG(clientId,aParam1,RMobilePhone::TClientId);
		UNPACK_PCKG(bufSize,aParam2,TInt);
		TRAPD(leaveCode,GetSmspListPhase1L(aTsyReqHandle,clientId,bufSize));
		if (leaveCode)
			return leaveCode;
		return KErrNone;
		}
	else
		return KErrInUse;

	}

void CSimSmsMessaging::GetSmspListPhase1L(TTsyReqHandle aTsyReqHandle, 
											 RMobilePhone::TClientId& aClientId, 
											 TInt& aBufSize)
/** Get SMSP List Phase 1 
 *
 * @param aTsyReqHandle the request ID 
 * @param aClient The client sends down a handle that is saved together with the 
 *				  list so the list can be returned to the right client in phase 2.
 * @param aBufSiz The size of the smsp list. The size is set in 
 * @return error code. 
 */
	{
	// just check and remove if there are already existing entries from the 
	// same client
	TInt numberOfLists = iSmspReadAll->Count();
	// Find the get smsplists attempts from this client, starting from end.  
	for (TInt i = numberOfLists-1; i >= 0; --i)
		{
		CListReadAllAttempt* readOld=iSmspReadAll->At(i);
		if ((readOld->iClient.iSessionHandle==aClientId.iSessionHandle) &&
		    (readOld->iClient.iSubSessionHandle==aClientId.iSubSessionHandle))
			{
			iSmspReadAll->Delete(i);
			}
		}
    // once we have cleaned all then we can proceed...
	iSmspReqHandle=aTsyReqHandle;
	// Store the streamed list and the client ID
	
	CListReadAllAttempt* read=CListReadAllAttempt::NewL(aClientId, aTsyReqHandle);
	CleanupStack::PushL(read);
	
	read->iListBuf = iSmspEntries->StoreLC();
	CleanupStack::Pop(read->iListBuf); // pop the CBufFlat allocated by StoreLC

	iSmspReadAll->AppendL(read);
	CleanupStack::Pop(read); // pop the CListReadAllAttempt

// return the CBufFlat's size to client
	aBufSize=(read->iListBuf)->Size();

//	CleanupStack::PopAndDestroy(); // pop&destroy list

	iSmspTimer->Start(iSmspBatchPause,this, ETimerIdSmsMessSmsp);
	}

TInt CSimSmsMessaging::GetSmspListPhase2(const TTsyReqHandle aTsyReqHandle,
                                            TDes8* aParam1,TDes8* aParam2)
/** Get SMSP List phase 2 
 *
 * In this metod the list which was retrieved during phase 1 is copied to 
 * the memory which the client has allocated for this purose.
 * @param aTsyReqHandle		Const pointer to the request ID 
 * @param aClient			Handle to the client which list we are looking for.
 * @param aBuf				Pointer to the memory that the etelmm has allocated. 
 * @return error code. 
 */
	{	
	UNPACK_PCKG(clientId,aParam1,RMobilePhone::TClientId);
	TInt numberOfLists = iSmspReadAll->Count();
	// Find the get smsplists attempts from this client  
	for (TInt i = 0; i < numberOfLists; ++i)
		{
		CListReadAllAttempt* read=iSmspReadAll->At(i);
		if ((read->iClient.iSessionHandle==clientId.iSessionHandle) &&
		    (read->iClient.iSubSessionHandle==clientId.iSubSessionHandle))
			{
			TPtr8 bufPtr((read->iListBuf)->Ptr(0));
			aParam2->Copy(bufPtr);						// Copy the streamed list to the client
			delete read;
			iSmspReadAll->Delete(i);
			ReqCompleted(aTsyReqHandle,KErrNone);	// Completes the retrieval of a network list succesfully.
			return KErrNone;
			}
		}
	return(KErrNotFound);
	}

TInt CSimSmsMessaging::StoreSmspList(const TTsyReqHandle aTsyReqHandle, TDes8* aBuffer)
/**
 *	This function stores a new smsp list 
 *  warning the new smsp list will only exist at run time. If the tsy is reloaded the smsp list 
 *  will go back to the one defined in the configuration file
 *  @param aBuffer Descriptor containing the new smsp list  
 */
	{
	if (iSmspBusy==EFalse)
		{
		iSmspBusy=ETrue;
		TRAPD(leaveCode,iSmspEntries->RestoreL(*aBuffer));
		if (leaveCode)
			return leaveCode;
		iSmspReqHandle=aTsyReqHandle;
		iSmspTimer->Start(iSmspBatchPause,this, ETimerIdSmsMessSmsp);
		LOGSMS1("<<StoreSmsList,Exit function");
		return KErrNone;
		}
	else
		LOGSMS1("<<StoreSmsList,Exit function");
		return KErrInUse;
	
	}

void CSimSmsMessaging::StoreSmspListCancel()
/*
 * Cancel an outstanding store smspList request
 * as iSmspBusy mutexes get and store, only 1 request handle wil exist at a time 
 */
	{
	if(iSmspBusy != EFalse)
		{
		iSmspTimer->Cancel();
		iSmspBusy=EFalse;
		ReqCompleted(iSmspReqHandle,KErrNone);//The timer is cancelled but data has already been stored
		}
	}

void CSimSmsMessaging::GetSmspListCancel()
/*
 * Cancel an outstanding get smspList request.
 * as iSmspBusy mutexes get and store, only 1 request handle wil exist at a time 
 */
	{
	if(iSmspBusy != EFalse)
		{
		iSmspTimer->Cancel();
		iSmspBusy=EFalse;
		ReqCompleted(iSmspReqHandle,KErrCancel);
		}
	}

void CSimSmsMessaging::TimerCallBack(TInt aId)
/**
 * Process a timer call back event.  
 * @param aId Contains the Id of the timer that triggered the event
 * 
 */
	{
	LOGSMS3(">>CSimSmsMesaging::TimerCallBack IN [aId=%d iSmsReceiveMode=%d]", aId, iSmsReceiveMode);
	switch(aId)
		{
		case ETimerIdSmsMessTx:
			{
			TInt ret=ActionTxEvent(ESmsEventSubmitReportReceived);
			__ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalSmsTxEvent));	// There should be no error from this action, but to check...
			break;
			}
		case ETimerIdSmsMessSmsp:
			{
			iSmspBusy=EFalse;
			ReqCompleted(iSmspReqHandle, KErrNone);
			break;
			}
		case ETimerIdSmsMessRx:
			{
			TInt ret=0;
			
			switch (iSmsReceiveMode)//swich which state machine to enter
				{
			case RMobileSmsMessaging::EReceiveUnstoredClientAck:
				ret=ActionRxEventUnstoredClientAck(ESmsEventRxTimer);
				break;
			case RMobileSmsMessaging::EReceiveUnstoredPhoneAck:
				ret=ActionRxEventUnstoredPhoneAck(ESmsEventRxTimer);
				break;
			case RMobileSmsMessaging::EReceiveStored:
				LOGSMS1("Recieve Stored SMS Rx Event.");
				ret=ActionRxEventStored(ESmsEventRxTimer);
				break;
			default://other receive modes cannot be set
				break;
				}//end switch

			if (ret != KErrNone)
				{
				LOGSMS2("ERROR: Unexpected ret code %d", ret);
				__ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalSmsRxEvent, __LINE__));	// There should be no error from this action, but to check...
				}

			break;
			}

		case ETimerIdSmsMessResumeReception:
			{
			if (iSmsRxReqOutstanding)
				{
				iRxState = ESmsRxStateWaitingForSmsRx;
				}
			else
				{
				iRxState = ESmsRxStateIdle;
				}
			StartSmsMtTimer();
			CompletePendingReq();
			break;
			}

		default:
			break;
		}
	LOGSMS1(">>CSimSmsMesaging::TimerCallBack OUT");
	}

const CTestConfigSection* CSimSmsMessaging::CfgFileSection()
/**
* Returns a pointer to the config file section
*
* @return CTestConfigSection a pointer to the configuration file data section
*/
	{
	LOGSMS1(">>CSimSmsMessaging::CfgFileSection");
	return iPhone->CfgFile();
	}


void CSimSmsMessaging::ReloadConfigurationSettingsL()
/**
 *  This function reloads settings from the config file
 */
    {
    Reset();
    InitializeL();
    }

HBufC8* CSimSmsMessaging::PduToAscii(TDesC8& aSmsPdu)
/**
 * Converts the contents of a TDes8 to their Hex representation
 * @param aSmsPdu Reference to the descriptor to convert
 * @return A pointer to an HBufC8 containing the Hex representation of aSmsPdu. The caller is responsible for freeing the object.
 * @return Null if the HBufC8 was not successfuly created.
 */
	{
	HBufC8* hexBuf = HBufC8::New(aSmsPdu.Length()*2+1);
	if (hexBuf == NULL) return NULL;
	TPtr8 des = hexBuf->Des();
	des.FillZ();
	des.Zero();
	if (hexBuf != NULL)
		{
		for (TInt i = 0; i < aSmsPdu.Length(); i++)
			{
			TInt left = (aSmsPdu[i] & 0xF0) >> 4;
			TInt right = aSmsPdu[i] & 0x0F;
			if (left < 10)
				{
				des.Append(0x30 + left);
				}
			else
				{
				des.Append(0x41 + (left - 10));
				}
			if (right < 10)
				{
				des.Append(0x30 + right);
				}
			else
				{
				des.Append(0x41 + (right - 10));
				}
			}
		}
	des.Append(0);
	return hexBuf;
	}

#ifdef _DEBUG // to prevent UREL build warnings
void CSimSmsMessaging::DumpPdu(const TDesC8& aText, TDesC8& aSmsPdu, HBufC8* aPduInAscii)
#else
void CSimSmsMessaging::DumpPdu(const TDesC8& /*aText*/, TDesC8& aSmsPdu, HBufC8* aPduInAscii)
#endif
/**
Print PDU in a loop, 150 chars per line
@param aText - a header line about the PDU.
@param aSmsPdu - PDU to log.
@param aPduInAscii - aSmsPdu in ASCII format (default NULL).
*/
    {
	LOGSMS3("%S pdu length=%d", &aText, aSmsPdu.Length());

    if( !aSmsPdu.Length() )
        return;

	// In sendPdu case, caller needs to call PduToAscii for comparison.
	// Then aPduInAscii is non-zero.
	HBufC8* hexBuf = (aPduInAscii) ? aPduInAscii : PduToAscii(aSmsPdu);
	if (! hexBuf)
	    return;

	//Print the pdu in a loop because LOGTEXT can only print up to 150 characters
	for (TInt i = 0; i < hexBuf->Length(); i+=100)
	    {
		TInt len = Min(100, hexBuf->Mid(i).Length());
        TPtrC8 pduChunk(hexBuf->Mid(i).Left(len).Ptr(), len);
		LOGSMS2("PDU Chunk: %S:", &pduChunk);
		}

	if (0 == aPduInAscii)
	  delete hexBuf;
    }

#ifdef _DEBUG

/**
Appends Type of number and Numbering plan identification to TBuf8 buffer.

@param aBuffer Name of aTon will be appended to this buffer.
@param aTon TMobileTON whose name will be appended to aBuffer.
*/
void CSimSmsMessaging::AppendTonToBuffer(TDes8& aBuffer,const RMobilePhone::TMobileTON& aTon)
	{
	switch(aTon)
		{
	case (RMobilePhone::EUnknownNumber):
		{
		aBuffer.Append(_L("EUnknownNumber"));
		break;
		}
	case (RMobilePhone::EInternationalNumber):
		{
		aBuffer.Append(_L("EInternationalNumber"));
		break;
		}
	case (RMobilePhone::ENationalNumber):
		{
		aBuffer.Append(_L("ENationalNumber"));
		break;
		}
	case (RMobilePhone::ENetworkSpecificNumber):
		{
		aBuffer.Append(_L("ENetworkSpecificNumber"));
		break;
		}
	case (RMobilePhone::ESubscriberNumber):
		{
		aBuffer.Append(_L("ESubscriberNumber"));
		break;
		}
	case (RMobilePhone::EAlphanumericNumber):
		{
		aBuffer.Append(_L("EAlphanumericNumber"));
		break;
		}
	case (RMobilePhone::EAbbreviatedNumber):
		{
		aBuffer.Append(_L("EAbbreviatedNumber"));
		break;
		}
	default:
		aBuffer.Append(_L("Wrong Ton Type"));
		}
	}

void CSimSmsMessaging::AppendNpiToBuffer(TDes8& aBuffer,const RMobilePhone::TMobileNPI& aNpi)
/**
 *	Appends Numbering plan identification to TBuf8 buffer.
 */
	{
	switch(aNpi)
		{
	case (RMobilePhone::EUnknownNumberingPlan):
		{
		aBuffer.Append(_L("EUnknownNumberingPlan"));
		break;
		}
	case (RMobilePhone::EIsdnNumberPlan):
		{
		aBuffer.Append(_L("EIsdnNumberPlan"));
		break;
		}
	case (RMobilePhone::EDataNumberPlan):
		{
		aBuffer.Append(_L("EDataNumberPlan"));
		break;
		}
	case (RMobilePhone::ETelexNumberPlan):
		{
		aBuffer.Append(_L("ETelexNumberPlan"));
		break;
		}
	case (RMobilePhone::EServiceCentreSpecificPlan1):
		{
		aBuffer.Append(_L("EServiceCentreSpecificPlan1"));
		break;
		}
	case (RMobilePhone::EServiceCentreSpecificPlan2):
		{
		aBuffer.Append(_L("EServiceCentreSpecificPlan2"));
		break;
		}
	case (RMobilePhone::ENationalNumberPlan):
		{
		aBuffer.Append(_L("ENationalNumberPlan"));
		break;
		}
	case (RMobilePhone::EPrivateNumberPlan):
		{
		aBuffer.Append(_L("EPrivateNumberPlan"));
		break;
		}
	case (RMobilePhone::EERMESNumberPlan):
		{
		aBuffer.Append(_L("EERMESNumberPlan"));
		break;
		}
	default:
		aBuffer.Append(_L("Wrong Npi Type"));
		}
	}

void CSimSmsMessaging::LogTMobileSmsAttributesV1(const RMobileSmsMessaging::TMobileSmsAttributesV1& aSmsAttributesV1)
	{
	const TInt KTextWidth = 100;
	_LIT8(KFLAGS,		"   iFlags:      ");
	_LIT8(KSCADDR,		"   SC Address:  ");
	_LIT8(KSCADDRTON,	"   SC Addr TON: ");
	_LIT8(KSCADDRNPI,	"   SC Addr NPI: ");
	_LIT8(KDATAFORMAT,	"   iDataFormat: ");
	_LIT8(KDEADDR,		"   DE Address:  ");
	_LIT8(KDEADDRTON,	"   DE Addr TON: ");
	_LIT8(KDEADDRNPI,	"   DE Addr NPI: ");
	_LIT8(KMORETOSEND,	"   iMore:       ");
	_LIT8(KMSGREF,		"   iMsgRef:     ");
	_LIT8(KSUBMITREP,	"   iSubmitRep:  ");

	TBuf8<KTextWidth> buffer;

	LOGSMS1("Send Sms Attributes:");
	
	buffer.Zero();
	buffer.Copy(KFLAGS);
	buffer.Append(_L8("0x"));
	buffer.AppendFormat(_L8("%08X") , ((TInt)(aSmsAttributesV1.iFlags)));
	LOGSMS2("Buffer: %S", &buffer);

	if(aSmsAttributesV1.iFlags & RMobileSmsMessaging::KGsmServiceCentre)
		{
		buffer.Zero();
		buffer.Copy(KSCADDR);
		buffer.Append(aSmsAttributesV1.iGsmServiceCentre.iTelNumber);
		LOGSMS2("buffer: %S", &buffer);

		buffer.Zero();
		buffer.Copy(KSCADDRTON);
		AppendTonToBuffer(buffer,(aSmsAttributesV1.iGsmServiceCentre.iTypeOfNumber));
		LOGSMS2("buffer: %S", &buffer);

		buffer.Zero();
		buffer.Copy(KSCADDRNPI);
		AppendNpiToBuffer(buffer,(aSmsAttributesV1.iGsmServiceCentre.iNumberPlan));		   
		LOGSMS2("buffer: %S", &buffer);
		}
	if(aSmsAttributesV1.iFlags & RMobileSmsMessaging::KSmsDataFormat)
		{
		buffer.Zero();
		buffer.Copy(KDATAFORMAT);
		if(aSmsAttributesV1.iDataFormat == RMobileSmsMessaging::EFormatUnspecified)
			{
			buffer.Append(_L("EFormatUnspecified"));
			}
		else if(aSmsAttributesV1.iDataFormat == RMobileSmsMessaging::EFormatGsmTpdu)
			{
			buffer.Append(_L("EFormatGsmTpdu"));
			}		
		LOGSMS2("buffer: %S", &buffer);
		}
	if(aSmsAttributesV1.iFlags & RMobileSmsMessaging::KRemotePartyInfo)
		{
		const RMobileSmsMessaging::TMobileSmsSendAttributesV1& smsSendAttributesV1 = static_cast<const RMobileSmsMessaging::TMobileSmsSendAttributesV1&> (aSmsAttributesV1);

		buffer.Zero();
		buffer.Copy(KDEADDR);
		buffer.Append(smsSendAttributesV1.iDestination.iTelNumber);
		LOGSMS2("buffer: %S", &buffer);

		buffer.Zero();
		buffer.Copy(KDEADDRTON);
		AppendTonToBuffer(buffer,(smsSendAttributesV1.iDestination.iTypeOfNumber));
		LOGSMS2("buffer: %S", &buffer);

		buffer.Zero();
		buffer.Copy(KDEADDRNPI);
		AppendNpiToBuffer(buffer,(smsSendAttributesV1.iDestination.iNumberPlan)); 
		LOGSMS2("buffer: %S", &buffer);
		}
	if(aSmsAttributesV1.iFlags & RMobileSmsMessaging::KMoreToSend)
		{
		const RMobileSmsMessaging::TMobileSmsSendAttributesV1& smsSendAttributesV1 = static_cast<const RMobileSmsMessaging::TMobileSmsSendAttributesV1&> (aSmsAttributesV1);

		buffer.Zero();
		buffer.Copy(KMORETOSEND);

		if(smsSendAttributesV1.iMore)
			{
			buffer.Append(_L8("ETrue"));
			}
		else
			{
			buffer.Append(_L8("EFalse"));
			}
		LOGSMS2("buffer: %S", &buffer);
		}
	if(aSmsAttributesV1.iFlags & RMobileSmsMessaging::KMessageReference)
		{
		const RMobileSmsMessaging::TMobileSmsSendAttributesV1& smsSendAttributesV1 = static_cast<const RMobileSmsMessaging::TMobileSmsSendAttributesV1&> (aSmsAttributesV1);

		buffer.Zero();
		buffer.Copy(KMSGREF);
		buffer.Append(_L("0x"));
		buffer.AppendFormat(_L8("%08X") , smsSendAttributesV1.iMsgRef);
		LOGSMS2("buffer: %S", &buffer);
		}

	if(aSmsAttributesV1.iFlags & RMobileSmsMessaging::KGsmSubmitReport)
		{
		const RMobileSmsMessaging::TMobileSmsSendAttributesV1& smsSendAttributesV1 = static_cast<const RMobileSmsMessaging::TMobileSmsSendAttributesV1&> (aSmsAttributesV1);

		buffer.Zero();
		buffer.Copy(KSUBMITREP);

		TInt i = buffer.Length(); 
		TInt j(0);
		TInt k = (smsSendAttributesV1.iSubmitReport.Length() * 2) + buffer.Length();

		TInt l = 0;
		do
			{
			for(;i<=(KTextWidth-2);i+=2)
				{
				if(j==smsSendAttributesV1.iSubmitReport.Length())
					{
					break;
					}
				buffer.AppendFormat(_L8("%X") , smsSendAttributesV1.iSubmitReport[j]);
				j++;
				}
			LOGSMS2("buffer: %S", &buffer);
			buffer.Zero();
			i=0;
			l+=KTextWidth;
			}
		while(l < k);
		}
	}

#endif // _DEBUG
