diff -r c3e98f10fcf4 -r 388a17646e40 localconnectivityservice/modematplugin/src/atcopscmd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/localconnectivityservice/modematplugin/src/atcopscmd.cpp Tue Feb 02 00:45:58 2010 +0200 @@ -0,0 +1,1109 @@ +/* +* Copyright (c) 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: Handles the commands "AT+COPS?", "AT+COPS=?" and "AT+COPS=..." +* +*/ + + +#include +#include "atcopscmd.h" +#include "cmdpluginobserver.h" +#include "debug.h" + +_LIT8( KCOPSTestCmd, "AT+COPS=?"); +_LIT8( KCOPSReadCmd, "AT+COPS?"); +_LIT8( KCOPSSetCmd, "AT+COPS="); + +_LIT8(KSupportedModesStr, ",(0,1,3,4)"); +_LIT8(KSupportedFormatsStr, ",(0,1,2)"); + +// The parameters are in predefined indexes in an incoming AT command. +const TInt KModeParameterIndex = 0; +const TInt KFormatParameterIndex = 1; +const TInt KOperatorParameterIndex = 2; +const TInt KAccessTechnologyParameterIndex = 3; + +const TInt KMinimumParameterCountWhenModePresent = 1; +const TInt KMinimumParameterCountWhenFormatPresent = 2; +const TInt KMinimumParameterCountWhenOperatorPresent = 3; +const TInt KMinimumParameterCountWhenAccTechPresent = 4; + +// These parameter lengths are derived from 3GPP TS 27.007 V8.4.1 +const TInt KShortOperatorNameFormatLength = 10; +const TInt KLongOperatorNameFormatLength = 20; +const TInt KNumericOperatorNameFormatLength = 5; +const TInt KMaxNetworkTestResponseAdditionalSize = 17; // The maximun length of parts of fixed length. +const TInt KMaxNetworkReadResponseAdditionalSize = 28 ; // The maximun length of parts fixed length. + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CATCOPSCmd* CATCOPSCmd::NewL( MCmdPluginObserver* aCallback ) + { + CATCOPSCmd* self = new (ELeave) CATCOPSCmd( aCallback ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CATCOPSCmd::~CATCOPSCmd() + { + iParamArray.ResetAndDestroy(); + iParamArray.Close(); + iPacketService.Close(); + iCustomApi.Close(); + iPhone.Close(); + iServer.Close(); + delete iDetectedNetworks; + delete iRetrieveDetectedNetworks; + } + +// --------------------------------------------------------------------------- +// CATCOPSCmd::CATCOPSCmd +// --------------------------------------------------------------------------- +// +CATCOPSCmd::CATCOPSCmd( MCmdPluginObserver* aCallback ) : + CActive(EPriorityStandard), + iCallback( aCallback ), + iFormat(RMmCustomAPI::EOperatorNameMccMnc), + iRegistrationMode(EModeAutomatic), + iAccTech(EAccTechNotSet), + iCurrentOperation(EIdle) + { + iCmdHandlerType = ECmdHandlerTypeUndefined; + } + +// --------------------------------------------------------------------------- +// CATCOPSCmd::ConstructL +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::ConstructL() + { + if ( !iCallback ) + { + User::Leave( KErrGeneral ); + } + CActiveScheduler::Add(this); + LEAVE_IF_ERROR(iServer.Connect()); + LEAVE_IF_ERROR(iServer.LoadPhoneModule(KMmTsyModuleName)); + LEAVE_IF_ERROR(iPhone.Open(iServer, KMmTsyPhoneName)); + LEAVE_IF_ERROR(iCustomApi.Open(iPhone)); + LEAVE_IF_ERROR(iPacketService.Open(iPhone)); + iRetrieveDetectedNetworks = CRetrieveMobilePhoneDetectedNetworks::NewL(iPhone); + } + +// --------------------------------------------------------------------------- +// Reports the support status of an AT command. This is a synchronous API. +// --------------------------------------------------------------------------- +// +TBool CATCOPSCmd::IsCommandSupported( const TDesC8& aCmd ) + { + TRACE_FUNC_ENTRY + TInt retTemp = KErrNone; + + // First test if "test" command, because the pattern is similar with the "set" command, + // this is just one extra question mark longer than that. + retTemp = aCmd.Compare( KCOPSTestCmd ); + if ( retTemp == 0 ) + { + iCmdHandlerType = ECmdHandlerTypeTest; + TRACE_FUNC_EXIT + return ETrue; + } + + retTemp = aCmd.Compare( KCOPSReadCmd ); + if ( retTemp == 0 ) + { + iCmdHandlerType = ECmdHandlerTypeRead; + TRACE_FUNC_EXIT + return ETrue; + } + + // Test if the beginning matches the test command pattern. We're skipping parameters + // here on purpose, because "set" handler will create an error reply later if + // parameters are not valid. + retTemp = aCmd.Left(KCOPSSetCmd().Length()).Compare(KCOPSSetCmd); + if ( retTemp == 0 ) + { + iCmdHandlerType = ECmdHandlerTypeSet; + TRACE_FUNC_EXIT + return ETrue; + } + + iCmdHandlerType = ECmdHandlerTypeUndefined; + TRACE_FUNC_EXIT + return EFalse; + } + +// --------------------------------------------------------------------------- +// Handles an AT command. Cancelling of the pending request is done by +// HandleCommandCancel(). The implementation in the extension plugin should +// be asynchronous. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::HandleCommand( const TDesC8& aCmd, + RBuf8& aReply, + TBool aReplyNeeded ) + { + TRACE_FUNC_ENTRY + + if ( !aReplyNeeded ) + { + TRACE_FUNC_EXIT + return; + } + + if(iCurrentOperation != EIdle) + { + // only one call at time allowed. If another one is passed in, + // then cancel the previous and reply with an error. + HandleCommandCancel(); + CreateReply(EFalse); + } + + if ( iCmdHandlerType == ECmdHandlerTypeUndefined ) + { + CreateReply(EFalse); + } + + if ( iCmdHandlerType == ECmdHandlerTypeTest ) + { + // Collect network data and complete in RunL + iRetrieveDetectedNetworks->StartV2(iStatus); + iCurrentOperation = EListAvailableNetworkOperators; + SetActive(); + TRACE_FUNC_EXIT + return; + } + +/* +Read command returns the current mode, the currently selected operator +and the current Access Technology. If no operator is selected, , + and < AcT> are omitted. +*/ + if ( iCmdHandlerType == ECmdHandlerTypeRead ) + { + // Collect data in two steps. First read operator name. Continue in RunL() + RMobilePhone::TMobilePhoneNetworkSelectionV1 selection; + RMobilePhone::TMobilePhoneNetworkSelectionV1Pckg nwSelectionSetting(selection); + iPhone.GetNetworkSelectionSetting(nwSelectionSetting); + switch(selection.iMethod) + { + case RMobilePhone::ENetworkSelectionAutomatic: + iRegistrationMode = EModeAutomatic; + break; + case RMobilePhone::ENetworkSelectionManual: + iRegistrationMode = EModeManual; + break; + default: + // Cannot get a known selection mode! + TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- Cannot get a known selection mode!")); + CreateReply(EFalse); + TRACE_FUNC_EXIT + return; + } + RMobilePhone::TMobilePhoneNetworkInfoV2Pckg nwInfo(iNetworkInfo); + iPhone.GetCurrentNetwork(iStatus, nwInfo); + iCurrentOperation = EGetNetworkInfoOperatorName; + SetActive(); + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation)); + TRACE_FUNC_EXIT + return; + } + + // Getting this far means ECmdHandlerTypeSet. There must be parameter(s), too. + TRAPD(err, ExtractParametersL(aCmd)); + + // Check that we got some parameters, at least the "mode". If not, return an error: + if(iParamArray.Count() < KMinimumParameterCountWhenModePresent) + { + // Return error response, there were no parameters! + TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- no parameters!")); + CreateReply(EFalse); + TRACE_FUNC_EXIT + return; + } + + // At least the mode parameter is present at this point. Inspect it and check other parameters. + TNetworkRegistrationMode mode; + err = GetModeAndCheckParameterCount(iParamArray[KModeParameterIndex]->Des(), mode); + if(err != KErrNone) + { + // Return error response, invalid mode or other parameters! + TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- invalid mode or other parameters!")); + CreateReply(EFalse); + TRACE_FUNC_EXIT + return; + } + + // At this point the iRegistrationMode is stored and the parameters are valid. + iRegistrationMode = mode; + TRACE_INFO(( _L("CATCOPSCmd::HandleCommand() mode stored (%d)"), iRegistrationMode)); + + if(iParamArray.Count() > 1) + { + // If also format is present, extract it and store for later reference. + RMmCustomAPI::TOperatorNameType format; + err = GetFormatFromParameter(iParamArray[KFormatParameterIndex]->Des(), format); + if(err != KErrNone) + { + // Return an error, invalid format. + // Previously set format is still in use. + TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- invalid format!")); + CreateReply(EFalse); + TRACE_FUNC_EXIT + return; + } + // Format parameter is OK, keep it. + iFormat = format; + TRACE_INFO(( _L("CATCOPSCmd::HandleCommand() format stored (%d)"), iFormat)); + } + + // We're done with the required parameters, it's time to start processing the command. + // So do a self complete and continue in RunL(): + iReply = &aReply; // Store the reply for later reference in RunL. + iCurrentOperation = EInspectModeAndProcessCommand; + TRequestStatus *status = &iStatus; + User::RequestComplete(status, KErrNone); + SetActive(); + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation)); + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// Parses the aCmd parameter and stores results in iParamArray. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::ExtractParametersL(const TDesC8& aCmd) + { + TRACE_FUNC_ENTRY + + TRACE_INFO(( _L8("CATCOPSCmd::ExtractParameters() extracting (%S)"), &aCmd)); + + TPtrC8 parameters = aCmd.Right(aCmd.Length() - KCOPSSetCmd().Length()); + + iParamArray.ResetAndDestroy(); + + // Parse the parameters into the parameter array: + TInt separatorPos; + while((separatorPos = parameters.Locate(',')) != KErrNotFound) + { + TRACE_INFO(( _L("CATCOPSCmd::ExtractParameters() separator position (%d)"), separatorPos)); + TPtrC8 param = parameters.Left(separatorPos); + parameters.Set(parameters.Right(parameters.Length() - (separatorPos + 1))); // Remove the extracted part + separator + HBufC8 *heapParam = param.AllocL(); + CleanupStack::PushL( heapParam ); + // Strip the quotation marks from the parameter: + TPtr8 ptr = heapParam->Des(); + RemoveQuotationMarks(ptr); + TRACE_INFO(( _L8("CATCOPSCmd::ExtractParameters() appending (%S)"), &ptr)); + iParamArray.Append(heapParam); + CleanupStack::Pop( heapParam ); + } + + // Finally append the last piece of parameters: + HBufC8 *param = parameters.AllocL(); + CleanupStack::PushL( param ); + TPtr8 ptr = param->Des(); + RemoveQuotationMarks(ptr); + TRACE_INFO(( _L8("CATCOPSCmd::ExtractParameters() appending (%S)"), &ptr)); + iParamArray.Append(param); + CleanupStack::Pop( param ); + + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// Strips all quotation parms from the string passed in. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::RemoveQuotationMarks(TPtr8& aParameter) + { + TRACE_FUNC_ENTRY + // Strip the quotation marks from the parameter: + TInt quotePos; + while((quotePos = aParameter.Locate('"')) != KErrNotFound) + { + aParameter.Delete(quotePos,1); + } + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// Returns the selected mode in aMode and checks the parameter count. +// --------------------------------------------------------------------------- +// +TInt CATCOPSCmd::GetModeAndCheckParameterCount(const TDesC8& aParameter, TNetworkRegistrationMode &aMode) + { + TRACE_FUNC_ENTRY + TLex8 lex; + lex.Assign(aParameter); + TInt mode(0); + + TInt err = lex.Val(mode); + TRACE_INFO(( _L("CATCOPSCmd::GetModeAndCheckParameterCount() mode (%d)"), mode)); + + if( err != KErrNone ) + { + TRACE_INFO(_L("CATCOPSCmd::GetModeAndCheckParameterCount() TLex error!)")); + TRACE_FUNC_EXIT + return KErrArgument; + } + + if(mode < EModeAutomatic || mode > EModeManualAutomatic || mode == EModeDeregister) + { + // Not a valid mode. + TRACE_FUNC_EXIT + return KErrArgument; + } + + if( (mode == EModeManual || mode == EModeManualAutomatic) && iParamArray.Count() < KMinimumParameterCountWhenOperatorPresent ) + { + // Valid modes but not enough parameters. At least format and operator needed. + TRACE_INFO(( _L("CATCOPSCmd::GetModeAndCheckParameterCount() not enough parameters (%d)"), iParamArray.Count())); + TRACE_FUNC_EXIT + return KErrArgument; + } + if( mode == EModeSetFormatParameter && iParamArray.Count() < KMinimumParameterCountWhenFormatPresent ) + { + // Valid mode, but not enough parameters. Format is needed. + TRACE_INFO(_L("CATCOPSCmd::GetModeAndCheckParameterCount() no format parameter)")); + TRACE_FUNC_EXIT + return KErrArgument; + } + + // Valid mode and enough parameters. + aMode = static_cast(mode); + + TRACE_FUNC_EXIT + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Converts an AT command parameter to numeric format value and checks it is valid. +// --------------------------------------------------------------------------- +// +TInt CATCOPSCmd::GetFormatFromParameter(const TDesC8& aParameter, RMmCustomAPI::TOperatorNameType &aFormat) + { + TRACE_FUNC_ENTRY + TLex8 lex; + lex.Assign(aParameter); + TInt format(0); + TInt err = lex.Val(format); + + if(err != KErrNone) + { + TRACE_FUNC_EXIT + return KErrArgument; + } + switch(format) + { + case EFormatLong: // long by 3GPP TS 27.007 V8.4.1 + TRACE_INFO(_L("Format is long by 3GPP TS 27.007 V8.4.1")); + aFormat = RMmCustomAPI::EOperatorNameNitzFull; + break; + case EFormatShort: // short by 3GPP TS 27.007 V8.4.1 + TRACE_INFO(_L("Format is short by 3GPP TS 27.007 V8.4.1")); + aFormat = RMmCustomAPI::EOperatorNameNitzShort; + break; + case EFormatNumeric: // numeric by 3GPP TS 27.007 V8.4.1 + TRACE_INFO(_L("Format is numeric by 3GPP TS 27.007 V8.4.1")); + aFormat = RMmCustomAPI::EOperatorNameMccMnc; + // Operator is numeric, conver it into S60 style. + break; + default: + TRACE_FUNC_EXIT + return KErrArgument; + } + + TRACE_FUNC_EXIT + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Converts an AT command parameter to numeric access technology value and checks it is valid. +// --------------------------------------------------------------------------- +// +TInt CATCOPSCmd::GetAccTechFromParameter(const TDesC8& aParameter, TAccessTechnology& aAccTech) + { + TRACE_FUNC_ENTRY + TLex8 lex; + lex.Assign(aParameter); + TInt accTech(0); + TInt err = lex.Val(accTech); + + if(err != KErrNone) + { + TRACE_FUNC_EXIT + return KErrArgument; + } + + if(accTech != EGSM && accTech != EUDMA) // The only allowed access technologies. + { + TRACE_FUNC_EXIT + return KErrArgument; + } + + aAccTech = static_cast(accTech); + + TRACE_FUNC_EXIT + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Converts an AT command parameter to ETel compatible operator values +// --------------------------------------------------------------------------- +// +TInt CATCOPSCmd::ConvertOperatorToMccMnc(const CMobilePhoneNetworkListV2 *aDetectedNetworks, + const RMmCustomAPI::TOperatorNameType aFormat, + const TBuf& aOperatorParameter, + RMobilePhone::TMobilePhoneNetworkCountryCode& aMcc, + RMobilePhone::TMobilePhoneNetworkIdentity& aMnc) + { + TRACE_FUNC_ENTRY + + if(aFormat == RMmCustomAPI::EOperatorNameMccMnc) + { + // Check first that there are at least five characters passed in. + TChar nextChar; + if(aOperatorParameter.Length() < 5) + { + return KErrArgument; + } + for(int i = 0; i < 5; ++i) + { + nextChar = aOperatorParameter[i]; + if(!nextChar.IsDigit()) + { + return KErrArgument; + } + } + // Operator is in three digit country code + two digit network code format. + // Must be converted to ETel style. The possible extra will be simply discarded. + TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() operator is all digits, convert it into ETel data types.")); + aMcc.Copy(aOperatorParameter.Left(3)); + aMnc.Copy(aOperatorParameter.Right(2)); + } + else // The short or long text string formats. + { + // Find the requested operator from the operator array. + // If array is empty, return an error. + if(!aDetectedNetworks) + { + TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() No detected networks!")); + TRACE_FUNC_EXIT + return KErrNotFound; + } + + RMobilePhone::TMobilePhoneNetworkInfoV2 nwInfo; + for(TInt i=0; i < iDetectedNetworks->Enumerate(); ++i) + { + TRAPD(err, nwInfo = iDetectedNetworks->GetEntryL(i)) + if(err != KErrNone) + { + return KErrNotFound; + } + + if(aFormat == RMmCustomAPI::EOperatorNameNitzShort) + { + TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() Operator is in short format, comparing.")); + if(nwInfo.iShortName.Compare(aOperatorParameter) == 0) + { + TRACE_INFO(_L("Match found.")); + aMcc = nwInfo.iCountryCode; + aMnc = nwInfo.iNetworkId; + TRACE_FUNC_EXIT + return KErrNone; + } + } + else if(aFormat == RMmCustomAPI::EOperatorNameNitzFull) + { + TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() Operator is in long format, comparing.")); + if(nwInfo.iLongName.Compare(aOperatorParameter) == 0) + { + TRACE_INFO(_L("Match found.")); + aMcc = nwInfo.iCountryCode; + aMnc = nwInfo.iNetworkId; + TRACE_FUNC_EXIT + return KErrNone; + } + } + else + { + TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() Unknown operator format!")); + TRACE_FUNC_EXIT + return KErrArgument; + } + } + TRACE_INFO(_L("CATCOPSCmd::ConvertOperatorToMccMnc() Operator was not found in list!")); + TRACE_FUNC_EXIT + return KErrNotFound; + } + + TRACE_FUNC_EXIT + return KErrNone; + } + + +// --------------------------------------------------------------------------- +// Initiates an automatic network registration. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::AutomaticNetworkRegistration() + { + TRACE_FUNC_ENTRY + RMobilePhone::TMobilePhoneNetworkManualSelection nwInfo; + iCurrentOperation = EAutomaticallyRegisterToNetwork; + nwInfo.iCountry = KNullDesC; + nwInfo.iNetwork = KNullDesC; + iPhone.SelectNetwork(iStatus, EFalse, nwInfo); + SetActive(); // Response will be sent in RunL + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation)); + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// Initiates a manual network registration. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::ManualNetworkRegistration(const RMobilePhone::TMobilePhoneNetworkCountryCode& aMcc, + const RMobilePhone::TMobilePhoneNetworkIdentity& aMnc) + { + TRACE_FUNC_ENTRY + RMobilePhone::TMobilePhoneNetworkManualSelection nwInfo; + iCurrentOperation = EManuallyRegisterToNetwork; + nwInfo.iCountry.Append(aMcc); + nwInfo.iNetwork.Append(aMnc); + iPhone.SelectNetwork(iStatus, ETrue, nwInfo); + SetActive(); // Response will be sent in RunL + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation)); + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// Initiates a manual network registration and access technology selection. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::ManualNetworkRegistration(const RMobilePhone::TMobilePhoneNetworkCountryCode& aMcc, + const RMobilePhone::TMobilePhoneNetworkIdentity& aMnc, + const TAccessTechnology aAccTech) + { + TRACE_FUNC_ENTRY + // Store access technology for later reference: + iAccTech = aAccTech; + // Call another overload to start the first phase of the operation: + ManualNetworkRegistration(aMcc, aMnc); + // Set the state again so the RunL knows to launch the next phase: + iCurrentOperation = EManuallyRegisterToNetworkAndChooseAccTech; + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation)); + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// CATCOPSCmd::RunL +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::RunL() + { + TRACE_FUNC_ENTRY + TInt err = KErrNone; + if(iStatus != KErrNone) + { + HandleError(); + } + // Proceed to next step or return a response if all is done. + switch(iCurrentOperation) + { + case EListAvailableNetworkOperators: + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() completing operation (%d)"), iCurrentOperation)); + if(iDetectedNetworks) + { + delete iDetectedNetworks; + iDetectedNetworks = NULL; + } + iDetectedNetworks = iRetrieveDetectedNetworks->RetrieveListV2L(); + // Then create a response. + TRAP(err, ConstructNetworkListResponseL()); + if(err != KErrNone) + { + // An error here means that no response has been sent. Reply with an error. + CreateReply(EFalse); + } + break; + + case EInspectModeAndProcessCommand: + // Check the mode and act accordingly + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() completing operation (%d)"), iCurrentOperation)); + err = InspectModeAndProcessCommand(); + if(err != KErrNone) + { + CreateReply(EFalse); + } + break; + + case EGetNetworkInfoOperatorName: + if(ConstructNetworkInfoResponse() != KErrNone) + { + // An error means that no response has been sent. Reply with an error. + CreateReply(EFalse); + } + break; + + case EManuallyRegisterToNetworkAndChooseAccTech: + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() completing operation (%d)"), iCurrentOperation)); + switch(iAccTech) + { + case EGSM: + iCustomApi.SetSystemNetworkMode(iStatus, RMmCustomAPI::KCapsNetworkModeGsm); + iCurrentOperation = ESetSystemNetworkBand; + SetActive(); + break; + case EUDMA: + iCustomApi.SetSystemNetworkMode(iStatus, RMmCustomAPI::KCapsNetworkModeUmts); + iCurrentOperation = ESetSystemNetworkBand; + SetActive(); + break; + default: + // No automatic registering requested, so send back an error response. + TRACE_INFO( _L("CATCOPSCmd::RunL() incorrect acc.tech., reply an error.")); + CreateReply(EFalse); + } + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() starting operation (%d)"), iCurrentOperation)); + break; + + case EManuallyRegisterToNetwork: + case EAutomaticallyRegisterToNetwork: + case ESetSystemNetworkBand: + TRACE_INFO((_L("CATCOPSCmd::HandleCommand() completing operation (%d)"), iCurrentOperation)); + // Last step completed successfully, so create OK response. + CreateReply(ETrue); + break; + + default: + TRACE_INFO(( _L("CATCOPSCmd::RunL() default operation (%d)!"), iCurrentOperation)); + break; + } + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// Handles an error in async call. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::HandleError() + { + TRACE_FUNC_ENTRY + TRACE_INFO(( _L("CATCOPSCmd::RunL() failure (%d) in operation (%d)!"), iStatus.Int(), iCurrentOperation)); + + // In case of failure check the operation. In some cases failures are OK. + switch(iCurrentOperation) + { + case EManuallyRegisterToNetwork: + if(iRegistrationMode == EModeManualAutomatic) + { + // Manual registration failed, try automatic next. + TRACE_INFO( _L("CATCOPSCmd::RunL() registration mode manual automatic, try automatic.")); + AutomaticNetworkRegistration(); + } + else + { + // No automatic registering requested, so send back an error response. + TRACE_INFO( _L("CATCOPSCmd::RunL() reply an error.")); + CreateReply(EFalse); + } + break; + case ESetSystemNetworkBand: + case EManuallyRegisterToNetworkAndChooseAccTech: + // Cannot set the access technology, so set it back to EAccTechNotSet. + // This prevents replying to queries with outdated or incorrect acc tech information. + TRACE_INFO( _L("CATCOPSCmd::RunL() couldn't set system network band, so reset access tech.")); + iAccTech = EAccTechNotSet; + // Fall through to default, because these require an error response. + + default: + // In all other cases send back an error response. + TRACE_INFO( _L("CATCOPSCmd::RunL() reply an error.")); + CreateReply(EFalse); + break; + } + TRACE_FUNC_EXIT + } + + +// --------------------------------------------------------------------------- +// Cancels a pending HandleCommand request. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::HandleCommandCancel() + { + TRACE_FUNC_ENTRY + Cancel(); + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// CATCOPSCmd::DoCancel +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::DoCancel() + { + TRACE_FUNC_ENTRY + switch(iCurrentOperation) + { + case EAutomaticallyRegisterToNetwork: + case EManuallyRegisterToNetwork: + case EManuallyRegisterToNetworkAndChooseAccTech: + iPhone.CancelAsyncRequest(EMobilePhoneSelectNetworkCancel); + break; + case EGetNetworkInfoOperatorName: + iPhone.CancelAsyncRequest(EMobilePhoneGetCurrentNetworkCancel); + break; + case ESetSystemNetworkBand: + iCustomApi.CancelAsyncRequest(ECustomSetSystemNetworkModeIPC); + break; + case EListAvailableNetworkOperators: + iRetrieveDetectedNetworks->Cancel(); + break; + default: + break; + } + + iCurrentOperation = EIdle; + + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// Helper method for RunL() +// --------------------------------------------------------------------------- +// +TInt CATCOPSCmd::InspectModeAndProcessCommand() + { + TRACE_FUNC_ENTRY + TBuf buf; + TInt err; + + switch (iRegistrationMode) + { + case EModeAutomatic: + AutomaticNetworkRegistration(); + break; + case EModeManual: + case EModeManualAutomatic: // see also RunL() + if(iParamArray.Count() < KMinimumParameterCountWhenOperatorPresent) + { + TRACE_FUNC_EXIT + return KErrArgument; + } + + // At least the operator is present, so convert it into S60 format. + buf.Copy(iParamArray[KOperatorParameterIndex]->Des()); + err = ConvertOperatorToMccMnc(iDetectedNetworks, iFormat, buf, iMcc, iMnc); + if(err != KErrNone) + { + TRACE_INFO(_L("CATCOPSCmd::HandleCommand() -- operator conversion failed!")); + TRACE_FUNC_EXIT + return KErrArgument; + } + + if (iParamArray.Count() >= KMinimumParameterCountWhenAccTechPresent) + { + // Also access tech. is present. Convert it to ETel compatible value. + TAccessTechnology accTech; + TInt err = GetAccTechFromParameter(iParamArray[KAccessTechnologyParameterIndex]->Des(), accTech); + if(err != KErrNone) + { + // Parameter problem, return an error. + TRACE_FUNC_EXIT + return KErrArgument; + } + // Register both operator and access technology manually. + ManualNetworkRegistration(iMcc, iMnc, accTech); + } + else + { + // No access technology parameter, so register just the operator. + ManualNetworkRegistration(iMcc, iMnc); + } + break; + case EModeDeregister: // Deregister from network + // Not supported, return an error. + TRACE_FUNC_EXIT + return KErrArgument; + case EModeSetFormatParameter: + // Storing format parameter was done already, so just reply OK. + CreateReply(ETrue); + TRACE_FUNC_EXIT + return KErrNone; + default: + return KErrArgument; + } + TRACE_FUNC_EXIT + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Converts the ETel access technology into 3GPP TS 27.007 V8.4.1 compatible format. +// --------------------------------------------------------------------------- +// +TInt CATCOPSCmd::SolveAccessTechnology(RMobilePhone::TMobilePhoneNetworkAccess &aAccessTech) + { + TRACE_FUNC_ENTRY + + TUint caps; + if(iPacketService.GetStaticCaps(caps, RPacketContext::EPdpTypePPP) != KErrNone) + { + TRACE_FUNC_EXIT + return KErrGeneral; + } + + TRACE_INFO(( _L8("CATCOPSCmd::SolveAccessTechnology() static caps gotten (%b)"), caps)); + + switch(aAccessTech) + { + case RMobilePhone::ENetworkAccessGsm: + if(caps & RPacketService::KCapsEGPRSSupported) + { + iAccTech = EGSMwithEGPRS; + } + else + { + iAccTech = EGSM; + } + break; + case RMobilePhone::ENetworkAccessGsmCompact: + iAccTech = EGSMCompact; + break; + case RMobilePhone::ENetworkAccessUtran: + if(caps & RPacketService::KCapsHSDPASupported) + { + if(caps & RPacketService::KCapsHSUPASupported) + { + iAccTech = EUDMAwithHSDPAandHSUPA; + } + else + { + iAccTech = EHSDPA; + } + } + else if(caps & RPacketService::KCapsHSUPASupported) + { + iAccTech = EHSUPA; + } + else + { + iAccTech = EUDMA; + } + break; + default: + TRACE_INFO( _L("CATCOPSCmd::SolveAccessTechnology() unknown access tech!")); + iAccTech = EAccTechNotSet; + return KErrArgument; + } + TRACE_FUNC_EXIT + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Contructs a response for the read command. +// --------------------------------------------------------------------------- +// +TInt CATCOPSCmd::ConstructNetworkInfoResponse() + { + TRACE_FUNC_ENTRY + RBuf8 reply; + TInt size(KMaxNetworkTestResponseAdditionalSize + KLongOperatorNameFormatLength); + TChar carriageReturn; + TChar lineFeed; + TInt err; + err = reply.Create(size); + err |= iCallback->GetCharacterValue( ECharTypeCR, carriageReturn ); + err |= iCallback->GetCharacterValue( ECharTypeLF, lineFeed ); + if(err != KErrNone) + { + return err; + } + + // Some PC Software expects and extra CR+LF, hence those are added twice: + reply.Append( carriageReturn ); + reply.Append( lineFeed ); + reply.Append( carriageReturn ); + reply.Append( lineFeed ); + reply.Append(_L("+COPS: ")); + reply.AppendNum(iRegistrationMode); + reply.Append(_L(",")); + switch(iFormat) + { + case RMmCustomAPI::EOperatorNameNitzFull: + reply.AppendNum(EFormatLong); + reply.Append(_L(",")); + reply.Append(_L("\"")); + TRACE_INFO(( _L8("CATCOPSCmd::ConstructNetworkInfoResponse() appending (%S)"), + &iNetworkInfo.iLongName)); + reply.Append(iNetworkInfo.iLongName); + break; + case RMmCustomAPI::EOperatorNameNitzShort: + reply.AppendNum(EFormatShort); + reply.Append(_L(",")); + reply.Append(_L("\"")); + TRACE_INFO(( _L8("CATCOPSCmd::ConstructNetworkInfoResponse() appending (%S)"), + &iNetworkInfo.iShortName)); + reply.Append(iNetworkInfo.iShortName); + break; + case RMmCustomAPI::EOperatorNameMccMnc: + reply.AppendNum(EFormatNumeric); + reply.Append(_L(",")); + reply.Append(_L("\"")); + TRACE_INFO(( _L8("CATCOPSCmd::ConstructNetworkInfoResponse() appending codes (%S) and (%S)"), + &iNetworkInfo.iCountryCode, &iNetworkInfo.iNetworkId)); + reply.Append(iNetworkInfo.iCountryCode); + reply.Append(iNetworkInfo.iNetworkId); + break; + } + reply.Append(_L("\"")); + + if(SolveAccessTechnology(iNetworkInfo.iAccess) == KErrNone && iAccTech != EAccTechNotSet) + { + TRACE_INFO((_L("CATCOPSCmd::ConstructNetworkInfoResponse() appending acc. tech. (%d)"), + iAccTech)); + reply.Append(_L(",")); + reply.AppendNum(iAccTech); + } + + reply.Append( carriageReturn ); + reply.Append( lineFeed ); + + CreateReply(ETrue, reply); + + TRACE_FUNC_EXIT + return KErrNone; + } + + +// --------------------------------------------------------------------------- +// Contructs a response for the test command. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::ConstructNetworkListResponseL() + { + TRACE_FUNC_ENTRY + RBuf8 reply; + TChar carriageReturn; + TChar lineFeed; + + TInt maxItemSize(KMaxNetworkReadResponseAdditionalSize + + KShortOperatorNameFormatLength + + KLongOperatorNameFormatLength + + KNumericOperatorNameFormatLength + + KSupportedModesStr().Length() + + KSupportedFormatsStr().Length()); + + CleanupClosePushL(reply); + + User::LeaveIfNull(iDetectedNetworks); + User::LeaveIfError(reply.Create( maxItemSize * iDetectedNetworks->Enumerate())); + User::LeaveIfError(iCallback->GetCharacterValue( ECharTypeCR, carriageReturn )); + User::LeaveIfError(iCallback->GetCharacterValue( ECharTypeLF, lineFeed )); + + // Some PC Software expects and extra CR+LF, hence those are added twice: + reply.Append( carriageReturn ); + reply.Append( lineFeed ); + reply.Append( carriageReturn ); + reply.Append( lineFeed ); + reply.Append( _L("+COPS: ") ); + + RMobilePhone::TMobilePhoneNetworkInfoV2 nwInfo; + for(TInt i = 0; i < iDetectedNetworks->Enumerate(); ++i) + { + if(i > 0) // Add CR+LF after the first cycle. + { + reply.Append( carriageReturn ); + reply.Append( lineFeed ); + } + nwInfo = iDetectedNetworks->GetEntryL(i); + + reply.Append(_L("(")); + reply.AppendNum(nwInfo.iStatus); + reply.Append(_L(",")); + reply.Append(_L("\"")); + reply.Append(nwInfo.iLongName); + reply.Append(_L("\"")); + reply.Append(_L(",")); + reply.Append(_L("\"")); + reply.Append(nwInfo.iShortName); + reply.Append(_L("\"")); + reply.Append(_L(",")); + reply.Append(_L("\"")); + reply.Append(nwInfo.iCountryCode); + reply.Append(nwInfo.iNetworkId); + reply.Append(_L("\"")); + if(SolveAccessTechnology(nwInfo.iAccess) == KErrNone && iAccTech != EAccTechNotSet) + { + TRACE_INFO((_L("CATCOPSCmd::ConstructNetworkListResponse() appending acc. tech. (%d)"), iAccTech)); + reply.Append(_L(",")); + reply.AppendNum(iAccTech); + } + reply.Append(_L(")")); + reply.Append(_L(",")); + TRACE_INFO( _L("CATCOPSCmd::ConstructNetworkListResponse() -- entry added to reply.")); + } + reply.Append(KSupportedModesStr); // Supported modes as defined in 3GPP TS 27.007 V8.4.1 + reply.Append(KSupportedFormatsStr); // Supported formats as defined in 3GPP TS 27.007 V8.4.1 + + reply.Append( carriageReturn ); + reply.Append( lineFeed ); + + // Finally append the "OK". CreateOkOrErrorReply returns verbose or numeric version. + RBuf8 okReply; + CleanupClosePushL(okReply); + iCallback->CreateOkOrErrorReply( okReply, ETrue ); + reply.Append( okReply); + CreateReply(ETrue, reply); + CleanupStack::PopAndDestroy(&okReply); + CleanupStack::PopAndDestroy(&reply); + TRACE_FUNC_EXIT + } + +// --------------------------------------------------------------------------- +// Finalises the response and sends it. +// --------------------------------------------------------------------------- +// +void CATCOPSCmd::CreateReply(TBool aIsOK, const TDesC8 &aReply) + { + if(aIsOK == EFalse) + { + iCallback->CreateReplyAndComplete( EReplyTypeError); + } + else + { + if(aReply.Length() > 0) + { + iCallback->CreateReplyAndComplete( EReplyTypeOther, + aReply ); + } + else + { + iCallback->CreateReplyAndComplete( EReplyTypeOk); + } + } + iCurrentOperation = EIdle; + TRACE_FUNC_EXIT + }