--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/btnotif/btnotifsrv/src/btnotifpairinghelper.cpp Fri May 14 16:01:46 2010 +0300
@@ -0,0 +1,958 @@
+/*
+* ============================================================================
+* 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 );
+ }