bluetoothmgmt/btmgr/BTManClient/BTManClient.cpp
changeset 0 29b1cd4cb562
child 51 20ac952a623c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothmgmt/btmgr/BTManClient/BTManClient.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1315 @@
+// Copyright (c) 1999-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 <btmanclient.h>
+#include <e32math.h>
+#include <utf.h>
+#include "btmanclientserver.h"
+#include "s32strm.h"
+#include <bluetooth/logger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_BT_MANAGER_CLIENT);
+#endif
+
+const TInt KServerRetries = 2;
+const TUint8 KDummyDevicePointer = 0xff;
+
+/**
+Start the btmanserver
+@return Systemwide error code
+@internalComponent
+@released
+*/
+static TInt StartServer()
+	{
+	LOG_STATIC_FUNC
+
+	const TUidType serverUid(KNullUid,KNullUid,KBTManServerUid3);
+	
+#ifdef __BTMANSERVER_NO_PROCESSES__
+	//
+	// In EKA1 WINS the server is a DLL, the exported entrypoint returns a TInt
+	// which represents the real entry-point for the server thread
+	//
+	RLibrary lib;
+	TInt r=lib.Load(KBTManServerImg,serverUid);
+	if (r!=KErrNone)
+		return r;
+	TLibraryFunction ordinal1=lib.Lookup(1);
+	TThreadFunction serverFunc=reinterpret_cast<TThreadFunction>(ordinal1());
+	//
+	// To deal with the unique thread (+semaphore!) naming in EPOC, and that we may
+	// be trying to restart a server that has just exited we attempt to create a
+	// unique thread name for the server.
+	// This uses Math::Random() to generate a 32-bit random number for the name
+	//
+	TName name(KBTManServerName);
+	_LIT(KHexString, "0x");
+ 	name.Append(KHexString());
+	name.AppendNum(Math::Random(),EHex);
+	RThread server;
+	r=server.Create(name,serverFunc,
+					KBTManServerStackSize,
+					NULL,&lib,NULL,
+					KBTManServerInitHeapSize,KBTManServerMaxHeapSize,EOwnerProcess);
+	lib.Close();	// if successful, server thread has handle to library now
+#else
+	//
+	// EPOC and EKA2 is easy, we just create a new server process. Simultaneous
+	// launching of two such processes should be detected when the second one
+	// attempts to create the server object, failing with KErrAlreadyExists.
+	//
+	RProcess server;
+	TInt r=server.Create(KBTManServerImg,KNullDesC,serverUid);
+#endif
+
+	LOG1(_L("BTMan Server created, code %d"), r);
+
+	if (r!=KErrNone)
+		return r;
+	TRequestStatus stat;
+	server.Rendezvous(stat);
+	if (stat!=KRequestPending)
+		{
+		server.Kill(0);		// abort startup
+		}
+	else
+		{
+		server.Resume();	// logon OK - start the server
+		LOG(_L("BTMan Server Resumed"));
+		}
+		
+	User::WaitForRequest(stat);		// wait for start or death
+	// we can't use the 'exit reason' if the server panicked as this
+	// is the panic 'reason' and may be '0' which cannot be distinguished
+	// from KErrNone
+	LOG1(_L("BTMan Server started, code %d (0=>success)"), stat.Int());
+	r=(server.ExitType()==EExitPanic) ? KErrGeneral : stat.Int();
+	
+    server.Close(); 
+ 	LOG(_L("BTMan Server Closed"));
+ 	
+	return r;
+	}
+
+
+/**
+Default Constructor.
+@publishedAll
+@released
+*/
+EXPORT_C RBTMan::RBTMan()
+	{
+	LOG_FUNC
+	}
+
+
+/**
+Connects to the btman server.
+@return systemwide error code
+@publishedAll
+@released
+*/
+EXPORT_C TInt RBTMan::Connect()
+	{
+	LOG_FUNC
+	TInt retry=KServerRetries;
+	for (;;)
+		{
+		TInt r=CreateSession(KBTManServerName,Version());	//gives MessageSlots of -1
+																//this uses global pool rather
+																//than local pool
+		if (r!=KErrNotFound && r!=KErrServerTerminated)
+			return r;
+		if (--retry==0)
+			return r;
+		r=StartServer();
+		if (r!=KErrNone && r!=KErrAlreadyExists)
+			return r;
+		}
+	}
+
+/**
+Returns the version of the server.
+@return version of btmanserver
+*/
+EXPORT_C TVersion RBTMan::Version() const
+/**
+**/
+	{
+	LOG_FUNC
+	return TVersion(KBTManServerMajorVersionNumber, 
+					KBTManServerMinorVersionNumber, 
+					KBTManServerBuildVersionNumber);
+	}
+
+
+/**
+Default constructor of base class for subsessions
+@publishedAll
+@released
+*/
+EXPORT_C RBTManSubSession::RBTManSubSession()
+: iClientServerMsg()
+	{
+	LOG_FUNC
+	iClientServerMsg().iClientBusy = EFalse;
+	iClientServerMsg().iClientStatusToCancel = NULL;
+	}
+
+/**
+Cancel an outstanding request on btmanserver
+@param aStatus the status of active object that made the original request
+@publishedAll
+@released
+*/
+EXPORT_C void RBTManSubSession::CancelRequest(TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (SubSessionHandle())
+		{
+		SendReceive(EBTManCancelRequest, TIpcArgs(&aStatus));
+		}
+	else
+		{
+		//Client has a bad handle therefore complete the call from here
+		LocalComplete(aStatus, KErrBadHandle);
+		}
+	}
+
+/**
+Completes a request locally without involving the server.
+Called when a client-side error occurs.
+@param	aStatus:	The TRequestStatus of the active object that made the request that needs to be completed.
+@param	aErr:		The reason for completion. aErr will be written into the TRequestStatus of the active object.
+@internalComponent
+@released
+**/
+void RBTManSubSession::LocalComplete(TRequestStatus& aStatus, TInt aErr)
+	{
+	LOG_FUNC
+	aStatus = KRequestPending;
+	TRequestStatus* pS = &aStatus;
+	User::RequestComplete(pS, aErr);
+	}
+
+
+TBool RBTManSubSession::IsBusy() const
+	{
+	LOG_FUNC
+	return iClientServerMsg().iClientBusy;
+	}
+
+/**
+To prevent clients using the server more than once
+Business is cleared once the server has completed the job
+@param aStatus the status of the client AO making a request on the server. this will can be used for cancelling later
+@internalComponent
+@released
+**/
+void RBTManSubSession::SetBusy(TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	iClientServerMsg().iClientBusy = ETrue;
+	iClientServerMsg().iClientStatusToCancel = &aStatus;
+	}
+
+/**
+Default constructor of registry session
+@publishedAll
+@released
+*/
+EXPORT_C RBTRegServ::RBTRegServ()
+	{
+	LOG_FUNC
+	}
+
+
+/**
+Connect to Registry Server
+@return System-wide error code
+@publishedAll
+@released
+@capability LocalServices
+*/
+EXPORT_C TInt RBTRegServ::Connect()
+	{
+	LOG_FUNC
+	// we provide the standard RBTMan session for now, but the client doesnt know this!
+	TInt r=RBTMan::Connect();
+	return r;
+	}
+
+/**
+Close session on Registry Server
+@publishedAll
+@released
+*/
+EXPORT_C void RBTRegServ::Close()
+	{
+	LOG_FUNC
+	RBTMan::Close();
+	}
+
+/**
+Return reference to the server session
+@return reference to btman session
+@publishedAll
+@released
+*/
+EXPORT_C RBTMan& RBTRegServ::Session()
+	{
+	LOG_STATIC_FUNC
+	return static_cast<RBTMan&>(*this);
+	}
+
+#ifndef _DEBUG
+EXPORT_C TInt RBTRegServ::SetHeapFailure(TInt /*aType*/,TInt /*aRate*/)
+#else
+EXPORT_C TInt RBTRegServ::SetHeapFailure(TInt aType,TInt aRate)
+#endif
+/**
+Send a message to the server to fail memory allocations (in debug builds)
+@internalAll
+@released
+*/
+	{
+	LOG_FUNC
+#ifdef _DEBUG
+	return SendReceive(EBTManSetHeapFailure,TIpcArgs(static_cast<RHeap::TAllocFail>(aType), aRate));
+#else
+	return KErrNotSupported;
+#endif
+	}
+
+
+/**
+Returns the number of open subsessions.
+This should be used by clients to do resource leakage debugging checks
+@publishedAll
+@released
+*/
+EXPORT_C TInt RBTRegServ::ResourceCount()
+	{
+	LOG_FUNC
+	TInt count = 0;
+	TPckg<TInt> pckg(count);
+	SendReceive(EBTManSubSessionCount, TIpcArgs(&pckg));
+	return count;
+	}
+
+/**
+Default constructor for registry subsession
+@publishedAll
+@released
+*/
+EXPORT_C RBTRegistry::RBTRegistry()
+: RBTManSubSession(), iDevicePckg(*reinterpret_cast<TBTNamelessDevice*>(KDummyDevicePointer))
+	{
+	LOG_FUNC
+	} 
+
+/**
+Open a Bluetooth device subsession.
+@param	aSession The BTManager session to which this subsession is to be attached.
+@return An error code depicting the outcome of the "open".
+@publishedAll
+@released
+@capability LocalServices
+*/
+EXPORT_C TInt RBTRegistry::Open(RBTRegServ& aSession)
+	{
+	LOG_FUNC
+	iSendBuffer = NULL;
+	return CreateSubSession(aSession.Session(), EBTManCreateRegistrySubSession, TIpcArgs(NULL));
+	}
+
+/** Create a constrained view of devices on the remote device table of the registry server.
+
+This is in effect a registry search facility. 
+It is needed if the user wishes find data in the registry of uncertain size.
+For example:-
+1) a list of remote devices. 
+2) full details of a remote device including its name and/or friendly name.
+Note 1: Some methods in the API (e.g. UnpairAllInView) require a view to have been created prior to their use.
+Note 2: When a view has been generated, if details of the device(s) found are needed, these should be obtained using an instance of CBTRegistryResponse.
+Note 3: A view must be closed before a new view can be created.
+
+@see UnpairAllInView
+@see DeleteAllInView
+@see CloseView
+@see NotifyViewChange
+@see TBTRegistrySearch
+@see CBTRegistryResponse
+@param	aSearch A search struct with details of devices to be contained in the result set
+@param	aStatus TRequestStatus supplied by caller
+@return systemwide error
+@publishedAll
+@released
+@capability LocalServices
+@capability ReadDeviceData  (LocalServices only if link key is not needed)
+*/
+EXPORT_C void RBTRegistry::CreateView(const TBTRegistrySearch& aSearch, TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (IsBusy())
+		{
+		LocalComplete(aStatus, KErrInUse);
+		}
+	else
+		{
+		if (SubSessionHandle())
+			{
+			SetBusy(aStatus);
+			iSearchPckg = aSearch;
+			SendReceive(EBTManRegistrySearch, TIpcArgs(&iSearchPckg, NULL, &iClientServerMsg), aStatus);
+			}
+		else
+			{
+			//Client has a bad handle therefore complete the call from here
+			LocalComplete(aStatus, KErrBadHandle);
+			}
+		}
+	}
+
+/**
+Close the subsession.  Removes all server side resources pertaining to this subsession
+@publishedAll
+@released
+*/
+EXPORT_C void RBTRegistry::Close()
+	{
+	LOG_FUNC
+	delete iSendBuffer;
+	iSendBuffer = NULL;
+	RSubSessionBase::CloseSubSession(EBTManCloseSubSession);
+	}
+	
+
+/**
+Close a previously created view on the registry.
+Allows an app to use this subsession for other view or non-view operations
+@return Systemwide error
+@post Subsession is left open for further use - eg to create another view, or perform a viewless operation
+@publishedAll
+@released
+*/
+EXPORT_C TInt RBTRegistry::CloseView()
+	{
+	LOG_FUNC
+	if (SubSessionHandle())
+		{
+		return SendReceive(EBTRegistryCloseView, TIpcArgs(NULL, NULL, NULL));	// synchronous
+		}
+	else
+		{
+		return KErrBadHandle;
+		}
+	}
+
+
+/**
+Unpair a device in the registry
+@param aAddress The device to unpair
+@param aStatus reference to client AO's TRequestStatus
+@publishedPartner
+@released
+@capability LocalServices
+@capability WriteDeviceData
+*/
+EXPORT_C void RBTRegistry::UnpairDevice(const TBTDevAddr& aAddress, TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (IsBusy())
+		{
+		LocalComplete(aStatus, KErrInUse);
+		}
+	else
+		{
+		if (SubSessionHandle())
+			{
+			SetBusy(aStatus);
+			iAddrBuf = aAddress;
+			SendReceive(EBTRegistryDeleteLinkKey, TIpcArgs(&iAddrBuf, NULL,  &iClientServerMsg), aStatus);
+			}
+		else
+			{
+			//Client has a bad handle therefore complete the call from here
+			LocalComplete(aStatus, KErrBadHandle);
+			}
+		}
+	}
+
+/**
+Unpair all the devices in the view - useful to unbond eg all devices (create a View with search All), or eg unbond all headsets
+@param aStatus reference to client AO's TRequestStatus
+@publishedPartner
+@released
+@capability LocalServices
+@capability WriteDeviceData
+*/
+EXPORT_C void RBTRegistry::UnpairAllInView(TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (SubSessionHandle())
+		{
+		iClientServerMsg().iClientStatusToCancel = &aStatus;
+		SendReceive(EBTRegistryUnpairView, TIpcArgs(NULL, NULL, &iClientServerMsg), aStatus);
+		}
+	else
+		{
+		//Client has a bad handle therefore complete the call from here
+		LocalComplete(aStatus, KErrBadHandle);
+		}
+	}
+
+
+/**
+Add device to the registry
+@leave OOM
+@param aDevice reference to CBTDevice of details of device to add
+@param aStatus reference to client AO's TRequestStatus
+@publishedAll
+@released
+@capability LocalServices
+*/
+EXPORT_C void RBTRegistry::AddDeviceL(const CBTDevice& aDevice, TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (IsBusy())
+		{
+		LocalComplete(aStatus, KErrInUse);
+		}
+	else
+		{
+		if (SubSessionHandle())
+			{
+			if (iSendBuffer)
+				{
+				delete iSendBuffer;
+				iSendBuffer = NULL;
+				}
+			// need to contiguate CBTDevice into a buffer
+			SetBusy(aStatus);
+			iSendBuffer = CBufFlat::NewL(sizeof(CBTDevice)); //granularity
+
+			RBufWriteStream stream;
+			stream.Open(*iSendBuffer);
+			CleanupClosePushL(stream);
+
+			aDevice.ExternalizeL(stream);
+			const TPtr8 ptr=iSendBuffer->Ptr(0);
+			iSendBufferPtr.Set(ptr);
+			// now we can give the buffer to BTMan
+			SendReceive(EBTRegistryAddDevice, TIpcArgs(&iSendBufferPtr, NULL,  &iClientServerMsg), aStatus);
+
+			CleanupStack::PopAndDestroy(1);	// stream
+			}
+		else
+			{
+			//Client has a bad handle therefore complete the call from here
+			LocalComplete(aStatus, KErrBadHandle);
+			}
+		}
+	}
+
+/**
+Get a *nameless* device to the registry. To retrieve a full device with names a view should be created
+@see CreateView
+@pre Clients must ensure that they do not call this method while the same operation is already outstanding on the same RBTRegistry subsession
+@param aDevice reference to TBTDevice (used as input and output). The input MUST contain the device address - this is used as the key. Once the method completes the reference will contain all other details found from the registry
+@param aStatus reference to client AO's TRequestStatus
+@publishedPartner
+@released
+@capability LocalServices
+@capability ReadDeviceData  (LocalServices only if link key is not needed) 
+*/
+EXPORT_C void RBTRegistry::GetDevice(TBTNamelessDevice& aDevice, TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (IsBusy())
+		{
+		LocalComplete(aStatus, KErrInUse);
+		}
+	else
+		{
+		if (SubSessionHandle())
+			{
+			SetBusy(aStatus);
+			TPckg<TBTNamelessDevice> temp(aDevice);
+			iDevicePckg.Set(temp);
+			SendReceive(EBTRegistryGetNamelessDevice, TIpcArgs(&iDevicePckg, NULL,  &iClientServerMsg), aStatus);
+			}
+		else
+			{
+			//Client has a bad handle therefore complete the call from here
+			LocalComplete(aStatus, KErrBadHandle);
+			}
+		}
+	}
+
+
+/**
+Modify the friendly name of a device
+@leave OOM
+@param aAddress	The address of the device of which to change the name
+@param aName		The new name (note - not an 8bit descriptor)
+@param aStatus reference to client AO's TRequestStatus
+@publishedAll
+@released
+@capability LocalServices
+*/
+EXPORT_C void RBTRegistry::ModifyFriendlyDeviceNameL(const TBTDevAddr& aAddress,
+											   		 const TDesC& aName,
+											   		 TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (IsBusy())
+		{
+		LocalComplete(aStatus, KErrInUse);
+		}
+	else
+		{
+		if (SubSessionHandle())
+			{
+			SetBusy(aStatus);
+			TBuf8<KMaxFriendlyNameLen> tempBuf;
+			tempBuf.Zero();
+			if (CnvUtfConverter::ConvertFromUnicodeToUtf8(tempBuf, aName) != KErrNone)
+				{
+				LocalComplete(aStatus, KErrBadName);
+				return;
+				}
+			
+			if (iSendBuffer)
+				{
+				delete iSendBuffer;
+				iSendBuffer = NULL;
+				}
+
+			iSendBuffer = CBufFlat::NewL(sizeof(TBuf8<KMaxFriendlyNameLen>)); //granularity
+
+			iSendBuffer->Reset();
+			iSendBuffer->InsertL(0, tempBuf);
+
+			const TPtr8 ptr=iSendBuffer->Ptr(0);
+			iSendBufferPtr.Set(ptr);
+			
+			iAddrBuf = aAddress;
+
+			SendReceive(EBTRegistryModifyFriendlyName,
+						TIpcArgs(&iAddrBuf, &iSendBufferPtr,  &iClientServerMsg), aStatus);
+			}
+		else
+			{
+			//Client has a bad handle therefore complete the call from here
+			LocalComplete(aStatus, KErrBadHandle);
+			}
+		}
+	}
+
+
+
+/**
+Modify the Bluetooth name of a device.  This is not used beyond the stack
+@param aAddress	The address of the device of which to change the name
+@param aName		The new name (note - this is an 8bit descriptor)
+@param aStatus reference to client AO's TRequestStatus
+@internalAll
+@released
+@capability LocalServices
+@capability WriteDeviceData (localServices only if friendly device name)
+*/
+EXPORT_C void RBTRegistry::ModifyBluetoothDeviceNameL(const TBTDevAddr& aAddress,
+													  const TDesC8& aName,
+													  TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (IsBusy())
+		{
+		LocalComplete(aStatus, KErrInUse);
+		}
+	else
+		{
+		if (SubSessionHandle())
+			{
+			SetBusy(aStatus);
+			
+			if (iSendBuffer)
+				{
+				delete iSendBuffer;
+				iSendBuffer = NULL;
+				}
+
+			iSendBuffer = CBufFlat::NewL(sizeof(TBuf8<KMaxBluetoothNameLen>)); //granularity
+			
+			iSendBuffer->Reset();
+			iSendBuffer->InsertL(0, aName);
+
+			const TPtr8 ptr=iSendBuffer->Ptr(0);
+			iSendBufferPtr.Set(ptr);
+			
+			iAddrBuf = aAddress;
+
+			SendReceive(EBTRegistryModifyBluetoothName,
+						TIpcArgs(&iAddrBuf, &iSendBufferPtr,  &iClientServerMsg), aStatus);
+			}
+		else
+			{
+			//Client has a bad handle therefore complete the call from here
+			LocalComplete(aStatus, KErrBadHandle);
+			}
+		}
+	}
+
+
+/**
+Update details of a device - other than its names: Not used beyond stack
+@param aDeviceDetails The new details - the device address MUST be present in aDeviceDetails is used as the key
+@param aStatus reference to client AO's TRequestStatus
+@internalTechnology
+@released
+@capability LocalServices
+@capability WriteDeviceData
+*/
+EXPORT_C void RBTRegistry::ModifyDevice(const TBTNamelessDevice& aDeviceDetails, TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (IsBusy())
+		{
+		LocalComplete(aStatus, KErrInUse);
+		}
+	else
+		{
+		if (SubSessionHandle())
+			{
+			SetBusy(aStatus);
+			TPckg<TBTNamelessDevice> temp(aDeviceDetails);
+			iDevicePckg.Set(temp);
+			SendReceive(EBTRegistryModifyNamelessDevice, TIpcArgs(&iDevicePckg, NULL,  &iClientServerMsg), aStatus);
+			}
+		else
+			{
+			//Client has a bad handle therefore complete the call from here
+			LocalComplete(aStatus, KErrBadHandle);
+			}
+		}
+	}
+
+/**
+Notifies the client when a change has been made to the registry that affects the currently open view of devices.
+@see CreateView
+@see CloseView
+@param aStatus reference to client AO's TRequestStatus
+@publishedAll
+@released
+*/
+EXPORT_C void RBTRegistry::NotifyViewChange(TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (SubSessionHandle())
+		{
+		// We don't set the session as busy because then no other commands can be sent
+		iClientServerMsg().iClientStatusToCancel = &aStatus;
+		SendReceive(EBTRegistryNotifyViewChange, TIpcArgs(NULL, NULL, &iClientServerMsg), aStatus);
+		}
+	else
+		{
+		//Client has a bad handle therefore complete the call from here
+		LocalComplete(aStatus, KErrBadHandle);
+		}
+	}
+
+/**
+@internalComponent
+*/
+void RBTRegistry::PreLoad(TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (SubSessionHandle())
+		{
+		iClientServerMsg().iClientStatusToCancel = &aStatus;
+		SendReceive(EBTManExtractRegistryDataIntoServer, TIpcArgs(NULL, NULL, &iClientServerMsg), aStatus);
+		}
+	else
+		{
+		//Client has a bad handle therefore complete the call from here
+		LocalComplete(aStatus, KErrBadHandle);
+		}
+	}
+
+
+
+/**
+@internalComponent
+**/
+void RBTRegistry::GetResults(TPtr8& aResults, TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (SubSessionHandle())
+		{
+		iClientServerMsg().iClientStatusToCancel = &aStatus;
+		SendReceive(EBTManRetrieveRegistryData, TIpcArgs(&aResults, NULL, &iClientServerMsg), aStatus);
+		}
+	else
+		{
+		//Client has a bad handle therefore complete the call from here
+		LocalComplete(aStatus, KErrBadHandle);
+		}
+	}
+
+/**
+Remove all devices in the view from the Registry
+@pre View must be created first by client
+@see CreateView
+@param aStatus a TRequestStatus passed in by the caller
+@publishedPartner
+@released
+@capability LocalServices
+@capability WriteDeviceData (Only if different process than the one that created the device)
+*/
+EXPORT_C void RBTRegistry::DeleteAllInView(TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (SubSessionHandle())
+		{
+		iClientServerMsg().iClientStatusToCancel = &aStatus;
+		SendReceive(EBTRegistryDeleteDevices, TIpcArgs(NULL, NULL, &iClientServerMsg), aStatus);
+		}
+	else
+		{
+		//Client has a bad handle therefore complete the call from here
+		LocalComplete(aStatus, KErrBadHandle);
+		}
+	}
+
+/**
+default c'tor
+@publishedAll
+@released
+*/
+EXPORT_C RBTLocalDevice::RBTLocalDevice()
+:RBTManSubSession(), iLocalDevicePckg(*reinterpret_cast<TBTLocalDevice*>(KDummyDevicePointer))
+	{
+	LOG_FUNC
+	}
+
+
+/**
+Open a local device subsession on the server, used for manipulating settings about the local device
+@param aSession A server session
+@return systemwide error
+@publishedAll
+@released
+*/
+EXPORT_C TInt RBTLocalDevice::Open(RBTRegServ& aSession)
+	{
+	LOG_FUNC
+	return CreateSubSession(aSession.Session(), EBTManCreateLocalDeviceSubSession, TIpcArgs(NULL));
+	}
+
+
+/**
+Close the subsession on the server
+@publishedAll
+@released
+*/
+EXPORT_C void RBTLocalDevice::Close()
+	{
+	LOG_FUNC
+	RSubSessionBase::CloseSubSession(EBTManCloseSubSession);
+	}
+
+
+/**
+Retrieve the local device details. Synchronous - intended mainly for Bluetooth stack use on startup
+
+@param	aLocalDeviceResult	a reference to a TBTLocalDevice to store the results from the Registry
+@return	SystemWide error
+@publishedAll
+@released
+*/
+EXPORT_C TInt RBTLocalDevice::Get(TBTLocalDevice& aLocalDeviceResult)
+	{
+	LOG_FUNC
+	if (SubSessionHandle())
+		{
+		TPckg<TBTLocalDevice> pckg(aLocalDeviceResult);
+		return SendReceive(EBTRegistryGetLocalDevice, TIpcArgs(&pckg, NULL, NULL));	// synchronous
+		}
+	else
+		{
+		//Client has a bad handle therefore complete the call from here
+		return KErrBadHandle;
+		}
+	}
+
+/**
+Update the details about the local Bluetooth device
+@param aLocalDevice New settings for local device
+@param aStatus reference Client AO's TRequestStatus
+@publishedPartner
+@released
+@capability LocalServices
+@capability WriteDeviceData
+*/
+EXPORT_C void RBTLocalDevice::Modify(const TBTLocalDevice& aLocalDevice, TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+	if (IsBusy())
+		{
+		LocalComplete(aStatus, KErrInUse);
+		}
+	else
+		{
+		if (SubSessionHandle())
+			{
+			SetBusy(aStatus);
+			TPckg<TBTLocalDevice> pckg(aLocalDevice);
+			iLocalDevicePckg.Set(pckg);
+			SendReceive(EBTRegistryUpdateLocalDevice, TIpcArgs(&iLocalDevicePckg, NULL, &iClientServerMsg), aStatus);
+			}
+		else
+			{
+			//Client has a bad handle therefore complete the call from here
+			LocalComplete(aStatus, KErrBadHandle);
+			}
+		}
+	}
+
+/**
+Synchronous overload of Modify (primarily for stack operations)
+@see RBTLocalDevice::Modify(const TBTLocalDevice& aLocalDevice, TRequestStatus& aStatus)
+@publishedPartner
+@released
+@capability LocalServices
+@capability WriteDeviceData
+*/
+EXPORT_C TInt RBTLocalDevice::Modify(const TBTLocalDevice& aLocalDevice)
+	{
+	LOG_FUNC
+	// synchronous version for stack on close-down
+	TRequestStatus status;
+	Modify(aLocalDevice, status);
+	User::WaitForRequest(status);
+	return status.Int();
+	}
+
+
+/**
+Two-phase constructor to create a helper class to retrieve a set of results (a view) from the Registry
+@leave OOM
+@pre A non-empty view on the Registry task has been created
+@param aView the Registry subsession that has had a View created on it
+@return pointer to allocated object
+@see CreateView()
+@publishedAll
+@released
+*/
+EXPORT_C CBTRegistryResponse* CBTRegistryResponse::NewL(RBTRegistry& aView)
+	{
+	LOG_STATIC_FUNC
+	return new (ELeave) CBTRegistryResponse(aView);
+	}
+
+
+/**
+Start fetching results from the Registry Server.  When the request is complete, the results can be obtained via the Results() method.
+@param aClientStatus a TRequestStatus passed in by the caller
+@publishedAll
+@released
+*/
+EXPORT_C void CBTRegistryResponse::Start(TRequestStatus& aClientStatus)
+	{
+	LOG_FUNC
+	// we do late construction on the heap buffer
+	__ASSERT_DEBUG(!IsActive(), User::Panic(KBTManClientPanic, EBTManClientResultRetrieveAlreadyActive));
+
+	iClientStatus = &aClientStatus;
+	*iClientStatus = KRequestPending;
+	CActiveScheduler::Add(this);
+	DoGet();
+	}
+
+/** Get Results previously fetched from the Registry Server.
+ 
+@pre The method Start needs to have been called, and notification of its completion received.
+@return reference to the array of results
+@publishedAll
+@released
+*/
+EXPORT_C RBTDeviceArray& CBTRegistryResponse::Results()
+	{
+	LOG_FUNC
+	return iArray;
+	}
+
+CBTRegistryResponse::CBTRegistryResponse(RBTRegistry& aView)
+: CActive(EPriorityStandard), iView(aView), iResponsePtr(NULL,0)
+	{
+	LOG_FUNC
+	}
+
+/**
+Destructor
+*/
+EXPORT_C CBTRegistryResponse::~CBTRegistryResponse()
+	{
+	LOG_FUNC
+	Cancel();
+
+	iArray.ResetAndDestroy();
+	delete iResponseBuf;
+	}
+
+void CBTRegistryResponse::DoGet()
+	{
+	LOG_FUNC
+// create RPointerArray to point to n CBTDevices
+// ask server async size of result set - this causes BTMan to extract from DBMS and return size
+// we then allocate and in 2nd phase get the stuff from the server (could be synchronous
+// we could wrap all this up in a helper object for client to use: CBTRegistryResponder
+
+	iArray.ResetAndDestroy();
+	iState = EGettingSize;
+	// Get the size of the entry
+	iView.PreLoad(iStatus);
+	SetActive();
+	}
+
+void CBTRegistryResponse::DoCancel()
+	{
+	LOG_FUNC
+	//cancel the server
+	iView.CancelRequest(iStatus);
+	//notify our user
+	User::RequestComplete(iClientStatus, KErrCancel);
+	}
+
+void CBTRegistryResponse::RunL()
+	{
+	LOG_FUNC
+	switch (iState)
+		{
+		case EGettingSize:
+			{
+			// get the results
+			if (iStatus.Int() >= KErrNone)
+				{
+				// we have a byte count of the response size
+				iResponseBuf = HBufC8::NewMaxL(iStatus.Int());
+				iResponsePtr.Set(iResponseBuf->Des());
+				iView.GetResults(iResponsePtr, iStatus);
+				iState = EGettingResults;
+				SetActive();
+				}
+			else
+				{
+				User::Leave(iStatus.Int());
+				}
+			}
+			break;
+		case EGettingResults:
+			{
+			if (iStatus.Int() >= KErrNone)
+				{
+				// got n CBTDevices to return
+				TInt c = iStatus.Int();
+				RDesReadStream stream(iResponsePtr);
+				CleanupClosePushL(stream);
+				while (c-->0)
+					{
+					CBTDevice* device = CBTDevice::NewLC();
+					device->InternalizeL(stream);
+					// place it into the result array
+					User::LeaveIfError(iArray.Append(device));
+					CleanupStack::Pop();			//device - don't destroy as 'owned' by array
+					}
+				CleanupStack::PopAndDestroy();	//stream
+				// free up memory:
+				delete iResponseBuf;
+				iResponseBuf = NULL;
+
+				User::RequestComplete(iClientStatus, KErrNone);
+				} // if
+			else
+				{
+				User::Leave(iStatus.Int());
+				}
+			break;
+			} // case
+		default:
+			User::Panic(KBTManClientPanic, EBTManClientBadResultRetrieveState);
+		}
+
+	}
+
+TInt CBTRegistryResponse::RunError(TInt aError)
+	{
+	LOG_FUNC
+	//complete request if its pending
+	if (*iClientStatus == KRequestPending)
+		{
+		User::RequestComplete(iClientStatus, aError);
+		}
+	return KErrNone;
+	}
+
+/**
+Default constructor
+@publishedAll
+@released
+*/
+EXPORT_C TBTRegistrySearch::TBTRegistrySearch()
+	{
+	LOG_FUNC
+	Reset();
+	}
+
+/**
+Resets the search criteria
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::Reset()
+	{
+	LOG_FUNC
+	iSearchMask =0;
+	}
+
+/**	
+Copy Constructor
+@publishedAll
+@released
+*/
+EXPORT_C TBTRegistrySearch::TBTRegistrySearch(const TBTRegistrySearch& aSearch)
+	{
+	LOG_FUNC
+	iSearchMask = aSearch.iSearchMask;
+	iDeviceClass = aSearch.iDeviceClass;
+	iDeviceAddress = aSearch.iDeviceAddress;
+	iLastSeen = aSearch.iLastSeen;
+	iLastUsed = aSearch.iLastUsed;
+	iCurrentProcessSID = aSearch.iCurrentProcessSID;
+	iBluetoothName.Set(aSearch.iBluetoothName);
+	iFriendlyName.Set(aSearch.iFriendlyName);
+	}
+
+
+/**
+Add search criterion for bonded devices
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindBonded()
+	{
+	LOG_FUNC
+	iSearchMask |= EBonded;
+	}
+
+
+/**
+Add search criterion for trusted devices
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindTrusted()
+	{
+	LOG_FUNC
+	iSearchMask |= ETrusted;
+	}
+
+/**
+Add search criterion to search for specific CoD
+@param aClass The CoD to search
+@see TBTDeviceClass
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindCoD(const TBTDeviceClass& aClass)
+	{
+	LOG_FUNC
+	iDeviceClass = aClass;
+	iSearchMask |= ECoD;
+	}
+
+
+/**
+Add search criterion to search for certain classes of device
+@param aClass the device class to search for
+@param aPref describes the type of device search to perform
+@see TBTDeviceClass
+@see enum TBTDeviceClassSearch
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindCoD(const TBTDeviceClass& aClass, TBTDeviceClassSearch aPref)
+	{
+	LOG_FUNC
+	iDeviceClass = aClass;
+	iSearchMask |= (aPref & EMajorDevice ? ECoDMajorDev : 0);
+	iSearchMask |= (aPref & EMinorDevice ? ECoDMinorDev : 0);
+	}
+
+/**
+Add search criterion to search for given device
+@param	aAddress address of device to search for
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindAddress(const TBTDevAddr& aAddress)
+	{
+	LOG_FUNC
+	iDeviceAddress = aAddress;
+	iSearchMask |= EAddress;
+	}
+
+
+/**
+Add search criterion to search for devices seen since given date
+NOTE not currently implemented
+@param	aLastSeen date from which to find devices
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindSinceSeen(const TTime& aLastSeen)
+	{
+	LOG_FUNC
+	iLastSeen = aLastSeen;
+	iSearchMask |= ELastSeen;
+	}
+
+/**
+Add search criterion to search for devices used since given date
+@param	aLastUsed date from which to find devices
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindSinceUsed(const TTime& aLastUsed)
+	{
+	LOG_FUNC
+	iLastUsed = aLastUsed;
+	iSearchMask |= ELastUsed;
+	}
+
+
+
+/**
+Add search criterion to search for devices with some Bluetooth device name
+@param aName device name to search for
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindBluetoothName(const TDesC8& aName)
+/**
+	Add search criteria of specific Bluetooth name
+*/
+	{
+	LOG_FUNC
+	iBluetoothName.Set(aName);
+	iSearchMask |= EBTName;
+	}
+
+/**
+Add search criterion to search for devices with some friendly name
+@param aName device name to search for
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindFriendlyName(const TDesC& aName)
+	{
+	LOG_FUNC
+	iFriendlyName.Set(aName);
+	iSearchMask |= EFriendlyName;
+	}
+
+/**
+Add search criterion to search for finding all devices
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindAll()
+	{
+	LOG_FUNC
+	iSearchMask |= EAll;
+	}
+
+/**
+Add search criterion to search for devices added by the current process
+@publishedAll
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindCurrentProcessOwned()
+	{
+	LOG_FUNC
+	iCurrentProcessSID = User::Identity();
+	iSearchMask |= EProcess;
+	}
+
+/**
+Add search criterion to search for devices with a particular UI Cookie value.
+@param aUiCookie The particular UI cookie value to search on.
+@publishedPartner
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindUiCookie(TUint32 aUiCookie)
+	{
+	LOG_FUNC
+	static const TUint32 KAllBitsMasked = 0xffffffff;
+	FindUiCookie(aUiCookie, KAllBitsMasked);
+	}
+
+/**
+Add search criterion to search for devices with a particular UI Cookie value.
+@param aUiCookie The particular UI cookie value to search on.
+@param aUiCookieMask The mask to indicate which bits of the cookie value are to be searched on.
+@publishedPartner
+@released
+*/
+EXPORT_C void TBTRegistrySearch::FindUiCookie(TUint32 aUiCookie, TUint32 aUiCookieMask)
+	{
+	LOG_FUNC
+	iUiCookie = aUiCookie;
+	iUiCookieMask = aUiCookieMask;
+	iSearchMask |= EUiCookie;
+	}
+
+/**
+Assignment operator
+@param aSearch the search pattern to which to assign this
+@publishedAll
+@released
+*/
+EXPORT_C TBTRegistrySearch& TBTRegistrySearch::operator=(const TBTRegistrySearch& aSearch)
+	{
+	LOG_FUNC
+	if (this != &aSearch)
+		{
+		iSearchMask = aSearch.iSearchMask;
+		iDeviceClass = aSearch.iDeviceClass;
+		iDeviceAddress = aSearch.iDeviceAddress;
+		iLastSeen = aSearch.iLastSeen;
+		iLastUsed = aSearch.iLastUsed;
+		iCurrentProcessSID = aSearch.iCurrentProcessSID;
+		iUiCookie = aSearch.iUiCookie;
+		iUiCookieMask = aSearch.iUiCookieMask;
+		iBluetoothName.Set(aSearch.iBluetoothName);
+		iFriendlyName.Set(aSearch.iFriendlyName);
+		}
+	return *this;
+	}
+
+