diff -r 000000000000 -r 3553901f7fa8 telephonyserverplugins/simtsy/src/CSimPhBkStore.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/telephonyserverplugins/simtsy/src/CSimPhBkStore.cpp Tue Feb 02 01:41:59 2010 +0200 @@ -0,0 +1,1295 @@ +// 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: +// Implements the Phonebook Store manipulation code. +// +// + +/** + @file +*/ + +#include "CSimPhBkStore.h" +#include "CSimPhone.h" +#include "Simlog.h" +#include + +const TUint16 KNpiTonInternational=145; // < The Number Plan Identifier and Type of Number for an international telephone number. +const TUint16 KNpiTonNational=129; // < The Number Plan Identifier and Type of Number for a national telephone number. +const TInt KPhonebookErrorGranularity=3; // < Granularity of phonebook error list array. +// +// CSimPhBkStore +// +void CSimPhBkStore::ClosePhone(TAny* aObj) +/** + * A utility function for cleaning up the stack. + */ + { + ((CObject*)aObj)->Close(); + } + +CSimPhBkStore* CSimPhBkStore::NewL(CSimPhone* aPhone, const TDesC8& aName, TInt aMaxNumSlots, TInt aMaxNumLen, TInt aMaxTextLen) +/** + * Standard two phase constructor. + * @param aPhone The phone object from which this Phonebook was opened. + * @param aName The name of the created Phonebook. + * @param aMaxNumSlots The maximum number of slots in the Phonebook. + * @return CSimPhBkStore* The newly created object. + */ + { + CSimPhBkStore* store=new(ELeave) CSimPhBkStore(aPhone); + TCleanupItem newObjClose(ClosePhone,store); + CleanupStack::PushL(newObjClose); + store->ConstructL(aName,aMaxNumSlots,aMaxNumLen,aMaxTextLen); + CleanupStack::Pop(); + return store; + } + +CSimPhBkStore::CSimPhBkStore(CSimPhone* aPhone) + : CSimPhone(iDummyPhoneBaseRef), iPhone(aPhone),iIpcCnt(0),iEvOutstandingReq(EFalse) +/** + * Trivial first phase constructor. + * @param aPhone The phone object from which this phonebook was opened. + */ + {} + +void CSimPhBkStore::ConstructL(const TDesC8& aName, TInt aMaxNumSlots, TInt aMaxNumLen, TInt aMaxTextLen) +/** + * Second phase constructor that allocates memory for the phonebook, 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 phonebook. + * @param aMaxNumLen The maximum length of a telephone number. + * @param aMaxTextLen The maximum length of an alpha tag. + */ + { + LOGPHBK1("Starting to parse Phonebook store additional config parameters..."); + __ASSERT_ALWAYS(aMaxNumLen<=KPhBkMaxTelNumSize,SimPanic(EPhonebookNameOrNumberTooLarge)); + __ASSERT_ALWAYS(aMaxTextLen<=KPhBkMaxAlphaTagSize,SimPanic(EPhonebookNameOrNumberTooLarge)); + + iPhBkStoreEntries=new(ELeave) TPhBkStoreEntry[aMaxNumSlots+1]; //slot 0 is unused + iPhBkMaxNumSlots=aMaxNumSlots; + iPhBkMaxTelNumLen=aMaxNumLen; + iPhBkMaxTextLen=aMaxTextLen; + iPhBkStoreName.Copy(aName); + + iReqTimer=CSimTimer::NewL(iPhone); + iOOBWriteTimer=CSimTimer::NewL(iPhone); + iOOBDeleteTimer=CSimTimer::NewL(iPhone); + iPhBkRwBuffer=new(ELeave) CPhoneBookBuffer(); + iPhBkError=new(ELeave) CArrayFixFlat(KPhonebookErrorGranularity); + + const CTestConfigItem* item=NULL; + TInt ret=KErrNone; + item=CfgFile()->Item(KTriggerEventIPC,0); + if(item) + { + TInt ipc, cnt, event; + + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,ipc); + if(ret!=KErrNone) + { + LOGPARSERR("ipc",ret,0,&KTriggerEventIPC); + } + else + iTriggerEventIPC.iIPC=ipc; + + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,cnt); + if(ret!=KErrNone) + { + LOGPARSERR("cnt",ret,1,&KTriggerEventIPC); + } + else + iTriggerEventIPC.iIPCCnt=cnt; + + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,event); + if(ret!=KErrNone) + { + LOGPARSERR("event",ret,2,&KTriggerEventIPC); + } + else + iTriggerEventIPC.iEvent=RMobilePhone::TMobilePhoneSecurityEvent(event); + + + } + + const CTestConfigItem* item0=NULL; + item0=CfgFile()->Item(KPhBkPhoneStoreCaps,0); + if (item0) + { + TPtrC8 value0; + TInt ret0=CTestConfig::GetElement(item0->Value(),KStdDelimiter,0,value0); + if(ret0!=KErrNone) + { + iPhBkStoreCaps=KDefaultPhBkPhoneStoreCaps; + LOGPARSERR("value0",ret0,0,&KPhBkPhoneStoreCaps); + } + else + { + TUint32 intValue; + TInt ret = AsciiToNum(value0, intValue); + if(ret!=KErrNone) + iPhBkStoreCaps=KDefaultPhBkPhoneStoreCaps; + else + iPhBkStoreCaps = intValue; + } + } + else + iPhBkStoreCaps=KDefaultPhBkPhoneStoreCaps; + + + LOGPHBK1("...Finished parsing Phonebook store additional config parameters..."); + } + +void CSimPhBkStore::PopulateStoreFromConfigFileL() +/** + * Populate the Phonebook Store from information in the configuration file. This is performed + * after the standard Phonebook Store construction in order to prevent reseting the configuation + * file accessor class' pointers while possibly multiple Phonebook Stores are created. + * + * The store entries comply to the following format: + * "PhBkStoreEntry = , , , " + */ + { + LOGPHBK1("Starting to read Phonebook store entries..."); + iPhBkIndividualPause=CfgFile()->ItemValue(KPhBkStoreIndividualReqPause,KDefaultPhBkStoreIndividualReqPause); + iPhBkBatchPause=CfgFile()->ItemValue(KPhBkStoreBatchReqPause,KDefaultPhBkStoreBatchReqPause); + + TInt count=CfgFile()->ItemCount(KPhBkStoreEntry); + const CTestConfigItem* item=NULL; + TInt ret=KErrNone; + + TInt i; + for(i=0;iItem(KPhBkStoreEntry,i); + if(!item) + break; + + TPtrC8 phonebookName,alphaTag,telNum; + TInt index; + TUint8 npiTon; + ret=GetPhBkEntry(item,0,phonebookName,index,telNum,alphaTag,npiTon); + if(ret!=KErrNone) + { + LOGPARSERR("Phonebook Entry",ret,index,&KPhBkStoreEntry); + continue; + } + if(phonebookName.MatchF(iPhBkStoreName)!=0)// Not this phonebook + continue; + + iPhBkStoreEntries[index].iAlphaTag.Copy(alphaTag); + iPhBkStoreEntries[index].iTelNum.Copy(telNum); + iPhBkStoreEntries[index].iTonNpi=npiTon; + } + + count=CfgFile()->ItemCount(KPhBkError); + item=NULL; + + for(i=0;iItem(KPhBkError,i); + if(!item) + break; + + TInt count,error; + TPtrC8 phonebookName, phonebookStore; + + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,count); + if(ret!=KErrNone) + { + LOGPARSERR("count",ret,0,&KPhBkError); + continue; + } + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,error); + if(ret!=KErrNone) + { + LOGPARSERR("error",ret,1,&KPhBkError); + continue; + } + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,phonebookName); + if(ret!=KErrNone) + { + LOGPARSERR("phonebookName",ret,2,&KPhBkError); + continue; + } + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,phonebookStore); + if(ret!=KErrNone) + { + LOGPARSERR("phonebookStore",ret,3,&KPhBkError); + } + else //not for the global phonebook + continue; + + if(phonebookName.MatchF(iPhBkStoreName)!=0)// Not this phonebook + continue; + + + TPhBkError entry; + entry.iCount=count; + entry.iError=error; + iPhBkError->AppendL(entry); + } + PopulateOOBWrite(); + PopulateOOBDelete(); + LOGPHBK1("...Finished reading Phonebook store entries..."); + + if(iPhBkOOBWriteDuration!=-1) + iOOBWriteTimer->Start(iPhBkOOBWriteDuration,this,ETimerIdPhBkStorOOBWrite); + if(iPhBkOOBDeleteDuration!=-1) + iOOBDeleteTimer->Start(iPhBkOOBDeleteDuration,this,ETimerIdPhBkStorOOBDelete); + } + +void CSimPhBkStore::PopulateOOBWrite() +/** + * Populate the member variables required to operate the OOB Store functionality from + * the configuration file. + * The OOBPhBkStore configuration file tag should have the following format: + * "OOBPhBkStore= , , , , " + */ + { + iPhBkOOBWriteDuration=KErrNotFound; + const CTestConfigItem* item=CfgFile()->Item(KOOBPhBkWrite); + if(!item) + return; + + TInt count; + TInt ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,count); + if(ret!=KErrNone) + { + LOGPARSERR("count",ret,0,&KOOBPhBkWrite); + return; + } + + TPtrC8 phonebookName,alphaTag,telNum; + TInt index; + TUint8 npiTon; + ret=GetPhBkEntry(item,1,phonebookName,index,telNum,alphaTag,npiTon); + if(ret!=KErrNone) + { + LOGPARSERR("npiTon",ret,index,&KOOBPhBkWrite); + return; + } + if(phonebookName.MatchF(iPhBkStoreName)!=0) + return; // Not this phonebook + + iPhBkOOBWriteDuration=count; + iPhBkOOBWriteIndex=index; + iPhBkOOBWrite.iAlphaTag.Copy(alphaTag); + iPhBkOOBWrite.iTelNum.Copy(telNum); + iPhBkOOBWrite.iTonNpi=npiTon; + } + +void CSimPhBkStore::PopulateOOBDelete() +/** + * Populate the member variables required to operate the OOB Delete functionality from + * the configuration file. + * The OOBPhBkDelete configuration file tag should have the following format: + * "OOBPhBkDelete= , , + */ + { + iPhBkOOBDeleteDuration=KErrNotFound; + const CTestConfigItem* item=CfgFile()->Item(KOOBPhBkDelete); + if(!item) + return; + + TInt count; + TInt ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,count); + if(ret!=KErrNone) + { + LOGPARSERR("count",ret,0,&KOOBPhBkDelete); + return; + } + + TPtrC8 phonebookName; + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,phonebookName); + if(ret!=KErrNone) + { + LOGPARSERR("phonebookName",ret,1,&KOOBPhBkDelete); + return; + } + if(phonebookName.MatchF(iPhBkStoreName)!=0) + return; // Not this phonebook + + TInt index; + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,index); + if(ret!=KErrNone) + { + LOGPARSERR("index",ret,2,&KOOBPhBkDelete); + return; + } + + iPhBkOOBDeleteDuration=count; + iPhBkOOBDeleteIndex=index; + } + +TInt CSimPhBkStore::GetPhBkEntry(const CTestConfigItem* aItem, TInt aItemIndex, + TPtrC8& aPhonebookName, TInt& aIndex, + TPtrC8& aTelNum, TPtrC8& aAlphaTag, TUint8& aNpiTon) +/** + * Retrieve a phonebook entry from the configuration file, starting at a given item index + * value. + * @param aItem Pointer to the config file item from which the phonebook entry will be read. + * @param aItemIndex The index number within the item from which the phonebook entry will be read. + * @param aPhonebookName The returned phonebook name + * @param aIndex The returned index number + * @param aTelNum The returned telephone number + * @param aAlphaTag The returned alpha tag + * @param aNpiTon The returned Number Plan Identifier and Type of Number information + * @return TInt Standard error value. + */ + { + TInt ret; + ret=CTestConfig::GetElement(aItem->Value(),KStdDelimiter,aItemIndex++,aPhonebookName); + if(ret!=KErrNone) + return ret; + + ret=CTestConfig::GetElement(aItem->Value(),KStdDelimiter,aItemIndex++,aIndex); + if(ret!=KErrNone) + return ret; + + if(aIndex>iPhBkMaxNumSlots) //the max number of slot is a valid slot + return KErrArgument; + + ret=CTestConfig::GetElement(aItem->Value(),KStdDelimiter,aItemIndex++,aTelNum); + if(ret!=KErrNone) + return ret; + if(aTelNum.Length()>iPhBkMaxTelNumLen) + return KErrArgument; + + ret=CTestConfig::GetElement(aItem->Value(),KStdDelimiter,aItemIndex++,aAlphaTag); + if(ret!=KErrNone) + return ret; + if(aAlphaTag.Length()>iPhBkMaxTextLen) + return KErrArgument; + + if((aTelNum.Length()>0) && (aTelNum[0]=='+')) + { + aTelNum.Set(aTelNum.Mid(1)); + aNpiTon=KNpiTonInternational; + } + else + aNpiTon=KNpiTonNational; + return ret; + } + +CSimPhBkStore::~CSimPhBkStore() +/** + * Standard destructor. Any objects created by the ::ConstructL() function + * will be destroyed here. + */ + { + delete[] iPhBkStoreEntries; + delete iPhBkError; + delete iPhBkRwBuffer; + delete iOOBWriteTimer; + delete iOOBDeleteTimer; + delete iReqTimer; + } + +TInt CSimPhBkStore::ExtFunc(const TTsyReqHandle aReqHandle,const TInt aIpc, const TDataPackage& aPckg) +/** + * Dispatch function for all Phonebook 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. + */ + { + iIpcCnt++; + TInt error=KErrNone; + if(FindIpcErrorMatch(error)) + { + ReqCompleted(aReqHandle,error); + return KErrNone; + } + +// The following requests can be completed even if the completion of another request is pending. + switch(aIpc) + { + case EMobilePhoneStoreGetInfo: + error = GetInfo(aReqHandle,aPckg.Des1n()); + if(iTriggerEventIPC.iIPC==aIpc) + { + iTriggerCnt++; + if(iTriggerEventIPC.iIPCCnt==iTriggerCnt) + iPhone->SecurityEvent(iTriggerEventIPC.iEvent); + } + return error; + + case EMobilePhoneStoreNotifyStoreEvent: + error = NotifyStoreEvent(aReqHandle,aPckg.Des1n(),aPckg.Des2n()); + if(iTriggerEventIPC.iIPC==aIpc) + { + iTriggerCnt++; + if(iTriggerEventIPC.iIPCCnt==iTriggerCnt) + iPhone->SecurityEvent(iTriggerEventIPC.iEvent); + } + return error; + + 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(iReqTimer->IsActive()) + { + ReqCompleted(aReqHandle,KErrInUse); + return KErrNone; + } + + switch(aIpc) + { +// The standard multimode store read and write are not supported. + case EMobilePhoneStoreRead: + case EMobilePhoneStoreWrite: + case EMobilePhoneStoreReadAllPhase1: + case EMobilePhoneStoreReadAllPhase2: + ReqCompleted(aReqHandle,KErrNotSupported); + return KErrNone; + + case EMobilePhoneBookStoreRead: + error = Read(aReqHandle,aPckg.Des1n(),aPckg.Des2n()); + if(iTriggerEventIPC.iIPC==aIpc) + { + iTriggerCnt++; + if(iTriggerEventIPC.iIPCCnt==iTriggerCnt) + iPhone->SecurityEvent(iTriggerEventIPC.iEvent); + } + return error; + + case EMobilePhoneBookStoreWrite: + error = Write(aReqHandle,aPckg.Des1n(),aPckg.Des2n()); + if(iTriggerEventIPC.iIPC==aIpc) + { + iTriggerCnt++; + if(iTriggerEventIPC.iIPCCnt==iTriggerCnt) + iPhone->SecurityEvent(iTriggerEventIPC.iEvent); + } + return error; + + case EMobilePhoneStoreDelete: + error = Delete(aReqHandle,aPckg.Des1n()); + if(iTriggerEventIPC.iIPC==aIpc) + { + iTriggerCnt++; + if(iTriggerEventIPC.iIPCCnt==iTriggerCnt) + iPhone->SecurityEvent(iTriggerEventIPC.iEvent); + } + return error; + + case EMobilePhoneStoreDeleteAll: + error = DeleteAll(aReqHandle); + if(iTriggerEventIPC.iIPC==aIpc) + { + iTriggerCnt++; + if(iTriggerEventIPC.iIPCCnt==iTriggerCnt) + iPhone->SecurityEvent(iTriggerEventIPC.iEvent); + } + return error; + + default: + break; + } + + return KErrNotSupported; + } + +CTelObject* CSimPhBkStore::OpenNewObjectByNameL(const TDesC& /*aName*/) +/** + * The API does not support any objects that could be opened from this one. + */ + { + User::Leave(KErrNotSupported); + return NULL; + } + +CTelObject* CSimPhBkStore::OpenNewObjectL(TDes&) +/** + * The API does not support any objects that could be opened from this one. + */ + { + User::Leave(KErrNotSupported); + return NULL; + } + +CTelObject::TReqMode CSimPhBkStore::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 EMobilePhoneStoreDelete: + case EMobilePhoneStoreDeleteAll: + case EMobilePhoneBookStoreRead: + case EMobilePhoneBookStoreWrite: + break; + + case EMobilePhoneStoreNotifyStoreEvent: + ret=KReqModeMultipleCompletionEnabled | KReqModeRePostImmediately; + break; + + default: + User::Leave(KErrNotSupported); + break; + } + + return ret; + } + +TInt CSimPhBkStore::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 CSimPhBkStore::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 CSimPhBkStore::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 CSimPhBkStore::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 EMobilePhoneStoreDelete: + case EMobilePhoneStoreDeleteAll: + case EMobilePhoneBookStoreRead: + case EMobilePhoneBookStoreWrite: + break; + + case EMobilePhoneStoreNotifyStoreEvent: + NotifyStoreEventCancel(); + break; + + default: + break; + } + return KErrNone; + } + +void CSimPhBkStore::Init() +/** + * This function can be used to perform any necessary synchronous initialisation. + */ + { + } + +TInt CSimPhBkStore::GetInfo(TTsyReqHandle aReqHandle, TDes8* aPckg) +/** + * Retrieve Phonebook 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. + */ + { + + if(iPhone->IsICCLocked()!=EFalse) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + RMobilePhoneBookStore::TMobilePhoneBookInfoV1Pckg* getInfoPckg=(RMobilePhoneBookStore::TMobilePhoneBookInfoV1Pckg*)aPckg; + RMobilePhoneBookStore::TMobilePhoneBookInfoV1& getInfo=(*getInfoPckg)(); + + PopulatePhBkStoreInfo(&getInfo); + + if(&getInfo!=NULL) // This will be the case if the version checking within PopulatePhBkStoreInfo has failed. + { + ReqCompleted(aReqHandle,KErrNone); + } + else + { + ReqCompleted(aReqHandle,KErrNotSupported); + } + + return KErrNone; + } + +void CSimPhBkStore::PopulatePhBkStoreInfo(RMobilePhoneStore::TMobilePhoneStoreInfoV1* aStoreInfo) +/** + * Populate the passed parameter with Phonebook Store information. + * @param aStoreInfo Pointer to phonebook store information structure to be populated. + */ + { + __ASSERT_ALWAYS(aStoreInfo, SimPanic(EIllegalNullPtrParameter)); + + aStoreInfo->iType=RMobilePhoneStore::EPhoneBookStore; + aStoreInfo->iTotalEntries=MaxSlots(); + aStoreInfo->iCaps=iPhBkStoreCaps; + aStoreInfo->iName.Copy(iPhBkStoreName); + aStoreInfo->iUsedEntries=UsedEntries(); + + if(aStoreInfo->ExtensionId()==RMobilePhoneStore::KETelMobilePhonebookStoreV1) + { + RMobilePhoneBookStore::TMobilePhoneBookInfoV1* getExtraInfo=(RMobilePhoneBookStore::TMobilePhoneBookInfoV1*)aStoreInfo; + + // Check that the data structure is supported by the simulated TSY version + TInt err = iPhone->CheckSimTsyVersion(*getExtraInfo); + if(err != KErrNone) + { + getExtraInfo = NULL; + return; + } + + getExtraInfo->iMaxNumLength=iPhBkMaxTelNumLen; + getExtraInfo->iMaxTextLength=iPhBkMaxTextLen; + getExtraInfo->iLocation=RMobilePhoneBookStore::ELocationIccMemory; + getExtraInfo->iChangeCounter=0; + getExtraInfo->iIdentity.Copy(iPhone->GetImsi()); + } + else if(aStoreInfo->ExtensionId()==RMobilePhoneStore::KETelMobilePhonebookStoreV2) + { + RMobilePhoneBookStore::TMobilePhoneBookInfoV2* getExtraInfo=(RMobilePhoneBookStore::TMobilePhoneBookInfoV2*)aStoreInfo; + + // Check that the data structure is supported by the simulated TSY version + TInt err = iPhone->CheckSimTsyVersion(*getExtraInfo); + if(err != KErrNone) + { + getExtraInfo = NULL; + return; + } + + getExtraInfo->iMaxNumLength=iPhBkMaxTelNumLen; + getExtraInfo->iMaxTextLength=iPhBkMaxTextLen; + getExtraInfo->iLocation=RMobilePhoneBookStore::ELocationIccMemory; + getExtraInfo->iChangeCounter=0; + getExtraInfo->iIdentity.Copy(iPhone->GetImsi()); + + getExtraInfo->iPhBkMode.Zero(); + } + else if(aStoreInfo->ExtensionId()==RMobilePhoneStore::KETelMobilePhonebookStoreV5) + { + RMobilePhoneBookStore::TMobilePhoneBookInfoV5* getExtraInfo=(RMobilePhoneBookStore::TMobilePhoneBookInfoV5*)aStoreInfo; + + // Check that the data structure is supported by the simulated TSY version + TInt err = iPhone->CheckSimTsyVersion(*getExtraInfo); + if(err != KErrNone) + { + getExtraInfo = NULL; + return; + } + + getExtraInfo->iMaxNumLength=iPhBkMaxTelNumLen; + getExtraInfo->iMaxTextLength=iPhBkMaxTextLen; + getExtraInfo->iLocation=RMobilePhoneBookStore::ELocationIccMemory; + getExtraInfo->iChangeCounter=0; + getExtraInfo->iIdentity.Copy(iPhone->GetImsi()); + + getExtraInfo->iPhBkMode.Zero(); + + getExtraInfo->iMaxSecondNames = 0; + getExtraInfo->iMaxTextLengthSecondName = 0; + getExtraInfo->iMaxAdditionalNumbers = 0; + getExtraInfo->iMaxTextLengthAdditionalNumber = 0; + getExtraInfo->iMaxNumLengthAdditionalNumber = 0; + getExtraInfo->iMaxGroupNames = 0; + getExtraInfo->iMaxTextLengthGroupName = 0; + getExtraInfo->iMaxEmailAddr = 0; + getExtraInfo->iMaxTextLengthEmailAddr = 0; + } + } + +TInt CSimPhBkStore::Read(TTsyReqHandle aReqHandle, TDes8* aPckg1,TDes8* aPckg2) +/** + * Read Phonebook store entries. 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 aPckg1 The first parameter package associated with this request. + * It contains the index from which the read should start and + * the number of entries which should be read. + * @param aPckg2 The second parameter package associated with this request. + * It contains the buffer, which will be populated with the retrieved + * values. + * @return TInt Standard return value. + */ + { + if(iPhone->IsICCLocked()!=EFalse) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + TPckg* indexNumPckg=(TPckg*)aPckg1; + RMobilePhoneBookStore::TPBIndexAndNumEntries& indexNum=(*indexNumPckg)(); + + if(indexNum.iNumSlots==iPhBkMaxNumSlots) + { + if (!(iPhBkStoreCaps & static_cast(RMobilePhoneStore::KCapsWholeStore) && iPhBkStoreCaps & RMobilePhoneStore::KCapsReadAccess)) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + } + else if((indexNum.iIndex+indexNum.iNumSlots - 1)>iPhBkMaxNumSlots) + { + ReqCompleted(aReqHandle,KErrArgument); + return KErrNone; + } + + else if (!(iPhBkStoreCaps & RMobilePhoneStore::KCapsIndividualEntry && iPhBkStoreCaps & RMobilePhoneStore::KCapsReadAccess)) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + iPhBkRwBuffer->Set(aPckg2); + + TInt cnt=0; + TInt ret=0; + TBool partial=EFalse; + for(TInt i=indexNum.iIndex;i<=iPhBkMaxNumSlots;i++) + { + if((iPhBkStoreEntries[i].iTelNum.Length()!=0)||(iPhBkStoreEntries[i].iAlphaTag.Length()!=0)) + { + ret=iPhBkRwBuffer->AddNewEntryTag(); + if(ret!=KErrNone) + break; + + partial=ETrue; + ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBAdnIndex,(TUint16)i); + if(ret!=KErrNone) + break; + ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBText,iPhBkStoreEntries[i].iAlphaTag); + if(ret!=KErrNone) + break; + ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBTonNpi,iPhBkStoreEntries[i].iTonNpi); + if(ret!=KErrNone) + break; + ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBNumber,iPhBkStoreEntries[i].iTelNum); + if(ret!=KErrNone) + break; + + partial=EFalse; + if(++cnt>=indexNum.iNumSlots) + break; + } + } + if(partial) + // EXPORT - but return value not relevant + (void)iPhBkRwBuffer->RemovePartialEntry(); + + indexNum.iNumSlots=cnt; + + if((cnt==0)&&(partial)) + ReqCompleted(aReqHandle,KErrArgument); // An entry was found, but the buffer was too small to return it. + else if((cnt==0)&&(!partial)) + ReqCompleted(aReqHandle,KErrNotFound); // No entries found. + else + ReqCompleted(aReqHandle,KErrNone); + + return KErrNone; + } + +TInt CSimPhBkStore::Write(TTsyReqHandle aReqHandle,TDes8* aPckg1,TDes8* aPckg2) +/** + * Write a phonebook store entries. 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 aPckg1 The first parameter package associated with this request. + * This contains the TLV phonebook entry to be written. + * @param aPckg2 The second parameter package associated with this request. + * This contains the slot index number to which the entry must be written. + */ + { + if(iPhone->IsICCLocked()!=EFalse) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + if (!(iPhBkStoreCaps & RMobilePhoneStore::KCapsIndividualEntry && iPhBkStoreCaps & RMobilePhoneStore::KCapsWriteAccess)) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + TPckg* indexPckg=(TPckg*)aPckg2; + TInt& index=(*indexPckg)(); + +// If the index is -1, then use the first available free slot. + if(index==-1) + { + for(TInt i=1;i<=iPhBkMaxNumSlots;i++) + { + if((iPhBkStoreEntries[i].iTelNum.Length()==0)&&(iPhBkStoreEntries[i].iAlphaTag.Length()==0)) + { + index=i; + break; + } + } + } + + if(index==-1) + { + ReqCompleted(aReqHandle,EXTENDEDERROR(KErrNoMemory, KErrPhonebookNoMemory)); + return KErrNone; + } + + if((index<1)||(index>iPhBkMaxNumSlots)) + { + ReqCompleted(aReqHandle,KErrArgument); + return KErrNone; + } + + TBool isSlotAlreadyUsed=EFalse; + if(iPhBkStoreEntries[index].iTelNum.Length()!=0) + isSlotAlreadyUsed=ETrue; + +// Unpick the phonebook entry. + iPhBkRwBuffer->Set(aPckg1); + iPhBkRwBuffer->StartRead(); + + TUint8 tagVal; + TUint8 npiTon=0; + TPtrC alphaTag; + TPtrC telNum; + TPtrC alphaTag2; + TBool skipToNextEntry=EFalse; + CPhoneBookBuffer::TPhBkTagType tagType; + TInt ret=KErrNone; + + while(ret==KErrNone) + { + ret=iPhBkRwBuffer->GetTagAndType(tagVal,tagType); + if(ret==KErrNotFound) + { + ret=KErrNone; + break; + } + else if(ret!=KErrNone) + break; + + + switch(tagVal) + { + case RMobilePhoneBookStore::ETagPBNewEntry: + skipToNextEntry=EFalse; + break; + + case RMobilePhoneBookStore::ETagPBText: + if(!skipToNextEntry) + ret=iPhBkRwBuffer->GetValue(alphaTag); + else + { + TPtrC throwAway; + ret=iPhBkRwBuffer->GetValue(throwAway); + } + break; + + case RMobilePhoneBookStore::ETagPBNumber: + if(!skipToNextEntry) + ret=iPhBkRwBuffer->GetValue(telNum); + else + { + TPtrC throwAway; + ret=iPhBkRwBuffer->GetValue(throwAway); + } + break; + + case RMobilePhoneBookStore::ETagPBTonNpi: + if(!skipToNextEntry) + ret=iPhBkRwBuffer->GetValue(npiTon); + else + { + TUint8 throwAway; + ret=iPhBkRwBuffer->GetValue(throwAway); + } + break; + + // Alexandros - phbksync "shortcut" should be discussed and removed + case RMobilePhoneBookStore::ETagPBAnrStart: + skipToNextEntry=ETrue; + break; + + case RMobilePhoneBookStore::ETagPBEmailAddress: + case RMobilePhoneBookStore::ETagPBGroupName: + case RMobilePhoneBookStore::ETagPBSecondName: + ret=iPhBkRwBuffer->GetValue(alphaTag2); + break; + case RMobilePhoneBookStore::ETagPBHiddenInfo: + TUint8 throwAway; + ret=iPhBkRwBuffer->GetValue(throwAway); + break; + + default: + //DEF001769 - SIM TSY should ignore extra fields in short entries + //ret=KErrNotSupported; + break; + } + } + + if(ret!=KErrNone) + { + ReqCompleted(aReqHandle,ret); + return KErrNone; + } + + LOGPHBK2("alphaTag Length = (%d)",alphaTag.Length()); + LOGPHBK2("Phonebook Max Text Length = (%d)",iPhBkMaxTextLen); + LOGPHBK2("TelNum Length = (%d)",telNum.Length()); + LOGPHBK2("TelNum Max Length = (%d)",iPhBkMaxTelNumLen); + + if(alphaTag.Length()>iPhBkMaxTextLen) + { + ReqCompleted(aReqHandle, EXTENDEDERROR(KErrOverflow, KErrPhonebookTextOverflow)); + return KErrNone; + } + else if(telNum.Length()>iPhBkMaxTelNumLen) + { + ReqCompleted(aReqHandle, EXTENDEDERROR(KErrOverflow, KErrPhonebookNumberOverflow)); + return KErrNone; + } + + iPhBkStoreEntries[index].iAlphaTag.Copy(alphaTag); + iPhBkStoreEntries[index].iTelNum.Copy(telNum); + iPhBkStoreEntries[index].iTonNpi=npiTon; + if(isSlotAlreadyUsed) + DelayCompletion(iPhBkIndividualPause,aReqHandle,EStoreEventChanged,index); + else + DelayCompletion(iPhBkIndividualPause,aReqHandle,EStoreEventAdded,index); + return KErrNone; + } + +TInt CSimPhBkStore::Delete(TTsyReqHandle aReqHandle,TDes8* aPckg) +/** + * Delete a single Phonebook 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(iPhone->IsICCLocked()!=EFalse) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + if (!(iPhBkStoreCaps & RMobilePhoneStore::KCapsIndividualEntry && iPhBkStoreCaps & RMobilePhoneStore::KCapsWriteAccess)) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + + TPckg* intPckg=(TPckg*)aPckg; + TInt& index=(*intPckg)(); + + if((index<1)||(index>iPhBkMaxNumSlots)) + { + ReqCompleted(aReqHandle,KErrArgument); + return KErrNone; + } + + iPhBkStoreEntries[index].iTelNum.Zero(); + iPhBkStoreEntries[index].iAlphaTag.Zero(); + DelayCompletion(iPhBkIndividualPause,aReqHandle,EStoreEventDeleted,index); + return KErrNone; + } + +TInt CSimPhBkStore::DeleteAll(TTsyReqHandle aReqHandle) +/** + * Delete all entries in the Phonebook 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 Phonebook Store notification. + * + * @param aReqHandle The TSY request handle associated with this request. + * @return Standard return value. + */ + { + if(iPhone->IsICCLocked()!=EFalse) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + if (!(iPhBkStoreCaps & static_cast(RMobilePhoneStore::KCapsWholeStore) && iPhBkStoreCaps & RMobilePhoneStore::KCapsWriteAccess)) + { + ReqCompleted(aReqHandle, KErrAccessDenied); + return KErrNone; + } + + for(TInt i=1;i<=iPhBkMaxNumSlots;i++) + { + iPhBkStoreEntries[i].iTelNum.Zero(); + iPhBkStoreEntries[i].iAlphaTag.Zero(); + } + DelayCompletion(iPhBkBatchPause,aReqHandle,EStoreEventDeleted,-1); + return KErrNone; + } + +TInt CSimPhBkStore::NotifyStoreEvent(TTsyReqHandle aReqHandle,TDes8* aPckg1,TDes8* aPckg2) +/** + * Register a client's interest in Phonebook 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. + */ + { + 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 CSimPhBkStore::NotifyStoreEventCancel() +/** + * Cancel an outstanding notify store request. + */ + { + if(iEvOutstandingReq) + { + iEvOutstandingReq=EFalse; + ReqCompleted(iEvReqHandle,KErrCancel); + } + } + +TPtrC8 CSimPhBkStore::Name() +/** + * Accessor function fot the Phonebook Store name. + * + * @return TPtrC8 The name of this Phonebook Store. + */ + { + return iPhBkStoreName; + } + +TInt CSimPhBkStore::UsedEntries() +/** + * Count the number of used entries in the Phonebook Store. + * @return TInt The number of used entries in the store. + */ + { + TInt cnt=0; + for(TInt i=1;i<=iPhBkMaxNumSlots;i++) + { + if((iPhBkStoreEntries[i].iTelNum.Length()!=0)||(iPhBkStoreEntries[i].iAlphaTag.Length()!=0)) + cnt++; + } + return cnt; + } + +TInt CSimPhBkStore::MaxSlots() +/** + * Retrieve the maximum number of slots in this Phonebook Store. + * @return TInt The maximum number of slots in this Phonebook Store. + */ + { + return iPhBkMaxNumSlots; + } + +void CSimPhBkStore::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); + } + +void CSimPhBkStore::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; + iReqTimer->Start(aDelayDuration,this,ETimerIdPhBkStorReq); + } + +void CSimPhBkStore::TimerCallBack(TInt aId) +/** + * Process a timer call back event. There are three timers associated with this class + * and this callback will be used for all of them. The timers can be identified from the + * aId parameter passed with the callback. + * + * The "Request" timer is used to kick requests which have had their completions delayed. + * The "Out of Band Write" timer is used to schedule a non-client phonebook write. + * The "Out of Band Delete" timer is used to schedule a non-client phonebook delete. + * + * @param aId The Id of the timer to which this callback relates. + */ + { + switch(aId) + { + case ETimerIdPhBkStorReq: + StoreEvent(iPendingEvent,iPendingIndex); + ReqCompleted(iPendingReqCompletion,KErrNone); + break; + + case ETimerIdPhBkStorOOBWrite: + iPhBkStoreEntries[iPhBkOOBWriteIndex].iAlphaTag.Copy(iPhBkOOBWrite.iAlphaTag); + iPhBkStoreEntries[iPhBkOOBWriteIndex].iTelNum.Copy(iPhBkOOBWrite.iTelNum); + iPhBkStoreEntries[iPhBkOOBWriteIndex].iTonNpi=iPhBkOOBWrite.iTonNpi; + StoreEvent(EStoreEventAdded,iPhBkOOBWriteIndex); + break; + + case ETimerIdPhBkStorOOBDelete: + iPhBkStoreEntries[iPhBkOOBDeleteIndex].iAlphaTag.Zero(); + iPhBkStoreEntries[iPhBkOOBDeleteIndex].iTelNum.Zero(); + iPhBkStoreEntries[iPhBkOOBDeleteIndex].iTonNpi=0; + StoreEvent(EStoreEventDeleted,iPhBkOOBDeleteIndex); + break; + + default: + break; + } + } + +void CSimPhBkStore::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; + + default: + break; + } + + TInt cnt=UsedEntries(); + if(cnt==0) + event|=RMobilePhoneStore::KStoreEmpty; + + if(cnt==iPhBkMaxNumSlots) + event|=RMobilePhoneStore::KStoreFull; + else + event|=RMobilePhoneStore::KStoreHasSpace; + + *iEvEvent=event; + *iEvIndex=aIndex; + iEvOutstandingReq=EFalse; + ReqCompleted(iEvReqHandle,KErrNone); + } + } + +TBool CSimPhBkStore::FindIpcErrorMatch(TInt& aError) +/** + * Determine whether the IPC counter has signalled that the current request should + * be errored, rather than executed. + * + * @param aError If the function returns ETrue, this parameter will pass back the + * number of the error to be propagated. + * @return TBool Returns ETrue if a match with the IPC count is found, EFalse if not. + */ + { + TInt i; + for(i=0;iCount();i++) + { + TInt pi=iPhBkError->At(i).iCount; + if(pi==iIpcCnt) + { + aError=iPhBkError->At(i).iError; + return ETrue; + } + } + return EFalse; + } + +const CTestConfigSection* CSimPhBkStore::CfgFile() +/** +* Returns a pointer to the config file section +* +* @return CTestConfigSection a pointer to the configuration file data section +*/ + { + LOGPHBK1(">>CSimPhBkStore::CfgFile"); + return iPhone->CfgFile(); + }