// Copyright (c) 2002-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 Phone Smart Card application and file manipulation code.
// 
//

/**
 @file
*/

#include <testconfigfileparser.h>
#include <etelmmerr.h>
#include "CSimPhone.h"
#include "Simlog.h"

//
// CSimPhoneSmartCardApp
//

CSimPhoneSmartCardApp* CSimPhoneSmartCardApp::NewL(CSimPhone* aPhone)
/**
 * Standard two phase constructor.
 * @param aPhone The phone object from which the Phone Smart Card applications will open
 */
	{
	CSimPhoneSmartCardApp* obj=new(ELeave) CSimPhoneSmartCardApp(aPhone);
	CleanupStack::PushL(obj);
	obj->ConstructL();
	CleanupStack::Pop();
	return obj;
	}

CSimPhoneSmartCardApp::CSimPhoneSmartCardApp(CSimPhone* aPhone)
: iPhone(aPhone), iCurrentSelection(RMobilePhone::EUSimSelectionAutomatic), 
	iFoundScAppTags(EFalse)
/**
 * Trivial first phase constructor.
 * @param aPhone	The phone object from which this Phone SmartCard App was opened.
 */
	{}

void CSimPhoneSmartCardApp::Init()
	{}

void CSimPhoneSmartCardApp::ConstructL()
/**
* Second phase of the 2-phase constructor.
* Constructs all the member data and retrieves all the data from the config file specific to this class.
*
* @leave Leaves due to not enough memory or if any data member does not construct for any reason.
*/
	{
	LOGPHONE1("Starting to parse Phone Smart Card applications additional config parameters...");
	ParseSmartCardApplicationInfoL();
	ParseSmartCardFileInfoL();
	MapUSimAppsL();
	LOGPHONE1("Finished parsing Phone Smart Card applications additional config parameters...");
	}


CSimPhoneSmartCardApp::~CSimPhoneSmartCardApp()
/**
 * Standard destructor.  Any objects created by the ::ConstructL() function
 * will be destroyed here.
 */
	{
	delete iTimer;
	if(iSmartCardAppEventList)
		{
		iSmartCardAppEventList->Delete(0, iSmartCardAppEventList->Count());
		delete iSmartCardAppEventList;
		}
	if(iSmartCardAppList)
		{
		iSmartCardAppList->Delete(0, iSmartCardAppList->Count());
		delete iSmartCardAppList;
		}
	if (iSmartCardFileList)
		{
		iSmartCardFileList->ResetAndDestroy();
		delete iSmartCardFileList;
		}
	if(iUSimAppList)
		{
		iUSimAppList->Close();
		delete iUSimAppList;
		}
	}


TInt CSimPhoneSmartCardApp::ExtFunc(const TTsyReqHandle aTsyReqHandle,const TInt aIpc, const TDataPackage& aPckg)
/**
* ExtFunc is called by the server when it has an "extended", i.e. non-core ETel request
* for the TSY to process.
* A request handle, request type and request data are passed to the TSY
* 
* @param aTsyReqHandle  The request handle for completing the request 
* @param aIpc Ipc representing the request
* @param aPackage any data associated with the request
* @return err KErrNone if request completes ok
*/
	{

	TAny* dataPtr = aPckg.Ptr1();
	TAny* dataPtr2 = aPckg.Ptr2();

	// The following requests can be completed even if the completion of another request is pending.
	switch(aIpc)
		{
	case EMobilePhoneGetCurrentActiveUSimApplication:
		return GetCurrentActiveUSimApplication(aTsyReqHandle,
			reinterpret_cast<RMobilePhone::TAID*>(dataPtr));
			
	case EMobilePhoneEnumerateUSimApplications:
		return EnumerateUSimApplications(aTsyReqHandle, 
			reinterpret_cast<TInt*> (dataPtr),
			reinterpret_cast<RMobilePhone::TAID*> (dataPtr2));

	case EMobilePhoneSetUSimApplicationStatus:
		return SetUSimApplicationStatus(aTsyReqHandle,
			reinterpret_cast<RMobilePhone::TAID*> (dataPtr),
			reinterpret_cast<RMobilePhone::TUSimAppAction*> (dataPtr2));

	case EMobilePhoneGetUSimApplicationsInfo:
		return GetUSimApplicationInfo(aTsyReqHandle, 
			reinterpret_cast<TInt*> (dataPtr),
			aPckg.Des2n());

	case EMobilePhoneNotifyUSimApplicationsInfoChange:
		return NotifyUSimApplicationsInfoChange(aTsyReqHandle, 
			reinterpret_cast<TInt*> (dataPtr),
			reinterpret_cast<RMobilePhone::TAID*> (dataPtr2));
		
	case EMobilePhoneEnumerateSmartCardApplications:
		return EnumerateScApplications(aTsyReqHandle, 
			reinterpret_cast<TUint*>(dataPtr));

	case EMobilePhoneGetSmartCardApplicationInfo:
		return GetScApplicationInfo(aTsyReqHandle, 
			reinterpret_cast<TInt*>(dataPtr), 
			aPckg.Des2n());

	case EMobilePhoneSetSmartCardApplicationStatus:
		return SetScApplicationStatus(aTsyReqHandle,
			reinterpret_cast<RMobilePhone::TAID*>(dataPtr),
			reinterpret_cast<RMobilePhone::TSmartCardApplicationAction*>(dataPtr2));

	case EMobilePhoneNotifySmartCardApplicationInfoChange:
		return NotifyScApplicationInfoChange(aTsyReqHandle, 
			reinterpret_cast<RMobilePhone::TAID*>(dataPtr), 
			reinterpret_cast<RMobilePhone::TSmartCardApplicationEvent*>(dataPtr2));

	case EMobilePhoneGetUSimAppsSelectionMode:
		return GetUSimAppsSelectionMode(aTsyReqHandle,
			reinterpret_cast<RMobilePhone::TUSimSelectionMode*>(dataPtr));

	case EMobilePhoneSetUSimAppsSelectionMode:
		return SetUSimAppsSelectionMode(aTsyReqHandle,
			reinterpret_cast<RMobilePhone::TUSimSelectionMode*>(dataPtr));

	case EMobilePhoneNotifyUSimAppsSelectionModeChange:
		return NotifyUSIMAppsSelectionModeChange(aTsyReqHandle, 
			reinterpret_cast<RMobilePhone::TUSimSelectionMode*>(dataPtr));
			
	case EMobilePhoneGetScFileInfo:
		return GetScFileInfo(aTsyReqHandle,
			*reinterpret_cast<RMobilePhone::TScFilePath*>(dataPtr),
			aPckg.Des2n());
		
	case EMobilePhoneReadScFile:
		return ReadScFile(aTsyReqHandle,
			*reinterpret_cast<RMobilePhone::TScFilePathWithAccessOffsets*>(dataPtr),
			aPckg.Des2n());
		
	case EMobilePhoneUpdateScFile:
		return UpdateScFile(aTsyReqHandle,
			*reinterpret_cast<RMobilePhone::TScFilePathWithAccessOffsets*>(dataPtr),
			aPckg.Des2n());

	default:
		break;
		}
	return KErrNotSupported;
	}
	

CTelObject::TReqMode CSimPhoneSmartCardApp::ReqModeL(const TInt aIpc)
/**
 * This function returns the Request Mode for the request with the passed IPC value.
 * The function leaves if the IPC is not found.
 *
 * @param aIpc		The IPC number of the request.
 * @return TReqMode	The request mode.
 */
	{
	CTelObject::TReqMode ret=0;	

	switch(aIpc)
		{
	case EMobilePhoneGetCurrentActiveUSimApplication:
	case EMobilePhoneEnumerateUSimApplications:
	case EMobilePhoneSetUSimApplicationStatus:
	case EMobilePhoneGetUSimApplicationsInfo:
	case EMobilePhoneEnumerateSmartCardApplications:
	case EMobilePhoneSetSmartCardApplicationStatus:
	case EMobilePhoneGetSmartCardApplicationInfo:
	case EMobilePhoneGetUSimAppsSelectionMode:
	case EMobilePhoneSetUSimAppsSelectionMode:
	case EMobilePhoneGetScFileInfo:
	case EMobilePhoneReadScFile:
	case EMobilePhoneUpdateScFile:
		break;

	case EMobilePhoneNotifyUSimAppsSelectionModeChange:
	case EMobilePhoneNotifyUSimApplicationsInfoChange:
	case EMobilePhoneNotifySmartCardApplicationInfoChange:
		ret=KReqModeMultipleCompletionEnabled | KReqModeRePostImmediately;
		break;

	default:
		User::Leave(KErrNotSupported);
		break;
		}

	return ret;
	}
	
TInt CSimPhoneSmartCardApp::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 CSimPhoneSmartCardApp::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;
	}

CTelObject* CSimPhoneSmartCardApp::OpenNewObjectByNameL(const TDesC& /*aName*/)
/**
 * The API does not support any objects that could be opened from this one.
 */
	{
	User::Leave(KErrNotSupported);
	return NULL;
	}

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


TInt CSimPhoneSmartCardApp::NumberOfSlotsL(const TInt aIpc)
/**
 * Return the number of slots that the ETel Server should allocate for buffering requests
 * of the given IPC number.
 *
 * @param aIpc	The IPC number of the request.
 */
	{
	TInt numberOfSlots = 0;
	
	switch(aIpc)
		{
	case EMobilePhoneNotifyUSimAppsSelectionModeChange:
	case EMobilePhoneNotifyUSimApplicationsInfoChange:
	case EMobilePhoneNotifySmartCardApplicationInfoChange:
		numberOfSlots = KDefaultNumberOfSlots;
		break;
	default:
		LOGPHONE1("CSimPhoneSmartCardApp: Number of Slots error, unknown IPC");
		User::Leave(KErrNotSupported);
		break;
		}
	return numberOfSlots;
	}


TInt CSimPhoneSmartCardApp::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.
 * @return	Standard return value.
 */
	{

	switch(aIpc)
		{
	case EMobilePhoneEnumerateSmartCardApplications:
		return EnumerateScApplicationsCancel(aTsyReqHandle);

	case EMobilePhoneEnumerateUSimApplications:
		return EnumerateUSimApplicationsCancel(aTsyReqHandle);

	case EMobilePhoneSetUSimApplicationStatus:
		return SetUSimApplicationStatusCancel(aTsyReqHandle);
	
	case EMobilePhoneGetUSimApplicationsInfo:
		return GetUSimApplicationInfoCancel(aTsyReqHandle);

	case EMobilePhoneNotifyUSimApplicationsInfoChange:
		return NotifyUSimApplicationsInfoChangeCancel(aTsyReqHandle);

	case EMobilePhoneSetSmartCardApplicationStatus:
		return SetScApplicationStatusCancel(aTsyReqHandle);
	
	case EMobilePhoneGetSmartCardApplicationInfo:
		return GetScApplicationInfoCancel(aTsyReqHandle);

	case EMobilePhoneGetCurrentActiveUSimApplication:
		return GetCurrentActiveUSimApplicationCancel(aTsyReqHandle);

	case EMobilePhoneNotifySmartCardApplicationInfoChange:
		return NotifyScApplicationInfoChangeCancel(aTsyReqHandle);
		
	case EMobilePhoneSetUSimAppsSelectionMode:
		return SetUSimAppsSelectionModeCancel(aTsyReqHandle);
	
	case EMobilePhoneGetUSimAppsSelectionMode:
		return GetUSimAppsSelectionModeCancel(aTsyReqHandle);
	
	case EMobilePhoneNotifyUSimAppsSelectionModeChange:
		return NotifyUSIMAppsSelectionModeChangeCancel(aTsyReqHandle);
	
	case EMobilePhoneGetScFileInfo:
		return GetScFileInfoCancel(aTsyReqHandle);

	case EMobilePhoneReadScFile:
		return ReadScFileCancel(aTsyReqHandle);

	case EMobilePhoneUpdateScFile:
		return UpdateScFileCancel(aTsyReqHandle);

	default:
		break;
		}
	return KErrNone;
	}


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

void CSimPhoneSmartCardApp::TimerCallBack(TInt /*aId*/)
/**
* Timer callback function.  When the timer goes off, it will call back into this
* function for further processing.
*
* @param aId an id identifying which timer callback is being called
*/	
	{
	if(iNotifyScInfo.iNotifyPending || iNotifyUSimInfo.iNotifyPending)
		{
		TSmartCardAppEvent theEvent=iSmartCardAppEventList->At(iEventPointer);
		TInt ret;
		RMobilePhone::TSmartCardApplicationEvent occuredEvent;
		TBool isUSimAppAffected = EFalse;
				
		if(theEvent.iAction == RMobilePhone::EScApplicationActivate)
			{
			ret=ActivateSmartCardApp(theEvent.iAID, isUSimAppAffected);
			occuredEvent = RMobilePhone::EScApplicationActivated;
			}
		else
			{
			ret=TerminateSmartCardApp(theEvent.iAID, isUSimAppAffected);
			occuredEvent = RMobilePhone::EScApplicationTerminated;
			}
			
		if (ret == KErrNone)
			{
			iEventPointer++;

			//notify any ScApp client if such notify request is pending
			if(iNotifyScInfo.iNotifyPending)
				{
				iNotifyScInfo.iNotifyPending=EFalse;
				*(RMobilePhone::TAID*)iNotifyScInfo.iNotifyData1=theEvent.iAID;
				*(RMobilePhone::TSmartCardApplicationEvent*)iNotifyScInfo.iNotifyData2=occuredEvent;
				iPhone->ReqCompleted(iNotifyScInfo.iNotifyHandle,KErrNone);
				}
				
			//notify any USimApp client if such notify request is pending
			if(isUSimAppAffected  && iNotifyUSimInfo.iNotifyPending)
				{
				iNotifyUSimInfo.iNotifyPending=EFalse;

				if(occuredEvent == RMobilePhone::EScApplicationActivated)
					{
					*(RMobilePhone::TAID*)iNotifyUSimInfo.iNotifyData1=theEvent.iAID;
					}
				else
					{
					*(RMobilePhone::TAID*)iNotifyUSimInfo.iNotifyData1=_L8("");
					}

				*(TInt*)iNotifyUSimInfo.iNotifyData2=iUSimAppList->Count();
				iPhone->ReqCompleted(iNotifyUSimInfo.iNotifyHandle,KErrNone);
				}
			}
		}//end if(iNotifyScInfo.iNotifyPending...
	}
	
TBool CSimPhoneSmartCardApp::FoundScAppTags()
/**
* Returns a value to indicate whether SCApp tags were found in the Config file
*
*/
	{
	return iFoundScAppTags;
	}
	
	
void CSimPhoneSmartCardApp::TSmartCardFile::GetFileInfo(RMobilePhone::TScFileInfoV5& aScFileInfo)
/**
* Gets the SmartCard file's File info
* 
* @param aScFileInfo The function passes back the file info through this reference
*/
	{
	aScFileInfo.iFileID = iFileID;
	aScFileInfo.iType = iType;
	aScFileInfo.iTotalLength = iTotalLength;
	aScFileInfo.iRecordLength = iRecordLength;
	aScFileInfo.iNumberRecords = iNumberRecords;		
	}

CSimPhoneSmartCardApp::TCyclicSmartCardFile::TCyclicSmartCardFile()
	:iOldestRecord(0)
	{}
		
TInt CSimPhoneSmartCardApp::TCyclicSmartCardFile::ReadFile(
		const RMobilePhone::TScFilePathWithAccessOffsets& aFilePathOffsets, TDes8* aReadBuffer)
/**
* Concrete implementation of the ReadFile() method for reading file data from a record based
* cyclic smart card file. Reads precisely one record (iRecordLength bytes).
*
* Note: Records are numbered from 1 to n NOT 0 to n-1
*
* @param aFilePathOffsets Information about which file to read (path) and where in the file to read data from (offsets)
* @param aReadBuffer The requested data is read into this buffer
*/
	{
	//check that the client has provided a buffer of sufficient size
	if(aReadBuffer->MaxSize() < iRecordLength)
		{
		return KErrOverflow;
		}
		
	//check that the client has specified a valid start offset
	else if(aFilePathOffsets.iStartOffset < 1 || aFilePathOffsets.iStartOffset > iNumberRecords)
		{
		LOGPHONE1("ERROR: File start offset information invalid.");
		return KErrMMEtelScRecordNotFound;	
		}
		
	else
		{
		//Var filepointer initially holds a pointer to the beginning of the specified record
		//The record to read is specified as an offset from the oldest record. I.e. Record 1 is the
		//newest record.
		TInt filePointer = iOldestRecord + (aFilePathOffsets.iStartOffset * iRecordLength);
		if(filePointer >= iTotalLength)
			{
			filePointer = filePointer - iTotalLength;	
			}
			
		aReadBuffer->SetLength(iRecordLength);
		aReadBuffer->FillZ();
		
		TInt index;
		
		for(index = 0; index < iRecordLength; index++)
			{
			(*aReadBuffer)[index] = iFileData[filePointer];
			filePointer++;
			}
		return KErrNone;		
		}
	}

TInt CSimPhoneSmartCardApp::TCyclicSmartCardFile::UpdateFile(
		const RMobilePhone::TScFilePathWithAccessOffsets& /*aFilePathOffsets*/, TDes8* aWriteBuffer)
/**
* Concrete implementation of the UpdateFile() method for updating file data in a record based
* cyclic smart card file. Updates precisely one record (iRecordLength bytes). The record that is
* updated is the oldest record.
*
* Note: Records are numbered from 1 to n NOT 0 to n-1
*
* @param aReadBuffer The data with which the file should be updated.
*/
	{
	//Check that the client has provided a buffer of sufficient size
	if(aWriteBuffer->Size() != iRecordLength)
		{
		return KErrMMEtelScWrongLength;
		}
	else
		{
		TInt filePointer = iOldestRecord ;
			
		TInt index;

		for(index = 0; index < iRecordLength; index++)
			{
			iFileData[filePointer] = (*aWriteBuffer)[index];
			filePointer++;
			}
		UpdateOldestRecordPointer();
		return KErrNone;
		}
	}
	
void CSimPhoneSmartCardApp::TCyclicSmartCardFile::UpdateOldestRecordPointer()
	{
	//IF the OldestRecord pointer is set to point to the beginning of the buffer
	if(iOldestRecord==0)
		{
		//Set it to point to the beginning of the last record in the buffer
		iOldestRecord = iTotalLength - iRecordLength;
		}
	//ELSE set it to point to the beginning of previous record (the second oldest record)
	else
		{
		iOldestRecord = iOldestRecord - iRecordLength;
		}
	}
	
	
TInt CSimPhoneSmartCardApp::TLinearSmartCardFile::ReadFile(
		const RMobilePhone::TScFilePathWithAccessOffsets& aFilePathOffsets, TDes8* aReadBuffer)
/**
* Concrete implementation of the ReadFile() method for reading file data from a record based
* linear fixed smart card file. Reads precisely one record (iRecordLength bytes).
*
* Note: Records are numbered from 1 to n NOT 0 to n-1
*
* @param aFilePathOffsets Information about which file to read (path) and where in the file to read data from (offsets)
* @param aReadBuffer The requested data is read into this buffer
*/
	{
	//check that the client has provided a buffer of sufficient size
	if(aReadBuffer->MaxSize() < iRecordLength)
		{
		return KErrOverflow;
		}
		
	//check that the client has specified a valid start offset
	else if(aFilePathOffsets.iStartOffset < 1 || aFilePathOffsets.iStartOffset > iNumberRecords)
		{
		LOGPHONE1("ERROR: File start offset information invalid.");
		return KErrMMEtelScRecordNotFound;	
		}
	else
		{
		TInt filePointer = (aFilePathOffsets.iStartOffset - 1) * iRecordLength;
		TInt index;

		aReadBuffer->SetLength(iRecordLength);
		aReadBuffer->FillZ();
		
		for(index = 0; index < iRecordLength; index++)
			{
			(*aReadBuffer)[index] = iFileData[filePointer];
			filePointer++;
			}
		return KErrNone;
		}
	}
	
TInt CSimPhoneSmartCardApp::TLinearSmartCardFile::UpdateFile(
		const RMobilePhone::TScFilePathWithAccessOffsets& aFilePathOffsets, TDes8* aWriteBuffer)
/**
* Concrete implementation of the UpdateFile() method for updating data in a record based
* linear fixed smart card file. Updates precisely one record (iRecordLength bytes).
*
* Note: Records are numbered from 1 to n NOT 0 to n-1
*
* @param aFilePathOffsets Information about which file to update (path) and where in the file to write data to (offsets)
* @param aReadBuffer The data with which the file should be updated.
*/
	{
	//check that the client has provided a buffer of sufficient size
	if(aWriteBuffer->Size() != iRecordLength)
		{
		return KErrMMEtelScWrongLength;
		}
	
	//check that the client has specified a valid start offset
	else if(aFilePathOffsets.iStartOffset < 1 || aFilePathOffsets.iStartOffset > iNumberRecords)
		{
		LOGPHONE1("ERROR: File start offset information invalid.");
		return KErrMMEtelScRecordNotFound;	
		}
	else
		{
		TInt filePointer = (aFilePathOffsets.iStartOffset - 1) * iRecordLength;
		TInt index;

		for(index = 0; index < iRecordLength; index++)
			{
			iFileData[filePointer] = (*aWriteBuffer)[index];
			filePointer++;
			}
		return KErrNone;
		}
	}
	
TInt CSimPhoneSmartCardApp::TTransparentSmartCardFile::ReadFile(
		const RMobilePhone::TScFilePathWithAccessOffsets& aFilePathOffsets, TDes8* aReadBuffer)
/**
* Concrete implementation of the ReadFile() method for reading file data from a binary transparent
* smart card file.
*
* @param aFilePathOffsets Information about which file to read (path) and where in the file to read data from (offsets)
* @param aReadBuffer The requested data is read into this buffer
*/
	{
	const TInt& bytesToRead = aFilePathOffsets.iCount;
	TInt filePointer = aFilePathOffsets.iStartOffset;

	//check that the client has provided a buffer of sufficient size
	if(aReadBuffer->MaxSize() < bytesToRead)
		{
		return KErrOverflow;
		}
	
	//check that the client has specified a valid start offset
	else if(aFilePathOffsets.iStartOffset >= (TUint)iTotalLength)
		{
		LOGPHONE1("ERROR: File start offset information invalid.");
		return KErrMMEtelScReferencedDataNotFound;	
		}
	
	//check the client is not requesting to read too many bytes, resulting in reading
	//off the end of the file
	else if((bytesToRead + filePointer) > iTotalLength)
		{
		LOGPHONE1("ERROR: Path offset information results in reading off the end of the file");
		return KErrMMEtelScEofReached;
		}
	else
		{
		aReadBuffer->SetLength(bytesToRead);
		aReadBuffer->FillZ();
		
		TInt index;
		
		for(index = 0; index < bytesToRead; index++)
			{
			(*aReadBuffer)[index] = iFileData[filePointer];
			filePointer++;
			}
		return KErrNone;
		}
	}
	
TInt CSimPhoneSmartCardApp::TTransparentSmartCardFile::UpdateFile(
		const RMobilePhone::TScFilePathWithAccessOffsets& aFilePathOffsets, TDes8* aWriteBuffer)
/**
* Concrete implementation of the UpdateFile() method for updating data in a binary transparent
* smart card file.
*
* @param aFilePathOffsets Information about which file to update (path) and where in the file to write data to (offsets)
* @param aReadBuffer The data with which the file should be updated.
*/
	{
	const TInt& bytesToWrite = aFilePathOffsets.iCount;
	TInt filePointer = aFilePathOffsets.iStartOffset;
	TInt index;

	//check that the client has provided a buffer of sufficient size
	if(aWriteBuffer->Size() != bytesToWrite)
		{
		//The length of the provided buffer does not match the number of bytes that client has requested
		//should be updated in the file.
		return KErrArgument;
		}

	//check that the client has specified a valid start offset
	else if(aFilePathOffsets.iStartOffset >= (TUint)iTotalLength)
		{
		LOGPHONE1("ERROR: File start offset information invalid.");
		return KErrMMEtelScReferencedDataNotFound;	
		}
	
	//check the client is not requesting to write too many bytes, resulting in writing
	//off the end of the file
	else if((bytesToWrite + filePointer) > iTotalLength)
		{
		LOGPHONE1("ERROR: Path offset information results in reading off the end of the file");
		return KErrMMEtelScEofReached;
		}
	else
		{
		for(index = 0; index < bytesToWrite; index++)
			{
			iFileData[filePointer] = (*aWriteBuffer)[index];
			filePointer++;
			}
			
		return KErrNone;
		}
	}
	
RMobilePhone::TAID CSimPhoneSmartCardApp::GetActiveUSim()
/**
* Returns the active aid (internally)
*
*/
	{
	return iActiveUSimApp;
	}
	
TInt CSimPhoneSmartCardApp::GetCurrentActiveUSimApplication(const TTsyReqHandle aTsyReqHandle, RMobilePhone::TAID* aAID)
/**
* Returns the active aid
*
* @param aReqHandle	The TSY request handle for this request.
* @param aAID	Returns the AID of the Active USim Application
* @return KErrNone
*/
	{
	if(iActiveUSimApp.Size() == 0)
		{
		iPhone->ReqCompleted(aTsyReqHandle, KErrMMEtelScApplicationNotActive);
		}
	else
		{
		*aAID=iActiveUSimApp;
		iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
		}
	return KErrNone;	
	}
	
TInt CSimPhoneSmartCardApp::GetCurrentActiveUSimApplicationCancel(const TTsyReqHandle aTsyReqHandle)	
/**
* Attempts to cancel a pending GetActiveUSimApplication request (unsuccessfully)
*
*/
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;		
	}
	

TInt CSimPhoneSmartCardApp::EnumerateUSimApplications(TTsyReqHandle aTsyReqHandle, TInt* aCount, RMobilePhone::TAID* aActiveAID)
/**
* Enumerates the number of USim applications in the UICC and returns the
* AID of the active application.
*
* @param aTsyReqHandle A handle belonging to the client that created the
*                    session with this TSY server.
* @param aCount Returns the number of USim applications.
* @param aActiveAID Returns the AID of the currently active application.
* @return KErrNone.
*/
	{
	*aCount=iUSimAppList->Count();
	aActiveAID->Copy(iActiveUSimApp);
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::EnumerateUSimApplicationsCancel(TTsyReqHandle aTsyReqHandle)
/**
*Attempts to cancel a pending EnumerateUSimApplications request (unsuccesfully).
*
*@param aTsyReqHandle A handle belonging to the client that created the
*                     session with this TSY server.
*/
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::GetUSimApplicationInfo(TTsyReqHandle aTsyReqHandle, TInt* aUSimAppIndex, TDes8* aInfo)
/**
* Retrieves information for a specified USim application
*
* @param aTsyReqHandle A handle belonging to the client that created the
*                      session with this TSY server.
* @param aUSimAppIndex Used to specify the index of the application.
* @param aInfo Returns the information of the specified appplication.
* @return KErrNone.
*/	
	{
	if(*aUSimAppIndex>=iUSimAppList->Count())
		{
		iPhone->ReqCompleted(aTsyReqHandle, KErrNotFound);
		return KErrNone;
		}
	else
		{
		TPckg<RMobilePhone::TUSimApplicationInfoV2>* infoPckg = 
			(TPckg<RMobilePhone::TUSimApplicationInfoV2>*)aInfo;
			
		RMobilePhone::TUSimApplicationInfoV2& info = (*infoPckg)();

		// Check that the data structure is supported by the simulated TSY version
		TInt err = iPhone->CheckSimTsyVersion(info);
		if(err != KErrNone)
			{
			iPhone->ReqCompleted(aTsyReqHandle, err);
			return KErrNone;
			}
	
		info.iAID = (*iUSimAppList)[*aUSimAppIndex]->iAID;
		info.iLabel = (*iUSimAppList)[*aUSimAppIndex]->iLabel;
		iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
		}
	
	return KErrNone;
	}

/**
Attempts to cancel a pending GetUSimApplicationInfo request
(unsuccesfully).

@param aTsyReqHandle A handle belonging to the client that created the
                     session with this TSY server.
*/
TInt CSimPhoneSmartCardApp::GetUSimApplicationInfoCancel(TTsyReqHandle aTsyReqHandle)
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::SetUSimApplicationStatus(TTsyReqHandle aTsyReqHandle, RMobilePhone::TAID* aAID, RMobilePhone::TUSimAppAction* aUsimAppAction)
/**
* Attempts to set the status of a specific USim application.
*
* @param aTsyReqHandle A handle belonging to the client that created the
*                      session with this TSY server.
* @param aAID The specific application's ID whose status is to be set.
* @param aUsimAppAction The status to apply to the application identified
*                       by aAID.
* @return KErrNone on completion of request, unless the aAID given is not
*         identifiable, in which case KErrArgument is returned.
*/
	{
	TInt ret;
	RMobilePhone::TAID aAidToAction;
	RMobilePhone::TSmartCardApplicationEvent aScEvent;
	TBool isUSimAppAffected = EFalse;
	
	//if the request is to activate a USimApp
	if(*aUsimAppAction == RMobilePhone::EUSimActivate)
		{
		//if another USimApp is active. 
		if(iActiveUSimApp.Size() != 0)
			{
			//terminate active USimApp
			aAidToAction = iActiveUSimApp;
			aScEvent = RMobilePhone::EScApplicationTerminated;
			isUSimAppAffected = EFalse;
			ret = TerminateSmartCardApp(aAidToAction, isUSimAppAffected);

			//if No error terminating
			if (ret == KErrNone)
				{			
				//notify ScApp client if notify request is pending
				if(iNotifyScInfo.iNotifyPending)
					{
					*(RMobilePhone::TAID*)iNotifyScInfo.iNotifyData1=aAidToAction;
					*(RMobilePhone::TSmartCardApplicationEvent*)iNotifyScInfo.iNotifyData2=aScEvent;
					iNotifyScInfo.iNotifyPending=EFalse;
					iPhone->ReqCompleted(iNotifyScInfo.iNotifyHandle,KErrNone);				
					}
				}
			}//end if(iActiveUSimApp.Size() != 0)
			
		//activate the requested application
		aAidToAction = *aAID;
		aScEvent = RMobilePhone::EScApplicationActivated;
		isUSimAppAffected = EFalse;
		ret=ActivateSmartCardApp(*aAID, isUSimAppAffected);

		//if no error activating
		if (ret == KErrNone)
			{
			//notify any ScApp client if such notify request is pending
			if(iNotifyScInfo.iNotifyPending)
				{
				iNotifyScInfo.iNotifyPending=EFalse;
				*(RMobilePhone::TAID*)iNotifyScInfo.iNotifyData1=aAidToAction;
				*(RMobilePhone::TSmartCardApplicationEvent*)iNotifyScInfo.iNotifyData2=aScEvent;
				iPhone->ReqCompleted(iNotifyScInfo.iNotifyHandle,KErrNone);
				}
			//notify any USimApp client if such notify request is pending
			if(iNotifyUSimInfo.iNotifyPending)
				{
				iNotifyUSimInfo.iNotifyPending=EFalse;
				*(RMobilePhone::TAID*)iNotifyUSimInfo.iNotifyData1=aAidToAction;
				*(TInt*)iNotifyUSimInfo.iNotifyData2=iUSimAppList->Count();
				iPhone->ReqCompleted(iNotifyUSimInfo.iNotifyHandle,KErrNone);
				}
			}
			
		//complete requests and return
		iPhone->ReqCompleted(aTsyReqHandle,ret);
		return KErrNone;
			
		}
	
	else
		{
		//the request is to terminate a USimApp
		aAidToAction = *aAID;
		aScEvent = RMobilePhone::EScApplicationTerminated;	

		//terminate active USimApp
		isUSimAppAffected = EFalse;
		ret = TerminateSmartCardApp(aAidToAction, isUSimAppAffected);

		//if No error terminating
		if (ret == KErrNone)
			{			
			//notify ScApp client if such notify request is pending
			if(iNotifyScInfo.iNotifyPending)
				{
				*(RMobilePhone::TAID*)iNotifyScInfo.iNotifyData1=aAidToAction;
				*(RMobilePhone::TSmartCardApplicationEvent*)iNotifyScInfo.iNotifyData2=aScEvent;
				iNotifyScInfo.iNotifyPending=EFalse;
				iPhone->ReqCompleted(iNotifyScInfo.iNotifyHandle,KErrNone);				
				}
			//notify any USimApp client if such notify request is pending
			if(iNotifyUSimInfo.iNotifyPending)
				{
				*(RMobilePhone::TAID*)iNotifyUSimInfo.iNotifyData1=_L8("");
				*(TInt*)iNotifyUSimInfo.iNotifyData2=iUSimAppList->Count();
				iNotifyUSimInfo.iNotifyPending=EFalse;
				iPhone->ReqCompleted(iNotifyUSimInfo.iNotifyHandle,KErrNone);
				}			
			}
		//complete requests and return
		iPhone->ReqCompleted(aTsyReqHandle,ret);
		return KErrNone;
		}
	}


TInt CSimPhoneSmartCardApp::SetUSimApplicationStatusCancel(TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending SetUSimApplicationStatus request (unsuccesfully).
*
* @param aTsyReqHandle A handle belonging to the client that created the
*                      session with this TSY server.
* @return KErrNone.
*/
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::NotifyUSimApplicationsInfoChange(const TTsyReqHandle aTsyReqHandle, TInt* aCount, RMobilePhone::TAID* aActiveAID)
/**
* Notifies the client when the specified USim application's information
* changes.
*
* @param aTsyReqHandle A handle belonging to the client that created the
*                      session with this TSY server.
* @param aCount Returns the total number of USim applications when the
*               request completes.
* @param aActiveAID The application's AID whose infromation change will
*                   be notified to the client.
* @return KErrNone.
*/
	{
	__ASSERT_ALWAYS(!iNotifyUSimInfo.iNotifyPending,SimPanic(ENotificationReqAlreadyOutstanding));

	TInt count=iSmartCardAppEventList->Count();

	if(iEventPointer<count)
		{
		if(iTimerStarted)
			{
			delete iTimer;
			iTimer = NULL;
			TRAP_IGNORE(iTimer=CSimTimer::NewL(iPhone));
			}

		TSmartCardAppEvent event=iSmartCardAppEventList->At(iEventPointer);
		
		if (iTimer != NULL)
			{
			iTimer->Start(event.iDuration,this);
			iTimerStarted = ETrue;
			}
		}

	iNotifyUSimInfo.iNotifyPending=ETrue;
	iNotifyUSimInfo.iNotifyHandle=aTsyReqHandle;
	iNotifyUSimInfo.iNotifyData1=aActiveAID;
	iNotifyUSimInfo.iNotifyData2=aCount;		
	return KErrNone;
	}


/**
*Attempts to cancel a pending NotifyUSimApplicationsInfoChange request.
*
*@param aTsyReqHandle A handle belonging to the client that created the
*                     session with this TSY server.
*@param KErrNone
*/
TInt CSimPhoneSmartCardApp::NotifyUSimApplicationsInfoChangeCancel(TTsyReqHandle aTsyReqHandle)
	{
	if(iNotifyUSimInfo.iNotifyPending)
		{
		iNotifyUSimInfo.iNotifyPending=EFalse;
		iPhone->ReqCompleted(aTsyReqHandle,KErrCancel);
		}
	return KErrNone;
	}
	

TInt CSimPhoneSmartCardApp::EnumerateScApplications(const TTsyReqHandle aTsyReqHandle, TUint* aCount)
/**
* Enumerates the number of Smart Card applications on the UICC
*
* @param aReqHandle	The TSY request handle for this request
* @param aCount	Returns the number of Smart Card applications
* @return KErrNone
*/

	{
	*aCount=iSmartCardAppList->Count();
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::EnumerateScApplicationsCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending EnumerateUSimApplications request (unsuccessfully)
*
* @param aReqHandle	The TSY request handle for this request
*/
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::GetScApplicationInfo(const TTsyReqHandle aTsyReqHandle, TInt* aAppIndex, TDes8* aInfo)
/**
* Retrieves information for a specified Smart Card application
*
* @param aReqHandle	The TSY request handle for this request
* @param aAppIndex	is used to specify the index of the application 
* @param aInfo	Returns the information of the specified appplication
* @return KErrNone
*/
	{
	if(*aAppIndex>=iSmartCardAppList->Count())
		{
		iPhone->ReqCompleted(aTsyReqHandle, KErrNotFound);
		}
	else
		{
		TPckg<RMobilePhone::TSmartCardApplicationInfoV5>* infoPckg = 
			(TPckg<RMobilePhone::TSmartCardApplicationInfoV5>*)aInfo;

		RMobilePhone::TSmartCardApplicationInfoV5& info = (*infoPckg)();

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

		info.iAID=iSmartCardAppList->At(*aAppIndex).iAID;
		info.iLabel=iSmartCardAppList->At(*aAppIndex).iLabel;
		if (info.ExtensionId() == KEtelExtMultimodeV6)
			{
			RMobilePhone::TUiccApplicationEapInfoV6& withEapInfo = static_cast<RMobilePhone::TUiccApplicationEapInfoV6&>(info);
			withEapInfo.iEapTypeList = iSmartCardAppList->At(*aAppIndex).iEapList;
			}
		iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
		}
	
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::GetScApplicationInfoCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending GetScApplicationInfo request (unsuccessfully)
*
*/
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::NotifyScApplicationInfoChange(const TTsyReqHandle aTsyReqHandle, 
		RMobilePhone::TAID* aAID, RMobilePhone::TSmartCardApplicationEvent* aEvent)
/**
* Notifies of any Smart Card application information changes
*
* @param aReqHandle	The TSY request handle for this request
* @param aAID				Return the AID of the application whose status has changed 
* @param aEvent				Return the event that took place on application aAID
* @return KErrNone
*/

	{		
	__ASSERT_ALWAYS(!iNotifyScInfo.iNotifyPending,SimPanic(ENotificationReqAlreadyOutstanding));
	
	TInt count=iSmartCardAppEventList->Count();

	if(iEventPointer<count)
		{
		if(iTimerStarted)
			{
			delete iTimer;
			iTimer = NULL;
			TRAP_IGNORE(iTimer=CSimTimer::NewL(iPhone));
			}
		
		TSmartCardAppEvent event=iSmartCardAppEventList->At(iEventPointer);
		
		if (iTimer != NULL)
			{
			iTimer->Start(event.iDuration,this);
			iTimerStarted = ETrue;
			}
		}
	iNotifyScInfo.iNotifyPending=ETrue;
	iNotifyScInfo.iNotifyHandle=aTsyReqHandle;
	iNotifyScInfo.iNotifyData1=aAID;
	iNotifyScInfo.iNotifyData2=aEvent;
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::NotifyScApplicationInfoChangeCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending NotifyUSimApplicationsInfoChange request
*
*/
	{
	if(iNotifyScInfo.iNotifyPending)
		{
		iNotifyScInfo.iNotifyPending=EFalse;
		iPhone->ReqCompleted(aTsyReqHandle,KErrCancel);
		}
	return KErrNone;
	}
	

TInt CSimPhoneSmartCardApp::SetScApplicationStatus(const TTsyReqHandle aTsyReqHandle, RMobilePhone::TAID* aAID, RMobilePhone::TSmartCardApplicationAction* aAction)
/**
* Sets the Application Status for specified smart card application
* 
* @param aReqHandle	The TSY request handle for this request
* @param aAID		The AID of the application whose status should be changed
* @param aAction	The action that should take place on the specified application
* @return KErrNone
*/
	{
	TInt ret;
	RMobilePhone::TSmartCardApplicationEvent event;
	TBool isUSimAppAffected = EFalse;
	
	if(*aAction==RMobilePhone::EScApplicationActivate)
		{
		event=RMobilePhone::EScApplicationActivated;
		ret=ActivateSmartCardApp(*aAID, isUSimAppAffected);
		}
	else
		{
		event=RMobilePhone::EScApplicationTerminated;
		ret=TerminateSmartCardApp(*aAID, isUSimAppAffected);
		}
		
	if(ret==KErrNone)
		{
		if(iNotifyScInfo.iNotifyPending)
			{
			iNotifyScInfo.iNotifyPending=EFalse;
			*(RMobilePhone::TAID*)iNotifyScInfo.iNotifyData1=*aAID;
			*(RMobilePhone::TSmartCardApplicationEvent*)iNotifyScInfo.iNotifyData2=event;
			iPhone->ReqCompleted(iNotifyScInfo.iNotifyHandle,KErrNone);
			}
		
		//If the affected ScApp is a USimApp...
		//notify any USimApp client if such notify request is pending
		if(isUSimAppAffected  && iNotifyUSimInfo.iNotifyPending)
			{
			iNotifyUSimInfo.iNotifyPending=EFalse;

			if(event == RMobilePhone::EScApplicationActivated)
				{
				*(RMobilePhone::TAID*)iNotifyUSimInfo.iNotifyData1=*aAID;
				}
			else
				{
				*(RMobilePhone::TAID*)iNotifyUSimInfo.iNotifyData1=_L8("");
				}

			*(TInt*)iNotifyUSimInfo.iNotifyData2=iUSimAppList->Count();
			iPhone->ReqCompleted(iNotifyUSimInfo.iNotifyHandle,KErrNone);
			}
		}

	iPhone->ReqCompleted(aTsyReqHandle,ret);
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::SetScApplicationStatusCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending SetScApplicationStatus request (unsuccessfully)
*
*/
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::SetUSimAppsSelectionMode(TTsyReqHandle aTsyReqHandle, RMobilePhone::TUSimSelectionMode* aUSimSelectionMode)
/**
* Sets the Selection mode for USim applications
*
* @param aReqHandle	The TSY request handle for this request
* @param aUSimSelectionMode	is used to specify the new selection mode for applications
* @return KErrNone
*/	
	{
	iCurrentSelection=*aUSimSelectionMode;
	if(iNotifyMode.iNotifyPending)
		{
		iNotifyMode.iNotifyPending=EFalse;
		*(RMobilePhone::TUSimSelectionMode*)iNotifyMode.iNotifyData=iCurrentSelection;
		iPhone->ReqCompleted(iNotifyMode.iNotifyHandle,KErrNone);
		}
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}
	
TInt CSimPhoneSmartCardApp::SetUSimAppsSelectionModeCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending SetUSimAppsSelectionMode request (unsuccessfully)
*
*/
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}	

TInt CSimPhoneSmartCardApp::GetUSimAppsSelectionMode(TTsyReqHandle aTsyReqHandle, RMobilePhone::TUSimSelectionMode* aUSimSelectionMode)
/**
* Gets the Selection mode for USim applications
*
* @param aReqHandle	The TSY request handle for this request
* @param aUSimSelectionMode	Returns the selection mode for applications
* @return KErrNone
*/	
	{
	*aUSimSelectionMode=iCurrentSelection;
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}
	
TInt CSimPhoneSmartCardApp::GetUSimAppsSelectionModeCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending GetUSimAppsSelectionMode request (unsuccessfully)
*
*/
	{
	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::NotifyUSIMAppsSelectionModeChange(TTsyReqHandle aTsyReqHandle, RMobilePhone::TUSimSelectionMode* aUSimSelectionMode)
/**
* Notifies for any Selection mode changes for USim applications
*
* @param aReqHandle	The TSY request handle for this request
* @param aUSimSelectionMode	Returns the new selection mode for applications
* @return KErrNone
*/	
	{
	__ASSERT_ALWAYS(!iNotifyMode.iNotifyPending,SimPanic(ENotificationReqAlreadyOutstanding));
	iNotifyMode.iNotifyPending=ETrue;
	iNotifyMode.iNotifyHandle=aTsyReqHandle;
	iNotifyMode.iNotifyData=aUSimSelectionMode;
	return KErrNone;
	}

TInt CSimPhoneSmartCardApp::NotifyUSIMAppsSelectionModeChangeCancel(TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending NotifyUSIMAppsSelectionModeChange request
*
*/
	{
	if(iNotifyMode.iNotifyPending)
		{
		iNotifyMode.iNotifyPending=EFalse;
		iPhone->ReqCompleted(aTsyReqHandle,KErrCancel);
		}
	return KErrNone;
	}

	
TInt CSimPhoneSmartCardApp::GetScFileInfo(const TTsyReqHandle aTsyReqHandle, 
		const RMobilePhone::TScFilePath& aFilePathId, TDes8* aInfo)
/**
* Gets information about the specified smart card file
*
* @param aReqHandle	The TSY request handle for this request
* @param aFilePathId Used to specify path of the file for which information should be retrieved
* @param aInfo Used to return the retrieved file information
*/
	{
	
	LOGPHONE1("CSimPhoneSmartCardApp::GetScFileInfo called");

	RMobilePhone::TScFileInfoV5Pckg *scFileInfoPckg = reinterpret_cast<RMobilePhone::TScFileInfoV5Pckg*>(aInfo);
	RMobilePhone::TScFileInfoV5 &scFileInfo = (*scFileInfoPckg)();

	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(scFileInfo);
	if(err != KErrNone)
		{
		iPhone->ReqCompleted(aTsyReqHandle, err);
		return KErrNone;
		}
		
	if(scFileInfo.ExtensionId() == KEtelExtMultimodeV5)
		{
		TSmartCardFile* scFile = NULL;
		TInt ret = FindScFile(aFilePathId, scFile);
		if(ret==KErrNone)
			{
			scFile->GetFileInfo(scFileInfo);
			iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
			}
		else
			{
			iPhone->ReqCompleted(aTsyReqHandle,ret);
			}
		}

	else
		{
		iPhone->ReqCompleted(aTsyReqHandle,KErrCorrupt);
		}	
	
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::GetScFileInfoCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending GetScFileInfo request (unsuccessfully)
*
*/
	{
	LOGPHONE1("CSimPhoneSmartCardApp::GetScFileInfoCancel called");

	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::ReadScFile(const TTsyReqHandle aTsyReqHandle, 
		const RMobilePhone::TScFilePathWithAccessOffsets& aFilePathOffsets, TDes8* aReadBuffer)
/**
* Reads a specified amount of data from a specified smart card file
*
* @param aReqHandle	The TSY request handle for this request
* @param aFilePathOffsets Used to specify which file to read (path) and where in the file to read data from (offsets)
* @param aReadBuffer Used to return the read file data
*/
	{
	TSmartCardFile* scFile = NULL;
	TInt ret = FindScFile((RMobilePhone::TScFilePath)aFilePathOffsets, scFile);
	if(ret==KErrNone)
		{
		ret = scFile->ReadFile(aFilePathOffsets, aReadBuffer);
		}
	
	iPhone->ReqCompleted(aTsyReqHandle,ret);
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::ReadScFileCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending ReadScFileInfo request (unsuccessfully)
*
*/
	{
	LOGPHONE1("CSimPhoneSmartCardApp::ReadScFileInfoCancel called");

	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::UpdateScFile(const TTsyReqHandle aTsyReqHandle, 
		const RMobilePhone::TScFilePathWithAccessOffsets& aFilePathOffsets, TDes8* aWriteBuffer)
/**
* Writes a specified amount of data to a specified smart card file
*
* @param aReqHandle	The TSY request handle for this request
* @param aFilePathOffsets Used to specify which file to update (path) and where in the file to write data to (offsets)
* @param aReadBuffer Used to return the read file data
*/
	{
	TSmartCardFile* scFile = NULL;
	TInt ret = FindScFile((RMobilePhone::TScFilePath)aFilePathOffsets, scFile);
	if(ret==KErrNone)
		{
		ret = scFile->UpdateFile(aFilePathOffsets, aWriteBuffer);
		}
	
	iPhone->ReqCompleted(aTsyReqHandle,ret);
	return KErrNone;
	}


TInt CSimPhoneSmartCardApp::UpdateScFileCancel(const TTsyReqHandle aTsyReqHandle)
/**
* Attempts to cancel a pending UpdateScFileInfo request (unsuccessfully)
*
*/
	{
	LOGPHONE1("CSimPhoneSmartCardApp::UpdateScFileInfoCancel called");

	iPhone->ReqCompleted(aTsyReqHandle, KErrNone);
	return KErrNone;
	}


void CSimPhoneSmartCardApp::ParseSmartCardApplicationInfoL()
/**
* Parses all Smart Card Application related tags from the config file
*
*/
	{
	const CTestConfigItem* item=NULL;
	TInt ret=KErrNone;
	TInt index;
	TPtrC8 activeUSimApp, aid, label, eap;
	TInt type;
	
	TSmartCardApplication appInfo;
	
	TRAP_IGNORE(iTimer=CSimTimer::NewL(iPhone));
	

	LOGPHONE1("Starting to Parse MaxActiveSmartCardApp Info");
	iMaxActiveSmartCardApps = CfgFile()->ItemValue(KMaxActiveSmartCardApps ,KDefaultMaxActiveSmartCardApps);


	LOGPHONE1("Starting to Parse ActiveUSIMApp Info");
	activeUSimApp.Set(CfgFile()->ItemValue(KActiveUSIMApp, KEmptyString));
	if(activeUSimApp.Length() == 0)
		{
		LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: ACTIVE USIM APP NOT SPECIFIED!");
		}


	TInt count = CfgFile()->ItemCount(KSmartCardAppInfo);
	iSmartCardAppList=new(ELeave) CArrayFixFlat<TSmartCardApplication>(count+1);

	LOGPHONE1("Starting to Load and Parse Smart Card Application Info");
	for(index=0;index<count;index++)
		{
		item=CfgFile()->Item(KSmartCardAppInfo,index);
		if(!item)
			{
			break;
			}
		
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,aid);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD APP INFO TAG");
			continue;
			}
		else
			{
			appInfo.iAID.Copy(aid);
			}
			
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,label);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD APP INFO TAG");
			continue;
			}
		else 
			{
			appInfo.iLabel.Copy(label);
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,type);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD APP INFO TAG");
			continue;
			}
		else
			{
			appInfo.iAppType = (TSmartCardAppType)type;
			}
		
		if((appInfo.iAppType == EUSimApp) && (appInfo.iAID == activeUSimApp))
			{
			//Make this the active USim App
			iActiveUSimApp = appInfo.iAID;
			appInfo.iAppStatus = EActive;
			iNumActiveSmartCardApps++;
			}
		else
			{
			appInfo.iAppStatus = EInactive;
			}

		ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 3, eap);
		if (ret != KErrNone)
			{
			LOGPHONE2("CONFIGURATION FILE PARSING: BAD OR NO (OPTIONAL) EAP LIST @ SMARTCARD APP INFO TAG [%d]", index);
			_LIT8(emptyEapList, "");
			eap.Set(emptyEapList);
			}
		// Append empty string if no info is given
		appInfo.iEapList.Copy(eap);

		iSmartCardAppList->AppendL(appInfo);
		iFoundScAppTags = ETrue;
		}//end of FOR loop
		
	if(iActiveUSimApp.Length() == 0)
		{
		LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: AID FOR ACTIVE USIM APP NOT FOUND!");
		}
		

	count=CfgFile()->ItemCount(KSmartCardAppEvent);
	iSmartCardAppEventList=new(ELeave) CArrayFixFlat<TSmartCardAppEvent>(count+1);
	TSmartCardAppEvent appEvent;
	TInt duration, action;
	
	LOGPHONE1("Starting to Load and Parse Smart Card Application Event Info");

	for(index=0;index<count;index++)
		{
		item=CfgFile()->Item(KSmartCardAppEvent,index);
		if(!item)
			{
			break;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0, duration);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMART CARD APP EVENT TAG");
			continue;
			}
		else
			{
			appEvent.iDuration=duration;
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1, aid);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING; BAD SMART CARD APP EVENT TAG");
			continue;
			}
		else 
			{
			appEvent.iAID.Copy(aid);
			}

		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2, action);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING; BAD SMART CARD APP EVENT TAG");
			continue;
			}
		else
			{
			appEvent.iAction = (RMobilePhone::TSmartCardApplicationAction)action;
			}

		iSmartCardAppEventList->AppendL(appEvent);
		}//end FOR loop	
	}


void CSimPhoneSmartCardApp::ParseSmartCardFileInfoL()
/**
* Parses all Smart Card File related tags from the config file
*
*/
	{
	const CTestConfigItem* item=NULL;
	TInt ret=KErrNone;
	TPtrC8 fileId, filePath, fileData;
	TInt aidIndex, fileType, fileLength, recordLength, numRecords, index;
	TSmartCardFile* file = NULL;
	
	LOGPHONE1("Starting to Parse Smart Card File Info");
	TInt count = CfgFile()->ItemCount(KSmartCardFile);
	iSmartCardFileList = new(ELeave) CArrayPtrFlat<TSmartCardFile>(count+1);

	for(index=0;index<count;index++)
		{
		item=CfgFile()->Item(KSmartCardFile,index);
		if(!item)
			{
			break;
			}
			
		//Get the file's type information
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,fileType);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE TAG");
			continue;
			}
		else
			{
			switch ((RMobilePhone::TScFileType)fileType)
				{
			case RMobilePhone::ELinearFixed:
				file = new(ELeave) TLinearSmartCardFile;
				break;
			case RMobilePhone::ECyclic:
				file = new(ELeave) TCyclicSmartCardFile;
				break;
			case RMobilePhone::ETransparent:
				file = new(ELeave) TTransparentSmartCardFile;
				break;
			default:
				LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING:");
				LOGPHONE1("ENCOUNTERED UNKNOWN SMART CARD FILE TYPE.");
				continue;				
				}
			file->iType = (RMobilePhone::TScFileType)fileType;
			}

		//Get the FID of the file
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,fileId);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE TAG");
			delete file;
			continue;
			}
		//check that the FID is precisely 4 bytes long	
		else if(fileId.Length() != KMaxHexFIDLen)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE FID");
			delete file;
			continue;
			}
		else
			{
			TBuf8<KMaxBinFIDLen> fileIdBuffer;
			TextToBin(fileId, fileIdBuffer);
			file->iFileID = (RMobilePhone::TScFileID)((fileIdBuffer[0] <<8) + (fileIdBuffer[1]));
			}
			
		//Get the Index of the AID of the application the file belongs to
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,aidIndex);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE TAG");
			delete file;
			continue;
			}
		else
			{
			file->iAIDIndex = aidIndex;
			}
			
		//Get the file's path information
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,filePath);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE TAG");
			delete file;
			continue;
			}
		else
			{
			file->iPath = filePath;
			}
		
		//Get the information about the total length of the file
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,4,fileLength);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE TAG");
			delete file;
			continue;
			}
		else
			{
			file->iTotalLength = fileLength;
			}
			
		//Get information about the length of each record in the file
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,5,recordLength);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE TAG");
			delete file;
			continue;
			}
		else
			{
			file->iRecordLength = recordLength;
			}
			
		//Get information about the number of records in the file
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,6,numRecords);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE TAG");
			delete file;
			continue;
			}
		else
			{
			file->iNumberRecords = numRecords;
			}
		
		//If the file is Cyclic or Linear record based file...
		//Check that record Length * number of records = Total length of file
		if((fileType != RMobilePhone::ETransparent) && ((recordLength*numRecords) != fileLength))
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING:...");
			LOGPHONE1("...Record Length * Number of Records != File Length");
			delete file;
			continue;
			}
			
		//Get file data
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,7,fileData);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE TAG");
			delete file;
			continue;
			}
		else if((fileData.Length() % 2 ) != 0)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD SMARTCARD FILE DATA");
			continue;
			}
		else
			{				
			TBuf8<KMaxFileSize> fileDataBuffer;
			TextToBin(fileData, fileDataBuffer);
			if(fileDataBuffer.Length() != fileLength)
				{
				LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING:INCONSISTANT DATA FILE LENGTH");
				delete file;
				continue;		
				}
			file->iFileData = fileDataBuffer;
			}		
		
		iSmartCardFileList->AppendL(file);	
		}//end FOR Loop
	}
	
void CSimPhoneSmartCardApp::MapUSimAppsL()
	{
	iUSimAppList=new(ELeave) RPointerArray<TSmartCardApplication>(iSmartCardAppList->Count() + 1);
	TInt index;
	TSmartCardApplication* SmartCardApp = NULL;
	
	//iterate through the list of smart card applications
	for(index=0; index < iSmartCardAppList->Count(); index++)
		{
		SmartCardApp = &(iSmartCardAppList->At(index));
		
		//if the smart card application is a USim App
		if(SmartCardApp->iAppType == EUSimApp)
			{
			//add a pointer to it in the list of USim Apps
			iUSimAppList->AppendL(SmartCardApp);
			}
		}//end FOR loop

	}
	
	
TInt CSimPhoneSmartCardApp::FindScFile(const RMobilePhone::TScFilePath& aFilePathInfo, TSmartCardFile*& aSmartCardFile)
/**
 * Helper function
 *
 * Searches through the SimTSYs internal list of Smart Card files and returns a pointer
 * to the requested file. If the file is under an application a check is done to ensure
 * the application is active.
 *
 * @param aFilePathInfo Some information about the file that the client is looking for
 * @param aSmartCardFile A pointer to the Smart Card File the client was looking for
 */
	{
	TInt index;
	TInt aidIndex = KNoAID;
	
	//If the user has specified a file that is under an application
	if(aFilePathInfo.iAID.Size() != 0)
		{
		//search the list of Smart Card Applications and get an index for the specifed AID
		for(index=0; index < iSmartCardAppList->Count(); index++)
			{
			if(iSmartCardAppList->At(index).iAID == aFilePathInfo.iAID)
				{
				aidIndex = index;
				break;
				}
			}
			
		//if the AID is not found
		if(aidIndex == KNoAID)
			{
			return KErrNotFound;
			}
		else
			{
			//return an error if the specified application is inactive
			if(iSmartCardAppList->At(aidIndex).iAppStatus == EInactive)
				{
				return KErrMMEtelScApplicationNotActive;
				}
			}
		}//end if(aFilePathInfo.iAID.Size() != 0)
	
	//Find the specified file
	TSmartCardFile* scFile=NULL;
		
	for(index = 0; index < iSmartCardFileList->Count(); index++)
		{
		scFile = iSmartCardFileList->At(index);
		if((scFile->iAIDIndex == aidIndex) && (scFile->iPath == aFilePathInfo.iPath))
			{
			aSmartCardFile = scFile;
			return KErrNone;
			}
		}
		
	return KErrMMEtelScFileNotFound;
	}


TInt CSimPhoneSmartCardApp::ActivateSmartCardApp(const RMobilePhone::TAID aAID, TBool& aActivatedUSimApp)
/**
* Performs the logic for Activating a Smart Card application
*
* @param aAID The AID of the application that should be activated
*/
	{
	TInt index;
	TSmartCardApplication* smartCardApp = NULL;

	for(index=0; index < iSmartCardAppList->Count(); index++)
		{
		smartCardApp = &(iSmartCardAppList->At(index));
		if(smartCardApp->iAID == aAID)	
			{
			//Check that 1)iMaxActiveSmartCardApps will not be exceeded by activating
			//a new smart card application; 2)The application is not already active
			if((iNumActiveSmartCardApps<iMaxActiveSmartCardApps) &&
				(smartCardApp->iAppStatus != CSimPhoneSmartCardApp::EActive))
				{
				//if we are activating a USIM and another USIM app is already active,
				//fail with KErrAlreadyExists
				if((smartCardApp->iAppType == CSimPhoneSmartCardApp::EUSimApp) &&
					(iActiveUSimApp.Length() != 0))
					{
					return KErrAlreadyExists;
					}
				else
					{
					smartCardApp->iAppStatus = CSimPhoneSmartCardApp::EActive;
					iNumActiveSmartCardApps++;

					if(smartCardApp->iAppType == CSimPhoneSmartCardApp::EUSimApp)
						{
						iActiveUSimApp = smartCardApp->iAID;
						aActivatedUSimApp = ETrue;
						}
					
					return KErrNone;
					}
				}

			else
				{
				if(smartCardApp->iAppStatus == CSimPhoneSmartCardApp::EActive)
					{
					LOGPHONE1("REACTIVATING AN ALREADY ACTIVE APPLICATION");
					return KErrNone;
					}
				else
					{
					//iMaxActiveSmartCardApps will be exceeded
					LOGPHONE1("WARNING: CANNOT PROCESS ACTIVATING APPLICATION");
					return KErrMMEtelScMaxApplicationsActive;
					}
				}

			}
		}//end for loop
		
		LOGPHONE1("WARNING: AID NOT FOUND. CANNOT PROCESS EVENT");
		return KErrNotFound;
	}


TInt CSimPhoneSmartCardApp::TerminateSmartCardApp(const RMobilePhone::TAID aAID, TBool& aTerminatedUSimApp)
/**
* Performs the logic for terminating a Smart Card application
*
* @param aAID The AID of the application that should be terminated
*/
	{
	TInt index;
	TSmartCardApplication* smartCardApp = NULL;
	for(index=0; index < iSmartCardAppList->Count(); index++)
		{
		smartCardApp = &(iSmartCardAppList->At(index));
		if(smartCardApp->iAID == aAID)	
			{	
			if(smartCardApp->iAppStatus == CSimPhoneSmartCardApp::EActive)
				{
				smartCardApp->iAppStatus = CSimPhoneSmartCardApp::EInactive;
				iNumActiveSmartCardApps--;
				
				if(smartCardApp->iAppType == CSimPhoneSmartCardApp::EUSimApp)
					{
					iActiveUSimApp.Zero();
					aTerminatedUSimApp = ETrue;
					}
				
				return KErrNone;
				}
			else
				{
				LOGPHONE1("ATTEMPTED TO TERMINATE NON-ACTIVE APPLICATION");
				return KErrMMEtelScApplicationNotActive;
				}
			}
	
		}//end for loop
	LOGPHONE1("WARNING: AID NOT FOUND. CANNOT PROCESS EVENT");
	return KErrNotFound;
	}
	
	
void CSimPhoneSmartCardApp::TextToBin(const TDesC8& aSrc, TDes8& aDst)
/**
 * Helper function
 *
 * Converts a text descriptor containing Hex information to binary.
 *
 * @param aSrc The input buffer
 * @param aDst The output buffer
 */
	{
	//LOG_ASSERT((aSrc.Length() % 2) == 0, "Not passed in an even-length string?");

	aDst.SetLength(aSrc.Length() / 2);

	for (TInt i = 0; i < aSrc.Length(); i += 2)
		{
		TInt val = 0;
		if ((aSrc[i] >= '0') && (aSrc[i] <= '9'))
			{
			val = ((aSrc[i] - '0') << 4);
			}
		else if ((aSrc[i] >= 'A') && (aSrc[i] <= 'F'))
			{
			val = ((aSrc[i] - 'A' + 10) << 4);
			}
		else
			{
			__DEBUGGER();
			}

		if ((aSrc[i+1] >= '0') && (aSrc[i+1] <= '9'))
			{
			val += (aSrc[i+1] - '0');
			}
		else if ((aSrc[i+1] >= 'A') && (aSrc[i+1] <= 'F'))
			{
			val += (aSrc[i+1] - 'A' + 10);
			}
		else
			{
			__DEBUGGER();
			}

		aDst[i/2] = (TUint8) val;
		}
	}
