telephonyserverplugins/simtsy/src/CSimCallWaiting.cpp
changeset 0 3553901f7fa8
child 24 6638e7f4bd8f
child 42 3adadc800673
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/simtsy/src/CSimCallWaiting.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,553 @@
+// 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
+// CallWaiting status and registration information.
+// 
+//
+
+/**
+ @file
+*/
+
+#include <testconfigfileparser.h>
+#include "CSimCallWaiting.h"
+#include "CSimPhone.h"
+#include "Simlog.h"
+
+const TInt KMobServiceIndxStart = 1;
+const TInt KMobServiceIndxEnd   = 5;
+
+
+CSimCallWaiting* CSimCallWaiting::NewL(CSimPhone* aPhone)
+/**
+ * Standard two-phase constructor.
+ * @param aPhone				The parent phone object.
+ * @return CSimCallWaiting		The new call waiting class.
+ */
+	{
+	CSimCallWaiting* self=new(ELeave) CSimCallWaiting(aPhone);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CSimCallWaiting::CSimCallWaiting(CSimPhone* aPhone)
+		: iPhone(aPhone)
+/**
+ * Trivial first phase construction.
+ * @param aPhone				The parent phone object.
+ */
+	{
+	}
+
+void CSimCallWaiting::ConstructL()
+/**
+	Second phase of 2-Phase Constructor
+  	Retrieves all the Call waiting related tags from the config file
+*/
+	{
+	LOGCALL1("Starting to parse Call waiting config parameters...");
+
+	iGetCWStatus = new(ELeave) CArrayPtrFlat<CListReadAllAttempt>(1);
+	FindAndCreateCWListL();
+	LOGCALL1("...Finished parsing Call waiting config parameters...");
+	}
+	
+void CSimCallWaiting::FindAndCreateCWListL()
+{
+/**
+  	Retrieves all the Call waiting tags that define the 
+  	original status of Call waiting from the config file
+*/
+	LOGCALL1("CSimPhone::FindAndCreateCWListL");
+	RMobilePhone::TMobilePhoneCWInfoEntryV1 entry;
+
+	iCWList = CMobilePhoneCWList::NewL();
+	TInt count=CfgFile()->ItemCount(KCWList);
+	const CTestConfigItem* item=NULL;
+	TInt ret=KErrNone;
+
+	LOGCALL1("Starting to Load and Parse CWList Config parameters");
+	TInt i;
+	for(i=0;i<count;i++)
+		{
+		item=CfgFile()->Item(KCWList,i);
+		if(!item)
+			break;
+		
+		TInt serviceGroup, status;
+		
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,serviceGroup);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("serviceGroup",ret,0,&KCWList);
+			continue;
+			}
+
+		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,status);
+		if(ret!=KErrNone)
+			{
+			LOGPARSERR("status",ret,1,&KCWList);
+			continue;
+			}
+		
+		entry.iServiceGroup=(RMobilePhone::TMobileService)serviceGroup;
+		entry.iStatus=(RMobilePhone::TMobilePhoneCWStatus)status;
+
+		iCWList->AddEntryL(entry);
+		}
+	}
+
+CSimCallWaiting::~CSimCallWaiting()
+	{
+	delete iCWList;
+	if (iGetCWStatus)
+		iGetCWStatus->ResetAndDestroy();
+	delete iGetCWStatus;
+	}
+
+TInt CSimCallWaiting::ExtFuncL(const TTsyReqHandle aReqHandle,const TInt aIpc, const TDataPackage& aPckg)
+	{
+	/**
+  	Handles the phone based requests that apply to call waiting
+  	@param aReqHandle Handle to the request
+  	@param aIpc request identifier
+  	@param aPckg contains additional information for the requests
+	*/
+
+	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 EMobilePhoneSetCallWaitingStatus:
+		return SetCallWaitingStatusL(aReqHandle,
+			REINTERPRET_CAST(RMobilePhone::TMobileService*, dataPtr),
+			REINTERPRET_CAST(RMobilePhone::TMobilePhoneServiceAction*,dataPtr2));
+	case EMobilePhoneNotifyCallWaitingStatusChange:
+		return NotifyCallWaitingStatusChange(aReqHandle, REINTERPRET_CAST(RMobilePhone::TMobilePhoneCWInfoEntryV1*, dataPtr));
+	case EMobilePhoneGetWaitingStatusPhase1:
+		return GetCallWaitingStatusPhase1(aReqHandle, 
+			REINTERPRET_CAST(CRetrieveMobilePhoneCWList::TGetCallWaitingRequest*, dataPtr), 
+			REINTERPRET_CAST(TInt*, dataPtr2));
+	case EMobilePhoneGetWaitingStatusPhase2:
+		return GetCallWaitingStatusPhase2(aReqHandle, 
+			REINTERPRET_CAST(RMobilePhone::TClientId*, dataPtr), aPckg.Des2n());		
+	default:
+		break;
+		}
+	return KErrNotSupported;
+	}
+	
+TInt CSimCallWaiting::CancelService(const TInt aIpc, const TTsyReqHandle aReqHandle)
+	{
+	/**
+  	Cancels any phone based request regarding call waiting
+  	@param aIpc the IPC to cancel
+  	@param aReqHandle handle to the request
+	*/
+	switch(aIpc)
+		{
+	case EMobilePhoneSetCallWaitingStatus:
+		return SetCallWaitingStatusCancel(aReqHandle);
+	case EMobilePhoneNotifyCallWaitingStatusChange:
+		return NotifyCallWaitingStatusChangeCancel(aReqHandle);
+	default:
+		break;
+		}
+	return KErrNone;
+	}
+
+TInt CSimCallWaiting::NotifyCallWaitingStatusChange(const TTsyReqHandle aReqHandle, RMobilePhone::TMobilePhoneCWInfoEntryV1* aCW)
+	{	
+	/**
+	Requests to be notified of change in the Call Waiting status
+	@param aReqHandle Handle to the request
+	@param aCW contains the service group and new status that has changed
+  	*/
+	__ASSERT_ALWAYS(!iCWNotification.iCWChangeInfoNotificationPending,SimPanic(ENotificationReqAlreadyOutstanding));
+	iCWNotification.iCWChangeInfoNotificationPending=ETrue;
+	iCWNotification.iCWChangeInfoReqHandle=aReqHandle;
+	iCWNotification.iCWInfo=aCW;
+	LOGCALL1("Finished CSimCallWaiting::NotifyCallWaitingStatusChange");
+	return KErrNone;
+	}
+
+TInt CSimCallWaiting::NotifyCallWaitingStatusChangeCancel(const TTsyReqHandle aReqHandle)
+	{
+	/**
+	Cancels request to be notified of call Waiting status change
+	@param aReqHandle Handle to the request
+	*/
+	if(iCWNotification.iCWChangeInfoNotificationPending)
+		{
+		iCWNotification.iCWChangeInfoNotificationPending=EFalse;
+		iPhone->ReqCompleted(aReqHandle,KErrCancel);
+		}
+	return KErrNone;
+	}
+	
+TInt CSimCallWaiting::SetCallWaitingStatusL(const TTsyReqHandle aReqHandle, RMobilePhone::TMobileService* aService,  RMobilePhone::TMobilePhoneServiceAction* aAction)
+	{
+	/**
+	Sets the status for call Waiting
+	@param aReqHandle Handle to the request
+	@param aCB condition for which the client whishes to set the call Waiting status
+	@param aInfo additional parameters to set the call Waiting status
+  	*/
+	
+	// make sure we know that the operation concluded sucessfully
+	TRAPD(ret,UpdateCWListL(aService,aAction)); 	
+	if ( ret != KErrNone )
+		{ 
+		iPhone->ReqCompleted(aReqHandle,ret);
+		}
+		
+	// otherwise proceed and notify all went well
+	// Notify change
+	if (iCWNotification.iCWChangeInfoNotificationPending)
+		{
+		
+		(iCWNotification.iCWInfo->iServiceGroup)=*aService;
+				
+		switch (*aAction)
+			{
+			case RMobilePhone::EServiceActionRegister:
+			case RMobilePhone::EServiceActionActivate:
+				iCWNotification.iCWInfo->iStatus= RMobilePhone::ECallWaitingStatusActive;
+				break;
+			case RMobilePhone::EServiceActionDeactivate:
+			case RMobilePhone::EServiceActionErase:
+				iCWNotification.iCWInfo->iStatus= RMobilePhone::ECallWaitingStatusNotActive;
+				break;
+			case RMobilePhone::EServiceActionUnspecified:
+			default:
+				iCWNotification.iCWInfo->iStatus= RMobilePhone::ECallWaitingStatusUnknown;
+				// no sense doing any further operation - leave
+				User::Leave( KErrArgument );
+				break;
+			}
+		
+		iCWNotification.iCWChangeInfoNotificationPending=EFalse;
+		iPhone->ReqCompleted(iCWNotification.iCWChangeInfoReqHandle,KErrNone);
+		}
+		
+	iPhone->ReqCompleted(aReqHandle,KErrNone);
+		
+	return KErrNone;
+	}
+
+TInt CSimCallWaiting::SetCallWaitingStatusCancel(const TTsyReqHandle aReqHandle)
+	{
+	/**
+	Cancels the request to sets the status for call waiting
+	@param aReqHandle Handle to the request
+  	*/
+	 
+	iPhone->ReqCompleted(aReqHandle,KErrCancel);
+	return KErrNone;
+	}
+	
+	
+	
+const CTestConfigSection* CSimCallWaiting::CfgFile()
+/**
+ * Returns a pointer to the current configuration file section.
+ *
+ * @return CTestConfigSection	A pointer to the current configuration file data section.
+ */
+	{
+	return iPhone->CfgFile();
+	}
+
+TInt CSimCallWaiting::GetCallWaitingStatusPhase1(const TTsyReqHandle aTsyReqHandle, 
+												 CRetrieveMobilePhoneCWList::TGetCallWaitingRequest* aReqData, 
+												 TInt* aBufSize)
+	{
+	/**
+	1st phase retrieval of the the call waiting status list
+	@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("CSimCallWaiting::GetCalWaitingStatusPhase1");
+	
+	TInt ret=KErrNone;
+	TInt leaveCode=KErrNone;
+	TRAP(leaveCode, ret=ProcessGetCallWaitingStatusPhase1L(aTsyReqHandle, aReqData, aBufSize););
+	if (leaveCode != KErrNone)
+			iPhone->ReqCompleted(aTsyReqHandle,leaveCode);
+
+	LOGCALL1("CSimCallWaiting::GetCalWaitingStatusPhase1");
+	return ret;
+	}
+	
+TInt CSimCallWaiting::ProcessGetCallWaitingStatusPhase1L(const TTsyReqHandle aTsyReqHandle, 
+														 CRetrieveMobilePhoneCWList::TGetCallWaitingRequest* aReqData, 
+														 TInt* aBufSize)
+	{
+	/** Retrieve call waiting status of each line from phone, 
+	store each CB 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("CSimCallWaiting::ProcessGetCallWaitingStatusPhase1L");
+
+	CMobilePhoneCWList* list=CMobilePhoneCWList::NewL();
+	CleanupStack::PushL(list);
+		
+	TInt maxNum=iCWList->Enumerate();
+	//if testing all CB are non-active
+	// then we have to return a single entry EAllServices
+	if ( maxNum )
+		{
+		for(TInt i=0;i<maxNum;i++)
+			{
+			list->AddEntryL(iCWList->GetEntryL(i));
+			}
+		}
+	else
+		{
+		// if the list is empty and the querry general then we have to return general info
+		RMobilePhone::TMobilePhoneCWInfoEntryV1 entry;
+		
+		// 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;
+			}
+
+		entry.iServiceGroup	= RMobilePhone::EAllServices;
+		entry.iStatus		= RMobilePhone::ECallWaitingStatusNotActive;
+		list->AddEntryL( entry );
+		}
+
+	// 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
+	
+	iGetCWStatus->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("CSimCallWaiting::ProcessGetCallWaitingStatusPhase1L");
+	return KErrNone;
+	}
+
+TInt CSimCallWaiting::GetCallWaitingStatusPhase2(const TTsyReqHandle aTsyReqHandle, 
+												 RMobilePhone::TClientId* aClient, TDes8* aBuf)
+	{
+	/**
+	2nd phase retrieval of the the call waiting status list
+	@param aReqHandle Handle to the request
+	@param aClient Ponter to the client
+	@param aBuf Buffer containiong the call waiting status list
+	*/
+	LOGCALL1("CSimCallWaiting::GetCallWaitingStatusPhase2");
+	CListReadAllAttempt* read=NULL;
+	// Find the get detected network attempt from this client
+	for (TInt i=0; i<iGetCWStatus->Count(); ++i)
+		{
+		read = iGetCWStatus->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;
+			iGetCWStatus->Delete(i);
+			iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
+			return KErrNone;
+			}
+		}
+	// Should handle error case of not finding the matching client from read all phase 1
+	LOGCALL1("CSimCallWaiting::GetCallWaitingStatusPhase2");
+	return KErrNotFound;
+	}
+
+TInt CSimCallWaiting::GetCallWaitingStatusCancel(const TTsyReqHandle aTsyReqHandle)
+	{
+	/*
+	Cancels a Request to retrieve the call waiting status list
+	@param aReqHandle Handle to the request
+	*/
+	LOGCALL1("CSimCallWaiting::GetCallWaitingStatusCancel");
+	iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
+	// Remove the read all attempt from iGetCBStatus
+	CListReadAllAttempt* read=NULL;
+	for (TInt i=0; i<iGetCWStatus->Count(); ++i)
+		{
+		read = iGetCWStatus->At(i);
+		if (read->iReqHandle == aTsyReqHandle)
+			{
+			delete read;
+			iGetCWStatus->Delete(i);
+			break;
+			}
+		}
+	iPhone->ReqCompleted(aTsyReqHandle,KErrCancel);
+	LOGCALL1("CSimCallWaiting::GetCallWaitingStatusCancel");
+	return KErrNone;
+	}
+	
+inline void SplitOneEntryIntoSeparateGroupsL( 
+								CMobilePhoneCWList* aCWList,
+								RMobilePhone::TMobilePhoneCWInfoEntryV1 aOrigEntry,
+								RMobilePhone::TMobileService aExceptServiceGroup
+									)
+	{
+	/*
+	Splits one entry valid for all basic service groups into individual entries 
+	and places them into a CMobilePhoneCBList. 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::TMobilePhoneCWInfoEntryV1 anotherEntry = aOrigEntry;
+
+	//anotherEntry.iCondition = aOrigEntry.iCondition;
+	//anotherEntry.iStatus = RMobilePhone::ECallBarringStatusActive;
+	RMobilePhone::TMobileService service;
+	
+	for (TInt i=KMobServiceIndxStart; i<=KMobServiceIndxEnd;i++)
+		{
+		service=static_cast<RMobilePhone::TMobileService>(i);
+		if( service != aExceptServiceGroup )
+			{
+			anotherEntry.iServiceGroup=service;
+			aCWList->AddEntryL(anotherEntry);
+			}
+		}//end for (another)
+	}
+	
+void CSimCallWaiting::UpdateCWListL(RMobilePhone::TMobileService* aServiceGroup, RMobilePhone::TMobilePhoneServiceAction* aAction )
+	{
+	/*
+	Updates the status of call waiting.
+	@param aServiceGroup service group to set
+	@param aAction ation to be performed 
+	*/
+	
+	// no sense processing if either condition or change info are NULLS 
+	User::LeaveIfNull(aServiceGroup);
+	User::LeaveIfNull(aAction);
+    
+	
+	//Lets do some work then
+	RMobilePhone::TMobilePhoneCWInfoEntryV1 theNewEntry;
+
+	theNewEntry.iServiceGroup = *aServiceGroup;
+	
+	switch (*aAction)
+		{
+		case RMobilePhone::EServiceActionRegister:
+		case RMobilePhone::EServiceActionActivate:
+			theNewEntry.iStatus= RMobilePhone::ECallWaitingStatusActive;
+			break;
+		case RMobilePhone::EServiceActionDeactivate:
+		case RMobilePhone::EServiceActionErase:
+			theNewEntry.iStatus= RMobilePhone::ECallWaitingStatusNotActive;
+			break;
+		case RMobilePhone::EServiceActionUnspecified:
+		default:
+			theNewEntry.iStatus= RMobilePhone::ECallWaitingStatusUnknown;
+			// no sense doing any further operation - leave
+			User::Leave( KErrArgument );
+			break;
+		}
+		
+	// retain prev version of the list in local variable and in Cleanup stack
+	CMobilePhoneCWList* thePrevCWList = CMobilePhoneCWList::NewL();
+	CleanupStack::PushL(thePrevCWList);
+	// copy existing data into the temp storage
+	for (TInt indx=0; indx<iCWList->Enumerate(); indx++)
+		{ 
+		thePrevCWList->AddEntryL(iCWList->GetEntryL(indx));
+		}
+	delete iCWList;
+	iCWList = NULL;
+	
+	// create a new version and hold it in the class member
+	iCWList = CMobilePhoneCWList::NewL();
+	// get a hold of it in a local variable       
+	CMobilePhoneCWList* theNewCWList = iCWList;
+	RMobilePhone::TMobilePhoneCWInfoEntryV1 entry;
+
+	TInt count = thePrevCWList->Enumerate();
+	
+	if (theNewEntry.iStatus == RMobilePhone::ECallWaitingStatusActive)
+		{
+		if (theNewEntry.iServiceGroup==RMobilePhone::EAllServices)
+			{
+			theNewCWList->AddEntryL(theNewEntry);
+			}
+		else
+			{
+			for (TInt i = 0; i<count; i++)
+				{
+				entry = thePrevCWList->GetEntryL(i);
+				if(entry.iServiceGroup!=theNewEntry.iServiceGroup
+					&& entry.iServiceGroup!=RMobilePhone::EAllServices)
+					theNewCWList->AddEntryL(entry);
+				}
+			theNewCWList->AddEntryL(theNewEntry);
+			}
+		}
+	else //deactivate
+		{
+		if (theNewEntry.iServiceGroup==RMobilePhone::EAllServices)
+			{
+			theNewCWList->AddEntryL(theNewEntry);
+			}
+		else
+			{
+			for (TInt i = 0; i<count; i++)
+				{
+				entry = thePrevCWList->GetEntryL(i);
+				if(entry.iServiceGroup==RMobilePhone::EAllServices)
+					{
+					//add to the list active entries for all servive groups but the one to be deactivated
+					SplitOneEntryIntoSeparateGroupsL(theNewCWList,entry, theNewEntry.iServiceGroup);
+					continue;
+					}
+				if(entry.iServiceGroup!=theNewEntry.iServiceGroup)
+					{
+					theNewCWList->AddEntryL(entry);
+					}
+				}				
+			}
+			
+		}
+	// now delete the old memory	
+	CleanupStack::PopAndDestroy(thePrevCWList);	
+	}
+