bluetoothmgmt/btmgr/BTManServer/BTRegistryDB.cpp
changeset 0 29b1cd4cb562
child 8 2b6718f05bdb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothmgmt/btmgr/BTManServer/BTRegistryDB.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1642 @@
+// 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:
+// This does the main work on behalf of the subsessions of liasing with DBMS
+// 
+//
+
+#include "BTRegistryDB.h"
+#include "btmanserverutil.h"
+#include <utf.h>
+#include <bluetooth/logger.h>
+#include <bafl/sysutil.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_BT_REGISTRY);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("btregdb");
+#endif
+
+
+void Panic(TBTRegistryDBPanic aPanic)
+	{
+	LOG_STATIC_FUNC
+	_LIT(KRegistryDBPanicName, "BT RegistryDB Panic");
+	User::Panic(KRegistryDBPanicName, aPanic);
+	}
+//
+
+CBTRegistry::CBTRegistry()
+	{
+	LOG_FUNC
+	}
+
+CBTRegistry::~CBTRegistry()
+	{
+	LOG_FUNC
+	iDB.Close();
+	iDBMSServer.Close();
+	}
+
+CBTRegistry* CBTRegistry::NewL()
+	{
+	LOG_STATIC_FUNC
+	CBTRegistry* self = new (ELeave) CBTRegistry;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+#ifdef _DEBUG
+	CleanupStack::Check(self);
+#endif
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CBTRegistry::ConstructL()
+	{
+	LOG_FUNC
+	// we use a DBMS Server session as multiple clients may
+	// be updating their views concurrently.  Without this
+	// DBMS would (rightly) panic a rowset already in update
+	User::LeaveIfError(iDBMSServer.Connect());
+	OpenRegistryL();
+	}
+
+void CBTRegistry::OpenRegistryL()
+/**
+	Open the Registry DB.
+	If it doesn't exist, attempt to create the necessary path,file and DB
+**/
+	{
+	LOG_FUNC
+	const static TInt KMaxTries=4;
+	TInt err;
+	TInt loopCount=0;
+	
+
+	//	In secure EKA2 DBMS land, registry DB is created in DBMS data cage
+	do
+		{
+		err=iDB.Open(iDBMSServer, TBTRegistryDatabaseSecure()(), KBTRegistryDatabaseSecurePolicy());
+			
+		if(err == KErrNotFound)
+			{
+			CreateRegistryL();
+			}
+		else if (err != KErrNone)
+			{
+			// If we get here the BT registry file must be corrupt. 
+			// Delete the file and go round the while loop once more.
+			DeleteCorruptRegistryL();
+			}
+		else
+			{
+			TRAP(err,ValidateMetaTableL()); // make sure it's ok version etc.
+			if(err==KErrNone)
+				{
+				TRAP(err,ValidatePersistTableL()); // make sure it's been properly written to
+				}
+			if (err!=KErrNone)
+				{
+				// Either the Meta Table validate failed or the Persist Table validate failed.
+				// Delete the file and go round the while loop once more.
+				DeleteCorruptRegistryL();
+				}
+			}	
+		loopCount++;
+		} while (err!=KErrNone && loopCount<KMaxTries);
+
+	if(err != KErrNone)
+		{
+		User::Leave(KErrAbort);		// give up gracefully
+		}
+
+	// Purge any SSP debug link keys left over from a previous SSP debug session
+	PurgeDebugLinkKeysL();
+
+	(void)iDB.Compact();	// compact now
+	// ready!
+	}
+
+
+
+RDbTable* CBTRegistry::OpenTableL(const TDesC& aTable)
+/**
+	Find tables of a given name
+	@param	aTable	Name of table to open
+	@return table and ownership
+**/
+	{
+	LOG_FUNC
+	RDbTable* table = new (ELeave) RDbTable;
+	CleanupCloseDeletePushL(table);
+
+	TInt err;
+
+	err = table->Open(iDB, aTable);
+	User::LeaveIfError(err);
+
+	CleanupStack::Pop(); // table
+
+	return table;
+	}
+
+RDbTable* CBTRegistry::OpenPersistTableL()
+/**
+	Find the persist table (local device settings)
+	and return it and ownership
+
+	@return ownership of table
+**/
+	{
+	LOG_FUNC
+	return OpenTableL(KPersistTable);
+	}
+
+RDbTable* CBTRegistry::OpenDeviceTableL()
+/**
+	Find the remote device table
+	@return table and ownership
+**/
+	{
+	LOG_FUNC
+	return OpenTableL(KDeviceTable);
+	}
+
+RDbTable* CBTRegistry::OpenCSYTableL()
+/**
+	Find the CSY table
+	@return table and ownership
+**/
+	{
+	LOG_FUNC
+	return OpenTableL(KCSYTable);
+	}
+
+void CBTRegistry::ValidateMetaTableL()
+/**
+	Go to Meta table and check version numbers etc
+**/
+	{
+	LOG_FUNC
+	RDbTable* table = OpenTableL(KMetaTable);
+	CleanupCloseDeletePushL(table);
+
+	// get the processSID
+	TBool success = table->FirstL();
+	if (!success)
+		{
+		LOG(_L("BT Registry DB Meta Table CORRUPT!"));
+		User::Leave(KErrEof);
+		}
+
+	table->GetL();
+	
+
+	//put version checking in when we think about backup server
+	TUint major = table->ColUint32(ColumnNoL(KMetaColName_VersionMajor, *table));
+	TUint minor = table->ColUint32(ColumnNoL(KMetaColName_VersionMinor, *table));
+	LOG(_L("CBTRegistry opened registry DB Meta Table"));
+	LOG1(_L("\tMajorVersion: %d"), major); 
+	LOG1(_L("\tMinorVersion: %d"), minor); 
+
+	if(KRegistryDBVersionMajor != major || 
+			KRegistryDBVersionMinor != minor)
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	CleanupStack::PopAndDestroy(table);
+	}
+
+void CBTRegistry::ValidatePersistTableL()
+/**
+	Go to Persist table and check local device values
+**/
+	{
+	LOG_FUNC
+	RDbTable* table = OpenTableL(KPersistTable);
+	CleanupCloseDeletePushL(table);
+
+	// get the processSID
+	TBool success = table->FirstL();
+	if (!success)
+		{
+		LOG(_L("BT Registry DB Local Device Table (Persist Table) CORRUPT!"));
+		User::Leave(KErrEof);
+		}
+		
+	table->GetL();
+	
+#ifdef _DEBUG
+	// check the Local device configuration (aka Stack Persistance data)
+	TPtrC8 addrBuf(table->ColDes8(ColumnNoL(KColName_DeviceAddress, *table)));
+	TUint32 CoD = table->ColUint32(ColumnNoL(KPersistColName_CoD, *table));
+	TUint8 scanEnable = table->ColUint8(ColumnNoL(KPersistColName_ScanEnable, *table));
+	TPtrC8 name = table->ColDes8(ColumnNoL(KPersistColName_LocalName, *table));
+	TUint8 powerSettings = table->ColUint8(ColumnNoL(KPersistColName_PowerSettings, *table));
+	TUint8 limDisc = table->ColUint8(ColumnNoL(KPersistColName_LimitedDiscoverable, *table));
+	TBool afhChannelAssessmentMode = table->ColUint8(ColumnNoL(KPersistColName_AFHChannelAssessmentMode, *table));
+	TBool acceptPairedOnlyMode = table->ColUint8(ColumnNoL(KPersistColName_AcceptPairedOnlyMode, *table));
+	LOG(_L("CBTRegistry opened registry DB Persist Table"));
+	LOG6(_L("\tDevice Address (zero is acceptable): %02x%02x %02x%02x%02x%02x"),
+			addrBuf[0],
+			addrBuf[1],
+			addrBuf[2],
+			addrBuf[3],
+			addrBuf[4],
+			addrBuf[5]
+			);
+	LOG1(_L("\tCoD: 0x%02x"),CoD);
+	LOG1(_L("\tScan Enable: 0x%02x"),scanEnable);
+	LOG1(_L8("\tLocal Name: \"%S\""),&name); //name is an 8 bit string
+	LOG1(_L("\tPower Settings: 0x%02x"),powerSettings);
+	LOG1(_L("\tLimited Discoverable: 0x%02x"),limDisc);
+	LOG1(_L("\tAFHChannelAssessmentMode: %d"),afhChannelAssessmentMode);
+	LOG1(_L("\tAcceptPairedOnlyMode: %d"),acceptPairedOnlyMode);
+#endif
+
+	CleanupStack::PopAndDestroy(table);
+	}
+
+void CBTRegistry::CreateRegistryL()
+/**
+	Creates the Database and Tables we need
+**/
+	{
+	LOG_FUNC
+	//	In secure DBMS land, the BT Manager DB is created in DBMS's data cage.
+	TInt err = iDB.Create(iDBMSServer, TBTRegistryDatabaseSecure()(), KBTRegistryDatabaseSecurePolicy()); // This leaves iDB in an open state.
+
+
+	User::LeaveIfError(err);
+	
+	SetupDefaultRegistryL();
+	
+	// close the database
+	iDB.Close();	
+	LOG(_L("BT Registry DB Created successfully"));
+	}
+
+void CBTRegistry::PurgeDebugLinkKeysL()
+/**
+ 	Remove (if present) any SSP debug link keys that may have been created by a previous SSP debug session.
+**/
+	{
+	LOG_FUNC
+	RBTDbQuery query;
+	CleanupClosePushL(query);
+	query.MatchLinkKeyTypeL(ELinkKeyDebug);
+
+	//We dont use the bookmark here, so employ a dummy bookmark.
+	TDbBookmark dummy;
+	RDbView* view = OpenViewL(query, dummy);
+	CleanupCloseDeletePushL(view);
+
+	if (!view->IsEmptyL())
+		{
+		// Debug link keys found in registry, unpair these.
+		UnpairViewL(*view);
+		}
+	
+	CleanupStack::PopAndDestroy(2, &query);	// view and query
+	}
+
+
+void CBTRegistry::CreatePersistTableL()
+/**
+	Create the table with all that is necessary for storing local device details
+**/
+	{
+	LOG_FUNC
+	CDbColSet* theColumns = CDbColSet::NewLC();
+
+	// add in the columns for the Local device configuration (aka Stack Persistance data)
+	theColumns->AddL(TDbCol(KColName_DeviceAddress,						EDbColText8));	// Binary not allowed in SQL
+	theColumns->AddL(TDbCol(KPersistColName_CoD,						EDbColUint32));
+	theColumns->AddL(TDbCol(KPersistColName_ScanEnable,					EDbColUint8));
+	// specify the maximum local name length to be KMaxBluetoothNameLen
+	theColumns->AddL(TDbCol(KPersistColName_LocalName,					EDbColText8, KMaxBluetoothNameLen));
+	theColumns->AddL(TDbCol(KPersistColName_PowerSettings,				EDbColUint8));
+	theColumns->AddL(TDbCol(KPersistColName_LimitedDiscoverable,		EDbColBit));
+	theColumns->AddL(TDbCol(KPersistColName_AFHChannelAssessmentMode,	EDbColBit));
+	theColumns->AddL(TDbCol(KPersistColName_AcceptPairedOnlyMode,		EDbColBit));
+	User::LeaveIfError(iDB.CreateTable(KPersistTable, *theColumns));
+
+	CleanupStack::PopAndDestroy(theColumns);
+	}
+
+void CBTRegistry::CreateDeviceTableL()
+/**
+	Create the table with all that is necessary to store details about remote devices
+	
+	To provide better CoD searching than the underlying SQL supports
+	this table uses >1 column for device class of remote device
+	
+	This also allows for future versions of the CoD field in the BT Spec
+**/
+	{
+	LOG_FUNC
+	CDbColSet* theColumns = CDbColSet::NewLC();
+
+	theColumns->AddL(TDbCol(KColName_ProcessSID,			EDbColUint32));	//SID of process adding record
+	theColumns->AddL(TDbCol(KColName_DeviceAddress,			EDbColText8));	// Binary not allowed in SQL
+	theColumns->AddL(TDbCol(KDeviceColName_CoD_MajorDev,	EDbColUint32));
+	theColumns->AddL(TDbCol(KDeviceColName_CoD_MinorDev,	EDbColUint32));
+	theColumns->AddL(TDbCol(KDeviceColName_CoD_Service,		EDbColUint32));
+	theColumns->AddL(TDbCol(KDeviceColName_BluetoothName,	EDbColText8, KMaxBluetoothNameLen));	// keep UTF8
+	theColumns->AddL(TDbCol(KDeviceColName_FriendlyName,	EDbColText16, KMaxBluetoothNameLen));	// possible UNICODE?
+	theColumns->AddL(TDbCol(KDeviceColName_LinkKey,			EDbColText8));	// Binary not allowed in SQL
+	theColumns->AddL(TDbCol(KDeviceColName_PassKey,			EDbColText8));	// Binary not allowed in SQL	
+	theColumns->AddL(TDbCol(KDeviceColName_PageScanMode,	EDbColUint8));
+	theColumns->AddL(TDbCol(KDeviceColName_PageScanRepMode,	EDbColUint8));
+	theColumns->AddL(TDbCol(KDeviceColName_PageScanPeriodMode,	EDbColUint8));
+	theColumns->AddL(TDbCol(KDeviceColName_LastSeen,		EDbColInt64));
+	theColumns->AddL(TDbCol(KDeviceColName_LastUsed,		EDbColInt64));
+	theColumns->AddL(TDbCol(KDeviceColName_GlobalSecSecurity,	EDbColUint8));
+	theColumns->AddL(TDbCol(KDeviceColName_GlobalSecPasskeyLen,	EDbColUint32));
+	theColumns->AddL(TDbCol(KDeviceColName_LinkKeyType,		EDbColUint8));
+	theColumns->AddL(TDbCol(KDeviceColName_UiCookie,		EDbColText8)); // Can only simulate "bit-masked" searching in SQL if stored as text
+
+	User::LeaveIfError(iDB.CreateTable(KDeviceTable, *theColumns));
+
+	CleanupStack::PopAndDestroy(theColumns);
+	}
+
+void CBTRegistry::CreateMetaTableL()
+/**
+	Stores useful information about the database
+	Version - useful for attempting to see if we can restore an old db
+	Originating process
+**/
+	{
+	LOG_FUNC
+	CDbColSet* theColumns = CDbColSet::NewLC();
+
+	theColumns->AddL(TDbCol(KMetaColName_VersionMajor,	EDbColUint32));
+	theColumns->AddL(TDbCol(KMetaColName_VersionMinor,	EDbColUint32));
+	theColumns->AddL(TDbCol(KColName_ProcessSID,		EDbColUint32));	//SID of process adding record
+
+	User::LeaveIfError(iDB.CreateTable(KMetaTable, *theColumns));
+
+	CleanupStack::PopAndDestroy(theColumns);
+
+	SetMetaDataL();
+	}
+
+void CBTRegistry::CreateCSYTableL()
+/**
+	Create the table with all that is necessary to store details about virtual serial ports
+**/
+	{
+	LOG_FUNC
+	CDbColSet* theColumns = CDbColSet::NewLC();
+
+	theColumns->AddL(TDbCol(KColName_ProcessSID,		EDbColUint32));	//SID of process adding record
+	theColumns->AddL(TDbCol(KBTCOMMColName_Port,		EDbColUint32));	
+	theColumns->AddL(TDbCol(KColName_DeviceAddress,		EDbColText8));	//Device address
+	theColumns->AddL(TDbCol(KBTCOMMColName_ServiceUUID,	EDbColText8));	//SDP UUID - 16bytes
+	theColumns->AddL(TDbCol(KBTCOMMColName_Security,	EDbColUint8));	//Security
+	theColumns->AddL(TDbCol(KBTCOMMColName_ServiceName,	EDbColText));	//ServiceName
+
+	User::LeaveIfError(iDB.CreateTable(KCSYTable, *theColumns));
+
+	CleanupStack::PopAndDestroy(theColumns);
+	}
+
+
+TDbColNo CBTRegistry::ColumnNoL(const TDesC& aColName, const RDbRowSet& aRowSet)
+/**
+Looks up column names and returns the column number
+
+	@param	aColName the name of the column
+	@param	aRowSet	the rowset in which to find the column
+	@return the column number with aColName
+**/
+	{
+	LOG_FUNC
+	// get the schema from the table - we own this
+#ifdef _DEBUG
+	CDbColSet* schema = NULL;
+	TRAPD(err, schema = aRowSet.ColSetL());
+	if(err == KErrNoMemory)
+		{
+		User::Leave(err);
+		}
+	//This __ASSERT_DEBUG is here to catch any 'Leaves'
+	//in RDbRowSet::ColSetL other than that\those using
+	//KErrNoMemory.
+	__ASSERT_DEBUG(err == KErrNone, Panic(EBTManColSetError));
+#else
+	CDbColSet* schema = aRowSet.ColSetL(); // no need to push onto cleanup
+#endif
+	// get the column number, based on name
+	TDbColNo column = schema->ColNo(aColName);
+	delete schema;
+	return column;
+	}
+
+
+
+TBool CBTRegistry::DevicePresentL(const TBTDevAddr& aAddress)
+/**
+	Checks to see if a device is present in the Registry
+	@param	aAddress	The key to finding a device
+	@return True if Device is present, false if not
+**/
+	{
+	LOG_FUNC
+	// form an SQL query for the device with address aAddress
+	RBTDbQuery query;
+	CleanupClosePushL(query);
+	query.FindDeviceL(aAddress);
+
+	TDbBookmark dummy;
+	RDbView* view = NULL;
+
+	// open the view with that SQL query
+	view = OpenViewL(query, dummy);	// uses a private view...
+	CleanupCloseDeletePushL(view);
+
+	TInt count = view->CountL();
+	
+	__ASSERT_ALWAYS(count <= 1, Panic(ETooManyRemoteDeviceEntries));
+
+	CleanupStack::PopAndDestroy(2, &query); // view and query
+	return (count!=0);
+	}
+
+void CBTRegistry::CreateDeviceL(const CBTDevice& aDetails, TBool aStoreUiCookie, const TSecureId& aClientSID)
+/**
+	Add a new record into the DB
+
+	@param	aDetails	The new device details to add
+	@param	aClientUid	The ID of the process adding the new record
+	@leave	KErrCorrupt if device to add is not valid
+	@leave	KErrAlreadyExists if device to add is already present
+**/
+	{
+	LOG_FUNC
+	if (!aDetails.IsValidBDAddr())
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	if (DevicePresentL(aDetails.BDAddr()))
+		{
+		User::Leave(KErrAlreadyExists);
+		}
+
+	RDbTable* table = OpenDeviceTableL();
+	CleanupCloseDeletePushL(table);
+
+	table->InsertL();
+	table->SetColL(ColumnNoL(KColName_DeviceAddress, *table), aDetails.BDAddr().Des());
+
+	table->SetColL(ColumnNoL(KColName_ProcessSID, *table), aClientSID);
+
+	// got some initial details; stick them in now...
+	SetDeviceL(*table, aDetails, !aStoreUiCookie);	// does the remaining columns
+	CleanupStack::PopAndDestroy(table);
+	}
+
+void CBTRegistry::UnpairL(RDbRowSet& aRowSet)
+/**
+	Unpairs a set of devices
+
+	@pre	A rowset constraining the view to a single device
+	@param	aRowSet	The set of records to unpair
+	@see    DBMS for leave codes
+**/
+	{
+	LOG_FUNC
+	aRowSet.UpdateL();
+	aRowSet.SetColNullL(ColumnNoL(KDeviceColName_LinkKey, aRowSet));
+	aRowSet.SetColNullL(ColumnNoL(KDeviceColName_PassKey, aRowSet));
+	aRowSet.SetColNullL(ColumnNoL(KDeviceColName_LinkKeyType, aRowSet));
+	
+	CleanPutL(aRowSet);
+	}
+
+void CBTRegistry::UnpairViewL(RDbRowSet& aRowSet)
+/**
+	Unpairs all sets of devices in the supplied rowset
+
+	@pre	A rowset constraining the view 
+	@param	aRowSet	The set of records to unpair
+	@see    DBMS for leave codes
+**/
+	{
+	LOG_FUNC
+	aRowSet.FirstL();
+	TInt c = aRowSet.CountL();
+	for (TInt i=0; i<c; i++)
+		{
+		UnpairL(aRowSet);
+		aRowSet.NextL();
+		}
+	}
+
+void CBTRegistry::UpdateDeviceL(RDbRowSet& aRowSet, const CBTDevice& aDetails)
+/**
+	Given a rowset (from a previous find) and
+	mark the rowset for update, and make the changes
+
+	@param	aRowSet	The set of rows to update - typically one row...
+**/
+	{
+	LOG_FUNC
+	aRowSet.UpdateL();
+	SetDeviceL(aRowSet, aDetails);
+	}
+
+void CBTRegistry::UpdateNameL(const TBTDevAddr& aAddress,
+							  const TDesC8& aName,
+							  TBTManServerRequest aRequest)
+/**
+	Update the name of a device - either friendly or Bluetooth name
+
+	@param	aAddress    The device to update
+	@param  aName	    The new name
+	@param  aRequest	Determines the type of name to change
+
+	Could change this so subsession opens the rowset and just gives that to this
+**/
+	{
+	LOG_FUNC
+	// Find the row
+	RBTDbQuery deviceQuery;
+	CleanupClosePushL(deviceQuery);
+	deviceQuery.FindDeviceL(aAddress);
+
+	TDbBookmark dummy;
+
+	RDbView* view = OpenViewL(deviceQuery, dummy);
+	CleanupCloseDeletePushL(view);
+
+	view->UpdateL();
+
+	switch (aRequest)
+		{
+	case EBTRegistryModifyFriendlyName:
+		{
+		TBuf<KMaxFriendlyNameLen> temp;
+		User::LeaveIfError(CnvUtfConverter::ConvertToUnicodeFromUtf8(temp,aName));
+		view->SetColL(ColumnNoL(KDeviceColName_FriendlyName, *view), temp);
+		break;
+		}
+
+	case EBTRegistryModifyBluetoothName:
+		{
+		view->SetColL(ColumnNoL(KDeviceColName_BluetoothName, *view), aName);
+		break;
+		}
+	default:
+		Panic(EBadNameToUpdate);
+		}
+	CleanPutL(*view);
+	CleanupStack::PopAndDestroy(2, &deviceQuery);	// view and deviceQuery
+	}
+
+void CBTRegistry::UpdateLocalDeviceL(const TBTLocalDevice& aLocalDevice)
+/**
+	@param	aLocalDevice The new settings
+**/
+	{
+	LOG_FUNC
+	// obliterate what's there
+	RDbTable* table = OpenPersistTableL();
+	CleanupCloseDeletePushL(table);	
+
+	TInt count = table->CountL();
+	__ASSERT_DEBUG(count <=1, Panic(ETooManyLocalDeviceEntries));
+	if (!count)
+		{
+		// we need to insert the one and only row as this is a fresh table
+		table->InsertL();
+		}
+	else
+		{
+		// go to the only row
+		TBool success = table->FirstL();
+		if (!success)
+			{
+			LOG(_L("BT Registry DB Local Device Table (Persist Table) CORRUPT!"));
+			User::Leave(KErrEof);
+			}
+
+		table->UpdateL();
+		}
+
+	if (aLocalDevice.IsValidAddress())
+		table->SetColL(ColumnNoL(KColName_DeviceAddress, *table),
+					aLocalDevice.Address().Des());
+
+	if (aLocalDevice.IsValidDeviceClass())
+		table->SetColL(ColumnNoL(KPersistColName_CoD, *table),
+					static_cast<TUint>(aLocalDevice.DeviceClass()));
+
+	if (aLocalDevice.IsValidDeviceName())
+		table->SetColL(ColumnNoL(KPersistColName_LocalName, *table),
+					aLocalDevice.DeviceName());
+
+	if (aLocalDevice.IsValidScanEnable())
+		table->SetColL(ColumnNoL(KPersistColName_ScanEnable, *table),
+					static_cast<TUint>(aLocalDevice.ScanEnable()));
+
+	if (aLocalDevice.IsValidPowerSetting())
+		table->SetColL(ColumnNoL(KPersistColName_PowerSettings, *table),
+					static_cast<TUint>(aLocalDevice.PowerSetting()));
+
+	if (aLocalDevice.IsValidAFHChannelAssessmentMode())
+		table->SetColL(ColumnNoL(KPersistColName_AFHChannelAssessmentMode, *table),
+					static_cast<TBool>(aLocalDevice.AFHChannelAssessmentMode()));
+
+	if (aLocalDevice.IsValidLimitedDiscoverable())
+		table->SetColL(ColumnNoL(KPersistColName_LimitedDiscoverable, *table),
+					static_cast<TBool>(aLocalDevice.LimitedDiscoverable()));
+
+	if (aLocalDevice.IsValidAcceptPairedOnlyMode())
+		table->SetColL(ColumnNoL(KPersistColName_AcceptPairedOnlyMode, *table),
+					static_cast<TBool>(aLocalDevice.AcceptPairedOnlyMode()));
+
+	CleanPutL(*table);
+	CleanupStack::PopAndDestroy(table);
+	}
+
+void CBTRegistry::SetMetaDataL()
+/**
+	Set the values for the MetaData Table
+**/
+	{
+	LOG_FUNC
+	// put defaults in
+	RDbTable* table = OpenTableL(KMetaTable);
+	CleanupCloseDeletePushL(table);
+	
+#ifdef _DEBUG
+	TInt c=0;
+	TRAP_IGNORE(c=table->CountL());
+	__ASSERT_DEBUG(c==0, Panic(EMetaTableBroken));
+#endif
+
+	table->InsertL();
+
+	table->SetColL(ColumnNoL(KColName_ProcessSID, *table), RProcess().SecureId());
+
+	table->SetColL(ColumnNoL(KMetaColName_VersionMajor, *table), KRegistryDBVersionMajor);
+	table->SetColL(ColumnNoL(KMetaColName_VersionMinor, *table), KRegistryDBVersionMinor);
+
+	CleanPutL(*table);
+	CleanupStack::PopAndDestroy(table);
+	}
+
+void CBTRegistry::SetDeviceL(RDbRowSet& aRowSet, const CBTDevice& aDetails, TBool aIgnoreUiCookie)
+/**
+	Set the values for the device record if the Details are valid
+
+	@param	aRowSet		The rowset to adjust...typically one row
+	@param 	aDetails	The new details
+**/
+	{
+	LOG_FUNC
+	if (aDetails.AsNamelessDevice().IsValidPageScanMode())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_PageScanMode, aRowSet), static_cast<TUint>(aDetails.AsNamelessDevice().PageScanMode()));
+		}
+	if (aDetails.AsNamelessDevice().IsValidPageScanRepMode())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_PageScanRepMode, aRowSet), static_cast<TUint>(aDetails.AsNamelessDevice().PageScanRepMode()));
+		}
+	if (aDetails.AsNamelessDevice().IsValidPageScanPeriodMode())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_PageScanPeriodMode, aRowSet), static_cast<TUint>(aDetails.AsNamelessDevice().PageScanPeriodMode()));
+		}
+	if (aDetails.IsValidDeviceClass())
+		{
+		const TBTDeviceClass& cod = aDetails.DeviceClass();
+		
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_CoD_MajorDev, aRowSet), static_cast<TUint>(cod.MajorDeviceClass()));
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_CoD_MinorDev, aRowSet), static_cast<TUint>(cod.MinorDeviceClass()));
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_CoD_Service, aRowSet), static_cast<TUint>(cod.MajorServiceClass()));
+		}
+	if (aDetails.IsValidDeviceName())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_BluetoothName, aRowSet), aDetails.DeviceName());
+		}
+	if (aDetails.IsValidFriendlyName())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_FriendlyName, aRowSet), aDetails.FriendlyName());
+		}
+	if (aDetails.IsValidUsed())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_LastUsed, aRowSet), aDetails.Used().Int64());
+		}
+	if (aDetails.IsValidSeen())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_LastSeen, aRowSet), aDetails.Seen().Int64());
+		}
+	if (aDetails.IsValidGlobalSecurity())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_GlobalSecSecurity, aRowSet), static_cast<TUint>(aDetails.GlobalSecurity().SecurityValue()));
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_GlobalSecPasskeyLen, aRowSet), static_cast<TUint>(aDetails.GlobalSecurity().PasskeyMinLength()));
+		}
+	if (aDetails.IsValidLinkKey())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_LinkKey, aRowSet), aDetails.LinkKey());
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_LinkKeyType, aRowSet), aDetails.LinkKeyType());
+		}
+	else
+		{
+		LOG(_L("Sec\tNot setting link key"))
+		}
+	if (aDetails.IsValidPassKey())
+		{
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_PassKey, aRowSet), aDetails.PassKey());
+		}
+	if (aDetails.IsValidUiCookie() && !aIgnoreUiCookie)
+		{
+		static const TUint8 KCookieBinaryRepresentationWidth = 32; // 32bits encoded as binary string.
+		TBuf8<KCookieBinaryRepresentationWidth> textCookieValue;
+		textCookieValue.NumFixedWidth(aDetails.UiCookie(), EBinary, KCookieBinaryRepresentationWidth);
+		aRowSet.SetColL(ColumnNoL(KDeviceColName_UiCookie, aRowSet), textCookieValue);
+		}
+	
+	CleanPutL(aRowSet);
+	}
+
+void CBTRegistry::CleanPutL(RDbRowSet& aRowSet)
+/**
+	Try to put the changes into a RowSet
+	If this fails cancel the update and reset
+	Then re-leave
+**/
+	{
+	LOG_FUNC
+	TRAPD(dbResult, aRowSet.PutL());
+
+	if (dbResult!=KErrNone)
+		{
+		aRowSet.Cancel();
+		aRowSet.Reset();
+		User::Leave(KErrCorrupt); // this will complete the client message
+		}
+	}
+
+RDbView* CBTRegistry::OpenDeviceL(const TBTDevAddr& aAddr, TDbBookmark& aBookmark)
+/**
+	Open a view onto a given record in the Registry
+	@return a bookmark to the entry should the caller want it
+**/
+	{
+	LOG_FUNC
+	RBTDbQuery query;
+	CleanupClosePushL(query);
+	query.FindDeviceL(aAddr);
+
+	// open the device
+	RDbView* view = NULL;
+	view = OpenViewL(query, aBookmark);
+
+	CleanupCloseDeletePushL(view);
+
+#ifdef _DEBUG
+	TInt c=0;
+	TRAP_IGNORE(c=view->CountL());
+	__ASSERT_DEBUG(c<=1, Panic(ETooManyRemoteDeviceEntries));
+#endif
+
+	CleanupStack::Pop(view); // view (pass ownership)
+	CleanupStack::PopAndDestroy(&query); // query
+	return view;
+	}
+
+RDbView* CBTRegistry::OpenViewL(const TDesC& aSQLQuery, TDbBookmark& aBookmark)
+/**
+	Returns a view resulting from the execution of the aSQLQuery
+	Update aBookmark to be the beginning of the view
+**/
+	{
+	LOG_FUNC
+	RDbView* view = new (ELeave) RDbView;
+	CleanupCloseDeletePushL(view);	
+
+	// open the view based on the SQL query
+	User::LeaveIfError(view->Prepare(iDB, aSQLQuery));
+	// could separate this into separate Evaluates, but expected to be smallish DB
+	User::LeaveIfError(view->EvaluateAll());
+
+	// move to first row, and bookmark it
+	view->FirstL();
+	aBookmark = view->Bookmark();	// set bookmark in case user would like it
+
+	CleanupStack::Pop(view);
+	return view;	// returns ownership
+	}
+
+RDbView* CBTRegistry::OpenViewL(const RBTDbQuery& aQuery, TDbBookmark& aBookmark)
+/**
+	Overload allowing just a RBTDbQuery to be executed - hides the SQL query
+**/
+	{
+	LOG_FUNC
+	return OpenViewL(aQuery.QueryBuf(), aBookmark);
+	}
+
+void CBTRegistry::IncrementRowL(RDbRowSet& aRowSet, TDbBookmark& aBookmark)
+/**
+	Move to the next row in a RowSet and return a bookmark should the caller be interested
+**/
+	{
+	LOG_FUNC
+	aRowSet.NextL();	// move onto next row for next get
+	aBookmark = aRowSet.Bookmark();
+	}
+
+void CBTRegistry::GetRowL(RDbRowSet& aRowSet, const TDbBookmark& aBookmark)
+/**
+	Mark the rowset for reading
+**/
+	{
+	LOG_FUNC
+	if (!aRowSet.AtEnd())
+		{
+		aRowSet.GotoL(aBookmark);
+		aRowSet.GetL();		// get the row (which is a remote device on this table)
+		}
+	else
+		{
+		User::Leave(KErrEof);
+		}
+	}
+
+
+void CBTRegistry::GetNamelessDetailsL(TBTNamelessDevice& aDevice, 
+									  RDbRowSet& aRowSet, 
+									  TBool includeKeys)
+/**
+	Gets the next device (row) out of a rowset and puts them in a CBTDevice
+	The CBTDevice and its ownership is returned to the caller
+**/
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(!aRowSet.IsColNull(ColumnNoL(KColName_DeviceAddress, aRowSet)), Panic(ECorruptDeviceEntry));
+
+	TPtrC8 addrBuf(aRowSet.ColDes8(ColumnNoL(KColName_DeviceAddress, aRowSet)));
+	aDevice.SetAddress(static_cast<TBTDevAddr>(addrBuf));
+
+	TDbColNo column;
+
+	column = ColumnNoL(KDeviceColName_PageScanMode, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		aDevice.SetPageScanMode(aRowSet.ColUint8(column));
+		}
+
+	column = ColumnNoL(KDeviceColName_PageScanPeriodMode, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		aDevice.SetPageScanPeriodMode(aRowSet.ColUint8(column));
+		}
+
+	column = ColumnNoL(KDeviceColName_PageScanRepMode, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		aDevice.SetPageScanRepMode(aRowSet.ColUint8(column));
+		}
+
+/*	column = ColumnNoL(KDeviceColName_CoD, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		aDevice.SetDeviceClass(aRowSet.ColUint32(column));
+		}
+*/
+	// all CoD columns must be set - just test one
+	column = ColumnNoL(KDeviceColName_CoD_MajorDev, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		TUint majorDeviceClass = aRowSet.ColUint(column);
+
+		column = ColumnNoL(KDeviceColName_CoD_MinorDev, aRowSet);
+		TUint minorDeviceClass = aRowSet.ColUint(column);
+
+		column = ColumnNoL(KDeviceColName_CoD_Service, aRowSet);
+		TUint serviceClass = aRowSet.ColUint(column);
+		
+		aDevice.SetDeviceClass(TBTDeviceClass(static_cast<TUint16>(serviceClass),
+											  static_cast<TUint8>(majorDeviceClass),
+											  static_cast<TUint8>(minorDeviceClass)));
+		
+		}
+	
+	column = ColumnNoL(KDeviceColName_GlobalSecSecurity, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		TBTDeviceSecurity devSec;
+		devSec.SetSecurityValue(aRowSet.ColUint8(column));
+		column = ColumnNoL(KDeviceColName_GlobalSecPasskeyLen, aRowSet);
+		devSec.SetPasskeyMinLength(aRowSet.ColUint32(column));
+				
+		aDevice.SetGlobalSecurity(devSec);
+		}
+
+	column = ColumnNoL(KDeviceColName_LinkKey, aRowSet);
+	TDbColNo typeColumn = ColumnNoL(KDeviceColName_LinkKeyType, aRowSet);
+
+	if (!aRowSet.IsColNull(column))
+		{
+		if(includeKeys)
+			{
+			TBTLinkKey linkKey;
+			linkKey.Copy(aRowSet.ColDes8(column));
+			aDevice.SetLinkKey(linkKey, static_cast<TBTLinkKeyType>(aRowSet.ColUint8(typeColumn)));
+			}
+		else
+			{
+			LOG(_L("Device paired but lack of capability to retrieve link key"));
+			aDevice.SetPaired(static_cast<TBTLinkKeyType>(aRowSet.ColUint8(typeColumn)));
+			}
+		}
+	else
+		{
+		LOG(_L("Sec\tDevice has NULL LinkKey column => Unpaired"))
+		}
+
+	column = ColumnNoL(KDeviceColName_PassKey, aRowSet);
+
+	if (!aRowSet.IsColNull(column))
+		{
+		if(includeKeys)
+			{
+			TBTPinCode passKey;
+			passKey.Copy(aRowSet.ColDes8(column));
+			aDevice.SetPassKey(passKey);
+			}
+		else
+			{
+			LOG(_L("Device has PIN code but lack of capability to retrieve PIN code"));
+			}
+		}
+	else
+		{
+		LOG(_L("Sec\tDevice has NULL PinCode column"))
+		}
+		
+	column = ColumnNoL(KDeviceColName_LastSeen, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		aDevice.SetSeen(TTime(aRowSet.ColInt64(column)));
+		}
+
+	column = ColumnNoL(KDeviceColName_LastUsed, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		aDevice.SetUsed(TTime(aRowSet.ColInt64(column)));
+		}
+	
+	column = ColumnNoL(KDeviceColName_UiCookie, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		TPtrC8 cookieBuf(aRowSet.ColDes8(column));
+		TLex8 lexer(cookieBuf);
+		TUint32 cookieValue = 0;
+		TInt err = lexer.Val(cookieValue, EBinary);
+		if(err != KErrNone)
+			{
+			// discard the specific lexer errors, the fundemental issue
+			// is that the device entry is corrupted in someway.
+			User::Leave(KErrCorrupt);
+			}
+		aDevice.SetUiCookie(cookieValue);
+		}
+	}
+
+const TBTNamelessDevice* CBTRegistry::GetNextNamelessDeviceLC(RDbRowSet& aRowSet, 
+															  TDbBookmark& aBookmark, 
+															  TBool includeKeys)
+/**
+	Get the next row from the rowset; building and return TBTNamelessDevice via heap
+**/
+	{
+	LOG_FUNC
+	GetRowL(aRowSet, aBookmark);
+	// there is a row to get, instantiate an object to receive details
+	TBTNamelessDevice* device = new(ELeave) TBTNamelessDevice; // for passing ownership
+	CleanupStack::PushL(device);
+	GetNamelessDetailsL(*device, aRowSet, includeKeys);
+	IncrementRowL(aRowSet, aBookmark);
+	return device;
+	}
+
+CBTDevice* CBTRegistry::GetNextDeviceL(RDbRowSet& aRowSet, 
+											 TDbBookmark& aBookmark, 
+											 TBool includeLinkKey)
+/**
+	Get the next row from the rowset; building and return CBTDevice via heap
+**/
+	{
+	LOG_FUNC
+	GetRowL(aRowSet, aBookmark);
+	// there is a row to get, so instantiate an object to receive details
+	CBTDevice* device = CBTDevice::NewLC();
+	GetNamelessDetailsL(device->AsNamelessDevice(), aRowSet, includeLinkKey);
+
+	TDbColNo column = ColumnNoL(KDeviceColName_BluetoothName, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		device->SetDeviceNameL(aRowSet.ColDes8(column));
+		}
+
+	column = ColumnNoL(KDeviceColName_FriendlyName, aRowSet);
+	if (!aRowSet.IsColNull(column))
+		{
+		TBuf<KMaxFriendlyNameLen> unicodeBuf;
+		unicodeBuf.Copy(aRowSet.ColDes(column));
+		device->SetFriendlyNameL(unicodeBuf);
+		}
+	IncrementRowL(aRowSet, aBookmark);
+	CleanupStack::Pop(device);
+	return device;
+	}
+
+const TUid CBTRegistry::CreatingProcessUidL(RDbRowSet& aRowSet)
+/**
+	@return	Value read from DB of the process that created a rowset
+**/
+	{
+	LOG_FUNC
+#ifdef _DEBUG
+	TInt c=0;
+	TRAP_IGNORE(c=aRowSet.CountL());
+	__ASSERT_DEBUG(c==1, Panic(ETooManyRemoteDeviceEntries));
+#endif
+
+	aRowSet.GetL();	// this makes the semantics of this function a bit odd...it leaves the rowset open for read
+	TInt val = aRowSet.ColUint32(ColumnNoL(KColName_ProcessSID, aRowSet));
+	return TUid::Uid(val);
+	}
+
+
+void CBTRegistry::DeleteViewL(RDbRowSet& aRowSet, TBool aDeleteAll, const TSecureId& aSecureId)
+/**
+	Delete all the rows in the set whose originating Id is the same as 
+	aSecureId
+	
+	@param aRowSet The rowset whose records are to be deleted
+	@param aDeleteAll If set to ETrue, all rows are deleted. If EFalse, only those
+	rows whose SID value is same as aSecureId will be deleted.
+	@param aSecureId The SID of the calling process.
+**/
+	{
+	LOG_FUNC
+	aRowSet.FirstL();
+	TInt c = aRowSet.CountL();
+	
+	if(	c == 0 )
+		{
+		//	No rows, nothing to do
+		return;
+		}
+		
+	TDbColNo secureIdColNo=ColumnNoL(KColName_ProcessSID, aRowSet);
+	//	There should always be a ProcessSID column present in the view
+	__ASSERT_ALWAYS(secureIdColNo != KDbNullColNo, Panic(EColumnNotFound));
+	
+	for (TInt i=0; i<c; i++)
+		{
+		//	Retrieve the current row ready to be accessed
+		aRowSet.GetL();
+		if( aDeleteAll || (aRowSet.ColUint32(secureIdColNo) == aSecureId) )
+			{
+			aRowSet.DeleteL();
+			}
+		//	Regardless of the DeleteL or no DeleteL, the cursor remains
+		//	in the same location, so we always need to call NextL.
+		aRowSet.NextL();
+		}
+	// better try to compact now to avoid ballooning
+	(void)iDB.Compact();
+	}
+
+
+TBTLocalDevice* CBTRegistry::GetLocalDeviceLC()
+/**
+	Get the single row pertaining to the local device
+	Build and return a TBTLocalDevice
+**/
+	{
+	LOG_FUNC
+	TBTLocalDevice* device = new(ELeave) TBTLocalDevice; // for passing ownership
+	CleanupStack::PushL(device);
+
+	RDbTable* table = OpenPersistTableL();
+	CleanupCloseDeletePushL(table);
+
+#ifdef _DEBUG
+	TInt c=0;
+	TRAP_IGNORE(c=table->CountL());
+	__ASSERT_DEBUG(c==1, Panic(ENotOneLocalDeviceEntry));
+#endif
+
+
+	TBool success = table->FirstL();	// go to only row in table
+	if (!success)
+		{
+		LOG(_L("BT Registry DB Local Device Table (Persist Table) CORRUPT!"));
+		User::Leave(KErrEof);
+		}
+
+	table->GetL();		// mark for retrieval
+
+	TPtrC8 addrBuf(table->ColDes8(ColumnNoL(KColName_DeviceAddress, *table)));
+	device->SetAddress(static_cast<TBTDevAddr>(addrBuf));
+
+	device->SetDeviceClass(table->ColUint32(ColumnNoL(KPersistColName_CoD, *table)));
+	device->SetDeviceName(table->ColDes8(ColumnNoL(KPersistColName_LocalName, *table)));
+	device->SetScanEnable(static_cast<THCIScanEnable>(table->ColUint8(ColumnNoL(KPersistColName_ScanEnable, *table))));
+	device->SetPowerSetting(table->ColUint8(ColumnNoL(KPersistColName_PowerSettings, *table)));
+	device->SetAFHChannelAssessmentMode(table->ColUint8(ColumnNoL(KPersistColName_AFHChannelAssessmentMode, *table)));
+	device->SetLimitedDiscoverable(table->ColUint8(ColumnNoL(KPersistColName_LimitedDiscoverable, *table)));
+	device->SetAcceptPairedOnlyMode(table->ColUint8(ColumnNoL(KPersistColName_AcceptPairedOnlyMode, *table)));
+	CleanupStack::PopAndDestroy(table); //table
+	return device;
+	}
+
+const TBTCommPortSettings* CBTRegistry::GetCommPortSettingsLC(const TBTCommPortSettings& aSettings)
+/**
+	Get the virtual serial port settings for the port referred to in aSettings
+**/
+	{
+	LOG_FUNC
+	TBTCommPortSettings* settings = new(ELeave) TBTCommPortSettings; // for passing ownership
+	CleanupStack::PushL(settings);
+
+	RDbView* view = OpenCommPortLC(aSettings);
+
+	// mark for retrieval
+	view->GetL();
+	// get the unit number
+	settings->SetPort(aSettings.Port());
+	// get the device address
+	TPtrC8 addrBuf(view->ColDes8(ColumnNoL(KColName_DeviceAddress, *view)));
+	settings->SetBTAddr(static_cast<TBTDevAddr>(addrBuf));
+
+	// get the uuid
+	TUUID uuid;
+	uuid.SetL(view->ColDes8(ColumnNoL(KBTCOMMColName_ServiceUUID, *view)));
+	settings->SetUUID(uuid);
+
+	// get the service uuid and name
+	settings->SetSecurityLevel(view->ColUint8(ColumnNoL(KBTCOMMColName_Security, *view)));
+	settings->SetName(view->ColDes(ColumnNoL(KBTCOMMColName_ServiceName, *view)));
+
+	CleanupStack::PopAndDestroy(view); //closes view
+	// don't pop settings - C function
+	return settings;	
+	}
+
+void CBTRegistry::PutCommPortSettingsInTableL(RDbRowSet& aRowSet,
+											  const TBTCommPortSettings& aSettings) 
+/**
+	Update the port settings
+**/
+	{
+	LOG_FUNC
+	aRowSet.SetColL(ColumnNoL(KBTCOMMColName_Port, aRowSet), aSettings.Port());
+	aRowSet.SetColL(ColumnNoL(KColName_DeviceAddress, aRowSet), aSettings.BDAddr().Des());
+	aRowSet.SetColL(ColumnNoL(KBTCOMMColName_ServiceUUID, aRowSet), aSettings.UUID().Des());
+	aRowSet.SetColL(ColumnNoL(KBTCOMMColName_Security, aRowSet), static_cast<TUint>(aSettings.SecurityLevel()));
+	aRowSet.SetColL(ColumnNoL(KBTCOMMColName_ServiceName, aRowSet), aSettings.Name());
+
+	TRAPD(err,aRowSet.PutL());
+	if (err!=KErrNone)
+		{
+		aRowSet.Cancel();
+		aRowSet.Reset();
+		User::Leave(err);
+		}
+	}
+
+RDbView* CBTRegistry::OpenCommPortL(const TBTCommPortSettings& aSettings)
+/**
+	Return view of the com port specified
+**/
+	{
+	LOG_FUNC
+	// Form the SQL query based on the search criteria
+	RBTDbQuery query;
+	CleanupClosePushL(query);
+	query.FindCommPortL(aSettings.Port());	// just search on port for now
+
+	// execute the SQL with dummy bookmark for now
+	TDbBookmark dummy;
+	RDbView* view = OpenViewL(query, dummy);
+	CleanupCloseDeletePushL(view);
+
+	TInt count = view->CountL();
+	
+	if (!count)
+		{
+		User::Leave(KErrNotFound); // nothing in there: which may be OK!
+		}
+
+	CleanupStack::Pop(view); // returns ownership - don't destroy
+	CleanupStack::PopAndDestroy(&query); // query
+	return view;
+	}
+
+RDbView* CBTRegistry::OpenCommPortLC(const TBTCommPortSettings& aSettings)
+	{
+	LOG_FUNC
+	RDbView* view = OpenCommPortL(aSettings);
+	CleanupCloseDeletePushL(view);
+	return view;
+	}
+
+void CBTRegistry::DeleteCommPortSettingsL(RDbView& aCommPortSettingsView)
+	{
+	LOG_FUNC
+	aCommPortSettingsView.DeleteL();
+	}
+
+void CBTRegistry::AddCommPortSettingsL(const TBTCommPortSettings& aSettings, 
+									   const TSecureId& aClientSID)
+/**
+	Add port settings row
+	Create row and enter values in aSettings.
+	THIS must only be called if the table has been checked for existing settings
+**/
+	{
+	LOG_FUNC
+#ifdef _DEBUG
+	// check it's not already there
+	TRAPD(err, OpenCommPortL(aSettings));
+	ASSERT_DEBUG(err==KErrNotFound);
+#endif
+	
+	RDbTable* table = OpenTableL(KCSYTable);
+
+	//create a record for this port, it wasn't there
+	CleanupCloseDeletePushL(table);
+	table->InsertL();
+
+	table->SetColL(ColumnNoL(KColName_ProcessSID, *table), aClientSID);	// store originating client ID
+
+	//put the port values in
+	PutCommPortSettingsInTableL(*table, aSettings);
+	CleanupStack::PopAndDestroy(table); //table
+	}
+
+void CBTRegistry::UpdateCommPortSettingsL(RDbView& aView,
+										  const TBTCommPortSettings& aSettings) 
+/**
+	Update the port settings
+**/
+	{
+	LOG_FUNC
+	aView.UpdateL();	// mark for update
+	PutCommPortSettingsInTableL(aView, aSettings);
+	}
+
+void CBTRegistry::DeleteCorruptRegistryL()
+	{
+	LOG_FUNC
+	// The registry is corrupt so we need to create a new one and notify 
+	// interested parties that all of the user's pairings may have been lost.
+
+	
+	// close the database (if open)
+	iDB.Close();
+	TInt err = KErrNone;
+
+	// The RDbs method must be used to access the private data cage.
+	err = iDBMSServer.DeleteDatabase(TBTRegistryDatabaseSecure()(), KBTManServerUid);  
+	if(err)
+		{
+		LOG1(_L("UNSUCCESSFUL attempt to delete Corrupt BT Registry DB, error %d"), err);
+		}
+	else
+		{
+		LOG(_L("Corrupt BT Registry DB Deleted successfully"));
+		// Use P&S to let UIs know that the registry may have lost some 
+		// of the user's pairings.			
+		RProperty::Set(KPropertyUidBluetoothCategory,
+					   KPropertyKeyBluetoothCorruptRegistryReset,
+					   User::TickCount());	   			   	
+		}
+	}
+
+void CBTRegistry::SetupDefaultRegistryL()
+	{
+	LOG_FUNC
+	CreateMetaTableL();
+	CreatePersistTableL();
+	CreateCSYTableL();
+	CreateDeviceTableL();
+
+	// now add default values for the tables: set all the states to 'unset'
+	TBTLocalDevice defaultDevice;
+	
+	
+	// Set up the defaults - these will get overwritten if there are appropriate values in the ini file
+	defaultDevice.SetAddress(TBTDevAddr(0));
+	defaultDevice.SetDeviceName(KDefaultLocalName);
+	defaultDevice.SetScanEnable(EPageScanOnly);
+	defaultDevice.SetLimitedDiscoverable(EFalse);
+	defaultDevice.SetDeviceClass(0);
+	// The registry is being kicked off with a default channel assessment 
+	// mode setting of 'enabled'. This is the default if h/w supports 
+	// channel assessment. If h/w does not support channel assessment,
+	// this value becomes meaningless.
+	// Any use of it to update h/w will be rejected.
+	defaultDevice.SetAFHChannelAssessmentMode(ETrue);
+	defaultDevice.SetAcceptPairedOnlyMode(EFalse);
+	
+	// Try and get any relevant parameters from the ini file
+	TRAP_IGNORE(GetDefaultDeviceFromIniL(defaultDevice)); // Ignore any leaves as they cannot result in corruption of defaultDevice
+
+	UpdateLocalDeviceL(defaultDevice);
+//#pragma message("defaults for persist table ini file/licensee?")
+	}
+
+//
+
+TInt CBTRegistry::SetDeviceName(const TDesC& aDeviceName, TBTLocalDevice& aDevice)
+	{
+	// GetDefaultDeviceName() returns 16bit unicode, it need to be converted to 8bit UTF
+	TBTDeviceName8 tempBuf;
+	TInt error = CnvUtfConverter::ConvertFromUnicodeToUtf8(tempBuf, aDeviceName);
+	if(error == KErrNone)
+		{
+		aDevice.SetDeviceName(tempBuf);
+		}
+	return error;
+	}
+
+TBool CBTRegistry::SetDeviceNameFromIniFile(TBTLocalDevice& aDevice, RBuf8& bufPtr)
+	{
+	// Default so try the old mechanism.
+	_LIT8(KVarDeviceName, "DeviceName");
+	TPtrC8 devName(NULL, 0);
+	if (FindVar(bufPtr, KVarDeviceName, devName) && devName.Length() <= KMaxBCBluetoothNameLen)
+		{
+		aDevice.SetDeviceName(devName);
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+void CBTRegistry::GetDefaultDeviceFromIniL(TBTLocalDevice& aDevice)
+	{
+	LOG_FUNC
+	// Try and open the .ini file and get any relavent parameters
+	RFs	fileSession;
+	User::LeaveIfError(fileSession.Connect());
+	CleanupClosePushL(fileSession);
+	
+	_LIT(KIniDrive, "Z:");
+	_LIT(KIniName, "DefaultBtReg.ini");
+	TFileName	iniFileName;
+	fileSession.PrivatePath(iniFileName);
+	iniFileName.Insert(0, KIniDrive);
+	iniFileName.Append(KIniName);
+	
+	RFile file;
+	User::LeaveIfError(file.Open(fileSession, iniFileName, EFileStreamText|EFileRead));
+	CleanupClosePushL(file);
+	TInt data_size = 0;
+	User::LeaveIfError(file.Size(data_size));
+
+	// All text encoding is narrow 8-bit ASCII as ini files generated on a PC will be encoded that way
+	// and the bluetooth specification only allows 8-bit ASCII strings so there is no need to convert
+	// between ASCII and Unicode and back again.
+	RBuf8 bufPtr;
+	bufPtr.CreateL(data_size);
+	CleanupClosePushL(bufPtr);
+	User::LeaveIfError(file.Read(bufPtr));
+	
+	// Any or all of the following variables may be specified in this ini file:
+	//
+	// Variable:								Variable Name:			Values Taken:
+	//	Default device name						DeviceName				String
+	//	Inquiry scan enabled by default			InquiryScan				0 or 1
+	//	Page scanning enabled by default		PageScan				0 or 1
+	//	Limited discovery enabled by default	LimitedDiscovery		0 or 1
+	//	Default device class					DeviceClass				Integer (decimal format)
+	//	Allow paired only eanabled by default	AcceptPairedOnlyMode	0 or 1
+	//
+	// Notes on file syntax:
+	// - Variable Names are followed by an ‘=’ character and then the value taken.
+	// - There are no whitespaces in variable names.
+	// - Variable names may be followed by any number of whitespaces, until the first character of the value taken. Thereafter any whitespaces are considered part of the value until the end of line.
+	// - All characters should be narrow (standard 8bit ASCII).
+	// - Integers should contain only the standard characters 0 to 9.
+	// - Boolean values should be indicated by a 0 or 1.
+	// - Strings may contain whitespaces, but any at the beginning will be stripped.
+	// - There is no need to terminate the file with a new line.
+	// - Anything after "//" on a line is ignored as comments
+	
+
+	// Remove any comments from the buffer
+	TInt slashPos;
+	TInt commentLength;
+	TPtr8 comment(NULL, 0);
+	_LIT8(KDoubleSlash, "//");
+	while ((slashPos = bufPtr.Find(KDoubleSlash)) != KErrNotFound)
+		{
+		_LIT8(KEol, "\n");
+		comment.Set(bufPtr.MidTPtr(slashPos));
+		if ((commentLength = comment.Find(KEol)) == KErrNotFound)
+			{
+			commentLength = comment.Length(); // just to end of file
+			}
+		bufPtr.Replace(slashPos, commentLength, KNullDesC8);
+		}
+
+	// Get the default device name
+	// we try to get the device name from deviceattributes.ini as a first resort,
+	// deviceattributes.ini is global device configuration for setting global data like the device name
+
+	CDeviceTypeInformation* deviceInfo = NULL;
+	TRAPD(ret, deviceInfo = SysUtil::GetDeviceTypeInfoL());
+	CleanupStack::PushL(deviceInfo);
+	TPtrC16 deviceName;
+
+	if (ret == KErrNone)
+		{
+		ret = deviceInfo->GetDefaultDeviceName(deviceName);
+		if (ret == KErrNone)
+			{
+			LEAVEIFERRORL(SetDeviceName(deviceName, aDevice));
+			}
+		else if (ret == CDeviceTypeInformation::KDefaultValue)
+			{
+			if(!SetDeviceNameFromIniFile(aDevice, bufPtr))
+				{
+				ret = SetDeviceName(deviceName, aDevice);
+				__ASSERT_DEBUG(ret == KErrNone,Panic(ECorruptDeviceEntry));
+				if(ret != KErrNone)
+					{
+					SetDeviceNameFromIniFile(aDevice, bufPtr);
+					}
+				}
+			}
+		else
+			{
+			SetDeviceNameFromIniFile(aDevice, bufPtr);
+			}
+		}
+	else
+		{ // if the above did not work, then use the old mechanism
+		SetDeviceNameFromIniFile(aDevice, bufPtr);
+		}
+
+	// Get default scan enabled status
+	TInt scanStatus = aDevice.ScanEnable();
+	TInt result = 0;
+	_LIT8(KVarInquiryScan, "InquiryScan");
+	if (FindVar(bufPtr, KVarInquiryScan, result))
+		{
+		if (result)
+			scanStatus |= EInquiryScanOnly;
+		else
+			scanStatus &= ~EInquiryScanOnly;  		
+		}
+	
+	_LIT8(KVarPageScan, "PageScan");
+	if (FindVar(bufPtr, KVarPageScan, result))
+		{
+		if (result)
+			scanStatus |= EPageScanOnly;
+		else
+			scanStatus &= ~EPageScanOnly;
+		}
+	aDevice.SetScanEnable(static_cast<THCIScanEnable>(scanStatus));
+	
+	
+	// Get default limited discovery status
+	_LIT8(KVarLimitedDiscovery, "LimitedDiscovery");
+	if (FindVar(bufPtr, KVarLimitedDiscovery, result))
+		{
+		aDevice.SetLimitedDiscoverable(result);	
+		}	
+	
+	
+	// Get default device class
+	_LIT8(KVarDeviceClass, "DeviceClass");
+	if (FindVar(bufPtr, KVarDeviceClass, result))
+		{
+		aDevice.SetDeviceClass(result);	
+		}	
+			
+	
+	// Get default AFH channel assessment only mode
+	_LIT8(KAFHChannelAssessmentMode, "AFHChannelAssessmentMode");
+	if (FindVar(bufPtr, KAFHChannelAssessmentMode, result))
+		{
+		aDevice.SetAFHChannelAssessmentMode(result);
+		}
+			
+	
+	// Get default accept paired only mode
+	_LIT8(KAcceptPairedOnlyMode, "AcceptPairedOnlyMode");
+	if (FindVar(bufPtr, KAcceptPairedOnlyMode, result))
+		{
+		aDevice.SetAcceptPairedOnlyMode(result);
+		}
+
+
+	CleanupStack::PopAndDestroy(4, &fileSession); // deviceinfo, bufPtr, file, fileSession
+	}
+
+TBool CBTRegistry::FindVar(const TDesC8& aPtr, const TDesC8 &aVarName, TPtrC8 &aResult) const
+	{
+	LOG_FUNC
+	// Find the variable name
+	TInt start=aPtr.Find(aVarName);
+	if (start == KErrNotFound)
+		{
+		return EFalse;
+		}
+	
+	// Now find the end of the value string (end of line or end of file)
+	TPtrC8 value(aPtr.Mid(start));
+	_LIT8(KEol, "\n");
+	TInt length = value.Find(KEol);
+	if (length != KErrNotFound)
+		{
+		if (value[length-1] == '\r')
+			{
+			length--;
+			}
+		}
+	else
+		{
+		length = value.Length();
+		}
+		
+	// Now find the start of the value to be parsed
+	TLex8 lex(aPtr.Mid(start, length));
+	TChar next = lex.Get();
+	while (next != '=' && next != NULL)	
+		{		
+		next = lex.Get(); // Step through until we find a '=' character or EOS
+		}
+	
+	if (next == NULL)
+		{
+		return EFalse;	// End of string was found before '=' so there's no valid value.
+		}
+		
+	lex.SkipSpace();	// Will now be at the start of the value
+	
+	// Now copy the variable value into the result
+	aResult.Set(lex.Remainder());
+	
+	return ETrue;
+	}
+
+
+TBool CBTRegistry::FindVar(const TDesC8& aPtr, const TDesC8 &aVarName, TInt &aResult) const
+	{
+	LOG_FUNC
+	TPtrC8 ptr(NULL,0);
+	
+	if (FindVar(aPtr, aVarName,ptr))
+		{
+		TLex8 lex(ptr);
+		if (lex.Val(aResult) == KErrNone)
+			{
+			return(ETrue);			
+			}
+		}
+		
+	return(EFalse);
+	}
+
+
+TBTRegistryDatabaseSecure::TBTRegistryDatabaseSecure()
+	{
+	LOG_FUNC
+	iBuf.Append(RFs::GetSystemDrive() + 'a'); //Gets the system drive and convert it from enum to a char
+	iBuf.Append(':');
+	iBuf.Append(KBTRegistryDatabaseSecure);		
+	}
+		
+const TDesC& TBTRegistryDatabaseSecure::operator()() const
+	{
+	LOG_FUNC
+	return iBuf;
+	}
+