// Copyright (c) 2006-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 "srvreqs.h"
#include "backup.h"
#include "srvsubsess.h"
#include "log.h"
#include "centralrepositoryinternal.h"
#include <e32def_private.h>

using namespace NCentralRepositoryConstants;

CServerSubSession::CServerSubSession(CServerSession* aSession)
 : iSession(aSession), iInitialised(EFalse)
	{
	}

CServerSubSession::~CServerSubSession()
	{
#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE1("~CServerSubSession() UID: 0x%x\n",uid.iUid);
#endif

	iRepository.Close();
	iFindResult.Close();
	iInitialised = EFalse;
	}

// if session ServiceL Leaves, execution resumes in this method.
// this allows us to panic clients using bad descriptors, to deal with OOM conditions
// and to fail transactions with the correct reason: OOM etc.
void CServerSubSession::ServiceError(TInt aError)
	{
	// ensure any transaction is failed for the reason aError
	iRepository.FailTransaction(aError, KUnspecifiedKey);
	}

TInt CServerSubSession::ServiceL(const RMessage2& aMessage)
	{
	const TClientRequest msg(aMessage);

	struct SAction
		{
		TServerRequest req;
		TInt (CServerSubSession::*groupFuncL)(const TClientRequest&, TServerFunc);
		TServerFunc funcL;
		};

	static const SAction actionTable[] =
		{
			{EInitialise,				&CServerSubSession::GeneralOperationsL,	&CServerSubSession::InitialiseL},
			{ECreateInt,				&CServerSubSession::WriteOperationsL,	&CServerSubSession::CreateIntL},
			{ECreateReal,				&CServerSubSession::WriteOperationsL,	&CServerSubSession::CreateRealL},
			{ECreateString,				&CServerSubSession::WriteOperationsL,	&CServerSubSession::CreateStringL},
			{EDelete,					&CServerSubSession::WriteOperationsL,	&CServerSubSession::DeleteL},
			{EGetInt,					&CServerSubSession::ReadOperationsL,	&CServerSubSession::GetIntL},
			{ESetInt,					&CServerSubSession::WriteOperationsL,	&CServerSubSession::SetIntL},
			{EGetReal,					&CServerSubSession::ReadOperationsL,	&CServerSubSession::GetRealL},
			{ESetReal,					&CServerSubSession::WriteOperationsL,	&CServerSubSession::SetRealL},
			{EGetString,				&CServerSubSession::ReadOperationsL,	&CServerSubSession::GetStringL},
			{ESetString,				&CServerSubSession::WriteOperationsL,	&CServerSubSession::SetStringL},
			{EFind,						&CServerSubSession::ReadOperationsL,	&CServerSubSession::FindL},
			{EFindEqInt,				&CServerSubSession::ReadOperationsL,	&CServerSubSession::FindEqIntL},
			{EFindEqReal,				&CServerSubSession::ReadOperationsL,	&CServerSubSession::FindEqRealL},
			{EFindEqString,				&CServerSubSession::ReadOperationsL,	&CServerSubSession::FindEqStringL},
			{EFindNeqInt,				&CServerSubSession::ReadOperationsL,	&CServerSubSession::FindNeqIntL},
			{EFindNeqReal,				&CServerSubSession::ReadOperationsL,	&CServerSubSession::FindNeqRealL},
			{EFindNeqString,			&CServerSubSession::ReadOperationsL,	&CServerSubSession::FindNeqStringL},
			{EGetFindResult,			&CServerSubSession::ReadOperationsL,	&CServerSubSession::GetFindResultL},
			{ENotifyRequestCheck,		&CServerSubSession::GeneralOperationsL,	&CServerSubSession::NotifyRequestCheck},
			{ENotifyRequest,			&CServerSubSession::GeneralOperationsL,	&CServerSubSession::NotifyRequest},
			{ENotifyCancel,				&CServerSubSession::GeneralOperationsL,	&CServerSubSession::NotifyCancel},
			{ENotifyCancelAll,			&CServerSubSession::GeneralOperationsL,	&CServerSubSession::NotifyCancelAll},
			{EGroupNotifyRequest,		&CServerSubSession::GeneralOperationsL,	&CServerSubSession::GroupNotifyRequest},
			{EGroupNotifyCancel,		&CServerSubSession::GeneralOperationsL,	&CServerSubSession::GroupNotifyCancel},
			{EReset,					&CServerSubSession::ResetOperationsL,	&CServerSubSession::ResetL},
			{EResetAll,					&CServerSubSession::ResetOperationsL,	&CServerSubSession::ResetAllL},
			{ETransactionStart,			&CServerSubSession::GeneralOperationsL,	&CServerSubSession::TransactionStart},
  			{ETransactionCommit,		&CServerSubSession::GeneralOperationsL,	&CServerSubSession::TransactionCommitL},
  			{ETransactionCancel,		&CServerSubSession::GeneralOperationsL,	&CServerSubSession::TransactionCancel},
			{EMove,						&CServerSubSession::WriteOperationsL,	&CServerSubSession::MoveL},
			{ETransactionState,			&CServerSubSession::GeneralOperationsL,	&CServerSubSession::TransactionStateL},
			{ETransactionFail,			&CServerSubSession::GeneralOperationsL,	&CServerSubSession::TransactionFail},
			{EDeleteRange,				&CServerSubSession::WriteOperationsL,	&CServerSubSession::DeleteRangeL},
			{EGetMeta,					&CServerSubSession::ReadOperationsL,	&CServerSubSession::GetMeta}
		};

#ifdef SRVSUBSESS_TRACE
	const TPtrC actionTableNames[] =
		{
			_L("EInitialize"),
			_L("ECreateInt"),
			_L("ECreateReal"),
			_L("ECreateString"),
			_L("EDelete"),
			_L("EGetInt"),
			_L("ESetInt"),
			_L("EGetReal"),
			_L("ESetReal"),
			_L("EGetString"),
			_L("ESetString"),
			_L("EFind"),
			_L("EFindEqInt"),
			_L("EFindEqReal"),
			_L("EFindEqString"),
			_L("EFindNeqInt"),
			_L("EFindNeqReal"),
			_L("EFindNeqString"),
			_L("EGetFindResult"),
			_L("ENotifyRequestCheck"),
			_L("ENotifyRequest"),
			_L("ENotifyCancel"),
			_L("ENotifyCancelAll"),
			_L("EGroupNotifyRequest"),
			_L("EGroupNotifyCancel"),
			_L("EReset"),
			_L("EResetAll"),
			_L("ETransactionStart"),
	  		_L("ETransactionCommit"),
	  		_L("ETransactionCancel"),
			_L("EMove"),
			_L("ETransactionState"),
			_L("ETransactionFail"),
			_L("EDeleteRange"),
			_L("EGetMeta")
		};
#endif

	TInt r;
	TServerRequest fn = static_cast<TServerRequest>(aMessage.Function());

	__ASSERT_ALWAYS(iInitialised || fn==EInitialise, PanicClient(ESessionNotInitialised, msg));
	// In this assert we use (ELastInTable - 1) rather than ELastInTable because EClose is handled in the session
	// rather than the subsession, consiquently the actionTable array is one element shorter than ELastInTable
	__ASSERT_ALWAYS((fn < (ELastInTable)) && (fn >= EInitialise), PanicClient(EBadMessageNumber, msg));

	if (EInitialise != fn)
		{
		iRepository.AccessRepositoryL();
		}
#ifdef SRVSUBSESS_TRACE

	if (EInitialise != fn)
		{
		TUid uid = RepositoryUid();

		__SRVSUBSESS_TRACE2("CServerSubSession::ServiceL - UID: 0x%x %S\n",uid.iUid,&actionTableNames[fn]);
		}
	else
		{
		__SRVSUBSESS_TRACE1("CServerSubSession::ServiceL - UID: 0x?? %S\n",&actionTableNames[fn]);
		}

#endif
	// plus need to check we are initialised
	// this comment removes a false positive from the coverity output.  if fn >= ELastInTable then this code
	// will assert (see above).  but coverity doesn't consider this and therefore complains that there is a
	// posibility that actionTable could be indexed beyond it's length
	//coverity[overrun-local]
	r = (this->*actionTable[fn].groupFuncL)(aMessage, actionTable[fn].funcL);

	return r;
	}

//method allows transactions and notify requests to get through during backup/restore
//process to prevent them from being blocked.
//Transactions being blocked would lead clients to be panicked
//if they were trying to open a second transaction in the same session.
// Notify cancels must be allowed through because they must always succeed.
TInt CServerSubSession::GeneralOperationsL(const TClientRequest& aMessage, TServerFunc aFuncL)
	{
	ASSERT(aFuncL != NULL);
	return (this->*aFuncL)(aMessage);
	}

// method allows read operations to share transaction-related tasks.
// Read operations are allowed only during backup process.
// During restore it fails transactions with KErrLocked and returns KErrAbort
// and if it is a standalone read oparation it rejects it with KErrServerBusy.
TInt CServerSubSession::ReadOperationsL(const TClientRequest& aMessage, TServerFunc aFuncL)
	{
	TInt backupStatus = CRepositoryBackupClient::GetBackupStatus();

	if (iRepository.IsInFailedTransaction())
		{
		return KErrAbort;
		}
	else if (iRepository.IsInTransaction() && (backupStatus == ERestoreInProgress) )
	    {
	    iRepository.FailTransaction(KErrLocked,KUnspecifiedKey);
	    return KErrAbort;
	    }
	else if (backupStatus == ERestoreInProgress)
	    {
	    return KErrServerBusy;
	    }

	ASSERT(aFuncL != NULL);
	return (this->*aFuncL)(aMessage);
	}

// method allows write operations to share transaction-related tasks
// All write operations are not allowed either during backup or restore process.
// If backup or restore is in progress it fails transaction with KErrLocked,
// returns KErrAbort or if it is a standalone operation it returns KErrServerBusy.
TInt CServerSubSession::WriteOperationsL(const TClientRequest& aMessage, TServerFunc aFuncL)
	{
	TInt backupStatus = CRepositoryBackupClient::GetBackupStatus();

	if (iRepository.IsInFailedTransaction())
		{
		return KErrAbort;
		}
	else if (iRepository.IsInTransaction() && (backupStatus != ENoBackupActivty) )
	    {
	    iRepository.FailTransaction(KErrLocked,KUnspecifiedKey);
	    return KErrAbort;
	    }
    else if (backupStatus != ENoBackupActivty)
        {
        return KErrServerBusy;
        }

	// if not already in a transaction, create a temporary concurrent read/write transaction
	const TBool tempTransaction = !iRepository.IsInTransaction();
	if (tempTransaction)
		{
		// concurrent read/write transaction is guaranteed to start
		iRepository.StartTransaction(EConcurrentReadWriteTransaction);
		// to protect against Leaves:
		iRepository.CleanupCancelTransactionPushL();
		}
	else
		{
		if (iRepository.IsInActiveReadTransaction())
			{
			// must be a read/write transaction to continue
			iRepository.AttemptPromoteTransactionToReadWrite();
			// Note we don't check the return value of the above and return it here.
			// Instead we call the next level write function and expect it to have the
			// following code:
			//	if (iRepository.IsInActiveReadTransaction())
			//		{
			//		return iRepository.FailTransaction(KErrLocked, key);
			//		}
			// this ensures CommitTransaction reports the failing key.
			}
		// Note ServiceError will fail the transaction if write operation leaves
		}

	// call the server function
	ASSERT(aFuncL != NULL);
	TInt result = (this->*aFuncL)(aMessage);

	// commit the temporary transaction
	if (tempTransaction)
		{
		CleanupStack::Pop(); // remove cleanup item from earlier
		// absorb result and keyInfo from commit of temporary transaction
		TUint32 tempKeyInfo;
		User::LeaveIfError(iRepository.CommitTransaction(tempKeyInfo));
		}
	return result;
	}

TInt CServerSubSession::ResetOperationsL(const TClientRequest& aMessage, TServerFunc aFuncL)
	{
	// reset operations are not currently supported in transactions
	if (iRepository.IsInTransaction())
		{
		// fail transaction otherwise client may be misled to believe operation worked
		return iRepository.FailTransaction(KErrNotSupported, KUnspecifiedKey);
		}
   //can't reset when backup or restore is in progress
   else if (CRepositoryBackupClient::GetBackupStatus() != ENoBackupActivty)
        {
        return KErrServerBusy;
        }
	ASSERT(aFuncL != NULL);
	return (this->*aFuncL)(aMessage);
	}

TInt CServerSubSession::InitialiseL(const TClientRequest& aMessage)
	{
	__ASSERT_ALWAYS(!iInitialised,
		PanicClient(ESessionAlreadyInitialised, aMessage));
	// We let anyone to open a repository...
	// it's not considered a breach of security to let people know
	// that a repository is there...
	TUid uid = TUid::Uid(aMessage.Int0());

	__SRVSUBSESS_TRACE1("CServerSubSession::InitialiseL UID: 0x%x\n",uid.iUid);

	// Calls iObserver->AccessL internally
	iRepository.OpenL(uid, iNotifier);

	iInitialised = ETrue;

	return KErrNone;
	}

TInt CServerSubSession::CreateIntL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	// cannot make changes in a read transaction - upgrade must have failed due to write lock being used
	if (iRepository.IsInActiveReadTransaction())
		{
		return iRepository.FailTransaction(KErrLocked, key);
		}

	if(KErrNone !=  CheckPolicy(aMessage,iRepository.GetWriteAccessPolicy(key),
			__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSubSession::CreateIntL - Attempt made to create a setting")))
		return iRepository.FailTransaction(KErrPermissionDenied, key);

	TInt val = aMessage.Int1();

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE2("CServerSubSession::CreateIntL UID: 0x%x Key=0x%x\n",uid.iUid,key);
#endif

	TInt r = iRepository.TransactionCreateL(key, val, NULL);

	return r;
	}

TInt CServerSubSession::CreateRealL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	// cannot make changes in a read transaction - upgrade must have failed due to write lock being used
	if (iRepository.IsInActiveReadTransaction())
		{
		return iRepository.FailTransaction(KErrLocked, key);
		}

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetWriteAccessPolicy(key),
			__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::CreateRealL - Attempt made to create a setting")))
		return iRepository.FailTransaction(KErrPermissionDenied, key);

	TReal val;
	TPckg<TReal> p(val);
	aMessage.ReadL(1, p);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE2("CServerSubSession::CreateRealL UID: 0x%x Key=0x%x\n",uid.iUid,key);
#endif
	TInt r = iRepository.TransactionCreateL(key, val, NULL);

	return r;
	}

TInt CServerSubSession::CreateStringL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	// cannot make changes in a read transaction - upgrade must have failed due to write lock being used
	if (iRepository.IsInActiveReadTransaction())
		{
		return iRepository.FailTransaction(KErrLocked, key);
		}

	// sometime: must ensure bad descriptor results in client being panic'd

	// check for descriptor-too-long was previously on the client side,
	// hence test code expects KErrArgument response before KErrPermissionDenied
	TInt length = aMessage.GetDesLengthL(1);
	if (length > KMaxBinaryLength)
		{
		return iRepository.FailTransaction(KErrArgument, key);
		}

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetWriteAccessPolicy(key),
			__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::CreateStringL - Attempt made to create a setting")))
		return iRepository.FailTransaction(KErrPermissionDenied, key);

	TBuf8<KMaxBinaryLength> val;
	aMessage.ReadL(1, val);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE2("CServerSubSession::CreateStringL UID: 0x%x Key=0x%x\n",uid.iUid,key);
#endif

	TInt error = iRepository.TransactionCreateL(key, val, NULL);

	return error;
	}

TInt CServerSubSession::DeleteL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	// cannot make changes in a read transaction - upgrade must have failed due to write lock being used
	if (iRepository.IsInActiveReadTransaction())
		{
		return iRepository.FailTransaction(KErrLocked, key);
		}

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetWriteAccessPolicy(key),
			__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::DeleteL - Attempt made to delete a setting")))
		return iRepository.FailTransaction(KErrPermissionDenied, key);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE2("CServerSubSession::DeleteL UID: 0x%x Key=0x%x\n",uid.iUid,key);
#endif

	TInt r = iRepository.TransactionDeleteL(key);

	return r;
	}

TInt CServerSubSession::GetIntL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetReadAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::GetIntL - Attempt made to read a setting")))
		return KErrPermissionDenied;

	TInt val;
	TInt error = iRepository.Get(key, val);

	if (error == KErrNone)
		{
		TPckg<TInt> p(val);
		aMessage.WriteL(1, p);
		}

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::GetIntL UID: 0x%x Key=0x%x Value=%d\n",uid.iUid,key,val);
		}
	else
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::GetIntL **Failure** UID: 0x%x Key=0x%x\n",uid.iUid,key);
		}
#endif

	return error;
	}

TInt CServerSubSession::SetIntL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	// cannot make changes in a read transaction - upgrade must have failed due to write lock being used
	if (iRepository.IsInActiveReadTransaction())
		{
		return iRepository.FailTransaction(KErrLocked, key);
		}

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetWriteAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::SetIntL - Attempt made to write a setting")))
		return iRepository.FailTransaction(KErrPermissionDenied, key);

	TInt val = aMessage.Int1();
	TInt error = iRepository.TransactionSetL(key, val);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::SetIntL UID: 0x%x Key=0x%x Value=%d\n",uid.iUid,key,val);
		}
	else
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::SetIntL **Failure** UID: 0x%x Key=0x%x Value=%d\n",uid.iUid,key,val);
		}
#endif
	return error;
	}

TInt CServerSubSession::GetRealL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetReadAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::GetRealL - Attempt made to read a setting")))
		return KErrPermissionDenied;

	TReal val;
	TInt error = iRepository.Get(key, val);

	if(error==KErrNone)
		{
		TPckg<TReal> p(val);
		aMessage.WriteL(1, p);
		}

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::GetRealL UID: 0x%x Key=0x%x Value=%d\n",uid.iUid,key,val);
		}
	else
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::GetRealL **Failure** UID: 0x%x Key=0x%x\n",uid.iUid,key);
		}
#endif
	return error;
	}

TInt CServerSubSession::SetRealL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	// cannot make changes in a read transaction - upgrade must have failed due to write lock being used
	if (iRepository.IsInActiveReadTransaction())
		{
		return iRepository.FailTransaction(KErrLocked, key);
		}

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetWriteAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::SetRealL - Attempt made to write a setting")))
		return iRepository.FailTransaction(KErrPermissionDenied, key);

	TReal val;
	TPckg<TReal> p(val);
	aMessage.ReadL(1, p);

	TInt error = iRepository.TransactionSetL(key, val);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::SetRealL UID: 0x%x Key=0x%x Value=%d\n",uid.iUid,key,val);
		}
	else
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::SetRealL **Failure** UID: 0x%x Key=0x%x Value=%d\n",uid.iUid,key,val);
		}
#endif

	return error;
	}

TInt CServerSubSession::GetStringL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetReadAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::GetStringL - Attempt made to read a setting")))
		return KErrPermissionDenied;

	TBuf8<KMaxBinaryLength> val;

	TInt error = iRepository.Get(key, val);

	if(error==KErrNone)
		{
		TInt clientMaxDescriptorLength;
		TPckg<TInt> pInt (clientMaxDescriptorLength);
		aMessage.Read(2, pInt);

		TInt descriptorLength = val.Length();

		// write the descriptor length to aMessage
		TPckg<TInt> p(descriptorLength);
		error = aMessage.Write(2, p);

		if(error==KErrNone)
			{
			if(descriptorLength > clientMaxDescriptorLength)
				{
				// if it is, fill the descriptor up to its max length
				error = aMessage.Write(1, val.Left(clientMaxDescriptorLength));

				// if client-side descriptor is too small to take the value, which it is, returns KErrOverflow
				if(error == KErrNone)
					{
					error = KErrOverflow;
					}
				}
			else
				{
				error = aMessage.Write(1, val);
				}

#ifdef SRVSUBSESS_TRACE
			TUid uid = RepositoryUid();

			if (error == KErrNone)
				{
				__SRVSUBSESS_TRACE3("CServerSubSession::GetStringL UID: 0x%x Key=0x%x Value=%S\n",uid.iUid,key,&val);
				}
			else
				{
				__SRVSUBSESS_TRACE2("CServerSubSession::GetStringL **Failure** UID: 0x%x Key=0x%x\n",uid.iUid,key);
				}
#endif
			}

		// if error is KErrOverflow should not failing transaction
		if ((error != KErrNone) && (error != KErrOverflow))
			{
			// ServiceError will fail transaction
			User::Leave(error);
			}
		}
	return error;
	}

TInt CServerSubSession::SetStringL(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	// cannot make changes in a read transaction - upgrade must have failed due to write lock being used
	if (iRepository.IsInActiveReadTransaction())
		{
		return iRepository.FailTransaction(KErrLocked, key);
		}

	// check for descriptor-too-long was previously on the client side,
	// hence test code expects KErrArgument response before KErrPermissionDenied
	TInt length = aMessage.GetDesLengthL(1);
	if (length > KMaxBinaryLength)
		{
		return iRepository.FailTransaction(KErrArgument, key);
		}

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetWriteAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::SetStringL - Attempt made to write a setting")))
		return iRepository.FailTransaction(KErrPermissionDenied, key);

	TBuf8<KMaxBinaryLength> val;
	aMessage.ReadL(1, val);  // no error if too long, truncated instead

	TInt error = iRepository.TransactionSetL(key, val);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::SetStringL UID: 0x%x Key=0x%x Value=%S\n",uid.iUid,key,&val);
		}
	else
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::SetStringL **Failure** UID: 0x%x Key=0x%x\n",uid.iUid,key);
		}
#endif

	return error;
	}

TInt CServerSubSession::GetMeta(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

	if(KErrNone != CheckPolicy(aMessage,iRepository.GetReadAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::GetMeta - Attempt made to read a setting")))
		return KErrPermissionDenied;

	TUint32 meta;
	TInt error = iRepository.GetMeta(key, meta);

	if (error == KErrNone)
		{
		TPckg<TUint32> p(meta);
		error = aMessage.Write(1, p);
		}

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::GetMeta UID: 0x%x Key=0x%x Meta=0x%x\n",uid.iUid,key,meta);
		}
	else
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::GetMeta **Failure** UID: 0x%x Key=0x%x\n",uid.iUid,key);
		}
#endif

	return error;
	}

TInt CServerSubSession::FindL(const TClientRequest& aMessage)
	{
	// PLATSEC NOTE:
	// There are no read policy checks on FindL.
	// Client is returned the full list of keys whether they have read permission or not.
	// They were able to find this out by brute force using FindL on single setting ranges
	// anyway (because it would return KErrPermissionDenied if it existed, KErrNotFound otherwise).
	// Revealing the existence of settings is not considered a breach of security.
	TKeyFilter keyIdentifier;
	TPckg<TKeyFilter> p(keyIdentifier);
	aMessage.Read(0, p);
	// we reset results first since we do not police GetResult
	// and this way we can guarantee no results are available if access not granted
	iFindResult.Reset();
	
	RArray<TUint32> settingsToSend;
	CleanupClosePushL(settingsToSend);

	TInt error=KErrNone;
	TRAP(error,iRepository.FindL(keyIdentifier.iPartialId, keyIdentifier.iIdMask,settingsToSend,KCentRepFindBufSize,iFindResult));	
	if (error==KErrNone)
		{
		//write back the total number of settingsFound;
		TInt numSettings=settingsToSend.Count()+iFindResult.Count();
		TPtrC8 count(reinterpret_cast<TUint8*>(&numSettings),sizeof(TUint32));
		error=aMessage.Write(2,count);
		if (error==KErrNone)
			{
			TPtrC8 p(reinterpret_cast<TUint8*>(&(settingsToSend[0])), (settingsToSend.Count())*sizeof(TUint32));
			error=aMessage.Write(2,p,4);
			}
	
#ifdef SRVSUBSESS_TRACE
		TUid uid = RepositoryUid();
		if (error == KErrNone)
			{
			__SRVSUBSESS_TRACE4("CServerSubSession::FindL UID: 0x%x Key=0x%x Mask=0x%x Value=%S\n",uid.iUid,keyIdentifier.iPartialId,
					keyIdentifier.iIdMask,&p);
			}
		else
			{
			__SRVSUBSESS_TRACE4("CServerSubSession::FindL (failed write) UID: 0x%x Key=0x%x Mask=0x%x Value=%S\n",uid.iUid,keyIdentifier.iPartialId,
					keyIdentifier.iIdMask,&p);			
			}
#endif
		}
	CleanupStack::PopAndDestroy(); //settingsToSend
	
	if (error != KErrNone)
		{
		iFindResult.Reset();
		if ((error != KErrNone) && (error != KErrNotFound))
			{
			// ServiceError will fail transaction
			User::Leave(error);
			}
		}
	return error;
	}

TInt CServerSubSession::FindEqIntL(const TClientRequest& aMessage)
	{
	TInt val = aMessage.Int1();
	// PlatSec check done in FindValueL
	return FindValueL(aMessage, val);
	}

TInt CServerSubSession::FindEqRealL(const TClientRequest& aMessage)
	{
	TReal val;
	TPckg<TReal> p(val);
	aMessage.Read(1, p);
	// PlatSec check done in FindValueL
	return FindValueL(aMessage, val);
	}

TInt CServerSubSession::FindEqStringL(const TClientRequest& aMessage)
	{
	TBuf8<KMaxBinaryLength> val;
	aMessage.ReadL(1, val);  // no error if too long, truncated instead
	// PlatSec check done in FindValueL
	return FindValueL(aMessage, val);
	}

TInt CServerSubSession::FindNeqIntL(const TClientRequest& aMessage)
	{
	TInt val = aMessage.Int1();
	// PlatSec check done in FindValueL
	return FindValueL(aMessage, val, ENotEqual);
	}

TInt CServerSubSession::FindNeqRealL(const TClientRequest& aMessage)
	{
	TReal val;
	TPckg<TReal> p(val);
	aMessage.Read(1, p);
	// PlatSec check done in FindValueL
	return FindValueL(aMessage, val, ENotEqual);
	}

TInt CServerSubSession::FindNeqStringL(const TClientRequest& aMessage)
	{
	TBuf8<KMaxBinaryLength> val;
	aMessage.ReadL(1, val);  // no error if too long, truncated instead
	// PlatSec check done in FindValueL
	return FindValueL(aMessage, val, ENotEqual);
	}

template <class T>
TInt CServerSubSession::FindValueL(const TClientRequest& aMessage, const T& aVal,TComparison aComparison)
	{
	// IMPORTANT PLATSEC NOTE:
	// MUST return KErrPermissionDenied if read policy of ANY setting in the search range not passed.
	// MUST NOT merely check read policy of matching entries, otherwise it is possible to determine
	// secret values by brute force: Using single-value ranges, cycling through the possible values and
	// confirming a match when it returns KErrPermissionDenied rather than KErrNotFound.
	TKeyFilter keyIdentifier;
	TPckg<TKeyFilter> p(keyIdentifier);
	aMessage.Read(0, p);
	// we reset results first since we do not police GetResult
	// and this way we can guarantee no results are available if access not granted
	iFindResult.Reset();
	RSettingPointerArray settings;
	CleanupClosePushL(settings);
	TInt error = iRepository.FindSettings(keyIdentifier.iPartialId, keyIdentifier.iIdMask, settings);
	if (error == KErrNone)
		{
		//perform the read checking policies first
		TUint32 dummyErrId;
		error=iRepository.CheckPermissions(settings,aMessage,
		__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::FindValueL - Attempt made to search settings"),ETrue,dummyErrId);
		if (error==KErrPermissionDenied)
			iFindResult.Reset();

		//now if everything passes, do perform the FindValue
		if (error==KErrNone)
			{
			TRAP(error,iRepository.FindCompareL(settings,aVal,aComparison,iFindResult));
			if (error==KErrNone)
				{
				const TInt numSettings = iFindResult.Count();
				const TInt numInitial = numSettings > KCentRepFindBufSize ? KCentRepFindBufSize : numSettings;
				RArray<TUint32> settingsToSend;
				CleanupClosePushL(settingsToSend);
				
				//reserve memory for everything that needs to be added to the array
				settingsToSend.Reserve(numInitial);
				
				//first append the number of found settings
				settingsToSend.AppendL(numSettings);

				//now append up to KCentRepFindBufSize settings
				for(TInt i = 0; i < numInitial; i++)
					{
					settingsToSend.AppendL(iFindResult[0]);
					iFindResult.Remove(0);
					}
					
				if(iFindResult.Count() == 0)
					{
					iFindResult.Reset();
					}

				//send:
				//1 - the count of total settings found
				//2 - the settings that fit in the buffer allocated for the first IPC 
				TPtrC8 p(reinterpret_cast<TUint8*>(&(settingsToSend[0])), (numInitial+1)*sizeof(TUint32));
				error = aMessage.Write(2, p);

	#ifdef SRVSUBSESS_TRACE
				TUid uid = RepositoryUid();
				
				__SRVSUBSESS_TRACE4("CServerSubSession::FindValueL UID: 0x%x Key=0x%x Mask=0x%x Value=%S\n",uid.iUid,keyIdentifier.iPartialId, 
						keyIdentifier.iIdMask,&p);
	#endif
				CleanupStack::PopAndDestroy(); //settingsToSend		
				}
			}
		}
	if ((error != KErrNone) && (error != KErrNotFound) && (error != KErrPermissionDenied))
		{
		iFindResult.Reset();
		CleanupStack::PopAndDestroy(); //settings

		// ServiceError will fail transaction
		User::Leave(error);
		}
#ifdef SRVSUBSESS_TRACE
	else
		{
		TUid uid = RepositoryUid();

		__SRVSUBSESS_TRACE3("CServerSubSession::FindValueL **Failure** UID: 0x%x Key=0x%x Mask=0x%x\n",uid.iUid,keyIdentifier.iPartialId,
				keyIdentifier.iIdMask);
		}
#endif

	CleanupStack::PopAndDestroy(); //settings
	return error;
	}

TInt CServerSubSession::GetFindResultL(const TClientRequest& aMessage)
	{
	TInt n = iFindResult.Count();	
	if (n==0)
		{
		return KErrNotFound;
		}

  	TPtrC8 p(reinterpret_cast<TUint8*>(&(iFindResult[0])), n*sizeof(TUint32));
  	TInt error = aMessage.Write(0, p);
  	// Free up iFindResult - it's no longer needed
  	iFindResult.Reset();
	// ServiceError will fail transaction

#ifdef SRVSUBSESS_TRACE
  	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::GetFindResultL UID: 0x%x Value=%S\n",uid.iUid,&p);
		}
	else
		{
		__SRVSUBSESS_TRACE1("CServerSubSession::GetFindResultL **Failure** UID: 0x%x\n",uid.iUid);
		}
#endif
	return User::LeaveIfError(error);
	}

TInt CServerSubSession::NotifyRequestCheck(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();
	if(KErrNone != CheckPolicy(aMessage,iRepository.GetReadAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::NotifyRequestCheck - Attempt made to check Notify request")))
		return KErrPermissionDenied;

	TInt error = iRepository.GetPersistentSetting(key) ? KErrNone : KErrNotFound;

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::NotifyRequestCheck UID: 0x%x Key=0x%x\n",uid.iUid,key);
		}
	else
		{
		__SRVSUBSESS_TRACE1("CServerSubSession::NotifyRequestCheck **Failure** UID: 0x%x\n",uid.iUid);
		}
#endif
	return error;
	}

TInt CServerSubSession::NotifyRequest(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();
	if(KErrNone != CheckPolicy(aMessage,iRepository.GetReadAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::NotifyRequest - Attempt made to register for Notify")))
		return KErrPermissionDenied;
	TInt error = iNotifier.AddRequest(key, aMessage);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::NotifyRequest UID: 0x%x Key=0x%x\n",uid.iUid,key);
		}
	else
		{
		__SRVSUBSESS_TRACE1("CServerSubSession::NotifyRequest **Failure** UID: 0x%x\n",uid.iUid);
		}
#endif

	return (error == KErrNone) ? KDontCompleteMessage : error;
	}

TInt CServerSubSession::NotifyCancel(const TClientRequest& aMessage)
	{
	TUint32 key = aMessage.Int0();

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE2("CServerSubSession::NotifyCancel UID: 0x%x Key=0x%x\n",uid.iUid,key);
#endif

	return iNotifier.CancelRequest(key);
	}

TInt CServerSubSession::NotifyCancelAll(const TClientRequest& /*aMessage*/)
	{
#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE1("CServerSubSession::NotifyCancelAll UID: 0x%x\n",uid.iUid);
#endif
	return iNotifier.CancelAllRequests();
	}

TInt CServerSubSession::GroupNotifyRequest(const TClientRequest& aMessage)
	{
	TUint32 partialId = aMessage.Int0();
	TUint32 idMask = aMessage.Int1();
	RSettingPointerArray settings;
	TInt error = iRepository.FindPersistentSettings(partialId, idMask, settings);
	if (error == KErrNone)
		{
		TUint32 dummyErrId;
		error = iRepository.CheckPermissions(settings, aMessage,
			__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::GroupNotifyRequest - Attempt made to register for group Notify"),ETrue,dummyErrId);
		}
	settings.Reset();
	if (error != KErrNone)
		{
#ifdef SRVSUBSESS_TRACE
		TUid uid = RepositoryUid();

		__SRVSUBSESS_TRACE3("CServerSubSession::GroupNotifyRequest **Failure** UID: 0x%x\n PartialId=0x%x Mask=0x%x\n",
				uid.iUid,partialId,idMask);
#endif

		return KErrPermissionDenied;
		}

	error = iNotifier.AddRequest(partialId, idMask, aMessage);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::GroupNotifyRequest UID: 0x%x PartialId=0x%x Mask=0x%x\n",
				uid.iUid,partialId,idMask);
		}
	else
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::GroupNotifyRequest **Failure** UID: 0x%x PartialId=0x%x Mask=0x%x\n",uid.iUid,
				partialId,idMask);
		}
#endif

	return error==KErrNone ? KDontCompleteMessage : error;
	}

TInt CServerSubSession::GroupNotifyCancel(const TClientRequest& aMessage)
	{
	TKeyFilter keyIdentifier;
	TPckg<TKeyFilter> p(keyIdentifier);
	aMessage.Read(0, p);

	RSettingPointerArray settings;
	TInt error = iRepository.FindPersistentSettings(keyIdentifier.iPartialId, keyIdentifier.iIdMask, settings);
	settings.Reset();
	if (error != KErrNone)
		{
#ifdef SRVSUBSESS_TRACE
		TUid uid = RepositoryUid();

		__SRVSUBSESS_TRACE3("CServerSubSession::GroupNotifyCancel **Failure** UID: 0x%x\n PartialId=0x%x Mask=0x%x\n",
				uid.iUid,keyIdentifier.iPartialId, keyIdentifier.iIdMask);
#endif
		return error;
		}

	error = iNotifier.CancelRequest(keyIdentifier.iPartialId, keyIdentifier.iIdMask);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::GroupNotifyCancel UID: 0x%x PartialId=0x%x Mask=0x%x\n",
				uid.iUid,keyIdentifier.iPartialId, keyIdentifier.iIdMask);
		}
	else
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::GroupNotifyCancel **Failure** UID: 0x%x PartialId=0x%x Mask=0x%x\n",uid.iUid,
				keyIdentifier.iPartialId, keyIdentifier.iIdMask);
		}
#endif


	return error;
	}

TInt CServerSubSession::ResetL(const TClientRequest& aMessage)
	{
	// individual setting reset is not yet supported in transactions
	ASSERT(!iRepository.IsInTransaction());
	TUint32 key = aMessage.Int0();
	if(KErrNone != CheckPolicy(aMessage,iRepository.GetWriteAccessPolicy(key),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::ResetL - Attempt made to reset a setting")))
		return iRepository.FailTransaction(KErrPermissionDenied, key);

	TInt error = iRepository.ResetL(key);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::ResetL UID: 0x%x Key=0x%x\n",
				uid.iUid,key);
		}
	else
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::ResetL **Failure** UID: 0x%x Key=0x%x\n",uid.iUid,key);
		}
#endif

	return error;
	}

TInt CServerSubSession::ResetAllL(const TClientRequest& aMessage)
	{
	// factory reset operation is not yet supported in transactions
	ASSERT(!iRepository.IsInTransaction());
	if(KErrNone != CheckPolicy(aMessage,iRepository.GetDefaultWriteAccessPolicy(),
				__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerSession::ResetAllL - Attempt made to reset repository")))
		return KErrPermissionDenied;

	iNotifier.IdReportingOff();
	TInt error = iRepository.ResetAllL();
	iNotifier.IdReportingOn();

	if (error == KErrNone)
		{
		iRepository.CommitChangesL();  // temporary measure
		}

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE1("CServerSubSession::ResetAllL UID: 0x%x\n",uid.iUid);
		}
	else
		{
		__SRVSUBSESS_TRACE1("CServerSubSession::ResetAllL **Failure** UID: 0x%x\n",uid.iUid);
		}
#endif

	return error;
	}

TInt CServerSubSession::MoveL(const TClientRequest& aMessage)
	{
	if (iRepository.IsInActiveReadTransaction())
		{
		TKeyFilter keyIdentifier;
		TPckg<TKeyFilter> p(keyIdentifier);
		aMessage.Read(0, p);

#ifdef SRVSUBSESS_TRACE
		TUid uid = RepositoryUid();

		__SRVSUBSESS_TRACE3("CServerSubSession::MoveL **Failure** In Transaction UID: 0x%x PartialId=0x%x Mask=0x%x\n",
				uid.iUid,keyIdentifier.iPartialId,keyIdentifier.iIdMask);
#endif

		// could not promote to read/write: fail & give the source partialKey as the error key
		return iRepository.FailTransaction(KErrLocked, keyIdentifier.iPartialId);
		}
	
	TUint32 errorKey = KUnspecifiedKey;
	TInt result = iRepository.TransactionMoveL(aMessage, errorKey);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (result == KErrNone)
		{
		__SRVSUBSESS_TRACE1("CServerSubSession::MoveL UID: 0x%x\n",uid.iUid);
		}
	else
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::MoveL **Failure** UID: 0x%x Error=%d\n",uid.iUid,errorKey);
		}
#endif

	if (result != KErrNone && result!=KErrNotFound)
		{
		iRepository.FailTransaction(result, errorKey);
		TPckg<TUint32> p(errorKey);
		aMessage.WriteL(2, p);
		}
	return result;
	}

TInt CServerSubSession::TransactionStart(const TClientRequest& aMessage)
	{
	// check if we are already in a transaction
	TBool inTransactionAlready = iRepository.IsInTransaction();

	// panic client if attempting to start a transaction when already in one
	__ASSERT_ALWAYS(!inTransactionAlready, PanicClient(EStartAlreadyInTransaction, aMessage));

	// if the client has been panicked then we don't want to continue.
	// client session will already have been taken down so don't want to complete the message
	if (inTransactionAlready)
		{
#ifdef SRVSUBSESS_TRACE
		TUid uid = RepositoryUid();

		__SRVSUBSESS_TRACE1("CServerSubSession::TransactionStart **Failure** already in transaction UID=0x%x\n",uid.iUid);
#endif

		return KDontCompleteMessage;
		}

	const TInt mode = aMessage.Int0();

	TInt error = iRepository.StartTransaction(mode);

#ifdef SRVSUBSESS_TRACE

	TUid uid = RepositoryUid();

	// mode strings match transstate.h - if that is updated, this should be as well.
	const TPtrC modeStrings[] =
		{
			_L("ENoTransaction"),                              // 0
			_L("EReadTransaction"),                            // EReadBit     1
			_L("EConcurrentReadWriteTransaction"),             // EWriteBit    2
			_L("EReadWriteTransaction|EAllTransactionBits"),   //EReadBit | EWriteBit 3
			_L("EFailedBit")                                   // 4
		};

	if (error == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::TransactionStart UID: 0x%x Mode=%d (%S)\n",uid.iUid,mode,&modeStrings[mode]);
		}
	else
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::TransactionStart **Failure** UID: 0x%x Mode=%d (%S)\n",uid.iUid,mode,&modeStrings[mode]);
		}
#endif

	return error;
	}

// serves as both rollback and async cancel
TInt CServerSubSession::TransactionCancel(const TClientRequest& /*aMessage*/)
	{
#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE1("CServerSubSession::TransactionCancel UID: 0x%x",uid.iUid);
#endif
	iRepository.CancelTransaction();
	return KErrNone;
	}

TInt CServerSubSession::TransactionCommitL(const TClientRequest& aMessage)
	{
	// check if we are in a transaction
	TBool inTransaction = iRepository.IsInTransaction();

	// panic client if attempting to commit a transaction when we are not in one
	__ASSERT_ALWAYS(inTransaction, PanicClient(ECommitNotInTransaction, aMessage));

	// if the client has been panicked then we don't want to continue.
	// client session will already have been taken down so don't want to complete the message
	if (!inTransaction)
		{
#ifdef SRVSUBSESS_TRACE
		TUid uid = RepositoryUid();

		__SRVSUBSESS_TRACE1("CServerSubSession::TransactionCommitL **Failure** In Transaction UID: 0x%x TransactionKey=%d\n",uid.iUid);
#endif
		return KDontCompleteMessage;
		}

	TUint32 keyInfo = KUnspecifiedKey;
	TInt result = iRepository.CommitTransaction(keyInfo);

	TPckg<TUint32> p(keyInfo);
	aMessage.WriteL(0, p);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	if (result == KErrNone)
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::TransactionCommitL UID: 0x%x TransactionKey=%d\n",uid.iUid,keyInfo);
		}
	else
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::TransactionCommitL **Failure** UID: 0x%x TransactionKey=%d\n",uid.iUid,keyInfo);
		}
#endif
	return result;
	}

TInt CServerSubSession::DeleteRangeL(const TClientRequest& aMessage)
	{
	if (iRepository.IsInActiveReadTransaction())
		{
		// could not promote to read/write: fail & give the partialKey as the error key
		TUint32 partialKey = aMessage.Int0();
		return iRepository.FailTransaction(KErrLocked, partialKey);
		}
	TUint32 errorKey = KUnspecifiedKey;
	TInt result = iRepository.TransactionDeleteRangeL(aMessage, errorKey);
	if (result != KErrNone)
		{
		TPckg<TUint32> p(errorKey);
		aMessage.WriteL(2, p);
		}

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();
	TUint32 partialKey = aMessage.Int0();
	TUint32 keyMask    = aMessage.Int1();

	if (result == KErrNone)
		{
		__SRVSUBSESS_TRACE3("CServerSubSession::DeleteRangeL UID: 0x%x Key=0x%x Mask=0x%x\n",uid.iUid,partialKey,keyMask);
		}
	else
		{
		__SRVSUBSESS_TRACE2("CServerSubSession::DeleteRangeL **Failure** UID: 0x%x ErrorKey=%d\n",uid.iUid,errorKey);
		}
#endif

	return result;
	}

TInt CServerSubSession::TransactionStateL(const TClientRequest& aMessage)
	{
	TInt iState = iRepository.TransactionState();

	TPckg<TInt> p(iState);
	aMessage.WriteL(0, p);

#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE2("CServerSubSession::TransactionStateL UID: 0x%x State=%d\n",uid.iUid,iState);
#endif

	return KErrNone;
	}

TInt CServerSubSession::TransactionFail(const TClientRequest& aMessage)
	{
#ifdef SRVSUBSESS_TRACE
	TUid uid = RepositoryUid();

	__SRVSUBSESS_TRACE1("CServerSubSession::TransactionFail UID: 0x%x",uid.iUid);
#endif

	iRepository.FailTransaction(aMessage.Int0(), KUnspecifiedKey);
	return KErrNone;
	}

//Check the security policy against a RMessage.
TInt CServerSubSession::CheckPolicy(const TClientRequest& msg,
								 const TSecurityPolicy& aPolicy,
								 const char *aDiagnostic)
	{
	return msg.CheckPolicy(aPolicy,aDiagnostic) ? KErrNone : KErrPermissionDenied;
	}
