diff -r 0ba996a9b75d -r 613943a21004 bluetoothengine/btnotif/btnotifsrv/src/btnotifpairnotifier.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/btnotif/btnotifsrv/src/btnotifpairnotifier.cpp Tue Aug 31 15:25:10 2010 +0300 @@ -0,0 +1,698 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include "btnotifpairnotifier.h" +#include "btnotifclientserver.h" +#include +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#endif +#include "btnotifconnectiontracker.h" +#include "btnotifsecuritymanager.h" +#include "btnotificationmanager.h" +#include "bluetoothnotification.h" +#include "btnotifserver.h" +#include "bluetoothtrace.h" + + +/** Format syntax for numeric comparison value. */ +_LIT( KNumCompFormat, "%06u" ); +/** Format syntax for passkey display value. */ +_LIT( KPassKeyFormat, "%06u" ); + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// C++ default constructor. +// --------------------------------------------------------------------------- +// +CBTNotifPairNotifier::CBTNotifPairNotifier( + CBTNotifSecurityManager& aParent ) +: iParent( aParent ) + { + } + +// --------------------------------------------------------------------------- +// Symbian 2nd-phase constructor. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::ConstructL() + { + } + +// --------------------------------------------------------------------------- +// NewL +// --------------------------------------------------------------------------- +// +CBTNotifPairNotifier* CBTNotifPairNotifier::NewL( + CBTNotifSecurityManager& aParent ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + CBTNotifPairNotifier* self = new( ELeave ) CBTNotifPairNotifier( aParent ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + BOstraceFunctionExit0( DUMMY_DEVLIST ); + return self; + } + + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CBTNotifPairNotifier::~CBTNotifPairNotifier() + { + 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; + } + iParams.Close(); + if ( !iNotifierMessage.IsNull() ) + { + iNotifierMessage.Complete( KErrServerTerminated ); + } + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Handle a notifier request for pairing with a remote device. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::StartPairingNotifierL(const RMessage2& aMessage ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + + TInt uid = aMessage.Int0(); + TInt opCode = aMessage.Function(); + BOstrace1(TRACE_DEBUG,DUMMY_DEVLIST,"[BTNotif]:Opcode: %d",opCode); + + if ( (!iNotifierMessage.IsNull()) && + (opCode != EBTNotifCancelNotifier )&&(opCode != EBTNotifUpdateNotifier)) + { + // todo: do we allow concurrent pairing? + BOstrace0(TRACE_DEBUG,DUMMY_DEVLIST,"[BTNotif]:We are busy"); + User::Leave(KErrServerBusy ); + } + + if(opCode == EBTNotifCancelNotifier){ + CancelPairingNotifierL(uid); + aMessage.Complete(KErrNone); + return; + } + + // Store the parameters locally, we need them later again. + iParams.CreateL( aMessage.GetDesLengthL( EBTNotifSrvParamSlot ) ); + aMessage.ReadL( EBTNotifSrvParamSlot, iParams ); + iNotifierMessage = aMessage; + + // Read the notifier parameters + ParseNotifierReqParamsL(); + + if(opCode ==EBTNotifUpdateNotifier ){ + UpdatePairingNotifierL(uid,iParams); + aMessage.Complete(KErrNone); + return; + } + + const CBtDevExtension* dev = iParent.BTDevRepository().Device(iRemote); + if(dev) + { + if (!iLocallyInitiated && dev->Device().GlobalSecurity().Banned() ) + { + // If the device is banned and pairing is not locally initiated + // then we reject. + BOstrace0(TRACE_DEBUG,DUMMY_DEVLIST,"[BTNotif]:Device is banned"); + iNotifierMessage.Complete( KErrCancel ); + return; + } + if (iLocallyInitiated && dev->Device().GlobalSecurity().Banned()) + { + // Remove the banned device from the blocking history + iParent.ConnectionTracker().UpdateBlockingHistoryL(&dev->Device(),ETrue); + iParent.BlockDevice(dev->Addr(),EFalse); + } + if(0 != dev->Device().FriendlyName().Length()&& dev->Device().IsValidFriendlyName()) + { + // If we have a friendly name use it for the UI + iCurrentDeviceName = dev->Device().FriendlyName(); + } + else + { + // We don't have any friendly name then chek if we have the device name + // otherwise use the Alias + if(0 >= iCurrentDeviceName.Length()) + { + iCurrentDeviceName = dev->Alias(); + } + } + } + else + { + //If we didn't get a name then we make one from the Bluetooth device address + if(0 >= iCurrentDeviceName.Length()) + { + iRemote.GetReadable(iCurrentDeviceName); + } + } + // If this is an incoming pairing, we first ask the user to accept it. + if( !iLocallyInitiated ) + { + User::LeaveIfError(iParent.SetPairObserver(iRemote,ETrue)); + StartAcceptPairingQueryL(); + } + else + { + TInt uid = iNotifierMessage.Int0(); + if(uid == KBTNumericComparisonNotifierUid.iUid) + { + StartPairingUserInputL(); + } + else + { + TBTPinCode pinCode; + if ( iMinPinLength > -1 ) + { + // Legacy Pin pairing. Check if a pin code is already available + // in pairing manager for this device: + iParent.GetPinCode( pinCode, iRemote, iMinPinLength ); + } + if ( pinCode().iLength > 0 ) + { + // a pin is ready for this pairing. + // write it back to client (stack) + TInt err = iNotifierMessage.Write( EBTNotifSrvReplySlot, pinCode ); + iNotifierMessage.Complete( err ); + } + else + { + // no pin code is available or a pin code does not meet + // the security requirement. + // User need to interact: + StartPairingUserInputL(); + } + } + } + BOstraceFunctionExit1( DUMMY_DEVLIST, this ); + } + +// --------------------------------------------------------------------------- +// Update a notifier, update the outstanding dialog if the notifier request +// is currently being served. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::UpdatePairingNotifierL( TInt aUid, const TDesC8& aParams ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + (void) aUid; + TBTNotifierUpdateParams2 params; // Enough for reading the base class type parameter + TPckgC paramsPckg( params ); + paramsPckg.Set( aParams ); + if( paramsPckg().Type() == TBTNotifierUpdateParams2::EPasskeyDisplay ) + { + // Paskey display update - keypress on remote device. + } + else + { + // name update + TBTDeviceNameUpdateParams nameUpdate; + TPckgC nameUpdatePckg( nameUpdate ); + nameUpdatePckg.Set( aParams ); + // The result means result of conversion to unicode + if( !nameUpdatePckg().Result() ) + { + // Check first if we already have a friendly name + const CBtDevExtension* dev = iParent.BTDevRepository().Device(iRemote); + if(dev) + { + if(0 != dev->Device().FriendlyName().Length()&& dev->Device().IsValidFriendlyName()) + { + return; + } + // We don't have a friendly name then use this name + iCurrentDeviceName = nameUpdatePckg().DeviceName(); + if(0 == iCurrentDeviceName.Length()) + { + // The new name is empty then use the Alias + iCurrentDeviceName = dev->Alias(); + } + } + else + { + // We don't have a friendly name then use this name + iCurrentDeviceName = nameUpdatePckg().DeviceName(); + if(0 == iCurrentDeviceName.Length()) + { + // The new name is empty then use the Alias + iRemote.GetReadable(iCurrentDeviceName); + } + } + 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(iCurrentDeviceName); + } + } + } + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Cancel a request, dismiss the outstanding dialog if the notifier request +// is currently being served. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::CancelPairingNotifierL( TInt aUid ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + if( iNotifierMessage.Int0() == aUid ) + { + if( iNotification ) + { + // Cancel the user query + // This will also unregister us from the notification. + TInt err = iNotification->Close(); + NOTIF_NOTHANDLED( !err ) + iNotification = NULL; + } + // todo: Any bonding requester needs to be informed. + // Currently we don't show any "Unable to pair" note + // so no need to inform any bonding requester. + if ( !iNotifierMessage.IsNull() ) + { + iNotifierMessage.Complete( KErrCancel ); + } + } + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// From class MBTNotificationResult. +// Handle a result from a user query. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::MBRDataReceived( CHbSymbianVariantMap& aData ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + if(aData.Keys().MdcaPoint(0).Compare(_L("actionResult")) == 0) + { + TInt val = *(static_cast(aData.Get(_L("actionResult"))->Data())); + if(val) + { + iAcceptPairingResult = ETrue; + } + else + { + iAcceptPairingResult = EFalse; + } + } + else if(aData.Keys().MdcaPoint(0).Compare(_L("checkBoxState")) == 0) + { + iCheckBoxState = *(static_cast(aData.Get(_L("checkBoxState"))->Data())); + } + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// From class MBTNotificationResult. +// The notification is finished. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::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 ) ); + BOstraceFunctionExit1( DUMMY_DEVLIST, this ); + } + +// --------------------------------------------------------------------------- +// Request a user input for the outstanding pairing request. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::StartPairingUserInputL() + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + PrepareNotificationL( iDialog, iDialogResource ); + iState = EPairingInputConfirm; + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Process the user input and complete the outstanding pairing request. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::CompletePairingNotifierL( TInt aError, TBool aResult, + const TDesC8& aData ) + { + BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aError ); + if ( iNotifierMessage.IsNull() ) + { + // Request not anymore active -> ignore + return; + } + TInt err = aError; + TPtrC8 resultData(KNullDesC8); + TBTPinCode pinCode; + TPckgBuf userAcceptance; + TInt uid = iNotifierMessage.Int0(); + + if( !err ) + { + // The returned data is the entered passkey. + const CBtDevExtension* dev = iParent.BTDevRepository().Device(iRemote); + if(dev) + { + iParent.ConnectionTracker().UpdateBlockingHistoryL(&dev->Device(),aResult); + } + if( uid == KBTNumericComparisonNotifierUid.iUid ) + { + // Numeric comparison needs the boolean result passed back. + userAcceptance() = aResult; + resultData.Set( userAcceptance ); + } + if( aResult ) + { + if( uid == KBTManPinNotifierUid.iUid + || uid == KBTPinCodeEntryNotifierUid.iUid ) + { + // Check the passkey entered by the user. + // The length of the returned data equals the number of characters + // entered by the user. + // Check that the passkey length do not exceed the maximum allowed size + TInt pinCodeLength = aData.Length(); + if(pinCodeLength > KHCIPINCodeSize) + { + pinCodeLength = KHCIPINCodeSize; + } + pinCode().iLength = pinCodeLength; + // Check that the length of the passkey meets the minimum + // required pin code length + if( pinCodeLength >= iMinPinLength ) + { + for( TInt i = 0; i < pinCodeLength; i++ ) + { + pinCode().iPIN[i] = aData[i]; + } + resultData.Set( pinCode ); + } + else + { + // shouldn't happen since the length is checked in the dialog + err = KErrCompletion; + } + } + } + else + { + err = KErrCancel; + } + } + // Complete the message with the result, and result data if any. + if ( !err && resultData.Length() ) + { + err = iNotifierMessage.Write( EBTNotifSrvReplySlot, resultData ); + } + if(err && (uid == KBTNumericComparisonNotifierUid.iUid)) + { + // We need to reject the numeric comparaison otherwise + // the link will remain active + userAcceptance() = aResult; + resultData.Set( userAcceptance ); + err = iNotifierMessage.Write( EBTNotifSrvReplySlot, resultData ); + } + iNotifierMessage.Complete( err ); + BOstraceFunctionExit1( DUMMY_DEVLIST, this ); + } + +// --------------------------------------------------------------------------- +// Ask the user to allow incoming pairing. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::StartAcceptPairingQueryL() + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + PrepareNotificationL( TBluetoothDialogParams::EUserAuthorization, EAuthorization ); + iState = EIncomingPairingAcceptconfirm; + // if rejected, the client message is completed in CompleteAcceptPairingQueryL + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// The user was asked to accept an incoming pairing. Process and proceed. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::CompleteAcceptPairingQueryL( TInt aError) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + TInt err = aError; + TBool proceed = EFalse; + + if( !err ) + { + const CBtDevExtension* dev = iParent.BTDevRepository().Device(iRemote); + if(dev) + { + proceed = iParent.ConnectionTracker().UpdateBlockingHistoryL(&dev->Device(),iAcceptPairingResult); + } + if( iAcceptPairingResult ) + { + // User accepted, continue to show pairing query. + // Trust the device + if(iCheckBoxState){ + iParent.TrustDevice(iRemote); + } + StartPairingUserInputL(); + } + else + { + if( proceed && iCheckBoxState ) + { + //ask to block the device. + iParent.BlockDevice(iRemote,proceed); + } + err = iParent.SetPairObserver(iRemote,EFalse); + err = KErrCancel; // We need to complete the pairing request here + } + } + if( err ) + { + // The user denied the connection, or something else prevented completion. + CompletePairingNotifierL( err, EFalse, KNullDesC8 ); + } + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Parse the parameters of a request for pairing. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::ParseNotifierReqParamsL() + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + // Reset to make sure all vars contain initial values. + iLocallyInitiated = EFalse; + iDialogNumeric.Zero(); + iDialog = TBluetoothDialogParams::EInvalidDialog; + iDialogResource = ENoResource; + iRemote = TBTDevAddr(); + iMinPinLength = -1; + + TInt uid = iNotifierMessage.Int0(); + // Reset for other pairing modes than PIN code. + // Determine the notifier type by the length of the parameter buffer + if( uid == KBTManPinNotifierUid.iUid || uid == KBTPinCodeEntryNotifierUid.iUid ) + { + if ( uid == KBTManPinNotifierUid.iUid ) + { + ParseLegacyPinCodeReqParamsL( iLocallyInitiated, iMinPinLength, iRemote ); + } + else + { + ParsePinCodeReqParamsL( iLocallyInitiated, iMinPinLength, iRemote ); + } + iDialog = TBluetoothDialogParams::EInput; + iDialogResource = EPinInput; + } + else if( uid == KBTNumericComparisonNotifierUid.iUid ) + { + ParseNumericCompReqParamsL( iLocallyInitiated, iDialogNumeric, iRemote ); + iDialog = TBluetoothDialogParams::EQuery; + iDialogResource = ENumericComparison; + } + else if( uid == KBTPasskeyDisplayNotifierUid.iUid ) + { + ParsePasskeyDisplayReqParamsL( iLocallyInitiated, iDialogNumeric, iRemote ); + iDialog = TBluetoothDialogParams::EQuery; + iDialogResource = EPasskeyDisplay; + } + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Parse the parameters of a request for pairing using pin query. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::ParseLegacyPinCodeReqParamsL( TBool& aLocallyInitiated, + TInt& aMinPinLength, TBTDevAddr& aAddr ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + TBTPasskeyNotifierParams params; + TPckgC paramsPckg( params ); + paramsPckg.Set( iParams ); + aLocallyInitiated = paramsPckg().iLocallyInitiated; + aMinPinLength = paramsPckg().iPasskeyMinLength; + aAddr = paramsPckg().iBDAddr; + iCurrentDeviceName = paramsPckg().iName; + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Parse the parameters of a request for pairing using pin query. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::ParsePinCodeReqParamsL( TBool& aLocallyInitiated, + TInt& aMinPinLength, TBTDevAddr& aAddr ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + TBTPinCodeEntryNotifierParams params; + TPckgC paramsPckg( params ); + paramsPckg.Set( iParams ); + aLocallyInitiated = paramsPckg().LocallyInitiated(); + aMinPinLength = paramsPckg().PinCodeMinLength(); + aAddr = paramsPckg().DeviceAddress(); + iCurrentDeviceName = paramsPckg().DeviceName(); + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Parse the parameters of a request for pairing using numeric comparison. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::ParseNumericCompReqParamsL( TBool& aLocallyInitiated, + TDes& aNumVal, TBTDevAddr& aAddr ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + TBTNumericComparisonParams params; + TPckgC paramsPckg( params ); + paramsPckg.Set( iParams ); + aLocallyInitiated = paramsPckg().LocallyInitiated(); + TBTNumericComparisonParams::TComparisonScenario scenario = + paramsPckg().ComparisonScenario(); + aNumVal.Format( KNumCompFormat, paramsPckg().NumericalValue() ); + aNumVal.Insert(3,_L(" ")); + aAddr = paramsPckg().DeviceAddress(); + iCurrentDeviceName = paramsPckg().DeviceName(); + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Parse the parameters of a request for pairing using passkey display. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::ParsePasskeyDisplayReqParamsL( TBool& aLocallyInitiated, + TDes& aNumVal, TBTDevAddr& aAddr ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + TBTPasskeyDisplayParams params; + TPckgC paramsPckg( params ); + paramsPckg.Set( iParams ); + aLocallyInitiated = paramsPckg().LocallyInitiated(); + aNumVal.Format( KPassKeyFormat, paramsPckg().NumericalValue() ); + aAddr = paramsPckg().DeviceAddress(); + iCurrentDeviceName = paramsPckg().DeviceName(); + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// Get and configure a notification. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::PrepareNotificationL( TBluetoothDialogParams::TBTDialogType aType, + TBTDialogResourceId aResourceId ) + { + BOstraceFunctionEntry0( DUMMY_DEVLIST ); + iNotification = + iParent.ConnectionTracker().NotificationManager()->GetNotification(); + User::LeaveIfNull( iNotification ); // For OOM exception, leaves with KErrNoMemory + iNotification->SetObserver( this ); + iNotification->SetNotificationType( aType, aResourceId ); + TInt err = iNotification->SetData( TBluetoothDeviceDialog::EDeviceName, iCurrentDeviceName ); + NOTIF_NOTHANDLED( !err ) + TBTDeviceName name; + iRemote.GetReadable(name); + err = iNotification->SetData( TBluetoothDialogParams::EAddress, name ); + NOTIF_NOTHANDLED( !err ) + const CBtDevExtension* dev = iParent.BTDevRepository().Device(iRemote); + TInt classofdevice = 0; + if(dev) + { + if(dev->Device().IsValidDeviceClass()) + { + classofdevice = dev->Device().DeviceClass().DeviceClass(); + } + } + err = iNotification->SetData( (TInt) TBluetoothDeviceDialog::EDeviceClass, + classofdevice ); + if( iDialogNumeric.Length() ) + { + err = iNotification->SetData( + TBluetoothDeviceDialog::EAdditionalDesc, iDialogNumeric ); + } + err = iNotification->SetData( TBluetoothDialogParams::EDialogTitle, TBluetoothDialogParams::EPairingRequest); + iCheckBoxState = ETrue; + iAcceptPairingResult = EFalse; + iParent.ConnectionTracker().NotificationManager()->QueueNotificationL( iNotification); + NOTIF_NOTHANDLED( !err ) + BOstraceFunctionExit0( DUMMY_DEVLIST ); + } + +// --------------------------------------------------------------------------- +// The notification is finished, handle the result. +// --------------------------------------------------------------------------- +// +void CBTNotifPairNotifier::NotificationClosedL( TInt aError, const TDesC8& aData ) + { + BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aError ); + // Read the result. + TPckgC 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() ) ); + + if ( iState == EIncomingPairingAcceptconfirm ) + { + CompleteAcceptPairingQueryL(aError); + } + else + { + CompletePairingNotifierL( aError, result(), dataPtr ); + } + BOstraceFunctionExit1( DUMMY_DEVLIST, this ); + } + + + +