telephonyserverplugins/simtsy/src/CSimPhBkUsimStore.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:40:21 +0100
branchRCL_3
changeset 20 07a122eea281
parent 19 630d2f34d719
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201035 Kit: 201035

// 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 "CSimPhBkUsimStore.h"
#include "CSimPhone.h"
#include "Simlog.h"
#include <testconfigfileparser.h>

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 KMaxGroups = 10;					// < The maximum allowed number of groups associated with a phonebook entry
const TInt KMaxSecondNames = 1;				// < The maximum allowed number of Second Names associated with a phonebook entry
const TInt KPhonebookErrorGranularity=3;	// < Granularity of phonebook error list array.
const TUint DELETED=0xdededede; 
//
// CSimPhBkUSimStore
//
void CSimPhBkUSimStore::ClosePhone(TAny* aObj)
/**
 * A utility function for cleaning up the stack.
 */
	{
	((CObject*)aObj)->Close();
	}

CSimPhBkUSimStore* CSimPhBkUSimStore::NewL(CSimPhone* aPhone, const TDesC8& aStore, const TDesC8& aName, TInt aMaxNumSlots, TInt aMaxNumLen, TInt aMaxTextLen, TInt aAdditional, TInt aMaxEmail, TInt aMaxAdditionalTelNumLen, TInt aMaxAdditionalTextLen)
/**
 * 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.
 * @param aMaxNumLen		The maximum length of the telephone number (<100)
 * @param aMaxTextLen		The maximum length of the alpha text strings (<100)
 * @param aAdditional		The maximum number of additional numbers associated with an entry
 * @param aMaxEmail			The maximum number of email addresses associated with an entry
 * @param aMaxAdditionalTelNumLen	The maximum length of the an additional telephone number.
 * @param aMaxAdditionalTextLen		The maximum length of the alpha tag in an additional telephone number.
 * @return CSimPhBkUSimStore*			The newly created object.
 */
	{
	CSimPhBkUSimStore* store=new(ELeave) CSimPhBkUSimStore(aPhone);
	TCleanupItem newObjClose(ClosePhone,store);
	CleanupStack::PushL(newObjClose);
	store->ConstructL(aStore,aName,aMaxNumSlots,aMaxNumLen,aMaxTextLen,aAdditional,aMaxEmail, aMaxAdditionalTelNumLen, aMaxAdditionalTextLen);	
	CleanupStack::Pop();
	return store;
	}

CSimPhBkUSimStore::CSimPhBkUSimStore(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 CSimPhBkUSimStore::ConstructL(const TDesC8& aStore, const TDesC8& aName, TInt aMaxNumSlots, TInt aMaxNumLen, TInt aMaxTextLen, TInt aAdditional, TInt aMaxEmail, TInt aMaxAdditionalTelNumLen, TInt aMaxAdditionalTextLen)
/**
 * 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.
 * @param aMaxNumLen	The maximum length of the telephone number (<100).
 * @param aMaxTextLen	The maximum length of the alpha text strings (<100).
 * @param aAdditional	The maximum number of additional numbers associated with an entry.
 * @param aMaxEmail		The maximum number of email addresses associated with an entry.
 * @param aMaxAdditionalTelNumLen	The maximum length of the an additional telephone number.
 * @param aMaxAdditionalTextLen		The maximum length of the alpha tag in an additional telephone number.
 */
	{
	LOGPHBK1("Starting to parse Phonebook store additional config parameters...");
	__ASSERT_ALWAYS(aMaxNumLen<=KPhBkMaxTelNumSize,SimPanic(EPhonebookNameOrNumberTooLarge));
	__ASSERT_ALWAYS(aMaxTextLen<=KPhBkMaxAlphaTagSize,SimPanic(EPhonebookNameOrNumberTooLarge));

	iPhBkMaxNumSlots=aMaxNumSlots;
	iPhBkMaxTelNumLen=aMaxNumLen;
	iPhBkMaxTextLen=aMaxTextLen;
	iPhBkStoreName.Copy(aName);
	iPhBkStore.Copy(aStore);
	iPhBkAdditional=aAdditional;
	iPhBkMaxEmail=aMaxEmail;
	iPhBkMaxAdditionalTelNumLen = aMaxAdditionalTelNumLen;
	iPhBkMaxAdditionalTextLen = aMaxAdditionalTextLen;	
	
	iPhBkAid.Zero();
	iPhBkAidUSim1.Zero();
	iPhBkAidUSim2.Zero();

	if(iPhBkStore.Compare(KUSimPhoneBook)==KErrNone)
		{
		iPhBkUSim1StoreEntries=new(ELeave) TPhBkUSimStoreEntry[aMaxNumSlots+1]; //slot 0 is unused
		iPhBkUSim2StoreEntries=new(ELeave) TPhBkUSimStoreEntry[aMaxNumSlots+1]; //slot 0 is unused
		}
	else
		{
		iPhBkUSim1StoreEntries=new(ELeave) TPhBkUSimStoreEntry[aMaxNumSlots+1]; //slot 0 is unused
		iPhBkUSimStoreEntries=iPhBkUSim1StoreEntries;
		}

	iReqTimer=CSimTimer::NewL(iPhone);
	iOOBWriteTimer=CSimTimer::NewL(iPhone);
	iOOBDeleteTimer=CSimTimer::NewL(iPhone);
	iPhBkRwBuffer=new(ELeave) CPhoneBookBuffer();
	iPhBkError=new(ELeave) CArrayFixFlat<TPhBkError>(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;
	TInt count=CfgFile()->ItemCount(KPhBkPhoneUSimStoreCaps);
	
	if(count==0)
		iPhBkStoreCaps=KDefaultPhBkPhoneStoreCaps;
	else
		{
		TBool capsFound=EFalse;
		for(TInt i=0;(i<count || !capsFound);i++)
		{
			item0=CfgFile()->Item(KPhBkPhoneUSimStoreCaps,i);
			
			if (item0)
				{
				TPtrC8 value0,phonebookStore, phonebookName;
				TInt ret0;

				ret0=CTestConfig::GetElement(item0->Value(),KStdDelimiter,0,phonebookStore);
				if(ret0!=KErrNone)
					{
					iPhBkStoreCaps=KDefaultPhBkPhoneStoreCaps;
					LOGPARSERR("Caps:PhonebookStore",ret,0,&KPhBkPhoneUSimStoreCaps);
					}	

				if(phonebookStore.MatchF(iPhBkStore)!=0)// Not this PhBkStore type
					continue;

				ret0=CTestConfig::GetElement(item0->Value(),KStdDelimiter,1,phonebookName);
				if(ret0!=KErrNone)
					{
					iPhBkStoreCaps=KDefaultPhBkPhoneStoreCaps;
					LOGPARSERR("phonebookName",ret,1,&KPhBkPhoneUSimStoreCaps);
					}	
				
				if(phonebookName.MatchF(iPhBkStoreName)!=0)// Not this PhBkStoreName type
					continue;
				
				ret0=CTestConfig::GetElement(item0->Value(),KStdDelimiter,2,value0);
				if(ret0!=KErrNone)
					{
					iPhBkStoreCaps=KDefaultPhBkPhoneStoreCaps;
					LOGPARSERR("caps",ret,2,&KPhBkPhoneUSimStoreCaps);
					}	
				else
					{
					TUint32 intValue;
					TInt ret = AsciiToNum(value0, intValue);
					if(ret!=KErrNone)
						iPhBkStoreCaps=KDefaultPhBkPhoneStoreCaps;
					else
						{
						iPhBkStoreCaps = intValue;
						capsFound=ETrue;
						}
					}
				
				}
			}
	}
	LOGPHBK1("...Finished parsing Phonebook store additional config parameters...");
	}

void CSimPhBkUSimStore::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.
//alex
 *
 * The store entries comply to the following format:
 * "PhBkStoreEntry = <store name>, <slot number>, <telephone number>, <alphatag>"
 */
	{
	LOGPHBK1("Starting to read Phonebook store entries...");
	iPhBkIndividualPause=CfgFile()->ItemValue(KPhBkStoreIndividualReqPause,KDefaultPhBkStoreIndividualReqPause);
	iPhBkBatchPause=CfgFile()->ItemValue(KPhBkStoreBatchReqPause,KDefaultPhBkStoreBatchReqPause);

	const CTestConfigItem* item=NULL;
	TInt ret=KErrNone;

	TInt i;

	// Get Phonebook entries
	TInt count=CfgFile()->ItemCount(KPhBkUSimStoreEntry);
	for(i=0;i<count;i++)
		{
		TInt parseIndex=0;

		item=CfgFile()->Item(KPhBkUSimStoreEntry,i);
		if(!item)
			break;

		TPtrC8 phonebookStore,aid, phonebookName,alphaTag,telNum,alphaTag2,emails, groups, additional;
		TInt index;
		TUint8 npiTon;
		ret=GetPhBkUSimEntry(item,parseIndex,phonebookStore,phonebookName,aid,index,telNum,alphaTag,npiTon,alphaTag2);
		if(ret!=KErrNone)
			{
			LOGPARSERR("Phonebook Entry",ret,index,&KPhBkUSimStoreEntry);
			continue;
			}

		if(phonebookStore.MatchF(iPhBkStore)!=0)// Not this PhBkStore type
			continue;
		else if(phonebookName.MatchF(iPhBkStoreName)!=0)// Not this phonebook
			continue;

		if(phonebookStore.MatchF(KUSimPhoneBook)==0 &&
			iPhBkAid.Length()==0) //starting up
			{
			iPhBkAid.Copy(aid);
			iPhBkAidUSim1.Copy(aid);
			iPhBkUSimStoreEntries=iPhBkUSim1StoreEntries;
			}

		else if(phonebookStore.MatchF(KUSimPhoneBook)==0 &&
			iPhBkAid.Length()!=0 && iPhBkAid.Compare(aid)!=KErrNone)
			{
			if(iPhBkAidUSim2.Length()==0)
				{
				iPhBkAid.Copy(aid);
				iPhBkAidUSim2.Copy(aid);
				iPhBkUSimStoreEntries=iPhBkUSim2StoreEntries;
				}
			else if(iPhBkAidUSim2.Compare(aid)==KErrNone)
				{
				iPhBkAid.Copy(aid);
				iPhBkUSimStoreEntries=iPhBkUSim2StoreEntries;	
				}
			else if(iPhBkAidUSim2.Compare(aid)!=KErrNone)
				//Currently there is support for only 2 USim phonebooks
				{continue;} //...so, a possible third one will be ignored!!!
			}

		iPhBkUSimStoreEntries[index].iAlphaTag.Copy(alphaTag);
		iPhBkUSimStoreEntries[index].iTelNum.Copy(telNum);
		iPhBkUSimStoreEntries[index].iTonNpi=npiTon;
		iPhBkUSimStoreEntries[index].iAlphaTag2.Copy(alphaTag2);
	
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,parseIndex++,additional);
		if(ret!=KErrNone)
			{
			LOGPARSERR("additional",ret,parseIndex,&KPhBkUSimStoreEntry);
			}
		else
			{	
			TPtrC8 myName,myNum;
			TUint8 myTon;
			TInt myindex=0,pIndex=0;
			iPhBkUSimStoreEntries[index].iAdditional=new(ELeave) CArrayFixFlat<TPhBkStoreEntry>(iPhBkAdditional+1);
	
			while((GetPhBkAdditionalEntry(additional,pIndex,myNum,myName,myTon)==KErrNone)
					&& (myindex < iPhBkAdditional))
				{
				TPhBkStoreEntry entry;
			
				entry.iAlphaTag.Copy(myName);
				entry.iTelNum.Copy(myNum);
				entry.iTonNpi=myTon;
				TRAP_IGNORE(iPhBkUSimStoreEntries[index].iAdditional->AppendL(entry));

				myindex++;
				}

			}
	
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,parseIndex++,emails);
		if(ret!=KErrNone)
			{
			LOGPARSERR("emails",ret,parseIndex,&KPhBkUSimStoreEntry);
			}
		else
		{	
			TPtrC8 myemail;
			TInt myindex=0;
			iPhBkUSimStoreEntries[index].iEmails=new(ELeave) CArrayFixFlat<TPhBkUSimEmail>(iPhBkMaxEmail+1);
			
			while((CTestConfig::GetElement(emails,';',myindex,myemail)==KErrNone) &&
					(myindex < iPhBkMaxEmail))
			{
			TPhBkUSimEmail entry;
			entry.Copy(myemail);
			TRAP_IGNORE(iPhBkUSimStoreEntries[index].iEmails->AppendL(entry));
			myindex++;
			}
		}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,parseIndex++,groups);
		if(ret!=KErrNone)
			{
			LOGPARSERR("groups",ret,parseIndex,&KPhBkUSimStoreEntry);
			}
		else
		{	

			TPtrC8 mygroup;
			TInt myindex=0;
			iPhBkUSimStoreEntries[index].iGroups=new(ELeave) CArrayFixFlat<TPhBkUSimGroup>(KMaxGroups+1);

		
			while((CTestConfig::GetElement(groups,';',myindex,mygroup)==KErrNone) &&
					(myindex < KMaxGroups))
			{
			TPhBkUSimGroup entry;
			entry.Copy(mygroup);
			TRAP_IGNORE(iPhBkUSimStoreEntries[index].iGroups->AppendL(entry));
			myindex++;
			}
		}

		TBool hidden;
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,parseIndex++,hidden);
		if(ret!=KErrNone)
			{
			LOGPARSERR("emails",ret,parseIndex,&KPhBkUSimStoreEntry);
			}
		else
			iPhBkUSimStoreEntries[index].iHiddenEntry=hidden;

		}

	count=CfgFile()->ItemCount(KPhBkError);
	item=NULL;

	for(i=0;i<count;i++)
		{
		item=CfgFile()->Item(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);
			//global phonebook error
			continue;
			}
		
		if(phonebookName.MatchF(iPhBkStoreName)!=0)// Not this phonebook
			continue;
		else if(phonebookStore.MatchF(iPhBkStore)!=0)// Not this phonebook
			continue;

		TPhBkError entry;
		entry.iCount=count;
		entry.iError=error;
		TRAP_IGNORE(iPhBkError->AppendL(entry));
		}
	PopulateOOBWrite();
	PopulateOOBDelete();
	LOGPHBK1("...Finished reading Phonebook store entries...");

	if(iPhBkOOBWriteDuration!=-1)
		iOOBWriteTimer->Start(iPhBkOOBWriteDuration,this,ETimerIdPhBkUSimStorOOBWrite);
	if(iPhBkOOBDeleteDuration!=-1)
		iOOBDeleteTimer->Start(iPhBkOOBDeleteDuration,this,ETimerIdPhBkUSimStorOOBDelete);
	}

void CSimPhBkUSimStore::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= <duration>, <phonebook name>, <index>, <telephone number>, <alpha tag>"
 */
	{
	TInt parseIndex=0;
	iPhBkOOBWriteDuration=KErrNotFound;
	const CTestConfigItem* item=CfgFile()->Item(KOOBPhBkUSimWrite);
	if(!item)
		return;

	TInt count;
	TInt ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,parseIndex++,count);
	if(ret!=KErrNone)
		{
		LOGPARSERR("count",ret,parseIndex,&KOOBPhBkUSimWrite);
		return;
		}

	TPtrC8 phonebookStore,aid, phonebookName,alphaTag,telNum,alphaTag2,emails, groups, additional;
	TInt index;
	TUint8 npiTon;
	ret=GetPhBkUSimEntry(item,parseIndex,phonebookStore,phonebookName,aid,index,telNum,alphaTag,npiTon,alphaTag2);
	if(ret!=KErrNone)
		{
		LOGPARSERR("Phonebook Entry",ret,parseIndex,&KOOBPhBkUSimWrite);
		return;
		}

	if(phonebookStore.MatchF(iPhBkStore)!=0)// Not this PhBkStore type
		return;
	else if(phonebookName.MatchF(iPhBkStoreName)!=0)// Not this phonebook
		return;

	iPhBkOOBWriteDuration=count;
	iPhBkOOBWriteIndex=index;
	iPhBkOOBWrite.iAlphaTag.Copy(alphaTag);
	iPhBkOOBWrite.iTelNum.Copy(telNum);
	iPhBkOOBWrite.iTonNpi=npiTon;
	iPhBkOOBWrite.iAlphaTag2.Copy(alphaTag2);

	ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,parseIndex++,additional);
	if(ret!=KErrNone)
		{
		LOGPARSERR("additional",ret,parseIndex,&KOOBPhBkUSimWrite);
		}
	else
	{	
		TPtrC8 myName,myNum;
		TUint8 myTon;
		TInt myindex=0,pIndex=0;
		
		TRAPD(err,iPhBkOOBWrite.iAdditional=new(ELeave) CArrayFixFlat<TPhBkStoreEntry>(iPhBkAdditional+1));
		if (err!=KErrNone)
			return;
		while((GetPhBkAdditionalEntry(additional,pIndex,myNum,myName,myTon)==KErrNone)
				&& (myindex < iPhBkAdditional))
		{
		TPhBkStoreEntry entry; 

		entry.iAlphaTag.Copy(myName);
		entry.iTelNum.Copy(myNum);
		entry.iTonNpi=myTon;
		TRAP_IGNORE(iPhBkOOBWrite.iAdditional->AppendL(entry));
		myindex++;
		}
	}

	ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,parseIndex++,groups);
	if(ret!=KErrNone)
		{
		LOGPARSERR("groups",ret,parseIndex,&KOOBPhBkUSimWrite);
		}
	else
	{	
		TPtrC8 mygroup;
		TInt myindex=0;
		
		TRAPD(err,iPhBkOOBWrite.iGroups=new(ELeave) CArrayFixFlat<TPhBkUSimGroup>(KMaxGroups+1));
		if (err!=KErrNone)
			return;
		while((CTestConfig::GetElement(groups,';',myindex,mygroup)==KErrNone) &&
				(myindex < KMaxGroups))
		{
		TPhBkUSimGroup entry;
		entry.Copy(mygroup);
		TRAP_IGNORE(iPhBkOOBWrite.iGroups->AppendL(entry));
		myindex++;
		}
	}

	ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,parseIndex++,emails);
	if(ret!=KErrNone)
		{
		LOGPARSERR("emails",ret,parseIndex,&KOOBPhBkUSimWrite);
		}
	else
	{	
		TPtrC8 myemail;
		TInt myindex=0;
		
		TRAPD(err,iPhBkOOBWrite.iEmails=new(ELeave) CArrayFixFlat<TPhBkUSimEmail>(iPhBkMaxEmail+1));
		if (err!=KErrNone)
			return;
	
		while((CTestConfig::GetElement(emails,';',myindex,myemail)==KErrNone) &&
				(myindex < iPhBkMaxEmail))
		{
		TPhBkUSimEmail entry;
		entry.Copy(myemail);
		TRAP_IGNORE(iPhBkOOBWrite.iEmails->AppendL(entry));
		myindex++;
		}
	}

	}

void CSimPhBkUSimStore::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= <duration>, <phonebook name>, <index>
 */
	{
	iPhBkOOBDeleteDuration=KErrNotFound;
	const CTestConfigItem* item=CfgFile()->Item(KOOBPhBkUSimDelete);
	if(!item)
		return;

	TInt count;
	TInt ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,count);
	if(ret!=KErrNone)
		{
		LOGPARSERR("count",ret,0,&KOOBPhBkUSimDelete);
		return;
		}

	TPtrC8 phonebookName, phonebookStore;
		
	ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,phonebookStore);
	if(ret!=KErrNone)
		{
		LOGPARSERR("phonebookStore",ret,1,&KOOBPhBkUSimDelete);
		return;
		}

	ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,phonebookName);
	if(ret!=KErrNone)
		{
		LOGPARSERR("phonebookName",ret,2,&KOOBPhBkUSimDelete);
		return;
		}

	if(phonebookStore.MatchF(iPhBkStore)!=0)
		return;						// Not this store
	else if(phonebookName.MatchF(iPhBkStoreName)!=0)// Not this phonebook
		return;

	TInt index;
	ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,index);
	if(ret!=KErrNone)
		{
		LOGPARSERR("index",ret,3,&KOOBPhBkUSimDelete);
		return;
		}

	iPhBkOOBDeleteDuration=count;
	iPhBkOOBDeleteIndex=index;
	}


TInt CSimPhBkUSimStore::GetPhBkUSimEntry(const CTestConfigItem* aItem, TInt& aItemIndex,
								 TPtrC8& aPhonebookStore, 
								 TPtrC8& aPhonebookName, 
								 TPtrC8& aAid,TInt& aIndex,
								 TPtrC8& aTelNum, TPtrC8& aAlphaTag, TUint8& aNpiTon,
								 TPtrC8& aAlphaTag2)
/**
 * 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++,aPhonebookStore);
	if(ret!=KErrNone)
		return ret;

	ret=CTestConfig::GetElement(aItem->Value(),KStdDelimiter,aItemIndex++,aPhonebookName);
	if(ret!=KErrNone)
		return ret;

	ret=CTestConfig::GetElement(aItem->Value(),KStdDelimiter,aItemIndex++,aAid);
	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 EXTENDEDERROR(KErrArgument, KErrPhonebookNumberOverflow);

	ret=CTestConfig::GetElement(aItem->Value(),KStdDelimiter,aItemIndex++,aAlphaTag);
	if(ret!=KErrNone)
		return ret;
	if(aAlphaTag.Length()>iPhBkMaxTextLen)
		return EXTENDEDERROR(KErrArgument, KErrPhonebookTextOverflow);

	if((aTelNum.Length()>0) && (aTelNum[0]=='+'))
		{
		aTelNum.Set(aTelNum.Mid(1));
		aNpiTon=KNpiTonInternational;
		}
	else
		aNpiTon=KNpiTonNational;

	ret=CTestConfig::GetElement(aItem->Value(),KStdDelimiter,aItemIndex++,aAlphaTag2);
	if(ret!=KErrNone)
		return ret;
	if(aAlphaTag.Length()>iPhBkMaxTextLen)
		return EXTENDEDERROR(KErrArgument, KErrPhonebookTextOverflow);

	return ret;
	}

TInt CSimPhBkUSimStore::GetPhBkAdditionalEntry(TPtrC8& aEntry, TInt& aItemIndex,
								 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 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(aEntry,';',aItemIndex++,aAlphaTag);
	if(ret!=KErrNone)
		return ret;
	
	if(aAlphaTag.Length()>iPhBkMaxAdditionalTextLen)
		return EXTENDEDERROR(KErrArgument, KErrPhonebookAdditionalNumberAlphaTextOverflow);

	ret=CTestConfig::GetElement(aEntry,';',aItemIndex++,aTelNum);
	if(ret!=KErrNone)
		return ret;
	if(aTelNum.Length()>iPhBkMaxAdditionalTelNumLen)
		return EXTENDEDERROR(KErrArgument, KErrPhonebookAdditionalNumberNumberOverflow);

		
	if((aTelNum.Length()>0) && (aTelNum[0]=='+'))
		{
		aTelNum.Set(aTelNum.Mid(1));
		aNpiTon=KNpiTonInternational;
		}
	else
		{
		aNpiTon=KNpiTonNational;
		}
		
	return ret;
	}

CSimPhBkUSimStore::~CSimPhBkUSimStore()
/**
 * Standard destructor.  Any objects created by the ::ConstructL() function
 * will be destroyed here.
 */
	{

	for(TInt i=1;i<=iPhBkMaxNumSlots;i++)
		{
			if(iPhBkUSim1StoreEntries[i].iTelNum.Length()>0 ||
				iPhBkUSim1StoreEntries[i].iAlphaTag.Length()>0)
			{
				iPhBkUSim1StoreEntries[i].iTelNum.Zero();
				if((iPhBkUSim1StoreEntries[i].iAdditional!=NULL)
					&& ((TUint)iPhBkUSim1StoreEntries[i].iAdditional!=DELETED))
				{
					if(iPhBkUSim1StoreEntries[i].iAdditional->Count()>=0)
					{
						iPhBkUSim1StoreEntries[i].iAdditional->Delete(0,iPhBkUSim1StoreEntries[i].iAdditional->Count());
						delete iPhBkUSim1StoreEntries[i].iAdditional;
					}
				}
				if((iPhBkUSim1StoreEntries[i].iGroups!=NULL)
					&& ((TUint)iPhBkUSim1StoreEntries[i].iGroups!=DELETED))
				{
					if(iPhBkUSim1StoreEntries[i].iGroups->Count()>=0)
					{
						iPhBkUSim1StoreEntries[i].iGroups->Delete(0,iPhBkUSim1StoreEntries[i].iGroups->Count());
						delete iPhBkUSim1StoreEntries[i].iGroups;
					}
				}
				if((iPhBkUSim1StoreEntries[i].iEmails!=NULL)	
					&& ((TUint)iPhBkUSim1StoreEntries[i].iEmails!=DELETED))
				{
					if(iPhBkUSim1StoreEntries[i].iEmails->Count()>=0)
					{
						iPhBkUSim1StoreEntries[i].iEmails->Delete(0,iPhBkUSim1StoreEntries[i].iEmails->Count());
						delete iPhBkUSim1StoreEntries[i].iEmails;
					}
				}
			}
		if(iPhBkUSim2StoreEntries!=NULL &&
			(iPhBkUSim2StoreEntries[i].iTelNum.Length()>0 ||
				iPhBkUSim2StoreEntries[i].iAlphaTag.Length()>0))
		{
			iPhBkUSim2StoreEntries[i].iTelNum.Zero();
			if((iPhBkUSim2StoreEntries[i].iAdditional!=NULL)	
				&& ((TUint)iPhBkUSim2StoreEntries[i].iAdditional!=DELETED))
			{
				if(iPhBkUSim2StoreEntries[i].iAdditional->Count()>=0)
				{
					iPhBkUSim2StoreEntries[i].iAdditional->Delete(0,iPhBkUSim2StoreEntries[i].iAdditional->Count());
					delete iPhBkUSim2StoreEntries[i].iAdditional;
				}
			}
			if((iPhBkUSim2StoreEntries[i].iGroups!=NULL)
				&& ((TUint)iPhBkUSim2StoreEntries[i].iGroups!=DELETED))
			{
				if(iPhBkUSim2StoreEntries[i].iGroups->Count()>=0)
				{
					iPhBkUSim2StoreEntries[i].iGroups->Delete(0,iPhBkUSim2StoreEntries[i].iGroups->Count());
					delete iPhBkUSim2StoreEntries[i].iGroups;
				}
			}
			if((iPhBkUSim2StoreEntries[i].iEmails!=NULL)
				&& ((TUint)iPhBkUSim2StoreEntries[i].iEmails!=DELETED))
			{
				if(iPhBkUSim2StoreEntries[i].iEmails->Count()>=0)
				{
					iPhBkUSim2StoreEntries[i].iEmails->Delete(0,iPhBkUSim2StoreEntries[i].iEmails->Count());
					delete iPhBkUSim2StoreEntries[i].iEmails;	
				}
			}
		}
	}	
	
	if((iPhBkOOBWrite.iAdditional!=NULL)
		&& ((TUint)iPhBkOOBWrite.iAdditional!=DELETED))
	{
		iPhBkOOBWrite.iAdditional->Delete(0,iPhBkOOBWrite.iAdditional->Count());
		delete iPhBkOOBWrite.iAdditional;
	}
	if((iPhBkOOBWrite.iGroups!=NULL)
		&& ((TUint)iPhBkOOBWrite.iGroups!=DELETED))
	{
		iPhBkOOBWrite.iGroups->Delete(0,iPhBkOOBWrite.iGroups->Count());
		delete iPhBkOOBWrite.iGroups;
	}
	if((iPhBkOOBWrite.iEmails!=NULL)
		&& ((TUint)iPhBkOOBWrite.iEmails!=DELETED))
	{
		iPhBkOOBWrite.iEmails->Delete(0,iPhBkOOBWrite.iEmails->Count());
		delete iPhBkOOBWrite.iEmails;
	}
	delete[] iPhBkUSim1StoreEntries;
	delete[] iPhBkUSim2StoreEntries;
	delete iPhBkError;
	delete iPhBkRwBuffer;
	delete iOOBWriteTimer;
	delete iOOBDeleteTimer;
	delete iReqTimer;

	}

TInt CSimPhBkUSimStore::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* CSimPhBkUSimStore::OpenNewObjectByNameL(const TDesC& /*aName*/)
/**
 * The API does not support any objects that could be opened from this one.
 */
	{
	User::Leave(KErrNotSupported);
	return NULL;
	}

CTelObject* CSimPhBkUSimStore::OpenNewObjectL(TDes&)
/**
 * The API does not support any objects that could be opened from this one.
 */
	{
	User::Leave(KErrNotSupported);
	return NULL;
	}

CTelObject::TReqMode CSimPhBkUSimStore::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 CSimPhBkUSimStore::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 CSimPhBkUSimStore::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 CSimPhBkUSimStore::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 CSimPhBkUSimStore::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 CSimPhBkUSimStore::Init()
/**
 *	This function can be used to perform any necessary synchronous initialisation.
 */
	{
	}

TInt CSimPhBkUSimStore::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;
		}

	if(CheckAndSwitchUSimApps()!=KErrNone)
		{
		ReqCompleted(aReqHandle, KErrNotFound);
		return KErrNone;
		}

	RMobilePhoneBookStore::TMobilePhoneBookInfoV1Pckg* getInfoPckg=(RMobilePhoneBookStore::TMobilePhoneBookInfoV1Pckg*)aPckg;
	RMobilePhoneBookStore::TMobilePhoneBookInfoV1& getInfo=(*getInfoPckg)();

	PopulatePhBkStoreInfo(&getInfo);

	if(&getInfo!=NULL) // NULL will have been assigned by PopulatePhBkStoreInfo if the version checking failed.
		{
		ReqCompleted(aReqHandle,KErrNone);
		}
	else
		{
		ReqCompleted(aReqHandle,KErrNotSupported);
		}
	
	return KErrNone;
	}

void CSimPhBkUSimStore::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.Zero();		

		getExtraInfo->iPhBkMode.Copy(PhBkStore());		
	
		if(PhBkStore().Compare(KUSimPhoneBook)!=KErrNone)
			{
			getExtraInfo->iIdentity.Copy(iPhone->GetImsi());
			}
		else
			{
			TPtrC8 USimId(iPhone->GetActiveUSim().Right(1));
			getExtraInfo->iIdentity.Copy(USimId);
			getExtraInfo->iIdentity.Append(iPhone->GetImsi());
			}
		}
	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.Zero();		

		getExtraInfo->iPhBkMode.Copy(PhBkStore());

		getExtraInfo->iMaxSecondNames = KMaxSecondNames;
		getExtraInfo->iMaxTextLengthSecondName = iPhBkMaxTextLen;
		getExtraInfo->iMaxAdditionalNumbers = iPhBkAdditional;
		getExtraInfo->iMaxTextLengthAdditionalNumber = iPhBkMaxAdditionalTextLen;
		getExtraInfo->iMaxNumLengthAdditionalNumber = iPhBkMaxAdditionalTelNumLen;
		getExtraInfo->iMaxGroupNames = KMaxGroups;
		getExtraInfo->iMaxTextLengthGroupName = iPhBkMaxTextLen;
		getExtraInfo->iMaxEmailAddr = iPhBkMaxEmail;
		getExtraInfo->iMaxTextLengthEmailAddr = iPhBkMaxTextLen;
	
		if(PhBkStore().Compare(KUSimPhoneBook)!=KErrNone)
			{
			getExtraInfo->iIdentity.Copy(iPhone->GetImsi());			
			}
		else
			{
			TPtrC8 USimId(iPhone->GetActiveUSim().Right(1));
			getExtraInfo->iIdentity.Copy(USimId);
			getExtraInfo->iIdentity.Append(iPhone->GetImsi());
			}
		}	
	}

TInt CSimPhBkUSimStore::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(CheckAndSwitchUSimApps()!=KErrNone)
		{
		ReqCompleted(aReqHandle, KErrNotFound);
		return KErrNone;
		}

	if(iPhone->IsICCLocked()!=EFalse)
		{
		ReqCompleted(aReqHandle, KErrAccessDenied);
		return KErrNone;
		}

	TPckg<RMobilePhoneBookStore::TPBIndexAndNumEntries>* indexNumPckg=(TPckg<RMobilePhoneBookStore::TPBIndexAndNumEntries>*)aPckg1;
	RMobilePhoneBookStore::TPBIndexAndNumEntries& indexNum=(*indexNumPckg)();

	if(indexNum.iNumSlots==iPhBkMaxNumSlots)
		{
		if (!(iPhBkStoreCaps & static_cast<TUint32>(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;
	TBool onlyHidden=EFalse;

	for(TInt i=indexNum.iIndex;i<=iPhBkMaxNumSlots;i++)
		{
		if((iPhBkUSimStoreEntries[i].iTelNum.Length()!=0)||(iPhBkUSimStoreEntries[i].iAlphaTag.Length()!=0))
			{				
			ret=iPhBkRwBuffer->AddNewEntryTag();
			if(ret!=KErrNone)
				break;
			
			if((iPhone->IsHiddenEnabled()!=EFalse) &&
				iPhBkUSimStoreEntries[i].iHiddenEntry==1)
				{
				//This is a hidden entry, the key is required and is currently locked
				//Therefore, the client should be notified that the slot has been occupied by a hidden entry

				partial=ETrue;
				ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBAdnIndex,(TUint16)i);
				if(ret!=KErrNone)
					break;
				ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBHiddenInfo,(TUint8) iPhBkUSimStoreEntries[i].iHiddenEntry);
				if(ret!=KErrNone)
					break;
				partial=EFalse;
				onlyHidden=ETrue;
				break;
				}

			partial=ETrue;
			ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBAdnIndex,(TUint16)i);
			if(ret!=KErrNone)
				break;
			ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBText,iPhBkUSimStoreEntries[i].iAlphaTag);
			if(ret!=KErrNone)
				break;
			ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBTonNpi,iPhBkUSimStoreEntries[i].iTonNpi);
			if(ret!=KErrNone)
				break;
			ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBNumber,iPhBkUSimStoreEntries[i].iTelNum);
			if(ret!=KErrNone)
				break;
	
			ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBSecondName,iPhBkUSimStoreEntries[i].iAlphaTag2);
			if(ret!=KErrNone)
				break;

			TInt EmailCount = iPhBkUSimStoreEntries[i].iEmails->Count();
			TInt GroupCount = iPhBkUSimStoreEntries[i].iGroups->Count();
			TInt AnrCount = iPhBkUSimStoreEntries[i].iAdditional->Count();
			TInt j;

			TBool corrupt=EFalse;

			for(j=0; j<AnrCount; j++)
				{
				TPhBkStoreEntry entry = iPhBkUSimStoreEntries[i].iAdditional->At(j);
				
				corrupt=ETrue;

				ret=iPhBkRwBuffer->AddNewNumberTag();
				if(ret!=KErrNone)
					break;
				
				ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBText,entry.iAlphaTag);
				if(ret!=KErrNone)
					break;
						
				ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBNumber,entry.iTelNum);
				if(ret!=KErrNone)
					break;

				ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBTonNpi,entry.iTonNpi);
				if(ret!=KErrNone)
					break;

				corrupt=EFalse;
				}			
			if(corrupt)
				break;

			for(j=0; j<EmailCount; j++)
				{
				TPhBkUSimEmail entry = iPhBkUSimStoreEntries[i].iEmails->At(j);
				
				corrupt=ETrue;
				ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBEmailAddress,entry);
				if(ret!=KErrNone)
					break;
				corrupt=EFalse;
				}			
			if(corrupt)
				break;
			
			for(j=0; j<GroupCount; j++)
				{
				TPhBkUSimGroup entry = iPhBkUSimStoreEntries[i].iGroups->At(j);
				
				corrupt=ETrue;
				ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBGroupName,entry);
				if(ret!=KErrNone)
					break;
				corrupt=EFalse;
				}			
			if(corrupt)
				break;

			ret=iPhBkRwBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBHiddenInfo,(TUint8) iPhBkUSimStoreEntries[i].iHiddenEntry);
			if(ret!=KErrNone)
				break;

			partial=EFalse;
			onlyHidden=ETrue;
			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)&&(!onlyHidden))
		ReqCompleted(aReqHandle,KErrNotFound);		// No entries found.
	else if((cnt==0)&&(!partial)&&(onlyHidden))
		ReqCompleted(aReqHandle,KErrAccessDenied);
	else
		ReqCompleted(aReqHandle,KErrNone);

	return KErrNone;
	}

TInt CSimPhBkUSimStore::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(CheckAndSwitchUSimApps()!=KErrNone)
		{
		ReqCompleted(aReqHandle, KErrNotFound);
		return KErrNone;
		}

	if(iPhone->IsICCLocked()!=EFalse)
		{
		ReqCompleted(aReqHandle, KErrAccessDenied);
		return KErrNone;
		}
	
	if (!(iPhBkStoreCaps & RMobilePhoneStore::KCapsIndividualEntry && iPhBkStoreCaps & RMobilePhoneStore::KCapsWriteAccess))
		{
		ReqCompleted(aReqHandle, KErrAccessDenied);
		return KErrNone;
		}

	TPckg<TInt>* indexPckg=(TPckg<TInt>*)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((iPhBkUSimStoreEntries[i].iTelNum.Length()==0)&&(iPhBkUSimStoreEntries[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(iPhBkUSimStoreEntries[index].iTelNum.Length()!=0)
		{
		if((iPhone->IsHiddenEnabled()!=EFalse) &&
			iPhBkUSimStoreEntries[index].iHiddenEntry==1)
			{
			ReqCompleted(aReqHandle, KErrAccessDenied);
			return KErrNone;
			}

		isSlotAlreadyUsed=ETrue;
		TInt idx,count;
		
		count=iPhBkUSimStoreEntries[index].iAdditional->Count();
		for(idx=0;idx<count;idx++)
			{
			TPhBkStoreEntry entry=
				iPhBkUSimStoreEntries[index].iAdditional->At(idx);
			entry.iTelNum.Zero();
			entry.iAlphaTag.Zero();	
			entry.iTonNpi=0;
			}
		iPhBkUSimStoreEntries[index].iAdditional->Delete(0,count);
		delete iPhBkUSimStoreEntries[index].iAdditional;
		count=iPhBkUSimStoreEntries[index].iGroups->Count();
		iPhBkUSimStoreEntries[index].iGroups->Delete(0,count);
		delete iPhBkUSimStoreEntries[index].iGroups;
		count=iPhBkUSimStoreEntries[index].iEmails->Count();
		iPhBkUSimStoreEntries[index].iEmails->Delete(0,count);
		delete iPhBkUSimStoreEntries[index].iEmails;

		TRAPD(err,iPhBkUSimStoreEntries[index].iAdditional=
				new(ELeave) CArrayFixFlat<TPhBkStoreEntry>(iPhBkAdditional+1));
		if (err!=KErrNone)
			return (err);

		TRAP(err,iPhBkUSimStoreEntries[index].iGroups=
				new(ELeave) CArrayFixFlat<TPhBkUSimGroup>(KMaxGroups));
		if (err!=KErrNone)
			return (err);

		TRAP(err,iPhBkUSimStoreEntries[index].iEmails=
				new(ELeave) CArrayFixFlat<TPhBkUSimEmail>(iPhBkMaxEmail+1));
		if (err!=KErrNone)
			return (err);
	}
	else 
		{
		TRAPD(err,iPhBkUSimStoreEntries[index].iAdditional=
				new(ELeave) CArrayFixFlat<TPhBkStoreEntry>(iPhBkAdditional+1));
		if (err!=KErrNone)
			return (err);

		TRAP(err,iPhBkUSimStoreEntries[index].iGroups=
				new(ELeave) CArrayFixFlat<TPhBkUSimGroup>(KMaxGroups));
		if (err!=KErrNone)
			return (err);

		TRAP(err,iPhBkUSimStoreEntries[index].iEmails=
				new(ELeave) CArrayFixFlat<TPhBkUSimEmail>(iPhBkMaxEmail+1));
		if (err!=KErrNone)
			return (err);
	}
// Unpick the phonebook entry.
	iPhBkRwBuffer->Set(aPckg1);
	iPhBkRwBuffer->StartRead();

	TUint8 tagVal;
	TUint8 npiTon=0;
	TUint8 hidden;
	TPtrC alphaTag,alphaTag2;
	TPtrC telNum;
	TPtrC bufPtr;
	TBool additional=EFalse;
	TInt additionalCount=0;
	
	CPhoneBookBuffer::TPhBkTagType tagType;
	TInt ret=KErrNone;

	TPhBkStoreEntry additionalEntry;

	while(ret==KErrNone)
		{
		ret=iPhBkRwBuffer->GetTagAndType(tagVal,tagType);
		if(ret==KErrNotFound)
			{
			ret=KErrNone;
			break;
			}
		else if(ret!=KErrNone)
			break;
		switch(tagVal)
			{
		case RMobilePhoneBookStore::ETagPBNewEntry:
			break;

		case RMobilePhoneBookStore::ETagPBText:
			ret=iPhBkRwBuffer->GetValue(alphaTag);

			LOGPHBK2("alphaTag (ETagPBText) Length = (%d)",alphaTag.Length());
			LOGPHBK2("Phonebook Max Text Length = (%d)",iPhBkMaxTextLen);

			if(!additional && ret==KErrNone && (alphaTag.Length()<=iPhBkMaxTextLen))
				iPhBkUSimStoreEntries[index].iAlphaTag.Copy(alphaTag);
			else if(additional && ret==KErrNone && (alphaTag.Length()<=iPhBkMaxAdditionalTextLen)
					&& (additionalCount<iPhBkAdditional))
				additionalEntry.iAlphaTag.Copy(alphaTag);
			else if(additional)
				ret=EXTENDEDERROR(KErrArgument, KErrPhonebookAdditionalNumberAlphaTextOverflow);
			else
				ret=EXTENDEDERROR(KErrOverflow, KErrPhonebookTextOverflow);
			break;

		case RMobilePhoneBookStore::ETagPBSecondName:
			ret=iPhBkRwBuffer->GetValue(alphaTag2);

			LOGPHBK2("alphaTag2 (ETagPBSecondName) Length = (%d)",alphaTag2.Length());
			LOGPHBK2("Phonebook Max Text Length = (%d)",iPhBkMaxTextLen);

			if(ret==KErrNone && (alphaTag2.Length()<=iPhBkMaxTextLen))
				iPhBkUSimStoreEntries[index].iAlphaTag2.Copy(alphaTag2);
			else
				ret=EXTENDEDERROR(KErrOverflow, KErrPhonebookSecondNameTextOverflow);
			break;

		case RMobilePhoneBookStore::ETagPBNumber:
			ret=iPhBkRwBuffer->GetValue(telNum);

			LOGPHBK2("telNum (ETagPBNumber) Length = (%d)",telNum.Length());
			LOGPHBK2("Phonebook Max Text Length = (%d)",iPhBkMaxTelNumLen);

			if(!additional && ret==KErrNone && (telNum.Length()<=iPhBkMaxTelNumLen))
				iPhBkUSimStoreEntries[index].iTelNum.Copy(telNum);
			else if(additional && ret==KErrNone && (telNum.Length()<=iPhBkMaxAdditionalTelNumLen)
					&& (additionalCount<iPhBkAdditional))
				additionalEntry.iTelNum.Copy(telNum);
			else if(additional)
				ret=EXTENDEDERROR(KErrArgument, KErrPhonebookAdditionalNumberNumberOverflow);
			else 
				ret=EXTENDEDERROR(KErrOverflow, KErrPhonebookNumberOverflow);
			break;

		case RMobilePhoneBookStore::ETagPBTonNpi:
			ret=iPhBkRwBuffer->GetValue(npiTon);
			if(!additional && ret==KErrNone)
				iPhBkUSimStoreEntries[index].iTonNpi=npiTon;
			else if (additional && ret==KErrNone)
				{
				additionalEntry.iTonNpi=npiTon;
				TRAP_IGNORE(iPhBkUSimStoreEntries[index].iAdditional->AppendL(additionalEntry));
				additional=EFalse;
				additionalCount++;
				additionalEntry.iAlphaTag.Zero();
				additionalEntry.iTelNum.Zero();
				additionalEntry.iTonNpi=0;
				}
			break;

		case RMobilePhoneBookStore::ETagPBAnrStart:
			if(!additional)
				additional=ETrue;
			else
				ret=KErrArgument;
			break;

		case RMobilePhoneBookStore::ETagPBGroupName:
			ret=iPhBkRwBuffer->GetValue(bufPtr);

			LOGPHBK2("bufPtr (ETagPBGroupName) Length = (%d)",bufPtr.Length());
			LOGPHBK2("Phonebook Max Text Length = (%d)",iPhBkMaxTextLen);

			if(ret==KErrNone && (bufPtr.Length()<=iPhBkMaxTextLen)
				&& (iPhBkUSimStoreEntries[index].iGroups->Count() < KMaxGroups))
			{
				TRAP_IGNORE(iPhBkUSimStoreEntries[index].iGroups->AppendL(bufPtr));
			}
			else 
				ret=EXTENDEDERROR(KErrOverflow, KErrPhonebookGroupAlphaTextOverflow);
			break;

		case RMobilePhoneBookStore::ETagPBEmailAddress:
			ret=iPhBkRwBuffer->GetValue(bufPtr);

			LOGPHBK2("bufPtr (ETagPBEmailAddress) Length = (%d)",bufPtr.Length());
			LOGPHBK2("Phonebook Max Text Length = (%d)",iPhBkMaxTextLen);

			if(ret==KErrNone && (bufPtr.Length()<=iPhBkMaxTextLen)
				&& (iPhBkUSimStoreEntries[index].iEmails->Count() < iPhBkMaxEmail))
			{
				TRAP_IGNORE(iPhBkUSimStoreEntries[index].iEmails->AppendL(bufPtr));
			}
			else
				ret=EXTENDEDERROR(KErrOverflow, KErrPhonebookEmailTextOverflow);		
			break;

		case RMobilePhoneBookStore::ETagPBHiddenInfo:
			ret=iPhBkRwBuffer->GetValue(hidden);	
			if(ret==KErrNone)
				iPhBkUSimStoreEntries[index].iHiddenEntry=hidden;
			break;

		default:
			ret=KErrNotSupported;
			}
		}

	if(ret!=KErrNone)
		{
		//Cleanup!
		iPhBkUSimStoreEntries[index].iTelNum.Zero();
		iPhBkUSimStoreEntries[index].iAlphaTag.Zero();
		iPhBkUSimStoreEntries[index].iAlphaTag2.Zero();
		iPhBkUSimStoreEntries[index].iHiddenEntry=0;
		iPhBkUSimStoreEntries[index].iTonNpi=npiTon;

		if(iPhBkUSimStoreEntries[index].iGroups!=NULL) 
		{
			iPhBkUSimStoreEntries[index].iGroups->Delete(0,iPhBkUSimStoreEntries[index].iGroups->Count());
			delete iPhBkUSimStoreEntries[index].iGroups;
		}
		if(iPhBkUSimStoreEntries[index].iEmails!=NULL)
		{
			iPhBkUSimStoreEntries[index].iEmails->Delete(0,iPhBkUSimStoreEntries[index].iEmails->Count());
			delete iPhBkUSimStoreEntries[index].iEmails;
		}
		if(iPhBkUSimStoreEntries[index].iAdditional!=NULL)
		{
			iPhBkUSimStoreEntries[index].iAdditional->Delete(0,iPhBkUSimStoreEntries[index].iAdditional->Count());
			delete iPhBkUSimStoreEntries[index].iAdditional;
		}
		ReqCompleted(aReqHandle,ret);
		return KErrNone;
		}

//	if(alphaTag.Length()>iPhBkMaxTextLen)
//		{
//		ReqCompleted(aReqHandle, EXTENDEDERROR(KErrOverflow, KErrPhonebookTextOverflow));
//		return KErrNone;
//		}
//	else if(telNum.Length()>iPhBkMaxTelNumLen)
//		{
//		ReqCompleted(aReqHandle, EXTENDEDERROR(KErrOverflow, KErrPhonebookNumberOverflow));
//		return KErrNone;
//		}
	
	if(isSlotAlreadyUsed)
		DelayCompletion(iPhBkIndividualPause,aReqHandle,EStoreEventChanged,index);
	else
		DelayCompletion(iPhBkIndividualPause,aReqHandle,EStoreEventAdded,index);
	return KErrNone;
	}

TInt CSimPhBkUSimStore::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(CheckAndSwitchUSimApps()!=KErrNone)
		{
		ReqCompleted(aReqHandle, KErrNotFound);
		return KErrNone;
		}

	if(iPhone->IsICCLocked()!=EFalse)
		{
		ReqCompleted(aReqHandle, KErrAccessDenied);
		return KErrNone;
		}
	
	if (!(iPhBkStoreCaps & RMobilePhoneStore::KCapsIndividualEntry && iPhBkStoreCaps & RMobilePhoneStore::KCapsWriteAccess))
		{
		ReqCompleted(aReqHandle, KErrAccessDenied);
		return KErrNone;
		}


	TPckg<TInt>* intPckg=(TPckg<TInt>*)aPckg;
	TInt& index=(*intPckg)();

	if((index<1)||(index>iPhBkMaxNumSlots))
		{
		ReqCompleted(aReqHandle,KErrArgument);
		return KErrNone;
		}
	
	if((iPhone->IsHiddenEnabled()!=EFalse) &&
		iPhBkUSimStoreEntries[index].iHiddenEntry==1)
		{
		ReqCompleted(aReqHandle, KErrAccessDenied);
		return KErrNone;
		}
	
	iPhBkUSimStoreEntries[index].iTelNum.Zero();
	iPhBkUSimStoreEntries[index].iAlphaTag.Zero();
	iPhBkUSimStoreEntries[index].iAlphaTag2.Zero();
	
	if((iPhBkUSimStoreEntries[index].iGroups!=NULL) &&
		((TUint)iPhBkUSimStoreEntries[index].iGroups!=DELETED))
	{
		iPhBkUSimStoreEntries[index].iGroups->Delete(0,
			iPhBkUSimStoreEntries[index].iGroups->Count());
		delete iPhBkUSimStoreEntries[index].iGroups;
	}
	if((iPhBkUSimStoreEntries[index].iEmails!=NULL) &&
		((TUint)iPhBkUSimStoreEntries[index].iEmails!=DELETED))
	{
		iPhBkUSimStoreEntries[index].iEmails->Delete(0,
			iPhBkUSimStoreEntries[index].iEmails->Count());
		delete iPhBkUSimStoreEntries[index].iEmails;
	}

	if((iPhBkUSimStoreEntries[index].iAdditional!=NULL) &&
		((TUint)iPhBkUSimStoreEntries[index].iAdditional!=DELETED))
		{
		TInt count = iPhBkUSimStoreEntries[index].iAdditional->Count();
		for(TInt i=0;i<count;i++)
			{
			TPhBkStoreEntry entry=iPhBkUSimStoreEntries[index].iAdditional->At(i);
			entry.iTelNum.Zero();
			entry.iAlphaTag.Zero();
			entry.iTonNpi=0;
			}

		iPhBkUSimStoreEntries[index].iAdditional->Delete(0,count);
		delete iPhBkUSimStoreEntries[index].iAdditional;
		}

	DelayCompletion(iPhBkIndividualPause,aReqHandle,EStoreEventDeleted,index);
	return KErrNone;
	}

TInt CSimPhBkUSimStore::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(CheckAndSwitchUSimApps()!=KErrNone)
		{
		ReqCompleted(aReqHandle, KErrNotFound);
		return KErrNone;
		}

	if(iPhone->IsICCLocked()!=EFalse)
		{
		ReqCompleted(aReqHandle, KErrAccessDenied);
		return KErrNone;
		}

	if (!(iPhBkStoreCaps & static_cast<TUint32>(RMobilePhoneStore::KCapsWholeStore) && iPhBkStoreCaps & RMobilePhoneStore::KCapsWriteAccess))
		{
		ReqCompleted(aReqHandle, KErrAccessDenied);
		return KErrNone;
		}

	for(TInt i=1;i<=iPhBkMaxNumSlots;i++)
		{
		TBool entryUsed =EFalse;

		if((iPhone->IsHiddenEnabled()!=EFalse) &&
		iPhBkUSimStoreEntries[i].iHiddenEntry==1)
			{
			//Skip me because I am a hidden entry!
			//The hidden key has to be verified to delete me!
			continue;
			}
		if(iPhBkUSimStoreEntries[i].iTelNum.Length()>0)
			entryUsed = ETrue;
			
		iPhBkUSimStoreEntries[i].iTelNum.Zero();
		iPhBkUSimStoreEntries[i].iAlphaTag.Zero();
		iPhBkUSimStoreEntries[i].iAlphaTag2.Zero();
		
		if(entryUsed)
			{
			if((iPhBkUSimStoreEntries[i].iGroups!=NULL) &&
				((TUint)iPhBkUSimStoreEntries[i].iGroups!=DELETED))
			{
				iPhBkUSimStoreEntries[i].iGroups->Delete(0,
					iPhBkUSimStoreEntries[i].iGroups->Count());
				delete iPhBkUSimStoreEntries[i].iGroups;
			}
			if((iPhBkUSimStoreEntries[i].iEmails!=NULL) &&
				((TUint)iPhBkUSimStoreEntries[i].iEmails!=DELETED))
			{
				iPhBkUSimStoreEntries[i].iEmails->Delete(0,
					iPhBkUSimStoreEntries[i].iEmails->Count());
				delete iPhBkUSimStoreEntries[i].iEmails;
			}
			if((iPhBkUSimStoreEntries[i].iAdditional!=NULL) &&
				((TUint)iPhBkUSimStoreEntries[i].iAdditional!=DELETED))
				{
				TInt count = iPhBkUSimStoreEntries[i].iAdditional->Count();
	            for(TInt index=0;index<count;index++)
					{
					TPhBkStoreEntry entry=iPhBkUSimStoreEntries[i].iAdditional->At(index);
					entry.iTelNum.Zero();
					entry.iAlphaTag.Zero();
					entry.iTonNpi=0;
					}

				iPhBkUSimStoreEntries[i].iAdditional->Delete(0,count);
				delete iPhBkUSimStoreEntries[i].iAdditional;
				}
			}
	}
	DelayCompletion(iPhBkBatchPause,aReqHandle,EStoreEventDeleted,-1);
	return KErrNone;
	}

TInt CSimPhBkUSimStore::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<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 CSimPhBkUSimStore::NotifyStoreEventCancel()
/**
 * Cancel an outstanding notify store request.
 */
	{
	if(iEvOutstandingReq)
		{
		iEvOutstandingReq=EFalse;
		ReqCompleted(iEvReqHandle,KErrCancel);
		}
	}

TPtrC8 CSimPhBkUSimStore::Name()
/**
 * Accessor function fot the Phonebook Store name.
 *
 * @return TPtrC8	The name of this Phonebook Store.
 */
	{
	return iPhBkStoreName;
	}

TPtrC8 CSimPhBkUSimStore::PhBkStore()
/**
 * Accessor function fot the Phonebook Store name.
 *
 * @return TPtrC8	The name of this Phonebook Store.
 */
	{
	return iPhBkStore;
	}

TPtrC8 CSimPhBkUSimStore::AID()
/**
 * Accessor function fot the Phonebook Store name.
 *
 * @return TPtrC8	The name of this Phonebook Store.
 */
	{
	return iPhBkAid;
	}

TInt CSimPhBkUSimStore::UsedEntries()
/**
 * Count the number of used entries in the Phonebook Store.
 * @return TInt	The number of used entries in the store.
 */
	{
	TInt cnt=0;
	if(CheckAndSwitchUSimApps()!=KErrNone)
  		return KErrNotFound;
	for(TInt i=1;i<=iPhBkMaxNumSlots;i++)
		{
		if((iPhBkUSimStoreEntries[i].iTelNum.Length()!=0)||(iPhBkUSimStoreEntries[i].iAlphaTag.Length()!=0))
			cnt++;
		}
	return cnt;
	}

TInt CSimPhBkUSimStore::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 CSimPhBkUSimStore::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 CSimPhBkUSimStore::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,ETimerIdPhBkUSimStorReq);
	}

void CSimPhBkUSimStore::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.
 */
	{
	TInt idx=0,count;
	TBool isSlotAlreadyUsed=EFalse;

	switch(aId)
		{
	case ETimerIdPhBkUSimStorReq:
		StoreEvent(iPendingEvent,iPendingIndex);
		ReqCompleted(iPendingReqCompletion,KErrNone);
		break;

	case ETimerIdPhBkUSimStorOOBWrite:

		if(CheckAndSwitchUSimApps()!=KErrNone)
			if(iEvOutstandingReq)
				{
				ReqCompleted(iEvReqHandle,KErrNotFound);
				return;
				}
			else
				{
				return;
				}

		if(iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iTelNum.Length()!=0)
			isSlotAlreadyUsed=ETrue;
		
		iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iAlphaTag.Copy(iPhBkOOBWrite.iAlphaTag);
		iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iTelNum.Copy(iPhBkOOBWrite.iTelNum);
		iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iTonNpi=iPhBkOOBWrite.iTonNpi;
		iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iAlphaTag2.Copy(iPhBkOOBWrite.iAlphaTag2);

		if(isSlotAlreadyUsed)
			{
			if((count=iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iAdditional->Count())>0)
				{
				for(idx=0;idx<count;idx++)
						{
						TPhBkStoreEntry entry=
							iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iAdditional->At(idx);
						entry.iTelNum.Zero();
						entry.iAlphaTag.Zero();	
						entry.iTonNpi=0;
						}
				iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iAdditional->Delete(0,count);
				delete iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iAdditional;
				}
			
			if((count = iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iGroups->Count())>0)
				{
					iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iGroups->Delete(0,count);
					delete iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iGroups;
				}
			if((count = iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iEmails->Count())>0)
				{
					iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iEmails->Delete(0,count);
					delete iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iEmails;
				}
			}
	
		count = iPhBkOOBWrite.iAdditional->Count();

		//sometimes because of a kernel bug on wins, iAdditional pointer gets filled up with
		//bad address 0xdededede (investigating)
	
		TRAPD(err,iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iAdditional=new(ELeave) CArrayFixFlat<TPhBkStoreEntry>(iPhBkAdditional+1));
		if (err!=KErrNone)
			{
			LOGPHBK1("CSimPhBkUSimStore::TimerCallBack - Memory Allocation Failure");
			return;
			}

		for(idx=0;idx<count;idx++)
			{
			TPhBkStoreEntry entry=iPhBkOOBWrite.iAdditional->At(idx);
			TRAP_IGNORE(iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iAdditional->AppendL(entry));
			}

		
		TRAP(err,iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iGroups=new(ELeave) CArrayFixFlat<TPhBkUSimGroup>(KMaxGroups));
		if (err!=KErrNone)
			{
			LOGPHBK1("CSimPhBkUSimStore::TimerCallBack - Memory Allocation Failure");
			return;
			}

		for(idx=0;idx<count;idx++)
			{
			TPhBkUSimGroup entry;
			TRAP_IGNORE(iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iGroups->AppendL(entry));
			}
		
		count = iPhBkOOBWrite.iEmails->Count();
		TRAP(err,iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iEmails=new(ELeave) CArrayFixFlat<TPhBkUSimEmail>(iPhBkMaxEmail+1));	
		if (err!=KErrNone)
			{
			LOGPHBK1("CSimPhBkUSimStore::TimerCallBack - Memory Allocation Failure");
			return;
			}

		for(idx=0;idx<count;idx++)
			{
			TPhBkUSimEmail entry;
			TRAP_IGNORE(iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iEmails->AppendL(entry));
			}
		
		iPhBkUSimStoreEntries[iPhBkOOBWriteIndex].iHiddenEntry=iPhBkOOBWrite.iHiddenEntry;
	
		StoreEvent(EStoreEventAdded,iPhBkOOBWriteIndex);
		break;

	case ETimerIdPhBkUSimStorOOBDelete:
		
		if(CheckAndSwitchUSimApps()!=KErrNone)
			if(iEvOutstandingReq)
				{
				ReqCompleted(iEvReqHandle,KErrNotFound);
				return;
				}
			else
				{
				return;
				}

		iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iAlphaTag.Zero();
		iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iTelNum.Zero();
		iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iTonNpi=0;
		iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iAlphaTag2.Zero();

		iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iGroups->Delete(0,
			iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iGroups->Count());
		delete iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iGroups;

		iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iEmails->Delete(0,
			iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iEmails->Count());
		delete iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iEmails;

		count = iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iAdditional->Count();
		for(idx=0;idx<count;idx++)
			{
			TPhBkStoreEntry entry=iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iAdditional->At(idx);
			entry.iTelNum.Zero();
			entry.iAlphaTag.Zero();	
			entry.iTonNpi=0;
			}

		iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iAdditional->Delete(0,count);
		delete iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iAdditional;
		iPhBkUSimStoreEntries[iPhBkOOBDeleteIndex].iHiddenEntry=0;

		StoreEvent(EStoreEventDeleted,iPhBkOOBDeleteIndex);
		break;

	default:
		break;
		}
	}

void CSimPhBkUSimStore::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 CSimPhBkUSimStore::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;i<iPhBkError->Count();i++)
		{
		if(iPhBkError->At(i).iCount==iIpcCnt)
			{
			aError=iPhBkError->At(i).iError;
			return ETrue;
			}
		}
	return EFalse;
	}


/**
 *  Check that the USIM App phonebook in use is the same as the current
 *  USIM App, and if not then swap the phonebook over.
 */
TInt CSimPhBkUSimStore::CheckAndSwitchUSimApps()
	{	
	TInt ret=KErrNone;

	if(iPhBkStore.Compare(KUSimPhoneBook)==KErrNone)
		{
		if(iPhone->GetActiveUSim().Compare(iPhBkAid)==KErrNone) 
			{
			//
			// The active USIM App is the same as last time, but ensure that
			// we are using the right phonebook anyway.
			//
			if(iPhBkAid.Compare(iPhBkAidUSim2)==KErrNone)
				{
				iPhBkUSimStoreEntries=iPhBkUSim2StoreEntries;
				}
			else if(iPhBkAid.Compare(iPhBkAidUSim1)==KErrNone)
				{
				iPhBkUSimStoreEntries=iPhBkUSim1StoreEntries;
				}
			else 
				{
				//messed up
				return KErrUnknown;
				}
			}
		else if((iPhone->GetActiveUSim().Compare(iPhBkAid)!=KErrNone) &&
			(iPhone->GetActiveUSim().Compare(iPhBkAidUSim2)==KErrNone)) 
			{
			//
			// The active USIM App is not the same as last time and it appears
			// to be USIM App 2, so use USIM phonebook number 2.
			//
			iPhBkAid.Copy(iPhBkAidUSim2);
			iPhBkUSimStoreEntries=iPhBkUSim2StoreEntries;
			}
		else if((iPhone->GetActiveUSim().Compare(iPhBkAid)!=KErrNone) &&
			(iPhone->GetActiveUSim().Compare(iPhBkAidUSim1)==KErrNone)) 
			{
			//
			// The active USIM App is not the same as last time and it appears
			// to be USIM App 1, so use USIM phonebook number 1.
			//
			iPhBkAid.Copy(iPhBkAidUSim1);
			iPhBkUSimStoreEntries=iPhBkUSim1StoreEntries;
			}
		else
			{
			//Unknown active application!!
			ret=KErrNotFound;
			}
		}	
	return ret;
}

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