locationrequestmgmt/networkrequesthandler/src/privacyandlocationrequesthandler.cpp
changeset 36 b47902b73a93
child 49 5f20f71a57a3
child 51 95c570bf4a05
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/locationrequestmgmt/networkrequesthandler/src/privacyandlocationrequesthandler.cpp	Fri Jun 04 10:34:15 2010 +0100
@@ -0,0 +1,2835 @@
+// 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 <e32std.h>
+#include <e32property.h>
+#include <centralrepository.h>
+
+#ifdef SYMBIAN_FEATURE_MANAGER
+    #include <featdiscovery.h>
+    #include <featureuids.h>
+#endif
+
+// LBS-specific
+#include <lbs.h>
+#include <lbs/lbsadmin.h>
+#include <lbs/lbslocerrors.h>
+#include <lbs/lbslocclasstypes.h>
+
+#include "nrhpanic.h"
+#include "lbsdevloggermacros.h"
+#include "lbsqualityprofile.h"
+#include "lbsrootcenrepdefs.h"
+#include "lbspositioningstatusprops.h"
+
+#include "privacyandlocationrequesthandler.h"
+
+// Special 'invalid session' SessionId.
+const TLbsNetSessionIdInt KInvalidSessionId(TUid::Uid(0), 0);
+
+const TPositionModuleInfo::TTechnologyType KTerminalAssistedMode = (TPositionModuleInfo::ETechnologyNetwork |
+																	TPositionModuleInfo::ETechnologyAssisted);
+	
+// ----------------------------------------------------------------------------- 
+// 
+// ----------------------- Class CPrivacyAndLocationHandler --------------------
+//
+// State Machine class which owns the states of the Privacy and Location Handler
+//
+// ----------------------------------------------------------------------------- 
+//
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::NewL
+// Description: CPrivacyAndLocationHandler static constructor 
+// ----------------------------------------------------------------------------- 
+//
+CPrivacyAndLocationHandler* CPrivacyAndLocationHandler::NewL(CNGMessageSwitch& aMessageSwitch,
+											CLbsAdmin& aLbsAdmin,
+											RLbsNetworkRegistrationStatus& aNetRegStatus)
+	{
+	CPrivacyAndLocationHandler* self; 
+	self = new (ELeave) CPrivacyAndLocationHandler(aMessageSwitch, aNetRegStatus);
+	CleanupStack::PushL(self);
+	self->ConstructL(&aLbsAdmin);
+	CleanupStack::Pop(self);
+	return(self);	
+	}
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::CPrivacyAndLocationHandler
+// Description: CPrivacyAndLocationHandler constructor 
+// ----------------------------------------------------------------------------- 
+//
+CPrivacyAndLocationHandler::CPrivacyAndLocationHandler(CNGMessageSwitch& aMessageSwitch, 
+													   RLbsNetworkRegistrationStatus& aNetRegStatus)
+:	iNetRegStatus(aNetRegStatus),
+	iMessageSwitch(&aMessageSwitch),
+	iNumActiveSessions(0)
+	{	
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::~CPrivacyAndLocationHandler
+// Description: CPrivacyAndLocationHandler destructor 
+// ----------------------------------------------------------------------------- 
+//
+CPrivacyAndLocationHandler::~CPrivacyAndLocationHandler()
+	{
+	// If iEmergencyFsm has been used by any outstanding request,
+	// it needs to be removed before calling ResetAndDestroy(),
+	// otherwise it will get double-deleted when delete iEmergencyFsm
+	// is called.
+			
+	TInt index = iFsmArray.Find(iEmergencyFsm);
+	if (index >= 0)
+		{
+		iFsmArray.Remove(index);
+		}
+	
+	iFsmArray.ResetAndDestroy();
+
+    // force the count of active network initiated positioning sessions to 0
+	// this supports the pre-APE centric architecture wherein the NRH is
+	// destroyed on completion of network initiated positioning. 
+    RProperty::Set(iPosStatusCategory, KLbsNiPositioningStatusKey, 0);
+
+	delete iEmergencyFsm;
+    delete iAgpsInterface;
+    delete iPrivacyHandler;
+	}
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::ConstructL
+// Description: CPrivacyAndLocationHandler second-phase constructor.
+//              Creates the states of the system and the Privacy Handler.
+// ----------------------------------------------------------------------------- 
+//
+
+const TInt KLbsDefaultMaxNumLocationRequests   = 4;
+
+void CPrivacyAndLocationHandler::ConstructL(CLbsAdmin* aLbsAdmin)
+	{
+	iLbsAdmin = aLbsAdmin;
+	
+	iPrivacyHandler = CPrivacyHandler::CreateL(this, *iLbsAdmin, iNetRegStatus);
+	iMessageSwitch->RegisterObserver(this);
+
+	// Get the behaviour mode and device gps mode capabilities
+	TInt err = iLbsAdmin->Get(KLbsSettingBehaviourMode, iLbsBehaviourMode);
+	if (err != KErrNone)
+		{
+		iLbsBehaviourMode = CLbsAdmin::ELbsBehaviourCustom1;
+		}
+	// get device mode capabilities:
+	err = LbsModuleInfo::GetDeviceCapabilities(KLbsGpsLocManagerUid, iDeviceGpsModeCaps);
+	if(err != KErrNone || (iDeviceGpsModeCaps==TPositionModuleInfoExtended::EDeviceGpsModeNone))
+		{
+		// Assume module supports hybrid if it has not reported its capabilities in module info file
+		iDeviceGpsModeCaps = TPositionModuleInfoExtended::EDeviceGpsModeSimultaneousTATB;
+		}
+
+
+	err = iLbsAdmin->Get(KLbsSettingMaximumExternalLocateRequests, iMaxNumSessions);
+	if (err != KErrNone)
+		{
+		iMaxNumSessions = KLbsDefaultMaxNumLocationRequests;
+		}
+	
+	iAgpsInterface = CAgpsInterfaceHandler::NewL(*this, *iLbsAdmin, iNetRegStatus);
+
+
+#ifdef NRH_UNIT_TEST
+	// For testing use the Uid of the dummy NG
+	const TInt KTestNgUidInt = 0x1028226B;
+	const TUid KTestNgUid = {KTestNgUidInt};
+	iProtocolModuleUid = KTestNgUid;
+#else
+	ReadProtocolModuleAdminSetting();
+#endif
+	
+	iEmergencyFsm = CLbsPrivLocFsm::NewL(*this, KInvalidSessionId);
+	
+	// Reserve space for FSMs. Note "+1" because a pointer to the emergency Fsm gets added to this array
+	iFsmArray.ReserveL(iMaxNumSessions+1);
+
+	CLbsAdmin::TSpecialFeature specialFeature(CLbsAdmin::ESpecialFeatureOff);
+	err = iLbsAdmin->Get(KLbsSpecialFeatureIntermediateFutileUpdate, specialFeature);
+	if (err != KErrNone)
+		{
+		LBSLOG_ERR2(ELogP3, "Failed to get KLbsSpecialFeatureIntermediateFutileUpdate (err %d)", err);
+		}
+	LBSLOG2(ELogP3, "Using KLbsSpecialFeatureIntermediateFutileUpdate = %d", specialFeature);
+	iSpecialFeatureIntermediateFutileUpdate = (specialFeature == CLbsAdmin::ESpecialFeatureOn) ? ETrue : EFalse;
+	
+#ifdef SYMBIAN_FEATURE_MANAGER
+    iLocationManagementSupported = CFeatureDiscovery::IsFeatureSupportedL(NFeature::KLocationManagement);
+#else
+    __ASSERT_ALWAYS(EFalse, User::Invariant()); // Would happen on older versions of symbian OS if this code ever backported
+#endif    
+    
+    // Get the CategoryUid from the cenrep file owned by LbsRoot for accessing Positioning Status P&S Keys
+    CRepository* rep = CRepository::NewLC(KLbsCenRepUid);
+    TInt posStatusCategory;
+    err = rep->Get(KNiPositioningStatusAPIKey, posStatusCategory);
+    User::LeaveIfError(err);
+    CleanupStack::PopAndDestroy(rep);
+    iPosStatusCategory = TUid::Uid(posStatusCategory);
+	}
+
+
+
+/**
+Reads the Uid of a current Protocol Module from the Admin Settings.
+*/
+void CPrivacyAndLocationHandler::ReadProtocolModuleAdminSetting()
+	{
+	LBSLOG(ELogP1, "CPrivacyAndLocationHandler::ReadProtocolModuleAdminSetting()");
+	TLbsProtocolModuleId protUid(KLbsProtocolNullModuleId);
+	
+	TInt err = iLbsAdmin->Get(KLbsSettingHomeProtocolModule, protUid);
+	if (err != KErrNone)
+		{
+		LBSLOG_ERR2(ELogP4, "Failed to get KLbsSettingHomeProtocolModule (err %d)", err);
+		}
+
+	iProtocolModuleUid = protUid;
+	}
+
+/** Compares sessionId for RPointerArray::Find().
+*/
+TBool CPrivacyAndLocationHandler::IsSessionIdEqual(
+		const TLbsNetSessionIdInt* aSessionId,
+		const CLbsPrivLocFsm& aFsm)
+	{
+	return (*aSessionId == aFsm.SessionId());
+	}
+
+/** Compares session type for RPointerArray::Find().
+*/
+TBool CPrivacyAndLocationHandler::IsSessionTypeEqual(
+		const TLbsNetworkEnumInt::TLbsNetProtocolServiceInt* aSessionType,
+		const CLbsPrivLocFsm& aFsm)
+	{
+	return (*aSessionType == const_cast<CLbsPrivLocFsm&>(aFsm).SessionType());
+	}
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::LookupFsm
+// Description: Lookup CLbsPrivLocFsm object by session ID.
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocFsm* CPrivacyAndLocationHandler::LookupFsm(const TLbsNetSessionIdInt& aSessionId)
+	{
+	LBSLOG2(ELogP3, "LookupFsm session=%d", aSessionId.SessionNum());
+
+	// Standard sessions always use the standard state machines.
+	TInt index = iFsmArray.Find(aSessionId, IsSessionIdEqual);
+	if (index >= 0)
+		{
+		LBSLOG(ELogP3, "LookupFsm: Existing standard FSM found");
+		return iFsmArray[index];
+		}
+	else
+		{
+		LBSLOG(ELogP3, "LookupFsm: No standard FSM found");
+		return NULL;		
+		}
+	}
+
+/** Get a new state machine to use for a new request.
+
+The state machine can either be re-using an existing FSM,
+or allocating a new one from the heap or, for emergencies one thats was prepared earlier is used.
+*/
+CLbsPrivLocFsm* CPrivacyAndLocationHandler::GetNewFsm(
+		const TLbsNetSessionIdInt& aSessionId,
+		TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType,
+		TBool aEmergency)
+	{
+	LBSLOG2(ELogP3, "LookupFsm session=%d", aSessionId.SessionNum());
+	
+	CLbsPrivLocFsm* fsm(NULL);
+
+	// If this is an emergency request, use the emergency FSM  
+	// Note, we only have to support ONE emergency at a time
+	// this implies that only one Protcol module may deal with emergencies
+	// So we do NOT support TWO emergencies .. one from each of the PMs
+	// Note: only MT-LR or NI-LR requests can be emergency requests.
+	if (aEmergency
+		&& (aSessionType == MLbsNetworkProtocolObserver::EServiceMobileTerminated
+		|| aSessionType == MLbsNetworkProtocolObserver::EServiceNetworkInduced))
+		{					
+		TInt index = iFsmArray.Find(iEmergencyFsm);
+		if (index >= 0)
+			{
+			iFsmArray.Remove(index);
+			iNumActiveSessions--;
+			}
+		// clean out Fsm
+		iEmergencyFsm->RefPosProcessed() = EFalse;
+		iEmergencyFsm->LocReqReceived() = EFalse;
+		iEmergencyFsm->LocationFixReceived()= EFalse;
+		iEmergencyFsm->TapMode() = EFalse;
+		iEmergencyFsm->WasPrivacyResponseReceivedStateExited() = EFalse;
+		iEmergencyFsm->NetSessionId()= aSessionId;
+		fsm = iEmergencyFsm;
+		}
+	else
+		{
+		if (iNumActiveSessions <= iMaxNumSessions)
+			{
+			// Create a new session to handle this privacy request
+			LBSLOG2(ELogP3, "Creating FSM for new standard request %d",aSessionId.SessionNum());
+			TRAPD(err, fsm = CLbsPrivLocFsm::NewL(*this, aSessionId)); 
+			if (err != KErrNone)
+				{
+				LBSLOG_ERR2(ELogP3, "Failed to create new FSM, error code : %d", err);
+				}
+			}
+		else
+			{
+			LBSLOG_ERR3(ELogP3, "Session start rejected! iNumActiveSessions=%d > iMaxNumSessions=%d", iNumActiveSessions, iMaxNumSessions);
+			}
+		}
+
+	if (fsm)
+		{
+		// Add the state machine to the buffer.
+		iFsmArray.Append(fsm);
+	
+		iNumActiveSessions++; // conceptually, a session starts when a Fsm is created for it
+
+		}
+	
+	return fsm;
+	}
+
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::PrivacyHandler
+// Description: Return a pointer to the privacy handler implementation
+//              (controller or notifier).
+// ----------------------------------------------------------------------------- 
+//
+CPrivacyHandler* CPrivacyAndLocationHandler::PrivacyHandler()
+	{
+	return iPrivacyHandler;
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::MessageSwitch
+// Description: Return a pointer to the Network Gateway Message Switch
+// ----------------------------------------------------------------------------- 
+//
+CNGMessageSwitch* CPrivacyAndLocationHandler::MessageSwitch()
+	{
+	return iMessageSwitch;
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::LbsAdmin
+// Description: Return a pointer to the Admin settings database
+// ----------------------------------------------------------------------------- 
+//
+CLbsAdmin* CPrivacyAndLocationHandler::LbsAdmin()
+	{
+	return iLbsAdmin;
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::SetServerObserver
+// Description: Store a pointer to the NRH server which comunicates with the 
+// Privacy Controller.
+// ----------------------------------------------------------------------------- 
+//
+void CPrivacyAndLocationHandler::SetServerObserver(MLbsSessionObserver* aNrhServer)
+    {
+    PrivacyHandler()->SetServerObserver(aNrhServer);
+    }
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::OnRespondNetworkLocationRequest
+// Description: Called by the Privacy Handler to report the result of a privacy
+// check. Handling of the response is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CPrivacyAndLocationHandler::OnRespondNetworkLocationRequest(const TLbsNetSessionIdInt& aRequestId, 
+                            TLbsNetworkEnumInt::TLbsPrivacyResponseInt aRequestResult,
+                            TInt aResponseReason)
+	{
+	LBSLOG2(ELogP3, "Received response %d to privacy request", aRequestResult);
+	CLbsPrivLocFsm* fsm = LookupFsm(aRequestId);
+	
+	if (NULL != fsm)
+		{
+		fsm->OnRespondNetworkLocationRequest(aRequestId, aRequestResult, aResponseReason);
+		}
+	else
+		{
+		LBSLOG_WARN(ELogP3, "Couldn't find a FSM with matching session Id");
+		}
+    }
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::OnCancelNetworkLocationRequest
+// Description: Called by the Privacy Handler to report that a privacy check 
+// has been rejected. This may occur after it has already been accepted.
+// Handling of the response is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CPrivacyAndLocationHandler::OnCancelNetworkLocationRequest(const TLbsNetSessionIdInt& aRequestId)
+    {
+	LBSLOG2(ELogP3, "Received cancellation to privacy request %d", aRequestId.SessionNum());
+	CLbsPrivLocFsm* fsm = LookupFsm(aRequestId);
+	
+	if (NULL != fsm)
+		{
+		fsm->OnCancelNetworkLocationRequest(aRequestId);
+		}
+	else
+		{
+		LBSLOG_WARN(ELogP3, "Couldn't find a FSM with matching session Id");
+		}
+    }
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::OnMTLRRequest
+// Description: The Message Switch has forwarded a request to start an MTLR 
+// session.
+// Handling of the request is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CPrivacyAndLocationHandler::OnMTLRRequest(const TLbsNetSessionIdInt& aSessionId,
+					   TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+					   TBool aIsEmergency,
+					   const TLbsExternalRequestInfo& aExternalRequestInfo,
+					   const TLbsNetPosRequestPrivacyInt& aNetPosRequestPrivacy)
+	{
+	LBSLOG2(ELogP3, "Received privacy request with id %d", aSessionId.SessionNum());
+	CLbsPrivLocFsm* fsm = LookupFsm(aSessionId);
+
+	if (fsm==NULL)
+		{
+		fsm = GetNewFsm(aSessionId, aSessionType, aIsEmergency);
+		}
+	
+	if (NULL != fsm)
+		{
+		fsm->OnMTLRRequest(aSessionId, 
+						   aSessionType, 
+						   aIsEmergency, 
+						   aExternalRequestInfo, 
+						   aNetPosRequestPrivacy);
+		}
+	else
+		{					
+		// Failed to create a state machine for this request,
+		// so simply reply with a privacy rejection.
+		iMessageSwitch->SendMTLRResponse(aSessionId, 
+										 TLbsNetworkEnumInt::EPrivacyResponseRejected,
+										 KErrGeneral, EFalse); // can't be an emergency cuase we know we have a Fsm for these!
+		}
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::OnSessionComplete
+// Description: The Message Switch has reported that the session is
+// over (complete or aborted due to some error).
+// Handling of the message is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CPrivacyAndLocationHandler::OnSessionComplete(
+									const TLbsNetSessionIdInt& aSessionId,
+									TInt aReason)
+	{
+	LBSLOG3(ELogP3, "Received Session Complete for id %d, reason %d", aSessionId.SessionNum(), aReason);
+	CLbsPrivLocFsm* fsm = LookupFsm(aSessionId);
+	
+	if (NULL != fsm)
+		{
+		fsm->OnSessionComplete(aSessionId, aReason);
+
+		// The session complete marks the end of a session.
+		TInt index = iFsmArray.Find(fsm);
+		if (index != KErrNotFound)
+			{ 
+			
+			if (fsm->SessionType()== TLbsNetworkEnumInt::EServiceSelfLocation)
+				{
+				iMolRFsm = NULL;
+				}
+			else if (fsm->SessionType()== TLbsNetworkEnumInt::EServiceTransmitThirdParty)
+				{
+				iX3pFsm = NULL;
+				}
+			
+			// We should never delete the emergency FSM.
+			iFsmArray.Remove(index);
+			iNumActiveSessions--;
+			
+			if (fsm != iEmergencyFsm)
+				{
+				delete fsm;
+				}
+			}
+		}
+	else
+		{
+		LBSLOG_WARN(ELogP3, "Couldn't find a FSM with matching session Id");
+		}
+	}
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::OnNetLocRequest
+// Description: The Message Switch has passed on a request for a position update
+// Handling of the request is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CPrivacyAndLocationHandler::OnNetLocRequest(
+						const TLbsNetSessionIdInt& aSessionId, 
+						const TLbsNetPosRequestMethodInt& aPosRequestMethod,
+						TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+						TBool aIsEmergency,
+						const TLbsNetPosRequestQualityInt& aQuality)
+	{
+	LBSLOG2(ELogP3, "Received position update request for id %d", aSessionId.SessionNum());
+	
+	TLbsNetSessionIdInt sessionId;
+	TPositionInfo    posInfo;
+	TPosition		 pos;
+	TTime 			 timeStamp;
+	TInt 			 err;
+	
+	TBool tapMode = EFalse;
+	TInt numMethods = aPosRequestMethod.NumPosMethods();
+    if (numMethods==1)
+    	{
+    	TLbsNetPosMethodInt netPosMethod;
+    	aPosRequestMethod.GetPosMethod(0,netPosMethod);
+                 
+    	if (netPosMethod.PosMode()== (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted))
+    		{
+    		tapMode = ETrue;
+    		}
+    	}
+	
+	// This filtering used to be in the NG Message Switch, but has been moved
+	// here to get an access to the ref position bus
+	
+	if( (aSessionType == TLbsNetworkEnumInt::EServiceNetworkLocation) && !tapMode)
+		{
+		// A Network-based location request generates a location 
+		// request to the network request handler, but there's no point 
+		// passing it any further - the AGPS manager & privacy 
+		// controller aren't interested.
+		// Simply return the saved reference location
+		err = iMessageSwitch->GetNetworkReferencePosition(aSessionId, posInfo);			
+		posInfo.GetPosition(pos);
+		timeStamp = pos.Time();
+		TLbsNetPosRequestQualityInt dummyQuality;
+		MessageSwitch()->SendNetLocResponse(aSessionId, err, dummyQuality, posInfo, timeStamp, EFalse);
+		}
+	else
+		{
+		// we note that a self locate MoLr session can be implicitly
+		// cancelled by the start of a new session for a new client.
+		// In this case we complete the session before creating a new
+		// fsm for the new client 
+		CLbsPrivLocFsm* fsm = LookupFsm(aSessionId);
+		if (!fsm)
+			{
+			// here, we need to create a new fsm
+			// We note that only one self locate MolR (or X3p) is supported
+			// a new one will implicitly cancel any ongoing
+			if(aSessionType == TLbsNetworkEnumInt::EServiceSelfLocation)
+				{
+				if (iMolRFsm)
+					{
+					TInt index = iFsmArray.Find(iMolRFsm);
+					if (index != KErrNotFound)
+						{ 
+						iFsmArray.Remove(index);
+						iNumActiveSessions--;
+						delete iMolRFsm;
+						iMolRFsm = NULL;
+						}
+					}
+					
+				}
+			else if(aSessionType == TLbsNetworkEnumInt::EServiceTransmitThirdParty)
+				{
+				if (iX3pFsm)
+					{
+					TInt index = iFsmArray.Find(iX3pFsm);
+					if (index != KErrNotFound)
+						{ 
+						iFsmArray.Remove(index);
+						iNumActiveSessions--;
+						delete iX3pFsm;
+						iX3pFsm = NULL;
+						}
+					}
+				}
+				
+			fsm = GetNewFsm(aSessionId, aSessionType, aIsEmergency);
+			}
+		
+		if (NULL != fsm)
+			{
+			if(aSessionType == TLbsNetworkEnumInt::EServiceSelfLocation)
+				{
+				iMolRFsm = fsm;
+				}
+			else if(aSessionType == TLbsNetworkEnumInt::EServiceTransmitThirdParty)
+				{
+				iX3pFsm = fsm;
+				}
+			
+			fsm->OnNetLocRequest(aSessionId,
+					aPosRequestMethod, 
+			 					aSessionType, 
+								aIsEmergency, 
+								aQuality);
+			}			
+		else
+			{
+			// TODO: Return a dummy loc response with error code?
+			LBSLOG_WARN(ELogP3, "Couldn't find a FSM with matching session Id");
+			}
+		}
+	}
+
+/** Called when a reference position arrives from the network.
+*/
+void CPrivacyAndLocationHandler::OnNetLocReferenceUpdate(
+		const TLbsNetSessionIdInt& aSessionId, 
+		const TPositionInfoBase& aPosInfo)
+	{
+	LBSLOG2(ELogP3, "Received reference position update for id %d", aSessionId.SessionNum());
+	CLbsPrivLocFsm* fsm = LookupFsm(aSessionId);
+	
+	if (NULL != fsm)
+		{
+		fsm->OnNetLocReferenceUpdate(aSessionId, aPosInfo);
+		}
+	else
+		{
+		LBSLOG_WARN(ELogP3, "Couldn't find a FSM with matching session Id");
+		}	
+	}
+
+/** Callend when a final location arrives from the network.
+*/
+void CPrivacyAndLocationHandler::OnNetLocFinalUpdate(
+		const TLbsNetSessionIdInt& aSessionId, 
+		const TPositionInfoBase& aPosInfo)
+	{
+	LBSLOG2(ELogP3, "Received final network position update for id %d", aSessionId.SessionNum());
+	CLbsPrivLocFsm* fsm = LookupFsm(aSessionId);
+	
+	if (NULL != fsm)
+		{
+		fsm->OnNetLocFinalUpdate(aSessionId, aPosInfo);
+		}
+	else
+		{
+		LBSLOG_WARN(ELogP3, "Couldn't find a FSM with matching session Id");
+		}
+	}
+
+/** Callback when a GPS position update arrives from AGPS manager.
+*/
+void CPrivacyAndLocationHandler::OnAgpsPositionUpdate(
+	TInt aReason,
+	const TPositionExtendedSatelliteInfo& aPosInfo,
+	const TTime& aTimeStamp)
+	{
+	// Broadcast the update to all state machines.
+	const TInt count = iFsmArray.Count();
+	for (TInt i = 0; i < count; i++)
+		{
+		iFsmArray[i]->OnAgpsPositionUpdate(aReason, aPosInfo, aTimeStamp);
+		}
+	}
+
+/** Callback when a GPS measurement results update arrives from AGPS manager.
+*/
+void CPrivacyAndLocationHandler::OnAgpsMeasurementUpdate(
+	TInt aReason,
+	const TPositionGpsMeasurementInfo& aPosInfo,
+	const TTime& aTimeStamp)
+	{
+	// Broadcast the update to all state machines
+	const TInt count = iFsmArray.Count();
+	for (TInt i = 0; i < count; i++)
+		{
+		iFsmArray[i]->OnAgpsMeasurementUpdate(aReason, aPosInfo, aTimeStamp);
+		}
+	}
+
+/**
+*/
+CAgpsInterfaceHandler* CPrivacyAndLocationHandler::AgpsHandler()
+	{
+	return iAgpsInterface;
+	}
+	
+// -----------------------------------------------------------------------------
+// CPrivacyAndLocationHandler::DeviceGpsModeCaps
+// Description: Return the device mode capabilities
+// -----------------------------------------------------------------------------
+//
+TPositionModuleInfoExtended::TDeviceGpsModeCapabilities CPrivacyAndLocationHandler::DeviceGpsModeCaps()
+	{
+	return iDeviceGpsModeCaps;
+	}
+
+// -----------------------------------------------------------------------------
+// CPrivacyAndLocationHandler::BehaviourMode
+// Description: Return the behaviour mode setting
+// -----------------------------------------------------------------------------
+//
+CLbsAdmin::TLbsBehaviourMode CPrivacyAndLocationHandler::BehaviourMode()
+	{
+	return iLbsBehaviourMode;
+	}
+
+RLbsNetworkRegistrationStatus& CPrivacyAndLocationHandler::NetworkRegistrationStatus()
+	{
+	return iNetRegStatus;
+	}
+
+// increments the P&S key tracking mobile terminated positioning requests
+void CPrivacyAndLocationHandler::IncrementPositioningStatus()
+    {
+    TInt count;     
+    RProperty::Get(iPosStatusCategory, KLbsNiPositioningStatusKey, count);
+    RProperty::Set(iPosStatusCategory, KLbsNiPositioningStatusKey, count+1);
+    }
+
+// decrements the P&S key tracking mobile terminated positioning requests
+// if location management is supported. In the alternative architecture,
+// the NRH is not aware of the positioning session's progress, but is 
+// transient. Therefore the positioning status is set to zero in the 
+// class destructor.
+void CPrivacyAndLocationHandler::DecrementPositioningStatus()
+    {
+    if (iLocationManagementSupported)
+        {
+        TInt count;     
+        RProperty::Get(iPosStatusCategory, KLbsNiPositioningStatusKey, count);
+        if(count>0)
+            {
+            RProperty::Set(iPosStatusCategory, KLbsNiPositioningStatusKey, count-1);
+            }
+        else
+            {
+            LBSLOG_ERR(ELogP3, "CPrivacyAndLocationHandler::DecrementPositioningStatus() - Incorrect Positioning Status count\n");
+            }
+        }
+    }
+	
+
+/**
+*/
+MX3pStatusHandler& CPrivacyAndLocationHandler::X3pStatusHandler()
+	{
+	return *iAgpsInterface;
+	}
+
+/** Returns ETrue if KLbsSpecialFeatureIntermediateFutileUpdate is on.
+@return ETrue if the special feature is on, EFalse otherwise.
+*/
+TBool CPrivacyAndLocationHandler::IsSpecialFeatureIntermediateFutileUpdateOn()
+	{
+	return iSpecialFeatureIntermediateFutileUpdate;
+	}
+
+// ----------------------------------------------------------------------------- 
+// 
+// ----------------------- Class CLbsPrivLocStateBase --------------------
+//
+// This class is not intended for instantiation. Implemented functions are
+// those common to multiple derived states
+//
+// ----------------------------------------------------------------------------- 
+//
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocStateBase::OnCancelNetworkLocationRequest
+// Description: Pass on a received privacy request cancel to the network gateway, 
+// if it relates to the current session. 
+// This behaviour is common to states EStateWaitLocationRequest,
+// EStateWaitLocationUpdate and EStateWaitPrivacyResponse.
+// Other states ignore the event.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocStateBase::OnCancelNetworkLocationRequest(const TLbsNetSessionIdInt& aSessionId)
+	{
+	/* Ignore the cancel if this is an emergency request */
+	if(!iFsm->IsEmergency())
+		{
+		// Also ignore it if the cancel doesn't relate to this session.
+		if(aSessionId == iFsm->SessionId())
+			{
+			iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitCancelledByPrivacyController, KErrCancel);
+			iFsm->ChangeState(CLbsPrivLocFsm::EStateIdle, aSessionId);
+			}
+		}
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocStateBase::OnEntry
+// Description: Handles initialisation actions which are common to multiple states. 
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocStateBase::OnEntry(const TPrivLocCommonParams& /* aStateParams */)
+	{
+	// Exit reason should always be explicitly set by a state, 
+	// otherwise OnExit() will panic
+	iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitReasonNone, KErrNone);
+	}
+	
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocStateBase::OnExit
+// Description: Handles exit actions which are common to multiple states. 
+// Any exit reason not handled here is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+TBool CLbsPrivLocStateBase::OnExit()
+	{
+	TBool consumed = ETrue;
+	switch(iFsm->iExitData.iExitReason)
+		{
+		case TPrivLocStateExitData::EExitSessionComplete:
+			{
+			// Tell the AGPS interface handle this location request has finished.
+			AgpsInterface()->StopPositioning(iFsm->SessionId());
+
+			// Tell the privacy controller this session is finished.
+			PrivacyHandler()->ProcessRequestComplete(iFsm->SessionId(),
+													 iFsm->ExitData().iExitInfo);
+			break;
+			}
+
+		case TPrivLocStateExitData::EExitCancelledByPrivacyController:
+			{
+			// Send a cancel to the network gateway
+			TPositionInfo dummyPosInfo;
+			TTime dummyTime;
+			TLbsNetPosRequestQualityInt dummyQuality;
+			MessageSwitch()->SendNetLocResponse(iFsm->SessionId(),
+												iFsm->ExitData().iExitInfo,
+												dummyQuality,
+												dummyPosInfo,
+												dummyTime,
+												iFsm->IsEmergency());
+			}
+			break;
+
+		case TPrivLocStateExitData::EExitLocReqReceived:
+			// No action required - request is issued on entry to next state.
+		case TPrivLocStateExitData::EExitPrivacyRequestReceived:
+			// No action required, state moves to waiting for loc request.
+			{
+			consumed = ETrue;
+			break;			
+			}
+			
+		default:
+			{
+			// Don't know what to do with it.
+			consumed = EFalse;
+			break;							
+			}
+		}
+	return(consumed);
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocStateBase::HandleLocRequest
+// Description: Common handling of a location request received while the 
+// Privacy and Location Handler is dealing with a session.
+// 
+// If the session type is anything but MTLR, then it is processed, otherwise
+// a privacy request is generated
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocStateBase::HandleLocRequest(const TLbsNetSessionIdInt& aSessionId, 
+						 const TLbsNetPosRequestMethodInt& aPosRequestMethod,
+						 TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+						 TBool aIsEmergency,
+						 const TLbsNetPosRequestQualityInt& aQuality)
+	{
+	// MTLR.
+	if (aSessionType == TLbsNetworkEnumInt::EServiceMobileTerminated)
+		{
+		// An MTLR with out a prior privacy request is not supported, report error via
+		// RespondLocationRequest(dummy position).
+		TPositionInfo dummyPosInfo;
+		TTime dummyTime;
+		TLbsNetPosRequestQualityInt dummyQuality;
+
+		MessageSwitch()->SendNetLocResponse(aSessionId,
+											KErrNotSupported,
+											dummyQuality,
+											dummyPosInfo,
+											dummyTime, aIsEmergency); 
+		}
+
+	// Network Induced.	
+	else if (aSessionType == TLbsNetworkEnumInt::EServiceNetworkInduced)
+		{
+		// If a request for a position update has been received without
+		// a privacy request, then there's nothing to say how the user
+		// should be informed or what do do if there is no response.
+		// The safest thing is to get the user to confirm (verify)
+		// the request, and in the absence of confirmation to reject the
+		// request. For emergency requests we notify and accept.
+		
+		// Store the loc req.
+		iFsm->LocReqReceived() = ETrue;
+
+		iFsm->IsEmergency() = aIsEmergency;
+		iFsm->NetRequestQuality() = aQuality;
+		iFsm->PosRequestMethod() = aPosRequestMethod;
+
+
+		// The following notification types are chosen based on the emergency and network requests admin status.
+		//
+		// Emergency = On, Admin = Any, gives ENotifyLocationAccepted 
+		// Emergency = Off,	Admin = On, gives ENotifyLocationAccepted
+		// Emergency = Off,	Admin = OnButAlwayVerify, gives ENotifyAndVerifyLocationRejectedIfNoResponse
+		// Emergency = Off, Admin = Off, N/A the notifier or controller will not be called
+		// Emergency = Off, Admin = OffButNotify, gives ENotifyLocationRejected
+		TLbsNetPosRequestPrivacyInt requestPrivacy;
+		
+		requestPrivacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceNotify);
+		requestPrivacy.SetRequestAction(TLbsNetPosRequestPrivacyInt::ERequestActionAllow);
+
+		// Verifications are rejected after timeout.
+		CLbsAdmin::TExternalLocateService externalLocate(CLbsAdmin::EExternalLocateOff);
+
+		ReadNetworkInducedAdminSetting(externalLocate);
+		if ((externalLocate == CLbsAdmin::EExternalLocateOnButAlwaysVerify) && (!aIsEmergency))
+			{
+	    	requestPrivacy.SetRequestAdvice(TLbsNetPosRequestPrivacyInt::ERequestAdviceVerify);
+	    	requestPrivacy.SetRequestAction(TLbsNetPosRequestPrivacyInt::ERequestActionReject);
+			}
+
+		// Similarly, default values have to be assigned to the external request info.
+		TLbsExternalRequestInfo requestInfo;
+		_LIT8(KUnknownExternalReqInfoField, "");
+		requestInfo.SetRequesterId(KUnknownExternalReqInfoField);
+		requestInfo.SetClientName(KUnknownExternalReqInfoField);
+		requestInfo.SetClientExternalId(KUnknownExternalReqInfoField);
+
+
+		// Process the privacy request.		
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocReqReceived, KErrNone);
+		
+		TPrivLocWaitPrivResponseParams privacyRequestParams(aSessionId, aSessionType, requestInfo, requestPrivacy, aIsEmergency);
+		iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitPrivacyResponse, privacyRequestParams);
+		}
+	
+	// All other location requests.
+	else
+		{
+		TPrivLocWaitLocationUpdateParams updateRequestParams(aSessionId,
+															aPosRequestMethod,
+															aSessionType,
+															aIsEmergency,
+															aQuality);
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitSessionComplete, KErrCancel);
+		iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationUpdate, updateRequestParams);
+		}
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocStateBase::OnSessionComplete
+// Description: Common handling of a session complete message received other
+// than when it is expected as normal session completion.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocStateBase::OnSessionComplete(const TLbsNetSessionIdInt& aSessionId,
+																TInt aReason)
+	{
+	if(aSessionId == iFsm->SessionId())
+		{
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitSessionComplete, aReason);
+		iFsm->ChangeState(CLbsPrivLocFsm::EStateIdle, aSessionId);
+		}		
+	}
+
+/** Called when a reference position arrives from the network.
+*/
+void CLbsPrivLocStateBase::OnNetLocReferenceUpdate(
+		const TLbsNetSessionIdInt& /*aSessionId*/ , 
+		const TPositionInfoBase& aPosInfo)
+	{
+	TLbsNetworkEnumInt::TLbsNetProtocolServiceInt sessionType = iFsm->SessionType();
+	__ASSERT_DEBUG((sessionType != MLbsNetworkProtocolObserver::EServiceNone), Panic(ENrhPanicBadParamType));
+
+	if( ((sessionType == MLbsNetworkProtocolObserver::EServiceNetworkInduced) || 
+											   (sessionType == MLbsNetworkProtocolObserver::EServiceMobileTerminated)))
+		{
+		TPositionInfo posInfo = static_cast<const TPositionInfo&>(aPosInfo);
+		
+		// Set the module Id and position mode for the reference position.
+		// These values are not 'real' values, since this position
+		// came directly from the network and not one of the location
+		// managers within LBS.
+		posInfo.SetModuleId(KLbsGpsLocManagerUid);
+		posInfo.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork);
+		posInfo.SetPositionModeReason(EPositionModeReasonNone);
+		posInfo.SetUpdateType(EPositionUpdateGeneral);
+		
+		if (!iFsm->RefPosProcessed())
+			{
+			iFsm->RefPosProcessed() = ETrue;
+			PrivacyHandler()->ProcessNetworkPositionUpdate(iFsm->SessionId(), posInfo);
+			}
+
+		}	
+	}
+
+/* Timer callback called when the MaxFixTime for a gps location update request has expired. 
+
+The default action is to ignore this callback. Any state interested in it must
+implement its own version.
+*/
+void CLbsPrivLocStateBase::OnTimerEventL(TInt /*aTimerId*/)
+	{
+	}
+
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocStateBase::ReadNetworkInducedAdminSetting
+// Description: Determine the external location value from the admin settings for network induced location requests.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocStateBase::ReadNetworkInducedAdminSetting(CLbsAdmin::TExternalLocateService& aExternalLocateService)
+	{
+	CLbsAdmin::TExternalLocateService serviceStatus(CLbsAdmin::EExternalLocateOff);
+	RLbsNetworkRegistrationStatus::TLbsNetworkRegistrationStatus netRegStatus(RLbsNetworkRegistrationStatus::ENetworkRegistrationUnknown);	
+	TInt err = LbsNetworkRegistrationStatus().GetNetworkRegistrationStatus(netRegStatus);
+	if (err == KErrNone)
+		{
+		switch (netRegStatus)
+			{
+			case RLbsNetworkRegistrationStatus::ERegisteredHomeNetwork:
+				{
+				err = LbsAdmin()->Get(KLbsSettingHomeNetworkInducedLocate, serviceStatus);
+				break;
+				}
+			case RLbsNetworkRegistrationStatus::ERegisteredRoamingNetwork:
+			case RLbsNetworkRegistrationStatus::ENotRegistered:
+				{
+				err = LbsAdmin()->Get(KLbsSettingRoamingNetworkInducedLocate, serviceStatus);
+				break;
+				}		
+			case RLbsNetworkRegistrationStatus::ENetworkRegistrationUnknown:
+			default:
+				{
+				LBSLOG_WARN2(ELogP4, "Unrecognised TLbsNetworkRegistrationStatus (%d), defaulting to EExternalLocateOff",
+							 netRegStatus);
+				serviceStatus = CLbsAdmin::EExternalLocateOff;
+				break;
+				}
+			}
+		}
+	else
+		{
+		LBSLOG_WARN2(ELogP4, "Failed to get TExternalLocateService, couldn't read roaming status (err %d), defaulting to EExternalLocateOff",  
+					 err);		
+		}
+	
+	aExternalLocateService = serviceStatus;
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocStateBase::CLbsPrivLocStateBase
+// Description: Constructor
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocStateBase::CLbsPrivLocStateBase(CLbsPrivLocFsm* aFsm)
+:	iFsm(aFsm)
+	{	
+	}
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocStateBase::PrivacyHandler, MessageSwitch, LbsAdmin
+// Description: Allows concrete states access to NRH resources passed to
+// the FSM
+// Returns: pointers.
+// ----------------------------------------------------------------------------- 
+//
+CPrivacyHandler* CLbsPrivLocStateBase::PrivacyHandler()
+	{
+	return iFsm->PrivLocHandler().PrivacyHandler();
+	}
+CNGMessageSwitch* CLbsPrivLocStateBase::MessageSwitch()
+	{
+	return iFsm->PrivLocHandler().MessageSwitch();
+	}
+CLbsAdmin* CLbsPrivLocStateBase::LbsAdmin()
+	{
+	return iFsm->PrivLocHandler().LbsAdmin();
+	}
+CAgpsInterfaceHandler* CLbsPrivLocStateBase::AgpsInterface()
+	{
+	return iFsm->PrivLocHandler().AgpsHandler();
+	}
+
+
+TPositionModuleInfoExtended::TDeviceGpsModeCapabilities CLbsPrivLocStateBase::DeviceGpsModeCaps()
+	{
+	return iFsm->PrivLocHandler().DeviceGpsModeCaps();
+	}
+
+CLbsAdmin::TLbsBehaviourMode CLbsPrivLocStateBase::BehaviourMode()
+	{
+	return iFsm->PrivLocHandler().BehaviourMode();
+	}
+
+RLbsNetworkRegistrationStatus& CLbsPrivLocStateBase::LbsNetworkRegistrationStatus()
+	{
+	return iFsm->PrivLocHandler().NetworkRegistrationStatus();
+	}
+
+/*
+ * increments the network initiated positioning status count
+ * and remembers that it has done
+ */
+void CLbsPrivLocStateBase::IncrementPositioningStatus()
+    {
+    iFsm->PrivLocHandler().IncrementPositioningStatus();
+    iFsm->WasPositioningStatusIncremented() = ETrue;
+    }
+
+
+// ----------------------------------------------------------------------------- 
+// 
+// ----------------------- Class CLbsPrivLocIdleState --------------------
+//
+// Implements the Idle state of the Privacy and Location Request Handler
+//
+// ----------------------------------------------------------------------------- 
+//
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocIdleState::NewL
+// Description: CLbsPrivLocIdleState static constructor 
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocIdleState* CLbsPrivLocIdleState::NewL(CLbsPrivLocFsm* aFsm)
+	{
+	return new (ELeave) CLbsPrivLocIdleState(aFsm);
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocIdleState::CLbsPrivLocIdleState
+// Description: CLbsPrivLocIdleState constructor.
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocIdleState::CLbsPrivLocIdleState(CLbsPrivLocFsm* aFsm) 
+: CLbsPrivLocStateBase(aFsm)
+	{
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocIdleState::OnEntry
+// Description: Carries out tasks required on entry to the state.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocIdleState::OnEntry(const TPrivLocCommonParams& aStateParams)
+	{
+	CLbsPrivLocStateBase::OnEntry(aStateParams);
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocIdleState::OnExit
+// Description: Carries out tasks required on exit from the state.
+// Panics if the exit reason is not handled by the base state exit
+// ----------------------------------------------------------------------------- 
+//
+TBool CLbsPrivLocIdleState::OnExit()
+	{
+	TBool consumed = CLbsPrivLocStateBase::OnExit();
+	// If the exit reason wasn't handled, panic (should only happen in development)
+	__ASSERT_DEBUG(consumed, Panic(ENrhPanicIdleUnknownExitReason));
+	
+	return(consumed);
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocIdleState::OnNetLocRequest
+// Description: The Message Switch has forwarded a request for a control 
+// measurement.
+// If the session type is anything but MTLR, then it is processed, otherwise
+// a privacy request is generated
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocIdleState::OnNetLocRequest(
+		const TLbsNetSessionIdInt& aSessionId,
+		const TLbsNetPosRequestMethodInt& aPosRequestMethod,
+		TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+		TBool aIsEmergency,
+        const TLbsNetPosRequestQualityInt& aQuality)
+    {
+    iFsm->SessionType() = aSessionType;
+    if(iFsm->WasPrivacyResponseReceivedStateExited())
+        {
+        // The request relates to a rejected privacy request
+        // or a request for this session which has already been answered. 
+        // In either case, it should be refused. The message is sent to the
+        // network gateway as a part of exit from the state, but we want to 
+        // remain in Idle state.
+        iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitCancelledByPrivacyController, KErrAccessDenied);
+        iFsm->ChangeState(CLbsPrivLocFsm::EStateIdle, aSessionId);
+        }
+    else
+        {
+        TInt numMethods = aPosRequestMethod.NumPosMethods();
+        if (numMethods==1)
+            {
+            TLbsNetPosMethodInt netPosMethod;
+            aPosRequestMethod.GetPosMethod(0,netPosMethod);
+                    
+            if (netPosMethod.PosMode()== (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted))
+                {
+                iFsm->TapMode() = ETrue;
+                }
+            }
+        
+            
+        if ((aSessionType != MLbsNetworkProtocolObserver::EServiceMobileTerminated) &&
+            (aSessionType != MLbsNetworkProtocolObserver::EServiceNetworkInduced))
+            {
+            iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocReqReceived, KErrNone);
+            TPrivLocWaitLocationUpdateParams updateRequestParams(aSessionId,
+                                                            aPosRequestMethod,
+                                                            aSessionType,
+                                                            aIsEmergency,
+                                                            aQuality);
+            iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationUpdate, updateRequestParams);
+            }
+            else
+            {
+            // It's a request for a different session. Need to find out what to do with it.
+            HandleLocRequest(aSessionId, aPosRequestMethod, 
+                                    aSessionType,aIsEmergency,
+                                    aQuality);
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocIdleState::OnMTLRRequest
+// Description: The Message Switch has forwarded a request for a location update
+// (a privacy request) 
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocIdleState::OnMTLRRequest(const TLbsNetSessionIdInt& aSessionId,
+				TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType,
+				TBool aIsEmergency,
+				const TLbsExternalRequestInfo& aExternalRequestInfo,
+				const TLbsNetPosRequestPrivacyInt& aNetPosRequestPrivacy)
+	{
+	iFsm->SessionType() = aSessionType;
+	iFsm->ExternalRequestType() = aExternalRequestInfo.RequestType();
+	iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitPrivacyRequestReceived, KErrNone);
+	TPrivLocWaitPrivResponseParams privacyRequestParams(	aSessionId, 
+													aSessionType,
+													aExternalRequestInfo, 
+													aNetPosRequestPrivacy,
+													aIsEmergency);
+	iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitPrivacyResponse, privacyRequestParams);
+	}
+
+/** Called when a reference position arrives from the network.
+ * 
+*/
+void CLbsPrivLocIdleState::OnNetLocReferenceUpdate(
+		const TLbsNetSessionIdInt& /*aSessionId*/, 
+		const TPositionInfoBase& /* aPosInfo */)
+	{
+	// note that the reference postion is stored by the message switch
+	// so here we don't need to save it again!
+	}
+	
+// ----------------------------------------------------------------------------- 
+// 
+// ----------------------- Class CLbsPrivLocWaitPrivRespState --------------------
+//
+// Implements the Idle state of the Privacy and Location Request Handler
+//
+// ----------------------------------------------------------------------------- 
+//
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitPrivRespState::NewL
+// Description: CLbsPrivLocIdleState static constructor 
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocWaitPrivRespState* CLbsPrivLocWaitPrivRespState::NewL(CLbsPrivLocFsm* aFsm)
+	{
+	return new (ELeave) CLbsPrivLocWaitPrivRespState(aFsm);
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitPrivRespState::CLbsPrivLocWaitPrivRespState
+// Description: CLbsPrivLocWaitPrivRespState constructor.
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocWaitPrivRespState::CLbsPrivLocWaitPrivRespState(CLbsPrivLocFsm* aFsm)
+: CLbsPrivLocStateBase(aFsm)
+	{
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitPrivRespState::OnEntry
+// Description: Actions performed when the state is entered.
+// Unpack the parameters and issue the privacy request.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitPrivRespState::OnEntry(const TPrivLocCommonParams& aStateParams)
+	{
+	CLbsPrivLocStateBase::OnEntry(aStateParams);
+	const TPrivLocWaitPrivResponseParams& params = TPrivLocWaitPrivResponseParams::Cast(const_cast<TPrivLocCommonParams&>(aStateParams));	
+	iFsm->SessionType() = params.iSessionType;
+	iFsm->IsEmergency() = params.iIsEmergency;
+
+	PrivacyHandler()->ProcessNetworkLocationRequest(iFsm->SessionId(), 
+													iFsm->SessionType(),
+													params.iExternalRequestInfo, 
+													params.iNetPosRequestPrivacy,
+													iFsm->IsEmergency());	
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitPrivRespState::OnExit
+// Description: Actions performed on leaving the state.
+// ----------------------------------------------------------------------------- 
+//
+TBool CLbsPrivLocWaitPrivRespState::OnExit()
+	{
+	TInt consumed = EFalse;
+	switch(iFsm->ExitData().iExitReason)
+		{
+		case TPrivLocStateExitData::EExitPrivacyResponseReceived:
+			{
+            // Remember that we exited the privacy response received state 
+			// so that we can deny the network location requests in the idle staet.
+
+            iFsm->WasPrivacyResponseReceivedStateExited() = ETrue;
+
+			
+			// For the NI case a Reference position may have arrived by now
+			// So we must pass this onto the privacy handler.
+
+			if (iFsm->SessionType() == MLbsNetworkProtocolObserver::EServiceNetworkInduced) 
+				{
+				if (iFsm->PrivacyResponse() == CLbsNetworkProtocolBase::EPrivacyResponseAccepted)
+					{
+					TPositionInfo posInfo;
+					TInt err = MessageSwitch()->GetNetworkReferencePosition(iFsm->SessionId(), posInfo);
+					if (KErrNone == err)
+						{
+						if (!iFsm->RefPosProcessed())
+							{
+							iFsm->RefPosProcessed() = ETrue;
+							PrivacyHandler()->ProcessNetworkPositionUpdate(iFsm->SessionId(), posInfo);
+							}
+				
+						}
+					
+					}
+				}		
+				
+			// For MtLrs the Protocol module should not
+			// send a REF position until after we have sent the Priv response to the PM 
+	            
+			// Inform network of the privacy response for normal privacy requests.
+			if (iFsm->SessionType() == TLbsNetworkEnumInt::EServiceMobileTerminated)
+				{
+				MessageSwitch()->SendMTLRResponse(iFsm->SessionId(), iFsm->PrivacyResponse(), iFsm->PrivacyResponseReason(), iFsm->IsEmergency());	
+				}
+
+			// Inform network of a rejected privacy response via a "RespondLocationRequest" for faked privacy requests (generated internaly).
+			else if ((iFsm->SessionType() == TLbsNetworkEnumInt::EServiceNetworkInduced) && (iFsm->PrivacyResponse() == TLbsNetworkEnumInt::EPrivacyResponseRejected))
+				{
+				// The faked privacy request was rejected, so reject the location request.
+				TPositionInfo dummyPosInfo;
+				TTime dummyTime;
+				TLbsNetPosRequestQualityInt dummyQuality;
+
+				MessageSwitch()->SendNetLocResponse(iFsm->SessionId(),
+													KErrAccessDenied,
+													dummyQuality,
+													dummyPosInfo,
+													dummyTime,
+													iFsm->IsEmergency());
+				}
+			
+			consumed = ETrue;
+			break;
+			}
+
+		case TPrivLocStateExitData::EExitCancelledByPrivacyController:
+			{
+			// Send a cancel to the network gateway
+			iFsm->PrivacyResponse() = TLbsNetworkEnumInt::EPrivacyResponseRejected;
+			iFsm->PrivacyResponseReason() = KErrCancel;
+			MessageSwitch()->SendMTLRResponse(iFsm->SessionId(), iFsm->PrivacyResponse(), iFsm->PrivacyResponseReason(), iFsm->IsEmergency());
+			consumed = ETrue;
+			}
+			break;
+
+		default:
+			{
+			consumed = CLbsPrivLocStateBase::OnExit();
+			// If the exit reason wasn't handled, panic (should only happen in development)
+			__ASSERT_DEBUG(consumed, Panic(ENrhPanicWaitPrivRespUnknownExitReason));
+			break;
+			}
+		}
+		
+	iFsm->LocReqReceived() = EFalse;
+
+	return(consumed);
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitPrivRespState::OnRespondNetworkLocationRequest
+// Description: Pass on a received privacy response to the network gateway, if
+// it relates to the current session.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitPrivRespState::OnRespondNetworkLocationRequest(
+											const TLbsNetSessionIdInt& aSessionId, 
+											TLbsNetworkEnumInt::TLbsPrivacyResponseInt aRequestResult,
+											TInt /* aResponseReason*/)
+	{
+
+	if(aSessionId == iFsm->SessionId())
+		{
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitPrivacyResponseReceived, KErrNone);
+		iFsm->PrivacyResponse() = aRequestResult;
+		if(iFsm->PrivacyResponse() == TLbsNetworkEnumInt::EPrivacyResponseAccepted)
+			{
+			// Tell the AGPS handler that we are going to start a location request soon.
+			AgpsInterface()->PreStartPositioning(iFsm->SessionId(), iFsm->IsEmergency());
+			
+			// Set the Positioning Status for the UI indicator.
+			// Not done for silent requests.
+			if (iFsm->ExternalRequestType() < TLbsExternalRequestInfo::ERequestSingleShotSilent)
+			    {
+                IncrementPositioningStatus();
+			    }
+			
+			if(iFsm->LocReqReceived())
+				{				
+				TPrivLocWaitLocationUpdateParams updateRequestParams(iFsm->SessionId(),
+																iFsm->PosRequestMethod(),
+																iFsm->SessionType(),
+																iFsm->IsEmergency(),
+																iFsm->NetRequestQuality());
+				iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationUpdate, updateRequestParams);	            
+				}
+			else
+				{
+				TPrivLocWaitLocationRequestParams locationRequestParams(iFsm->SessionId(),
+																		iFsm->IsEmergency(),
+																		EFalse);
+				iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationRequest, locationRequestParams);
+				}
+			}
+		else
+			{
+			iFsm->ChangeState(CLbsPrivLocFsm::EStateIdle, aSessionId);
+			}
+		}
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitPrivRespState::OnNetLocRequest
+// Description: The Message Switch has forwarded a request for a control 
+// measurement.
+// If the session Id is the same as the current one, then save the parameters
+// so that the request can be issued when privacy is accepted.
+// Otherwise (the session Id is different) a cancel is implied and we cancel 
+// the current session and start another, which may or may not require a new 
+// privacy query.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitPrivRespState::OnNetLocRequest(
+		const TLbsNetSessionIdInt& aSessionId,
+		const TLbsNetPosRequestMethodInt& aPosRequestMethod,
+		TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+		TBool aIsEmergency,
+        const TLbsNetPosRequestQualityInt& aQuality)
+	{	
+	TInt numMethods = aPosRequestMethod.NumPosMethods();
+	if (numMethods==1)
+		{
+		TLbsNetPosMethodInt netPosMethod;
+		aPosRequestMethod.GetPosMethod(0,netPosMethod);
+				
+		if (netPosMethod.PosMode()== (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted))
+			{
+			iFsm->TapMode() = ETrue;
+			}
+		}
+	if(aSessionId == iFsm->SessionId() && 
+		aIsEmergency == iFsm->IsEmergency() &&
+		aSessionType == iFsm->SessionType())
+		{
+		iFsm->PosRequestMethod() = aPosRequestMethod;
+		iFsm->NetRequestQuality() = aQuality;
+		iFsm->LocReqReceived() = ETrue;
+		}
+	else
+		{
+		// It's a request for different session. Need to find out what to do with it.
+		HandleLocRequest(aSessionId,aPosRequestMethod, 
+							aSessionType,aIsEmergency,
+							aQuality);
+		}
+	}
+	
+	
+void CLbsPrivLocWaitPrivRespState::OnMTLRRequest(const TLbsNetSessionIdInt& /*aSessionId*/,
+					   TLbsNetworkEnumInt::TLbsNetProtocolServiceInt /*aSessionType*/, 
+					   TBool /*aIsEmergency*/,
+					   const TLbsExternalRequestInfo& /*aExternalRequestInfo*/,
+					   const TLbsNetPosRequestPrivacyInt& /*aNetPosRequestPrivacy*/)
+	{
+	// this can never happen. If the Fsm is in the WaitPrivRespState then 
+	// any arrival of a MTLR request would start a new session (no implicit cancel!)
+	// and the OnMTLRRequest()would be directed to that session not this one
+	__ASSERT_DEBUG(EFalse, Panic(ENrhPanicBadParamType));
+	}
+
+/** Called when a reference position arrives from the network.
+ *  
+*/
+void CLbsPrivLocWaitPrivRespState::OnNetLocReferenceUpdate(
+		const TLbsNetSessionIdInt& /*aSessionId*/, 
+		const TPositionInfoBase& /*aPosInfo*/)
+	{
+	// note that the reference postion is stored by the message switch
+	// so here we don't need to save it again!
+	}
+	
+	
+// ----------------------------------------------------------------------------- 
+// 
+// ----------------------- Class CLbsPrivLocWaitLocUpdateState --------------------
+//
+// Implements the Wait For Location Update state of the Privacy and Location 
+// Request Handler
+//
+// On entry, issues a location update request then starts a timer and waits for 
+// a response.
+//
+// ----------------------------------------------------------------------------- 
+//
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocUpdateState::NewL
+// Description: CLbsPrivLocWaitLocUpdateState static constructor 
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocWaitLocUpdateState* CLbsPrivLocWaitLocUpdateState::NewL(CLbsPrivLocFsm* aFsm)
+	{
+	CLbsPrivLocWaitLocUpdateState* self; 
+	self = new (ELeave) CLbsPrivLocWaitLocUpdateState(aFsm);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return(self);	
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocUpdateState::CLbsPrivLocWaitLocUpdateState
+// Description: CLbsPrivLocWaitLocUpdateState constructor.
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocWaitLocUpdateState::CLbsPrivLocWaitLocUpdateState(CLbsPrivLocFsm* aFsm)
+: CLbsPrivLocStateBase(aFsm)
+	{
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocUpdateState::~CLbsPrivLocWaitLocUpdateState
+// Description: CLbsPrivLocWaitLocUpdateState destructor.
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocWaitLocUpdateState::~CLbsPrivLocWaitLocUpdateState()
+	{
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocIdleState::ConstructL
+// Description: CLbsPrivLocIdleState second-phase constructor.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitLocUpdateState::ConstructL()
+	{
+	}
+
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocUpdateState::OnEntry
+// Description: Carries out tasks required on entry to the state.
+// Issues the location update request and starts a timer.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitLocUpdateState::OnEntry(const TPrivLocCommonParams& aStateParams)
+	{
+	TInt err(KErrNone);
+	
+	CLbsPrivLocStateBase::OnEntry(aStateParams);
+	const TPrivLocWaitLocationUpdateParams& params = TPrivLocWaitLocationUpdateParams::Cast(aStateParams);	
+	iFsm->IsEmergency() = params.iIsEmergency;
+	iFsm->SessionType() = params.iSessionType;
+	iFsm->PosRequestMethod() = params.iPosRequestMethod;
+
+	// If the network has not specified a positioning method, get the default
+	// one from the admin settings.
+	TLbsNetPosMethodInt netReqMethod;
+	iFsm->PosRequestMethod().GetPosMethod(0, netReqMethod);		
+	if (iFsm->PosRequestMethod().NumPosMethods() == 1
+		&& (netReqMethod.PosMode() == TPositionModuleInfo::ETechnologyUnknown))
+		{
+		AgpsInterface()->GetDefaultPosMethod(iFsm->PosRequestMethod());
+		}
+
+    // We may use two sources for the required quality for the
+    // new location request, either:
+    // 1) The quality from the network (aQuality)
+    // 2) The quality defined in a quality profile (which profile to
+    //    use depends on the service type, e.g. MT-LR or X3P)
+    //
+    // We decide which to use based on the required quality from the network.
+    // Any invalid/unsupplied parameter is read from the quality profile 
+    // for the ocation request type.
+   	TBool maxFixTimeRequired = params.iQuality.MaxFixTime() == 0;
+    TBool minVerticalAccuracyRequired = 
+    				Math::IsNaN(params.iQuality.MinVerticalAccuracy());
+    TBool minHorizontalAccuracyRequired = 
+    				Math::IsNaN(params.iQuality.MinHorizontalAccuracy());
+    
+    if (maxFixTimeRequired || minVerticalAccuracyRequired || minHorizontalAccuracyRequired)
+    	{
+    	// Select which LbsAdmin setting to use for the
+    	// quality profile Id based on the type of location
+    	// request.
+	    TLbsAdminSetting adminSetting(KLbsSettingNone);
+	    switch (iFsm->SessionType())
+	    	{
+	    	case TLbsNetworkEnumInt::EServiceMobileTerminated:
+	    	case TLbsNetworkEnumInt::EServiceNetworkInduced:
+	    		{
+	    		adminSetting = KLbsSettingQualityProfileExternalLocate;
+	    		break;
+	    		}
+	    	case TLbsNetworkEnumInt::EServiceTransmitThirdParty:
+	    		{
+	    		adminSetting = KLbsSettingQualityProfileTransmitLocate;
+	    		break;
+	    		}
+	    	case TLbsNetworkEnumInt::EServiceTriggeredMolr:
+                // SUPL 2.0 "Triggered MOLR" request uses Self Locate Quality Profile
+	    	case TLbsNetworkEnumInt::EServiceNetworkLocation:
+	    		// This type of request should only get here in the case of a TA MOLR. Treat as Self-Locate
+	    	case TLbsNetworkEnumInt::EServiceSelfLocation:
+	    		{
+	    		adminSetting = KLbsSettingQualityProfileSelfLocate;
+	    		break;
+	    		}
+	    	default:
+	    		{
+				// We must not fail if it is an emergency request
+				if (!iFsm->IsEmergency())
+					{
+					LBSLOG2(ELogP3, 
+					"Unable to select quality profile for TLbsNetProtocolService (%d), using quality data from network instead.",
+		    				iFsm->SessionType());
+					__ASSERT_DEBUG(EFalse, Panic(ENrhPanicNoQualityProfile));
+					}
+	    		else
+	    			{
+	   				adminSetting = KLbsSettingQualityProfileExternalLocate;
+	   				}
+	    		}
+	    	}
+
+		// Retrieve the Id of the quality profile to use
+	    TLbsQualityProfileId profileId(KLbsNullQualityProfileId);
+	    if (adminSetting != KLbsSettingNone)
+	    	{
+	    	LbsAdmin()->Get(adminSetting, profileId);
+	    	}
+
+	    // Retrieve the data for the quality profile
+    	TQualityProfile qualityProfile;
+    	err = LbsQualityProfile::GetQualityProfileById(profileId, qualityProfile);
+    	if (err == KErrNone)
+    		{
+    		// Use the quality data from the quality profile for any missing/invalid data
+			if(maxFixTimeRequired)
+				{
+				iFsm->GpsRequestQuality().SetMaxFixTime(qualityProfile.MaxFixTime());
+				}
+			else
+				{
+				iFsm->GpsRequestQuality().SetMaxFixTime(params.iQuality.MaxFixTime());
+				}
+			if(minHorizontalAccuracyRequired)
+				{
+				iFsm->GpsRequestQuality().SetMinHorizontalAccuracy(qualityProfile.MinHorizontalAccuracy());
+				}
+			else
+				{
+				iFsm->GpsRequestQuality().SetMinHorizontalAccuracy(params.iQuality.MinHorizontalAccuracy());
+				}
+			if(minVerticalAccuracyRequired)
+				{
+				iFsm->GpsRequestQuality().SetMinVerticalAccuracy(qualityProfile.MinVerticalAccuracy());
+				}
+			else
+				{
+				iFsm->GpsRequestQuality().SetMinVerticalAccuracy(params.iQuality.MinVerticalAccuracy());				
+				}
+    		}
+		else
+			{
+			// We should not fail if we are emergency
+			if (!iFsm->IsEmergency())
+				{
+				// We couldn't find the quality profile with the given Id.
+				// This is an error, so reject the location request.
+				TPositionInfo dummyPosInfo;
+				TTime dummyTime;
+				TLbsNetPosRequestQualityInt dummyQuality;
+				MessageSwitch()->SendNetLocResponse(iFsm->SessionId(),
+									KErrAccessDenied,
+										dummyQuality,
+										dummyPosInfo,
+										dummyTime,
+										iFsm->IsEmergency());
+			
+				// if this location request is the result of a privacy request,
+				// then notify the privacy handler of the error
+				if ((params.iSessionType == TLbsNetworkEnumInt::EServiceMobileTerminated) ||
+					(params.iSessionType == TLbsNetworkEnumInt::EServiceNetworkInduced))
+					{
+					iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitSessionComplete, KErrAccessDenied);
+					}
+				else
+					{
+					iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitBadQualityProfile, KErrNone);
+					}
+
+				// Whatever the result, this session is finished, so return to idle.
+				iFsm->ChangeState(CLbsPrivLocFsm::EStateIdle, iFsm->SessionId());
+				return;
+				} // if (!iIsEmergency)
+			else
+				{
+				// Just set some defaults
+				TTimeIntervalMicroSeconds timeout(30000000);
+				iFsm->GpsRequestQuality().SetMinHorizontalAccuracy(50);
+				iFsm->GpsRequestQuality().SetMinVerticalAccuracy(1000);
+				iFsm->GpsRequestQuality().SetMaxFixTime(timeout);
+				}
+    		}
+    	}
+    else
+    	{
+    	// Use the quality parameters supplied with the request.
+    	iFsm->GpsRequestQuality().SetMinHorizontalAccuracy(params.iQuality.MinHorizontalAccuracy());
+    	iFsm->GpsRequestQuality().SetMinVerticalAccuracy(params.iQuality.MinVerticalAccuracy());
+    	iFsm->GpsRequestQuality().SetMaxFixTime(params.iQuality.MaxFixTime());
+    	}
+
+
+    // Check for any existing position updates in case they meet the
+    // MaxFixAge and quality requirements for this request.
+    TInt updateReason;
+    err = AgpsInterface()->GetPosition(updateReason, 
+    								   iFsm->GpsPosition(), 
+    								   iFsm->ActualTime());
+    if (err == KErrNone)
+    	{
+		TPrivLocWaitLocationRequestParams locationRequestParams(iFsm->SessionId(),
+																iFsm->IsEmergency(),
+																EFalse,
+																updateReason);
+
+    	// Check the existing update in case it meets the MaxFixAge and quality requirements for this request.
+    	if (params.iQuality.MaxFixAge() > 0)
+    		{
+    		TTime now;
+    		now.UniversalTime();
+    		TTimeIntervalMicroSeconds age(Max((now.Int64() - iFsm->ActualTime().Int64()), TInt64(0)));
+    		if (updateReason == KErrNone
+    			&& (age <= params.iQuality.MaxFixAge())
+    			&& ReceivedFixIsAccurate())
+    			{
+    			// Accurate update that is within the MaxFixAge time limit,
+    			// so return it straight away.
+    			iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocFixReceived, updateReason);
+    			iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationRequest, locationRequestParams);
+    			return;
+    			}
+    		}
+    		
+
+		// Special feature behaviour!
+		// If the admin setting KLbsSpecialFeatureIntermediateFutileUpdate is on,
+		// it means that we should check to see if a futile update has happened
+		// since the first location request of this session. This might happen
+		// in a hybrid session, if the GPS module sends a futile update when there
+		// is no outstanding location request in the NRH. E.g. in the gap between
+		// sending the response for one hybrid loc request and getting the next
+		// loc request from the network.
+		//
+		// Note: This only really applies to hybrid of TA position modes, because
+		//       in TB or autonomous you only have one location request per 
+		//       session.
+    	else if (iFsm->IsSpecialFeatureIntermediateFutileUpdateOn())
+    		{
+		    // If this is the first request for a new sessionId, record the current session id.
+		    // We need to know this for terminal assisted or hybrid requests, in case
+		    // we need to check for a futile update that has happened in the gap between
+		    // one location response and the next location update request.
+		    if (iFsm->LastLocReqSessionId() != iFsm->SessionId())
+		    	{
+		    	iFsm->LastLocReqSessionId() = iFsm->SessionId();
+		    	}
+		    else
+				{
+				// Before sending the location request, see if a futile update has 
+				// happened since the start of the session (in general only terminal-assisted 
+				// and hybrid requests should have more than one location request
+			    // per session, however the SUPL PM will have more than one for all request modes).
+   			    TGpsRequestMode gpsMode = AgpsInterface()->ConvertPosMethodToGpsRequestMode(iFsm->PosRequestMethod());
+				if ((updateReason == KPositionCalculationFutile) && 
+					((gpsMode == EGpsRequestModeTerminalAssisted) || (gpsMode == EGpsRequestModeHybrid)))
+					{
+					// Return last measurement straight away.
+					iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocMeasurementResultsReceived, updateReason);
+					iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationRequest, locationRequestParams);
+		    		return;
+					}
+				}
+    		}
+    	}
+
+    
+	// Issue the request and supply pointers to the data to be updated
+    iFsm->LocationFixReceived() = EFalse;
+    iFsm->MeasurementInfoReceived() = EFalse;
+    err = AgpsInterface()->StartPositioning(iFsm->SessionId(),
+								    		iFsm->PosRequestMethod(),
+											iFsm->GpsRequestQuality(),
+											iFsm->IsEmergency());
+	if (KErrNone == err)
+		{
+		iFsm->LocationUpdateTimer().EventAfter(iFsm->GpsRequestQuality().MaxFixTime(), 1);
+    	iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitReasonNone, KErrNone);
+		}
+	else
+		{
+		// Error sending the location request, send a location response
+		// with the error and go to Idle state.
+    	iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitBadLocationRequest, err);
+    	iFsm->ChangeState(CLbsPrivLocFsm::EStateIdle, iFsm->SessionId());
+		}
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocUpdateState::OnExit
+// Description: Carries out tasks required on exit from the state.
+// Cancels the location update request and stops the timer.
+// ----------------------------------------------------------------------------- 
+//
+TBool CLbsPrivLocWaitLocUpdateState::OnExit()
+	{	
+	// Cancel the update timer.
+	iFsm->LocationUpdateTimer().Cancel();
+	
+	TInt consumed = EFalse;
+	switch(iFsm->ExitData().iExitReason)
+		{
+		case TPrivLocStateExitData::EExitLocFixReceived:
+			{
+			// Don't cancel the location request yet, but tell the AGPS interface
+			// handler to put it on 'hold'. If we are in a hybrid or terminal-assisted
+			// request then we are going to get another location request very shortly
+			// anyway...
+			AgpsInterface()->HoldPositioning(iFsm->SessionId(), KErrNone);
+	
+			// Report the position to the message switch
+			MessageSwitch()->SendNetLocResponse(iFsm->SessionId(),
+												iFsm->ExitData().iExitInfo,
+            	                             	iFsm->GpsRequestQuality(),
+            	                             	iFsm->GpsPosition(),
+            	                             	iFsm->ActualTime(),
+            	                             	iFsm->IsEmergency());
+
+			// For MTLR pass the data to the privacy handler 
+			// in case the Privacy Controller wants it.
+			if ((iFsm->ExitData().iExitInfo >= KErrNone) &&
+				(iFsm->ExitData().iExitInfo != KPositionCalculationFutile) && 
+				((iFsm->SessionType() == TLbsNetworkEnumInt::EServiceMobileTerminated) ||
+				(iFsm->SessionType() == TLbsNetworkEnumInt::EServiceNetworkInduced)))
+				{
+				PrivacyHandler()->ProcessNetworkPositionUpdate(iFsm->SessionId(), 
+						iFsm->GpsPosition());
+				}
+
+			consumed = ETrue;
+			break;
+			}
+
+		case TPrivLocStateExitData::EExitLocMeasurementResultsReceived:
+			{
+			// Don't cancel the location request yet, but tell the AGPS interface
+			// handler to put it on 'hold'. If we are in a hybrid or terminal-assisted
+			// request then we are going to get another location request very shortly
+			// anyway...
+			AgpsInterface()->HoldPositioning(iFsm->SessionId(), KErrNone);
+
+			// Report the measurement data to the message switch, even if we
+			// didn't get any. The error code will indicate that the data
+			// is rubbish in that case.
+			LBSLOG2(ELogP3, "CLbsPrivLocWaitLocUpdateState:returning with reason %d", iFsm->MeasurementInfoError());
+
+			MessageSwitch()->SendNetLocResponse(iFsm->SessionId(),
+												iFsm->ExitData().iExitInfo,
+												iFsm->GpsRequestQuality(),
+            	                             	iFsm->GpsMeasurementInfo(),
+            	                             	iFsm->ActualTime(),
+            	                             	iFsm->IsEmergency());
+			break;	
+			}
+		
+		case TPrivLocStateExitData::EExitTimedOut:
+			{
+			// Don't cancel the location request yet, but tell the AGPS interface
+			// handler to put it on 'hold'. If we are in a hybrid or terminal-assisted
+			// request then we are going to get another location request very shortly
+			// anyway...
+			AgpsInterface()->HoldPositioning(iFsm->SessionId(), KErrNone);
+
+			// If the request has timed out, then return whatever position 
+			// data we have, but make it clear it's not what was requested.
+			// If there's an error (probably KErrTimedOut) there's
+			// nothing to report, so send dummy data with the error.			
+			MessageSwitch()->SendNetLocResponse(iFsm->SessionId(), 
+												iFsm->ExitData().iExitInfo,
+												iFsm->GpsRequestQuality(),
+												iFsm->GpsPosition(),
+												iFsm->ActualTime(),
+												iFsm->IsEmergency());
+
+			// For MTLR, pass the data to the privacy handler in case the Privacy
+			// Controller wants it.
+			// NB Don't send the update if the error is KErrTimedOut, as that means there's
+			// nothing to report.
+			if((iFsm->SessionType() == TLbsNetworkEnumInt::EServiceMobileTerminated) &&
+			    (iFsm->ExitData().iExitInfo == KPositionQualityLoss))
+				{
+				PrivacyHandler()->ProcessNetworkPositionUpdate(iFsm->SessionId(), 
+						iFsm->GpsPosition());
+				}
+
+			consumed = ETrue;
+			break;
+			}
+			
+		case TPrivLocStateExitData::EExitCancelledByPrivacyController:
+			{
+			// Stop the location request immediately.
+			AgpsInterface()->StopPositioning(iFsm->SessionId());
+			
+			// Send a SendExternalLocateCancel to NetGateWay- if the protcol module does not support this then
+			// the Gateway will do nothing
+			MessageSwitch()->SendExternalLocateCancel(iFsm->SessionId(), KErrCancel);
+				
+			// Send a location response with 'cancel' set to the network
+			TPositionInfo dummyPosInfo;
+			TTime dummyTime;
+			TLbsNetPosRequestQualityInt dummyQuality;
+			MessageSwitch()->SendNetLocResponse(iFsm->SessionId(),
+												iFsm->ExitData().iExitInfo,
+												dummyQuality,
+												dummyPosInfo,
+												dummyTime,
+												iFsm->IsEmergency());
+			
+			consumed = ETrue;
+			}
+			break;
+
+		case TPrivLocStateExitData::EExitBadQualityProfile:
+			{
+			// Do nothing; we're just going back to Idle state
+			consumed = ETrue;
+			break;
+			}
+		
+		case TPrivLocStateExitData::EExitBadLocationRequest:
+			{
+			// Error processing the location request - 
+			// send a dummy response with an error code.
+			TPositionInfo dummyPosInfo;
+			TTime dummyTime;
+			TLbsNetPosRequestQualityInt dummyQuality;
+			MessageSwitch()->SendNetLocResponse(iFsm->SessionId(),
+												iFsm->ExitData().iExitInfo,
+												dummyQuality,
+												dummyPosInfo,
+												dummyTime,
+												iFsm->IsEmergency());
+			
+			consumed = ETrue;
+			break;
+			}
+		
+		default:
+			{
+			consumed = CLbsPrivLocStateBase::OnExit();
+			// If the exit reason wasn't handled, panic (should only happen in development)
+			__ASSERT_DEBUG(consumed, Panic(ENrhPanicWaitLocUpdateUnknownExitReason));
+			}
+		}
+	return(consumed);
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocIdleState::OnNetLocRequest
+// Description: The Message Switch has forwarded a request for a network 
+// location.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitLocUpdateState::OnNetLocRequest(const TLbsNetSessionIdInt& aSessionId, 
+						const TLbsNetPosRequestMethodInt& aPosRequestMethod,
+						 TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+						 TBool aIsEmergency,
+						 const TLbsNetPosRequestQualityInt& aQuality)
+	{
+	TInt numMethods = aPosRequestMethod.NumPosMethods();
+	if (numMethods==1)
+		{
+		TLbsNetPosMethodInt netPosMethod;
+		aPosRequestMethod.GetPosMethod(0,netPosMethod);
+				
+		if (netPosMethod.PosMode()== (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted))
+			{
+			iFsm->TapMode() = ETrue;
+			}
+		}
+	if(aSessionId != iFsm->SessionId())
+		{
+		/* This request is for a different session. Cancel the current one 
+		 * and start a new one.
+		 */
+		HandleLocRequest(aSessionId,aPosRequestMethod,
+							aSessionType,aIsEmergency,
+							aQuality);
+		}
+	else
+		{
+		LBSLOG(ELogP3, "CLbsPrivLocWaitLocUpdateState::OnNetLocRequest: Matching SessionId.");
+		TPrivLocWaitLocationUpdateParams updateRequestParams(aSessionId,
+				aPosRequestMethod,
+				aSessionType,
+				aIsEmergency,
+				aQuality);
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocReqReceived, KErrNone);
+		iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationUpdate, updateRequestParams);
+		}
+	}
+
+
+void CLbsPrivLocWaitLocUpdateState::OnMTLRRequest(const TLbsNetSessionIdInt& /*aSessionId*/,
+					   TLbsNetworkEnumInt::TLbsNetProtocolServiceInt /*aSessionType*/, 
+					   TBool /*aIsEmergency*/,
+					   const TLbsExternalRequestInfo& /*aExternalRequestInfo*/,
+					   const TLbsNetPosRequestPrivacyInt& /*aNetPosRequestPrivacy*/)
+	{
+	// this can never happen. If the Fsm is in the WaitLocUpdateState then 
+	// any arrival of a MTLR request would start a new session and not
+	// implicitly cancel the ongoing MTLR and the OnMTLRRequest()
+	// would be directed to that session not this one
+		
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocUpdateState::OnTimerEventL
+// Description: The Location Update timer has expired.
+// Cancel the request, and pass on the response if any has been received,
+// otherwise report failure.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitLocUpdateState::OnTimerEventL(TInt /*aTimerId*/)
+	{	
+	LBSLOG(ELogP3, "CLbsPrivLocWaitLocUpdateState::OnTimerEventL");
+	
+	if(iFsm->MeasurementInfoReceived())
+		{
+		// A position fix may have been received, but it can't be accurate enough
+		// (otherwise the request would have been completed before timeout), so 
+		// return the most recent measurement info		
+		LBSLOG(ELogP3, "OnTimerEventL, measurement data received");
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocMeasurementResultsReceived, 
+									 iFsm->MeasurementInfoError());
+		}
+	else if(iFsm->LocationFixReceived())
+		{
+		// position received, but not accurate enough (or request would already have been completed)
+		LBSLOG(ELogP3, "OnTimerEventL, inaccurate location data received");
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitTimedOut, 
+									 KPositionQualityLoss);
+		}
+	else
+		{
+		// we've received no update (position / measurements)
+		LBSLOG(ELogP3, "OnTimerEventL, NO measurement data received");
+		LBSLOG(ELogP3, "(Setting exit info KErrPositionNoGpsUpdate");
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitTimedOut, 
+									 KErrPositionNoGpsUpdate);
+		}
+
+	SetExitState();	
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocUpdateState::SetExitState
+// Description: Works out the next state on the basis of the current session 
+// type and whether any update has been received.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitLocUpdateState::SetExitState()
+	{
+	TPrivLocWaitLocationRequestParams locationRequestParams(iFsm->SessionId(),
+															iFsm->IsEmergency(),
+															EFalse,
+															iFsm->ExitData().iExitInfo);
+	iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationRequest, 
+					locationRequestParams);
+	}
+
+TBool CLbsPrivLocWaitLocUpdateState::ReceivedFixIsAccurate()
+	{    
+	TBool fixIsAccurate = EFalse;
+
+	// Compare the accuracy to the request values.
+	// Make sure the location update is (A)GPS and not Network based.
+	TPosition latestPosition;
+	iFsm->GpsPosition().GetPosition(latestPosition);
+	
+	if ((latestPosition.HorizontalAccuracy() <= iFsm->GpsRequestQuality().MinHorizontalAccuracy()) &&
+		(latestPosition.VerticalAccuracy() <= iFsm->GpsRequestQuality().MinVerticalAccuracy()) &&
+		(iFsm->GpsPosition().PositionMode() != TPositionModuleInfo::ETechnologyNetwork))//Pure Reference Location
+		{
+		fixIsAccurate = ETrue;
+		}
+
+	return(fixIsAccurate);
+    }
+
+/** Callback when a GPS position update arrives from AGPS manager.
+*/
+void CLbsPrivLocWaitLocUpdateState::OnAgpsPositionUpdate(
+	TInt aReason,
+	const TPositionExtendedSatelliteInfo& aPosInfo,
+	const TTime& aTimeStamp)
+	{
+	iFsm->GpsPosition() = aPosInfo;
+	iFsm->ActualTime() = aTimeStamp;
+	iFsm->LocationFixReceived() = ETrue;
+	iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocFixReceived, aReason);
+
+	if (KErrNone == aReason)
+		{
+		if (iFsm->TapMode())
+			{
+			LBSLOG(ELogP1,"TAP mode) - NOT sending position to network");	
+			return; // do NOT return AGPS postions to TAP mode sessions
+			}
+		// See if the reported accuracy matches the specified quality.
+		// If the accuracy is good enough, report the position
+		
+		// if this session is TAP then discard the position
+		
+		if(ReceivedFixIsAccurate())
+			{
+			SetExitState();
+			}
+		}
+	else if ((aReason <= KErrNone) || (KPositionCalculationFutile == aReason))
+		{
+		// GPS Manager can't provide a location update. return what we do have.
+		if(iFsm->MeasurementInfoReceived())
+			{
+			LBSLOG(ELogP1,"CLbsPrivLocWaitLocUpdateState::OnPositionUpdate() - measurement received");	
+			iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocMeasurementResultsReceived, aReason);
+			}
+		else
+			{
+			iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocFixReceived, aReason);				
+			}
+		SetExitState();
+		}
+	else if (KPositionEarlyComplete == aReason)
+		{
+		// Not an error. Report back what was accepted.
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocFixReceived, KErrNone);				
+		SetExitState();	
+		}
+	else
+		{
+		// A real error
+		SetExitState();
+		}
+	}
+
+/** Callback when a GPS measurement results update arrives from AGPS manager.
+
+Only location requests that are 'hybrid' or 'terminal assisted' should record 
+the measurement results. Other types of request (autonomous, terminal based)
+are only interested in the GPS position update.
+*/
+void CLbsPrivLocWaitLocUpdateState::OnAgpsMeasurementUpdate(
+	TInt aReason,
+	const TPositionGpsMeasurementInfo& aPosInfo,
+	const TTime& /*aTimeStamp*/)
+	{
+	// Check that we should be listening for measurement updates.
+	
+	TBool positionCalculationPossible = aPosInfo.PositionCalculationPossible();
+	
+	const TInt methodCount = iFsm->PosRequestMethod().NumPosMethods();
+	for(TInt i = 0; i < methodCount; ++i)
+		{
+		TLbsNetPosMethodInt posMethod;
+		iFsm->PosRequestMethod().GetPosMethod(i, posMethod);
+		if((posMethod.PosMode() & KTerminalAssistedMode) == KTerminalAssistedMode)
+			{
+			iFsm->MeasurementInfoReceived() = ETrue;
+			iFsm->MeasurementInfoError() = aReason;
+			iFsm->GpsMeasurementInfo() = aPosInfo;
+
+			// don't wait until alpha2 time expires, instead
+			// return measuremnts now
+			if (positionCalculationPossible)
+				{
+				iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocMeasurementResultsReceived, 
+											 iFsm->MeasurementInfoError());
+				SetExitState();	
+				}
+			break;
+			}
+		}
+	}
+
+/** Callback when a GPS measurement results update arrives from AGPS manager.
+
+Only location requests that are 'hybrid' or 'terminal assisted' should record 
+the measurement results. Other types of request (autonomous, terminal based)
+are only interested in the GPS position update.
+*/
+void CLbsPrivLocWaitLocUpdateState::OnNetLocReferenceUpdate(
+		const TLbsNetSessionIdInt& aSessionId, 
+		const TPositionInfoBase& aPosInfo)
+	{
+	CLbsPrivLocStateBase::OnNetLocReferenceUpdate(aSessionId,aPosInfo);
+	}
+
+
+// ----------------------------------------------------------------------------- 
+// 
+// ----------------------- Class CLbsPrivLocWaitLocReqState --------------------
+//
+// Implements the Wait For Location Request state of the Privacy and Location 
+// Request Handler
+//
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocWaitLocReqState* CLbsPrivLocWaitLocReqState::NewL(CLbsPrivLocFsm* aFsm)
+	{
+	return new(ELeave)CLbsPrivLocWaitLocReqState(aFsm);
+	}
+	
+CLbsPrivLocWaitLocReqState::CLbsPrivLocWaitLocReqState(CLbsPrivLocFsm* aFsm)	
+: CLbsPrivLocStateBase(aFsm)
+	{
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocReqState::OnEntry
+// Description: Carries out tasks required on entry to the state.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitLocReqState::OnEntry(const TPrivLocCommonParams& aStateParams)
+	{
+	CLbsPrivLocStateBase::OnEntry(aStateParams);
+	const TPrivLocWaitLocationRequestParams& params = TPrivLocWaitLocationRequestParams::Cast(aStateParams);	
+	iFsm->IsEmergency() = params.iIsEmergency;
+	iFsm->PrivacyRequestCancelled() = params.iReqCancelled;
+	iFsm->PreviousStateExitInfo() = params.iPreviousStateExitInfo;
+	}
+
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocReqState::OnExit
+// Description: Carries out tasks required on exit from the state.
+// Panics if the exit reason is not handled by the base state exit
+// ----------------------------------------------------------------------------- 
+//
+TBool CLbsPrivLocWaitLocReqState::OnExit()
+	{
+	TBool consumed = CLbsPrivLocStateBase::OnExit();
+	// If the exit reason wasn't handled, panic (should only happen in development)
+	__ASSERT_DEBUG(consumed, Panic(ENrhPanicWaitLocReqUnknownExitReason));
+	return(consumed);
+	}
+
+void CLbsPrivLocWaitLocReqState::OnMTLRRequest(const TLbsNetSessionIdInt& /*aSessionId*/,
+					   TLbsNetworkEnumInt::TLbsNetProtocolServiceInt /*aSessionType*/, 
+					   TBool /*aIsEmergency*/,
+					   const TLbsExternalRequestInfo& /*aExternalRequestInfo*/,
+					   const TLbsNetPosRequestPrivacyInt& /*aNetPosRequestPrivacy*/)
+	{
+	// this can never happen. If the Fsm is in the WaitLocReqState then 
+	// any arrival of a MTLR request would start a new session and the OnMTLRRequest()
+	// would be directed to that session not this one
+	__ASSERT_DEBUG(EFalse, Panic(ENrhPanicBadParamType)); 
+	}
+	
+void CLbsPrivLocWaitLocReqState::OnNetLocRequest(const TLbsNetSessionIdInt& aSessionId, 
+						const TLbsNetPosRequestMethodInt& aPosRequestMethod,
+						 TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+						 TBool aIsEmergency,
+						 const TLbsNetPosRequestQualityInt& aQuality)
+	{
+	TInt numMethods = aPosRequestMethod.NumPosMethods();
+	if (numMethods==1)
+		{
+		TLbsNetPosMethodInt netPosMethod;
+		aPosRequestMethod.GetPosMethod(0,netPosMethod);
+				
+		if (netPosMethod.PosMode()== (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted))
+			{
+			iFsm->TapMode() = ETrue;
+			}
+		}
+	
+	
+	if(aSessionId == iFsm->SessionId())
+		{
+		if (iFsm->PrivacyRequestCancelled())
+			{
+			iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitCancelledByPrivacyController, KErrCancel);
+			TPrivLocWaitLocationRequestParams locationRequestParams(iFsm->SessionId(), 
+																	iFsm->IsEmergency(), 
+																	iFsm->PrivacyRequestCancelled());
+			iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationRequest, locationRequestParams);
+			}
+		else
+			{
+			iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitLocReqReceived, KErrNone);
+			TPrivLocWaitLocationUpdateParams updateRequestParams(aSessionId,
+																 aPosRequestMethod,
+																 aSessionType,
+																 aIsEmergency,
+																 aQuality);
+			iFsm->ChangeState(CLbsPrivLocFsm::EStateWaitLocationUpdate, updateRequestParams);
+			}
+		}
+	else
+		{
+		HandleLocRequest(aSessionId,aPosRequestMethod,
+							aSessionType,aIsEmergency,
+							aQuality);
+		}
+	}
+
+void CLbsPrivLocWaitLocReqState::OnCancelNetworkLocationRequest(const TLbsNetSessionIdInt& aSessionId)
+	{
+	if (!iFsm->IsEmergency() && (aSessionId == iFsm->SessionId()))
+			{
+			if (!iFsm->PrivacyRequestCancelled() )
+				{
+				TLbsNetSessionIdInt sessionId = iFsm->SessionId();
+				MessageSwitch()->SendExternalLocateCancel(sessionId,KErrCancel);
+				}
+			iFsm->PrivacyRequestCancelled() = ETrue;
+			}
+	}
+
+
+/** Called when a reference position arrives from the network.
+*/
+void CLbsPrivLocWaitLocReqState::OnNetLocReferenceUpdate(
+		const TLbsNetSessionIdInt& aSessionId, 
+		const TPositionInfoBase& aPosInfo)
+	{
+	// if the MTLR is still active (has not been cancelled by the privacy handler)
+	if (!iFsm->PrivacyRequestCancelled())
+		{
+		CLbsPrivLocStateBase::OnNetLocReferenceUpdate(aSessionId, aPosInfo);
+		}	
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocReqState::OnSessionComplete
+// Description: handling of a session complete message
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocWaitLocReqState::OnSessionComplete(const TLbsNetSessionIdInt& aSessionId,
+																TInt aReason)
+	{
+	
+	
+	if(aSessionId == iFsm->SessionId())
+		{
+		// Make sure the reason passed with the Session Complete is sent to the
+ 		// Privacy Controller EXCEPT when the update previously passed to the 
+ 		// network didn't meet the quality criteria. In this case use the
+ 		// KPositionQualityLoss status.
+		TInt completionReason = aReason;
+		if(aReason == KErrNone)
+ 			{
+ 			if(KPositionQualityLoss == iFsm->PreviousStateExitInfo())
+ 				{
+ 				completionReason = KPositionQualityLoss;
+ 				}
+ 			}
+		
+		iFsm->ExitData().SetExitData(TPrivLocStateExitData::EExitSessionComplete, completionReason);
+		iFsm->ChangeState(CLbsPrivLocFsm::EStateIdle, aSessionId);	            
+		}		
+	}
+
+// ----------------------------------------------------------------------------- 
+//
+// Package classes
+//
+// ----------------------------------------------------------------------------- 
+//
+TPrivLocCommonParams::TPrivLocCommonParams()
+	{	
+	}
+TPrivLocCommonParams::TPrivLocCommonParams(TLbsNetSessionIdInt aSessionId)
+	{
+	iSessionId = aSessionId;												
+	}
+
+TPrivLocWaitLocationRequestParams::TPrivLocWaitLocationRequestParams()
+	{
+	}
+TPrivLocWaitLocationRequestParams::TPrivLocWaitLocationRequestParams(
+			const TLbsNetSessionIdInt& aSessionId,
+			TBool	aIsEmergency,
+			TBool   aReqCancelled,
+			TInt    aPreviousStateExitInfo) :
+	TPrivLocCommonParams(aSessionId),
+	iIsEmergency(aIsEmergency),
+	iReqCancelled(aReqCancelled),
+	iPreviousStateExitInfo(aPreviousStateExitInfo)
+	{
+	}
+
+TPrivLocWaitLocationUpdateParams::TPrivLocWaitLocationUpdateParams()
+	{	
+	}
+TPrivLocWaitLocationUpdateParams::TPrivLocWaitLocationUpdateParams(
+			const TLbsNetSessionIdInt& aSessionId,
+			const TLbsNetPosRequestMethodInt& aPosRequestMethod,
+			TLbsNetworkEnumInt::TLbsNetProtocolServiceInt  aSessionType,
+			TBool aIsEmergency,
+			const TLbsNetPosRequestQualityInt& aQuality) :
+	TPrivLocCommonParams(aSessionId),
+	iSessionType(aSessionType),
+	iIsEmergency(aIsEmergency),
+	iQuality(aQuality),
+	iPosRequestMethod(aPosRequestMethod)
+	{
+	}
+
+TPrivLocWaitPrivResponseParams::TPrivLocWaitPrivResponseParams()
+	{
+	
+	}
+TPrivLocWaitPrivResponseParams::TPrivLocWaitPrivResponseParams(
+			const TLbsNetSessionIdInt& aSessionId,
+			const TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType,
+			const TLbsExternalRequestInfo& aExternalRequestInfo,
+			const TLbsNetPosRequestPrivacyInt& aNetPosRequestPrivacy,
+			TBool aIsEmergency) :
+	TPrivLocCommonParams(aSessionId),
+	iNetPosRequestPrivacy(aNetPosRequestPrivacy),
+	iIsEmergency(aIsEmergency),
+	iSessionType(aSessionType)
+	{
+	// Need to check the type of aExternalRequestInfo before 
+	// copying it into this class.
+	if (aExternalRequestInfo.ClassType() == EExternalRequestInfoClass)
+		{
+		__ASSERT_DEBUG(aExternalRequestInfo.ClassSize() == sizeof(TLbsExternalRequestInfo), 
+					   Panic(ENrhPanicInvalidExternalRequestInfoType));
+		
+		Mem::Copy(&iExternalRequestInfo, 
+				  &aExternalRequestInfo, 
+				  sizeof(TLbsExternalRequestInfo));
+		}
+	else 
+		{
+		if (aExternalRequestInfo.ClassType() == (EExternalRequestInfoClass | EExternalRequestInfoClass2))
+			{
+			__ASSERT_DEBUG(aExternalRequestInfo.ClassSize() == sizeof(TLbsExternalRequestInfo2), 
+						   Panic(ENrhPanicInvalidExternalRequestInfoType));
+
+			Mem::Copy(&iExternalRequestInfo, 
+					  &aExternalRequestInfo, 
+					  sizeof(TLbsExternalRequestInfo2));
+			}
+		else
+			{
+			Panic(ENrhPanicInvalidExternalRequestInfoType);
+			}
+		}
+	}
+
+// ----------------------------------------------------------------------------- 
+// 
+// ----------------------------- Class CLbsPrivLocFsm --------------------------
+//
+// State Machine class which owns the states of the Privacy and Location Handler
+//
+// ----------------------------------------------------------------------------- 
+//
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::NewL
+// Description: CLbsPrivLocFsm static constructor 
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocFsm* CLbsPrivLocFsm::NewL(
+		CPrivacyAndLocationHandler& aPrivLocHandler,
+		const TLbsNetSessionIdInt& aSessionId)
+	{
+	CLbsPrivLocFsm* self; 
+	self = new (ELeave) CLbsPrivLocFsm(aPrivLocHandler, aSessionId);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return(self);	
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::CLbsPrivLocFsm
+// Description: CLbsPrivLocFsm constructor 
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocFsm::CLbsPrivLocFsm(
+		CPrivacyAndLocationHandler& aPrivLocHandler,
+		const TLbsNetSessionIdInt& aSessionId) :
+	iPrivLocHandler(aPrivLocHandler),
+	iSessionId(aSessionId),
+	iIsEmergency(EFalse),
+	iSessionType(TLbsNetworkEnumInt::EServiceNone),
+	iRefPosProcessed(EFalse),
+	iLocReqReceived(EFalse),
+	iReqCancelled(EFalse),
+	iWasPrivacyResponseReceivedStateExited(EFalse),
+	iPositioningStatusIncremented(EFalse)
+	{	
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::~CLbsPrivLocFsm
+// Description: CLbsPrivLocFsm destructor 
+// ----------------------------------------------------------------------------- 
+//
+CLbsPrivLocFsm::~CLbsPrivLocFsm()
+	{
+	delete iLocationUpdateTimer;
+	iStates.DeleteAll();
+	iStates.Reset();
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::SessionId
+// Description: Get the current session Id for this FSM.
+// ----------------------------------------------------------------------------- 
+//
+const TLbsNetSessionIdInt& CLbsPrivLocFsm::SessionId() const
+	{
+	return iSessionId;
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::ConstructL
+// Description: CLbsPrivLocFsm second-phase constructor.
+//              Creates the states of the system and the Privacy Handler.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::ConstructL()
+	{
+	// Create the states
+	iStates.At(EStateIdle) = CLbsPrivLocIdleState::NewL(this);
+	iStates.At(EStateWaitPrivacyResponse) = CLbsPrivLocWaitPrivRespState::NewL(this);
+	iStates.At(EStateWaitLocationRequest) = CLbsPrivLocWaitLocReqState::NewL(this);
+	iStates.At(EStateWaitLocationUpdate) = CLbsPrivLocWaitLocUpdateState::NewL(this);
+
+	iCurrentState = iStates.At(EStateIdle);
+    // When waiting for an update, there is a maximum duration specified by the
+    // LBS admin data to avoid the risk of hanging around forever in the event of 
+    // a problem with the A-GPS module. Create a timer to deal with this.
+    iLocationUpdateTimer = CLbsCallbackTimer::NewL(*this);
+	}
+	
+	
+TBool CLbsPrivLocFsm::IsSpecialFeatureIntermediateFutileUpdateOn()
+	{
+	return PrivLocHandler().IsSpecialFeatureIntermediateFutileUpdateOn();
+	}
+
+// ----------------------------------------------------------------------------- 
+// CPrivacyAndLocationHandler::SetServerObserver
+// Description: Store a pointer to the NRH server which comunicates with the 
+// Privacy Controller.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::SetServerObserver(MLbsSessionObserver* aNrhServer)
+    {
+    PrivLocHandler().PrivacyHandler()->SetServerObserver(aNrhServer);
+    }
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::OnRespondNetworkLocationRequest
+// Description: Called by the Privacy Handler to report the result of a privacy
+// check. Handling of the response is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::OnRespondNetworkLocationRequest(const TLbsNetSessionIdInt& aRequestId, 
+                            TLbsNetworkEnumInt::TLbsPrivacyResponseInt aRequestResult,
+                            TInt aResponseReason)
+	{
+	LBSLOG3(ELogP3, "FSM(%d) OnRespondNetworkLocationRequest response=%d",iSessionId.SessionNum(),aRequestResult);
+	iCurrentState->OnRespondNetworkLocationRequest(aRequestId, aRequestResult, aResponseReason);
+    }
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::OnCancelNetworkLocationRequest
+// Description: Called by the Privacy Handler to report that a privacy check 
+// has been rejected. This may occur after it has already been accepted.
+// Handling of the response is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::OnCancelNetworkLocationRequest(const TLbsNetSessionIdInt& aRequestId)
+    {
+	LBSLOG2(ELogP3, "FSM(%d) OnCancelNetworkLocationRequest",iSessionId.SessionNum());
+	iCurrentState->OnCancelNetworkLocationRequest(aRequestId);
+    }
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::OnMTLRRequest
+// Description: The Message Switch has forwarded a request to start an MTLR 
+// session.
+// Handling of the request is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::OnMTLRRequest(const TLbsNetSessionIdInt& aSessionId,
+					   TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+					   TBool aIsEmergency,
+					   const TLbsExternalRequestInfo& aExternalRequestInfo,
+					   const TLbsNetPosRequestPrivacyInt& aNetPosRequestPrivacy)
+	{
+	LBSLOG2(ELogP3, "FSM(%d) OnMTLRRequest",iSessionId.SessionNum());
+	iCurrentState->OnMTLRRequest(aSessionId, 
+								aSessionType, 
+								aIsEmergency, 
+								aExternalRequestInfo, 
+								aNetPosRequestPrivacy);
+	}
+	
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::OnSessionComplete
+// Description: The Message Switch has reported that the session is
+// over (complete or aborted due to some error).
+// Handling of the message is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::OnSessionComplete(
+									const TLbsNetSessionIdInt& aSessionId,
+									TInt aReason)
+	{
+	LBSLOG3(ELogP3, "FSM(%d) OnSessionComplete reason=%d",iSessionId.SessionNum(),aReason);
+	iCurrentState->OnSessionComplete(aSessionId, aReason);
+	
+    // update the positioning status. Note this is updated only if it was previously
+    // incremented as a result of this session.
+    if (WasPositioningStatusIncremented())
+        {
+        PrivLocHandler().DecrementPositioningStatus();
+        WasPositioningStatusIncremented() = EFalse;
+        }
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::OnNetLocRequest
+// Description: The Message Switch has passed on a request for a position update
+// Handling of the request is delegated to the current state.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::OnNetLocRequest(
+						const TLbsNetSessionIdInt& aSessionId, 
+						const TLbsNetPosRequestMethodInt& aPosRequestMethod,
+						TLbsNetworkEnumInt::TLbsNetProtocolServiceInt aSessionType, 
+						TBool aIsEmergency,
+						const TLbsNetPosRequestQualityInt& aQuality)
+	{
+	LBSLOG2(ELogP3, "FSM(%d) OnNetLocRequest",iSessionId.SessionNum());
+	iCurrentState->OnNetLocRequest(aSessionId,
+	 					aPosRequestMethod, 
+	 					aSessionType, 
+						aIsEmergency, 
+						aQuality);
+	}
+
+/** Called when a reference position arrives from the network.
+*/
+void CLbsPrivLocFsm::OnNetLocReferenceUpdate(
+		const TLbsNetSessionIdInt& aSessionId, 
+		const TPositionInfoBase& aPosInfo)
+	{
+	LBSLOG2(ELogP3, "FSM(%d) OnNetLocReferenceUpdate",iSessionId.SessionNum());
+	iCurrentState->OnNetLocReferenceUpdate(aSessionId, aPosInfo);	
+	}
+
+/** Callend when a final location arrives from the network.
+
+Currently the final network position is never used by the 
+state machine - it is only needed by the X3P handler. 
+So this function just ignores the update.
+*/
+void CLbsPrivLocFsm::OnNetLocFinalUpdate(
+		const TLbsNetSessionIdInt& /*aSessionId*/, 
+		const TPositionInfoBase& /*aPosInfo*/)
+	{
+	// Final network position not used by CLbsPrivLocFsm, so ignore it.
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::ChangeState
+// Description: Called by a state of the FSM when a transition is required.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::ChangeState(TLocPrivacyHandlerState aNewStateId,const TPrivLocCommonParams& aStateParams)
+	{
+	// Tidy up the old state
+	if(iCurrentState)
+		{
+		// coverity[unchecked_value]
+		// We're not interested in whether it was consumed here
+		iCurrentState->OnExit();
+		}
+
+	// Note, here the session ID has already being set when the Fsm was created (when session first came into being)
+	// so no need to do this ... iSessionId = aStateParams.iSessionId;
+
+	// Set the new state
+	iCurrentState = iStates.At(aNewStateId);
+
+	LBSLOG3(ELogP3, "FSM(%d) Entering state %d",iSessionId.SessionNum(), aNewStateId);
+	
+	// Do any initialisation for the new state.
+	iCurrentState->OnEntry(aStateParams);
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::ChangeState
+// Description: Called by a state of the FSM when a transition is required to a 
+// state which only requires the session Id
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::ChangeState(TLocPrivacyHandlerState aNewStateId,
+											const TLbsNetSessionIdInt& aSessionId)
+	{
+	TPrivLocCommonParams commonParams(aSessionId);
+	ChangeState(aNewStateId, commonParams);
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocFsm::PrivLocHandler
+// Description: Get the CPrivacyAndLocationHandler object
+// ----------------------------------------------------------------------------- 
+//
+CPrivacyAndLocationHandler& CLbsPrivLocFsm::PrivLocHandler()
+	{
+	return iPrivLocHandler;
+	}
+
+// ----------------------------------------------------------------------------- 
+// CLbsPrivLocWaitLocUpdateState::OnTimerEventL
+// Description: The Location Update timer has expired.
+// Cancel the request, and pass on the response if any has been received,
+// otherwise report failure.
+// ----------------------------------------------------------------------------- 
+//
+void CLbsPrivLocFsm::OnTimerEventL(TInt aTimerId)
+	{	
+	LBSLOG2(ELogP3, "FSM(%d) OnTimerEventL", iSessionId.SessionNum());
+	iCurrentState->OnTimerEventL(aTimerId);
+	}
+
+/** Called if OnTimerEventL leaves */
+TInt CLbsPrivLocFsm::OnTimerError(TInt /*aTimerId*/, TInt aError)
+	{
+	__ASSERT_DEBUG(EFalse, Panic(ENrhPanicLocationTimerError));
+	return(aError);
+	}
+
+/** Callback when a GPS position update arrives from AGPS manager.
+*/
+void CLbsPrivLocFsm::OnAgpsPositionUpdate(
+	TInt aReason,
+	const TPositionExtendedSatelliteInfo& aPosInfo,
+	const TTime& aTimeStamp)
+	{
+	LBSLOG2(ELogP3, "FSM(%d) OnAgpsPositionUpdate", iSessionId.SessionNum());
+	iCurrentState->OnAgpsPositionUpdate(aReason, aPosInfo, aTimeStamp);
+	}
+
+/** Callback when a GPS measurement results update arrives from AGPS manager.
+*/
+void CLbsPrivLocFsm::OnAgpsMeasurementUpdate(
+	TInt aReason,
+	const TPositionGpsMeasurementInfo& aPosInfo,
+	const TTime& aTimeStamp)
+	{
+	LBSLOG2(ELogP3, "FSM(%d) OnAgpsMeasurementUpdate", iSessionId.SessionNum());
+	iCurrentState->OnAgpsMeasurementUpdate(aReason, aPosInfo, aTimeStamp);
+	}