authorisation/userpromptservice/database/source/upsdb.cpp
changeset 8 35751d3474b7
child 61 641f389e9157
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/authorisation/userpromptservice/database/source/upsdb.cpp	Thu Sep 10 14:01:51 2009 +0300
@@ -0,0 +1,511 @@
+/*
+* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+* Implements a read-only interface for UPS Database.
+*
+*/
+
+
+/**
+ @file
+ @internalTechnology
+ @prototype
+*/
+
+#include "upsdbw.h"
+#include "upscommon.h"
+
+using namespace UserPromptService;
+
+
+//
+//CDecisionView
+//
+
+CDecisionView::CDecisionView():CActive(EPriorityStandard)
+/**
+	Constructor for decision view object.
+ */
+	{
+	CActiveScheduler::Add(this);	
+	}
+
+
+
+CDecisionView::~CDecisionView()
+/**
+	Destructor for the decision view object.
+ */
+	{
+	iDbView.Close();
+	delete iColSet;
+	Deque();
+	}
+
+
+EXPORT_C CDecisionView* CDecisionView::NewLC()
+/**
+	Creates a decision view object. The function leaves, if creation of the view object fails.
+	
+	@return A pointer to the newly allocated view object, if creation is successful.
+	        The pointer is also put onto the cleanup stack.
+ */
+	{
+	CDecisionView* self = new(ELeave) CDecisionView();
+	CleanupStack::PushL(self);
+	return self;
+	}
+
+
+void CDecisionView::DoCancel()
+//From CActive
+	{
+	iDbView.Cancel();
+	if (iClientStatus)
+		{
+		User::RequestComplete(iClientStatus, KErrCancel);
+		}	
+	}
+
+
+TInt CDecisionView::RunError(TInt aError)
+//From CActive
+	{
+	if (iClientStatus)
+		{
+		User::RequestComplete(iClientStatus, aError);
+		}
+	return KErrNone;
+	}
+
+
+void CDecisionView::RunL() 
+//From CActive
+	{
+	TInt status = iStatus.Int();
+	User::LeaveIfError(status);
+	
+	if(status > 0)
+		{
+		iDbView.Evaluate(iStatus);
+		SetActive();
+		}
+	else
+		{
+		User::RequestComplete(iClientStatus,status);
+		}
+	}
+	
+		
+EXPORT_C void CDecisionView::EvaluateView(TRequestStatus& aStatus)
+/**
+	Performs all steps of the view evaluation, returning immediately and 
+	signalling when all steps are complete. 
+	
+	@param aStatus The request status used to contain completion information for the function.
+	               On completion, the status value should be interpreted as follows: 
+	               0, evaluation is complete.< 0, an error code.
+ */
+	{
+	__ASSERT_ALWAYS(!IsActive(), User::Panic(KDecisionViewPanic,KErrInUse));	
+	
+	aStatus = KRequestPending;
+	iClientStatus = &aStatus;	
+	
+	iDbView.Evaluate(iStatus);
+	
+	SetActive();
+	
+	}
+
+
+CDecisionRecord* CDecisionView::GenerateRecordL(RDbRowSet& aRowSet, CDbColSet* aColSet)
+/**
+	Retrieves all decision record fileds from the given rowset and generates
+	a decision record from these information.
+	
+	@param aRowSet A database rowset object.
+	@param aColSet A database column set object.
+	
+	@return The newly,created decision record if it is successful; otherwise, leaves.
+ */
+	{
+	TSecureId clientSid(aRowSet.ColUint32(aColSet->ColNo(KColClientSid))); 			 //Client Secure Id
+	TSecureId serverId = TSecureId(aRowSet.ColUint32(aColSet->ColNo(KColServerSid))); //Service Secure Id
+	TUid evaluatorId = TUid::Uid(aRowSet.ColUint32(aColSet->ColNo(KColEvaluatorId))); //Evaluator Uid
+	TUid serviceId = TUid::Uid(aRowSet.ColUint32(aColSet->ColNo(KColServiceId)));	 //Service Uid
+	TPtrC8 fingerprint = aRowSet.ColDes8(aColSet->ColNo(KColFingerprint));			 //Fingerprint
+	TPtrC8 clientEntity = aRowSet.ColDes8(aColSet->ColNo(KColClientEntity));			 //Client Entity
+	TInt8 result = aRowSet.ColInt8(aColSet->ColNo(KColResult));						 //Result
+	TUint16 ver = aRowSet.ColUint16(aColSet->ColNo(KColMajorPolicyVersion));			 //Major Policy Version
+	TUint32 recordId =  aRowSet.ColUint32(aColSet->ColNo(KColRecordId));				 //Unique Record ID
+	TUint32 evaluatorInfo = aRowSet.ColUint32(aColSet->ColNo(KColEvaluatorInfo));     //EvaluatorInfo
+		
+	//a stream is used to read long columns
+	TDbColNo col = aColSet->ColNo(KColDescription);
+	TInt len = aRowSet.ColLength(col);
+		
+	RBuf description;
+	CleanupClosePushL(description);
+	description.CreateL(len);
+		
+	RDbColReadStream str;
+	str.OpenLC(aRowSet,col);
+	str.ReadL(description,len);
+	str.Close();
+	CleanupStack::PopAndDestroy(&str);
+		
+	CDecisionRecord *retval = CDecisionRecord::NewL(clientSid,evaluatorId,serviceId,serverId,fingerprint,
+								 clientEntity,description,result,ver,evaluatorInfo,recordId);
+	
+	CleanupStack::PopAndDestroy(&description);
+	return retval;
+	}
+	
+		
+EXPORT_C CDecisionRecord* CDecisionView::NextDecisionL()
+/** 
+	Moves the cursor to the next row in the view object and returns the current decision row.
+ 	If there are no more rows, the cursor is positioned to the end of the view object.
+ 	
+ 	@return 0, If the cursor is positioned at the end of the view. Otherwise, current record. 
+ */
+	{
+	CDecisionRecord *record(0);
+	
+	if(iDbView.NextL())
+		{
+		iDbView.GetL();
+		record = GenerateRecordL(iDbView,iColSet);
+		}	
+	else
+		{
+		iDbView.Close();
+		}
+		
+	return record;
+	}
+
+
+//
+//CDecisionDb
+//
+
+
+CDecisionDb::CDecisionDb()
+/**
+	Constructor for read-only decision database object
+ */
+	{
+	
+	}
+
+
+CDecisionDb::~CDecisionDb()
+/**
+	Destructor for read-only decision database object
+ */
+	{
+	
+	}
+
+const TDesC* CDecisionDb::GetComparisonOperator(const TUint32& aFlag) const
+/**
+	Finds and returns the correspondent comparision operator string.
+	
+	@param aFlag 
+ */
+	{
+	UserPromptService::TComparisonOp op = static_cast<UserPromptService::TComparisonOp>(aFlag & 0xFFFF0000);
+	switch (op)
+		{
+		case UserPromptService::EEqual:
+			{
+			return &KSQLQueryEqual;
+			}
+		case UserPromptService::ENotEqual:
+			{
+			return &KSQLQueryNotEqual;
+			}
+		case UserPromptService::ELessThan:
+			{
+			return &KSQLQueryLessThan;
+			}
+		case UserPromptService::EGreaterThan:
+			{
+			return &KSQLQueryGreaterThan;
+			}
+		case UserPromptService::ELessThanOrEqual:
+			{
+			return &KSQLQueryLessThanOrEqual;
+			}
+		case UserPromptService::EGreaterThanOrEqual:
+			{
+			return &KSQLQueryGreaterThanOrEqual;
+			}
+		}
+	return &KSQLQueryEqual;
+	}
+
+
+void CDecisionDb::CreateSqlStatementLC(CDecisionFilter& aFilter, RBuf& aSql)
+/**
+	Creates an sql statement from a given filter.
+
+    @param aFilter A filter object used to create the SQL statement.
+    @param aSql    The newly created SQL statement.
+ */
+	{
+	//Estimate the maximum required buffer (maxLen) to save the sql statement.
+	//KSQLQueryBase must be in the statement at least.
+	TInt maxLen = KBaseSQLLength;
+	
+	//Get the bits belonging to ID values (ClientSid,EvaluatorId,ServiceId,ServerSid)
+	TUint32 combinedFlags = (aFilter.iSetFlag[KPosClientSid] | aFilter.iSetFlag[KPosEvaluatorId]   |
+						 	 aFilter.iSetFlag[KPosServiceId] | aFilter.iSetFlag[KPosServerSid]     |
+						 	 aFilter.iSetFlag[KPosFingerprint] | aFilter.iSetFlag[KPosClientEntity]|
+						 	 aFilter.iSetFlag[KPosMajorPolicyVersion] | aFilter.iSetFlag[KPosRecordId] |
+						 	 aFilter.iSetFlag[KPosDescription] | aFilter.iSetFlag[KPosResult] | 
+						 	 aFilter.iSetFlag[KPosEvaluatorInfo]);
+						 	
+	TUint16 flag = combinedFlags & 0x000006CF;
+	//Count how many bits are set, and add KMaxIntCondition for each set bit
+	while(flag != 0)
+		{
+		flag &= (flag-1);
+		maxLen += KMaxIntCondition;
+		}
+	//Get the bits belonging to string values (Fingerprint and ClientEntity)
+	flag = combinedFlags & 0x00000130;
+	//Count how many bits are set, and add KMaxStringCondition length for each set bit
+	while(flag != 0)
+		{
+		flag &= (flag-1);
+		maxLen += KMaxStringCondition;
+		}
+	
+	//Allocate the estimated number of bytes for the sql statement
+	aSql.CreateL(maxLen);
+	aSql.CleanupClosePushL();
+	//First copy the basic SQL statement
+	aSql.AppendFormat(KSQLQueryBase,&KDecisionTable);
+	
+	//If the filter is empty, there is no condition to add to the sql statement.
+	//So, simply return the base sql statement. In this case, all rows of
+	//the decision table are listed.
+	if(maxLen == KBaseSQLLength)
+		{
+		return;	
+		}
+	
+	//Filter is not empty, add 'WHERE' key word into the statement	
+	aSql.Append(KSQLQueryWhere);
+		
+	TBool multiple = EFalse;
+	//Append server SID if exists in the filter
+	AppendQueryInteger(aFilter.iServerSid.iId, aSql, multiple, aFilter.iSetFlag[KPosServerSid], KSetServerSid, KColServerSid);
+	//Append service UID if exists in the filter
+	AppendQueryInteger(aFilter.iServiceId.iUid, aSql, multiple, aFilter.iSetFlag[KPosServiceId], KSetServiceId, KColServiceId);
+	//Append client SID if exists in the filter
+	AppendQueryInteger(aFilter.iClientSid.iId, aSql, multiple, aFilter.iSetFlag[KPosClientSid], KSetClientSid, KColClientSid);		
+	//Append evaluator UID if exists in the filter
+	AppendQueryInteger(aFilter.iEvaluatorId.iUid, aSql, multiple, aFilter.iSetFlag[KPosEvaluatorId], KSetEvaluatorId, KColEvaluatorId);				
+	//Append major policy version if exists in the filter
+	AppendQueryInteger(aFilter.iMajorPolicyVersion, aSql, multiple, aFilter.iSetFlag[KPosMajorPolicyVersion], KSetMajorPolicyVersion, KColMajorPolicyVersion);
+	//Append record id if exists in the filter
+	AppendQueryInteger(aFilter.iRecordId, aSql, multiple, aFilter.iSetFlag[KPosRecordId], KSetRecordId, KColRecordId);		
+	//Append result if exists in the filter
+	AppendQueryInteger(aFilter.iResult, aSql, multiple, aFilter.iSetFlag[KPosResult], KSetResult, KColResult);		
+	//Append evaluator info if exists in the filter
+	AppendQueryInteger(aFilter.iEvaluatorInfo, aSql, multiple, aFilter.iSetFlag[KPosEvaluatorInfo], KSetEvaluatorInfo, KColEvaluatorInfo);		
+	//Append description if exists in the filter
+	AppendQueryStringL(*aFilter.iDescription, aSql, multiple, aFilter.iSetFlag[KPosDescription], KSetDescription, KColDescription);
+	
+	//Append fingerprint if exists in the filter	
+	//Convert 8-bit value to 16-bit
+	if(aFilter.iFingerprint)
+		{
+		HBufC* fp = HBufC::NewLC(aFilter.iFingerprint->Length());
+		TPtr ptrFp(fp->Des());
+		ptrFp.Copy(*aFilter.iFingerprint);
+	
+		AppendQueryStringL(*fp, aSql, multiple, aFilter.iSetFlag[KPosFingerprint], KSetFingerprint, KColFingerprint);
+		CleanupStack::PopAndDestroy(fp);
+		}
+	
+	//Append client entity if exists in the filter
+	//Convert 8-bit value to 16-bit 
+	if(aFilter.iClientEntity)
+		{
+		HBufC* ce = HBufC::NewLC(aFilter.iClientEntity->Length());
+		TPtr ptrCe(ce->Des());
+		ptrCe.Copy(*aFilter.iClientEntity);
+		
+		AppendQueryStringL(*ce, aSql, multiple, aFilter.iSetFlag[KPosClientEntity], KSetClientEntity, KColClientEntity);		
+		CleanupStack::PopAndDestroy(ce);
+		}
+	}
+
+
+void CDecisionDb::AppendQueryInteger(const TUint32& aValue, TDes& aSql, TBool& aMultiple, const TUint32& aFlag, const TUint32& aSetCol, const TDesC& aColName)
+/**
+	Appends an integer-based query key field to an SQL query string.
+	
+	@param aValue 	 The integer value which will be added to the query.
+	@param aSql   	 The SQL query string.
+	@param aMultiple EFalse, if there is only one query key in the query string. Otherwise, ETrue.
+	@param aFlag 	 The flag value corresponding to the query key.
+	@param aSetCol 	 A constant value indicating whether or not a specific column is set. 
+	@param aColName  The column name of the query key.
+ */
+	{
+	if(aFlag & aSetCol)
+		{
+		if(aMultiple)
+			{
+			aSql.Append(KSQLQueryAnd);
+			}
+		else
+			{
+			aMultiple=ETrue;
+			}
+			
+		aSql.Append(aColName);
+		aSql.AppendFormat(KSQLQueryString,GetComparisonOperator(aFlag));	
+		aSql.AppendFormat(KSQLQueryConditionInt,aValue);
+		}
+	}
+	
+
+void CDecisionDb::AppendQueryStringL(const TDesC& aValue, TDes& aSql, TBool& aMultiple, const TUint32& aFlag, const TUint32& aSetCol, const TDesC& aColName)
+/**
+	Appends an string query key to an SQL query string.
+	
+	@param aValue 	 The string value which will be added to the query.
+	@param aSql   	 The SQL query string.
+	@param aMultiple EFalse, if there is only one query key in the query string. Otherwise, ETrue.
+	@param aFlag 	 The flag value corresponding to the query key.
+	@param aSetCol 	 A constant value indicating whether or not a specific column is set. 
+	@param aColName  The column name of the query key.
+ */
+	{
+	if(aFlag & aSetCol)
+		{
+		if(aMultiple)
+			{
+			aSql.Append(KSQLQueryAnd);
+			}
+		else
+			{
+			aMultiple=ETrue;
+			}
+		
+		aSql.Append(aColName);
+		
+		if(aValue.Length() != 0)
+			{
+			//Scan for single quote
+			RBuf dbValue;
+			DoubleSingleQuotesL(aValue, dbValue);
+			dbValue.CleanupClosePushL();
+						
+			aSql.AppendFormat(KSQLQueryString,GetComparisonOperator(aFlag));	
+			aSql.AppendFormat(KSQLQueryConditionString,&dbValue);
+			
+			CleanupStack::PopAndDestroy(&dbValue);
+			}
+		else
+			{
+			aSql.Append(KSQLQueryNull);
+			}
+		}
+	}
+
+	
+void CDecisionDb::DoubleSingleQuotesL(const TDesC& aSource, RBuf& aDestination)
+/**
+	Copies a source descriptor into a destination descriptor. If a single quote
+	character is found an extra single quote is copied to the destination.
+	Because, it is not possible to search for a string in SQL with single quote (').
+	
+	@param aSource      A source descriptor.
+	@param aDestination A destination descriptor.
+ */
+	{
+	_LIT(KSingleQuote,"'");
+
+	aDestination.Close();
+	
+	if(aSource.FindF(KSingleQuote) > KErrNotFound)
+		{
+		const TUint16 KSingleQuoteHex = 0x27;
+		TInt len = aSource.Length();
+		
+		//Define a temporary buffer and set its maximum size to twice of the original (if it contained all quotes!)
+		RBuf temp;
+		temp.CreateL(len*2);
+		CleanupClosePushL(temp);
+		
+		const TUint16 *ptrSrc = aSource.Ptr();
+		TUint16 *ptrDes = (TUint16 *)temp.Ptr();
+		TInt srcIndex=0;
+		TInt desIndex=0;
+		
+		for(srcIndex=0; srcIndex<len; ++srcIndex,++desIndex)
+			{
+			ptrDes[desIndex]	= ptrSrc[srcIndex];
+			if(ptrSrc[srcIndex] == KSingleQuoteHex) //is single quote?
+				{
+				ptrDes[++desIndex] = ptrSrc[srcIndex];//add extra single quote
+				}
+			}
+			
+		//Set the actual length	
+		temp.SetLength(desIndex);
+		//Copy temp into destination. destination's maximum length is the same as the length of temp
+		aDestination.CreateL(temp);
+		CleanupStack::PopAndDestroy(&temp);
+		}
+	else
+		{
+		//there is no single quote, just copy it
+		aDestination.CreateL(aSource);
+		}
+	}
+		
+		
+EXPORT_C CDecisionView *CDecisionDb::CreateViewL(CDecisionFilter& aFilter)
+/**
+	Generates an SQL view rowset to the decision table by using a filter.
+	The view rowset contains a set of rows which depend on the filter.
+	  
+	@param aFilter 		 A filter object to query the decision database
+	@param aDecisionView A decision view object containing handle to the newly created SQL view rowset.
+ */		
+	{
+	RBuf sqlStatement;
+	CreateSqlStatementLC(aFilter, sqlStatement);
+	
+	CDecisionView *dbView = CDecisionView::NewLC();
+		
+	User::LeaveIfError(dbView->iDbView.Prepare(iDatabase,TDbQuery(sqlStatement),TDbWindow::EUnlimited));
+		
+	dbView->iColSet = dbView->iDbView.ColSetL();	
+		
+	CleanupStack::Pop(dbView);
+	CleanupStack::PopAndDestroy(&sqlStatement); //sqlStatement
+	
+	return dbView;
+	}
+