// 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);
}