diff -r 000000000000 -r 3553901f7fa8 telephonyserverplugins/simtsy/src/CSimSmsStore.cpp --- /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 +#include +#include +#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(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 = , , , " + */ + { + LOGSMS1("Starting reading SMS Store entries..."); + TInt count=CfgFileSection()->ItemCount(KSmsStoreEntry); + const CTestConfigItem* item=NULL; + TInt ret=KErrNone; + + for(TInt i=0;iItem(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* intPckg=(TPckg*)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(RMobilePhoneStore::KCapsWholeStore) && iSmsStoreCaps & RMobilePhoneStore::KCapsReadAccess)) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + + TPckg* clientIdPckg=(TPckg*) aPckg1; + CRetrieveMobilePhoneSmsList::TBatchRequestData& clientId=(*clientIdPckg)(); + TPckg* sizePckg=(TPckg*)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* clientIdPckg=(TPckg*) aPckg1; + RMobilePhone::TClientId& clientId=(*clientIdPckg)(); + + for (TInt i=0; iCount(); ++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(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* eventPckg=(TPckg*)aPckg1; + TUint32& event=(*eventPckg)(); + TPckg* indexPckg=(TPckg*)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(); + } +