/*
* Copyright (c) 2002 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: Implements authorisation notifier class.
*
*/
// INCLUDE FILES
#include <BTNotif.rsg> // Own resources
#include "btnauthnotifier.h" // Own class definition
#include "btNotifDebug.h" // Debugging macros
#include <btextnotifiers.h>
#include <AknMediatorFacade.h> // Cover UI
#include <SecondaryDisplay/BTnotifSecondaryDisplayAPI.h>
#include <btengconstants.h>
#include <btengsettings.h>
#include <e32cmn.h>
#include <btotgpairpub.inl>
#include <btengprivatecrkeys.h>
#include <e32property.h>
#include <e32const.h>
#include <e32des8.h>
#include <e32cmn.h>
#include <utf.h> // Unicode character conversion utilities
#include <btengutil.h>
#ifdef __SERIES60_HELP
#include <hlplch.h>
#include <csxhelp/bt.hlp.hrh> // The bt hrh info is needed, for help launching
#endif
#include <bluetoothuiutil.h>
#include "btnotifnameutils.h"
//
// SDP UUID Constants - Short form
// Taken from Bluetooth Profile specification v1.1
// These are used when registering the service to
// local SDP database and when searching the service
// information from remote device.
const TUint KBTSdpDun = 0x1103;
const TUint KBTSdpGenericTelephony = 0x1204;
const TUint KBTSdpFax = 0x1111;
const TUint KBTSdpObjectPush = 0x1105;
const TUint KBTSdpFileTransfer = 0x1106;
const TUint KBTSdpHeadSet = 0x1108;
const TUint KBTSdpGenericNetworking = 0x1201;
const TUint KBTSdpBasicImaging = 0x111b;
/** Identification for active object */
const TInt KBTNotifAuthNotifierLockReq = 10;
// ================= MEMBER FUNCTIONS =======================
// ----------------------------------------------------------
// CBTAuthNotifier::NewL
// Two-phased constructor.
// ----------------------------------------------------------
//
CBTAuthNotifier* CBTAuthNotifier::NewL()
{
CBTAuthNotifier* self = new (ELeave) CBTAuthNotifier();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
// ----------------------------------------------------------
// CBTAuthNotifier::CBTAuthNotifier
// C++ default constructor can NOT contain any code, that
// might leave.
// ----------------------------------------------------------
//
CBTAuthNotifier::CBTAuthNotifier()
{
}
// ----------------------------------------------------------
// Destructor
// ----------------------------------------------------------
//
CBTAuthNotifier::~CBTAuthNotifier()
{
}
// ----------------------------------------------------------
// CBTAuthNotifier::RegisterL
// ----------------------------------------------------------
//
CBTAuthNotifier::TNotifierInfo CBTAuthNotifier::RegisterL()
{
iInfo.iUid=KBTManAuthNotifierUid;
iInfo.iChannel=KBTAuthorisationChannel;
iInfo.iPriority=ENotifierPriorityVHigh;
return iInfo;
}
// ----------------------------------------------------------
// CBTAuthNotifier::GetParamsL
// Initialize parameters and check if device is already
// in registry. Jump to RunL as soon as possible.
// ----------------------------------------------------------
//
void CBTAuthNotifier::GetParamsL(const TDesC8& aBuffer, TInt aReplySlot, const RMessagePtr2& aMessage)
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::GetParamsL()"));
if( !iMessage.IsNull())
{
User::Leave(KErrInUse);
}
iMessage = aMessage;
iReplySlot = aReplySlot;
if ( AutoLockOnL() )
{
// The phone is locked, access denied.
// Write results back to caller and complete message.
CompleteMessage(EFalse, KErrNone);
return;
}
TBTAuthorisationParams param;
TPckgC<TBTAuthorisationParams> pckg(param);
pckg.Set(aBuffer);
iServiceUid = pckg().iUid.iUid; // Pick up service uid from message
iBTAddr = pckg().iBDAddr;
if ( OtherOutgoPairing( iBTAddr ) )
{
// We won't allow connection request from another device during outgoing pairing:
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier: outgoing pair in progress, reject request from other device"));
CompleteMessage(KErrCancel);
return;
}
// create iDevice so that the name won't be lost if the device does
// not exist in registry.
iDevice = CBTDevice::NewL( iBTAddr );
BtNotifNameUtils::SetDeviceNameL(pckg().iName, *iDevice);
if ( !iNotifLockProp.Handle() )
{
User::LeaveIfError( iNotifLockProp.Attach(
KPSUidBluetoothEnginePrivateCategory, KBTNotifierLocks ) );
}
if(!iLockActive)
{
iLockActive = CBTNotifActive::NewL( this, KBTNotifAuthNotifierLockReq, CActive::EPriorityStandard );
}
CheckAndSubscribeNotifLocks();
if ( !iSuspended )
{
// Check if device is in the registry, function of notifier base
GetDeviceFromRegL( iBTAddr );
}
#ifdef _DEBUG
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::GetParamsL() Executing authorisation..."));
TBuf<12> deviceAddressString;
pckg().iBDAddr.GetReadable(deviceAddressString);
FTRACE(FPrint(_L("[BTNOTIF]\t BT Address: %S"), &deviceAddressString));
FTRACE(FPrint(_L("[BTNOTIF]\t CBTAuthNotifier::GetParamsL Service Uid: %d = 0x%X"), iServiceUid, iServiceUid ));
#endif
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::GetParamsL() completed"));
}
// ----------------------------------------------------------
// CBTAuthNotifier::UpdateL
// Notifier update. Stores the received bluetooth
// device name into registry and show it on screen.
// ----------------------------------------------------------
//
TPtrC8 CBTAuthNotifier::UpdateL(const TDesC8& aBuffer)
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::UpdateL()"));
TBTNotifierUpdateParams params; // Contains iName and iResult (name request)
TPckgC<TBTNotifierUpdateParams> pckg(params);
pckg.Set(aBuffer);
FTRACE(FPrint(_L("[BTNOTIF]\t CBTAuthNotifier::UpdateL - Name: '%S' length: %d"), &pckg().iName, pckg().iName.Length() ));
// If the device name request was successful and if new name is valid, show the new name.
if (pckg().iResult == KErrNone)
{
BtNotifNameUtils::SetDeviceNameL(pckg().iName, *iDevice); // Override possible previous device name
// Show new prompt for dialog if it is still on the screen
if ( !iDevice->IsValidFriendlyName() && iDevice->IsValidDeviceName())
{
// Create new prompt string with new device name
RBuf stringholder;
CleanupClosePushL( stringholder );
BluetoothUiUtil::LoadResourceAndSubstringL(
stringholder, iStrResourceId,
BTDeviceNameConverter::ToUnicodeL(iDevice->DeviceName()), 0 );
iNotifUiUtil->UpdateQueryDlgL( stringholder );
iNotifUiUtil->UpdateCoverUiL( iDevice->DeviceName() );
CleanupStack::PopAndDestroy(); // stringholder
}
}
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::UpdateL() completed"));
TPtrC8 ret(KNullDesC8);
return (ret);
}
// ----------------------------------------------------------
// CBTAuthNotifier::RequestCompletedL
// Gets called when P&S key notifies change
// ----------------------------------------------------------
void CBTAuthNotifier::RequestCompletedL( CBTNotifActive* aActive, TInt aId, TInt aStatus )
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::RequestCompletedL()"));
ASSERT( aId == KBTNotifAuthNotifierLockReq );
(void) aActive;
(void) aId;
if ( aStatus == KErrNone )
{
TBool prevSuspend = iSuspended;
// check the latest lock status and subscribe to further lock event:
CheckAndSubscribeNotifLocks();
if ( prevSuspend && !iSuspended )
{
// Check if device is in the registry, function of notifier base
GetDeviceFromRegL( iBTAddr );
}
else if ( iSuspended && !(iNotifUiUtil->IsQueryReleased()) )
{
iNotifUiUtil->DismissDialog();
}
}
else
{
HandleError( aActive, KBTNotifAuthNotifierLockReq, iLockActive->RequestStatus().Int() );
}
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::RequestCompletedL() completed"));
}
// ----------------------------------------------------------
// CBTAuthNotifier::HandleError
// ----------------------------------------------------------
void CBTAuthNotifier::HandleError( CBTNotifActive* aActive, TInt aId, TInt aError )
{
FTRACE(FPrint(_L("[BTNOTIF]\t CBTAuthNotifier::HandleError() error = %d"), aError ));
(void) aActive;
(void) aId;
(void) aError;
}
// ----------------------------------------------------------
// CBTAuthNotifier::DoCancelRequest
// Root caller is CBTNotifActive::CancelRequest(), which calls
// CActive::Cancel that calls DoCancel() if request is active.
// ----------------------------------------------------------
void CBTAuthNotifier::DoCancelRequest( CBTNotifActive* aActive, TInt aId )
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::DoCancel() >>"));
ASSERT( aId == KBTNotifAuthNotifierLockReq );
(void) aActive;
(void) aId;
iNotifLockProp.Cancel();
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::DoCancel() <<"));
}
// ----------------------------------------------------------
// CBTAuthNotifier::Cancel
// Not Active Object's cancel, but notifier deactivation
// Release all own resources (member variables)
// ----------------------------------------------------------
//
void CBTAuthNotifier::Cancel()
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::Cancel()"));
if (iLockActive)
{
iLockActive->CancelRequest();
delete iLockActive;
iLockActive = NULL;
}
iNotifLockProp.Close();
CBTNotifierBase::Cancel();
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::Cancel() completed"));
}
void CBTAuthNotifier::HandleGetDeviceCompletedL(const CBTDevice* aDev)
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::HandleGetDeviceCompleted()"));
(void) aDev;
if ( iSuspended)
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::HandleGetDeviceCompleted, still suspended, wait"));
return;
}
TBool reqAllowed = IsJustWorksPaired( iDevice->AsNamelessDevice() ) ?
IsUserAwarePaired( iDevice->AsNamelessDevice() ) : ETrue ;
FTRACE(FPrint(_L("[BTNOTIF]\t CBTAuthNotifier, reqAllowed %d" ), reqAllowed ) );
if ( !reqAllowed )
{
// Do not grant access to device that is not paired in Just Works mode without
// user awareness, e.g. pairing due to an incoming connection request from a
// headset.
CompleteMessage(KErrAccessDenied);
return;
}
iStrResourceId = R_BT_AUTHORISATION_NAME;
// Select authorisation state for further use (dialogue selection)
switch( iServiceUid )
{
case KBTSdpObjectPush:
case KBTSdpBasicImaging:
iAuthState = EBTObexAuthorisation;
iStrResourceId = R_BT_RECEIVE_MESSAGE;
iCoverUiDlgId = ECmdShowReceiveMessageFromDeviceDlg;
if( IsUserAwarePaired( iDevice->AsNamelessDevice() ) )
{
iAuthState = EBTObexAuthForPairedDevice;
iStrResourceId = R_BT_RECEIVE_MESSAGE_PAIRED;
iCoverUiDlgId = ECmdShowReceiveMessageFromPairedDeviceDlg;
}
break;
case KBTSdpFax:
case KBTSdpDun:
case KBTSdpFileTransfer:
case KBTSdpHeadSet:
case KBTSdpGenericTelephony:
case KBTSdpGenericNetworking:
if ( iDevice->GlobalSecurity().NoAuthorise() )
{
iAuthState = EBTAutoAuthorisation;
}
else
{
iAuthState = EBTNormalAuthorisation;
}
iCoverUiDlgId = ECmdShowAcceptConnRequestDlg;
break;
default:
{ // check if device is authorized
if ( iDevice->GlobalSecurity().NoAuthorise() )
{
iAuthState = EBTAutoAuthorisation;
}
else
{
iAuthState = EBTAutoAuthorisationNotAuthorisedOnPhone;
}
break;
}
}
FTRACE(FPrint(_L("[BTNOTIF]\t CBTAuthNotifier::HandleGetDeviceComplete() Complete. iAuthState = %d"), iAuthState ));
ShowAuthoQueryL();
}
// ----------------------------------------------------------
// CBTAuthNotifier::GetByPassAudioNotifier
// is bypassing this audio connection query needed and if it is, will the
// query be automatically accepted or rejected.
//
// This is used for bypassing the notifiers of the 2nd audio connection, so
// the the user needs to reply to the incoming audio link only once.
// ----------------------------------------------------------
//
TBool CBTAuthNotifier::GetByPassAudioNotifier(const TBTDevAddr& aDeviceAddress,TBool& aAccept)
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::GetByPassAudioNotifier()"));
TBuf8<48> buf;
RProperty::Define(KPSUidBluetoothEnginePrivateCategory,KBTAuthorInfoPerDevice, RProperty::EByteArray );
RProperty::Get(KPSUidBluetoothEnginePrivateCategory,KBTAuthorInfoPerDevice,buf);
if(buf.Length()>2)
{
// accept status of last attempt
aAccept= (buf[0]=='1');
// last address
TBuf<12> oldAddrString;
oldAddrString.Copy(buf.Mid(2,12));
TBTDevAddr lastAddress;
lastAddress.SetReadable(oldAddrString);
// last time
TInt64 num(0);
TLex8 lex;
lex=buf.Mid(15);
TBuf<32> tmp_debug;
tmp_debug.Copy(buf.Mid(15));
lex.Val( num );
TTime lastConnectionTime( num );
TTime now;
now.UniversalTime();
TBuf16<48> buf2;
buf2.Copy(buf);
FTRACE(FPrint(_L("[BTNOTIF]\t CBTAuthNotifier::GetByPassAudioNotifier() Complete same_address=%d Time_ok=%d last_reply=%d"),lastAddress==aDeviceAddress,now>=lastConnectionTime && now <lastConnectionTime+ TTimeIntervalSeconds(5),aAccept));
return lastAddress==aDeviceAddress && (now>=lastConnectionTime && now <lastConnectionTime+ TTimeIntervalSeconds(5) );
}
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::GetByPassAudioNotifier() Complete - empty key"));
return EFalse;
}
// ----------------------------------------------------------
// CBTAuthNotifier::MemorizeCurrentAudioAttempt
// Store the information about this audio connection attempt
// and what user replied to that. This is used by
// GetBypassAudio Notifier.
// ----------------------------------------------------------
//
void CBTAuthNotifier::MemorizeCurrentAudioAttempt(const TBool aAccept,const TBTDevAddr& aDeviceAddress)
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::MemorizeCurrentAudioAttempt()"));
TBuf8<48> buf;
buf.Zero();
buf.AppendNum(aAccept!=EFalse);//now 0/1 only.
buf.Append(';');
TBuf<12> a;
aDeviceAddress.GetReadable(a);
for(TInt t=0;t<12;t++)
buf.Append(a[t]);
buf.Append(';');
TTime writeTime;
writeTime.UniversalTime();
buf.AppendNum( writeTime.Int64() );
RProperty::Set(KPSUidBluetoothEnginePrivateCategory,KBTAuthorInfoPerDevice,buf);
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::MemorizeCurrentAudioAttempt() complete"));
}
// ----------------------------------------------------------
// CBTAuthNotifier::ShowAuthoQueryL
// Ask user's response on authorization query
// ----------------------------------------------------------
//
void CBTAuthNotifier::ShowAuthoQueryL()
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::ShowAuthoQueryL"));
if ( iAuthState == EBTAutoAuthorisation )
{
// device alreay set trusted now. allow connection automatically
CompleteMessage(ETrue, KErrNone);
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier, device authorized already, allow connection automatically" ));
return;
}
TBool reply;
if ( GetByPassAudioNotifier(iDevice->BDAddr(),reply) )
{
FTRACE(FPrint(_L("[BTNOTIF]\t CBTAuthNotifier::ShowAuthoQueryL bypassing notifier with reply: %d"),reply));
CompleteMessage(reply, KErrNone);
return;
}
// Not asking user's response if auth request is for: profile HFP/HSP/A2DP/AVRCP, and
// there is already existing connection to one of those profiles from the same device.
//
TBool connectStatus = IsExistingConnectionToAudioL( iDevice->BDAddr() );
// if iAuthState==EBTAutoAuthorisationNotAuthorised and device is connected it means it tries several connections
// so we just approve this. Also if connected & EBTAutoAuthorisation.
//
if(connectStatus && ( iAuthState==EBTAutoAuthorisationNotAuthorisedOnPhone))
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::Automatic authorisation ()"));
//Antomatic authorisation without asking user
CompleteMessage(ETrue, KErrNone);
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::ShowAuthoQueryL() completed-" ));
return;
}
// check if we're showing bt off query
TInt queryValue=EBTQueryOff;
RProperty::Get(KPSUidBluetoothEnginePrivateCategory,KBTTurnBTOffQueryOn,queryValue);
if( queryValue == EBTQueryOn )
{
CompleteMessage(KErrCancel);
return;
}
TBTDeviceName tempDeviceName;
BtNotifNameUtils::GetDeviceDisplayName(tempDeviceName, iDevice);
RBuf stringholder;
CleanupClosePushL( stringholder );
BluetoothUiUtil::LoadResourceAndSubstringL(
stringholder, iStrResourceId, tempDeviceName, 0);
TInt keypress = iNotifUiUtil->ShowQueryL( stringholder, R_BT_AUTHORISATION_QUERY,
iCoverUiDlgId, tempDeviceName, CAknQueryDialog::EConfirmationTone );
CleanupStack::PopAndDestroy(); // stringholder
// If this notifier is cancelled by the caller, no need to perform the rest operation:
if ( iSuspended || iMessage.IsNull() )
{
return;
}
if( keypress ) // User has accepted the dialog
{
if( iDevice && !iDevice->IsValidLinkKey() )
{
TTime now;
now.UniversalTime();
TBuf8<32> buf;
buf.AppendNum( now.Int64() );
RProperty::Set(KPSUidBluetoothEnginePrivateCategory,KBTConnectionTimeStamp,buf);
}
MemorizeCurrentAudioAttempt(ETrue,iDevice->BDAddr() );
CompleteMessage( ETrue, KErrNone );
}
else // User has rejected the dialog.
{
iLockActive->CancelRequest();
DoRejectAuthorizationL();
}
}
// ----------------------------------------------------------
// CBTAuthNotifier::DoRejectAuthorizationL
// Handle query threshold and block after user rejects authorization
// ----------------------------------------------------------
//
void CBTAuthNotifier::DoRejectAuthorizationL()
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::DoRejectAuthorizationL()"));
CheckAndHandleQueryIntervalL();
if( iMessage.IsNull() )
{
return; // No need to continue.
}
MemorizeCurrentAudioAttempt(EFalse,iDevice->BDAddr());
//Logic: query block only at the second time for the same paired device
// query block everytime after rejection for non-paired device.
if( IsPaired( iDevice->AsNamelessDevice() ) )
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::DoRejectAuthorizationL() rejected a paired device."));
TBuf<2*KBTDevAddrSize> tmp; //2 hex digits per byte
RProperty::Get(KPSUidBluetoothEnginePrivateCategory, KBTBlockDevAddr, tmp);
TBTDevAddr priorDeviceaddress;
priorDeviceaddress.Reset();
priorDeviceaddress.SetReadable(tmp);
if(priorDeviceaddress != iDevice->BDAddr() )
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::DoRejectAuthorizationL() NOT the prior rejected device, no block query."));
// The last device was not current device,
// so the last device is updated to be current device.
iDevice->BDAddr().GetReadable(tmp);
RProperty::Set(KPSUidBluetoothEnginePrivateCategory, KBTBlockDevAddr, tmp );
// Complete message and free resources
CompleteMessage(EFalse, KErrNone);
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::DoRejectAuthorizationL() completed"));
return;
}
else
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier::DoRejectAuthorizationL() IS SAME as the prior rejected device."));
// this was 2nd time in row. Clear the key, so the question will not be made next time.
TBuf<2*KBTDevAddrSize> tmp;
TBTDevAddr emptyAddr;
emptyAddr.Reset();
emptyAddr.GetReadable(tmp);
RProperty::Set(KPSUidBluetoothEnginePrivateCategory, KBTBlockDevAddr, tmp );
}
}
// Ask user to Block this device or not.
if( !iMessage.IsNull() )
{
QueryBlockDeviceL();
}
}
// ----------------------------------------------------------
// CBTAuthNotifier::CheckAndSubscribeNotifLocks
// Subscribe to PS key and check key value.
// ----------------------------------------------------------
//
void CBTAuthNotifier::CheckAndSubscribeNotifLocks()
{
if ( !iLockActive->IsActive() )
{
FLOG(_L("[BTNOTIF]\t CBTAuthNotifier, Subscribe Device Operation Info"));
iNotifLockProp.Subscribe( iLockActive->RequestStatus() );
iLockActive->GoActive();
}
TInt ops;
TBTNotifLockPublish::GetNotifLocks( iNotifLockProp,
ops, iBTAddr );
iSuspended = ops & EBTNotiferLockPairedDeviceSetting;
FTRACE(FPrint(_L("[BTNOTIF]\t CBTAuthNotifier suspended ? %d"), iSuspended ));
}
// End of File