datacommsserver/networkcontroller/src/CSelectionRequest.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/networkcontroller/src/CSelectionRequest.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,904 @@
+// Copyright (c) 2003-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:
+//
+
+/**
+ @file CSelectionRequest.cpp
+*/
+
+#include <nifman.h>
+#include <comms-infras/nifagt.h>
+#include <es_connpref.h>
+#include "CSelectionRequest.h"
+#include "CNetworkController.h"
+#include "NetConPanic.h"
+#include "NetConLog.h"
+#include "NetConError.h"
+
+CSelectionRequest* CSelectionRequest::NewL(MNetConEnv* aController, MNetworkControllerObserver* aObserver, TConnStartType aStartType, const TConnPref& aPrefs, TInt aConnectionAttempt, TInt aLastConnectionError)
+/**
+Factory function
+
+Creates a new CSelectionRequest object
+
+@param aController pointer to the Network Controller
+@param aObserver the object that initiated this request
+@param aStartType how this request was initiated either Implicit(due to RSocket/RHostResolver calls) or Explicit(due to an RConnection call)
+@param aPrefs connection preferences to be used when selecting an appropriate Agent
+@param aConnectionAttempt indicates the current connection attempt
+@param aLastConnectionError if this is not the first connection attempt then the error of the last attempt
+@exception leaves if object cannot be constructed
+@return the new CSelectionRequest object
+*/
+ 	{
+
+	CSelectionRequest* self = new(ELeave) CSelectionRequest(aController, aObserver, aStartType, aPrefs, aConnectionAttempt, aLastConnectionError);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(); // self
+	return self;
+	}
+
+CSelectionRequest::~CSelectionRequest()
+/**
+Destructor
+*/
+	{
+
+	if(iOverrides)
+		delete iOverrides;
+
+	if(iAgentName)
+		delete iAgentName;
+	}
+
+CSelectionRequest::CSelectionRequest(MNetConEnv* aController, MNetworkControllerObserver* aObserver, TConnStartType aStartType, const TConnPref& aPrefs, TInt aConnectionAttempt, TInt aLastConnectionError)
+: CNetConRequestBase(aController, aObserver, NULL), iConnStartType(aStartType), iConnPrefs(aPrefs), iConnectionAttempt(aConnectionAttempt), iLastConnectionError(aLastConnectionError)
+/**
+Constructor
+
+@param aDatabase pointer to the object used to access CommDb
+@param aDialogPrc pointer to the object used to access the dialog processor
+@param aController pointer to the Network Controller
+@param aObserver the object that initiated this request
+@param aStartType how this request was initiated either Implicit(due to RSocket/RHostResolver calls) or Explicit(due to an RConnection call)
+@param aPrefs connection preferences to be used when selecting an appropriate Agent
+@param aConnectionAttempt indicates the current connection attempt
+@param aLastConnectionError if this is not the first connection attempt then the error of the last attempt
+*/
+	{ }
+
+void CSelectionRequest::ConstructL()
+/**
+2nd phase of construction
+
+@exception leaves if 2nd phase construction leaves
+*/
+	{
+	CNetConRequestBase::ConstructL();
+
+	// construct a HBufC in which to store the name of the agent
+	const TUint8 KInitialAgentNameLength = 20;
+	iAgentName = HBufC::NewL(KInitialAgentNameLength);
+	_LIT(KUndefined, "Undefined");
+	SetAgentNameL(KUndefined());
+	}
+
+void CSelectionRequest::SetAgentNameL(const TDesC& aName)
+/**
+Replace the value of iAgentName allocating more memory if needed
+
+@param aName the new name of the Agent
+@exception leaves with KErrNoMemory if allocation fails
+*/
+	{
+	ASSERT(iAgentName);
+
+	// see if we need to allocate more memory for the agent name
+	if (aName.Length() > iAgentName->Length())
+		{
+		iAgentName = iAgentName->ReAllocL(aName.Length());
+		}
+
+	// replace agent name
+	*iAgentName = aName;
+	}
+
+void CSelectionRequest::StartRequest()
+/**
+Start processing this request
+*/
+	{
+	LOG (
+		NetConLog::Printf(_L("\tRequest type = Selection"));
+		NetConLog::Printf(_L("\tConnection attempt = %d"), iConnectionAttempt);
+		NetConLog::Printf(_L("\tConnection type = %d"), iConnStartType);
+		)
+
+	// set overrides for this request in the databse
+	TRAPD(err, iDatabase->SetOverridesL(iOverrides);
+               iDatabase->RequestNotificationOfServiceChangeL(ipServiceChangeObserver));
+
+	if(err!=KErrNone)
+		{
+		LOG( NetConLog::Printf(_L("\tError %d encountered during start of IAP selection routine - is CommDb setup correctly?"), err); )
+		RequestComplete(err);
+		return;
+		}
+
+	TRAP(err, StartSelectL());
+	if(err!=KErrNone)
+		{
+		LOG( NetConLog::Printf(_L("\tError %d encountered during start of IAP selection routine - is CommDb setup correctly?"), err); )
+		RequestComplete(err);
+		}
+	}
+
+void CSelectionRequest::RequestComplete(TInt aError)
+/**
+Complete this request with a given error
+ 
+@param aError the error with which to complete the request
+*/
+	{
+
+	LOG( NetConLog::Printf(_L("\tRequest Complete with error %d"), aError); )
+
+	iController->RequestComplete(this, aError);
+	}
+
+const TDesC& CSelectionRequest::AgentName() const
+/**
+Retrieves the name of the agent that was selected
+*/
+	{
+	if(!iAgentName)
+		{
+		return KNullDesC();
+		}
+	else
+		{
+		return *iAgentName;
+		}
+	}
+
+const TPckgBuf<TSoIfConnectionInfo>& CSelectionRequest::AgentConnectionInfo() const
+/**
+Retrieves the connection information of the agent that was selected
+*/
+	{
+	return iAgentConnInfo;
+	}
+
+const TConnStartType& CSelectionRequest::ConnectionStartType() const
+/**
+@return the connection start type - i.e. either implicit or explicit
+*/
+	{
+	
+	return iConnStartType;
+	}
+
+const TConnPref& CSelectionRequest::ConnPrefs() const
+/**
+@return the connection preferences associated with this request
+*/
+	{
+
+	return iConnPrefs;
+	}
+
+void CSelectionRequest::StartSelectL()
+/**
+Start the selection process
+
+Read current connection preferences and settings from the database then start the selection process. 
+
+@exception leaves if database access leaves
+*/
+ 	{
+
+	// clear any existing overrides in the database
+	iDatabase->SetOverridesL(NULL);
+
+	// check that we are within the maximum number of connection attempts specified by CommDb
+	TInt maxConnectionAttempts = iDatabase->GetConnectionAttempts();
+	
+	User::LeaveIfError(maxConnectionAttempts);
+
+	// allow the connection preferences to override the max number of connection attempts in CommDb
+	if(iConnPrefs.ExtensionId() == TConnPref::EConnPrefCommDbMulti)
+		{
+		TInt preferences = TCommDbMultiConnPref::Cast(iConnPrefs).ConnectionAttempts();
+		maxConnectionAttempts = preferences; 
+		}
+
+	if(iConnectionAttempt > maxConnectionAttempts)
+		{
+		LOG( NetConLog::Printf(_L("\tError - maximum number of connection attempts (%d) reached"), maxConnectionAttempts); )
+		RequestComplete(KErrOverflow);
+		return;
+		}
+
+	// extract a TCommDbConnPref from iConnPrefs
+	TCommDbConnPref commDbPref;
+	User::LeaveIfError(ExtractCommDbConnPref(iConnPrefs, commDbPref));
+
+	// set connection attempt
+	iSettings.iRank = iConnectionAttempt;
+
+	// if direction is not specified then default to outgoing
+	if(commDbPref.Direction() == ECommDbConnectionDirectionUnknown)
+		{
+		commDbPref.SetDirection(ECommDbConnectionDirectionOutgoing);
+		}
+
+	// extract connection direction
+	iSettings.iDirection = commDbPref.Direction();
+
+	TUint32 overidenIap = commDbPref.IapId();
+
+	// Wnsure that a valid IAP exists in the 
+	TUint32 preferredIap(overidenIap);
+	LOG( NetConLog::Printf(_L("\tpreferredIap=%d"), preferredIap); )
+
+	if (overidenIap == 0)
+		{
+		iDatabase->GetPreferedIapL(preferredIap, iSettings.iDirection, iSettings.iRank);
+		LOG( NetConLog::Printf(_L("\tnew preferredIap=%d"), preferredIap); )
+		}
+
+	// If this IAP doesn't exist, we must prompt the user
+	if((preferredIap == 0) || !iDatabase->DoesIapExistL(preferredIap))
+		{
+		LOG( NetConLog::Printf(_L("\tActive settings for IAP have been set to prompt, since the IAP doesn't exist"));)
+		commDbPref.SetDialogPreference(ECommDbDialogPrefPrompt);
+
+		// IAP is invalid, override it in the active settings to allow prompt to continue
+		iDatabase->GetFirstValidIapL(preferredIap);
+		commDbPref.SetIapId(preferredIap);
+		}
+
+	// convert the connection preferences into some appropriate override settings
+	iOverrides = MapPrefsToOverridesL(commDbPref, iSettings);
+
+	if(iOverrides)
+		{
+		//set these overrides in the database
+		iDatabase->SetOverridesL(iOverrides);
+		}
+
+	iDatabase->GetCurrentSettingsL(iSettings, iSettings.iDirection, iSettings.iRank);
+
+	if((iConnStartType == EConnStartImplicit) && iController->ImplicitConnectionAgentName())
+		{
+		// there is already an implicit connection - try to match the preferences
+		TCommDbConnPref implicitPref;
+		User::LeaveIfError(ExtractCommDbConnPref(iController->ImplicitConnectionPrefs(), implicitPref));
+		if(commDbPref == implicitPref)
+			{
+			// This is an implicit request for an outgoing connection and there
+			// has already been another implicit request - just return the name
+			// of the existing agent
+			LOG( NetConLog::Printf(_L("\tReturning existing agent for implicit connection: '%S'"), iController->ImplicitConnectionAgentName()); )
+			SetAgentNameL(*iController->ImplicitConnectionAgentName());
+			RequestComplete(KErrNone);
+			}
+		else
+			{
+			LOG( NetConLog::Printf(_L("\tImplicit connection already exists - cannot start a new one with conflicting preferences!")); )
+			RequestComplete(KErrInUse);
+			}
+		return;
+		}
+
+	// store the completed preferences as iConnPrefs
+	// this is so that if the CNetworkController asks for the prefs used for the
+	// selected connection we will return the accurate prefs (with the default
+	// values filled in)
+	iConnPrefs = commDbPref;
+
+	// for some reason we have to write these settings back to the database, otherwise
+	// when dialog prompt is set to warn we get an error - why?
+	iDatabase->SetCurrentSettingsL(iSettings);
+
+	// note that we no-longer display the "Select Modem & Location" dialog boxes
+	// since the IAP points to the modem and location
+
+	// read service settings from database
+	iDatabase->GetServiceSettingsL(iSettings);
+
+	LOG (
+		NetConLog::Printf(_L("\tPreferred Service Type = '%S'"), &iSettings.iServiceType);
+		NetConLog::Printf(_L("\tPreferred Service Id = %d"), iSettings.iServiceId);
+		NetConLog::Printf(_L("\tPreferred Bearer Set = %d"), iSettings.iBearerSet);
+		)
+
+	// check for bearer availability
+	iDoBearerAvailability = !(iSettings.iDialogPref==ECommDbDialogPrefWarn || iSettings.iDialogPref==ECommDbDialogPrefDoNotPrompt);
+	if (iDoBearerAvailability)
+		{
+		// Bearer availability check is only performed if prompting
+		// It is only used to help populate the dialogue with available bearers
+		//
+		// Warning: that the results of the CheckBearerAvailability are 
+		// only used in the case of ECommDbDialogPrefPromptIfWrongMode
+		// so it might be possible to remove this check and speed things up
+		// 
+		LOG( NetConLog::Printf(_L("\tRequesting bearer availability")); )
+		iController->CheckBearerAvailability(EFalse);  // EFalse indicates that this is not a reconnection
+		}
+	else
+		{
+		// Not prompting so do best effort and allow all bearers
+		// Allow all bearers if bearer availability check is not done
+		LOG( NetConLog::Printf(_L("\tSkipping bearer availability check")); )
+		SetAvailableBearers(KCommDbBearerCSD | KCommDbBearerLAN | KCommDbBearerVirtual);
+		}
+	}
+
+TInt CSelectionRequest::ExtractCommDbConnPref(const TConnPref& aBasePref, TCommDbConnPref& aCommDbPref)
+/**
+Extract a single TCommDbConnPref from the given TConnPref
+
+@param aBasePref the TConnPref
+@param aCommDbPref on return contains the TCommDbConnPref extracted from the TConnPref
+@return KErrNone if the TCommDbConnPref could be extracted, otherwise KErrArgument
+*/
+	{
+	TInt err(KErrNone);
+
+	// if the TConnPref argument is a valid CommDb connection preference then cast it to one
+	switch(aBasePref.ExtensionId())
+		{
+		case TConnPref::EConnPrefCommDb:
+			// cast down to a TCommDbConnPref
+			aCommDbPref = TCommDbConnPref::Cast(aBasePref);
+			break;
+
+		case TConnPref::EConnPrefCommDbMulti:
+			{
+			// cast down to a TCommDbMultiConnPref
+			TCommDbMultiConnPref multiPrefs = TCommDbMultiConnPref::Cast(aBasePref);
+
+			// check the number of connection attempts
+			if(iConnectionAttempt > multiPrefs.ConnectionAttempts())
+				{
+				LOG( NetConLog::Printf(_L("\tError - maximum number of connection attempts (%d) reached"), multiPrefs.ConnectionAttempts()); )
+				err = KErrOverflow;
+				}
+			else
+				{
+				// connection attempt is ok, try to retrieve the connection preference for this attempt
+				err = multiPrefs.GetPreference(iConnectionAttempt, aCommDbPref);
+				}
+			
+			break;
+			}
+
+		case TConnPref::EConnPrefSnap:
+			err = KErrNotSupported;
+			break;
+			
+		case TConnPref::EConnPrefIdList:
+			{
+			const TCommIdList& pref = static_cast<const TCommIdList&>(aBasePref);
+			// check the number of connection attempts
+			if(iConnectionAttempt > pref.Count())
+				{
+				LOG( NetConLog::Printf(_L("\tError - the last AP (%d) reached"), pref.Count()); )
+				err = KErrOverflow;
+				}
+			else
+				{
+				// connection attempt is ok, try to retrieve the connection preference for this attempt
+				TInt iap = pref.Get(iConnectionAttempt-1);
+				aCommDbPref.SetIapId(iap);
+				aCommDbPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
+				//otherwise keep the default TCommDbConnPref class settings
+				}
+			break;
+			}
+			
+		case TConnPref::EConnPrefUnknown:
+			// a TConnPref - just ignore and use the default values from the connection preferences table
+			break;
+
+		default:
+			// some sort of unrecognised connection preference type - error the caller
+			err = KErrArgument;
+
+		}
+
+	return err;
+	}
+
+CStoreableOverrideSettings* CSelectionRequest::MapPrefsToOverridesL(TCommDbConnPref& aPrefs, const TConnectionSettings& aSettings)
+/**
+Convert user's connection preferences into an override setting
+
+@param aPrefs a set of connection preferences passed in by the user
+@param aSettings the current default connection preference settings
+@return override settings matching the supplied connection preferences or NULL if the TCommDbConnPref is empty
+@exception leaves if OOM or database access fails
+*/
+	{
+	CCommsDbConnectionPrefTableView::TCommDbIapConnectionPref iapPref;
+
+	// set rank to this connection attempt
+	iapPref.iRanking = aSettings.iRank;
+
+	// always use direction given in prefs
+	iapPref.iDirection = aSettings.iDirection;
+
+	// if specified, use the settings given in the connection
+	// preferences - otherwise read the default values from CommDb
+	TBool useOverrides(EFalse);
+
+	if(aPrefs.DialogPreference() != ECommDbDialogPrefUnknown)
+		{
+		LOG( NetConLog::Printf(_L("\tDialog Preference overriden to %d"), aPrefs.DialogPreference()); )
+
+		iapPref.iDialogPref = aPrefs.DialogPreference();
+		useOverrides = ETrue;
+		}
+	else
+		{
+		// use current connection preference dialog setting from database
+		iapPref.iDialogPref = aSettings.iDialogPref;
+		aPrefs.SetDialogPreference(aSettings.iDialogPref);
+		}
+
+	if(aPrefs.BearerSet() != KCommDbBearerUnknown)
+		{
+		LOG( NetConLog::Printf(_L("\tBearer Set overriden to %d"), aPrefs.BearerSet()); )
+
+		iapPref.iBearer.iBearerSet = aPrefs.BearerSet();
+		useOverrides = ETrue;
+		}
+	else
+		{
+		// use current connection preference BearerSet setting from database
+		iapPref.iBearer.iBearerSet = aSettings.iBearerSet;
+		aPrefs.SetBearerSet(aSettings.iBearerSet);
+		}
+	
+	if(aPrefs.IapId() != 0)
+		{
+		LOG( NetConLog::Printf(_L("\tIAP ID overriden to %d"), aPrefs.IapId()); )
+		
+		iapPref.iBearer.iIapId = aPrefs.IapId();
+		useOverrides = ETrue;
+
+		}
+	else
+		{
+		// use current connection preference IAP setting from database
+		iapPref.iBearer.iIapId = aSettings.iIAPId;
+		aPrefs.SetIapId(aSettings.iIAPId);
+		}
+
+	CStoreableOverrideSettings* overrides = NULL;
+	if (useOverrides)
+		{
+		overrides = CStoreableOverrideSettings::NewL(CCommDbOverrideSettings::EParamListPartial);
+		CleanupStack::PushL(overrides);
+		User::LeaveIfError(overrides->SetConnectionPreferenceOverride(iapPref));
+		CleanupStack::Pop(); // overrides
+		}
+
+	return overrides;
+	}
+
+void CSelectionRequest::SetAvailableBearers(TUint32 aBearerSet)
+/**
+Callback from the Network Controller when the bearer availability check is complete
+
+@param aBearerSet the set of available bearers
+*/
+	{
+	LOG( NetConLog::Printf(_L("\tAvailable Bearer Set = %d"), aBearerSet); )
+
+	// is the selected service available?
+	TBool available;
+	if( (iSettings.iDialogPref == ECommDbDialogPrefPrompt) || 
+	    (iSettings.iDialogPref == ECommDbDialogPrefPromptIfWrongMode))
+		{
+		/* The ServiceAvailable check is not necessary in prompt mode, since the user hasn't had a chance yet
+		   to select the IAP. */
+		available = ETrue;
+		}
+	else
+		{
+		available = SelectedServiceAvailable(aBearerSet);
+		}
+
+	TRAPD(err, SelectIapL(available, aBearerSet));
+	if(err!=KErrNone)
+		{
+		LOG_DETAILED( NetConLog::Printf(_L("SelectionRequest %x\tSelectIapL left with %d"), this, err); )
+		RequestComplete(err);
+		}
+	}
+
+TBool CSelectionRequest::ServiceAvailableInAlternateMode(TUint32& aBearerSet, const TUint32 aAvailableBearerSet)
+/**
+The selected service is not available in this network mode - see if it is available in an alternate mode
+
+If the selected service is GPRS but the network mode is CDMA (or vice versa) then prompt the user
+to select an appropriate IAP.
+
+@param aBearerSet on entry the set of selected bearers, on exit the set of bearers to pass to the dialog box
+@param aAvailableBearerSet the set of available bearers
+@return ETrue if an alternate bearer is available in another network mode, otherwise EFalse
+*/
+	{
+
+	// read network mode from database
+	RMobilePhone::TMobilePhoneNetworkMode networkMode(RMobilePhone::ENetworkModeUnknown);
+	networkMode = iDatabase->NetworkMode();
+
+	switch (networkMode)
+		{
+		case RMobilePhone::ENetworkModeGsm:
+		default:
+			LOG( NetConLog::Printf(_L("\tPacket data network mode is unknown")); )
+			break;
+		}
+
+	// we couldn't switch from GPRS to CDMA or
+	// vice-versa so see if CSD is available
+	if(aAvailableBearerSet & KCommDbBearerCSD)
+		{
+		LOG( NetConLog::Printf(_L("\tPSD selected but only CSD available")); )
+		aBearerSet = KCommDbBearerCSD;
+		return ETrue;
+		}
+	else
+		{
+		return EFalse;
+		}
+	}
+
+void CSelectionRequest::SelectIapL(const TBool aSelectedServiceAvailable, const TUint32 aAvailableBearerSet)
+/**
+Select which Internet Access Point to connect to
+
+@param aSelectedServiceAvailable whether the bearer required by the service is available
+@param aAvailableBearerSet the set of available bearers
+@exception leaves if database access leaves or if no service is available
+*/
+	{
+
+	// set up connection preferences
+	TConnectionPrefs prefs;
+	prefs.iRank = iSettings.iRank;
+	prefs.iDirection = iSettings.iDirection;
+	prefs.iBearerSet = iSettings.iBearerSet;
+
+	TBool serviceAvailable(aSelectedServiceAvailable);
+	TInt error(KErrNotFound);
+
+	switch (iSettings.iDialogPref)
+		{
+		case ECommDbDialogPrefWarn:
+			LOG( NetConLog::Printf(_L("\tDialog box preference set to Warn")); )
+				
+			if(serviceAvailable)
+				{
+				// display IAP warning dialog box
+				// will call back to MDPOWarnComplete() when finished
+				TBuf<KCommsDbSvrMaxFieldLength> iapName;
+				iDatabase->GetDesL(TPtrC(IAP),TPtrC(COMMDB_NAME), iapName);
+				WarnNewConnection(prefs, &iapName, NULL, 0);
+				}
+			break;
+		case ECommDbDialogPrefDoNotPrompt:
+			LOG( NetConLog::Printf(_L("\tDialog box preference set to Do Not Prompt")); )
+			
+			if(serviceAvailable)
+				{
+				SelectIAPCompleteL(iSettings);
+				}
+			break;
+		case ECommDbDialogPrefPromptIfWrongMode:
+			LOG( NetConLog::Printf(_L("\tDialog box preference set to Prompt If Wrong Mode")); )
+		
+			if(serviceAvailable)
+				{
+				SelectIAPCompleteL(iSettings);
+				}
+			else
+				{
+				serviceAvailable = ServiceAvailableInAlternateMode(prefs.iBearerSet, aAvailableBearerSet);
+				if(serviceAvailable)
+					{
+					// display IAP selection dialog box
+					// will call back to MDPOSelectComplete() when finished
+					// Warning:  prefs does not contain the aAvailableBearerSet
+					// so the dialogue may be presented with unavailable Bearers
+					SelectConnection(prefs, iLastConnectionError);
+					}
+				else
+					{
+					error = KErrNetConNoGPRSNetwork;
+					}
+				}
+			break;
+		case ECommDbDialogPrefPrompt:
+		case ECommDbDialogPrefUnknown:
+		default:
+			LOG ( 
+				if(iSettings.iDialogPref == ECommDbDialogPrefPrompt)
+					NetConLog::Printf(_L("\tDialog box preference set to Prompt"));
+				else
+					{
+					if (iSettings.iDialogPref == ECommDbDialogPrefUnknown)
+						NetConLog::Printf(_L("\tDialog box preference set to Unknown"));
+					else
+						NetConLog::Printf(_L("\tDialog box preference not set"));
+					}
+				)
+
+			if(serviceAvailable)
+				{
+				// display IAP selection dialog box
+				// will call back to MDPOSelectComplete() when finished
+				// Warning:  prefs does not contain the aAvailableBearerSet
+				// so the dialogue may be presented with unavailable Bearers
+				SelectConnection(prefs);
+				}
+			break;
+		}
+
+	if (!serviceAvailable)
+		{
+		if(iDoBearerAvailability)
+			{
+			iController->CancelBearerAvailabilityCheck();
+			}
+		User::Leave(error);
+		}
+	}
+
+void CSelectionRequest::SelectAgentL()
+/**
+Decide whether to create a new agent or return an existing one
+
+Check to see if there is already a connection to the
+selected IAP and if so use the existing CNifAgentBase
+Otherwise start a new Agent to the IAP
+
+@exception leaves if database access or memory allocation
+leaves or if signal strength is not sufficient
+*/
+	{
+	if(iDoBearerAvailability)
+		{
+		if (iSettings.iBearerType.Compare(TPtrC(MODEM_BEARER))==0)
+			{
+			// connection is not NTRAS so check that the received signal strength is still ok
+			User::LeaveIfError(iController->RequestSecondPhaseAvailability());
+			}
+		else
+			{
+			iController->CancelBearerAvailabilityCheck();
+			}
+		}
+
+	CNifAgentBase* agent=NULL;
+
+	TInt findErr = iController->FindExistingAgentForSelection(agent, iDatabase);
+
+	if(findErr==KErrNone)
+		{
+		// found an Agent already connected to this IAP
+		// retrieve the unique name of the agent and 
+		// complete the request
+		TNifAgentInfo info;
+		agent->Info(info);
+		LOG( NetConLog::Printf(_L("\tFound existing agent '%S' already connected to IAP %d"), &(info.iName), iSettings.iIAPId); )
+		SetAgentNameL(info.iName);
+		RequestComplete(KErrNone);
+		return;
+		}
+
+	// otherwise - no existing connection to IAP - try to load a new agent
+	LOG( NetConLog::Printf(_L("\tNo existing agent connected to IAP %d"), iSettings.iIAPId); )
+
+	// read name of Agent from the bearer table
+	TFileName agentName;
+	iDatabase->GetDesL(iSettings.iBearerType, TPtrC(AGENT_NAME), agentName);
+
+	// ask Nifman to create a new Agent, instantiating a new instance of an
+	// existing agent if needed (note that Nifman maintains ownership of the agent)
+	LOG( NetConLog::Printf(_L("\tCreating a new instance of agent '%S' for connection to IAP %d"), &agentName, iSettings.iIAPId); )
+	agent = Nif::CreateAgentL(agentName, ETrue);
+
+	// read the Agent's name
+	TNifAgentInfo info;
+	agent->Info(info);
+	SetAgentNameL(info.iName);
+	LOG( NetConLog::Printf(_L("\tAgent '%S' created for connection to IAP %d"), iAgentName, iSettings.iIAPId); )
+
+	if(iOverrides)
+		{
+		// set overrides in the Agent's database - ownership of the overrides is transferred to the agent
+		agent->SetOverridesL(iOverrides);
+		iOverrides = NULL;
+		}
+
+	// set connection settings in Agent's database
+	agent->SetConnectionSettingsL(iSettings);
+
+	// read the Network ID of the IAP
+	TUint32 networkId(0);
+	iDatabase->GetIntL(TPtrC(IAP), TPtrC(IAP_NETWORK), networkId);
+
+	// add the agent to the corresponding CNetwork object
+	iController->AddAgentToNetworkL(agent, networkId);
+
+	// store Agent Connection Info (IAP ID and Network ID)
+	iAgentConnInfo().iIAPId = iSettings.iIAPId;
+	iAgentConnInfo().iNetworkId = networkId;
+
+	// If this is the implicit connection and it has a commdb connection preference 
+	if ((iConnStartType == EConnStartImplicit) &&
+		(iConnPrefs.ExtensionId() == TConnPref::EConnPrefCommDb))
+		{
+		TCommDbConnPref* commdbPref = (TCommDbConnPref*) &iConnPrefs; // cast down to a TCommDbConnPref
+
+		if (commdbPref->IapId() == 0)
+			{
+			commdbPref->SetIapId(iSettings.iIAPId);
+			}
+		}
+
+	RequestComplete(KErrNone);
+	}
+
+void CSelectionRequest::SelectIAPCompleteL(const TConnectionSettings& aSettings)
+/**
+IAP Selection is complete
+
+At this point the selection is complete.  The Modem, Location and IAP have
+been selected so load the appropriate Agent and set these settings in the
+Agent.
+
+@param aSettings The set of (now complete) connection settings
+@exception leaves if database access or loading the Agent leaves
+*/
+ 	{
+ 	 	
+	if((iSettings.iDialogPref == ECommDbDialogPrefPrompt ||
+		iSettings.iDialogPref == ECommDbDialogPrefPromptIfWrongMode)
+		&& iSettings.iIAPId != aSettings.iIAPId)
+		{
+		// update stored connection preferences to reflect user's choice
+		TCommDbConnPref commDbPref(TCommDbConnPref::Cast(iConnPrefs));
+		commDbPref.SetIapId(aSettings.iIAPId);
+		commDbPref.SetBearerSet(aSettings.iBearerSet);
+		iConnPrefs = commDbPref;
+		iSettings.iIAPId = aSettings.iIAPId;
+
+		// Convert the new connection preferences into some appropriate override settings
+		CStoreableOverrideSettings* overrides;
+		overrides = MapPrefsToOverridesL(commDbPref, iSettings);
+		if (overrides)
+			{
+			CleanupStack::PushL(overrides);
+			iDatabase->SetOverridesL(overrides);
+			CleanupStack::Pop();		// overrides
+			}
+		else
+			{
+			iDatabase->SetOverridesL(overrides);
+			}
+
+		if (iOverrides)
+			{
+			delete iOverrides;
+			}
+
+		iOverrides = overrides;
+		}
+	else
+		{
+		// Store selected IAP
+		iSettings.iIAPId = aSettings.iIAPId;
+		}
+
+	// write the selected settings to the DbAccess object and refresh the service settings
+	iDatabase->SetCurrentSettingsL(iSettings);
+	iDatabase->GetCurrentSettingsL(iSettings, iSettings.iDirection, iSettings.iRank);
+	iDatabase->GetServiceSettingsL(iSettings);
+
+	LOG (
+		NetConLog::Printf(_L("\tSelected IAP Id = %d"), iSettings.iIAPId);
+		NetConLog::Printf(_L("\tSelected Location Id = %d"), iSettings.iLocationId);
+		NetConLog::Printf(_L("\tSelected Bearer Type = '%S'"), &iSettings.iBearerType);
+		NetConLog::Printf(_L("\tSelected Bearer Id = %d"), iSettings.iBearerId);
+		NetConLog::Printf(_L("\tSelected Service Type = '%S'"), &iSettings.iServiceType);
+		NetConLog::Printf(_L("\tSelected Service Id = %d"), iSettings.iServiceId);
+		NetConLog::Printf(_L("\tSelected Bearer Set = %d"), iSettings.iBearerSet);
+		)
+
+	SelectAgentL();
+	}
+
+void CSelectionRequest::MDPOWarnComplete(TInt aError, TBool aResponse)
+/**
+Callback from the dialog processor when the "Warn about New Connection" dialog box has completed
+
+@param aError KErrCancel if the user selected "Cancel", otherwise KErrNone
+@param aReponse ETrue if the user selected "OK" otherwise EFalse
+*/
+	{
+
+	if (aError == KErrNone)
+		{
+		if (aResponse)
+			{
+			// User did not cancel the connection
+			// Find or Load an Agent based on selection
+			TRAPD(err, SelectIAPCompleteL(iSettings));
+			if(err!=KErrNone)
+				{
+				LOG_DETAILED( NetConLog::Printf(_L("\tError %d loading agent"), err); )
+				RequestComplete(err);
+				}
+			}
+		else
+			{
+			// User cancelled the connection
+			aError = KErrCancel;
+			}
+		}
+
+	if(aError!=KErrNone)
+		{
+		iController->CancelBearerAvailabilityCheck();
+		RequestComplete(aError);
+		return;
+		}
+
+	}
+
+void CSelectionRequest::MDPOSelectComplete(TInt aError, const TConnectionSettings& aSettings)
+/**
+Callback from the dialog processor when the "Select IAP" dialog box has completed
+
+@param aError KErrNone if the dialog box complete ok, otherwise KErrCancel
+@param aSettings if there was no error will contain the CommDb ID of the selected IAP
+*/
+	{
+
+	if(aError!=KErrNone)
+		{
+		iController->CancelBearerAvailabilityCheck();
+		RequestComplete(aError);
+		return;
+		}
+
+	// Find or Load an Agent based on user selection
+	// Assume that the selected bearer is available its an edge case when
+	// the selected bearer is not available or has now failed 
+	TRAPD(err, SelectIAPCompleteL(aSettings));
+	if(err!=KErrNone)
+		{
+		LOG_DETAILED( NetConLog::Printf(_L("SelectionRequest %x\tSelectIAPCompleteL left with error %d"), this, err); )
+		RequestComplete(err);
+		}
+	}
+