--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/btnotif/btnotifsrv/src/btnotifconnection.cpp Mon May 03 14:36:07 2010 +0300
@@ -0,0 +1,964 @@
+/*
+* ============================================================================
+* Name : btnotifconnection.cpp
+* Part of : bluetoothengine / btnotif
+* Description : Class for observing events of a single connection, and for
+* managing any user notifications related to the connection.
+*
+* 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 "btnotifconnection.h"
+#include <btextnotifiers.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <btextnotifierspartner.h>
+#endif
+
+#include "btnotifconnectiontracker.h"
+#include "btnotifpairinghelper.h"
+#include "btnotificationmanager.h"
+#include "btnotifclientserver.h"
+#include "bluetoothtrace.h"
+
+/** Id for the baseband connection watcher active object. */
+const TInt KConnectionWatcher = 40;
+/** Id for the registry watcher active object. */
+const TInt KRegistryWatcher = 41;
+/** Id for the active object for updating the registry. */
+const TInt KRegistryRetriever = 42;
+/** Event mask for subscribing to baseband connection events
+ * (need to check if these are appropriate). */
+const TInt KBbEventMask = ENotifyAnyRole | ENotifyAuthenticationComplete |
+ ENotifyPhysicalLinkUp | ENotifyPhysicalLinkDown | ENotifyPhysicalLinkError;
+
+
+// ======== LOCAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Decide the device name to display from the device information, and
+// converts the name if necessary.
+// ---------------------------------------------------------------------------
+//
+void GetDeviceNameL( TBTDeviceName& aName, const CBTDevice& aDevice )
+ {
+ if( aDevice.IsValidFriendlyName() )
+ {
+ aName.Copy( aDevice.FriendlyName() );
+ }
+ else
+ {
+ aName.Zero();
+ if( aDevice.IsValidDeviceName() )
+ {
+ aName = BTDeviceNameConverter::ToUnicodeL( aDevice.DeviceName() );
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Compare 2 device records device pairing has succeeded.
+// aDev2 is the updated device record, aDev1 is the previous record.
+// ---------------------------------------------------------------------------
+//
+TBool CheckRegistryPairedStatus( const CBTDevice* aOrig, const CBTDevice* aNew )
+ {
+ TBool result = EFalse;
+ // Use the device class to check that this has any valid information.
+ if( aOrig->AsNamelessDevice().IsValidDeviceClass() &&
+ !( aOrig->IsValidPaired() && aOrig->IsPaired() ) ||
+ aOrig->LinkKeyType() == ELinkKeyUnauthenticatedUpgradable )
+ {
+ // Only consider the result if the original device is not marked as paired.
+ if( aNew->IsValidPaired() && aNew->IsPaired() && aNew->IsValidLinkKey() &&
+ aNew->LinkKeyType() != ELinkKeyUnauthenticatedUpgradable )
+ {
+ // The new device record has valid pairing information, so
+ // this device is now paired.
+ result = ETrue;
+ }
+ }
+ return result;
+ }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnection::CBTNotifConnection( const TBTDevAddr& aAddr,
+ CBTNotifConnectionTracker* aTracker )
+: iAddr( aAddr ),
+ iTracker( aTracker )
+ {
+ }
+
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd-phase constructor
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::ConstructL()
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ iDevice = CBTDevice::NewL( iAddr );
+ iPhyActive = CBtSimpleActive::NewL(*this, KConnectionWatcher );
+ iRegActive = CBtSimpleActive::NewL( *this, KRegistryRetriever );
+ // ToDo: need to check if this succeeds if a connection is
+ // being created, in case of outgoing pairing.
+ User::LeaveIfError( iPhyLink.Open( iTracker->SocketServerSession(), iAddr ) );
+ // Subscribe to events.
+ iBasebandEvent.FillZ(); // To be sure that we are not reading false events.
+ iPhyLink.NotifyNextBasebandChangeEvent( iBasebandEvent,
+ iPhyActive->RequestStatus(), KBbEventMask );
+ iPhyActive->GoActive();
+ // Get the details from BT registry
+ TBTRegistrySearch pattern;
+ pattern.FindAddress( iAddr );
+ User::LeaveIfError( iRegistry.Open( iTracker->RegistryServerSession() ) );
+ iRegistry.CreateView( pattern, iRegActive->RequestStatus() );
+ iRegActive->GoActive();
+ iCurrentOp = EReadingRegistry;
+ iRegDevArray = new CBTDeviceArray(1); // only 1 entry ever used
+ // ToDo: more initialization needed?
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// NewLC.
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnection* CBTNotifConnection::NewLC( const TBTDevAddr& aAddr,
+ CBTNotifConnectionTracker* aTracker )
+ {
+ CBTNotifConnection* self = new( ELeave ) CBTNotifConnection( aAddr, aTracker );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnection::~CBTNotifConnection()
+ {
+ 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 iRegActive;
+ delete iRegistryResponse;
+ iRegistry.Close();
+ delete iDevMan;
+
+ delete iPhyActive;
+ iPhyLink.Close();
+ delete iDevice;
+ delete iPairingHelper;
+
+ while( iMsgHandleQ.Count() )
+ {
+ CompleteClientRequest( KErrDisconnected, KNullDesC8 );
+ }
+ iMsgHandleQ.Close();
+ iAcceptedConnections.Close();
+ iDeniedConnections.Close();
+ iRegDevArray->ResetAndDestroy();
+ delete iRegDevArray;
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Check what to do next.
+// This function should be called whenever we may be ready for the next
+// request/action, which is from any callback function i.e.
+// MBAORequestCompletedL, MBRNotificationClosed, HandleNotifierRequestL and
+// CancelNotifierRequestL.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CheckNextOperationL()
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ if( iCurrentOp == EIdle )
+ {
+ // Check the link state, to see if it has gone down already.
+ TUint32 linkState = 0;
+ TInt err = iPhyLink.PhysicalLinkState( linkState );
+ TBool linkDown = linkState & ENotifyPhysicalLinkDown;
+ if( ( !err && linkDown ) || err == KErrDisconnected )
+ {
+ // The link state tells us that the link is down,
+ // inform the connection tracker the we are done.
+ iTracker->HandleLinkCountChangeL();
+ // Note that we may be deleted now!
+ }
+ else if( iMsgHandleQ.Count() )
+ {
+ // Get the next request and handle it.
+ // ToDo: differentiate between notifier and pairing message!
+ const RMessage2* message = iTracker->Server()->FindMessageFromHandle( iMsgHandleQ[0] );
+ NOTIF_NOTHANDLED( message )
+ TInt opcode = message->Function();
+ if( opcode <= EBTNotifUpdateNotifier )
+ {
+ TBuf8<0x250> paramsBuf; // Size needs to be long enough to read all possible parameter sizes.
+ message->ReadL( EBTNotifSrvParamSlot, paramsBuf );
+ HandleNotifierRequestL( paramsBuf, *message );
+ }
+ else
+ {
+ iMsgHandleQ.Remove( 0 );
+ StartBondingL( *message );
+ }
+ }
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Complete the first outstanding client request and removes it from the queue.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CompleteClientRequest( TInt aReason, const TDesC8& aReply )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ NOTIF_NOTHANDLED( iMsgHandleQ.Count() )
+ TInt err = iTracker->Server()->CompleteMessage( iMsgHandleQ[0], aReason, aReply );
+ NOTIF_NOTHANDLED( !err )
+ iMsgHandleQ.Remove( 0 );
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Distinguish a request and pass to corresponding handle.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleNotifierRequestL( const TDesC8& aParams,
+ const RMessage2& aMessage )
+ {
+ BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aMessage.Int0() );
+ if( !iMsgHandleQ.Count() || iMsgHandleQ[0] != aMessage.Handle() )
+ {
+ // If we are processing a queued request, we of course don't queue
+ // it again. In that case we are handling the first request from the queue.
+ iMsgHandleQ.AppendL( aMessage.Handle() );
+ }
+ if( iCurrentOp == EIdle || iCurrentOp == EBonding )
+ {
+ // ToDo: check non-pairing operation when bonding
+ TInt uid = aMessage.Int0();
+ if( uid == KBTManAuthNotifierUid.iUid )
+ {
+ HandleAuthorizationReqL( aParams );
+ }
+ else if( uid == KBTManPinNotifierUid.iUid ||
+ uid == KBTPinCodeEntryNotifierUid.iUid ||
+ uid == KBTNumericComparisonNotifierUid.iUid ||
+ uid == KBTPasskeyDisplayNotifierUid.iUid )
+ {
+ if( !iPairingHelper )
+ {
+ BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,
+ "[BTNOTIF]\t CBTNotifConnection::HandleNotifierRequestL: creating CBTNotifPairingHelper");
+ iPairingHelper = CBTNotifPairingHelper::NewL( this, iTracker );
+ }
+ if( iCurrentOp != EBonding )
+ {
+ iCurrentOp = EPairing;
+ }
+ iPairingHelper->StartPairingNotifierL( uid, aParams );
+ }
+ // We may be done with the current request, proceed to the next one
+ CheckNextOperationL();
+ }
+ BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Update a notifier, update the outstanding dialog if the notifier request
+// is currently being served.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleNotifierUpdateL( const TDesC8& aParams,
+ const RMessage2& aMessage )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ NOTIF_NOTHANDLED( iCurrentOp != EIdle )
+ (void) aParams;
+ TBuf8<0x250> paramsBuf; // Size needs to be long enough to read all possible sizes.
+ aMessage.ReadL( EBTNotifSrvParamSlot, paramsBuf );
+ TInt uid = aMessage.Int0();
+ if( uid == KBTManAuthNotifierUid.iUid )
+ {
+ TBTNotifierUpdateParams params;
+ TPckgC<TBTNotifierUpdateParams> paramsPckg( params );
+ paramsPckg.Set( paramsBuf );
+ // The result means result of conversion to unicode
+ if( !paramsPckg().iResult )
+ {
+ // Only update locally, registry will update us with the same info later on.
+ iDevice->SetDeviceNameL( BTDeviceNameConverter::ToUTF8L( paramsPckg().iName ) );
+ 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( )
+ }
+ }
+ }
+ else if( iPairingHelper && ( uid == KBTPinCodeEntryNotifierUid.iUid ||
+ uid == KBTNumericComparisonNotifierUid.iUid ||
+ uid == KBTPasskeyDisplayNotifierUid.iUid ) )
+ {
+ // Just forward to pairing helper
+ iPairingHelper->UpdatePairingNotifierL( uid, paramsBuf );
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Cancel a request, dismiss the outstanding dialog if the notifier request
+// is currently being served.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CancelNotifierRequestL( const RMessage2& aMessage )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ NOTIF_NOTHANDLED( iCurrentOp != EIdle )
+ TInt pos = iMsgHandleQ.Find( aMessage.Handle() );
+ if( pos > KErrNotFound )
+ {
+ // We have queued the message, remove it from the queue.
+ iMsgHandleQ.Remove( pos );
+ // We use the supplied handle to remove it, as it may not be
+ // the first in the queue.
+ TInt err = iTracker->Server()->CompleteMessage( aMessage.Handle(), KErrCancel, KNullDesC8 );
+ NOTIF_NOTHANDLED( !err )
+ if( pos == 0 )
+ {
+ // There could be the case that we are still post-processing
+ // the previous request (e.g. blocking query), then the next
+ // notification is not yet started but the first in the queue.
+ // We can see that from the current operation type.
+ if( iNotification && iCurrentOp < EAdditionalNotes )
+ {
+ // Cancel the user query
+ // This will also unregister us from the notification.
+ TInt err = iNotification->Close();
+ NOTIF_NOTHANDLED( !err )
+ iNotification = NULL;
+ iCurrentOp = EIdle;
+ }
+ if( iPairingHelper )
+ {
+ // The pairing helper calls back PairingCompleted and sets state.
+ iPairingHelper->CancelPairingNotifierL( aMessage.Int0() );
+ // The pairing helper may have now been deleted.
+ }
+ }
+ }
+ // We may be done with the current request, proceed to the next one
+ CheckNextOperationL();
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Start a bonding operation with the remote device.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::StartBondingL( const RMessage2& aMessage )
+ {
+ BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aMessage.Function() );
+ if( iCurrentOp == EIdle || iCurrentOp > EInternalOperations )
+ {
+ __ASSERT_ALWAYS( !iPairingHelper, PanicServer( EBTNotifPanicBadState ) );
+ iPairingHelper = CBTNotifPairingHelper::NewL( this, iTracker );
+ // The pairingg helper stored the handle, not in our queue here.
+ // This is because bonding will generate a pairing notifier request, which
+ // will be completed first. The bookkeeping gets complicated if we have to
+ // re-order the queue here.
+ iPairingHelper->StartBondingL( aMessage.Handle() );
+ iCurrentOp = EBonding;
+ }
+ else if( iCurrentOp == EPairing || iCurrentOp == EBonding )
+ {
+ // We only do one pairing at the time.
+ User::Leave( KErrInUse );
+ }
+ else
+ {
+ // We only store it here if it is not handled immediately.
+ iMsgHandleQ.AppendL( aMessage.Handle() );
+ }
+ BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Cancel an ongoing bonding operation with the remote device.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CancelBondingL()
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ if( iPairingHelper )
+ {
+ iPairingHelper->CancelBondingL();
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// The pairing handler has completed a pairing operation.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::PairingCompleted()
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ __ASSERT_ALWAYS( iPairingHelper, PanicServer( EBTNotifPanicNullMember ) );
+ if( iPairingHelper->CurrentOperation() == CBTNotifPairingHelper::EIdle )
+ {
+ // We are still idle. Remove the pairing helper
+ delete iPairingHelper;
+ iPairingHelper = NULL;
+ }
+ if( iCurrentOp == EPairing || iCurrentOp == EBonding )
+ {
+ iCurrentOp = EIdle;
+ TRAP_IGNORE( CheckNextOperationL() );
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Process a new pairing result, and determine if we need to show
+// anything to the user.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::PairingResult( TInt aError )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ if( !iPairingHelper )
+ {
+ TRAP_IGNORE( iPairingHelper = CBTNotifPairingHelper::NewL( this, iTracker ) );
+ }
+ if( iPairingHelper )
+ {
+ iPairingHelper->HandleAuthenticationCompleteL( aError );
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Process the new service-level connection, and determine if we need to
+// show anything to the user.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::ServiceConnectedL( TBTProfile aProfile )
+ {
+ (void) aProfile;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Process the new service-level disconnection, and determine if we need to
+// show anything to the user.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::ServiceDisconnectedL( TBTProfile aProfile )
+ {
+ (void) aProfile;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Ask the user if he/she wants to block future connection requests.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::LaunchBlockingQueryL()
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ iCurrentOp = EBlocking;
+ TBTDialogResourceId resourceId = EBlockUnpairedDevice;
+ if( iDevice->IsValidPaired() && iDevice->IsPaired() &&
+ iDevice->LinkKeyType() != ELinkKeyUnauthenticatedUpgradable )
+ {
+ resourceId = EBlockPairedDevice;
+ }
+ PrepareNotificationL( TBluetoothDialogParams::EQuery, resourceId );
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Modify the record for the remote device in BTRegistry, with the changes
+// already made in the local record.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::UpdateRegistryEntryL()
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ // We use CBTEngDevMan here. We could use the registry API directly, however,
+ // using this convenience API makes the registry processing much simpler.
+ if( !iDevMan )
+ {
+ iDevMan = CBTEngDevMan::NewL( this );
+ }
+ iDevMan->ModifyDevice( *iDevice );
+ if( iCurrentOp == EIdle ||
+ ( ( iCurrentOp == EPairing || iCurrentOp == EBonding ) &&
+ iPairingHelper->CurrentOperation() == CBTNotifPairingHelper::EIdle ) )
+ {
+ // To make sure that we don't get deleted while updating.
+ iCurrentOp = EUpdatingRegistry;
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+// ---------------------------------------------------------------------------
+// Modify the record for the remote device in BTRegistry, if aTrusted == true, then
+// update trusted status after reading device info from registry
+//
+// ---------------------------------------------------------------------------
+
+void CBTNotifConnection::UpdateRegistryEntryL( TBool aTrusted )
+ {
+ BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aTrusted );
+ if (!aTrusted) {
+ UpdateRegistryEntryL();
+ return;
+ }
+ // We use CBTEngDevMan here. We could use the registry API directly, however,
+ // using this convenience API makes the registry processing much simpler.
+ if( !iDevMan )
+ {
+ iDevMan = CBTEngDevMan::NewL( this );
+ }
+ // first read device info from registry, to make sure we have up-to-date local info
+ iCurrentOp = EReadingRegistry;
+ GetDeviceFromRegistry( iDevice->BDAddr() );
+ BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+ }
+
+// ---------------------------------------------------------------------------
+// From class MBTNotificationResult.
+// Handle a result from a user query.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::MBRDataReceived( CHbSymbianVariantMap & aData )
+ {
+ (void) aData;
+ NOTIF_NOTIMPL
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MBTNotificationResult.
+// The notification is finished.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::MBRNotificationClosed( TInt aError, const TDesC8& aData )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ // ToDo: call leaving function from here!
+ __ASSERT_ALWAYS( iCurrentOp != EIdle, PanicServer( EBTNotifPanicBadState ) );
+ // First unregister from the notification, so we can already get the next one.
+ iNotification->RemoveObserver();
+ iNotification = NULL;
+ TRAP_IGNORE( NotificationClosedL( aError, aData ) );
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+// Handle the active object completion.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::RequestCompletedL( CBtSimpleActive* aActive,
+ TInt aStatus )
+ {
+ BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aActive->RequestId() );
+ switch( aActive->RequestId() )
+ {
+ case KRegistryRetriever:
+ {
+ BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,
+ "[BTNOTIF]\t CBTNotifConnection::MBAORequestCompletedL: KRegistryRetriever" );
+ if( !iRegistryResponse )
+ {
+ // We have just created the view, now get the results.
+ // There can only be one result, as the address is unique.
+ // (note: how about LE random addresses?)
+ // Or then we have tried to re-open an existing view, so we get KErrInuse.
+ // We anyway just get the results.
+ __ASSERT_ALWAYS( aStatus < 2, PanicServer( EBTNotifPanicCorrupt ) );
+ iRegistryResponse = CBTRegistryResponse::NewL( iRegistry );
+ iRegistryResponse->Start( iRegActive->RequestStatus() );
+ iRegActive->GoActive();
+ }
+ else
+ {
+ if( !aStatus )
+ {
+ // There can be only one result.
+ __ASSERT_ALWAYS( iRegistryResponse->Results().Count() == 1, PanicServer( EBTNotifPanicCorrupt ) );
+ CBTDevice* regDevice = iRegistryResponse->Results()[0];
+ TBool paired = CheckRegistryPairedStatus( iDevice, regDevice );
+ iDevice->UpdateL( *regDevice );
+ if( paired )
+ {
+ __ASSERT_ALWAYS( iPairingHelper, PanicServer( EBTNotifPanicNullMember ) );
+ iPairingHelper->HandleAuthenticationCompleteL( KErrNone );
+ }
+ }
+ // ToDo: error handling of registry response result?
+ delete iRegistryResponse;
+ iRegistryResponse = NULL;
+ }
+ if( iCurrentOp == EReadingRegistry && !iRegActive->IsActive() )
+ {
+ // If this is part of the sequence of operations, we are done.
+ // Otherwise we just update with the latest info from registry,
+ // and then we don't interrupt or change the state.
+ iCurrentOp = EIdle;
+ }
+ }
+ // ToDo: start registry watching (preferably using registry API when this is available)
+ break;
+ case KRegistryWatcher:
+ {
+ BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,
+ "[BTNOTIF]\t CBTNotifConnection::MBAORequestCompletedL: KRegistryWatcher" );
+ NOTIF_NOTHANDLED( !aStatus )
+ // Ignore updates while we are already retrieving.
+ if( !iRegActive->IsActive() )
+ {
+ // Refresh our information with the latest from registry
+ iRegActive->SetRequestId( KRegistryRetriever );
+ TBTRegistrySearch pattern;
+ pattern.FindAddress( iAddr );
+ iRegistry.CreateView( pattern, iRegActive->RequestStatus() );
+ iRegActive->GoActive();
+ }
+ }
+ break;
+ case KConnectionWatcher:
+ {
+ BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,
+ "[BTNOTIF]\t CBTNotifConnection::MBAORequestCompletedL: KConnectionWatcher" );
+ TUint32 event = iBasebandEvent().EventType();
+ // First subscribe to the next event notification.
+ // This will overwrite iBasebandEvent().EventType() with KBbEventMask
+ iPhyLink.NotifyNextBasebandChangeEvent( iBasebandEvent,
+ iPhyActive->RequestStatus(), KBbEventMask );
+ iPhyActive->GoActive();
+ // Link down and link error are handled in CheckNextOperationL below.
+ // ToDo: handle events!
+ if( event & ( ENotifyPhysicalLinkDown | ENotifyPhysicalLinkError ) )
+ {
+ // We re-use the error code to store the indication that the
+ // link has disconnected. This will only be overridden by next
+ // event, which can only be a connection up event.
+ iBasebandEvent().SetErrorCode( KErrDisconnected );
+ }
+ if( iPairingHelper )
+ {
+ if( event & ( ENotifyPhysicalLinkDown | ENotifyPhysicalLinkError |
+ ENotifyAuthenticationComplete ) )
+ {
+ // Results interesting for pairing result processing.
+ iPairingHelper->HandleAuthenticationCompleteL( iBasebandEvent().SymbianErrorCode() );
+ }
+ else if( event & ENotifyPhysicalLinkUp &&
+ iPairingHelper->CurrentOperation() == CBTNotifPairingHelper::EDedicatedBonding )
+ {
+ iPairingHelper->StartBondingL( 0 );
+ }
+ }
+ }
+ break;
+ default:
+ PanicServer( EBTNotifPanicBadState );
+ break;
+ }
+ // We may be done with the current request, proceed to the next one
+ CheckNextOperationL();
+ BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+// Cancel and clean up all requests related to the active object.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CancelRequest( TInt aRequestId )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ if ( aRequestId == KConnectionWatcher )
+ {
+ iPhyLink.CancelNextBasebandChangeEventNotifier();
+ }
+ else if ( aRequestId == KRegistryWatcher && iRegistryResponse )
+ {
+ iRegistryResponse->Cancel();
+ }
+ else if ( aRequestId == KRegistryRetriever )
+ {
+ iRegistry.CancelRequest( iRegActive->RequestStatus());
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+//
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleError( CBtSimpleActive* aActive,
+ TInt aError )
+ {
+ (void) aActive;
+ (void) aError;
+ }
+
+// ---------------------------------------------------------------------------
+// From class MBTEngDevmanObserver.
+// Registry modification has completed.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleDevManComplete( TInt aErr )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ (void) aErr;
+ NOTIF_NOTHANDLED( !aErr )
+ if( iCurrentOp == EUpdatingRegistry )
+ {
+ // To make sure that we don't get deleted while updating.
+ iCurrentOp = EIdle;
+ }
+ // Refresh is done separately, we will get notified through
+ // the registry watcher of the change.
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MBTEngDevmanObserver.
+// Callback for getting a device from the registry
+//
+// Currently only used in context of setting device to trusted
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleGetDevicesComplete(
+ TInt err, CBTDeviceArray* deviceArray )
+ {
+ BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, err );
+ // err is not used here very much, -1 could be returned if there is no device in registry,
+ // but this case is covered by examing mRegDevArray.
+ if (!err && (iCurrentOp == EReadingRegistry) ) {
+ CBTDevice* dev (0);
+ if ( deviceArray->Count() ) {
+ dev = deviceArray->At( 0 );
+ }
+ if ( dev ) {
+ iDevice = dev->CopyL();
+ }
+ // Set device to trusted
+ // Copy the existing security settings.
+ TBTDeviceSecurity sec( iDevice->GlobalSecurity().SecurityValue(),
+ iDevice->GlobalSecurity().PasskeyMinLength() );
+ sec.SetNoAuthorise( ETrue ); // new value: set device as trusted
+ iDevice->SetGlobalSecurity( sec );
+ iDevMan->ModifyDevice( *iDevice ); // write trusted (& paired) status to registry
+ // To make sure that we don't get deleted while updating.
+ iCurrentOp = EUpdatingRegistry;
+ }
+ BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+ }
+
+// ---------------------------------------------------------------------------
+// Retrieves device from registry based on BT address parameter
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::GetDeviceFromRegistry( const TBTDevAddr &addr )
+{
+ BOstraceFunctionEntry1( DUMMY_DEVLIST, this );
+ TBTRegistrySearch searchPattern;
+ searchPattern.FindAddress( addr );
+ // and get this device from registry
+ iRegDevArray->ResetAndDestroy();
+ iDevMan->GetDevices(searchPattern, iRegDevArray);
+ BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+}
+
+// ---------------------------------------------------------------------------
+// Get and configure a notification.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::PrepareNotificationL( TBluetoothDialogParams::TBTDialogType aType,
+ TBTDialogResourceId aResourceId )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ iNotification = iTracker->NotificationManager()->GetNotification();
+ User::LeaveIfNull( iNotification ); // For OOM exception, leaves with KErrNoMemory
+ iNotification->SetObserver( this );
+ iNotification->SetNotificationType( aType, aResourceId );
+ // Set the address of the remote device
+ TBuf<KBTDevAddrSize> addr;
+ addr.Copy( iAddr.Des() );
+ TInt err = iNotification->SetData( TBluetoothDialogParams::EAddress, addr );
+ NOTIF_NOTHANDLED( !err )
+ // Set the name of the remote device
+ TBTDeviceName name;
+ GetDeviceNameL( name, *iDevice );
+ // ToDo: handle leave in name conversion!
+ err = iNotification->SetData( (TInt) TBluetoothDeviceDialog::EDeviceName, name );
+ NOTIF_NOTHANDLED( !err )
+ // Queue the notification for displaying to the user
+ err = iTracker->NotificationManager()->QueueNotification( iNotification );
+ NOTIF_NOTHANDLED( !err )
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// The notification is finished, handle the result.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::NotificationClosedL( TInt aError, const TDesC8& aData )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ switch( iCurrentOp )
+ {
+ case EAuthorizing:
+ CompleteAuthorizationReqL( aError, aData );
+ break;
+ case EBlocking:
+ CompleteBlockingReqL( aError, aData );
+ break;
+ default:
+ NOTIF_NOTIMPL
+ break;
+ }
+ // We may be done with the current request, proceed to the next one
+ CheckNextOperationL();
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Handle a request for authorization of this connection.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleAuthorizationReqL( const TDesC8& aParams )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ __ASSERT_ALWAYS( iCurrentOp == EIdle, PanicServer( EBTNotifPanicBadState ) );
+ __ASSERT_ALWAYS( !iNotification, PanicServer( EBTNotifPanicCorrupt ) );
+ TBTAuthorisationParams params;
+ TPckgC<TBTAuthorisationParams> paramsPckg( params );
+ paramsPckg.Set( aParams );
+ iCurrentOp = EAuthorizing;
+ // The name in the parameter package is the latest one, retrieved from
+ // the remote device during this connection.
+ if( paramsPckg().iName.Length() )
+ {
+ // Update the local device record. No need to update the registry,
+ // that will be done by the stack, and we will receive the update
+ // information when that has completed.
+ iDevice->SetDeviceNameL( BTDeviceNameConverter::ToUTF8L( paramsPckg().iName ) );
+ }
+ PrepareNotificationL( TBluetoothDialogParams::EQuery, EAuthorization );
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Process the user input and complete the outstanding authorization request.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CompleteAuthorizationReqL( TInt aError, const TDesC8& aData )
+ {
+ 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.
+ iCurrentOp = EIdle;
+ if( !aError )
+ {
+ TPckgC<TBool> result( EFalse );
+ result.Set( aData );
+ TBool proceed = iTracker->UpdateBlockingHistoryL( iDevice, result() );
+ if( result() == EFalse && proceed )
+ {
+ // The user denied the connection, ask to block the device.
+ LaunchBlockingQueryL();
+ }
+ CompleteClientRequest( KErrNone, aData );
+ }
+ else
+ {
+ CompleteClientRequest( aError, KNullDesC8 );
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Process the user input for blocking a device.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CompleteBlockingReqL( TInt aError, const TDesC8& aData )
+ {
+ BOstraceFunctionEntry0( DUMMY_DEVLIST );
+ TPckgC<TBool> result( EFalse );
+ result.Set( KNullDesC8 ); // to test!
+ result.Set( aData );
+ iCurrentOp = EIdle; // May get changed if we have a pending request.
+ if( !aError && result() )
+ {
+ // The user accepted to block this device.
+ TBTDeviceSecurity sec; // use default values when setting as banned.
+ sec.SetBanned( ETrue );
+ iDevice->SetGlobalSecurity( sec );
+ if( iDevice->IsValidPaired() && iDevice->IsPaired() )
+ {
+ // Deleting the link key will also set the device as unpaired.
+ iDevice->DeleteLinkKey();
+ }
+ UpdateRegistryEntryL();
+ }
+ BOstraceFunctionExit0( DUMMY_DEVLIST );
+ }