diff -r 000000000000 -r 3553901f7fa8 telephonyserverplugins/simtsy/src/CSimCallWaiting.cpp --- /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 +#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(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;iItem(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;iAddEntryL(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; iCount(); ++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; iCount(); ++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(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; indxEnumerate(); 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; iGetEntryL(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; iGetEntryL(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); + } +