bluetoothengine/btnotif/btnotifsrv/src/btnotifpairinghelper.cpp
author hgs
Wed, 05 May 2010 09:56:48 +0300
changeset 30 df7a93ede42e
parent 29 48ae3789ce00
permissions -rw-r--r--
201017_3

/*
* ============================================================================
*  Name        : btnotifpairinghelper.cpp
*  Part of     : bluetoothengine / btnotif
*  Description : Helper class for processing pairing requests and results, as extended functionality for CBTNotifConnection.
*
*  Copyright © 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:
*  Nokia Corporation
* ============================================================================
* Template version: 4.1
*/

#include "btnotifpairinghelper.h"
#include <bt_sock.h>
#include <btextnotifiers.h>
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <btextnotifierspartner.h>
#endif

#include "btnotifconnection.h"
#include "btnotifconnectiontracker.h"
#include "btnotificationmanager.h"
#include "btnotifserver.h"
#include "bluetoothtrace.h"

/**  Id for the active object for a dedicated bonding session. */
const TInt KDedicatedBonding = 50;
/**  Length of the default PIN. */
const TInt KDefaultPinLength = 4;
/**  Default PIN character. */
const TText8 KDefaultPinValue = '0';
/**  Format syntax for numeric comparison value. */
_LIT( KNumCompFormat, "%06u" );
/**  Format syntax for passkey display value. */
_LIT( KPassKeyFormat, "%06u" );


// ======== LOCAL FUNCTIONS ========

// ---------------------------------------------------------------------------
// ?description
// ---------------------------------------------------------------------------
//
/*?type ?function_name( ?arg_type ?arg,
                      ?arg_type ?arg )
    {
    }
*/

// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// C++ default constructor.
// ---------------------------------------------------------------------------
//
CBTNotifPairingHelper::CBTNotifPairingHelper( CBTNotifConnection* aConnection,
    CBTNotifConnectionTracker* aTracker )
:   iConnection( aConnection ),
    iTracker( aTracker )
    {
    }


// ---------------------------------------------------------------------------
// Symbian 2nd-phase constructor.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::ConstructL()
    {
    if( iConnection )
        {
        iDevice = iConnection->BTDevice();
        }
    }


// ---------------------------------------------------------------------------
// NewL
// ---------------------------------------------------------------------------
//
CBTNotifPairingHelper* CBTNotifPairingHelper::NewL( CBTNotifConnection* aConnection,
    CBTNotifConnectionTracker* aTracker )
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    CBTNotifPairingHelper* self = new( ELeave ) CBTNotifPairingHelper( aConnection, aTracker );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    return self;
    }


// ---------------------------------------------------------------------------
// Destructor.
// ---------------------------------------------------------------------------
//
CBTNotifPairingHelper::~CBTNotifPairingHelper()
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    if( iNotification )
        {
        // Clear the notification callback, we cannot receive them anymore.
        iNotification->RemoveObserver();
        iNotification->Close(); // Also dequeues the notification from the queue.
        iNotification = NULL;
        }
    delete iParams;
    if( iBondingActive )
        {
        iBondingActive->Cancel();   // Will close subsession;
        }
    delete iBondingActive;
    iBondingSession.Close();
    iBondingSocket.Close();
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    }


// ---------------------------------------------------------------------------
// Handle the authentication result from the baseband. Show the result in a note.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::HandleAuthenticationCompleteL( TInt aError )
    {
    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aError );
    if( iOperation == EDedicatedBonding || iOperation == EAwaitingPairingResult ||
        iOperation == EAutoPairing )
        {
        // Default case (aError == 0): Success, we are now paired.
        TBTDialogResourceId resourceId = EPairingSuccess;
        TBool autoPairing = ( iOperation == EAutoPairing ); // Remember the autopairing state
        iOperation = EShowPairingSuccess;
        if( aError && aError != KHCIErrorBase )
            {
            // Authentication failure, means pairing failed.
            resourceId = EPairingFailure;
            iOperation = EShowPairingFailure;
            // Communicate the error now that we still remember it.
            if( iDedicatedBonding )
                {
                if( autoPairing && aError == KHCIErrorBase - EAuthenticationFailure )
                    {
                    BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST, 
                            "[BTNOTIF]\t CBTNotifPairingHelper::HandleAuthenticationCompleteL: Autopairing failed, we need to try again.");
                    // Autopairing failed, we need to try again.
                    iOperation = EAutoPairing;  // Reset back
                    resourceId = ENoResource;
                    }
                CompleteBondingL( aError );
                }
            }
        if( resourceId )
            {
            // Inform the user of the result.
            BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,  
                    "[BTNOTIF]\t CBTNotifPairingHelper::HandleAuthenticationCompleteL: pairing successful, inform user" );
            PrepareNotificationL( TBluetoothDialogParams::EGlobalNotif, resourceId );
            // MBRNotificationClosed will be called from this, which will 
            // check the next stage.
            }
        }
    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
    }


// ---------------------------------------------------------------------------
// Start a bonding operation with the remote device.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::StartBondingL( TInt aHandle )
    {
    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aHandle );
    __ASSERT_ALWAYS( iOperation == EIdle || iOperation == EDedicatedBonding
                || iOperation == EAutoPairing, PanicServer( EBTNotifPanicBadState ) );
    if( !iBondingActive )
        {
        iBondingActive = CBtSimpleActive::NewL( *this, KDedicatedBonding );
        }
    if( aHandle )
        {
        iDedicatedBonding = aHandle;
        }
    if( iOperation == EIdle )
        {
        iOperation = EDedicatedBonding;
        }
    if( iOperation == EDedicatedBonding && iTracker->PairingServerSession() )
        {
        if( !iBondingActive->IsActive() )
            {
            BtTraceBtAddr1( TRACE_DEBUG,DUMMY_LIST,"CBTNotifPairingHelper::StartBondingL()",iDevice->BDAddr() );
            iBondingSession.Start( *iTracker->PairingServerSession(),
                        iDevice->BDAddr(), iBondingActive->RequestStatus() );
            iBondingActive->GoActive();
            }
        }
    else
        {
        // We are doing autopairing (or the unlikely situation that the pairing server is unavailable)
        CompleteBondingL( KErrServerTerminated );
        }
    BOstraceFunctionExit1( DUMMY_DEVLIST, this);
    }


// ---------------------------------------------------------------------------
// Cancel an ongoing bonding operation with the remote device.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CancelBondingL()
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    if( iDedicatedBonding )
        {
        CompleteBondingL( KErrCancel ); // Closes sessions
        if( iNotification )
            {
            // Cancel the outstanding user query
            // This will also unregister us from the notification.
            TInt err = iNotification->Close();
            NOTIF_NOTHANDLED( !err )
            iNotification = NULL;
            }
        if( iNotifierUid )
            {
            // Also finish up the notifier processing.
            CompletePairingNotifierL( KErrCancel, EFalse, KNullDesC8 );
            }
        iOperation = EIdle;
        iConnection->PairingCompleted();   // This may delete us.
        }
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    }


// ---------------------------------------------------------------------------
// Handle a notifier request for pairing with the remote device of this connection.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::StartPairingNotifierL( TInt aUid, const TDesC8& aParams )
    {
    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aUid );
    if( iDevice->GlobalSecurity().Banned() && !iDedicatedBonding )
        {
        // ToDo: should this case actually be ignored, and presume that
        // the caller will take care of unblocking the device?
        iOperation = EIdle;
        User::Leave( KErrAccessDenied );
        }
    // Store the parameters locally, we need them later again.
    delete iParams;
    iParams = NULL;
    iParams = HBufC8::NewL( aParams.Length() );
    *iParams = aParams;
    iNotifierUid = aUid;

    if( iDevice->IsValidPaired() && iDevice->IsPaired() )
        {
        // The device is still paired, we unpair it first.
        // Deleting the link key will set the device as unpaired.
        iDevice->DeleteLinkKey();
        iOperation = EUnpairing;    // So that parent state does not get changed.
        iConnection->UpdateRegistryEntryL();
        // Note that this will only be done before trying autopairing, so
        // it not interfere with a second attempt;
        }
    // Update the device name
    TBTPasskeyDisplayParams params; // Enough for reading the base class type parameter
    TPckgC<TBTPasskeyDisplayParams> paramsPckg( params );
    paramsPckg.Set( *iParams );
    if( paramsPckg().DeviceName().Length() )
        {
        // The name in the parameter package is the latest one, retrieved from 
        // the remote device during this connection. Update locally.
        iDevice->SetDeviceNameL( BTDeviceNameConverter::ToUTF8L( paramsPckg().DeviceName() ) );
        }

    TBool locallyInitiated = EFalse;
    TBuf<8> numVal;
    TBluetoothDialogParams::TBTDialogType dialog = TBluetoothDialogParams::EInvalidDialog;
    TBTDialogResourceId resource = ENoResource;
    // Read the notifier parameters (sets iOperation as well)
    ParseNotifierReqParamsL( locallyInitiated, numVal, dialog, resource );
    // If this is an incoming pairing, we first ask the user to accept it.
    if( !locallyInitiated && !iDedicatedBonding )
        {
        // Ignore the initatior if we initiated bonding.
        StartAcceptPairingQueryL(); // Overrides iOperation
        }
    else
        {
        __ASSERT_ALWAYS( resource != ENoResource, PanicServer( EBTNotifPanicBadState ) );
        CheckAutoPairingL( locallyInitiated, numVal );
        // CheckAutoPairingL sets 
        if( iOperation != EAutoPairing )
            {
            PrepareNotificationL( dialog, resource );
            if( numVal.Length() )
                {
                TInt err = iNotification->SetData( TBluetoothDeviceDialog::EAdditionalDesc, numVal );
                NOTIF_NOTHANDLED( !err )
                }
            }
        }
    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
    }


// ---------------------------------------------------------------------------
// Update a notifier, update the outstanding dialog if the notifier request 
// is currently being served.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::UpdatePairingNotifierL( TInt aUid, const TDesC8& aParams )
    {
    (void) aUid;
    TBTNotifierUpdateParams2 params;    // Enough for reading the base class type parameter
    TPckgC<TBTNotifierUpdateParams2> paramsPckg( params );
    paramsPckg.Set( aParams );
    if( paramsPckg().Type() == TBTNotifierUpdateParams2::EPasskeyDisplay )
        {
        // Paskey display update - keypress on remote device.
        }
    else
        {
        // name update
        TBTDeviceNameUpdateParams nameUpdate;
        TPckgC<TBTDeviceNameUpdateParams> nameUpdatePckg( nameUpdate );
        nameUpdatePckg.Set( aParams );
        // The result means result of conversion to unicode
        if( !nameUpdatePckg().Result() )
            {
            // Only update locally, registry will update us with the same info later on.
            iDevice->SetDeviceNameL( BTDeviceNameConverter::ToUTF8L( nameUpdatePckg().DeviceName() ) );
            if( iNotification )
                {
                // Update the dialog with the new name. It is up to the dialog to 
                // determine the validity (in case another dialog is shown).
                //iNotification->Update(  )
                }
            }
        }
    }


// ---------------------------------------------------------------------------
// Cancel a request, dismiss the outstanding dialog if the notifier request 
// is currently being served.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CancelPairingNotifierL( TInt aUid )
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    // ToDo: we need to check that the UID and the outstanding notification
    // type are matching?
    if( iOperation > EIdle && iOperation < EPostPairingOperations && aUid == iNotifierUid &&
        ( aUid == KBTPinCodeEntryNotifierUid.iUid ||
          aUid == KBTNumericComparisonNotifierUid.iUid ||
          aUid == KBTPasskeyDisplayNotifierUid.iUid ) )
        {
        if( iNotification )
            {
            // Cancel the user query
            // This will also unregister us from the notification.
            TInt err = iNotification->Close();
            NOTIF_NOTHANDLED( !err )
            iNotification = NULL;
            }
        iOperation = EIdle;
        iNotifierUid = 0;
        // We do not call pairing completed from here, our parent will
        // check our status by itself, and may delete us.

        // Any bonding requester needs to be informed though.
        CancelBondingL();
        }
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    }


// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::StartJustWorksProcessingL()
    {
    }


// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CancelJustWorksProcessingL()
    {
    }


// ---------------------------------------------------------------------------
// From class MBTNotificationResult.
// Handle a result from a user query.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::MBRDataReceived( CHbSymbianVariantMap& aData )
    {
    (void) aData;
    NOTIF_NOTIMPL
    }


// ---------------------------------------------------------------------------
// From class MBTNotificationResult.
// The notification is finished.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::MBRNotificationClosed( TInt aError, const TDesC8& aData )
    {
    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aError );
    // First unregister from the notification, so we can already get the next one.
    iNotification->RemoveObserver();
    iNotification = NULL;
    TRAP_IGNORE( NotificationClosedL( aError, aData ) );
    if( iOperation == EIdle )
        {
        // Any error has been communicated already.
        iConnection->PairingCompleted();   // This may delete us.
        }
    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
    }


// ---------------------------------------------------------------------------
// From class MBtSimpleActiveObserver.
// Handle the active object completion.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::RequestCompletedL( CBtSimpleActive* aActive,
    TInt aStatus )
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    switch( aActive->RequestId() )
        {
        case KDedicatedBonding:
            {
            if( iDedicatedBonding )
                {
                // If the result hasn't been processed already.
                HandleAuthenticationCompleteL( aStatus );
                }
            }
            break;
        default:
            NOTIF_NOTIMPL
            break;
        }
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    }


// ---------------------------------------------------------------------------
// From class MBtSimpleActiveObserver.
// Cancel and clean up all requests related to the active object.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CancelRequest( TInt aRequestId )
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    switch( aRequestId )
        {
        case KDedicatedBonding:
            iBondingSession.Close();
            break;
        default:
            NOTIF_NOTIMPL
            break;
        }
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    }

// ---------------------------------------------------------------------------
// From class MBtSimpleActiveObserver.
// 
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::HandleError( CBtSimpleActive* aActive, 
        TInt aError )
    {
    (void) aActive;
    (void) aError;
    }

// ---------------------------------------------------------------------------
// Process the user input and complete the outstanding pairing request.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CompletePairingNotifierL( TInt aError, TBool aResult,
    const TDesC8& aData )
    {
    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aError );
    TInt err = aError;
    TPtrC8 resultData;
    if( !err )
        {
        // The returned data is the entered passkey.
        TBool proceed = iTracker->UpdateBlockingHistoryL( iDevice, aResult );
        if( iOperation == ESspPairing && iNotifierUid == KBTNumericComparisonNotifierUid.iUid )
            {
            // Numeric comparison needs the boolean result passed back.
            TPckgBuf<TBool> userAcceptance( aResult );
            resultData.Set( userAcceptance );
            }
        if( aResult )
            {
            if( iOperation == ELegacyPairing || iOperation == EAutoPairing )
                {
                // Check the passkey entered by the user.
                // The length of the returned data equals the number of characters
                // entered by the user.
                TBTPinCode pinCode;
                pinCode().iLength = aData.Length();
                TUint minLen = 0;
                TBool locallyInitiated = EFalse; // Not used here.
                ParsePinCodeReqParamsL( locallyInitiated, minLen );
                if( aData.Length() >= minLen )
                    {
                    // Check that the length of the passkey meets the minimum 
                    // required pin code length
                    for( TInt i = 0; i < aData.Length(); i++ )
                        {
                        pinCode().iPIN[i] = aData[i];
                        }
                    resultData.Set( pinCode );
                    }
                else
                    {
                    // PIN wasn't long enough. This should be handled by the dialog though.
                    err = KErrCompletion;
                    }
                }
            // Now we just wait for the result to come in.
            if( iOperation != EAutoPairing )
                {
                iOperation = EAwaitingPairingResult; 
                }
            }
        else
            {
            err = KErrCancel;
            TBool locallyInitiated = EFalse;    // Needed below
            TBuf<8> numVal;     // Not needed here.
            TBluetoothDialogParams::TBTDialogType type = TBluetoothDialogParams::EInvalidDialog;
            TBTDialogResourceId resource = ENoResource; // Resources and type are not needed here.
            // Check the notifier parameters
            ParseNotifierReqParamsL( locallyInitiated, numVal, type, resource );
            if( proceed && locallyInitiated && !iDedicatedBonding )
                {
                // The user denied the connection, ask to block the device.
                // This is only for pairing (and not bonding) initiated by us,
                // as the user already gets the opportunity to block when
                // rejecting an incoming pairing request.
                // This case may be for someone requesting to access a service
                // which requires authentication by us, but not by the remote device.
                iConnection->LaunchBlockingQueryL();
                // For incoming pairing, blocking is asked after rejecting the 
                // pairing request. This is done in CompleteAcceptPairingQueryL
                }
            CompleteBondingL( err );    // Notify the client if there was a bonding request.
            }
        }
    iNotifierUid = 0;   // Clean up notifier data
    delete iParams;
    iParams = NULL;
    if( err )
        {
        iOperation = EIdle; // We are done now.
        }
    // Complete the message with the result, and result data if any.
    iConnection->CompleteClientRequest( err, resultData );
    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
    }


// ---------------------------------------------------------------------------
// Completes a bonding operation.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CompleteBondingL( TInt aError )
    {
    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aError );
    if( iDedicatedBonding )
        {
        if( iBondingActive )
            {
            iBondingActive->Cancel();   // Will close subsession;
            }
        iBondingSession.Close();    // In case not active
        iBondingSocket.Close();
        }
    // Determine if we try another time.
    if( ( iOperation == EAutoPairing && aError == KHCIErrorBase - EAuthenticationFailure ) ||
        ( iDedicatedBonding && iOperation == EAwaitingPairingResult &&
          aError == KErrRemoteDeviceIndicatedNoBonding ) ||
        aError == KErrServerTerminated )
        {
        // The cases are: 2) autopairing with a headset that has a non-default passkey
        // 2) SSP dedicated bonding with a device that does not allow that.
        // 3) the pairing server is unavailable (unlikely)
        // Then we try another time, requesting authentication on a 
        // RBTPhysicialLinkAdapter
        BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,  
                "[BTNOTIF]\t CBTNotifPairingHelper::CompleteBondingL: trying another time." );
        TInt err = iBondingSocket.Open( iTracker->SocketServerSession(), iConnection->Address() );
        TUint32 linkState = 0;
        if( !err )
            {
            err = iBondingSocket.PhysicalLinkState( linkState );
            }
        if( !err && linkState & ENotifyPhysicalLinkUp )
            {
            err = iBondingSocket.Authenticate();
            // Now wait for the dialog and then the link state notification
            }
        else
            {
            // We need to wait for the link to come up. We wait until our
            // parent calls us again.
            iBondingSocket.Close();
            }
        if( err )
            {
            // Cannot continue, show the result to the user.
            BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,  
                    "[BTNOTIF]\t CBTNotifPairingHelper::HandleAuthenticationCompleteL: pairing failed, complete message." );
            iOperation = EShowPairingFailure;
            PrepareNotificationL( TBluetoothDialogParams::ENote, EPairingFailure );
            }
        }
    if( iDedicatedBonding && iOperation != EAutoPairing )
        {
        BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,      
                "[BTNOTIF]\t CBTNotifPairingHelper::CompleteBondingL: complete message." );
        TInt err = iTracker->Server()->CompleteMessage( iDedicatedBonding, aError, KNullDesC8 );
        NOTIF_NOTHANDLED( !err )
        iDedicatedBonding = 0;
        }
    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
    }


// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CompleteJustWorksProcessingL( TInt aError )
    {
    (void) aError;
    }


// ---------------------------------------------------------------------------
// Ask the user to allow incoming pairing.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::StartAcceptPairingQueryL()
    {
    iOperation = EAcceptPairing;
    PrepareNotificationL( TBluetoothDialogParams::EQuery, EIncomingPairing );
    // if rejected, the client message is completed in CompleteAcceptPairingQueryL
    }


// ---------------------------------------------------------------------------
// The user was asked to accept an incoming pairing. Process and proceed. 
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CompleteAcceptPairingQueryL( TInt aError, TBool aResult )
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    // Set our state to idle for now. This may get changed if the user just chose 
    // to block, or if we have a pending request.
    iOperation = EIdle;
    TInt err = aError;
    if( !err )
        {
        TBool proceed = iTracker->UpdateBlockingHistoryL( iDevice, aResult );
        if( aResult )
            {
            // User accepted, continue to show pairing query.
            // Minimum lenght does not apply, should only be set on outgoing pairing
            TBool locallyInitiated = EFalse;
            TBuf<8> numVal;
            TBluetoothDialogParams::TBTDialogType dialog = TBluetoothDialogParams::EInvalidDialog;
            TBTDialogResourceId resource = ENoResource;
            // Read the notifier parameters
            ParseNotifierReqParamsL( locallyInitiated, numVal, dialog, resource );
            __ASSERT_ALWAYS( resource != ENoResource, PanicServer( EBTNotifPanicBadState ) );
            PrepareNotificationL( dialog, resource );
            if( numVal.Length() )
                {
                TInt err = iNotification->SetData( TBluetoothDeviceDialog::EAdditionalDesc, numVal );
                NOTIF_NOTHANDLED( !err )
                }
            }
        else
            {
            err = KErrCancel;
            if( proceed )
                {
                // The user denied the connection, ask to block the device.
                iConnection->LaunchBlockingQueryL();
                }
            }
        }
    if( err )
        {
        // The user denied the connection, or something else prevented completion.
        CompletePairingNotifierL( err, EFalse, KNullDesC8 );
        }
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    }


// ---------------------------------------------------------------------------
// Launch a dialog for setting the device as trusted.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::StartTrustedQueryL()
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    // Assume that the registry update has come through by now.
    iOperation = EQueryTrust;
    PrepareNotificationL( TBluetoothDialogParams::EQuery, ESetTrusted );
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    }


// ---------------------------------------------------------------------------
// Process the user input for setting the device as trusted.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CompleteTrustedQueryL( TInt aError, TBool aResult )
    {
    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aError );
    BOstraceExt2( TRACE_DEBUG, DUMMY_DEVLIST, 
            "CBTNotifPairingHelper::CompleteTrustedQueryL() err=%d result=%d", aError, aResult );
    iOperation = EIdle; // We are done with pairing now.
    if( !aError && aResult )
        {
        // need to update pairing info from registry before writing trusted status
        iConnection->UpdateRegistryEntryL(true);
        }
    CompleteBondingL( KErrNone );   // Notify the client if there was a bonding request.
    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
    }


// ---------------------------------------------------------------------------
// Parse the parameters of a request for pairing.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::ParseNotifierReqParamsL( TBool& aLocallyInitiated,
    TDes& aNumVal, TBluetoothDialogParams::TBTDialogType& aDialogType,
    TBTDialogResourceId& aResourceId )
    {
    // Determine the notifier type by the length of the parameter buffer
    if( iNotifierUid == KBTPinCodeEntryNotifierUid.iUid )
        {
        aNumVal.Zero();
        TUint minLen = 0;
        ParsePinCodeReqParamsL( aLocallyInitiated, minLen );
        if( minLen )
            {
            // Don't set zero to this buffer, the buffer length serves for this.
            aNumVal.Num( minLen );
            }
        aDialogType = TBluetoothDialogParams::EInput;
        aResourceId = EPinInput;
        if( iOperation != EAutoPairing )
            {
            iOperation = ELegacyPairing;
            }
        }
    else if( iNotifierUid == KBTNumericComparisonNotifierUid.iUid )
        {
        ParseNumericCompReqParamsL( aLocallyInitiated, aNumVal );
        aDialogType = TBluetoothDialogParams::EQuery;
        aResourceId = ENumericComparison;
        iOperation = ESspPairing;
        }
    else if( iNotifierUid == KBTPasskeyDisplayNotifierUid.iUid )
        {
        ParsePasskeyDisplayReqParamsL( aLocallyInitiated, aNumVal );
        aDialogType = TBluetoothDialogParams::EQuery;
        aResourceId = EPasskeyDisplay;
        iOperation = ESspPairing;
        }
    }


// ---------------------------------------------------------------------------
// Parse the parameters of a request for pairing using pin query.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::ParsePinCodeReqParamsL( TBool& aLocallyInitiated,
    TUint& aNumVal )
    {
    TBTPinCodeEntryNotifierParams params;
    TPckgC<TBTPinCodeEntryNotifierParams> paramsPckg( params );
    paramsPckg.Set( *iParams );
    aLocallyInitiated = paramsPckg().LocallyInitiated();
    aNumVal = paramsPckg().PinCodeMinLength();
    }


// ---------------------------------------------------------------------------
// Parse the parameters of a request for pairing using numeric comparison.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::ParseNumericCompReqParamsL( TBool& aLocallyInitiated,
    TDes& aNumVal )
    {
    TBTNumericComparisonParams params;
    TPckgC<TBTNumericComparisonParams> paramsPckg( params );
    paramsPckg.Set( *iParams );
    aLocallyInitiated = paramsPckg().LocallyInitiated();
    TBTNumericComparisonParams::TComparisonScenario scenario =
                paramsPckg().ComparisonScenario();
    aNumVal.Format( KNumCompFormat, paramsPckg().NumericalValue() );
    }


// ---------------------------------------------------------------------------
// Parse the parameters of a request for pairing using passkey display.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::ParsePasskeyDisplayReqParamsL( TBool& aLocallyInitiated,
    TDes& aNumVal )
    {
    TBTPasskeyDisplayParams params;
    TPckgC<TBTPasskeyDisplayParams> paramsPckg( params );
    paramsPckg.Set( *iParams );
    aLocallyInitiated = paramsPckg().LocallyInitiated();
    aNumVal.Format( KPassKeyFormat, paramsPckg().NumericalValue() );
    }


// ---------------------------------------------------------------------------
// Check if we can guess the PIN and complete the notifier without user interaction.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::CheckAutoPairingL( TBool aLocallyInitiated, const TDesC& aNumVal )
    {
    TUint minLen = 0;
    if( aNumVal.Length() )
        {
        ParsePinCodeReqParamsL( aLocallyInitiated, minLen );
        }
    // ToDo: Add support for NFC OOB pairing
    if( iDedicatedBonding && iOperation == ELegacyPairing &&
        iDevice->DeviceClass().MajorDeviceClass() == EMajorDeviceAV &&
        iDevice->DeviceClass().MinorDeviceClass() != EMinorDeviceAVHandsfree &&
        minLen <= KDefaultPinLength )
        {
        // Outgoing bonding with headset and no passkey requirement => AutomatedPairing
        // Complete message with 0000 and return.
        iOperation = EAutoPairing;
        TBuf8<KDefaultPinLength + sizeof( TPckgBuf<TBool> )> defaultPin( KDefaultPinLength );
        for( TInt i = 0; i < KDefaultPinLength; i++ )
            {
            defaultPin[i] = KDefaultPinValue;
            }
        // Complete the pairing through the function dedicated to that.
        CompletePairingNotifierL( KErrNone, ETrue, defaultPin );
        }
    else if( iOperation == EAutoPairing )
        {
        iOperation = ELegacyPairing;    // Reset the autopairing status
        }
    }


// ---------------------------------------------------------------------------
// Get and configure a notification.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::PrepareNotificationL( TBluetoothDialogParams::TBTDialogType aType,
    TBTDialogResourceId aResourceId )
    {
    BOstraceFunctionEntry0( DUMMY_DEVLIST );
    __ASSERT_ALWAYS( iOperation != EIdle || aType == TBluetoothDialogParams::ENote, PanicServer( EBTNotifPanicBadState ) );
    iNotification = iTracker->NotificationManager()->GetNotification();
    User::LeaveIfNull( iNotification ); // For OOM exception, leaves with KErrNoMemory
    iNotification->SetObserver( this );
    iNotification->SetNotificationType( aType, aResourceId );
    TBTDeviceName name;
    GetDeviceNameL( name, *iDevice );
    TInt err = iNotification->SetData( TBluetoothDeviceDialog::EDeviceName, name );
    NOTIF_NOTHANDLED( !err )
    // Re-use name buffer for 16-bit descriptor representation of remote address.
    iConnection->Address().GetReadable( name );
    err = iNotification->SetData( TBluetoothDialogParams::EAddress, name );
    NOTIF_NOTHANDLED( !err )
    err = iNotification->SetData( (TInt) TBluetoothDeviceDialog::EDeviceClass,
                iDevice->DeviceClass().DeviceClass() );
    err = iTracker->NotificationManager()->QueueNotification( iNotification );
    NOTIF_NOTHANDLED( !err )
    BOstraceFunctionExit0( DUMMY_DEVLIST );
    }


// ---------------------------------------------------------------------------
// The notification is finished, handle the result.
// ---------------------------------------------------------------------------
//
void CBTNotifPairingHelper::NotificationClosedL( TInt aError, const TDesC8& aData )
    {
    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aError );
    // Read the result.
    TPckgC<TBool> result( EFalse );
    result.Set( aData.Ptr(), result.Length() ); // Read the part containing the result
    // Set a pointer descriptor to capture the remaining data, if any.
    TPtrC8 dataPtr( aData.Mid( result.Length() ) );
    switch( iOperation )
        {
        case EAcceptPairing:
            CompleteAcceptPairingQueryL( aError, result() );
            break;
        case ELegacyPairing:
        case ESspPairing:
            CompletePairingNotifierL( aError, result(), dataPtr );
            break;
        case EQueryTrust:
            CompleteTrustedQueryL( aError, result() );
            break;
        case EShowPairingSuccess:
            StartTrustedQueryL();
            break;
        case EShowPairingFailure:
            // Pairing failure, we are done.
            iOperation = EIdle;
            break;
        default:
            NOTIF_NOTIMPL
            break;
        }
    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
    }