bluetoothmgmt/btmgr/BTManServer/BTRegistrySQL.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:38:54 +0100
branchRCL_3
changeset 24 e9b924a62a66
parent 0 29b1cd4cb562
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201031 Kit: 201035

// Copyright (c) 2002-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 "BTRegistryDB.h"
#include <bluetooth/logger.h>

#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_BT_MANAGER_SERVER);
#endif

const TInt KMaxLengthConstraintInitial = 60;	// constraint length is initially this
const TInt KMaxLengthConstraintIncrement = 60;	// - then we extend as necessary by this amount

RBTDbQuery::RBTDbQuery()
/**
	Required for non-default constructed RTextBuf
**/
	{
	LOG_FUNC
	}

void RBTDbQuery::Close()
	{
	LOG_FUNC
	iQueryBuf.Close();
	}

const TPtrC RBTDbQuery::QuoteEscapeLC(const TBTDevAddr& aBDAddr) const
	{
	LOG_FUNC
	TBuf<6> wideAddr;	// needed to stop implicit converstion back to DevAddr!
	wideAddr.Copy(aBDAddr.Des());
	return QuoteEscapeLC(wideAddr);
	}

const TPtrC RBTDbQuery::QuoteEscapeLC(const TDesC& aDes) const
/**
	Can't search for a string in SQL with a quote (') in un-escaped
	Escape by putting extra quote in for every quote in the descriptor
**/
	{
	LOG_FUNC
	const TUint16 KEscapeCode = 0x0027;	// SQL escape value
	// maximum size of new descriptor will be twice the original (if it contained all quotes!)
	HBufC* escaped = HBufC::NewMaxLC(2*aDes.Length());
	TPtr escapedPtr= escaped->Des();

	TInt i=0;
	TInt escapedIndex = 0;
	while (i<aDes.Length())
		{
		const TChar& element = aDes[i++];	// copes with narrow and wide
#pragma warning (disable : 4244)  // conversion - its ok here
		escapedPtr[escapedIndex++] = element;
#pragma warning (default : 4244)
		if (element == KEscapeCode)
			{
			escapedPtr[escapedIndex++] = KEscapeCode;
			}
		}
	escapedPtr.SetLength(escapedIndex);	// bring down from the MaxLength
	return escapedPtr;	// returns ownership of the HBuf via cleanupstack
	}

void RBTDbQuery::FindDeviceL(const TBTDevAddr& aBDAddr)
/**
	Construct a simple SQL query to see if the device is present
**/
	{
	LOG_FUNC
	// this is used to see if the device is in the registry
	TBuf<KMaxConstraintLen> constraint;

	constraint.Append(KColName_DeviceAddress);
	constraint.Append(KSQLEqual);
	constraint.Append(KSQLQuote);
	constraint.Append(QuoteEscapeLC(aBDAddr));
	constraint.Append(KSQLQuote);

	iQueryBuf.SetMaxLengthL(constraint.Length() + KSQLSelectAllConstrained().Length() + KDeviceTable().Length());
	iQueryBuf.Text().Format(KSQLSelectAllConstrained, &KDeviceTable, &constraint);

	CleanupStack::PopAndDestroy(1); // address buffer
	}

void RBTDbQuery::FindCommPortL(TUint32 aUnitNumber)
/**
	Construct a SQL query to find the virtual serial port with aUnitNumber
**/
	{
	LOG_FUNC
	TBuf<KMaxConstraintLen> constraint;

	constraint.Append(KBTCOMMColName_Port);
	constraint.Append(KSQLEqual);
	constraint.AppendNum(static_cast<TUint>(aUnitNumber), EDecimal);

	iQueryBuf.SetMaxLengthL(constraint.Length() + KSQLSelectAllConstrained().Length() + KCSYTable().Length());
	iQueryBuf.Text().Format(KSQLSelectAllConstrained, &KCSYTable, &constraint);
	}

void RBTDbQuery::MatchLinkKeyTypeL(TBTLinkKeyType aLinkKeyType)
/**
 	Construct a SQL query to find entries that have a link key of a specific type.
**/
	{
	LOG_FUNC
	TBuf<KMaxConstraintLen> constraint;

	constraint.Append(KDeviceColName_LinkKeyType);
	constraint.Append(KSQLEqual);
	constraint.AppendNum(static_cast<TUint>(aLinkKeyType), EDecimal);

	iQueryBuf.SetMaxLengthL(constraint.Length() + KSQLSelectAllConstrained().Length() + KDeviceTable().Length());
	iQueryBuf.Text().Format(KSQLSelectAllConstrained, &KDeviceTable, &constraint);
	}

const TDesC& RBTDbQuery::QueryBuf() const
	{
	LOG_FUNC
	return iQueryBuf.Text();
	}

TPtrC RBTDbQuery::ConstraintBuf() const
	{
	LOG_FUNC
	TInt index = QueryBuf().Find(KSQLWhere);
	return (index==KErrNotFound) ? TPtrC() : QueryBuf().Mid(index+KSQLWhere().Length());
	}

void RBTDbQuery::ExtendForAnotherTokenL(RTextBuf& aSQLBuf, TUint aMask)
/**
	Sees if the token 'AND' is required in a constrained search
	If so, add into the SQL query
	If the buffer is getting small, extend it
**/
	{
	LOG_FUNC
	if (aMask)
		{
		// need an AND - more constraints follow
		aSQLBuf.Text().Append(KSQLAnd);
		//Need to increase the size of the bufferno
		// RTextBuf::SetMaxLengthL is bad as it closes the textbuf
		RTextBuf copy;
		copy.SetMaxLengthL(aSQLBuf.Text().Length());
		CleanupClosePushL(copy);
		copy.Text().Append(aSQLBuf.Text());
		aSQLBuf.SetMaxLengthL(aSQLBuf.Text().Length()+KMaxLengthConstraintIncrement);
		//copy back from the copy to the aSQLBuf
		aSQLBuf.Text().Append(copy.Text());
		CleanupStack::PopAndDestroy();
		}
	// else do nothing - no further constraint to follow
	}

void RBTDbQuery::SearchL(const TBTRegistrySearch& aPattern)
/**
	Converts a search mask into SQL search tokens
**/
	{
	LOG_FUNC
	// do the catch all first - saves time
	if (aPattern.iSearchMask & TBTRegistrySearch::EAll)
		{
		iQueryBuf.SetMaxLengthL(KSQLSelectAll().Length() + KDeviceTable().Length());
		iQueryBuf.Text().Format(KSQLSelectAll, &KDeviceTable);
		return;
		}

	// we have a constrained search; formulate the SQL
	// we use a RTextBuf that can grow as needed (to reduce stack usage)

	RTextBuf constraintBuf;

	constraintBuf.SetMaxLengthL(KMaxLengthConstraintInitial);

	TPtr& constraint = constraintBuf.Text();

	TUint toSearch = aPattern.iSearchMask;
	
	if (toSearch & TBTRegistrySearch::EAddress)
		{
		constraint.Append(KColName_DeviceAddress);
		constraint.Append(KSQLEqual);
		constraint.Append(KSQLQuote);
		constraint.Append(QuoteEscapeLC(aPattern.iDeviceAddress));
		constraint.Append(KSQLQuote);
		CleanupStack::PopAndDestroy(1); // address buffer
		
		toSearch &= ~TBTRegistrySearch::EAddress;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}


	if (toSearch & TBTRegistrySearch::ECoD)
		{
		constraint.Append(KDeviceColName_CoD);
		constraint.Append(KSQLEqual);
		TUint cod = aPattern.iDeviceClass.DeviceClass();
		constraint.AppendNum(cod, EDecimal);

		toSearch &= ~TBTRegistrySearch::ECoD;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}
		
	if (toSearch & TBTRegistrySearch::ECoDMajorDev)
		{
		constraint.Append(KDeviceColName_CoD_MajorDev);
		constraint.Append(KSQLEqual);
		TUint majDev = aPattern.iDeviceClass.MajorDeviceClass();
		constraint.AppendNum(majDev, EDecimal);

		toSearch &= ~TBTRegistrySearch::ECoDMajorDev;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}

	if (toSearch & TBTRegistrySearch::ECoDMinorDev)
		{
		constraint.Append(KDeviceColName_CoD_MinorDev);
		constraint.Append(KSQLEqual);
		TUint minDev = aPattern.iDeviceClass.MinorDeviceClass();
		constraint.AppendNum(minDev, EDecimal);

		toSearch &= ~TBTRegistrySearch::ECoDMinorDev;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}

	if (toSearch & TBTRegistrySearch::EBTName)
		{
		constraint.Append(KDeviceColName_BluetoothName);
		constraint.Append(KSQLEqual);
		constraint.Append(KSQLQuote);
		TBuf<KMaxBluetoothNameLen> widened;
		widened.Copy(aPattern.iBluetoothName);
		constraint.Append(QuoteEscapeLC(widened));
		constraint.Append(KSQLQuote);
		CleanupStack::PopAndDestroy(1); //name

		toSearch &= ~TBTRegistrySearch::EBTName;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}

	if (toSearch & TBTRegistrySearch::EFriendlyName)
		{
		constraint.Append(KDeviceColName_FriendlyName);
		constraint.Append(KSQLEqual);
		constraint.Append(KSQLQuote);
		constraint.Append(QuoteEscapeLC(aPattern.iFriendlyName));
		constraint.Append(KSQLQuote);
		CleanupStack::PopAndDestroy(1); // name

		toSearch &= ~TBTRegistrySearch::EFriendlyName;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}

	if (toSearch & TBTRegistrySearch::EProcess)
		{
		constraint.Append(KColName_ProcessSID);
		constraint.Append(KSQLEqual);
		constraint.AppendNum(MAKE_TUINT64(0,aPattern.iCurrentProcessSID.iUid), EDecimal);

		toSearch &= ~TBTRegistrySearch::EProcess;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}

	if (toSearch & TBTRegistrySearch::EBonded)
		{
		constraint.Append(KDeviceColName_LinkKey);
		constraint.Append(KSQLIsNotNull);

		toSearch &= ~TBTRegistrySearch::EBonded;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}

	if (toSearch & TBTRegistrySearch::ETrusted)
		{
		// check global security for no authorisation AND authentication
		constraint.Append(KSQLOpenParentheses);
		constraint.Append(KDeviceColName_GlobalSecSecurity);
		constraint.Append(KSQLEqual);

		// we do this here in case TBTDeviceSecurity changes
		// trusted device = 'NoAuthentication'=No (MUST authenticate!),
		//					'NoAuthorisation'=Yes
		//					'Encryption' could be either.
		//					'Banned' =No (!)

		TBTDeviceSecurity noEncryption(EFalse, ETrue, EFalse, EFalse);
		constraint.AppendNum(static_cast<TUint>(noEncryption.SecurityValue()));

		constraint.Append(KSQLOr);
		constraint.Append(KDeviceColName_GlobalSecSecurity);
		constraint.Append(KSQLEqual);
		
		TBTDeviceSecurity encryption(EFalse, ETrue, ETrue, EFalse);
		constraint.AppendNum(static_cast<TUint>(encryption.SecurityValue()));
		constraint.Append(KSQLCloseParentheses);

		toSearch &= ~TBTRegistrySearch::ETrusted;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}

	if (toSearch & TBTRegistrySearch::ELastSeen)
		{
		constraint.Append(KDeviceColName_LastSeen);
		constraint.Append(KSQLGreaterEqual);
		constraint.AppendNum(aPattern.iLastSeen.Int64());
		toSearch &= ~TBTRegistrySearch::ELastSeen;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}

	if (toSearch & TBTRegistrySearch::ELastUsed)
		{
		constraint.Append(KDeviceColName_LastUsed);
		constraint.Append(KSQLGreaterEqual);
		constraint.AppendNum(aPattern.iLastUsed.Int64());
		toSearch &= ~TBTRegistrySearch::ELastUsed;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}
	
	if (toSearch & TBTRegistrySearch::EUiCookie)
		{
		constraint.Append(KDeviceColName_UiCookie);
		constraint.Append(KSQLLike);
		constraint.Append(KSQLQuote);
		static const TUint8 KCookieBinaryRepresentationWidth = 32; // 32bits encoded as binary string.
		TBuf<KCookieBinaryRepresentationWidth> cookiePattern;
		cookiePattern.NumFixedWidth(aPattern.iUiCookie, EBinary, KCookieBinaryRepresentationWidth);
		TUint32 shiftedMask = aPattern.iUiCookieMask;
		for(TInt i=KCookieBinaryRepresentationWidth-1; i>=0; --i)
			{
			if(!(shiftedMask&1)) // check the bottom bit (we loop through them all by shifting.)
				{
				// bit "i" isn't masked, and so we should ignore it.
				cookiePattern[i] = '?';
				}
			shiftedMask >>= 1;
			}
		constraint.Append(cookiePattern);
		constraint.Append(KSQLQuote);
		
		toSearch &= ~TBTRegistrySearch::EUiCookie;
		ExtendForAnotherTokenL(constraintBuf, toSearch);
		}
	
	if(toSearch)
		{
		// There is an unhandled search attribute that has been provided by the user.
		// If left the trailing SQL "AND" would trigger the KErrArgument error anyway.
		User::Leave(KErrArgument);
		}

	iQueryBuf.SetMaxLengthL(constraint.Length() + KSQLSelectAllConstrained().Length() + KDeviceTable().Length());
	iQueryBuf.Text().Format(KSQLSelectAllConstrained, &KDeviceTable, &constraint);
	}