diff -r 6465d5bb863a -r 13e71d907dc3 gssettingsuis/Gs/GSCallDivertPlugin/Src/GSCallDivertModel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gssettingsuis/Gs/GSCallDivertPlugin/Src/GSCallDivertModel.cpp Thu Nov 04 13:38:47 2010 +0800 @@ -0,0 +1,598 @@ +/* +* Copyright (c) 2008 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: Model for call divert functionality. Tries to encapsulate +* most of hw/engine related functionality from UI components. +* +*/ + + + + +// User includes: +#include "featmgr.h" +#include "GSCallDivertModel.h" +#include "GSCallDivertView.h" +#include "GsLogger.h" +#include "GSPhoneSettingConstants.h" + + +// System includes: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Constants for restricted call divert +const TInt KMaxLengthSendString = 40; +_LIT( KOne, "1" ); +_LIT( KAsterisk, "*" ); +_LIT( KHashMark, "#" ); +_LIT( KOneHundredTwenty, "120" ); + +// Class neme descriptor for panic descriptions +_LIT( KGSCallDivertModel, "CGSCallDivertModel" ); + + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::CGSCallDivertModel +// --------------------------------------------------------------------------- +CGSCallDivertModel::CGSCallDivertModel() +{ +} + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::NewL +// --------------------------------------------------------------------------- +CGSCallDivertModel* CGSCallDivertModel::NewL() +{ + CGSCallDivertModel* self = new( ELeave ) CGSCallDivertModel; + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; +} + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::ConstructL +// --------------------------------------------------------------------------- +void CGSCallDivertModel::ConstructL() +{ + iContactEngine = CPbkContactEngine::NewL(); + if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) ) + { + iBasicClient = CPhCltUssd::NewL(); + } + iSettings = CPsetContainer::NewL(); + iObsContainer = CPsuiContainer::NewL(); + iCfObserver = iObsContainer->CreateCFObsL(); + iForward = iSettings->CreateCFObjectL( *iCfObserver ); + iSsSettings = new (ELeave) RSSSettings; + User::LeaveIfError( iSsSettings->Open() ); +} + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::~CGSCallDivertModel +// --------------------------------------------------------------------------- +CGSCallDivertModel::~CGSCallDivertModel() +{ + // These objects have to be deleted in specific order or otherwise a access + // violation will follow. So, if changing order, be very careful and test + // thoroughly. + delete iContactEngine; + delete iObsContainer; + delete iCfObserver; + delete iForward; + delete iSettings; + if (FeatureManager::FeatureSupported ( KFeatureIdRestrictedCallDivert ) ) + { + delete iBasicClient; + } + if( iSsSettings ) + { + iSsSettings->Close ( ); + delete iSsSettings; + } + if( iNumberGroupingRepository ) + { + delete iNumberGroupingRepository; + iNumberGroupingRepository = NULL; + } +} + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::SendCallDivertRequestL +// --------------------------------------------------------------------------- +void CGSCallDivertModel::SendCallDivertRequestL( + TCallDivertSetting& aCallDivertSetting, + RMobilePhone::TMobilePhoneServiceAction aInfo, + TBool& aVmbxDivert, + TInt aCommand, + TGSCallDivertServices aDivertService ) + { + // Set Delay time if necessary. + TInt retVal = KCFNoNeedToGetTimeValue; + + //User is doing activation + if ( aCallDivertSetting.iSetting == EActivateDiverting ) + { + if ( aCallDivertSetting.iNumber == KNullDesC ) + { + return; //User started to activate, but cancelled. + } + //Delay time needs to be set for no answer, not available. + if ( aDivertService == ECFDivertWhenNoAnswer || + aDivertService == ECFDivertWhenNotAvailable ) + { + retVal = iDivertView->CreateTimeListL(); + } + } + if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) ) + { + // Always ask for duration if it's restricted call divert + retVal = iDivertView->CreateTimeListL(); + } + //Call Phonesettings if all values have been set. + if ( retVal ) + { + if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) ) + { + __GSLOGSTRING( "[CGSCallDivertModel::SendCallDivertRequestL] -- Sending restricted call divert request: --" ); + __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aCallDivertSetting.iNumber:%S", &aCallDivertSetting.iNumber ); + __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] iDivertServiceGroup: %d", iDivertServiceGroup ); + + ActivateRestrictedCallDivertL( aCallDivertSetting.iNumber ); + } + else + { + __GSLOGSTRING( "[CGSCallDivertModel::SendCallDivertRequestL] -- Sending call divert request: --" ); + __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aCallDivertSetting.iNumber:%S", &aCallDivertSetting.iNumber ); + __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aInfo: %d", aInfo ); + __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aVmbxDivert: %d", aVmbxDivert ); + __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aCommand: %d", aCommand ); + __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aDivertService: %d", aDivertService ); + __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] iDivertServiceGroup: %d", iDivertServiceGroup ); + + // Make a call to PhoneSettings. + EngineOperatorL( aCallDivertSetting, aInfo, aVmbxDivert, aCommand, aDivertService, iDivertServiceGroup ); + } + } + } + + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::EngineOperatorL +// +// Seems to be a blocking function... +// Handles the engine operating, arguments tell what to call and +// the number if needed. +// --------------------------------------------------------------------------- +void CGSCallDivertModel::EngineOperatorL( + TCallDivertSetting& aDivert, + const RMobilePhone::TMobilePhoneServiceAction& aInfo, + TBool& aVmbxValidNumber, + TInt aCommand, + TGSCallDivertServices aDivertService, + TGSCallDivertServiceGroups aDivertServiceGroup ) + { + __GSLOGSTRING("[CGSCallDivertModel::EngineOperatorL] Start..."); + + TBasicServiceGroups bsc = EAllTeleAndBearer; + aDivert.iNoReplyTimer = 0; + + if ( aCommand == ECFCmdCancelAll ) + { + aDivert.iCondition = EDivertConditionAllCalls; + aDivert.iSetting = EEraseDiverting; + aDivert.iStatus = EDivertingStatusUnknown; + aDivert.iServiceGroup = EServiceGroupAllTeleservices; + aDivert.iNumber.Zero(); + iForward->SetDivertingL( aDivert, bsc ); + + __GSLOGSTRING("[CGSCallDivertModel::EngineOperatorL] ECFCmdCancelAll"); + return; + } + + SetDivertParametersL( aDivert, bsc, aDivertService, aDivertServiceGroup ); + __GSLOGSTRING1("[CGSCallDivertModel::EngineOperatorL] ServiceGroup: %d", bsc); + + switch ( aInfo ) + { + case RMobilePhone::EServiceActionUnspecified: + iForward->GetDivertingStatusL( aDivert.iServiceGroup, + aDivert.iCondition, + bsc ); + break; + case RMobilePhone::EServiceActionActivate: + aDivert.iSetting = EActivateDiverting; + iForward->SetDivertingL( aDivert, bsc, aVmbxValidNumber ); + break; + case RMobilePhone::EServiceActionErase: + aDivert.iSetting = EEraseDiverting; + iForward->SetDivertingL( aDivert, bsc ); + break; + case RMobilePhone::EServiceActionDeactivate: + aDivert.iSetting = ECancelDiverting; + iForward->SetDivertingL( aDivert, bsc ); + break; + case RMobilePhone::EServiceActionRegister: + aDivert.iSetting = ERegisterDiverting; + iForward->SetDivertingL( aDivert, bsc, aVmbxValidNumber ); + break; + default: + Panic ( KGSCallDivertModel, EInvalidDivertAction ); + break; + } + __GSLOGSTRING("[CGSCallDivertModel::EngineOperatorL] End."); + } + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::VoiceMailActivationL +// +// Handles activation attempts to voicemail box. +// --------------------------------------------------------------------------- +TInt CGSCallDivertModel::VoiceMailActivationL( TDes& aTelNumber ) + { + __GSLOGSTRING1("[CGSCallDivertModel::VoiceMailActivationL] aTelNumber: %S", &aTelNumber); + TRAPD( err, iForward->VoiceMailQueryL( aTelNumber ) ); + if ( err ) + { + __GSLOGSTRING1("[CGSCallDivertModel::VoiceMailActivationL] err=%d", err); + // If application is killed via FSW, contact selection query + // returns KLeaveExit. This should propagate to "root" + // application where it reaches the active scheduler loop + // and thus allows proper application exit when the loop exits. + // Therefore propagate the error to caller and do not ignore it. + if ( KLeaveExit == err ) + { + __GSLOGSTRING("[CGSCallDivertModel::VoiceMailActivationL] KLeaveExit"); + User::Leave( err ); + } + return KErrCancel; + } + //Vmbx number can be "invalid" from CF point of view, because they are allowed to + //contain special characters. These must be removed before making a divert to the + //vmbx number. + //E.g. number +35850888#45 becomes +35850888 (end is dropped). + TInt noOfInvalidChars = KCFInvalidChars().Length(); + + for ( TInt index = 0; index < noOfInvalidChars; index++ ) + { + RemoveSpecialChar( aTelNumber, KCFInvalidChars().Mid( index, 1 ) ); + } + __GSLOGSTRING1("[CGSCallDivertModel::VoiceMailActivationL] aTelNumber: %S", &aTelNumber); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::VideoMailActivationL +// +// Handles activation attempts to videomail box. +// --------------------------------------------------------------------------- +TInt CGSCallDivertModel::VideoMailActivationL( TDes& aTelNumber ) + { + __GSLOGSTRING1("[CGSCallDivertModel::VideoMailActivationL] aTelNumber: %S", &aTelNumber); + // Trapped to return KErrCancel in all cases in order to provide same + // behaviour as in VoiceMailActivationL method (Both methods can be used + // in the same manner) + TRAPD( err, iForward->VideoMailQueryL( aTelNumber ) ); + if ( err ) + { + return KErrCancel; + } + //Vmbx number can be "invalid" from CF point of view, because they are allowed to + //contain special characters. These must be removed before making a divert to the + //vmbx number. + //E.g. number +35850888#45 becomes +35850888 (end is dropped). + TInt noOfInvalidChars = KCFInvalidChars().Length(); + TPtrC invalidChars( KCFInvalidChars ); + for ( TInt index = 0; index < noOfInvalidChars; index++ ) + { + RemoveSpecialChar( aTelNumber, TPtrC( &invalidChars[ index ] ) ); + } + __GSLOGSTRING1("[CGSCallDivertModel::VideoMailActivationL] aTelNumber: %S", &aTelNumber); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::ActivateRestrictedCallDivertL +// +// Handles attempts to activate call divert in restricted mode +// --------------------------------------------------------------------------- +void CGSCallDivertModel::ActivateRestrictedCallDivertL( + TTelNumber& aDivertNumber ) + { + if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) ) + { + //Send Number and ringing time to network by using USSD. + HBufC* sendString = HBufC::NewLC( KMaxLengthSendString ); + TPtr ptr = sendString->Des(); + + //Start call forwarding has following syntax: + //*120*SI1*SI2*SI3 # SEND(Start & Set CF number & Set the time (sec.)) + //where: S1 = 1 + //SI2:(CF number) + //SI3: 0 - 120(ringing time (sec.)) + ptr.Append( KAsterisk ); + ptr.Append( KOneHundredTwenty ); + ptr.Append( KAsterisk ); + ptr.Append( KOne ); + ptr.Append( KAsterisk ); + ptr.Append( aDivertNumber ); + ptr.Append( KAsterisk ); + ptr.AppendNum( iForward->GetTimerValueL() ); + ptr.Append( KHashMark ); + + iBasicClient->SendUssd( *sendString ); + CleanupStack::PopAndDestroy( sendString ); + } + } + + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::CheckStatusRestrictedCallDivertL +// +// Handles attempts to check divert status in restricted mode +// --------------------------------------------------------------------------- +void CGSCallDivertModel::CheckStatusRestrictedCallDivertL() + { + if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) ) + { + //Check call forwarding: * # 120*SI1 # SEND + HBufC* sendString = HBufC::NewLC( KMaxLengthSendString ); + TPtr ptr = sendString->Des(); + ptr.Append( KAsterisk ); + ptr.Append( KHashMark ); + ptr.Append( KOneHundredTwenty ); + ptr.Append( KAsterisk ); + ptr.Append( KOne ); + ptr.Append( KHashMark ); + iBasicClient->SendUssd( *sendString ); + CleanupStack::PopAndDestroy( sendString ); + } + } + + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::CancelRestrictedCallDivertL +// +// Handles attempts to cancel call divert in restricted mode +// --------------------------------------------------------------------------- +void CGSCallDivertModel::CancelRestrictedCallDivertL() + { + if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) ) + { + //Cancel call forwarding: # 120*SI1 # SEND + HBufC* sendString = HBufC::NewLC( KMaxLengthSendString ); + TPtr ptr = sendString->Des(); + ptr.Append( KHashMark ); + ptr.Append( KOneHundredTwenty ); + ptr.Append( KAsterisk ); + ptr.Append( KOne ); + ptr.Append( KHashMark ); + iBasicClient->SendUssd( *sendString ); + CleanupStack::PopAndDestroy( sendString ); + } + } + + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::SetDivertParametersL +// +// Sets parameters for EngineOperator function +// --------------------------------------------------------------------------- +void CGSCallDivertModel::SetDivertParametersL( + TCallDivertSetting& aDivert, + TBasicServiceGroups& aBsc, + TGSCallDivertServices aDivertService, + TGSCallDivertServiceGroups aDivertServiceGroup ) + { + aDivert.iStatus = EDivertingStatusUnknown; + //complains for ambiguous definition of EUnknown + //need to correct in PhoneSettings. + aBsc = ( TBasicServiceGroups )-1; + + if ( aDivertServiceGroup == EGSSettIdVoiceDivert ) + { + aDivert.iServiceGroup = EServiceGroupVoice; + } + else + { + aDivert.iServiceGroup = EServiceGroupData; + aBsc = EAllBearer; + } + + switch ( aDivertService ) + { + case ECFDivertVoiceCalls: + { + aDivert.iCondition = EDivertConditionUnconditional; + TInt alsLine = ESSSettingsAlsNotSupported; + TInt alsError = iSsSettings->Get( ESSSettingsAls, alsLine ); + if ( alsLine == ESSSettingsAlsNotSupported || ( alsLine == ESSSettingsAlsPrimary ) ) + { + // Etelephony only activates voice service nothing else or causes + // voice service status request. + aBsc = ETelephony; + } + else // ESSSettingsAlsAlternate + { + // EAltTele only activates alternate service nothing else or causes + // alternate service status request. + aBsc = EAltTele; + } + break; + } + case ECFDivertWhenBusy: + aDivert.iCondition = EDivertConditionBusy; + break; + case ECFDivertWhenNoAnswer: + aDivert.iCondition = EDivertConditionNoReply; + aDivert.iNoReplyTimer = iForward->GetTimerValueL(); + break; + case ECFDivertWhenOutOfReach: + aDivert.iCondition = EDivertConditionNotReachable; + break; + case ECFDivertWhenNotAvailable: + aDivert.iCondition = EDivertConditionAllConditionalCases; + aDivert.iNoReplyTimer = iForward->GetTimerValueL(); + break; + case ECFDivertVideoCalls: + aBsc = EAllBearer; + aDivert.iCondition = EDivertConditionUnconditional; + break; + default: + Panic ( KGSCallDivertModel, EInvalidCurrentItem ); + break; + } + } + + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::MatchNumberToContactLC +// +// Returns the contact name matching the number, or the number if +// no contact name is found. +// Pushes the found (i.e. returned) name into Cleanupstack. +// @see CContactDatabase::MatchPhoneNumberL(const TDesC&,const TInt) +// --------------------------------------------------------------------------- +HBufC* CGSCallDivertModel::MatchNumberToContactLC( const TDesC& aTelNum ) + { + CContactIdArray* idArray = iContactEngine->MatchPhoneNumberL( + aTelNum, + KCFCharactersToMatch ); + CleanupStack::PushL( idArray ); + HBufC* contactTitle = NULL; + // fill data only if only single match is found + TInt matches = idArray->Count(); + TBool conflict = EFalse; + if ( matches >= KCFSingleContact ) + { + //several matches, have to check that id is the same + if ( matches != KCFSingleContact ) + { + for ( TInt i = 1 ; i < matches ; i++ ) + { + //all have to have same ID + if ( (*idArray)[i] != (*idArray)[0] ) + { + conflict = ETrue; + break; //stop comparing + } + } + } + //Contact names are only shown if single match with same ID. + if ( !conflict ) + { + CPbkContactItem* pbkItem = + iContactEngine->ReadContactLC( ( *idArray )[0] ); + contactTitle = iContactEngine->GetContactTitleL( *pbkItem ); + CleanupStack::PopAndDestroy( pbkItem ); + } + } + CleanupStack::PopAndDestroy( idArray ); + CleanupStack::PushL( contactTitle ); + if( contactTitle ) + { + __GSLOGSTRING1("[CGSCallDivertModel::MatchNumberToContactLC] contactTitle: %S", &contactTitle); + } + return contactTitle; + } + + +// --------------------------------------------------------------------------- +// Removes a special character from vmbx number. +// --------------------------------------------------------------------------- +void CGSCallDivertModel::RemoveSpecialChar( TDes& aVmbxNumber, + const TDesC& aSpecChar ) + { + TInt location = aVmbxNumber.Find( aSpecChar ); + if ( location != KErrNotFound ) + { + aVmbxNumber = aVmbxNumber.Left( location ); + } + } + + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::DivertHandler +// --------------------------------------------------------------------------- +CPsetCallDiverting* CGSCallDivertModel::DivertHandler() + { + return iForward; + } + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::SetDivertView +// --------------------------------------------------------------------------- +void CGSCallDivertModel::SetDivertView( CGSCallDivertView* aDivertView ) + { + iDivertView = aDivertView; + } + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::CGSCallDivertModel +// --------------------------------------------------------------------------- +TGSCallDivertServiceGroups CGSCallDivertModel::DivertServiceGroup() + { + return iDivertServiceGroup; + } + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::SetDivertServiceGroup +// --------------------------------------------------------------------------- +void CGSCallDivertModel::SetDivertServiceGroup( + TGSCallDivertServiceGroups aDivertServiceGroup ) + { + iDivertServiceGroup = aDivertServiceGroup; + __GSLOGSTRING1( "[CGSCallDivertModel::SetDivertServiceGroup] aDivertServiceGroup:%d ", + aDivertServiceGroup ) + } + + + +// --------------------------------------------------------------------------- +// CGSCallDivertModel::NumberGroupingSupportedL +// +// --------------------------------------------------------------------------- +TBool CGSCallDivertModel::NumberGroupingSupportedL() + { + TInt numberGroupingVal; + TBool retVal = EFalse; + if( !iNumberGroupingRepository ) + { + iNumberGroupingRepository = CRepository::NewL( KCRUidNumberGrouping ); + } + iNumberGroupingRepository->Get( KNumberGrouping, numberGroupingVal ); + switch( numberGroupingVal ) + { + case CPNGNumberGrouping::ENumberGroupingDisabled: + retVal = EFalse; + break; + case CPNGNumberGrouping::ENumberGroupingEnabled: + retVal = ETrue; + break; + default: + retVal = EFalse; + break; + } + return retVal; + } +