locationrequestmgmt/networkrequesthandler/src/privacyhandler.cpp
changeset 0 9cfd9a3ee49c
child 52 29dbbeac905d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/locationrequestmgmt/networkrequesthandler/src/privacyhandler.cpp	Tue Feb 02 01:50:39 2010 +0200
@@ -0,0 +1,1643 @@
+// 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:
+// Privacy handler for Location Update requests
+// 
+//
+
+#include <e32base.h>
+#include <lbs/lbsadmin.h>
+
+#include "lbsdevloggermacros.h"
+#include <lbs/lbslocclasstypes.h>
+#include "lbsprivacynotifier.h"
+#include "privacyhandlerobserver.h"
+#include "privacyhandler.h"
+#include "lbsprivacycontrollerdata.h"
+#include "LbsInternalInterface.h"
+#include "lbsqualityprofile.h"
+#ifdef SYMBIAN_LOCATION_PRIVACY_V2
+	#include "privacyadvancednotifierhandler.h"
+#endif
+
+
+const TInt KErrLbsNotifierUnknown = KErrUnknown; // for now....
+
+//===================================================================================================
+CPrivacyHandler* CPrivacyHandler::CreateL(MPrivacyHandlerObserver* aObserver,
+                                          CLbsAdmin& aLbsAdmin,
+                                          RLbsNetworkRegistrationStatus& aNetRegStatus)
+	{
+	CPrivacyHandler* implementation = 0;
+
+	
+	// Find out whether we're referring notification/verification to a notifier 
+	// or a controller.
+	CLbsAdmin::TPrivacyHandler privacyHandler;
+	aLbsAdmin.Get(KLbsSettingPrivacyHandler, privacyHandler);
+
+	switch(privacyHandler)
+		{
+		case CLbsAdmin::EPrivacyHandleByNotifier:
+			{
+			implementation = CPrivacyNotifierHandler::NewL(aLbsAdmin,
+														   aNetRegStatus);
+			break;
+			}
+		case CLbsAdmin::EPrivacyHandleByController:
+			{
+			implementation = CPrivacyControllerHandler::NewL(aLbsAdmin,
+															 aNetRegStatus);
+			break;
+			}
+#ifdef SYMBIAN_LOCATION_PRIVACY_V2
+		case CLbsAdmin::EPrivacyHandleByAdvancedNotifier:
+			{
+			implementation = CPrivacyAdvancedNotifierHandler::NewL(aLbsAdmin,
+																   aNetRegStatus);
+			break;
+			}
+#endif
+		default:
+			{
+			User::Leave(KErrLbsNotifierUnknown);
+			break;
+			}
+		}
+	implementation->RegisterObserver(aObserver);    
+	return(implementation);
+	}
+
+CPrivacyHandler::CPrivacyHandler(CLbsAdmin& aLbsAdmin,
+								 RLbsNetworkRegistrationStatus& aNetRegStatus)
+: CActive(EPriorityStandard),
+	iLbsAdmin(aLbsAdmin),
+	iNetRegStatus(aNetRegStatus)
+	{		
+	}
+
+/* Get the current value for the admin setting for external locate.
+
+This functions checks the network registration (i.e. 'roaming') status
+and reads either the 'home' or 'network' admin setting as appropriate. 
+*/
+void CPrivacyHandler::GetExternalLocateAdminSetting(const TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, CLbsAdmin::TExternalLocateService& aExternalLocateService)
+	{
+	CLbsAdmin::TExternalLocateService								serviceStatus(CLbsAdmin::EExternalLocateOff);
+	RLbsNetworkRegistrationStatus::TLbsNetworkRegistrationStatus	netRegStatus(RLbsNetworkRegistrationStatus::ENetworkRegistrationUnknown);	
+
+	// Rread the network regisration to determine if currently roaming.
+	TInt err = iNetRegStatus.GetNetworkRegistrationStatus(netRegStatus);
+	if (err == KErrNone)
+		{
+		// Determine service status based on the normal MT-LR admin settings.
+		if (aSessionType == TLbsNetworkEnumInt::EServiceMobileTerminated)
+			{
+			switch (netRegStatus)
+				{
+				case RLbsNetworkRegistrationStatus::ERegisteredHomeNetwork:
+					{
+					err = iLbsAdmin.Get(KLbsSettingHomeExternalLocate, serviceStatus);
+					break;
+					}
+				case RLbsNetworkRegistrationStatus::ERegisteredRoamingNetwork:
+				case RLbsNetworkRegistrationStatus::ENotRegistered:
+					{
+					err = iLbsAdmin.Get(KLbsSettingRoamingExternalLocate, serviceStatus);
+					break;
+					}		
+				case RLbsNetworkRegistrationStatus::ENetworkRegistrationUnknown:
+				default:
+					{
+					LBSLOG_WARN2(ELogP4, "Unrecognised TLbsNetworkRegistrationStatus (%d), defaulting to EExternalLocateOff", netRegStatus);
+					break;
+					}
+				}
+			}
+			
+		// Determine service status based on the network induced MT-LR admin settings.
+		else if (aSessionType == TLbsNetworkEnumInt::EServiceNetworkInduced)
+			{
+			switch (netRegStatus)
+				{
+				case RLbsNetworkRegistrationStatus::ERegisteredHomeNetwork:
+					{
+					err = iLbsAdmin.Get(KLbsSettingHomeNetworkInducedLocate, serviceStatus);
+					break;
+					}
+				case RLbsNetworkRegistrationStatus::ERegisteredRoamingNetwork:
+				case RLbsNetworkRegistrationStatus::ENotRegistered:
+					{
+					err = iLbsAdmin.Get(KLbsSettingRoamingNetworkInducedLocate, serviceStatus);
+					break;
+					}		
+				case RLbsNetworkRegistrationStatus::ENetworkRegistrationUnknown:
+				default:
+					{
+					LBSLOG_WARN2(ELogP4, "Unrecognised TLbsNetworkRegistrationStatus (%d), defaulting to EExternalLocateOff", netRegStatus);
+					break;
+					}
+				}
+			}
+
+		else
+			{
+			LBSLOG_WARN2(ELogP4, "Unsupported TLbsNetworkEnumInt::TLbsNetProtocolServiceInt (%d), defaulting to EExternalLocateOff", aSessionType);
+			}
+		}
+
+	else
+		{
+		LBSLOG_WARN2(ELogP4, "Failed to get TExternalLocateService, couldn't read roaming status (err %d), defaulting to EExternalLocateOff", err);		
+		}
+
+	// Error during admin get. 
+	if (err)
+		{
+		serviceStatus = CLbsAdmin::EExternalLocateOff;
+		}
+	
+	aExternalLocateService = serviceStatus;
+	}
+
+/** Get the default privacy response based on the admin setting.
+ */
+void CPrivacyHandler::GetPrivacyTimeoutAction(
+		TLbsNetworkEnumInt::TLbsPrivacyResponseInt& aResponse, 
+		const TLbsNetPosRequestPrivacyInt& aRequestPrivacy)
+	{
+	CLbsAdmin::TPrivacyTimeoutAction privacyTimeoutAction;
+	iLbsAdmin.Get(KLbsSettingPrivacyTimeoutAction, privacyTimeoutAction);
+	
+	switch(privacyTimeoutAction)
+		{
+		case CLbsAdmin::EPrivacyTimeoutReject:
+			{
+			aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			break;
+			}
+		
+		case CLbsAdmin::EPrivacyTimeoutNetworkDefined:
+			{
+			//Use the network defined action to decide whether to reject/accept
+			switch(aRequestPrivacy.RequestAction())
+				{
+				case TLbsNetPosRequestPrivacyInt::ERequestActionAllow:
+					{
+					aResponse = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+					break;
+					}
+				case TLbsNetPosRequestPrivacyInt::ERequestActionReject:
+				case TLbsNetPosRequestPrivacyInt::ERequestActionNotUsed:
+					{
+					aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+					break;
+					}
+				}
+			break;
+			}
+		default:
+			{
+			aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			break;
+			}
+		}	
+	}
+
+//
+// CPrivacyRequest
+//
+CPrivacyRequest::CPrivacyRequest()
+	{
+	}
+
+CPrivacyRequest::~CPrivacyRequest()
+	{
+	}
+
+CPrivacyRequest* CPrivacyRequest::NewL()
+	{
+	CPrivacyRequest* self = new (ELeave) CPrivacyRequest;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CPrivacyRequest::ConstructL()
+	{
+	}
+
+CPrivacyRequest::TPrivReqState CPrivacyRequest::State() const
+	{
+	return iState;
+	}
+
+void CPrivacyRequest::SetState(CPrivacyRequest::TPrivReqState aState)
+	{
+	iState = aState;
+	}
+
+const TLbsNetSessionIdInt& CPrivacyRequest::SessionId() const
+	{
+	return iSessionId;
+	}
+
+void CPrivacyRequest::SetSessionId(const TLbsNetSessionIdInt& aSessionId)
+	{
+	iSessionId = aSessionId;
+	}
+
+const TLbsNetworkEnumInt::TLbsNetProtocolServiceInt& CPrivacyRequest::SessionType() const
+	{
+	return iSessionType;
+	}
+
+void CPrivacyRequest::SetSessionType(const TLbsNetworkEnumInt::TLbsNetProtocolServiceInt& aSessionType)
+	{
+	iSessionType = aSessionType;
+	}
+
+const TLbsExternalRequestInfo& CPrivacyRequest::RequestInfo() const
+	{
+	return iRequestInfo;
+	}
+
+void CPrivacyRequest::SetRequestInfo(const TLbsExternalRequestInfo& aRequestInfo)
+	{
+	Mem::Copy(&iRequestInfo, &aRequestInfo, aRequestInfo.ClassSize());
+	}
+
+const TLbsNetPosRequestPrivacyInt& CPrivacyRequest::RequestPrivacy() const
+	{
+	return iRequestPrivacy;
+	}
+
+void CPrivacyRequest::SetRequestPrivacy(const TLbsNetPosRequestPrivacyInt& aRequestPrivacy)
+	{
+	iRequestPrivacy = aRequestPrivacy;
+	}
+
+TBool CPrivacyRequest::IsEmergency() const
+	{
+	return iIsEmergency;
+	}
+
+void CPrivacyRequest::SetIsEmergency(TBool aIsEmergency)
+	{
+	iIsEmergency = aIsEmergency;
+	}
+
+TTime CPrivacyRequest::StartTime() const
+	{
+	return iStartTime;
+	}
+
+void CPrivacyRequest::SetStartTime()
+	{
+	iStartTime.UniversalTime();
+	}
+
+/** Comparison function for RPointerArray<CPrivacyRequest>::Find()
+ */
+TBool CPrivacyRequest::IsSessionIdEqual(
+		const TLbsNetSessionIdInt* aSessionId,
+		const CPrivacyRequest& aItem)
+	{
+	return (*aSessionId == aItem.SessionId());
+	}
+	
+//
+// CPrivacyNotifierHandler
+//
+CPrivacyNotifierHandler::CPrivacyNotifierHandler(CLbsAdmin& aLbsAdmin,
+												 RLbsNetworkRegistrationStatus& aNetRegStatus) : 
+	CPrivacyHandler(aLbsAdmin, aNetRegStatus)
+    {
+	iPrivacyResponseOutstanding = EFalse;
+    }
+    
+CPrivacyNotifierHandler* CPrivacyNotifierHandler::NewL(CLbsAdmin& aLbsAdmin,
+													   RLbsNetworkRegistrationStatus& aNetRegStatus)
+    {
+	CPrivacyNotifierHandler* self = new (ELeave)CPrivacyNotifierHandler(aLbsAdmin,
+																		aNetRegStatus);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return(self);
+    }
+
+/**
+*/
+void CPrivacyNotifierHandler::ConstructL()
+	{
+	CActiveScheduler::Add(this);
+	iPrivacyResponseTimer = CLbsCallbackTimer::NewL(*this);
+	}
+
+/**
+ * Called when the response timer expires.
+ * An accept or reject of the original query is reported to the NRH 
+ * depending on the request action parameter received with the original request.
+ * @param aTimerId always 1 (we only use one timer in this subcomponent)
+ */
+void CPrivacyNotifierHandler::OnTimerEventL(TInt aTimerId)
+	{
+	iNotifier->Cancel();
+	switch (aTimerId)
+		{
+		case 1:
+			{
+			// The privacy notifier has timed out without a response being
+			// received. Generate a response as required depending upon
+			// the LbsAdmin setting: TPrivacyTimeoutAction
+			CPrivacyRequest* request = iRequestBuffer[0];
+			TLbsNetworkEnumInt::TLbsPrivacyResponseInt response;
+			GetPrivacyTimeoutAction(response, request->RequestPrivacy());
+			
+			iObserver->OnRespondNetworkLocationRequest(
+					request->SessionId(), response, KErrNone);
+
+			// Delete the current request and start the next one in the buffer
+			iRequestBuffer.Remove(0);
+			delete request; 
+          	SendNextPrivacyRequest();
+			break;
+			}
+		default:
+			// do nothing
+			break;	
+		}
+	}
+	
+TInt CPrivacyNotifierHandler::OnTimerError(TInt /*aTimerId*/, 
+											TInt aError)
+	{
+	// Not used - OnTimerEventL doesn't generate any error.
+	return(aError);
+	}
+
+
+void CPrivacyNotifierHandler::ProcessNetworkLocationRequest(
+		TLbsNetSessionIdInt aSessionId,
+		const TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 		
+        const TLbsExternalRequestInfo&  aRequestInfo, 
+        const TLbsNetPosRequestPrivacyInt& aNetPosRequestPrivacy,
+        TBool aIsEmergency)
+           
+	{
+	BufferPrivacyRequest(aSessionId, aSessionType, aRequestInfo, aNetPosRequestPrivacy, aIsEmergency);
+	
+	if (!IsPrivacyRequestActive())
+		{
+		SendNextPrivacyRequest();
+		}
+	}
+void CPrivacyNotifierHandler::ProcessNetworkPositionUpdate(TLbsNetSessionIdInt /*aSessionId*/, 
+                                           const TPositionInfo& /*aPosInfo*/)
+    {
+    }
+		
+void CPrivacyNotifierHandler::ProcessRequestComplete(TLbsNetSessionIdInt aSessionId, TInt /*aReason*/)
+    {
+    // If the current request is still in the buffer here, 
+    // it is because it is still waiting for a reponse.
+    // So, we need to cancel the notifier and clean up.
+    if (iRequestBuffer.Count() > 0
+    	&& aSessionId == iRequestBuffer[0]->SessionId())
+    	{
+    	CPrivacyRequest* request = iRequestBuffer[0];
+    	
+    	// If the completed request is the currently active one,
+    	// may need to cancel the notifer and timer as well.
+		if (iNotifier)
+			{
+			iNotifier->Cancel();
+			}
+		
+		iPrivacyResponseTimer->Cancel();
+		
+		// Delete the completed request
+		iRequestBuffer.Remove(0);
+		delete request; 
+    	}
+    }
+
+void CPrivacyNotifierHandler::RegisterObserver(MPrivacyHandlerObserver* aObserver)
+    {
+    iObserver = aObserver;	
+    }
+    
+CPrivacyNotifierHandler::~CPrivacyNotifierHandler()
+    {	
+    if(iNotifier)
+    	{
+    	iNotifier->Cancel();
+    	}
+    delete iNotifier;
+    iRequestBuffer.ResetAndDestroy();
+	iPrivacyResponseTimer->Cancel();
+	delete iPrivacyResponseTimer;
+    Cancel();
+    }
+
+// From MLbsPrivacyNotifierObserver
+void CPrivacyNotifierHandler::OnNotificationDialogResponse(TInt aErr , 
+	                         const TLbsPrivacyNotifierResponse& aResponse)
+	{
+	iPrivacyResponseTimer->Cancel();
+	iPrivacyResponseOutstanding = EFalse;
+	
+	CPrivacyRequest* request = iRequestBuffer[0];
+	if(aErr == KErrNone)
+		{
+		switch(aResponse)
+			{
+			case EResponseAccepted:
+				{
+				iObserver->OnRespondNetworkLocationRequest(request->SessionId(), 
+						TLbsNetworkEnumInt::EPrivacyResponseAccepted, KErrNone);				
+				break;
+				}
+				
+			case EResponseTimedOut:
+				{
+				iNotifier->Cancel();
+				TLbsNetworkEnumInt::TLbsPrivacyResponseInt response;
+				GetPrivacyTimeoutAction(response, request->RequestPrivacy());
+				iObserver->OnRespondNetworkLocationRequest(
+									request->SessionId(), response, KErrNone);
+				break; // case EResponseTimedOut
+				}
+
+			default:				
+			case EResponseRejected:
+				{
+				iObserver->OnRespondNetworkLocationRequest(request->SessionId(), 
+						TLbsNetworkEnumInt::EPrivacyResponseRejected, KErrNone);				
+				break;
+				}
+			}
+		}
+	else			
+	// Treat any error as an 'unknown' response
+		{
+		iObserver->OnRespondNetworkLocationRequest(request->SessionId(), 
+					TLbsNetworkEnumInt::EPrivacyResponseUnknown, KErrArgument);
+		}
+	
+	// Delete the current request and start the next one in the buffer
+	iRequestBuffer.Remove(0);
+	delete request; 
+   	SendNextPrivacyRequest();
+	}
+
+/* Return ETrue if we are currently waiting on the RNotifier dialog.
+
+Uses the response timer, because this should only be running
+when we are waiting for the RNotifier.
+*/
+TBool CPrivacyNotifierHandler::IsPrivacyRequestActive()
+	{
+	return (iPrivacyResponseTimer->IsActive());
+	}
+
+void CPrivacyNotifierHandler::WaitForPrivacyResponse()
+	{
+	// Start a timeout timer, in case the privacy notifier doesn't reply.
+	iPrivacyResponseTimer->Cancel();
+	TUint privacyVerifyTimeoutInMilliSeconds = 0;		
+	// Note: the following should never fail as we create a default setting in case of absence
+	iLbsAdmin.Get(KLbsSettingPrivacyAppTimeout, privacyVerifyTimeoutInMilliSeconds);	
+	TTimeIntervalMicroSeconds privacyVerifyTimeout = privacyVerifyTimeoutInMilliSeconds * 1000;
+	if (privacyVerifyTimeout > 0)
+		{
+		iPrivacyResponseTimer->EventAfter(privacyVerifyTimeout, 1);		
+		}	
+	// flag to show we're waiting for a response
+	iPrivacyResponseOutstanding = ETrue;
+	}
+
+void CPrivacyNotifierHandler::SendNextPrivacyRequest()
+	{
+	// May need to loop over multiple *notify* requests,
+	// because we don't wait for a response for those.	
+	while (iRequestBuffer.Count() > 0 && !IsPrivacyRequestActive())
+		{
+		CPrivacyRequest* request = iRequestBuffer[0];
+		
+		TRequiredPrivacyAction notifierAction(ERequiredPrivacyActionNone);
+		TBool waitForResponse(ETrue);
+		TLbsNetworkEnumInt::TLbsPrivacyResponseInt response(TLbsNetworkEnumInt::EPrivacyResponseAccepted);
+		TInt responseReason = KErrNone;
+		
+		CLbsAdmin::TExternalLocateService externalLocate(CLbsAdmin::EExternalLocateOff);
+		GetExternalLocateAdminSetting(request->SessionType(), externalLocate);
+
+		// ERequestAdviceStealth is not supported, so reject any such request
+		if(request->RequestPrivacy().RequestAdvice() == 
+			TLbsNetPosRequestPrivacyInt::ERequestAdviceStealth)
+			{
+			notifierAction = ERequiredPrivacyActionNone;
+			waitForResponse = EFalse;
+			response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			responseReason = KErrNotSupported;
+			}
+		else
+			{
+			TLbsNetPosRequestPrivacyInt privacy = request->RequestPrivacy();
+			GetRequiredNotificationAction(	request->IsEmergency(), 
+											externalLocate,
+											notifierAction, 
+											waitForResponse, 
+											response,
+											privacy);
+			request->SetRequestPrivacy(privacy);
+			}
+		
+		// If required, raise a notification/verification
+		TInt displayErr = KErrNone;
+		if(iNotifier && iNotifierAction != notifierAction)
+			{
+	    	iNotifier->Cancel();
+			delete iNotifier;	
+			iNotifier = NULL;	
+			}
+			
+		// Start a notify or verify notifier depending on the type of the privacy request.
+		if(iNotifier == NULL)
+			{
+			switch(notifierAction)
+				{
+				case ERequiredPrivacyActionNotify:
+					{
+					TRAPD(err, iNotifier = CLbsPrivacyNotifier::NewL(EPrivacyDialogNotification));
+					if(err == KErrNone)
+					    {
+                        iNotifier->SetObserver(this);
+					    }
+					break;
+					}
+
+				case ERequiredPrivacyActionVerify:
+					{
+					TRAPD(err, iNotifier = CLbsPrivacyNotifier::NewL(EPrivacyDialogVerification));
+					if(err == KErrNone)
+					    {
+                        iNotifier->SetObserver(this);
+					    }
+					break;
+					}
+			
+				default:
+				case ERequiredPrivacyActionNone:
+					{
+					// do nothing
+					break;
+					}
+				}
+			}
+			
+		iNotifierAction = notifierAction;
+		if(iNotifier)
+			{
+			TRAPD(displayLeaveErr, iNotifier->DisplayL(displayErr, request->RequestInfo()));
+			// If there is an error, treat the notification as having returned an
+			// 'unknown' response.
+			if(displayLeaveErr != KErrNone || displayErr != KErrNone)
+				{
+				response = TLbsNetworkEnumInt::EPrivacyResponseUnknown;
+				waitForResponse = EFalse;
+				}	
+			}
+		
+		// If the privacy controller application is responsible for accepting
+		// or rejecting the privacy request, wait for its response
+		if (waitForResponse)
+			{
+			WaitForPrivacyResponse();		
+			}
+		else
+			{
+			// Send an immediate response
+			iObserver->OnRespondNetworkLocationRequest(request->SessionId(), response, responseReason);
+			
+			// Remove the request since we don't need to wait for the response.
+			iRequestBuffer.Remove(0);
+			delete request; 
+         	}
+		}
+	}
+
+void CPrivacyNotifierHandler::SendPrivacyResponse()
+	{
+	}
+	
+TInt CPrivacyNotifierHandler::BufferPrivacyRequest(
+		const TLbsNetSessionIdInt& aSessionId,
+		const TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType,		
+		const TLbsExternalRequestInfo& aRequestInfo,
+		const TLbsNetPosRequestPrivacyInt& aRequestPrivacy,
+		TBool aIsEmergency)
+	{
+	CPrivacyRequest* requestData = NULL;
+	TRAPD(err, requestData = CPrivacyRequest::NewL());
+	if (err == KErrNone)
+		{
+		requestData->SetSessionId(aSessionId);
+		requestData->SetSessionType(aSessionType);
+		requestData->SetRequestInfo(aRequestInfo);
+		requestData->SetRequestPrivacy(aRequestPrivacy);
+		requestData->SetIsEmergency(aIsEmergency);
+		requestData->SetStartTime();
+		err = iRequestBuffer.Append(requestData);
+		}
+	
+	return err;
+	}
+
+void CPrivacyNotifierHandler::RemovePrivacyRequestFromBuffer(
+		const TLbsNetSessionIdInt& aSessionId)
+	{
+	TInt index = iRequestBuffer.Find(aSessionId, CPrivacyRequest::IsSessionIdEqual);
+	while (KErrNotFound != index)
+		{
+		CPrivacyRequest* reqData = iRequestBuffer[index];
+		iRequestBuffer.Remove(index);
+		delete reqData; 
+    	index = iRequestBuffer.Find(aSessionId, CPrivacyRequest::IsSessionIdEqual);
+		}
+	}
+	
+void CPrivacyNotifierHandler::OnRespondNetworkLocationRequest(const TLbsNetSessionIdInt& /* aRequestId */, 
+                            TLbsNetworkEnumInt::TLbsPrivacyResponseInt /* aRequestResult */,
+                            TInt /*aResponseReason*/)
+	{
+	}
+	
+/**
+ * Unused for Notifier - cancel from the notifier is reported via 
+ * MLbsPrivacyNotifierObserver::OnNotificationDialogResponse.
+ */
+void CPrivacyNotifierHandler::OnCancelNetworkLocationRequest(const TLbsNetSessionIdInt& /*aRequestId*/)
+	{
+	}
+
+void CPrivacyNotifierHandler::RunL()
+	{
+	}
+	
+void CPrivacyNotifierHandler::DoCancel()
+	{
+	}
+	
+void CPrivacyNotifierHandler::SetServerObserver(MLbsSessionObserver* /*aNrhServer*/)
+    {
+    // Unused for notifier
+    }
+// A privacy request must be accepted or rejected, based on a
+// combination of iPrivacyRequest->RequestPrivacy() settings, LbsAdmin settings
+// and whether it is an emergency request.
+//
+
+void CPrivacyNotifierHandler::GetRequiredNotificationAction(
+									TBool aIsEmergency,
+									CLbsAdmin::TExternalLocateService aExternalLocate,
+									TRequiredPrivacyAction& aPrivacyAction, 
+									TBool& aTimeoutRequired,
+									TLbsNetworkEnumInt::TLbsPrivacyResponseInt& aResponse,
+									TLbsNetPosRequestPrivacyInt& aPrivacy
+									)
+	{
+	
+    if (aIsEmergency)
+    	{
+    	TBool silent = (aPrivacy.RequestAdvice() == TLbsNetPosRequestPrivacyInt::ERequestAdviceSilent);
+		aTimeoutRequired = EFalse; // always the case for emergency - it's only ever notified
+										
+    	// Decide whether to accept or reject an emergency request.
+    	switch (aPrivacy.RequestAction())
+    		{
+    		case TLbsNetPosRequestPrivacyInt::ERequestActionAllow:
+    			{
+				aResponse = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+				if(silent)
+					{
+    				aPrivacyAction = ERequiredPrivacyActionNone;										
+					}
+				else
+					{
+    				aPrivacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify);
+    				aPrivacyAction = ERequiredPrivacyActionNotify;
+					}
+    			break;
+    			}
+			case TLbsNetPosRequestPrivacyInt::ERequestActionReject:
+				{
+				aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+				if(silent)
+					{
+    				aPrivacyAction = ERequiredPrivacyActionNone;										
+					}
+				else
+					{
+    				aPrivacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify);
+    				aPrivacyAction = ERequiredPrivacyActionNotify;					
+					}
+    			break;
+    			}
+    		default:
+    			{
+	    		LBSLOG2(ELogP4, "CPrivCntrllrHandler::ProcessNetworkLocationRequest :  Unknown RequestAction() (0x%x), rejecting privacy request", 
+	    						 aPrivacy.RequestAction());    			
+    			aPrivacyAction = ERequiredPrivacyActionNone;
+				aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+    			break;
+    			}
+    		}
+    		// For the privacy notifier, if the original advice is not
+    		// notify or verify, don't do anything
+    	}
+    else
+    	{
+    	// Decide wether the privacy controller application should be notified,
+    	// and if not, whether the request should be accepted or rejected.
+	    switch (aExternalLocate)
+	    	{
+	    	case CLbsAdmin::EExternalLocateOn:
+	    		{
+				// Whether we wait for the privacy controller application response
+				// depends on the RequestAdvice() from the network
+				switch (aPrivacy.RequestAdvice())
+					{
+					case TLbsNetPosRequestPrivacyInt::ERequestAdviceVerify:
+						{
+    					aPrivacyAction = ERequiredPrivacyActionVerify;
+						aTimeoutRequired = ETrue;
+						break;
+						}
+					case TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify:
+						{
+    					aPrivacyAction = ERequiredPrivacyActionNotify;
+						aTimeoutRequired = EFalse;
+						if(aPrivacy.RequestAction() == TLbsNetPosRequestPrivacyInt::ERequestActionAllow)
+							{
+							aResponse = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+							}
+						else
+							{
+							aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+							}
+						break;
+						}
+					case TLbsNetPosRequestPrivacyInt::ERequestAdviceSilent:
+						{
+						// Always accept these types of privacy request for the controller - and 
+						// tell the controller about them. For the notifier, just do what it says, 
+						// without any notification
+						// Either way, no timer is needed
+						aTimeoutRequired = EFalse;
+						aPrivacyAction = ERequiredPrivacyActionNone;
+						if(aPrivacy.RequestAction() == TLbsNetPosRequestPrivacyInt::ERequestActionAllow)
+							{
+							aResponse = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+							}
+						else
+							{
+							aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+							}
+						break;
+						}
+					default:
+						{
+						// Error: Unknown RequestAdvice() value. Send a 
+						// 'reject' back to the network
+			    		LBSLOG2(ELogP4, "CPrivCntrllrHandler::ProcessNetworkLocationRequest : \
+			    						 Unknown RequestAdvice() (0x%x), \
+			    						 rejecting privacy request", 
+			    						 aPrivacy.RequestAdvice());
+    					aPrivacyAction = ERequiredPrivacyActionNone;
+						aTimeoutRequired = EFalse;
+						aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+						break;
+						}
+					}
+	    		break;
+	    		}
+	    	case CLbsAdmin::EExternalLocateOnButAlwaysVerify:
+	    		{
+    			aPrivacyAction = ERequiredPrivacyActionVerify;
+	    		aTimeoutRequired = ETrue;
+	    		aPrivacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceVerify);
+	    		break;
+	    		}
+	    	case CLbsAdmin::EExternalLocateOff:
+	    		{
+    			aPrivacyAction = ERequiredPrivacyActionNone;
+	    		aTimeoutRequired = EFalse;
+	    		aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+	    		break;
+	    		}
+	    	case CLbsAdmin::EExternalLocateOffButNotify:
+	    		{
+    			aPrivacyAction = ERequiredPrivacyActionNotify;
+	    		aTimeoutRequired = EFalse;
+	    		aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+	    		aPrivacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify);
+	    		aPrivacy.SetRequestAction(TLbsNetPosRequestPrivacyInt::ERequestActionReject);
+	    		break;
+	    		}
+	    	case CLbsAdmin::EExternalLocateUnknown:
+	    	default:
+	    		{
+	    		LBSLOG2(ELogP4, "CPrivCntrllrHandler::ProcessNetworkLocationRequest : \
+	    						 Unknown Admin setting (0x%x), \
+	    						 rejecting privacy request", aExternalLocate);
+    			aPrivacyAction = ERequiredPrivacyActionNone;
+	    		aTimeoutRequired = EFalse;
+	    		aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+	    		break;
+	    		}
+	    	}
+    	
+    	}
+	}
+
+//================================================================================
+/**
+ * The CPrivacyControllerHandler class handles privacy requests when the
+ * configuration specifies that a Privacy Controller Application is 
+ * present, rather than a Notifier Handler.
+ * Its main task is to pass on messages to the Privacy Controller using 
+ * he NRH server. Communications between this class and the NRH server 
+ * are mediated by internally-defined properties
+ */
+CPrivacyControllerHandler::CPrivacyControllerHandler(CLbsAdmin& aLbsAdmin,
+													 RLbsNetworkRegistrationStatus& aNetRegStatus)  :
+	CPrivacyHandler(aLbsAdmin, aNetRegStatus)
+    {
+	iSessionActive = EFalse;
+	iIsEmergency = EFalse;
+	iAlwaysVerify = EFalse;
+	TInt err = iLbsAdmin.Get(KLbsSettingBehaviourMode, iLbsBehaviourMode);
+	if (err != KErrNone)
+		{
+		iLbsBehaviourMode = CLbsAdmin::ELbsBehaviourCustom1;
+		}	
+    }
+CPrivacyControllerHandler::~CPrivacyControllerHandler()
+	{
+	iRequestBuffer.ResetAndDestroy();
+	iPrivacyResponseTimer->Cancel();
+	delete iPrivacyResponseTimer;
+	delete iEmergencyPrivReq;
+	}
+    
+CPrivacyControllerHandler* CPrivacyControllerHandler::NewL(CLbsAdmin& aLbsAdmin,
+														   RLbsNetworkRegistrationStatus& aNetRegStatus)
+    {
+	CPrivacyControllerHandler* self = new (ELeave)CPrivacyControllerHandler(aLbsAdmin,
+																			aNetRegStatus);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return(self);
+    }
+    
+void CPrivacyControllerHandler::ConstructL()
+	{
+	CActiveScheduler::Add(this);
+	iPrivacyResponseTimer = CLbsCallbackTimer::NewL(*this);
+	iEmergencyPrivReq = CPrivacyRequest::NewL();
+	}
+
+/**
+ * Passes on a privacy request to the server.
+ * @param aSessionId identified the location update session within the LBS System
+ * @param aRequestInfo 	data about the source of the request
+ * @param aNetPosRequestPrivacy defines what notification is necessary (e.g.
+ *                              notify or confirm). 
+ */
+void CPrivacyControllerHandler::ProcessNetworkLocationRequest(TLbsNetSessionIdInt aSessionId, 
+												const TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType,
+												const TLbsExternalRequestInfo&  aRequestInfo, 
+												const TLbsNetPosRequestPrivacyInt& aNetPosRequestPrivacy,
+												TBool aIsEmergency)
+	{	
+	CPrivacyRequest* privReq = NULL;
+	if (aIsEmergency)
+	    {
+	    privReq = iEmergencyPrivReq;
+	    }
+	else
+	    {
+	    TRAPD(err, privReq = CPrivacyRequest::NewL());
+	    if(err != KErrNone)
+	        {
+            // We can do nothing here
+            return;
+	        }
+	    }
+	privReq->SetIsEmergency(aIsEmergency);
+	privReq->SetSessionId(aSessionId);
+	privReq->SetSessionType(aSessionType);
+	privReq->SetRequestInfo(aRequestInfo);
+	// If the admin setting timeout strategy is reject
+	TLbsNetworkEnumInt::TLbsPrivacyResponseInt adminTimeoutAction;
+	GetPrivacyTimeoutAction(adminTimeoutAction, aNetPosRequestPrivacy);
+	if((adminTimeoutAction == TLbsNetworkEnumInt::EPrivacyResponseRejected)
+		&& (aNetPosRequestPrivacy.RequestAdvice() == TLbsNetPosRequestPrivacyInt::ERequestAdviceVerify))
+		{
+		// We should update the request timeout action so it is also reject
+		TLbsNetPosRequestPrivacyInt rejectNetPosRequestPrivacy;
+		rejectNetPosRequestPrivacy.SetRequestAdvice(aNetPosRequestPrivacy.RequestAdvice());
+		rejectNetPosRequestPrivacy.SetRequestAction(TLbsNetPosRequestPrivacyInt::ERequestActionReject);
+		privReq->SetRequestPrivacy(rejectNetPosRequestPrivacy);
+		}
+	else
+		{
+		// Otherwise keep it the same
+		privReq->SetRequestPrivacy(aNetPosRequestPrivacy);
+		}
+	privReq->SetStartTime();
+	iRequestBuffer.Append(privReq);
+	iAlwaysVerify = EFalse;	
+	
+	if (iNrhServer == 0)
+		{
+		if (privReq->IsEmergency())
+			{
+			// No handler to ProcessNetworkLocationRequest - just continue with processing emergency.
+			TLbsNetworkEnumInt::TLbsPrivacyResponseInt response(TLbsNetworkEnumInt::EPrivacyResponseAccepted);    
+			iObserver->OnRespondNetworkLocationRequest(privReq->SessionId(), response, KErrNone);
+			privReq->SetState(CPrivacyRequest::EPrivReqStateResponseSent);
+			return;			
+			}
+		else
+			{
+			// No handler to ProcessNetworkLocationRequest - respond depending on type:
+			// Verify - reject
+			// Notify - default action
+			TLbsNetworkEnumInt::TLbsPrivacyResponseInt response;
+			TInt responseReason = KErrNone;
+			switch (privReq->RequestPrivacy().RequestAdvice())
+				{
+				case TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify:
+					{
+					switch (privReq->RequestPrivacy().RequestAction())
+			    		{
+			    		case TLbsNetPosRequestPrivacyInt::ERequestActionAllow:
+			    			{
+			    			response = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+			    			break;
+			    			}
+			    		case TLbsNetPosRequestPrivacyInt::ERequestActionReject:
+			    			{
+			    			response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			    			break;
+			    			}
+			    		default:
+			    			{
+			    			response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			    			responseReason = KErrArgument;
+			    			break;
+			    			}
+			    		}
+					break;
+					}
+				case TLbsNetPosRequestPrivacyInt::ERequestAdviceVerify:
+					{
+					response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+					responseReason = KErrServerBusy;
+					break;
+					}
+				default:
+					{
+					response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+					responseReason = KErrArgument;
+					break;
+					}
+				}
+			iObserver->OnRespondNetworkLocationRequest(privReq->SessionId(), response, responseReason);
+			privReq->SetState(CPrivacyRequest::EPrivReqStateResponseSent);
+			return;
+			}
+		}
+
+    // The new privacy request must be accepted or rejected, based on a
+    // combination of iPrivacyRequest->RequestPrivacy() settings, LbsAdmin settings
+    // and whether it is an emergency request.
+    //
+    // For a normal privacy request, the privacy controller application usually
+    // has the responsibility for accepting or rejecting it. (Although this depends
+    // on the LbsAdmin settings). 
+    // NOTE (1): Any non-emergency request with RequestAdvice() of ERequestAdviceStealth 
+	//           will be rejected, since this is not currently supported by LBS.
+	// NOTE (2): If the current quality profile Id (admin setting) refers to an invalid
+	//           quality profile then any non-ememrgency request will be rejected.
+    //
+    // For an emergency privacy request, the privacy controller application
+    // is always notified of the request, but it has no say over whether
+    // the request is accepted or not. The request is accepted if the 
+    // RequestAction() is ERequestActionAllow, otherwise it will be rejected.
+    
+    TBool notifyController(EFalse);
+	TBool waitForResponse(ETrue);
+	TLbsNetworkEnumInt::TLbsPrivacyResponseInt response(TLbsNetworkEnumInt::EPrivacyResponseAccepted);    
+	TInt responseReason = KErrNone;
+	TLbsNetPosRequestPrivacyInt privacy = privReq->RequestPrivacy();
+    
+    if (aIsEmergency)
+    	{
+    	// Decide whether to accept or reject an emergency request.
+    	switch (privacy.RequestAction())
+    		{
+    		case TLbsNetPosRequestPrivacyInt::ERequestActionAllow:
+    			{
+    			privacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify);
+    			notifyController = ETrue;
+				waitForResponse = EFalse;
+				response = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+    			break;
+    			}
+    		case TLbsNetPosRequestPrivacyInt::ERequestActionReject:
+    			{
+    			privacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify);
+    			notifyController = ETrue;
+				waitForResponse = EFalse;
+				response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+    			break;
+    			}
+    		default:
+    			{
+	    		LBSLOG2(ELogP4, "CPrivCntrllrHandler::ProcessNetworkLocationRequest : \
+	    						 Unknown RequestAction() (0x%x), \
+	    						 rejecting privacy request", 
+	    						 privacy.RequestAction());
+    			notifyController = EFalse;
+				waitForResponse = EFalse;
+				response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+				responseReason = KErrArgument;
+    			break;
+    			}
+    		}
+    	
+		privReq->SetRequestPrivacy(privacy);	
+    		
+    	}
+    else
+    	{
+    	// Decide wether the privacy controller application should be notified,
+    	// and if not, whether the request should be accepted or rejected.
+    	CLbsAdmin::TExternalLocateService externalLocate(CLbsAdmin::EExternalLocateOff);
+		GetExternalLocateAdminSetting(privReq->SessionType(), externalLocate);
+	    switch (externalLocate)
+	    	{
+	    	case CLbsAdmin::EExternalLocateOn:
+	    		{
+				// Whether we wait for the privacy controller application response
+				// depends on the RequestAdvice() from the network
+				switch (privacy.RequestAdvice())
+					{
+					case TLbsNetPosRequestPrivacyInt::ERequestAdviceVerify:
+						{
+						notifyController = ETrue;
+						waitForResponse = ETrue;
+						break;
+						}
+					case TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify:
+						{
+						switch(privacy.RequestAction())
+							{
+							case TLbsNetPosRequestPrivacyInt::ERequestActionReject:
+								{
+								// automatically reject and inform user
+								notifyController = ETrue;
+								waitForResponse = EFalse;
+								response = TLbsNetworkEnumInt::EPrivacyResponseRejected;								
+								}
+								break;
+							case TLbsNetPosRequestPrivacyInt::ERequestActionAllow:
+								{
+								// Always accept these types of privacy request
+								notifyController = ETrue;
+								waitForResponse = EFalse;
+								response = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+								}
+								break;
+							case TLbsNetPosRequestPrivacy::ERequestActionNotUsed:
+							default:
+								{
+								// Error: Unknown RequestAdvice() value. Send a 
+								// 'reject' back to the network
+					    		LBSLOG2(ELogP4, "CPrivCntrllrHandler::ProcessNetworkLocationRequest : \
+					    						 Unknown TLbsRequestAction() (0x%x), \
+					    						 rejecting privacy request", 
+					    						 privacy.RequestAdvice());
+					    		notifyController = EFalse;
+								waitForResponse = EFalse;
+								response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+								responseReason = KErrArgument;
+								}
+								break;
+							}
+						break;
+						}
+					case TLbsNetPosRequestPrivacyInt::ERequestAdviceSilent:
+						{
+						// Always accept these types of privacy request
+						notifyController = ETrue;
+						waitForResponse = EFalse;
+						// For 'vanilla' lbs we should reject if network action = reject
+						if((iLbsBehaviourMode == CLbsAdmin::ELbsBehaviourModeOriginal) && (privacy.RequestAction() == TLbsNetPosRequestPrivacyInt::ERequestActionReject))
+							{
+							response = TLbsNetworkEnumInt::EPrivacyResponseRejected;							
+							}
+						else	// Always accept these types of privacy request for 'custom1' behaviour
+							{
+							response = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+							privacy.SetRequestAction(TLbsNetPosRequestPrivacyInt::ERequestActionAllow);							
+							}						
+						break;
+						}
+					case TLbsNetPosRequestPrivacyInt::ERequestAdviceStealth:
+						{
+						notifyController = EFalse;
+						waitForResponse = EFalse;
+						response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+						responseReason = KErrNotSupported;
+						break;
+						}
+					default:
+						{
+						// Error: Unknown RequestAdvice() value. Send a 
+						// 'reject' back to the network
+			    		LBSLOG2(ELogP4, "CPrivCntrllrHandler::ProcessNetworkLocationRequest : \
+			    						 Unknown RequestAdvice() (0x%x), \
+			    						 rejecting privacy request", 
+			    						 privacy.RequestAdvice());
+			    		notifyController = EFalse;
+						waitForResponse = EFalse;
+						response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+						responseReason = KErrArgument;
+						break;
+						}
+					}
+	    		break;
+	    		}
+	    	case CLbsAdmin::EExternalLocateOnButAlwaysVerify:
+	    		{
+	    		iAlwaysVerify = ETrue; 	    		
+	    		notifyController = ETrue;
+	    		waitForResponse = ETrue;
+	    		privacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceVerify);
+	    		break;
+	    		}
+	    	case CLbsAdmin::EExternalLocateOff:
+	    		{
+	    		notifyController = EFalse;
+	    		waitForResponse = EFalse;
+	    		response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+	    		break;
+	    		}
+	    	case CLbsAdmin::EExternalLocateOffButNotify:
+	    		{
+	    		notifyController = ETrue;
+	    		waitForResponse = EFalse;
+	    		response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+	    		privacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify);
+	    		privacy.SetRequestAction(TLbsNetPosRequestPrivacyInt::ERequestActionReject);
+	    		break;
+	    		}
+	    	case CLbsAdmin::EExternalLocateUnknown:
+	    	default:
+	    		{
+	    		LBSLOG2(ELogP4, "CPrivCntrllrHandler::ProcessNetworkLocationRequest : \
+	    						 Unknown Admin setting (0x%x), \
+	    						 rejecting privacy request", externalLocate);
+	    		notifyController = EFalse;
+	    		waitForResponse = EFalse;
+	    		response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+	    		responseReason = KErrArgument;
+	    		break;
+	    		}
+	    	}
+	    privReq->SetRequestPrivacy(privacy);	
+    	
+    	// ERequestAdviceStealth is currently not implemented/supported,
+    	// so regardless of the admin settings, etc. reject all requests
+    	// with RequestAdvice() of ERequestAdviceStealth.
+    	if (privReq->RequestPrivacy().RequestAdvice() == TLbsNetPosRequestPrivacyInt::ERequestAdviceStealth)
+    		{
+			notifyController = EFalse;
+			waitForResponse = EFalse;
+			response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			responseReason = KErrNotSupported;
+    		}
+    	
+		// For 'custom1' behaviour, always reject the request if the current quality profile is invalid,
+    	// For 'vanilla' we should allow for no profile in use (quality will be taken from request params)
+    	// note that the profileid is not used here, we just verify whether it exists.
+    	// When the location request arrives the quality settings from the profile are read and used
+	    TLbsQualityProfileId profileId(KLbsNullQualityProfileId);
+	    TInt err = iLbsAdmin.Get(KLbsSettingQualityProfileExternalLocate, profileId);
+	    if (err == KErrNone)	// there should always be a profile setting of some kind in admin
+	    	{
+	    	if(!((iLbsBehaviourMode == CLbsAdmin::ELbsBehaviourModeOriginal) && (profileId == KLbsNoProfileInUseQualityProfileId)))
+	    		{
+		    	TQualityProfile qualityProfile;
+	    		err = LbsQualityProfile::GetQualityProfileById(profileId, qualityProfile);
+	    		}
+	       	}
+		
+		if (err != KErrNone)	// no profile specified in admin, or profile in use and profile doesn't exist in profile ini file
+			{
+			notifyController = EFalse;
+			waitForResponse = EFalse;
+			response = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			}
+    	}
+
+	// If required, send a notification to the privacy controller application.
+	if (notifyController)
+		{
+		iNrhServer->ProcessNetworkLocationRequest(aSessionId, privReq->SessionType(), aRequestInfo, 
+												  privReq->RequestPrivacy(), 
+												  aIsEmergency);
+		iSessionActive = ETrue;
+		iRefPosReported = EFalse;
+		}
+	
+	// If the privacy controller application is responsible for accepting
+	// or rejecting the privacy request, wait for its response
+	if (waitForResponse)
+		{
+		privReq->SetState(CPrivacyRequest::EPrivReqStateWaitPrivacyResponse);
+		
+		// Start a timeout timer, in case the privacy controller application
+		// doesn't reply.
+		CancelResponseTimer();
+		StartResponseTimer();		
+		}
+	else
+		{
+		// Send an immediate response
+		iObserver->OnRespondNetworkLocationRequest(privReq->SessionId(), response, responseReason);
+		// If it's being rejected straight off, make sure any 
+		// 'request completes' which come along later aren't passed on, UNLESS
+		// the controller is to be told about the request (e.g. when the
+		// external locate is EExternalLocateOffButNotify.
+		if(response == TLbsNetworkEnumInt::EPrivacyResponseRejected && !notifyController)
+			{
+			iSessionActive = EFalse;
+			iIsEmergency = EFalse;
+			privReq->SetState(CPrivacyRequest::EPrivReqStateCompleted);
+			}
+		else
+			{
+			privReq->SetState(CPrivacyRequest::EPrivReqStateResponseSent);
+			}
+		}
+	}
+
+/**
+ * Not used. Here for symmetry with the Notifier Handler class
+ */
+void CPrivacyControllerHandler::RunL()
+	{
+	}	
+void CPrivacyControllerHandler::DoCancel()
+	{
+	}
+
+/**
+ * Called when a location update has been received. The data is passed on 
+ * to the server.
+ * @param aSessionId identifies the session within the LBS System
+ * @param aPositionInfo position data to be passed on to the 
+ *                      Privacy Controller
+ */
+void CPrivacyControllerHandler::ProcessNetworkPositionUpdate(
+		TLbsNetSessionIdInt aSessionId, 
+		const TPositionInfo& aPositionInfo)
+	{
+	// If there is no privacy handler, ignore the position update.
+	if (iNrhServer == 0)
+		{
+		return;
+		}
+	
+	CPrivacyRequest* privReq = FindPrivacyRequest(aSessionId, EFalse);
+	if (privReq == NULL)
+		{
+		// Not matching request found, so return.
+		return;
+		}
+
+	// For terminal assisted mode there may be several update requests.
+	// We don't want to bombard the privacy controller with all of these, 
+	// so just send the first one. Position updates that aren't flagged
+	// with PositionMode() of ETechnologyNetwork are  OK - these are 'real' 
+	// updates which the privacy controller wants to know about.
+	if(aPositionInfo.PositionMode() == TPositionModuleInfo::ETechnologyNetwork)
+		{
+		iRefPosReported = ETrue;
+		}
+		
+	if (iNrhServer != 0)
+		{
+		iNrhServer->ProcessNetworkPositionUpdate(
+			privReq->SessionId(), 
+			aPositionInfo);
+		}
+
+	}
+	
+/**
+ * Called when a session complete message has been received. 
+ * The data is passed on to the server.
+ * @param aSessionId identifies the session within the LBS System
+ * @param aReason reason for termination of the session
+ */
+void CPrivacyControllerHandler::ProcessRequestComplete(
+		TLbsNetSessionIdInt aSessionId, 
+		TInt aReason)
+	{
+	CPrivacyRequest* privReq = FindPrivacyRequest(aSessionId, ETrue);
+	if (privReq == NULL)
+		{
+		// Not matching request found, so return.
+		return;
+		}
+
+	if (privReq->State() != CPrivacyRequest::EPrivReqStateCompleted)
+		{
+		// Notify the privacy controller of the session complete message
+		if (iNrhServer != 0)
+			{
+			iNrhServer->ProcessRequestComplete(privReq->SessionId(), aReason);	
+			}
+		privReq->SetState(CPrivacyRequest::EPrivReqStateCompleted);
+		}
+	
+	// Delete the completed request.
+	// do not delete emergency buffer - not onheap
+	if(privReq != iEmergencyPrivReq)
+	    {
+	    delete privReq; 
+	    }
+	// Cancel the response timer, then re-start if any outstanding requests.
+	CancelResponseTimer();
+	StartResponseTimer();
+	}
+
+/**
+ * Called when the server passes on a response to a privacy query.
+ * Message wtaxchers and the timer are stopped, and the response is passed
+ * on to the Privacy and Location Handler subcomponent.
+ * @param aSessionId identifies the session within the LBS System
+ * @param aRequestResult response to the query
+ */
+void CPrivacyControllerHandler::OnRespondNetworkLocationRequest(
+		const TLbsNetSessionIdInt& aRequestId, 
+		TLbsNetworkEnumInt::TLbsPrivacyResponseInt aRequestResult,
+		TInt aResponseReason)
+	{
+	CPrivacyRequest* privReq = FindPrivacyRequest(aRequestId, EFalse);
+	if (privReq)
+		{
+		if (privReq->State() == CPrivacyRequest::EPrivReqStateWaitPrivacyResponse)
+			{
+			iObserver->OnRespondNetworkLocationRequest(
+						privReq->SessionId(), aRequestResult, aResponseReason);
+			privReq->SetState(CPrivacyRequest::EPrivReqStateResponseSent);
+			}
+
+		CancelResponseTimer();
+		StartResponseTimer();
+		}
+	}
+	
+/**
+ * Called when the server passes on cancellation of a privacy query by thet 
+ * Privacy Controller.
+ * Message wtaxchers and the timer are stopped, and the cancellation
+ * is passed on to the Privacy and Location Handler subcomponent.
+ * @param aSessionId identifies the session within the LBS System
+ */
+void CPrivacyControllerHandler::OnCancelNetworkLocationRequest(const TLbsNetSessionIdInt& aRequestId)
+	{
+	CPrivacyRequest* privReq = FindPrivacyRequest(aRequestId, EFalse);
+	if (privReq)
+		{
+		// Cancel/Restart the timeout timer.
+		CancelResponseTimer();
+		StartResponseTimer();
+		
+		// Send cancel to the network.
+		iObserver->OnCancelNetworkLocationRequest(privReq->SessionId());
+		}
+	}
+
+void CPrivacyControllerHandler::StartResponseTimer()
+	{
+	if (iPrivacyResponseTimer->IsActive())
+		{
+		// Timer is currently active, don't start again.
+		return;
+		}
+	
+	// Find the earliest request that is waiting for a response.
+	// (Buffer should be in order of time started, so earliest request
+	// should always be the one nearest the start of the buffer.
+	const TInt count = iRequestBuffer.Count();
+	TUint privacyVerifyTimeoutInMilliSeconds = 0;		
+	// Read timeout from admin (nb: should never fail as we create a default setting in case of absence)
+	iLbsAdmin.Get(KLbsSettingPrivacyAppTimeout, privacyVerifyTimeoutInMilliSeconds);
+	TTimeIntervalMicroSeconds timeout(privacyVerifyTimeoutInMilliSeconds*1000);	
+	for (TInt i = 0; i < count; i++)
+		{
+		if (iRequestBuffer[i]->State() == CPrivacyRequest::EPrivReqStateWaitPrivacyResponse)
+			{
+			// Pending request was found; start the timer.
+			CPrivacyRequest* privReq = iRequestBuffer[i];
+			
+			// Calculate the time at which the request would timeout.			
+			TTime endTime = privReq->StartTime() + timeout;
+			
+			// Start the timer.
+			iPrivacyResponseTimer->EventAtUTC(endTime, 1);
+			
+			break;
+			}
+		}
+	}
+
+void CPrivacyControllerHandler::CancelResponseTimer()
+	{
+	iPrivacyResponseTimer->Cancel();
+	}
+
+/**
+ * Called when the response timer expires.
+ * An accept or reject of the original query is reported to the NRH 
+ * depending on the request action parameter received with the original request.
+ * @param aTimerId always 1 (we only use one timer in this subcomponent)
+ */
+void CPrivacyControllerHandler::OnTimerEventL(TInt aTimerId)
+	{
+	// 1) Get time 'now'
+	// 2) search through all requests to see if 'now' > 'start' + timeout
+	// 3) For each request found in 2), send default response
+	// 4) Need to remove the response from the buffer??
+	// 5) Search through requests to find earliest 'start'
+	// 6) If 5) finds a request, re-start timer for it. 
+	//    (need to calculate revised interval).
+	
+	switch (aTimerId)
+		{
+		case 1:
+			{
+			// Find the earliest request that is waiting for a response.
+			// (Buffer should be in order of time started, so earliest request
+			// should always be the one nearest the start of the buffer.
+			const TInt count = iRequestBuffer.Count();
+			for (TInt i = 0; i < count; i++)
+				{
+				if (iRequestBuffer[i]->State() == CPrivacyRequest::EPrivReqStateWaitPrivacyResponse)
+					{
+					// Found a request in the correct state, assume
+					// this is the one which has timed out.
+					CPrivacyRequest* privReq = iRequestBuffer[i];
+					
+					// The privacy controller has timed out without a response being
+					// received. Generate a response as required depending upon
+					// the LbsAdmin setting: TPrivacyTimeoutAction
+					TLbsNetworkEnumInt::TLbsPrivacyResponseInt response;
+					GetPrivacyTimeoutAction(response, privReq->RequestPrivacy());	
+					iObserver->OnRespondNetworkLocationRequest(privReq->SessionId(), response, KErrNone);
+					
+					privReq->SetState(CPrivacyRequest::EPrivReqStateResponseSent);
+					
+					// Re-start the timer if there are more outstanding requests.
+					StartResponseTimer();
+					break;
+					}
+				}
+			break;
+			}
+		default:
+			// do nothing
+			break;	
+		}
+	}
+	
+TInt CPrivacyControllerHandler::OnTimerError(TInt /*aTimerId*/, 
+											TInt aError)
+	{
+	// Not used - OnTimerEventL doesn't generate any error.
+	return(aError);
+	}
+	
+/**
+ * Establish a connection with a server subsession (there is only ever one)
+ */
+void CPrivacyControllerHandler::SetServerObserver(MLbsSessionObserver* aNrhServer)
+    {
+    iNrhServer = aNrhServer;
+    }
+
+/**
+ * Register the observer of this subcomponent (the Privacy and Location Request 
+ * Handler)
+ */
+void CPrivacyControllerHandler::RegisterObserver(MPrivacyHandlerObserver* aObserver)
+    {
+    iObserver = aObserver;	
+    }
+
+TBool CPrivacyControllerHandler::IsSessionIdMatch(
+		const CPrivacyRequest& aReq1, 
+		const CPrivacyRequest& aReq2)
+	{
+	CPrivacyRequest& req1(const_cast<CPrivacyRequest&>(aReq1));
+	CPrivacyRequest& req2(const_cast<CPrivacyRequest&>(aReq2));
+	
+	return (req1.SessionId().SessionOwner() == req2.SessionId().SessionOwner()
+			&& req1.SessionId().SessionNum() == req2.SessionId().SessionNum());
+	}
+
+CPrivacyRequest* CPrivacyControllerHandler::FindPrivacyRequest(
+		const TLbsNetSessionIdInt& aSessionId,
+		TBool aRemoveRequest)
+	{
+	CPrivacyRequest* privReq = NULL;
+	CPrivacyRequest* matchReq = NULL;
+	TRAPD(err, matchReq = CPrivacyRequest::NewL());
+	if (KErrNone == err)
+		{
+		matchReq->SetSessionId(aSessionId);
+		TInt index = iRequestBuffer.Find(matchReq, IsSessionIdMatch);
+		if (KErrNotFound != index)
+			{
+			privReq = iRequestBuffer[index];
+			if (aRemoveRequest)
+				{
+				iRequestBuffer.Remove(index);
+				}
+			}
+		delete matchReq;
+		}
+	return privReq;
+	}
+
+/** Get the default privacy response based on the admin setting.
+ */
+void CPrivacyControllerHandler::GetPrivacyTimeoutAction(
+		TLbsNetworkEnumInt::TLbsPrivacyResponseInt& aResponse, 
+		const TLbsNetPosRequestPrivacyInt& aRequestPrivacy)
+	{
+	CLbsAdmin::TPrivacyTimeoutAction privacyTimeoutAction;
+	iLbsAdmin.Get(KLbsSettingPrivacyTimeoutAction, privacyTimeoutAction);
+	
+	switch(privacyTimeoutAction)
+		{
+		case CLbsAdmin::EPrivacyTimeoutReject:
+			{
+			aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			break;
+			}
+
+		case CLbsAdmin::EPrivacyTimeoutNetworkDefined:
+			{
+			// For 'vanilla' we shouldn't trust the network-specified action if admin setting says "always verify"			
+			if(aRequestPrivacy.RequestAction() == TLbsNetPosRequestPrivacyInt::ERequestActionReject ||
+					aRequestPrivacy.RequestAction() == TLbsNetPosRequestPrivacyInt::ERequestActionNotUsed ||
+					(iLbsBehaviourMode == CLbsAdmin::ELbsBehaviourModeOriginal && iAlwaysVerify))
+				{
+				aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;				
+				}
+			else
+				{
+				aResponse = TLbsNetworkEnumInt::EPrivacyResponseAccepted;
+				}
+			break;
+			}
+		default:
+			{
+			aResponse = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			break;
+			}
+		}	
+	}