bluetoothcommsprofiles/btpan/panagt/panagtremdevselector.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothcommsprofiles/btpan/panagt/panagtremdevselector.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,292 @@
+// Copyright (c) 2004-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:
+//
+// Description:
+//
+
+#include <bluetooth/logger.h>
+#include <networking/panuiinterfaces.h>
+#include <comms-infras/dbaccess.h>
+#include "panagtlog.h"
+#include "panagtremdevselector.h"
+using namespace PanAgent;
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT);
+#endif
+
+CPanRemoteDeviceSelector::CPanRemoteDeviceSelector(
+	MOutgoingConnectionCreator& aOutgoingConnectionCreator, CCommsDbAccess& aDatabase) :
+	CActive(KPanAgtAoRemoteDevicePromptPriority), 
+	iOutgoingConnectionCreator(aOutgoingConnectionCreator), 
+	iDatabase(aDatabase)
+/**
+Store all the pointers and chuck ourselves on the active scheduler
+*/
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CPanRemoteDeviceSelector::~CPanRemoteDeviceSelector()
+	{
+	iDevAddresses.Close();
+	}
+
+void CPanRemoteDeviceSelector::PerformRemoteDeviceSelectionL()
+/**
+Find out whether there are any remote devices in commdb, or whether we should be prompting 
+(or whether we should just do nothing)
+*/
+	{
+	LOG(_L("RemDevSelector: Deciding which device to connect to."));
+	TInt err;
+	
+	TBool prompt;
+	iDatabase.GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_PROMPT_FOR_REMOTE_DEVICES), prompt);
+	
+	LOG1(_L("RemDevSelector: prompt mode is %d..."), prompt);
+	
+	if (prompt)
+		{
+		LOG(_L("RemDevSelector: ...starting notifier..."));
+		
+		// Check if we're already prompting for devices.
+		if (IsPrompting())
+			{
+			User::Leave(KErrInUse);
+			}
+		
+		User::LeaveIfError(err = iNotifier.Connect());
+		iNotifier.StartNotifierAndGetResponse(iStatus, KBTPanDeviceSelectionNotifierUid, KNullDesC8, iDeviceList);
+		iState = EWaitingForNotifier;
+		SetActive();
+		return;
+		}
+	
+	// If we've got here, we aren't allowed to prompt until we've tried to connect to a fixed set of devices.
+	LOG(_L("RemDevSelector: ...reading address(es) from commdb..."));
+
+	TRAP(err, iDatabase.GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_PROMPT_IF_MAC_LIST_FAILS), iPromptIfMACFails));
+	if (err)
+		{
+		iPromptIfMACFails = EFalse;
+		}
+	LOG1(_L("RemDevSelector: prompt fallback set to %d"), iPromptIfMACFails);
+
+	TBuf<KCommsDbSvrMaxFieldLength> remoteDeviceAddressList;
+	TRAP(err, iDatabase.GetDesL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_PEER_MAC_ADDRESSES), remoteDeviceAddressList));
+	
+	// Parse buffer from commdb
+	if((remoteDeviceAddressList.Length()) && !err) // firstly make sure there's something in the buffer
+		{
+		LOG1(_L("RemDevSelector: ...commdb buffer is %d bytes long..."), remoteDeviceAddressList.Length());
+		
+		ConvertListToArray(remoteDeviceAddressList);
+		//Connect only to one of the devices at a time.
+		}
+	
+	if (HasMoreDevices())
+		{
+		CreateNextConnectionL();
+		}
+	else
+		{
+		if(err)
+			{
+			LOG1(_L("RemDevSelector: ...reading device addressses from commdb failed with %d, and prompt mode disabled.  Giving up - this must be a listen only connection, or someone's screwed up the commdb settings."), err);
+			}
+		else
+			{
+			LOG(_L("RemDevSelector: ...no device addresses in commdb, and prompt mode disabled.  Giving up - this must be a listen only connection, or someone's screwed up the commdb settings."));
+			}
+		}
+	}
+
+
+/**
+Called by the PanAgent upon disconnection (before PAN connection is up) to see if 
+there is more devices it can try to connect
+*/
+TBool CPanRemoteDeviceSelector::HasMoreDevices()
+	{
+	return iPromptIfMACFails || (iDevAddresses.Count() > 0);
+	}
+
+/**
+Called by the PanAgent upon device active to prevent PanAgent from trying the next 
+device upon disconnection of a successful PAN connection.
+*/
+void CPanRemoteDeviceSelector::Reset()
+	{
+	iDevAddresses.Reset();
+	}
+	
+void CPanRemoteDeviceSelector::RunL()
+/**
+Prompt has completed. We assume the user want to connect to all of them if multiple 
+devices are selected.
+*/
+	{
+	switch(iState)
+		{
+		case EWaitingForNotifier:
+			{
+			LOG1(_L("RemDevSelector: ...notifier completed with %d"), iStatus.Int());
+			TInt err = iNotifier.CancelNotifier(KBTPanDeviceSelectionNotifierUid);
+			LOG1(_L("RemDevSelector: ...CancelNotifier completed with %d"), err);
+
+			if(iStatus==KErrNone)
+				{
+				TBTDevAddr devAddr;
+				err = iDeviceList.GetDevice(devAddr);
+				while(err==KErrNone)
+					{
+					TRAP(err, iOutgoingConnectionCreator.CreateNewConnectionForOutgoingL(devAddr));
+					if(err) // might be that device is connected already, or a more general error
+						{
+						err = iOutgoingConnectionCreator.DeviceSelectionError(err); // replace one err with anoth-err
+						if(err==KErrDisconnected)	// we've decided to disconnect
+							{
+							return;
+							}
+						}
+					err = iDeviceList.GetDevice(devAddr);
+					}
+				iDeviceList.Reset();
+				}
+			else
+				{
+				if (iStatus==KErrCancel)
+					{
+					// The user has rejected the remote device(s) by cancelling the selector, 
+					// but in order that CNifSession::DecideWhetherToRetry() will respond to 
+					// this action by going to the next IAP in its connection preference list, 
+					// we need to change the reported error...
+					iStatus = KErrCouldNotConnect;
+					}
+					
+				iOutgoingConnectionCreator.DeviceSelectionError(iStatus.Int());
+				return;
+				}
+			break;
+			}
+		case ENotWaiting:
+		// fall through
+		default:
+			{
+			PanAgentPanic(EAsyncOperationOnOutgoingConnectionStarterWhenItsNotPerformingAnAsyncRequest);
+			}
+		}
+	}
+
+TBool CPanRemoteDeviceSelector::IsPrompting()
+/**
+Is there currently a prompt on screen?
+*/
+	{
+	return((iState==EWaitingForNotifier)&&IsActive());
+	}
+	
+void CPanRemoteDeviceSelector::DoCancel()
+/**
+
+*/
+	{
+	switch(iState)
+		{
+		case EWaitingForNotifier:
+			{
+			iNotifier.CancelNotifier(KBTPanDeviceSelectionNotifierUid);
+			break;
+			}
+		case ENotWaiting:
+		// fall through
+		default:
+			{
+			PanAgentPanic(EAsyncOperationOnOutgoingConnectionStarterWhenItsNotPerformingAnAsyncRequest);
+			break;
+			}
+		}
+	}
+
+void CPanRemoteDeviceSelector::ConvertListToArray(TDesC& aDeviceAddrList)
+/**
+Put the comma-separated list of readable BT device addresses into an array
+*/
+	{
+	TBTDevAddr devAddr;
+	TLex lex(aDeviceAddrList);
+
+	TChar charComma(',');	// this weird construct is needed to prevent us needing static data
+	while(lex.Peek()!=charComma && !lex.Eos())
+	{
+		lex.Mark();
+		while((lex.Get()!=charComma) && !lex.Eos())
+			{
+			
+			}
+		devAddr.SetReadable(lex.MarkedToken());
+		// RArrays default to a granularity of 8 and we only connect to one device
+		// at a time so it's reasonable to ignore this error, as a) in common use
+		// bluetooth piconet size can't go beyond 8 anyway and b) if we use up
+		// all the 8/16/... addresses in this array the user will be prompted for
+		// more (although they probably won't have enough memory to make the
+		// connection anyway).
+		(void)iDevAddresses.Append(devAddr);
+		}
+	}
+
+/**
+Connect to the first device in the address list and remove it from the list
+*/
+void CPanRemoteDeviceSelector::CreateNextConnectionL()
+	{
+	//Assertion here is just for flusing out internal problems e.g. The notifier completes the
+	//Request with KErrNone while no devices are selected
+	__ASSERT_DEBUG(HasMoreDevices(), PanAgentPanic(EPanAgtRemDevSelectorNoDevicesToConnect));
+	
+	// If we've run out of addresses in our list, CommsDat may be configured to allow us to ask
+	// the user for another device.
+	// In fact, if we're here and we have no devices, then we *MUST* be allowed to ask, as this
+	// will have already been checked.  So we can assume the prompt flag without having to check.
+	if (!iDevAddresses.Count())
+		{
+		iPromptIfMACFails = EFalse;		// To maintain symmetry with the consumption of the remote list, clear this flag.
+		
+		LOG(_L("RemDevSelector: ...starting notifier (empty devices list or no more remaining)..."));
+		
+		// Check if we're already prompting for devices.
+		if (IsPrompting())
+			{
+			User::Leave(KErrInUse);
+			}
+		
+		User::LeaveIfError(iNotifier.Connect());
+		iNotifier.StartNotifierAndGetResponse(iStatus, KBTPanDeviceSelectionNotifierUid, KNullDesC8, iDeviceList);
+		iState = EWaitingForNotifier;
+		SetActive();
+		return;
+		}
+
+
+	TBTDevAddr remDevAddr = iDevAddresses[0];
+
+#ifdef __FLOG_ACTIVE
+	TBuf<KMaxBtAddrSize> tempDevAddrBuf;
+	remDevAddr.GetReadable(tempDevAddrBuf, KNullDesC, KBtAddrSeparator, KNullDesC);
+	LOG1(_L("RemDevSelector: Creating connection to new device, address: %S"), &tempDevAddrBuf);
+#endif
+
+	
+	iDevAddresses.Remove(0);
+	iOutgoingConnectionCreator.CreateNewConnectionForOutgoingL(remDevAddr);
+	}