telephonyserverplugins/simtsy/src/CSimCallForwarding.cpp
changeset 0 3553901f7fa8
child 15 fc69e1e37771
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/simtsy/src/CSimCallForwarding.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,1089 @@
+// 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 functionality required to provide clients with
+// callforwarding status and registration information.
+// 
+//
+
+/**
+ @file
+*/
+
+#include <testconfigfileparser.h>
+#include "CSimCallForwarding.h"
+#include "CSimPhone.h"
+#include "Simlog.h"
+
+const TInt KSettingListGranularity=5;	// < The granularity used for parameter list arrays.
+const TInt KInvalidTimeout = -1;        // Value used when timeout period does not matter
+const TInt KMobServiceIndxStart = 1;
+const TInt KMobServiceIndxEnd   = 6;
+
+CSimCallForwarding* CSimCallForwarding::NewL(CSimPhone* aPhone)
+/**
+ * Standard two-phase constructor.
+ * @param aPhone				The parent phone object.
+ * @return CSimNetworkStatus	The new network status class.
+ */
+	{
+	CSimCallForwarding* self=new(ELeave) CSimCallForwarding(aPhone);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CSimCallForwarding::CSimCallForwarding(CSimPhone* aPhone)
+		: iPhone(aPhone)
+/**
+ * Trivial first phase construction.
+ * @param aPhone				The parent phone object.
+ */
+	{
+	}
+
+void CSimCallForwarding::ConstructL()
+	/** 
+	Second phase of 2-Phase Constructor
+ 	Retrieves all the Call forwarding and Identity services tags from the config file
+	*/
+	{
+	LOGCALL1("Starting to parse Call Forwarding config parameters...");
+
+	iIdentityServiceStatus=new(ELeave) CArrayFixFlat<TIdentityServiceStatus>(KSettingListGranularity);
+	
+	iGetCFStatus = new(ELeave) CArrayPtrFlat<CListReadAllAttempt>(1);
+	FindAndCreateCFListL();
+	
+	// Read in the Identity services information
+	TInt count=CfgFile()->ItemCount(KIdentityServiceStatus);
+	const CTestConfigItem* item=NULL;
+	TInt ret=KErrNone;
+	for(TInt i=0;i<count;i++)
+		{
+		item=CfgFile()->Item(KIdentityServiceStatus,i);
+		if(!item)
+			break;
+
+		TInt status, service;
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,service);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("service",ret,0,&KIdentityServiceStatus);
+			continue;
+			}
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,status);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("status",ret,1,&KIdentityServiceStatus);
+			continue;
+			}
+			
+		TIdentityServiceStatus identityServiceStatus;
+		identityServiceStatus.iService = static_cast<RMobilePhone::TMobilePhoneIdService>(service);
+		identityServiceStatus.iStatus = static_cast<RMobilePhone::TMobilePhoneIdServiceStatus>(status);
+		iIdentityServiceStatus->AppendL(identityServiceStatus);
+		}
+		
+	LOGCALL1("...Finished parsing Call Forwarding config parameters...");
+	}
+
+CSimCallForwarding::~CSimCallForwarding()
+	/** 
+	Destroy all the objects constructed.
+	*/
+	{
+	if (iIdentityServiceStatus != NULL)
+		{
+		iIdentityServiceStatus->Delete(0,iIdentityServiceStatus->Count());
+		delete iIdentityServiceStatus;
+		}
+	delete iCFList;
+	if (iGetCFStatus)
+		iGetCFStatus->ResetAndDestroy();
+	delete iGetCFStatus;
+	}
+
+
+TInt CSimCallForwarding::ExtFunc(const TTsyReqHandle aReqHandle,const TInt aIpc, const TDataPackage& aPckg)
+	{
+	/**
+	Handles all the Call forwarding APIs
+	@param aReqHandle to the request
+	@param Ipc unique identifier of the method to call
+	@param aPckg contains arguments of the method to call
+	*/
+	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 EMobilePhoneSetCallForwardingStatus:
+		return SetCallForwardingStatus(aReqHandle,
+			reinterpret_cast<RMobilePhone::TMobilePhoneCFCondition*>(dataPtr),
+			reinterpret_cast<RMobilePhone::TMobilePhoneCFChangeV1*>(dataPtr2));
+	case EMobilePhoneNotifyCallForwardingStatusChange:
+		return NotifyCallForwardingStatusChange(aReqHandle, reinterpret_cast<RMobilePhone::TMobilePhoneCFCondition*>(dataPtr));
+	case EMobilePhoneGetIdentityServiceStatus:
+		return GetIdentityServiceStatus(aReqHandle, 
+			reinterpret_cast<RMobilePhone::TMobilePhoneIdService*>(dataPtr),
+			reinterpret_cast<RMobilePhone::TMobilePhoneIdServiceStatus*>(dataPtr2));
+	case EMobilePhoneGetCallForwardingStatusPhase1:
+		return GetCallForwardingStatusPhase1(aReqHandle, 
+			REINTERPRET_CAST(CRetrieveMobilePhoneCFList::TGetCallForwardingRequest*, dataPtr), 
+			REINTERPRET_CAST(TInt*, dataPtr2));
+	case EMobilePhoneGetCallForwardingStatusPhase2:
+		return GetCallForwardingStatusPhase2(aReqHandle, 
+			REINTERPRET_CAST(RMobilePhone::TClientId*, dataPtr), aPckg.Des2n());			
+	default:
+		break;
+		}
+	return KErrNotSupported;
+	}
+	
+TInt CSimCallForwarding::CancelService(const TInt aIpc, const TTsyReqHandle aReqHandle)
+	/**
+	Cancels Call forwarding requests
+	@param ipc request to cancel
+	@param aReqHandle Handle to the request
+	*/
+	{
+	switch(aIpc)
+		{
+	case EMobilePhoneSetCallForwardingStatus:
+		return SetCallForwardingStatusCancel(aReqHandle);
+	case EMobilePhoneNotifyCallForwardingStatusChange:
+		return NotifyCallForwardingStatusChangeCancel(aReqHandle);
+	case EMobilePhoneGetIdentityServiceStatus:
+		return GetIdentityServiceStatusCancel(aReqHandle);
+	default:
+		break;
+		}
+	return KErrNone;
+	}
+	
+void CSimCallForwarding::FindAndCreateCFListL()
+	{
+	/**
+	Creates the Call forwarding list from the config file
+	*/
+	LOGCALL1("CSimPhone::FindAndCreateCFListL");
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 entry;
+
+	if(iCFList)
+		delete iCFList;
+	iCFList=NULL;
+
+	iCFList = CMobilePhoneCFList::NewL();
+	TInt count=CfgFile()->ItemCount(KCFList);
+	const CTestConfigItem* item=NULL;
+	TInt ret=KErrNone;
+
+	LOGCALL1("Starting to Load and Parse CFList Config parameters");
+	
+	TInt i;
+	for(i=0;i<count;i++)
+		{
+		item=CfgFile()->Item(KCFList,i);
+		if(!item)
+			break;
+		
+		TPtrC8 number;
+		TInt condition, serviceGroup, status, timeout; // valid for CFRNy only
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,condition);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("condition",ret,0,&KCFList);
+			continue;
+			}
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,serviceGroup);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("serviceGroup",ret,1,&KCFList);
+			continue;
+			}
+
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,status);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("status",ret,2,&KCFList);
+			continue;
+			}
+
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,timeout);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("timeout",ret,3,&KCFList);
+			continue;
+			}
+		
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,4,number);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("number",ret,4,&KCFList);
+			continue;
+			}
+		
+		entry.iServiceGroup=(RMobilePhone::TMobileService)serviceGroup;
+		entry.iNumber.iTelNumber.Copy(number);
+		entry.iTimeout=timeout;
+		entry.iCondition=(RMobilePhone::TMobilePhoneCFCondition)condition;
+		entry.iStatus=(RMobilePhone::TMobilePhoneCFStatus)status;
+		iCFList->AddEntryL(entry);
+		}//end for
+	
+	//CFlist must define entries for each condition even if unknown
+	//fill up table if it misses conditions:
+	
+	RArray<TBool> serviceArray;
+	//voice, auxVoice, data, packet, fax, sms, all;
+
+	CleanupClosePushL(serviceArray);
+
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 extraEntry;
+
+	for (TInt j=1;j<5;j++)//loop conditions
+		{
+		TInt serviceFound=EFalse;
+		TInt index;
+		extraEntry.iCondition=static_cast<RMobilePhone::TMobilePhoneCFCondition>(j);
+		serviceArray.Reset();
+		for(TInt h=0;h<8;h++)
+			{
+			serviceArray.Append(EFalse);
+			}
+		
+		for (TInt k=0;k<count;k++)//loop entries
+			{
+			entry=iCFList->GetEntryL(k);
+			if(entry.iCondition==static_cast<RMobilePhone::TMobilePhoneCFCondition>(j))
+				{
+				index = (TInt)entry.iServiceGroup;
+				serviceArray[index]=ETrue;
+				}
+			}
+		
+		if (!serviceArray[7])//(all services)
+			{
+			for (TInt l=1;l<7;l++)
+				{
+				if (serviceArray[l])
+					serviceFound=ETrue;										
+				}
+			//no service defined for this condition
+			if(!serviceFound)
+				{
+				extraEntry.iServiceGroup=RMobilePhone::EAllServices;
+				extraEntry.iStatus=RMobilePhone::ECallForwardingStatusNotRegistered;
+				iCFList->AddEntryL(extraEntry);
+				}
+			//some services defined in table
+			else
+				{
+				for (TInt m=1;m<7;m++)
+					{
+					if (!serviceArray[m])
+						{
+						extraEntry.iServiceGroup=static_cast<RMobilePhone::TMobileService>(m);
+						extraEntry.iStatus=RMobilePhone::ECallForwardingStatusNotRegistered;
+						iCFList->AddEntryL(extraEntry);
+						}
+					}//end for
+				}//end else
+			}//end if
+		}//end for
+		
+	CleanupStack::PopAndDestroy(&serviceArray);	//Destroying serviceArray to free the memory
+	}
+
+TInt CSimCallForwarding::GetIdentityServiceStatus(const TTsyReqHandle aReqHandle, RMobilePhone::TMobilePhoneIdService* aService, RMobilePhone::TMobilePhoneIdServiceStatus* aStatus)
+	/**
+	Gets the status of the identity services
+	@param aReqHandle handle to the request
+	@param aService service that the client is interested in
+	@param aStatus of the identity service
+	*/
+	{
+	RMobilePhone::TMobilePhoneIdServiceStatus status;
+	status = RMobilePhone::EIdServiceUnknown;
+	TInt count = iIdentityServiceStatus->Count();
+	for(TInt i=0; i<count; i++)
+		{
+		if(iIdentityServiceStatus->At(i).iService == *aService)
+			{
+			status = iIdentityServiceStatus->At(i).iStatus;
+			break;
+			}
+		}
+	*aStatus = status;
+	iPhone->ReqCompleted(aReqHandle, KErrNone);
+	return KErrNone;
+	}
+	
+TInt CSimCallForwarding::GetIdentityServiceStatusCancel(const TTsyReqHandle aReqHandle)
+	/**
+	Cancels the request to get the status of the identity services
+	@param aReqHandle hadle to the request
+	*/
+	{
+	iPhone->ReqCompleted(aReqHandle,KErrCancel);
+	return KErrNone;
+	}
+	
+TInt CSimCallForwarding::NotifyCallForwardingStatusChange(const TTsyReqHandle aReqHandle, RMobilePhone::TMobilePhoneCFCondition* aCF)
+	/**
+	Requests to be notified of call forwarding status change
+	@param aReqHandle handle to the request
+	@param aCF condition for which the client wants to be notified
+	 */
+	{
+	__ASSERT_ALWAYS(!iCFNotification.iCFChangeInfoNotificationPending,SimPanic(ENotificationReqAlreadyOutstanding));
+
+	iCFNotification.iCFChangeInfoNotificationPending=ETrue;
+	iCFNotification.iCFChangeInfoReqHandle=aReqHandle;
+	iCFNotification.iCurrentCFCondition=aCF;
+	LOGCALL1("Finished CSimCallForwarding::NotifyCallForwardingStatusChange");
+	return KErrNone;
+	}
+	
+TInt CSimCallForwarding::NotifyCallForwardingStatusChangeCancel(const TTsyReqHandle aReqHandle)
+	/**
+	Cancels the request to be notified of call forwarding status change
+	@param aReqHandle handle to the request
+	*/
+	{
+	if(iCFNotification.iCFChangeInfoNotificationPending)
+		{
+		iCFNotification.iCFChangeInfoNotificationPending=EFalse;
+		iPhone->ReqCompleted(aReqHandle,KErrCancel);
+		}
+	return KErrNone;
+	}
+	
+TInt CSimCallForwarding::SetCallForwardingStatus(const TTsyReqHandle aReqHandle, RMobilePhone::TMobilePhoneCFCondition* aCF,  RMobilePhone::TMobilePhoneCFChangeV1* aInfo)
+	/**
+	Sets the status of call forwarding
+	@param aReqHandle handle to the request
+	@param aCF condition for which the client wants to set the status
+	@param aInfo value of Call forwarding to set
+	*/
+	{
+	TRAPD(err, UpdateCFListL(aCF,aInfo));
+	if ( err != KErrNone )
+		{ 
+		iPhone->ReqCompleted(aReqHandle,err);
+		return KErrNone;
+		}
+		
+	if(iCFNotification.iCFChangeInfoNotificationPending)
+		{
+		*(iCFNotification.iCurrentCFCondition)=*aCF;
+		iCFNotification.iCFChangeInfoNotificationPending=EFalse;
+		iPhone->ReqCompleted(iCFNotification.iCFChangeInfoReqHandle,KErrNone);
+		}
+	
+	iPhone->ReqCompleted(aReqHandle,err);
+	LOGCALL1("Finished CSimCallForwarding::SetCallForwardingStatus");
+	return KErrNone;
+	}
+	
+TInt CSimCallForwarding::SetCallForwardingStatusCancel(const TTsyReqHandle aReqHandle)
+	/**
+	Cancels the request to set the status of call forwarding
+	@param aReqHandle handle to the request
+	*/
+	{
+	iPhone->ReqCompleted(aReqHandle,KErrCancel);
+	return KErrNone;
+	}
+	
+
+TInt CSimCallForwarding::GetCallForwardingStatusPhase1(const TTsyReqHandle aTsyReqHandle, 
+												 CRetrieveMobilePhoneCFList::TGetCallForwardingRequest* aReqData, 
+												 TInt* aBufSize)
+	{
+	/**
+	1st phase retrieval of the status of call forwarding
+	@param aTsyReqHandle handle to the request
+	@param aReqData contains details of the request
+	@param aBufSize size of the buffer the client needs to allocate for phase 2
+	*/
+	LOGCALL1("CSimPhone::GetCallForwardingStatusPhase1");
+	TInt ret=KErrNone;
+
+    // for forwarding we cannot querry for all conditions;
+    // conditions - specific
+    // services  - individual and all
+	if ((aReqData->iCondition==RMobilePhone::ECallForwardingUnspecified)
+	   || (aReqData->iCondition==RMobilePhone::ECallForwardingAllCases)
+	   || (aReqData->iCondition==RMobilePhone::ECallForwardingAllConditionalCases))
+	   {
+			iPhone->ReqCompleted(aTsyReqHandle,KErrArgument);
+		}
+	else
+		{
+		TInt leaveCode=KErrNone;
+		TRAP(leaveCode, ret=ProcessGetCallForwardingStatusPhase1L(aTsyReqHandle, aReqData, aBufSize););
+		if (leaveCode != KErrNone)
+			iPhone->ReqCompleted(aTsyReqHandle,leaveCode);
+		}
+	LOGCALL1("CSimPhone::GetCallForwardingStatusPhase1");
+	return ret;
+	}
+	
+TInt CSimCallForwarding::ProcessGetCallForwardingStatusPhase1L(const TTsyReqHandle aTsyReqHandle, 
+														 CRetrieveMobilePhoneCFList::TGetCallForwardingRequest* aReqData, 
+														 TInt* aBufSize)
+	{
+	/** Retrieve call forwarding status of each line from phone, 
+	store each CF status response as a list entry,
+	stream the list and then return size of this buffer to client
+	@param aReqHandle Handle to the request
+	@param aReqData information about the request
+	@param aBufSize Size of the buffer the client has to allocate for the 2nd pahase
+	*/
+
+	LOGCALL1("CSimPhone::ProcessGetCallForwardingStatusPhase1L");
+
+	CMobilePhoneCFList* list=CMobilePhoneCFList::NewL();
+	CleanupStack::PushL(list);
+	
+	TInt cnt=0;//Only interested by entries with a particular condition
+	TInt maxNum=iCFList->Enumerate();
+	TBool isAllGroups = (aReqData->iServiceGroup == RMobilePhone::EAllServices);
+	for(TInt i=0;i<maxNum;i++)
+		{
+		RMobilePhone::TMobilePhoneCFInfoEntryV1 entry = iCFList->GetEntryL(i);
+		
+		// Check that the data structure is supported by the simulated TSY version
+		TInt err = iPhone->CheckSimTsyVersion(entry);
+		if(err != KErrNone)
+			{
+			iPhone->ReqCompleted(aTsyReqHandle, err);
+			return KErrNone;
+			}
+
+		if((entry.iCondition == aReqData->iCondition) 
+		   &&(entry.iStatus != RMobilePhone::ECallForwardingStatusNotRegistered))
+			{
+			if ( !isAllGroups && (entry.iServiceGroup != aReqData->iServiceGroup))
+				{
+				continue;
+				}
+			list->AddEntryL(entry);
+			cnt++;
+			}	
+		}
+	// Store the streamed list and the client ID
+	CListReadAllAttempt* read=CListReadAllAttempt::NewL(aReqData->iClient,aTsyReqHandle);
+	CleanupStack::PushL(read);
+	
+	read->iListBuf = list->StoreLC();
+	CleanupStack::Pop(); // pop the CBufBase allocated by StoreLC
+	
+	iGetCFStatus->AppendL(read);
+	CleanupStack::Pop(read); // pop the CListReadAllAttempt
+	
+	// return the CBufBase’s size to client
+	*aBufSize=(read->iListBuf)->Size();
+	
+	CleanupStack::PopAndDestroy(list); // pop&destroy list
+	
+	// Complete first phase of list retrieval
+	iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
+	LOGCALL1("CSimPhone::ProcessGetCallForwardingStatusPhase1L");
+	return KErrNone;	
+	}
+
+TInt CSimCallForwarding::GetCallForwardingStatusPhase2(const TTsyReqHandle aTsyReqHandle, 
+												 RMobilePhone::TClientId* aClient, TDes8* aBuf)
+	/**
+	2nd phase retrieval of the status of call forwarding
+	@param aTsyRqHandle handle to the request
+	@param aClient pointer to the client
+	@param aBuf buffer that contains the call forwarding list
+	*/
+	{
+	LOGCALL1("CSimPhone::GetCallForwardingStatusPhase2");
+	CListReadAllAttempt* read=NULL;
+	// Find the get detected network attempt from this client
+	for (TInt i=0; i<iGetCFStatus->Count(); ++i)
+		{
+		read = iGetCFStatus->At(i);
+		if ((read->iClient.iSessionHandle==aClient->iSessionHandle) &&
+		    (read->iClient.iSubSessionHandle==aClient->iSubSessionHandle))
+			{
+			TPtr8 bufPtr((read->iListBuf)->Ptr(0));
+			// Copy the streamed list to the client
+			aBuf->Copy(bufPtr);
+			delete read;
+			iGetCFStatus->Delete(i);
+			iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
+			return KErrNone;
+			}
+		}
+	// Should handle error case of not finding the matching client from read all phase 1
+	LOGCALL1("CSimPhone::GetCallForwardingStatusPhase2");
+	return KErrNotFound;
+	}
+
+
+TInt CSimCallForwarding::GetCallForwardingStatusCancel(const TTsyReqHandle aTsyReqHandle)
+	{
+	/**
+	Cancel the request to retrieve the status of call forwarding
+	@param aTsyReqHandle handle to the request
+	*/
+	LOGCALL1("CSimPhone::GetCallForwardingStatusCancel");
+	iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
+	// Remove the read all attempt from iGetCFStatus
+	CListReadAllAttempt* read=NULL;
+	for (TInt i=0; i<iGetCFStatus->Count(); ++i)
+		{
+		read = iGetCFStatus->At(i);
+		if (read->iReqHandle == aTsyReqHandle)
+			{
+			delete read;
+			iGetCFStatus->Delete(i);
+			break;
+			}
+		}
+	iPhone->ReqCompleted(aTsyReqHandle,KErrCancel);
+	LOGCALL1("CSimPhone::GetCallForwardingStatusCancel");
+	return KErrNone;
+	}
+
+void CSimCallForwarding::UpdateCFListL(RMobilePhone::TMobilePhoneCFCondition* aCF, 
+									   RMobilePhone::TMobilePhoneCFChangeV1* aCFInfo )
+	{		
+	/**
+	Modifies the status of call forwarding
+	@param aCF condition
+	@param aCFInfo details of the request
+	*/
+	User::LeaveIfNull(aCF);
+	User::LeaveIfNull(aCFInfo);
+
+	if (*aCF == RMobilePhone::ECallForwardingUnspecified)
+	    {
+	    // not supported - tell user it is a wrong argument 
+		User::Leave(KErrArgument);
+	    }
+	     
+	if ((*aCF == RMobilePhone::ECallForwardingAllCases)
+		||(*aCF == RMobilePhone::ECallForwardingAllConditionalCases)) 
+	    {
+	    // not supported - tell user it is a wrong argument 
+		User::Leave(KErrNotSupported);
+	    }  
+	       
+	switch (aCFInfo->iAction)
+		{
+		case RMobilePhone::EServiceActionRegister:
+			RegisterL(aCF, aCFInfo);
+			break;
+			
+		case RMobilePhone::EServiceActionActivate:
+			ActivateL(aCF, aCFInfo);
+			break;
+			
+		case RMobilePhone::EServiceActionInvoke:
+		    // currently not supported
+		    // tell user it is a wrong argument 
+			User::Leave(KErrArgument);
+			break;
+			
+		case RMobilePhone::EServiceActionDeactivate:
+			DeactivateL(aCF, aCFInfo);
+			break;
+			
+		case RMobilePhone::EServiceActionErase:
+			EraseL(aCF, aCFInfo);
+			break;
+			
+		case RMobilePhone::EServiceActionUnspecified:
+		default:
+		    // not supported - tell user it is a wrong argument 
+			User::Leave(KErrArgument);
+			break;
+		}
+	}
+	
+
+inline void SplitOneCFEntryIntoSeparateGroupsL(CMobilePhoneCFList* aCFList,
+											   RMobilePhone::TMobilePhoneCFInfoEntryV1& aOrigEntry,
+											   RMobilePhone::TMobileService aExceptServiceGroup)
+	{
+	/*
+	Splits one entry valid for all basic service groups into individual entries 
+	and places them into a CMobilePhoneCFList. This excludes one service group.	 
+	@param aCBList The list to which to store the entries
+	@param aOrigEntry The original entry; details of which should be passed to individual group entries
+	@param aExceptServiceGroup The group which has to be avoided
+	*/
+	// we have to split the entry into entries 
+	// per group with the same condition; excluding the specified service group 
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 anotherEntry(aOrigEntry);
+
+	RMobilePhone::TMobileService service;
+	
+	for (TInt i = KMobServiceIndxStart;i <= KMobServiceIndxEnd;i++)
+		{
+		service=static_cast<RMobilePhone::TMobileService>(i);
+		
+		if( service != aExceptServiceGroup )
+			{
+			anotherEntry.iServiceGroup=service;
+			aCFList->AddEntryL(anotherEntry);
+			}
+		}//end for (another)
+	}
+	
+	
+void CSimCallForwarding::UpdateCFQuiescentCondition(TBool aActivate, 
+													RMobilePhone::TMobilePhoneCFCondition aCF)
+	{
+	// only the Call Forward Unconditional can alter any other CF condition
+	if(aCF == RMobilePhone::ECallForwardingUnconditional)
+		{		
+		TBool cFBChangeRequired = EFalse;
+		
+		RMobilePhone::TMobilePhoneCFInfoEntryV1 theEntry;
+		
+		const TInt count = iCFList->Enumerate();
+
+		// look for any instances of the ECallForwardingBusy
+		for (TInt indx=0; indx < count; indx++)
+			{ 
+			theEntry = iCFList->GetEntryL(indx);
+			
+			if(theEntry.iCondition == RMobilePhone::ECallForwardingBusy &&
+			  (theEntry.iStatus == RMobilePhone::ECallForwardingStatusActive || 
+			   theEntry.iStatus == RMobilePhone::ECallForwardingStatusQuiescent)) 
+				{
+				cFBChangeRequired = ETrue;
+				}												
+			}
+		
+		if(cFBChangeRequired)
+			{
+			// retain prev version of the list in local variable and in Cleanup stack
+			CMobilePhoneCFList* thePrevCFList = CMobilePhoneCFList::NewL();
+			CleanupStack::PushL(thePrevCFList);
+	
+			// copy existing data into the temp storage
+			for (TInt indx=0; indx < count; indx++)
+				{ 
+				thePrevCFList->AddEntryL(iCFList->GetEntryL(indx));
+				}
+
+			delete iCFList;
+			iCFList = NULL;
+	
+			// create a new version and hold it in the class member
+			iCFList = CMobilePhoneCFList::NewL();
+	
+			// get a hold of it in a local variable       
+			CMobilePhoneCFList* theNewCFList = iCFList;
+			
+			for(TInt indx=0; indx < count; indx++)
+				{
+				theEntry = thePrevCFList->GetEntryL(indx);
+			
+				if(theEntry.iCondition == RMobilePhone::ECallForwardingBusy)
+					{
+					if(aActivate)
+						{
+						if(theEntry.iStatus == RMobilePhone::ECallForwardingStatusActive)
+							{
+							theEntry.iStatus = RMobilePhone::ECallForwardingStatusQuiescent;
+							}
+						}
+					else
+						{
+						if(theEntry.iStatus == RMobilePhone::ECallForwardingStatusQuiescent)
+							{
+							theEntry.iStatus = RMobilePhone::ECallForwardingStatusActive;
+							}
+						}					
+					}			
+				theNewCFList->AddEntryL(theEntry);
+				}					
+			
+			// now delete the old memory
+			CleanupStack::PopAndDestroy(thePrevCFList);
+			}						
+		}
+	}	
+
+void CSimCallForwarding::ActivateL(RMobilePhone::TMobilePhoneCFCondition* aCF, 
+								   RMobilePhone::TMobilePhoneCFChangeV1* aCFInfo )
+	{
+	// NOTE: An assumption is made that the calling method has checked the parameters
+	// are not NULL.
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 theNewEntry;
+
+	theNewEntry.iCondition = *aCF;
+	theNewEntry.iServiceGroup = aCFInfo->iServiceGroup;
+	theNewEntry.iStatus= RMobilePhone::ECallForwardingStatusNotActive;
+	theNewEntry.iNumber = aCFInfo->iNumber;
+	
+	if (*aCF ==  RMobilePhone::ECallForwardingNoReply)
+		{	
+		theNewEntry.iTimeout = aCFInfo->iTimeout;
+		}
+	else
+		{
+		theNewEntry.iTimeout = KInvalidTimeout;
+		} 
+
+
+	// retain prev version of the list in local variable and in Cleanup stack
+	CMobilePhoneCFList* thePrevCFList = CMobilePhoneCFList::NewL();
+	CleanupStack::PushL(thePrevCFList);
+	
+	const TInt count = iCFList->Enumerate();
+	
+	TBool CFUActive = EFalse;
+	
+	// copy existing data into the temp storage
+	for (TInt indx = 0; indx < count; indx++)
+		{ 	
+		thePrevCFList->AddEntryL(iCFList->GetEntryL(indx));
+		
+		RMobilePhone::TMobilePhoneCFInfoEntryV1 copyEntry = iCFList->GetEntryL(indx);
+
+		if(copyEntry.iCondition == RMobilePhone::ECallForwardingUnconditional &&
+		   copyEntry.iStatus == RMobilePhone::ECallForwardingStatusActive)
+			{
+			CFUActive = ETrue;
+			}
+		}
+	
+	delete iCFList;
+	iCFList = NULL;
+	
+	// create a new version and hold it in the class member
+	iCFList = CMobilePhoneCFList::NewL();
+	
+	// get a hold of it in a local variable 
+	CMobilePhoneCFList* theNewCFList = iCFList;
+	
+	TBool callForwardActivated = EFalse;
+		
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 entry;
+	
+	for (TInt i = 0; i < count; i++)
+		{
+		entry = thePrevCFList->GetEntryL(i);
+					
+		if(theNewEntry.iCondition == entry.iCondition)
+			{			
+			if(theNewEntry.iServiceGroup == entry.iServiceGroup)
+				{
+				// only activate service if previously in a not active state
+				if(entry.iStatus == RMobilePhone::ECallForwardingStatusNotActive)
+					{
+					if(entry.iCondition == RMobilePhone::ECallForwardingBusy && CFUActive != EFalse)
+						{
+						// do nothing, condition's service will not be activated as callforwarding
+						// unconditional is active	
+						}
+					else
+						{
+						entry.iStatus = RMobilePhone::ECallForwardingStatusActive;
+						callForwardActivated = ETrue;									
+						}
+					}					
+				}
+			else if(entry.iServiceGroup == RMobilePhone::EAllServices)
+				{
+				if(entry.iStatus == RMobilePhone::ECallForwardingStatusNotActive)
+					{
+					SplitOneCFEntryIntoSeparateGroupsL(theNewCFList,
+													   entry,
+													   theNewEntry.iServiceGroup);
+					
+					callForwardActivated = ETrue;
+					entry = theNewEntry;
+					}				
+				}					
+			}		
+
+		theNewCFList->AddEntryL(entry);				
+		}
+	
+	if(callForwardActivated)
+		{
+		// only need to check quiescent status if an activation has occurred
+		UpdateCFQuiescentCondition(ETrue, theNewEntry.iCondition);	
+		}
+
+	CleanupStack::PopAndDestroy(thePrevCFList);
+	}
+
+void CSimCallForwarding::RegisterL(RMobilePhone::TMobilePhoneCFCondition* aCF, RMobilePhone::TMobilePhoneCFChangeV1* aCFInfo)
+	{
+	TInt count = iCFList->Enumerate();
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 theNewEntry;
+
+	theNewEntry.iCondition = *aCF;
+	theNewEntry.iServiceGroup = aCFInfo->iServiceGroup;
+	theNewEntry.iStatus= RMobilePhone::ECallForwardingStatusNotActive;
+
+	theNewEntry.iNumber = aCFInfo->iNumber;
+	if (*aCF ==  RMobilePhone::ECallForwardingNoReply)
+		{	
+		theNewEntry.iTimeout = aCFInfo->iTimeout;
+		}
+	else
+		{
+		 theNewEntry.iTimeout = KInvalidTimeout;
+		} 
+
+	// retain prev version of the list in local variable and in Cleanup stack
+	CMobilePhoneCFList* thePrevCFList = CMobilePhoneCFList::NewL();
+	CleanupStack::PushL(thePrevCFList);
+	// copy existing data into the temp storage
+	for (TInt indx=0; indx<count; indx++)
+		{ 
+		thePrevCFList->AddEntryL(iCFList->GetEntryL(indx));
+		}
+	delete iCFList;
+	iCFList = NULL;
+	// create a new version and hold it in the class member
+	iCFList = CMobilePhoneCFList::NewL();
+	// get a hold of it in a local variable       
+	CMobilePhoneCFList* theNewCFList = iCFList;
+		
+	if (theNewEntry.iServiceGroup==RMobilePhone::EAllServices)
+		{
+		//nothing for all conds
+		
+		//action is to Regiser (and activate)AllServices with a particular condition;
+		//Only copy entries with a different condition
+		//entries with same condition should not be copied as they will
+		//be represented by 1 with allservices
+		for (TInt i = 0; i<count; i++)
+			{
+			RMobilePhone::TMobilePhoneCFInfoEntryV1 entry = thePrevCFList->GetEntryL(i);
+
+			if (entry.iCondition != theNewEntry.iCondition)
+				// check if the existing entry is encompassed by the new one
+				theNewCFList->AddEntryL(entry);
+			}
+		theNewCFList->AddEntryL(theNewEntry);			
+		}
+	else
+		{
+		//ActivateOne;
+		for (TInt i = 0; i<count; i++)
+			{
+			RMobilePhone::TMobilePhoneCFInfoEntryV1 entry = thePrevCFList->GetEntryL(i);
+
+			if (theNewEntry.iCondition==entry.iCondition
+				&&  entry.iServiceGroup==theNewEntry.iServiceGroup)
+				{
+				theNewCFList->AddEntryL(theNewEntry);
+				continue;
+				}
+			if (entry.iCondition != theNewEntry.iCondition
+				|| (entry.iCondition == theNewEntry.iCondition
+				&& entry.iServiceGroup != theNewEntry.iServiceGroup
+				&& entry.iServiceGroup != RMobilePhone::EAllServices))
+				{
+				theNewCFList->AddEntryL(entry);	
+				continue;
+				}
+				
+			if(theNewEntry.iCondition==entry.iCondition
+				&&  entry.iServiceGroup==RMobilePhone::EAllServices)
+				{
+					
+				SplitOneCFEntryIntoSeparateGroupsL( 
+											theNewCFList,
+											entry,
+											theNewEntry.iServiceGroup
+											);
+					
+				theNewCFList->AddEntryL(theNewEntry);
+				}//end if
+			}//end for
+		}//end else
+	// now delete the old memory
+	CleanupStack::PopAndDestroy(thePrevCFList);
+	}
+
+void CSimCallForwarding::DeactivateL(RMobilePhone::TMobilePhoneCFCondition* aCF, 
+									 RMobilePhone::TMobilePhoneCFChangeV1* aCFInfo )
+	{
+	// NOTE: An assumption is made that the calling method has checked the parameters
+	// are not NULL.
+		
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 theNewEntry;
+
+	theNewEntry.iCondition = *aCF;
+	theNewEntry.iServiceGroup = aCFInfo->iServiceGroup;
+	theNewEntry.iStatus= RMobilePhone::ECallForwardingStatusNotActive;
+		
+	// retain prev version of the list in local variable and in Cleanup stack
+	CMobilePhoneCFList* thePrevCFList = CMobilePhoneCFList::NewL();
+	CleanupStack::PushL(thePrevCFList);
+		
+	const TInt count = iCFList->Enumerate();
+
+	// copy existing data into the temp storage
+	for (TInt indx = 0; indx < count; indx++)
+		{ 
+		thePrevCFList->AddEntryL(iCFList->GetEntryL(indx));
+		}
+	
+	delete iCFList;
+	iCFList = NULL;
+	
+	// create a new version and hold it in the class member
+	iCFList = CMobilePhoneCFList::NewL();
+	
+	// get a hold of it in a local variable       
+	CMobilePhoneCFList* theNewCFList = iCFList;
+		
+	TBool callForwardDeactivated = EFalse;
+			
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 entry;
+
+	//Deactivate will deactivate active entries 
+	for (TInt indx = 0; indx < count; indx++)
+		{
+		entry = thePrevCFList->GetEntryL(indx);
+				
+		if(entry.iCondition == theNewEntry.iCondition)
+			{
+			if(entry.iServiceGroup == theNewEntry.iServiceGroup)
+				{
+				if(entry.iStatus == RMobilePhone::ECallForwardingStatusActive)
+					{
+				   	entry.iStatus = RMobilePhone::ECallForwardingStatusNotActive;
+					callForwardDeactivated = ETrue;
+					}								
+				}
+			else if(entry.iServiceGroup == RMobilePhone::EAllServices)
+				{
+				if(entry.iStatus == RMobilePhone::ECallForwardingStatusActive)
+					{
+					SplitOneCFEntryIntoSeparateGroupsL(theNewCFList,
+													   entry,
+													   theNewEntry.iServiceGroup);
+										
+					entry = theNewEntry;
+					callForwardDeactivated = ETrue;					
+					}			
+				}			
+			}	
+		
+		theNewCFList->AddEntryL(entry);
+		}//end for
+		
+	// this method will check if any de-activation has caused another Condition to become 
+	// cleared of the quiescent state
+	if(callForwardDeactivated)
+		{		
+		// pass a FALSE to the function to notify of a service de-activation
+		UpdateCFQuiescentCondition(EFalse, theNewEntry.iCondition);
+		}
+
+	// now delete the old memory	
+	CleanupStack::PopAndDestroy(thePrevCFList);
+	}
+
+void CSimCallForwarding::EraseL(RMobilePhone::TMobilePhoneCFCondition* aCF, 
+								RMobilePhone::TMobilePhoneCFChangeV1* aCFInfo )
+	{
+	// NOTE: An assumption is made that the calling method has checked the parameters
+	// are not NULL.
+	
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 theNewEntry;
+
+	theNewEntry.iCondition = *aCF;
+	theNewEntry.iServiceGroup = aCFInfo->iServiceGroup;
+	theNewEntry.iNumber.iTelNumber.Copy(KEmptyString);
+	theNewEntry.iTimeout = KErrNotFound;
+	theNewEntry.iStatus = RMobilePhone::ECallForwardingStatusNotRegistered;
+	
+	// retain prev version of the list in local variable and in Cleanup stack
+	CMobilePhoneCFList* thePrevCFList = CMobilePhoneCFList::NewL();
+	CleanupStack::PushL(thePrevCFList);
+	
+	const TInt count = iCFList->Enumerate();
+
+	// copy existing data into the temp storage
+	for (TInt indx = 0; indx < count; indx++)
+		{ 
+		thePrevCFList->AddEntryL(iCFList->GetEntryL(indx));
+		}
+	
+	delete iCFList;
+	iCFList = NULL;
+	
+	// create a new version and hold it in the class member
+	iCFList = CMobilePhoneCFList::NewL();
+	
+	// get a hold of it in a local variable       
+	CMobilePhoneCFList* theNewCFList = iCFList;
+	
+	RMobilePhone::TMobilePhoneCFInfoEntryV1 entry;	
+	
+	for(TInt i = 0; i < count; i++)
+		{
+		entry = thePrevCFList->GetEntryL(i);
+		
+		if(entry.iCondition == theNewEntry.iCondition)
+			{
+			if(entry.iServiceGroup == theNewEntry.iServiceGroup)
+				{
+				if(entry.iStatus == RMobilePhone::ECallForwardingStatusNotActive)
+					{
+				   	entry = theNewEntry;
+					}								
+				}
+			else if(entry.iServiceGroup == RMobilePhone::EAllServices)
+				{
+				if(entry.iStatus == RMobilePhone::ECallForwardingStatusActive)
+					{
+					SplitOneCFEntryIntoSeparateGroupsL(theNewCFList,
+													   entry,
+													   theNewEntry.iServiceGroup);
+										
+					entry = theNewEntry;
+					}			
+				}
+			}
+		theNewCFList->AddEntryL(entry);		
+		}
+
+	// now delete the old memory
+	CleanupStack::PopAndDestroy(thePrevCFList);	
+	}
+	
+const CTestConfigSection* CSimCallForwarding::CfgFile()
+/**
+ * Returns a pointer to the current configuration file section.
+ *
+ * @return CTestConfigSection	A pointer to the current configuration file data section.
+ */
+	{
+	return iPhone->CfgFile();
+	}
+
+