cbsatplugin/atmisccmdplugin/src/clckcommandhandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 27 Apr 2010 16:49:44 +0300
branchRCL_3
changeset 16 b23265fb36da
child 32 19bd632b5100
permissions -rw-r--r--
Revision: 201015 Kit: 201017

/*
 * Copyright (c) 2010 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 :
 *
 */

#include "clckcommandhandler.h"

#include <startupdomainpskeys.h>
#include <e32property.h>

#include "securitycodeverifier.h"
#include "securityeventhandler.h"
#include "cbsettinghandler.h"

#include "atmisccmdpluginconsts.h"
#include "debug.h"

const TInt KSCPMaxHashLength( 32 );

CCLCKCommandHandler* CCLCKCommandHandler::NewL(MATMiscCmdPlugin* aCallback, TAtCommandParser& aATCmdParser, RMobilePhone& aPhone)
    {
    TRACE_FUNC_ENTRY
    CCLCKCommandHandler* self = new (ELeave) CCLCKCommandHandler(aCallback, aATCmdParser, aPhone);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    TRACE_FUNC_EXIT
    return self;
    }

CCLCKCommandHandler::CCLCKCommandHandler(MATMiscCmdPlugin* aCallback, TAtCommandParser& aATCmdParser, RMobilePhone& aPhone) :
    CATCmdAsyncBase(aCallback, aATCmdParser, aPhone),
    iLockInfoPckg(iLockInfo)
    {
    TRACE_FUNC_ENTRY
    TRACE_FUNC_EXIT
    }

void CCLCKCommandHandler::ConstructL()
    {
    TRACE_FUNC_ENTRY
    iReply.CreateL(KDefaultCmdBufLength);
    
    // initialise AOs
    iCBRetrieve = CRetrieveMobilePhoneCBList::NewL(iPhone);
    iCBSettingHandler = CCBSettingHandler::NewL(iPhone);
    iSecurityEventHandler = CSecurityEventHandler::NewL(this, iPhone);
    iSecurityCodeVerifier = CSecurityCodeVerifier::NewL(this, iPhone);

    TRACE_FUNC_EXIT
    }

CCLCKCommandHandler::~CCLCKCommandHandler()
    {
    TRACE_FUNC_ENTRY
    Cancel();
    
    delete iCBRetrieve;
    delete iCBSettingHandler;
    delete iSecurityEventHandler;
    delete iSecurityCodeVerifier;
    
    iPassword.Close();
    iReply.Close();
    TRACE_FUNC_EXIT
    }

void CCLCKCommandHandler::DoCancel()
    {
    TRACE_FUNC_ENTRY
    switch (iCLCKCommandType)
        {
        case (CCLCKCommandHandler::ECLCKLockGet):
            {
            iPhone.CancelAsyncRequest(EMobilePhoneGetLockInfo);
            break;
            }
        case (CCLCKCommandHandler::ECLCKLockSet):
            {
            iPhone.CancelAsyncRequest(EMobilePhoneSetLockSetting);
            iSecurityCodeVerifier->Cancel();
            iSecurityEventHandler->Cancel();
            break;
            }
        case (CCLCKCommandHandler::ECLCKBarringGet):
            {
            iCBRetrieve->Cancel();
            break;
            }
        case (CCLCKCommandHandler::ECLCKBarringSet):
            {
            iCBSettingHandler->Cancel();
            break;
            }
        }
    TRACE_FUNC_EXIT
    }

void CCLCKCommandHandler::HandleCommand( const TDesC8& /*aCmd*/, RBuf8& /*aReply*/, TBool /*aReplyNeeded*/)
    {
    TRACE_FUNC_ENTRY
    TAtCommandParser::TCommandHandlerType cmdHandlerType = iATCmdParser.CommandHandlerType();
    Trace(KDebugPrintD, "cmdHandlerType: ", cmdHandlerType);
    
    switch (cmdHandlerType)
        {
        case (TAtCommandParser::ECmdHandlerTypeTest):
            {
            iCallback->CreateReplyAndComplete(EReplyTypeOther, KCLCKSupportedCmdsList);
            break;
            }
        case (TAtCommandParser::ECmdHandlerTypeSet):
            {
            if (ParseCCLCKCommand() == KErrNone)
                {
                IssueCLCKCommand();
                }
            else
                {
                iCallback->CreateReplyAndComplete(EReplyTypeError);
                }
            break;
            }
        default:
            {
            iCallback->CreateReplyAndComplete(EReplyTypeError);
            break;
            }
        }
    TRACE_FUNC_EXIT
    }

void CCLCKCommandHandler::RunL()
    {
    TRACE_FUNC_ENTRY
    Trace(KDebugPrintD, "iStatus.Int(): ", iStatus.Int());
    TInt err = iStatus.Int();
    if (err == KErrNone)
        {
        switch ( iCLCKCommandType )
            {
            case (CCLCKCommandHandler::ECLCKLockGet):
                {
                iReply.Append(KAtCLCK);
                if (iLockInfo.iStatus == RMobilePhone::EStatusUnlocked)
                    {
                    iReply.AppendNum(0);
                    iReply.Append(KCRLF);
                    }
                else if (iLockInfo.iStatus == RMobilePhone::EStatusLocked)
                    {
                    iReply.AppendNum(1); 
                    iReply.Append(KCRLF);
                    }
                else
                    {
                    err = KErrArgument;
                    }
                break;
                }
            case(CCLCKCommandHandler::ECLCKBarringGet):
                {
                err = ReceiveCBList();
                break;
                }
            case (CCLCKCommandHandler::ECLCKLockSet):
                {
                iLockSettingState = ELockSettingIdle;
                iSecurityCodeVerifier->Cancel();
                iSecurityEventHandler->Cancel();
                break;
                }
            case(CCLCKCommandHandler::ECLCKBarringSet):
            default:
                {
                // no action required
                break;
                }
            }
        }

    if (err != KErrNone)
        {
        if (iCLCKCommandType == CCLCKCommandHandler::ECLCKLockSet)
            {
            iLockSettingState =ELockSettingIdle;
            iSecurityCodeVerifier->Cancel();
            iSecurityEventHandler->Cancel();
            }
        iCallback->CreateCMEReplyAndComplete(err);
        }
    else
        {
        iCallback->CreateReplyAndComplete( EReplyTypeOther, iReply );
        }
    
    TRACE_FUNC_EXIT
    }

TInt CCLCKCommandHandler::ReceiveCBList()
    {
    TRACE_FUNC_ENTRY
    iInfoClass = 0;
    CMobilePhoneCBList* callBarringList=NULL;
    TRAPD(leaveCode, callBarringList=iCBRetrieve->RetrieveListL(););
    if (leaveCode != KErrNone) 
        {
        TRACE_FUNC_EXIT
        return leaveCode;
        }

    TInt count = callBarringList->Enumerate();
    while (count-- > 0)
        {
        RMobilePhone::TMobilePhoneCBInfoEntryV1 entry;
        TRAP(leaveCode, entry = callBarringList->GetEntryL(count););
        if (leaveCode != KErrNone) 
            {
            TRACE_FUNC_EXIT
            return leaveCode;
            }
        if (entry.iCondition == iCondition &&
            entry.iStatus == RMobilePhone::ECallBarringStatusActive)
            {
            switch (entry.iServiceGroup)
                {
                case(RMobilePhone::ETelephony):
                    {
                    iInfoClass |= EInfoClassVoice;
                    break;   
                    }
                case(RMobilePhone::EAllBearer):
                    {
                    iInfoClass |= EInfoClassData;
                    break;   
                    }
                case(RMobilePhone::EFaxService):
                    {
                    iInfoClass |= EInfoClassFax;
                    break;   
                    }
                case(RMobilePhone::EShortMessageService):
                    {
                    iInfoClass |= EInfoClassSMS;
                    break;   
                    }
                case(RMobilePhone::ESyncData):
                    {
                    iInfoClass |= EInfoClassSyncData;
                    break;   
                    }
                case(RMobilePhone::EAsyncData):
                    {
                    iInfoClass |= EInfoClassASyncData;
                    break;   
                    }
                case(RMobilePhone::EPacketData):
                    {
                    iInfoClass |= EInfoClassPacketData;
                    break;   
                    }
                case(RMobilePhone::EPadAccess):
                    {
                    iInfoClass |= EInfoClassPadAccess;
                    break;   
                    }
                }
            }
        }
    
    // There are no services with barring active - therefore report
    // - status = 0 (inactive)
    // - class = 7 (default value; voice, fax and data)
    TInt status;
    if (iInfoClass == 0)
        {
        status = 0;
        iInfoClass = 7; // Default value, see ETSI TS 127 007 V6.9.0 (2007-06)
        }
    else
        {
        // There is at least one service with barring active - report status 1 (active)
        status = 1;
        }
    
    iReply.Append(KAtCLCK);
    iReply.AppendNum(status);
    iReply.Append(','); 
    iReply.AppendNum(iInfoClass);
    iReply.Append(KCRLF);
    
    delete callBarringList;
    TRACE_FUNC_EXIT
    return KErrNone;
    }

void CCLCKCommandHandler::HandleCommandCancel()
    {
    TRACE_FUNC_ENTRY
    Cancel();
    TRACE_FUNC_EXIT
    }

void CCLCKCommandHandler::IssueCLCKCommand()
    {
    TRACE_FUNC_ENTRY
    Trace(KDebugPrintD, "iCLCKCommandType: ", iCLCKCommandType);
    iReply.Zero();
    
    switch (iCLCKCommandType)
        {
        case (CCLCKCommandHandler::ECLCKLockGet):
            {
            iPhone.GetLockInfo(iStatus, iLockType, iLockInfoPckg);
            SetActive();
            break;
            }
        case (CCLCKCommandHandler::ECLCKLockSet):
            {
            if (iPassword.Compare(KNullDesC8) == 0)
                {
                iCallback->CreateReplyAndComplete( EReplyTypeError);
                }
            else
                {
                // Set the property to ignore security events in other clients
                // it allows to avoid GUI promt for security code
                TInt  ret = KErrNone;
                // TODO: reenable when KIgnoreSecurityEvent propety definition is submitted to codeline
//                if (iLockType == RMobilePhone::ELockICC)
//                    {
//                    ret = RProperty::Set(KPSUidStartup, KIgnoreSecurityEvent, EPSIgnoreSecurityEventEPin1Required);
//                    }
//                else
//                    {
//                    ret = RProperty::Set(KPSUidStartup, KIgnoreSecurityEvent, EPSIgnoreSecurityEventEPhonePasswordRequired);
//                    }
                Trace(KDebugPrintD, "RProperty::Set: ", ret);
                if (ret == KErrNone)
                    {
                    // Start security event handler - this will notify whether a 
                    // password is required to complete the set lock request.
                    iSecurityEventHandler->Start();
                
                    Trace(KDebugPrintD, "SetLockSetting iLockType: ", iLockType);
                    Trace(KDebugPrintD, "SetLockSetting iLockChange: ", iLockChange);
                    iPhone.SetLockSetting(iStatus, iLockType, iLockChange);
                    iLockSettingState = ELockSettingRequested;
                    SetActive();
                    }
                else
                    {
                    iCallback->CreateReplyAndComplete( EReplyTypeError);
                    }
                }
            break;
            }
        case (CCLCKCommandHandler::ECLCKBarringGet):
            {
            iCBRetrieve->Start(iStatus, iCondition, RMobilePhone::RMobilePhone::EInfoLocationNetwork);
            SetActive();
            break;
            }
        case (CCLCKCommandHandler::ECLCKBarringSet):
            {
            if (iPassword.Compare(KNullDesC8) == 0)
                {
                iCallback->CreateReplyAndComplete(EReplyTypeError);
                }
            else
                {
                iCBSettingHandler->Start(iStatus, iInfoClass, iCondition, &iCBInfo);
                SetActive();
                }
            break;
            }
        default:
            {
            iCallback->CreateReplyAndComplete(EReplyTypeError);
            break;
            }
        }   
    TRACE_FUNC_EXIT
    }

void CCLCKCommandHandler::HandlePasswordVerification(TInt aError)
    {
    TRACE_FUNC_ENTRY
    
    if (aError != KErrNone)
        {
        iCallback->CreateCMEReplyAndComplete(aError);
        Cancel();
        TRACE_FUNC_EXIT
        return;
        }
    
    switch (iLockSettingState)
         {
         case (ELockSettingIdle):
             {
             // Security code setting request has already been completed
             iSecurityEventHandler->Cancel();
             break;
             }
         case (ELockSettingPasswordRequested):
             {
             // after password has been verified go back to the previous state
             iLockSettingState = ELockSettingRequested;
             break;
             }
         case (ELockSettingRequested):
         default:
             {
             // should never be in this state
             __ASSERT_DEBUG(EFalse,  User::Invariant());
             break;
             }
         }

    TRACE_FUNC_EXIT
    }

void CCLCKCommandHandler::HandleSecurityEvent(TInt aError, RMobilePhone::TMobilePhoneSecurityEvent aSecurityEvent)
    {
    TRACE_FUNC_ENTRY
    if (aError != KErrNone)
        {
        iCallback->CreateCMEReplyAndComplete(aError);
        Cancel();
        TRACE_FUNC_EXIT
        return;
        }
    
    Trace(KDebugPrintD, "iLockSettingState: ", iLockSettingState);
    Trace(KDebugPrintD, "aSecurityEvent: ", aSecurityEvent);
    switch (iLockSettingState)
        {
        case (ELockSettingIdle):
            {
            // Set Lock request has already been completed
            iSecurityCodeVerifier->Cancel();
            break;
            }
        case (ELockSettingRequested):
            {
            switch (aSecurityEvent)
                 {
                 case(RMobilePhone::EPin1Required):
                 case(RMobilePhone::EPhonePasswordRequired):
                     {
                     iSecurityEventHandler->Start();
                     if( iSecurityCode == RMobilePhone::ESecurityCodePin1 &&
                         aSecurityEvent == RMobilePhone::EPin1Required ||
                         iSecurityCode == RMobilePhone::ESecurityCodePhonePassword &&
                         aSecurityEvent == RMobilePhone::EPhonePasswordRequired)
                         {
                         // security code request has been triggered, reissue the security notification
                         // request and provide the code if this is expected
                         iSecurityCodeVerifier->Start(iPassword, iSecurityCode);
                         iLockSettingState =ELockSettingPasswordRequested;
                         }
                     break;
                     }
                 case(RMobilePhone::ENoICCFound):
                 case(RMobilePhone::EICCTerminated):
                     {
                     // No SIM present or it is unusable
                     iCallback->CreateCMEReplyAndComplete(aError);
                     Cancel();
                     break;
                     }
                 default:
                     {
                     // other processes may trigger various security events, ignore them
                     // if not related and reissue the notification request
                     iSecurityEventHandler->Start();
                     break;
                     }
                 }
            break;
            }
        case (ELockSettingPasswordRequested):
            {
            switch (aSecurityEvent)
                 {
                 case(RMobilePhone::EPin1Verified):
                     {
                     // PIN1 has been verified, ignore if not applicable
                     // otherwise security event handler and  security code verifier
                     // no longer needed 
                     // (note that another client could have provided the PIN1)
                     if (iSecurityCode == RMobilePhone::ESecurityCodePin1)
                         {
                         iLockSettingState =ELockSettingRequested;
                         }
                     break;
                     }
                 case(RMobilePhone::EPhonePasswordVerified):
                     {
                     if (iSecurityCode == RMobilePhone::ESecurityCodePhonePassword)
                         {
                         iLockSettingState =ELockSettingRequested;
                         }
                     break;
                     }
                 case(RMobilePhone::ENoICCFound):
                 case(RMobilePhone::EICCTerminated):
                     {
                     // No SIM present or it is unusable, terminate the operation
                     Cancel();
                     iCallback->CreateCMEReplyAndComplete(aError);
                     break;
                     }
                 default:
                     {
                     // other processes may trigger various security events, ignore them if not related
                     // and reissue the notification request
                     iSecurityEventHandler->Start();
                     break;
                     }
                 }
            break;
            }
        default:
            {
            // lock setting state value is out of boundies, complete with error
            iCallback->CreateCMEReplyAndComplete(aError);
            Cancel();
            break;
            }
        }
    TRACE_FUNC_EXIT
    }

TInt CCLCKCommandHandler::ParseCCLCKCommand()
    {
    TRACE_FUNC_ENTRY
    TCmdFacilityType facilityType = ECmdFacilityTypeUnknown;
    TInt mode = 0;
    TInt ret = KErrNone;

    TPtrC8 command = iATCmdParser.NextTextParam(ret);
    if (!command.Compare(KNullDesC8) || ret != KErrNone)
        {
        TRACE_FUNC_EXIT
        return KErrArgument;
        }
    
    ret = iATCmdParser.NextIntParam(mode);
    if (!command.Compare(KNullDesC8) || ret != KErrNone)
        {
        TRACE_FUNC_EXIT
        return KErrArgument;
        }
    
    iPassword.Create(iATCmdParser.NextTextParam(ret));
    Trace(KDebugPrintD, "NextTextParam returned: ", ret);
    if (ret != KErrNone && ret != KErrNotFound)
        {
        TRACE_FUNC_EXIT
        return KErrArgument;
        }
    
    if (iPassword.Compare(KNullDesC8) != 0)
        {
        ret = iATCmdParser.NextIntParam(iInfoClass);
        Trace(KDebugPrintD, "NextIntParam(iInfoClass): ", ret);
        if (ret == KErrNotFound)
            {
            iInfoClass = 7;
            }
        if ((ret != KErrNone && ret != KErrNotFound ) || 
            iATCmdParser.NextParam().Compare(KNullDesC8) != 0)
            {
            TRACE_FUNC_EXIT
            return KErrArgument;
            }
        }
    
    if (command.Compare(KATCLCKPS) == 0)
        {
        // Lock phone to SIM on/off
        iSecurityCode = RMobilePhone::ESecurityCodePhonePassword;
        iLockType = RMobilePhone::ELockPhoneToICC;
        facilityType = ECmdFacilityTypeLock;
        }
    else if (command.Compare(KATCLCKSC) == 0)
        {
        // PIN on/off
        iSecurityCode = RMobilePhone::ESecurityCodePin1;
        iLockType = RMobilePhone::ELockICC;
        facilityType = ECmdFacilityTypeLock;
        }
    else if (command.Compare(KATCLCKAO) == 0)
        {
        iCondition = RMobilePhone::EBarAllOutgoing;
        facilityType = ECmdFacilityTypeBarring;
        }
    else if (command.Compare(KATCLCKOI) == 0)
        {
        iCondition = RMobilePhone::EBarOutgoingInternational;
        facilityType = ECmdFacilityTypeBarring;
        }
    else if (command.Compare(KATCLCKOX) == 0)
        {
        iCondition = RMobilePhone::EBarOutgoingInternationalExHC;
        facilityType = ECmdFacilityTypeBarring;
        }
    else if (command.Compare(KATCLCKAI) == 0)
        {
        iCondition = RMobilePhone::EBarAllIncoming;
        facilityType = ECmdFacilityTypeBarring;
        }
    else if (command.Compare(KATCLCKIR) == 0)
        {
        iCondition = RMobilePhone::EBarIncomingRoaming;
        facilityType = ECmdFacilityTypeBarring;
        }
    else if (command.Compare(KATCLCKAB) == 0)
        {
        iCondition = RMobilePhone::EBarAllCases;
        facilityType = ECmdFacilityTypeAllBarring;
        }
    else if (command.Compare(KATCLCKAG) == 0)
        {
        iCondition = RMobilePhone::EBarAllOutgoingServices;
        facilityType = ECmdFacilityTypeAllBarring;
        }
    else if (command.Compare(KATCLCKAC) == 0)
        {
        iCondition = RMobilePhone::EBarAllIncomingServices;
        facilityType = ECmdFacilityTypeAllBarring;
        }
    else 
        {
        TRACE_FUNC_EXIT
        return KErrArgument;
        }
    
    switch (facilityType)
        {
        case (ECmdFacilityTypeLock):
            {
            switch (mode)
                {
                case 0: // e.g. AT+CLCK="SC",0,"0000"
                    {
                    iCLCKCommandType = ECLCKLockSet;
                    iLockChange = RMobilePhone::ELockSetDisabled;
                    break;
                    }
                case 1: // e.g. AT+CLCK="SC",1
                    {
                    iCLCKCommandType = ECLCKLockSet;
                    iLockChange = RMobilePhone::ELockSetEnabled;
                    break;
                    }
                case 2: // e.g. AT+CLCK="SC",2
                    {
                    iCLCKCommandType = ECLCKLockGet;
                    break;
                    }
                default:
                    {
                    TRACE_FUNC_EXIT
                    return KErrArgument;
                    }
                }
            break;
            }
        case (ECmdFacilityTypeBarring):
            {
            iCBInfo.iPassword.Copy(iPassword);
            if (iInfoClass == 0)
                {
                iInfoClass = 7; // Default value, see ETSI TS 127 007 V6.9.0 (2007-06)
                }
            switch (mode)
                {
                case 0: // AT+CLCK="AO",0
                    {
                    iCLCKCommandType = ECLCKBarringSet;
                    iCBInfo.iAction = RMobilePhone::EServiceActionDeactivate;
                    break;
                    }
                case 1: // AT+CLCK="AO",1,"1919",1
                    {
                    iCLCKCommandType = ECLCKBarringSet;
                    iCBInfo.iAction = RMobilePhone::EServiceActionActivate;
                    break;
                    }
                case 2: // AT+CLCK="AO",2
                    {
                    iCLCKCommandType = ECLCKBarringGet;
                    break;
                    }
                default:
                    {
                    TRACE_FUNC_EXIT
                    return KErrArgument;
                    }
                }
            break;
            }
        case (ECmdFacilityTypeAllBarring):
            {
            iCBInfo.iPassword.Copy(iPassword);
            if (iInfoClass == 0)
                {
                iInfoClass = 7; // Default value, see ETSI TS 127 007 V6.9.0 (2007-06)
                }
            
            if ( mode == 0)
                {
                iCLCKCommandType = ECLCKBarringSet;
                iCBInfo.iAction = RMobilePhone::EServiceActionDeactivate;
                }
            else
                // only deactivation is supported
                {
                TRACE_FUNC_EXIT
                return KErrArgument;
                }
            break;
            }
        default:
            {
            TRACE_FUNC_EXIT
            return KErrArgument;
            }
        }
    
    // if phone password is required it needs to be hashed before verification
    if (iSecurityCode == RMobilePhone::ESecurityCodePhonePassword 
                    && iCLCKCommandType == ECLCKLockSet)
        {
        TBuf8<KSCPMaxHashLength> hashedPwd;
        iATCmdParser.HashSecurityCode(iPassword, hashedPwd);
        if (hashedPwd.Length() > iPassword.MaxLength())
            {
            TInt ret = iPassword.ReAlloc(hashedPwd.Length());
            if (ret != KErrNone)
                {
                TRACE_FUNC_EXIT
                return ret;
                }
            }
        iPassword = hashedPwd;
        }
            
    TRACE_FUNC_EXIT
    return KErrNone;
    }