telephonyserverplugins/simtsy/src/CSimSmsStore.cpp
changeset 0 3553901f7fa8
child 24 6638e7f4bd8f
child 42 3adadc800673
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/simtsy/src/CSimSmsStore.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,1183 @@
+// Copyright (c) 2003-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:
+// Implements the SMS Store manipulation code.
+// 
+//
+
+/**
+ @file
+*/
+
+#include <mmlist.h>
+#include <mmretrieve.h>
+#include <testconfigfileparser.h>
+#include "CSimSmsStore.h"
+#include "csimsmsmess.h"
+#include "Simlog.h"
+#include "CSimTsyMode.h"
+
+const TInt KSmsStoreGranularity=2;
+const TInt KCorruptPDU=9999;
+_LIT(KNullTelephoneNumber,"0");
+
+
+CListReadAllAttempt* CListReadAllAttempt::NewL(RMobilePhone::TClientId& aId, TTsyReqHandle aReqHandle)
+/**
+ * Standard two phase constructor.
+ * @param aId The client ID (session and sub-session handles) that uniquely identifies a client performing a two phase read.
+ * @param aReqHandle The TSY request handle of the client request associated with a two phase read.
+ * @return CListReadAllAttempt* The newly created object.
+ */
+	{
+	CListReadAllAttempt* read=new(ELeave) CListReadAllAttempt(aId, aReqHandle);
+	CleanupStack::PushL(read);
+	read->ConstructL();
+	CleanupStack::Pop();
+	return read;
+	}
+
+CListReadAllAttempt::CListReadAllAttempt(RMobilePhone::TClientId& aId, TTsyReqHandle aReqHandle)
+		: iListBuf(NULL),iReqHandle(aReqHandle)
+/**
+ * Trivial first phase constructor.
+ * @param aId The client ID (session and sub-session handles) that uniquely identifies a client performing a two phase read.
+ * @param aReqHandle The TSY request handle of the client request associated with a two phase read.
+ */
+	{
+	iClient.iSessionHandle=aId.iSessionHandle;
+	iClient.iSubSessionHandle=aId.iSubSessionHandle;
+	iReqHandle=aReqHandle;
+	iListBuf = NULL;
+	}
+
+void CListReadAllAttempt::ConstructL()
+/**
+ * Trivial second phase constructor.
+ */
+	{
+	}
+
+CListReadAllAttempt::~CListReadAllAttempt()
+/**
+ * Trivial destructor.
+ */
+	{
+	delete iListBuf;
+	}
+
+//
+// CSimSmsStore
+//
+void CSimSmsStore::ClosePhone(TAny* aObj)
+/**
+ * A utility function for cleaning up the stack.
+ */
+	{
+	((CObject*)aObj)->Close();
+	}
+
+CSimSmsStore* CSimSmsStore::NewL(CSimSmsMessaging* aSimSmsMess, const TDesC8& aName, TInt aMaxNumSlots, CSimPhone* aPhone)
+/**
+ * Standard two phase constructor.
+ * @param aSimSmsMess	The SMS Messaging object from which this SMS Store was opened.
+ * @param aName			The name of the created SMS Store.
+ * @param aMaxNumSlots	The maximum number of slots in the SMS Store.
+ * @return CSimSmsStore* The newly created object.
+ */
+	{
+	CSimSmsStore* store=new(ELeave) CSimSmsStore(aSimSmsMess, aPhone);
+	TCleanupItem newObjClose(ClosePhone,store);
+	CleanupStack::PushL(newObjClose);
+	store->ConstructL(aName,aMaxNumSlots);
+	CleanupStack::Pop();
+	return store;
+	}
+
+CSimSmsStore::CSimSmsStore(CSimSmsMessaging* aSmsMess, CSimPhone* aPhone)
+		: iSmsMessaging(aSmsMess), iEvOutstandingReq(EFalse), iPhone(aPhone)
+/**
+ * Trivial first phase constructor.
+ * @param aSimSmsMess	The SMS Messaging object from which this SMS Store was opened.
+ */
+	{}
+
+void CSimSmsStore::ConstructL(const TDesC8& aName, TInt aMaxNumSlots)
+/**
+ * Second phase constructor that allocates memory for the SMS store, batch read buffer and
+ * a delayed completion timer.  The constructor also reads the individual and batch read
+ * delays from the configuration file.
+ * 
+ * @param aName			The name of the created SMS Store.
+ * @param aMaxNumSlots	The maximum number of slots in the SMS Store.
+ */
+	{
+	iGsmSmsStoreEntries=new(ELeave) RMobileSmsStore::TMobileGsmSmsEntryV1[aMaxNumSlots+1];//index 0 is not used
+	iSmsMaxNumSlots=aMaxNumSlots;
+	iSmsStoreName.Copy(aName);
+	iSmsReadAll=new(ELeave) CArrayPtrFlat<CListReadAllAttempt>(KSmsStoreGranularity);
+	LOGSMS1("Starting to parse SMS Store config parameters...");
+	iSmsIndividualPause=CfgFileSection()->ItemValue(KSmsStoreIndividualReqPause,KDefaultSmsStoreIndividualReqPause);
+	iSmsBatchPause=CfgFileSection()->ItemValue(KSmsStoreBatchReqPause,KDefaultSmsStoreBatchReqPause);
+	
+	const CTestConfigItem* item0=NULL;
+	item0=CfgFileSection()->Item(KSmsPhoneStoreCaps,0);
+	if (item0)
+		{
+		TPtrC8 value0;
+		TInt ret0=CTestConfig::GetElement(item0->Value(),KStdDelimiter,0,value0);
+		if(ret0!=KErrNone)
+			{
+			LOGPARSERR("value0",ret0,0,&KSmsPhoneStoreCaps);
+			iSmsStoreCaps=KDefaultSmsPhoneStoreCaps+KDefaultSmsOnlySmsCaps;
+			}
+		else
+			{
+			TUint32 intValue;
+			TInt ret = AsciiToNum(value0, intValue);
+			if(ret!=KErrNone)
+				iSmsStoreCaps=KDefaultSmsPhoneStoreCaps+KDefaultSmsOnlySmsCaps;
+			else
+				iSmsStoreCaps = intValue+KDefaultSmsOnlySmsCaps;
+			}
+		}
+	else
+		iSmsStoreCaps=KDefaultSmsPhoneStoreCaps+KDefaultSmsOnlySmsCaps;
+
+
+	LOGSMS1("...Finished parsing SMS Store config parameters");
+	iTimer=CSimTimer::NewL(iSmsMessaging->iPhone);
+	iIncomingTimer=CSimTimer::NewL(iSmsMessaging->iPhone);
+	}
+
+void CSimSmsStore::PopulateStoreFromConfigFile()
+/**
+ * Populate the SMS Store from information in the configuration file.  This is performed
+ * after the standard SMS Store construction in order to prevent reseting the configuation
+ * file accessor class' pointers while possibly multiple SMS Stores are created.
+ *
+ * The store entries comply to the following format:
+ * "SmsStoreEntry = <store name>, <slot number>, <entry status>, <pdu>"
+ */
+	{
+	LOGSMS1("Starting reading SMS Store entries...");
+	TInt count=CfgFileSection()->ItemCount(KSmsStoreEntry);
+	const CTestConfigItem* item=NULL;
+	TInt ret=KErrNone;
+
+	for(TInt i=0;i<count;i++)
+		{
+		item=CfgFileSection()->Item(KSmsStoreEntry,i);
+		if(!item)
+			break;
+
+		TPtrC8 storeName;
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,storeName);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("storeName",ret,0,&KSmsStoreEntry);
+			continue;
+			}
+		if(storeName.MatchF(iSmsStoreName)!=0)
+			continue;						// Not this store
+
+		TInt index,stat;
+		TPtrC8 pdu;
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,index);
+		if((ret!=KErrNone)||(index>=iSmsMaxNumSlots))
+			{
+			LOGPARSERR("index",ret,1,&KSmsStoreEntry);
+			continue;
+			}
+	
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,stat);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("stat",ret,2,&KSmsStoreEntry);
+			continue;
+			}
+
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,pdu);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("pdu",ret,3,&KSmsStoreEntry);
+			continue;
+			}
+
+		TPtrC8 sca;
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,4,sca);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("sca",ret,4,&KSmsStoreEntry);
+			continue;
+			}
+		iGsmSmsStoreEntries[index].iIndex=index;
+		iGsmSmsStoreEntries[index].iMsgStatus=(RMobileSmsStore::TMobileSmsStoreStatus)stat;
+		ConvertAsciiSms(pdu,iGsmSmsStoreEntries[index].iMsgData);
+		RecordSca(sca, index);
+		}
+
+	LOGSMS1("...Finished reading SMS Store entries");
+	}
+
+
+
+void CSimSmsStore::RecordSca(const TDesC8& aAsciiAddr, TInt aIndex)
+/**
+ * Used to set the sca number
+ * 
+ *
+ * @param aAsciiSca Ascii representation of a telephone number such as the one found in the configuration file
+ * @param aType specifies whether aAsciiAddres should be used to fill in the sca or destination field of the smsp entry
+ * @param aIndex specifies at which index in the smsp list the number should be filled in
+ */
+	{
+	if(aAsciiAddr.Length()>0)//only support for international numbers
+		{
+		iGsmSmsStoreEntries[aIndex].iServiceCentre.iNumberPlan=RMobilePhone::EIsdnNumberPlan;
+		iGsmSmsStoreEntries[aIndex].iServiceCentre.iTypeOfNumber=RMobilePhone::EInternationalNumber;
+		iGsmSmsStoreEntries[aIndex].iServiceCentre.iTelNumber.Copy(aAsciiAddr);
+		}
+	}
+
+CSimSmsStore::~CSimSmsStore()
+/**
+ * Standard destructor.  Any objects created by the ::ConstructL() function
+ * will be destroyed here.
+ */
+	{
+	delete[] iGsmSmsStoreEntries;
+	
+	if (iSmsReadAll)
+		{
+		iSmsReadAll->ResetAndDestroy();
+		delete iSmsReadAll;
+		}
+
+	delete iTimer;
+	delete iIncomingTimer;
+	}
+
+#ifdef _DEBUG
+void CSimSmsStore::LogRequest(TBool aEntering, TInt aIpc, TInt aError)
+#else
+void CSimSmsStore::LogRequest(TBool aEntering, TInt aIpc, TInt /*aError*/)
+#endif
+/**
+ * This method logs client requests to the t_reg.txt
+ * @param aEntering Tells if the request is entering 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 EMobilePhoneStoreGetInfo:
+			ipcBuf = _L8("GetInfo");
+			break;
+
+		case EMobilePhoneStoreNotifyStoreEvent:
+			ipcBuf = _L8("NotifyStoreEvent");
+			break;
+
+		case EMobilePhoneStoreRead:
+			ipcBuf = _L8("Read");
+			break;
+
+		case EMobilePhoneStoreWrite:
+			ipcBuf = _L8("Write");
+			break;
+
+		case EMobilePhoneStoreDelete:
+			ipcBuf = _L8("Delete");
+			break;
+
+		case EMobilePhoneStoreReadAllPhase1:
+			ipcBuf = _L8("ReadAllPhase1");
+			break;
+
+
+		case EMobilePhoneStoreReadAllPhase2:
+			ipcBuf = _L8("ReadAllPhase2");
+			break;
+
+		case EMobilePhoneStoreDeleteAll:
+			ipcBuf = _L8("DeleteAll");
+			break;		
+		
+		default:
+			ipcBuf = _L8("OTHER");
+			break;
+		}
+
+	if (aEntering!=EFalse)
+		{
+		LOGSMS3(">>%d,CSimSmsStore::%S",aIpc, &ipcBuf );
+		}
+	else
+		{
+		LOGSMS4("<<%d,CSimSmsStore::%S with error %d",aIpc, &ipcBuf, aError);
+		}
+	}
+
+
+
+
+TInt CSimSmsStore::ExtFunc(const TTsyReqHandle aReqHandle,const TInt aIpc, const TDataPackage& aPckg)
+/**
+ * Dispatch function for all SMS Store requests.
+ * @param aReqHandle	The TSY request handle for this request.
+ * @param aIpc			The IPC number of this request.
+ * @param aPckg			The parameter package related to this request.
+ * @return TInt			The return error condition.
+ */
+	{
+// The following requests can be completed even if the completion of another request is pending.
+	TInt ret=KErrNone;//error is only used with LogRequest when at the end of ExtFunc
+	LogRequest(ETrue, aIpc, ret);
+	switch(aIpc)
+		{
+	case EMobilePhoneStoreGetInfo:
+		ret = GetInfo(aReqHandle,aPckg.Des1n());
+		LogRequest(EFalse, aIpc, ret);
+		return ret;
+
+	case EMobilePhoneStoreNotifyStoreEvent:
+		ret =  NotifyStoreEvent(aReqHandle,aPckg.Des1n(),aPckg.Des2n());
+		LogRequest(EFalse, aIpc, ret);
+		return ret;
+
+	default:
+		break;
+		}
+	
+
+// The TSY can only process one of the following requests at a time.  If a second is received
+// while processing the first, then it will be errored with KErrInUse.  This restriction will
+// be removed later, by inserting a request queuing mechanism.  Note that the standard TSY
+// "flow control" mechanism works phone-wide and so is not suitable.
+
+	if(iTimer->IsActive())
+		{
+		ReqCompleted(aReqHandle,KErrInUse);
+		return KErrNone;
+		}
+
+	switch(aIpc)
+		{
+	case EMobilePhoneStoreRead:
+		ret = Read(aReqHandle,aPckg.Des1n());
+		break;
+
+	case EMobilePhoneStoreWrite:
+		ret = Write(aReqHandle,aPckg.Des1n());
+		break;
+
+	case EMobilePhoneStoreDelete:
+		ret = Delete(aReqHandle,aPckg.Des1n());
+		break;
+
+	case EMobilePhoneStoreReadAllPhase1:
+		ret = ReadAllPhase1(aReqHandle,aPckg.Des1n(),aPckg.Des2n());
+		break;
+
+	case EMobilePhoneStoreReadAllPhase2:
+		ret = ReadAllPhase2(aReqHandle,aPckg.Des1n(),aPckg.Des2n());
+		break;
+
+	case EMobilePhoneStoreDeleteAll:
+		ret = DeleteAll(aReqHandle);
+		break;
+
+	default:
+		return KErrNotSupported;
+		}
+	LogRequest(EFalse, aIpc, ret);
+	return ret;
+
+	}
+
+CTelObject* CSimSmsStore::OpenNewObjectByNameL(const TDesC& /*aName*/)
+/**
+ * The API does not support any objects that could be opened from this one.
+ */
+	{
+	User::Leave(KErrNotSupported);
+	return NULL;
+	}
+
+CTelObject* CSimSmsStore::OpenNewObjectL(TDes&)
+/**
+ * The API does not support any objects that could be opened from this one.
+ */
+	{
+	User::Leave(KErrNotSupported);
+	return NULL;
+	}
+
+CTelObject::TReqMode CSimSmsStore::ReqModeL(const TInt aIpc)
+/**
+ * This function returns the Request Mode for the request with the passed IPC value.
+ * @param aIpc		The IPC number of the request.
+ * @return TReqMode	The request mode.
+ */
+	{
+	CTelObject::TReqMode ret=0;	
+
+	switch(aIpc)
+		{
+	case EMobilePhoneStoreGetInfo:
+	case EMobilePhoneStoreRead:
+	case EMobilePhoneStoreWrite:
+	case EMobilePhoneStoreDelete:
+	case EMobilePhoneStoreReadAllPhase1:
+	case EMobilePhoneStoreReadAllPhase2:
+	case EMobilePhoneStoreDeleteAll:
+		break;
+
+	case EMobilePhoneStoreNotifyStoreEvent:
+		ret=KReqModeMultipleCompletionEnabled | KReqModeRePostImmediately;
+		break;
+
+	default:
+		User::Leave(KErrNotSupported);
+		break;
+		}
+
+	return ret;
+	}
+
+TInt CSimSmsStore::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 CSimSmsStore::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 CSimSmsStore::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 CSimSmsStore::CancelService(const TInt aIpc,const TTsyReqHandle /*aTsyReqHandle*/)
+/**
+ * Cancel an outstanding request.
+ * @param aIpc			The IPC number of the request that is to be cancelled.
+ * @param aTsyReqHandle	The TSY request handle of the request that is to be cancelled.
+ * @param TInt			Standard return value.
+ */
+	{
+	switch(aIpc)
+		{
+	case EMobilePhoneStoreGetInfo:
+	case EMobilePhoneStoreRead:
+	case EMobilePhoneStoreWrite:
+	case EMobilePhoneStoreDelete:
+		if(iTimer->Running())
+			{
+			iTimer->Cancel();
+			ReqCompleted(iPendingReqCompletion,KErrCancel);
+			}
+		break;
+	case EMobilePhoneStoreReadAllPhase1:
+		ReadAllCancel();
+		break;
+	case EMobilePhoneStoreDeleteAll:
+		DeleteAllCancel();
+		break;
+	case EMobilePhoneStoreNotifyStoreEvent:
+		NotifyStoreEventCancel();
+		break;
+	default:
+		break;
+		}
+	return KErrNone;
+	}
+
+void CSimSmsStore::Init()
+/**
+ *	This function can be used to perform any necessary synchronous initialisation.
+ */
+	{
+	}
+
+TInt CSimSmsStore::GetInfo(TTsyReqHandle aReqHandle, TDes8* aPckg)
+/**
+ * Retrieve SMS Store information. This request is completed immediately, as it is assumed
+ * that in a real TSY, all this data will be cached in the TSY.
+ *
+ * @param aReqHandle	The TSY request handle associated with this request.
+ * @param aPckg			The parameter package associated with this request.
+ */
+	{
+	RMobilePhoneStore::TMobilePhoneStoreInfoV1Pckg* getInfoPckg=(RMobilePhoneStore::TMobilePhoneStoreInfoV1Pckg*)aPckg;
+	RMobilePhoneStore::TMobilePhoneStoreInfoV1& getInfo=(*getInfoPckg)();
+
+	// Check that the data structure is supported by the simulated TSY version
+	TInt err = iPhone->CheckSimTsyVersion(getInfo);
+	if(err != KErrNone)
+		{
+		ReqCompleted(aReqHandle, err);
+		return KErrNone;
+		}
+
+	getInfo.iType=RMobilePhoneStore::EShortMessageStore;
+	getInfo.iTotalEntries=MaxSlots();
+	getInfo.iCaps=iSmsStoreCaps;
+	getInfo.iName.Copy(iSmsStoreName);
+	getInfo.iUsedEntries=UsedEntries();
+
+	ReqCompleted(aReqHandle,KErrNone);
+	return KErrNone;
+	}
+
+TInt CSimSmsStore::Read(TTsyReqHandle aReqHandle, TDes8* aPckg)
+/**
+ * Read a single SMS store entry.  The completion of this request is delayed in order to
+ * simulate a real TSY that would have to go and get the information from a SIM card.
+ *
+ * @param aReqHandle	The TSY request handle associated with this request.
+ * @param aPckg			The parameter package associated with this request.
+ */
+	{
+	if (!(iSmsStoreCaps & RMobilePhoneStore::KCapsIndividualEntry && iSmsStoreCaps & RMobilePhoneStore::KCapsReadAccess))
+		{
+		ReqCompleted(aReqHandle, KErrAccessDenied);
+		return KErrNone;
+		}
+
+	RMobileSmsStore::TMobileSmsEntryV1Pckg* smsPckg=(RMobileSmsStore::TMobileSmsEntryV1Pckg*)aPckg;	
+	RMobileSmsStore::TMobileSmsEntryV1& sms=(*smsPckg)();
+		
+	// Check that the data structure is supported by the simulated TSY version
+	TInt err = iPhone->CheckSimTsyVersion(sms);
+	if(err != KErrNone)
+		{
+		ReqCompleted(aReqHandle, err);
+		return KErrNone;
+		}
+
+	switch (sms.ExtensionId())
+		{
+		case RMobileSmsStore::KETelMobileGsmSmsEntryV1:
+			{
+			RMobileSmsStore::TMobileGsmSmsEntryV1Pckg* gsmSmsPckg=(RMobileSmsStore::TMobileGsmSmsEntryV1Pckg*)aPckg;
+			RMobileSmsStore::TMobileGsmSmsEntryV1& gsmSms=(*gsmSmsPckg)();
+
+			// Check that the data structure is supported by the simulated TSY version
+			TInt err = iPhone->CheckSimTsyVersion(gsmSms);
+			if(err != KErrNone)
+				{
+				ReqCompleted(aReqHandle, err);
+				return KErrNone;
+				}
+
+			TInt& index=gsmSms.iIndex;
+			if((index<1)||(index>iSmsMaxNumSlots))
+				{
+				ReqCompleted(aReqHandle,KErrArgument);
+				return KErrNone;
+				}
+				
+			if (iGsmSmsStoreEntries[index].iMsgStatus == KCorruptPDU)
+				{
+				ReqCompleted(aReqHandle,KErrCorrupt);
+				return KErrNone;			    
+				}
+
+			if(iGsmSmsStoreEntries[index].iMsgData.Length()==0)
+				{
+				ReqCompleted(aReqHandle, KErrNotFound);
+				return KErrNone;
+				}
+
+			gsmSms.iMsgData.Copy(iGsmSmsStoreEntries[index].iMsgData);
+			gsmSms.iMsgStatus=iGsmSmsStoreEntries[index].iMsgStatus;
+			gsmSms.iServiceCentre=iGsmSmsStoreEntries[index].iServiceCentre;
+			break;
+			}
+		case RMobileSmsStore::KETelMobileCdmaSmsEntryV1:
+			 ReqCompleted(aReqHandle,KErrNotSupported);
+			 return KErrNone;	
+
+		default:
+			ReqCompleted(aReqHandle,KErrArgument);
+			return KErrNone;
+		}
+	
+	DelayCompletion(iSmsIndividualPause,aReqHandle);
+	return KErrNone;
+	}
+
+TInt CSimSmsStore::Write(TTsyReqHandle aReqHandle,TDes8* aPckg)
+/**
+ * Write a single SMS store entry.  The completion of this request is delayed in order to
+ * simulate a real TSY that would have to write the information to a SIM card. A store
+ * event may be triggered by this request.
+ *
+ * @param aReqHandle	The TSY request handle associated with this request.
+ * @param aPckg			The parameter package associated with this request.
+ */
+	{
+	if (!(iSmsStoreCaps & RMobilePhoneStore::KCapsIndividualEntry && iSmsStoreCaps & RMobilePhoneStore::KCapsWriteAccess))
+		{
+		ReqCompleted(aReqHandle, KErrAccessDenied);
+		return KErrNone;
+		}
+
+	TStoreEvent event=EStoreEventNoEvent;
+	TInt index;
+
+	RMobileSmsStore::TMobileSmsEntryV1Pckg* smsPckg=(RMobileSmsStore::TMobileSmsEntryV1Pckg*)aPckg;	
+	RMobileSmsStore::TMobileSmsEntryV1& sms=(*smsPckg)();
+		
+	// Check that the data structure is supported by the simulated TSY version
+	TInt err = iPhone->CheckSimTsyVersion(sms);
+	if(err != KErrNone)
+		{
+		ReqCompleted(aReqHandle, err);
+		return KErrNone;
+		}
+
+	switch (sms.ExtensionId())
+		{
+		case RMobileSmsStore::KETelMobileGsmSmsEntryV1:
+			{
+			RMobileSmsStore::TMobileGsmSmsEntryV1Pckg* gsmSmsPckg=(RMobileSmsStore::TMobileGsmSmsEntryV1Pckg*)aPckg;
+			RMobileSmsStore::TMobileGsmSmsEntryV1& gsmSms=(*gsmSmsPckg)();
+
+			// Check that the data structure is supported by the simulated TSY version
+			TInt err = iPhone->CheckSimTsyVersion(gsmSms);
+			if(err != KErrNone)
+				{
+				ReqCompleted(aReqHandle, err);
+				return KErrNone;
+				}
+
+			index=gsmSms.iIndex;
+			if(index==-1)//check the 1st free slot
+				{
+				for(TInt i=1;i<=iSmsMaxNumSlots;i++)
+					{
+					if(iGsmSmsStoreEntries[i].iMsgData.Length()==0)
+						{
+						index=i;
+						//ret = KErrNone;
+						break;
+						}
+					}
+				}
+			//else ret = KErrNone;//if index is specified entry will be overwitten, not possible to exceed memory
+			if((index<1)||(index>iSmsMaxNumSlots))
+				{
+				ReqCompleted(aReqHandle,KErrArgument);
+				return KErrNone;
+				}
+
+			//
+			// This can never happen because either ret is KErrNone or
+			// index is still -1 and we have returned.
+			// 
+				//if (ret==KErrNoMemory)
+					//ReqCompleted(aReqHandle,ret);
+
+			if(iGsmSmsStoreEntries[index].iMsgData.Length()==0)
+				event=EStoreEventAdded;
+			else
+				event=EStoreEventChanged;
+
+			gsmSms.iIndex = index;		// Update index data member for the client
+			iGsmSmsStoreEntries[index].iIndex=index;
+			iGsmSmsStoreEntries[index].iMsgData.Copy(gsmSms.iMsgData);
+			iGsmSmsStoreEntries[index].iMsgStatus=gsmSms.iMsgStatus;
+			iGsmSmsStoreEntries[index].iServiceCentre=gsmSms.iServiceCentre;
+			break;
+			}
+		case RMobileSmsStore::KETelMobileCdmaSmsEntryV1:
+			 ReqCompleted(aReqHandle,KErrNotSupported);
+			 return KErrNone;		
+
+		default:
+			ReqCompleted(aReqHandle,KErrArgument);
+			return KErrNone;
+		}
+
+	DelayCompletion(iSmsIndividualPause,aReqHandle,event,index);
+	return KErrNone;
+	}
+
+TInt CSimSmsStore::StoreIncomingMessage(RMobileSmsStore::TMobileGsmSmsEntryV1* aSms)
+/**
+ * This method is used to store Incoming sms messages with the status EMtMessageStored
+ * It is accessed by CSimSmsMessaging::AttemptSmsRxCompleteL.
+ * Note: this will not call ReqComplete as no client request has been posted on this class
+ * Note: the smsStack will delete the message from the store after ReceiveMessage has completed
+ **/
+	{
+	
+	TInt& index=aSms->iIndex;
+	TInt ret=KErrNoMemory;
+	TStoreEvent event=EStoreEventNoEvent;
+	for(TInt i=1;i<=iSmsMaxNumSlots;i++)
+		{
+		if(iGsmSmsStoreEntries[i].iMsgData.Length()==0)
+			{
+			index=i;
+			event=EStoreEventAdded;
+			ret = KErrNone;
+			break;
+			}
+			
+		}
+
+	aSms->iIndex=index;//set here to be used by CSimSmsMessaging
+	
+	if (ret==KErrNone)
+		{
+		iGsmSmsStoreEntries[index].iIndex=index;
+		iGsmSmsStoreEntries[index].iMsgData.Copy(aSms->iMsgData);
+		iGsmSmsStoreEntries[index].iMsgStatus=aSms->iMsgStatus;
+		iGsmSmsStoreEntries[index].iServiceCentre=aSms->iServiceCentre;
+
+		iPendingEvent=event;
+		iPendingIndex=index;
+		iIncomingTimer->Start(iSmsIndividualPause,this, 1);//delay the notification 
+		}
+
+	return ret;
+	}
+
+
+TInt CSimSmsStore::Delete(TTsyReqHandle aReqHandle,TDes8* aPckg)
+/**
+ * Delete a single SMS store entry.  The completion of this request is delayed in order to
+ * simulate a real TSY that would have to write the information to a SIM card. A store
+ * event may be triggered by this request.
+ *
+ * @param aReqHandle	The TSY request handle associated with this request.
+ * @param aPckg			The parameter package associated with this request.
+ * @return				Standard return value.
+ */
+	{
+	if (!(iSmsStoreCaps & RMobilePhoneStore::KCapsIndividualEntry && iSmsStoreCaps & RMobilePhoneStore::KCapsWriteAccess))
+		{
+		ReqCompleted(aReqHandle, KErrAccessDenied);
+		return KErrNone;
+		}
+
+	TPckg<TInt>* intPckg=(TPckg<TInt>*)aPckg;
+	TInt& index=(*intPckg)();
+
+	if((index<1)||(index>iSmsMaxNumSlots))
+		{
+		ReqCompleted(aReqHandle,KErrArgument);
+		return KErrNone;
+		}
+
+	iGsmSmsStoreEntries[index].iMsgData.Zero();
+	iGsmSmsStoreEntries[index].iMsgStatus=RMobileSmsStore::EStoredMessageUnknownStatus;
+	iGsmSmsStoreEntries[index].iServiceCentre.iTelNumber=KNullTelephoneNumber;
+	
+	DelayCompletion(iSmsIndividualPause,aReqHandle,EStoreEventDeleted,index);
+	return KErrNone;
+	}
+
+TInt CSimSmsStore::ReadAllPhase1(TTsyReqHandle aReqHandle,TDes8* aPckg1,TDes8* aPckg2)
+/**
+ * First phase of a batch SMS Store read.  The completion of this request is delayed in
+ * order to simulate a real TSY that would have to get the information from a SIM card.
+ * If the GetSmspListPhase1L should leave this method takes care of that and 
+ * makes a premature ReqCompleted to the client.
+ * 
+ * @param aReqHandle	The TSY request handle associated with this request.
+ * @param aPckg1		The first parameter package associated with this request.
+ *						It contains the client ID information required to uniquely identify this request.
+ *						It also contains the batch read information (first slot, number of slots).
+ * @param aPckg2		The parameter package associated with this request.
+ *						The size of the information to be passed back to the client is returned in this package.
+ * @return				Standard return value.
+ */	{
+ 	if (!(iSmsStoreCaps & static_cast<TUint32>(RMobilePhoneStore::KCapsWholeStore) && iSmsStoreCaps & RMobilePhoneStore::KCapsReadAccess))
+		{
+		ReqCompleted(aReqHandle, KErrAccessDenied);
+		return KErrNone;
+		}
+		
+
+	TPckg<CRetrieveMobilePhoneSmsList::TBatchRequestData>* clientIdPckg=(TPckg<CRetrieveMobilePhoneSmsList::TBatchRequestData>*) aPckg1;
+	CRetrieveMobilePhoneSmsList::TBatchRequestData& clientId=(*clientIdPckg)();
+	TPckg<TInt>* sizePckg=(TPckg<TInt>*)aPckg2;
+	TInt& size=(*sizePckg)();
+
+	TRAPD(leaveCode,ReadAllPhase1L(aReqHandle,clientId,size));
+
+	return leaveCode;
+	}
+
+
+
+
+void CSimSmsStore::ReadAllPhase1L(TTsyReqHandle aReqHandle,CRetrieveMobilePhoneSmsList::TBatchRequestData& aClientId, 
+											 TInt& aBufSize)
+/**
+ * Implementation of ReadAllPhase1. 
+ *
+ */
+
+	{
+	TInt cnt=0;
+	CMobilePhoneListBase* listBase = NULL;
+
+	if ((CSimTsyMode::GetMode() != CSimTsyMode::ECdmaV1) &&
+		(aClientId.iEntryType == RMobileSmsStore::KETelMobileGsmSmsEntryV1))
+		{
+		listBase = CMobilePhoneGsmSmsList::NewL();
+		}
+	else
+		{
+		// Nothing to read.
+		ReqCompleted(aReqHandle, KErrNone);
+		return;
+		}
+
+	CleanupStack::PushL(listBase);
+
+	if(!aClientId.iBatchRequest)
+		{
+		aClientId.iStartIndex=1;
+		aClientId.iBatchSize=iSmsMaxNumSlots;
+		}
+
+	for(TInt i = aClientId.iStartIndex; cnt < aClientId.iBatchSize; i++)
+		{
+		if (i > iSmsMaxNumSlots)
+			break;
+		
+		if (aClientId.iEntryType == RMobileSmsStore::KETelMobileGsmSmsEntryV1)
+			{
+			if (iGsmSmsStoreEntries[i].iMsgData.Length() != 0)
+				{
+				((CMobilePhoneGsmSmsList*)listBase)->AddEntryL(iGsmSmsStoreEntries[i]);
+				cnt++;
+				}
+			}
+
+		}
+
+	// Store the streamed list and the client ID
+	CListReadAllAttempt* read=CListReadAllAttempt::NewL(aClientId.iClient, aReqHandle);
+	CleanupStack::PushL(read);
+
+	read->iListBuf = listBase->StoreLC();
+	CleanupStack::Pop(); // pop the CBufFlat allocated by StoreLC
+
+	iSmsReadAll->AppendL(read);
+	CleanupStack::Pop(); // pop the CListReadAllAttempt
+	
+	// return the CBufFlat’s size to client			
+	aBufSize=(read->iListBuf)->Size();		
+	
+	CleanupStack::PopAndDestroy(); // pop&destroy list
+	// Complete first phase of list retrieval
+
+	DelayCompletion(iSmsBatchPause,aReqHandle);
+//	return KErrNone;
+	}
+
+TInt CSimSmsStore::ReadAllPhase2(TTsyReqHandle aReqHandle,TDes8* aPckg1,TDes8* aBuffer)
+/**
+ * Second phase of a batch SMS Store read.  The completion of this request is not delayed
+ * as it is assumed that the TSY has already cached the required information (during the
+ * first phase of the read).
+ *
+ * @param aReqHandle	The TSY request handle associated with this request.
+ * @param aPckg1		The first parameter package associated with this request.
+ *						It contains the client ID information required to uniquely identify this request.
+ * @param aBuffer		The parameter package associated with this request.
+ *						It contains the read buffer in which the required information is returned.
+ * @return				Standard return value.
+ */
+	{
+	TPckg<RMobilePhone::TClientId>* clientIdPckg=(TPckg<RMobilePhone::TClientId>*) aPckg1;
+	RMobilePhone::TClientId& clientId=(*clientIdPckg)();
+
+	for (TInt i=0; i<iSmsReadAll->Count(); ++i)
+		{
+		CListReadAllAttempt* read = iSmsReadAll->At(i);
+		if ((read->iClient.iSessionHandle==clientId.iSessionHandle) &&
+		    (read->iClient.iSubSessionHandle==clientId.iSubSessionHandle))
+			{
+			TPtr8 bufPtr((read->iListBuf)->Ptr(0));
+			// Copy the streamed list to the client
+			aBuffer->Copy(bufPtr);
+			delete read;
+			iSmsReadAll->Delete(i);
+			ReqCompleted(aReqHandle,KErrNone);
+			return KErrNone;
+			}
+		}
+
+// Don't delay completion of this request, as we assume the TSY will have the results in
+// memory from the first request.
+	ReqCompleted(aReqHandle,KErrNotFound);
+	return KErrNone;
+	}
+
+TInt CSimSmsStore::DeleteAll(TTsyReqHandle aReqHandle)
+/**
+ * Delete all entries in the SIM Store.  The completion of this function is delayed in
+ * order to simulate the SIM operations a real TSY would have to carry out.  This function
+ * may trigger an SMS Store notification.
+ *
+ * @param aReqHandle	The TSY request handle associated with this request.
+ * @return				Standard return value.
+ */
+	{
+	if (!(iSmsStoreCaps & static_cast<TUint32>(RMobilePhoneStore::KCapsWholeStore) && iSmsStoreCaps & RMobilePhoneStore::KCapsWriteAccess))
+		{
+		ReqCompleted(aReqHandle, KErrAccessDenied);
+		return KErrNone;
+		}
+
+	for(TInt i=1;i<=iSmsMaxNumSlots;i++)
+		{
+	
+			iGsmSmsStoreEntries[i].iIndex=i;
+			iGsmSmsStoreEntries[i].iMsgStatus=RMobileSmsStore::EStoredMessageUnknownStatus;
+			iGsmSmsStoreEntries[i].iMsgData.Zero();
+			iGsmSmsStoreEntries[i].iServiceCentre.iTelNumber=KNullTelephoneNumber;
+			
+		}
+
+	DelayCompletion(iSmsBatchPause,aReqHandle,EStoreEventDeleted,-1);
+	return KErrNone;
+	}
+
+TInt CSimSmsStore::NotifyStoreEvent(TTsyReqHandle aReqHandle,TDes8* aPckg1,TDes8* aPckg2)
+/**
+ * Register a client's interest in SMS Store events.
+ *
+ * @param aReqHandle	The TSY request handle associated with this request.
+ * @param aPckg1		The first parameter package associated with this request.
+ *						It contains the event flags that will be returned to the client.
+ * @param aPckg2		The second parameter package associated with this request.
+ *						It contains the index value associated with the event
+ *						that will be returned to the client.
+ * @return				Standard return value.
+ */
+	{
+	if (!(iSmsStoreCaps & RMobilePhoneStore::KCapsNotifyEvent))
+		{
+		ReqCompleted(aReqHandle, KErrNotSupported);
+		return KErrNone;
+		}
+
+	__ASSERT_ALWAYS(iEvOutstandingReq==EFalse,SimPanic(ENotificationAlreadyPending));
+	
+	TPckg<TUint32>* eventPckg=(TPckg<TUint32>*)aPckg1;
+	TUint32& event=(*eventPckg)();
+	TPckg<TInt>* indexPckg=(TPckg<TInt>*)aPckg2;
+	TInt& index=(*indexPckg)();
+
+	iEvOutstandingReq=ETrue;
+	iEvReqHandle=aReqHandle;
+	iEvEvent=&event;
+	iEvIndex=&index;
+	return KErrNone;
+	}
+
+void CSimSmsStore::NotifyStoreEventCancel()
+/**
+ * Cancel an outstanding notify store request.
+ */
+	{
+	if(iEvOutstandingReq)
+		{
+		iEvOutstandingReq=EFalse;
+		ReqCompleted(iEvReqHandle,KErrCancel);
+		}
+	}
+
+//coverity[bad_override]
+TPtrC8 CSimSmsStore::Name()
+/**
+ * Accessor function fot the SMS Store name.
+ *
+ * @return TPtrC8	The name of this SMS Store.
+ */
+	{
+	return iSmsStoreName;
+	}
+
+TInt CSimSmsStore::UsedEntries()
+/**
+ * Count the number of used entries in the SMS Store.
+ * @return TInt	The number of used entries in the store.
+ */
+	{
+	TInt cnt=0;
+	for(TInt i=1;i<=iSmsMaxNumSlots;i++)
+		{
+		if(iGsmSmsStoreEntries[i].iMsgData.Length()!=0)
+		cnt++;		
+		}
+	return cnt;
+	}
+
+TInt CSimSmsStore::MaxSlots()
+/**
+ * Retrieve the maximum number of slots in this SMS Store.
+ * @return TInt	The maximum number of slots in this SMS Store.
+ */
+	{
+	return iSmsMaxNumSlots;
+	}
+
+void CSimSmsStore::DelayCompletion(TInt aDelayDuration,TTsyReqHandle aReqHandle)
+/**
+ * A shell function for functions that wish to delay completion but do not trigger store
+ * events.
+ */
+	{
+	DelayCompletion(aDelayDuration,aReqHandle,EStoreEventNoEvent,0);
+	}
+
+TUint CSimSmsStore::StoreCaps()
+	{
+	return iSmsStoreCaps;
+	}
+
+void CSimSmsStore::DelayCompletion(TInt aDelayDuration,TTsyReqHandle aReqHandle,TStoreEvent aEvent,TInt aIndex)
+/**
+ * Delay the completion of a TSY request.  It is assumed that the member variable
+ * manipulation associated with the request has already taken place, and so all that is
+ * left to do is call the ETel server's request completion function when the timer expires.
+ * So, just record the parameters and kick off the timer.
+ *
+ * @param aDelayDuration	The time (in seconds) for which the request completion is to be delayed.
+ * @param aReqHandle		The TSY request handle related to the delayed completion.
+ * @param aEvent			The store event related to the delayed completion.
+ * @param aIndex			The index related to the event passed in aEvent.
+ */
+	{
+	iPendingReqCompletion=aReqHandle;
+	iPendingEvent=aEvent;
+	iPendingIndex=aIndex;
+	iTimer->Start(aDelayDuration,this);
+	}
+
+
+void CSimSmsStore::ReadAllCancel()
+/*
+ * Cancel an outstanding read/write smsp.
+ */
+	{
+	iTimer->Cancel();
+	ReqCompleted(iPendingReqCompletion,KErrCancel);
+	}
+
+void CSimSmsStore::DeleteAllCancel()
+/*
+ * Cancel an outstanding read/write smsp.
+ */
+	{
+	iTimer->Cancel();
+	ReqCompleted(iPendingReqCompletion,KErrNone);//The timer is cancelled but data has already been deleted
+	}
+
+void CSimSmsStore::TimerCallBack(TInt aId)
+/**
+ * Process a timer call back event.  The timer is used to kick requests which have had their
+ * completions delayed.
+ */
+	{
+	StoreEvent(iPendingEvent,iPendingIndex);
+	if (aId!=1)//aId is 1 if reuest is StoreIncomingMessage(coming from CSimSmsMessaging)
+		ReqCompleted(iPendingReqCompletion,KErrNone);
+	}
+
+void CSimSmsStore::StoreEvent(TStoreEvent aEvent,TInt aIndex)
+/**
+ * Determine if a store event notification should be completed.
+ * @param aEvent	The store event.
+ * @param aIndex	The index related to the store event.
+ */
+	{
+	if(iEvOutstandingReq)
+		{
+		TUint event=0;
+		switch(aEvent)
+			{
+		case EStoreEventNoEvent:
+			return;
+		
+		case EStoreEventAdded:
+			event|=RMobilePhoneStore::KStoreEntryAdded;
+			break;
+
+		case EStoreEventDeleted:
+			event|=RMobilePhoneStore::KStoreEntryDeleted;
+			break;
+
+		case EStoreEventChanged:
+			event|=RMobilePhoneStore::KStoreEntryChanged;
+			break;
+			}
+
+		if(UsedEntries()==0)
+			event|=RMobilePhoneStore::KStoreEmpty;
+
+		if(UsedEntries()==iSmsMaxNumSlots)
+			event|=RMobilePhoneStore::KStoreFull;
+		else
+			event|=RMobilePhoneStore::KStoreHasSpace;
+
+		*iEvEvent=event;
+		*iEvIndex=aIndex;
+		iEvOutstandingReq=EFalse;
+		ReqCompleted(iEvReqHandle,KErrNone);
+		}
+	}
+
+const CTestConfigSection* CSimSmsStore::CfgFileSection()
+/**
+* Returns a pointer to the config file section
+*
+* @return CTestConfigSection a pointer to the configuration file data section
+*/
+	{
+	LOGSMS1(">>CSimSmsStore::CfgFileSection");
+	return iSmsMessaging->CfgFileSection();
+	}
+