smartinstaller/bootstrap/src/bootstrapstatemachine.cpp
branchADM
changeset 48 364021cecc90
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smartinstaller/bootstrap/src/bootstrapstatemachine.cpp	Wed Jun 30 11:01:26 2010 +0530
@@ -0,0 +1,1686 @@
+/*
+* Copyright (c) 2009-2010 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:
+*     CStateMachine class implementation.
+*
+*
+*/
+
+#include <e32base.h>
+#include <aknappui.h>
+#include <swinstdefs.h>
+#include <swi/sisregistrysession.h>
+#include <swi/sisregistryentry.h>
+#include <httpdownloadmgrcommon.h>
+#include <coeutils.h>
+#include <SenDomFragment.h>
+#include <SenXmlReader.h>
+#include <SenElement.h>
+#include <centralrepository.h>      // CRepository
+#include <browseruisdkcrkeys.h>     // KCRUidBrowser
+
+#include <wlanerrorcodes.h> 		//For download error handling
+#include <etelpckt.h>       		//For download error handling
+#include <exterror.h>       		//For download error handling
+#include <httpdownloadmgrcommon.h>	//For download error handling (not in S60 5.0 SDK)
+
+#include <es_enum.h>
+#include <rconnmon.h>
+#include <eikdef.h>
+
+#include "bootstrapstatemachine.h"
+#include "bootstrapappui.h"
+#include "bootstrapconst.h"
+#include "bootstrapinstallationobserver.h"
+#include "smartinstallerdll.h"
+#include "debug.h"
+#include "globals.h"
+#include "macros.h"
+#include "config.h"
+#include "utils.h" // HideAppFromMenuL()
+
+// ADM binary name
+_LIT(KAdmExePath, "ADM.exe");
+_LIT(KDownloadFolder,"?:\\system\\adm\\");
+// Sis file extension
+_LIT(KSisExtn,".SIS");
+_LIT(KSisxExtn,".SISX");
+// Xml file extension
+_LIT(KXMLExtn,".XML");
+// Dep file extension
+_LIT(KDepExtn,"_DEP");
+// ADM changes file name
+_LIT(KAdmChangesFile, "adm_changes.xml");
+// Private folder of SWI Daemon
+_LIT(KSWIDaemonPrivateFolder, "\\private\\10202dce\\");
+
+// ---------------------------------------------------------------------------
+// CStateMachine::NewLC
+// ---------------------------------------------------------------------------
+//
+CStateMachine* CStateMachine::NewLC(CBootstrapAppUi& aSIUiObj, TUint32 aWrapperUid)
+	{
+	CStateMachine* object = new ( ELeave ) CStateMachine(aSIUiObj, aWrapperUid);
+	CleanupStack::PushL( object );
+	object->ConstructL();
+	return object;
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::NewL
+// ---------------------------------------------------------------------------
+//
+CStateMachine* CStateMachine::NewL(CBootstrapAppUi& aSIUiObj, TUint32 aWrapperUid)
+	{
+	CStateMachine* object = CStateMachine::NewLC(aSIUiObj, aWrapperUid);
+	CleanupStack::Pop();
+	return object;
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::CStateMachine
+// C++ default constructor.
+// ---------------------------------------------------------------------------
+//
+CStateMachine::CStateMachine(CBootstrapAppUi& aBsAppUiObj, TUint32 aWrapperUid) :
+							CActive(CActive::EPriorityStandard),
+							iAppUi(aBsAppUiObj),
+							iWrapperPackageUid(aWrapperUid),
+							iAdmChangesInfo(),
+							iBootstrapFailed(EFalse)
+#ifdef USE_LOGFILE
+							, iLog(aBsAppUiObj.iLog)
+#endif
+	{
+	CActiveScheduler::Add(this);
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::ConstructL
+// 2nd phase constructor.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::ConstructL()
+	{
+	// Connect to the Download Manager
+	TBool masterInstance(!(iAppUi.EikonEnv()->StartedAsServerApp()));
+	iDownloadManager.ConnectL( KUidBootstrapApp, *this, masterInstance );
+
+	User::LeaveIfError(iLauncher.Connect());
+
+	iIsAdmInstalled = IsPackagePresentL(KUidAdm, iAdmInstalledVersion);
+
+	ReadConfigurationL();
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::~CStateMachine
+// Virtual Destructor.
+// ---------------------------------------------------------------------------
+//
+CStateMachine::~CStateMachine()
+	{
+	LOG( "~StateMachine()" );
+	Cancel();
+	DELETE_IF_NONNULL( iDepFilename );
+	DELETE_IF_NONNULL( iSisFilename );
+	DELETE_IF_NONNULL( iDownloadUrl );
+	delete iInstallObsrv;
+	delete iConfigUrl;
+	delete iUrl;
+	delete iDownloadFileName;
+	iIapArray.Close();
+	iDownloadManager.DeleteAll();
+	iDownloadManager.Close();
+	iLauncher.Close();
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::RunL
+// Called for each state transition
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::RunL()
+	{
+	switch (iAppState)
+		{
+		case EBSStateInit:
+			{
+			StateInitL();
+			RequestState(EBSStateDownloadChanges);
+			}
+			break;
+		case EBSStateDownloadChanges:
+			{
+			StateDownloadL();
+			// No need to request a state change. HandleDMgrEventL() will
+			// trigger a correct event after the download has completed.
+			}
+			break;
+		case EBSStateParseChanges:
+			{
+			StateParseChangesL();
+			if( IsAdmDownloadRequired() )
+				{
+				RequestState(EBSStateDownloadAdm);
+				}
+			else
+				{
+				RequestState(EBSStateLaunchAdm);
+				}
+			}
+			break;
+		case EBSStateDownloadAdm:
+			{
+			StateDownloadL();
+			// No need to request a state change. HandleDMgrEventL() will
+			// trigger a correct event after the download has completed.
+			}
+			break;
+		case EBSStateInstallAdm:
+			{
+			StateInstallAdmL();
+			// No need to request a state change. HandleInstallCompleteL() will
+			// trigger a correct event after the installation has completed.
+			}
+			break;
+		case EBSStateLaunchAdm:
+			{
+			StateLaunchAdmL();
+			RequestState(EBSStateExit);
+			}
+			break;
+		case EBSStateExit:
+			{
+			// Exit the application
+			Cancel();
+			iAppUi.ExitApp(iAppState);
+			}
+			break;
+		case EBSStateExitWithError:
+			{
+			Cancel();
+			//Error Id needs to be already set before the state transition.
+			iAppUi.ExitApp(iAppState);
+			}
+			break;
+		default:
+			LOG2( "Ignoring state change %d", iAppState );
+			break;
+		}
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::StateComplete
+// Trigger the state transition.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::RequestState(const EBSAppState aNextState)
+	{
+	LOG3( "+ RequestState(): %d->%d", iAppState, aNextState );
+	iAppState = aNextState;
+	iStatus = KRequestPending;
+
+	if( !IsActive() )
+		{
+		SetActive();
+		}
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete( status, KErrNone );
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::RunError
+// Call Handlefailure incase of error.
+// ---------------------------------------------------------------------------
+//
+TInt CStateMachine::RunError(TInt aError)
+	{
+	LOG2( "+ CStateMachine::RunError(%d)", aError );
+	if ( aError != KLeaveExit )
+		{
+		HandleFailure();
+		return KErrNone;
+		}
+	else
+		{
+		return KLeaveExit;
+		}
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::DoCancel
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::DoCancel()
+	{
+	LOG( "+ CStateMachine::DoCancel()" );
+	iLauncher.CancelAsyncRequest(SwiUI::ERequestSilentInstall);
+	iDownloadManager.DeleteAll();
+	LOG( "- CStateMachine::DoCancel()" );
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::Start
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::Start()
+	{
+	SetActive();
+
+	// send signal that this request has completed
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::Stop
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::Stop()
+	{
+	LOG( "+ CStateMachine::Stop()" );
+	Cancel();
+	}
+
+// ---------------------------------------------------------------------------
+// CBootstrapAppUi::ReadConfigurationL
+// Leaves if runs out of memory
+// Called from ConstructL in InitState
+// @return KErrNone if configuration was read correctly, error code otherwise
+// ---------------------------------------------------------------------------
+//
+TInt CStateMachine::ReadConfigurationL()
+	{
+	LOG( "+ ReadConfiguration()" );
+
+	TFileName configFile;
+	RArray< TPtrC > lineBuffer;
+	RFs& rfs = CEikonEnv::Static()->FsSession();
+
+	// Find the configuration file from the private directory
+	TInt ret = rfs.PrivatePath( configFile );
+	if ( ret == KErrNone )
+		{
+		TBuf<2> appDrive;
+		// Insert the drive of the running application
+		appDrive.Copy(iAppUi.Application()->AppFullName().Left(2));
+		configFile.Insert( 0, appDrive );
+		// Append the configuration file name
+		configFile.Append( KConfigFile );
+
+		LOG2( "configFile = %S", &configFile );
+
+		HBufC* buffer = ReadConfigFile( rfs, configFile, lineBuffer, ret );
+
+		if ( buffer && ret == KErrNone )
+			{
+			// Get Url from the config file
+			TPtrC urlLine = GetConfigValue( KCfgTagUrl, lineBuffer, ret );
+			if ( ret == KErrNone )
+				{
+				iConfigUrl = HBufC8::NewL( urlLine.Length() );
+				iConfigUrl->Des().Copy(urlLine );
+				LOG8_2( "configUrl = %S", iConfigUrl );
+				}
+			delete buffer;
+			}
+		}
+	if ( !iConfigUrl )
+		{
+		// Error occured while reading the configuration, use default URL
+		iConfigUrl = HBufC8::NewL( KDefaultDepServerUrl().Length() );
+		*iConfigUrl = KDefaultDepServerUrl;
+		LOG8_2( "configUrl = %S (default)", iConfigUrl );
+		}
+
+	lineBuffer.Close();
+
+	LOG2("-  ReadConfiguration(): %d", ret );
+	return ret;
+	}
+
+// ---------------------------------------------------------------------------
+// CBootstrapAppUi::StateInitL
+// Enter in EBSStateSetup,
+//
+// Read the sis file name and dep file name, based on Bootstrap version
+// Set the ADM changes file to download and the url to download from.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::StateInitL()
+	{
+	LOG2( "+ SetFileNameInfo(): ver = %d", KBootstrapVersion );
+
+	if( ( KBootstrapVersion < 1 ) && ( KBootstrapVersion > 4 ) )
+		{
+		// Unsupported Bootstrap version
+		User::Leave( KErrNotSupported );
+		}
+
+	// Connect to SisRegistry to fetch Package info
+	Swi::RSisRegistrySession registrySession;
+	User::LeaveIfError( registrySession.Connect() );
+	CleanupClosePushL( registrySession );
+
+	Swi::RSisRegistryEntry entry;
+
+	// Open registry entry
+	User::LeaveIfError( entry.Open( registrySession, TUid::Uid( iWrapperPackageUid ) ) );
+	CleanupClosePushL( entry );
+
+	RPointerArray<HBufC> packageFiles;
+	entry.FilesL( packageFiles );
+	const TInt filesCount( packageFiles.Count() );
+
+	// look into the files installed as part of the package,
+	// to find the dep file name and actuall application file name.
+	for ( TInt i=0; i<filesCount; i++ )
+		{
+		TParsePtrC parse( *packageFiles[i] );
+		TPtrC orgExtn = parse.Ext();
+
+		if ( orgExtn.Length() == 0 )
+			{
+			continue;
+			}
+
+		HBufC* extn = orgExtn.AllocLC();
+		TPtr extnPtr = extn->Des();
+		extnPtr.UpperCase();
+
+		if ( KBootstrapVersion != 3 )
+			{
+			if (( extnPtr.Compare(KSisExtn) == 0 ) || ( extnPtr.Compare(KSisxExtn) == 0 ) )
+				{
+				TPtrC privatePath( KNullDesC );
+				const TInt KDriveLength = 2;
+				if ( ( packageFiles[i]->Length() ) > ( KSWIDaemonPrivateFolder().Length() + KDriveLength ) )
+					{
+					privatePath.Set( packageFiles[i]->Des().Mid( KDriveLength ) );
+					privatePath.Set( privatePath.Left( KSWIDaemonPrivateFolder().Length() ) );
+					}
+
+				// Ignore if its a Stub Sis file
+				if ( privatePath.CompareF( KSWIDaemonPrivateFolder ) )
+					{
+					if ( iSisFilename == NULL )
+						{
+						iSisFilename = packageFiles[i]->AllocL();
+						LOG2( "Application sis '%S'", iSisFilename );
+						}
+					else
+						// More than one sis present in the Wrapper Pkg
+						{
+						LOG2( "! More than one sis file present: '%S'. LEAVE.", packageFiles[i] );
+						//TODO:GM: should there be a new error code for this??
+						User::Leave( KErrNotSupported );
+						}
+					}
+				} // if sis extension
+			} // if (KBoostraVersion != 3)
+
+		if ( KBootstrapVersion != 4 )
+			{
+			if( extnPtr.Compare(KXMLExtn) == 0 )
+				{
+				TPtrC orgName = parse.Name();
+				const TInt namelength = orgName.Length();
+				const TInt depSuffixlength = KDepExtn().Length();
+
+				if ( namelength > depSuffixlength )
+					{
+					TPtrC depSuffix = orgName.Mid( ( namelength-depSuffixlength ), depSuffixlength );
+
+					HBufC* name = depSuffix.AllocLC();
+					TPtr namePtr = name->Des();
+					namePtr.UpperCase();
+
+					if ( namePtr.Compare( KDepExtn ) == 0 )
+						{
+						if ( iDepFilename == NULL )
+							{
+							iDepFilename = packageFiles[i]->AllocL();
+							LOG2( "Dep file name is '%S'", iDepFilename );
+							}
+						else
+							// More than one dep file present in the Wrapper Pkg
+							{
+							LOG2( "! More than one dep file present: '%S'. LEAVE.", packageFiles[i] );
+							//TODO:GM: should there be a new error code for this??
+							User::Leave( KErrNotSupported );
+							}
+						}
+					CleanupStack::PopAndDestroy( name );
+					}
+				} // if XML extn
+			} // if (KBoostrapVersion != 4)
+		CleanupStack::PopAndDestroy( extn );
+		}
+
+	packageFiles.ResetAndDestroy();
+	packageFiles.Close();
+
+	if (KBootstrapVersion != 3)
+		{
+		if ( iSisFilename == NULL )
+			{
+			User::Leave( KErrNotSupported );
+			}
+		}
+	if (KBootstrapVersion != 4)
+		{
+		if ( iDepFilename == NULL )
+			{
+			User::Leave( KErrNotSupported );
+			}
+		}
+
+	CleanupStack::PopAndDestroy(&entry);
+	CleanupStack::PopAndDestroy(&registrySession);
+
+	iFileName.Set(KAdmChangesFile);
+
+	// URL is already set
+	DELETE_IF_NONNULL(iUrl);
+	iUrl = iConfigUrl->AllocL();
+
+	LOG2( "Filename is '%S'",&iFileName );
+
+#ifdef FEATURE_BOOTSTRAP_SETIAP
+	SetAndValidateIAPL();
+#endif
+
+	LOG( "- SetFileNameInfo()" );
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::::IsAdmDownloadRequired
+// Enter after EBSStateParseChanges
+//
+// Verify whether ADM sis download is required. Based on this, the next state will be set.
+// ---------------------------------------------------------------------------
+//
+TBool CStateMachine::IsAdmDownloadRequired()
+	{
+	const TBool isAdmDownloadRequired =
+			CompareVersions(iAdmInstalledVersion, iAdmChangesInfo.iVersion)
+				== EGreaterSecondVersion;
+
+	if ( isAdmDownloadRequired )
+		{
+		LOG7( "ADM update required (v%d.%02d.%d -> v%d.%02d.%d)",
+			iAdmInstalledVersion.iMajor, iAdmInstalledVersion.iMinor, iAdmInstalledVersion.iBuild,
+			iAdmChangesInfo.iVersion.iMajor, iAdmChangesInfo.iVersion.iMinor, iAdmChangesInfo.iVersion.iBuild
+			);
+
+		iFileName.Set(*iAdmChangesInfo.iSisName);
+
+		DELETE_IF_NONNULL(iUrl);
+
+		iUrl = iConfigUrl->AllocL();
+		}
+	else
+		{
+		LOG4( "ADM is up-to-date (v%d.%02d.%d)",
+			iAdmInstalledVersion.iMajor, iAdmInstalledVersion.iMinor, iAdmInstalledVersion.iBuild
+			);
+		}
+
+	return isAdmDownloadRequired;
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::::StateDownloadL
+// Enter in case EBSStateDownloadChanges, EBSStateDownloadAdm
+//
+// Download the specified file from the given url.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::StateDownloadL()
+	{
+	LOG( "+ StateDownloadL()" );
+
+	// Create the full URL for download
+	DELETE_IF_NONNULL( iDownloadUrl );
+	// +1 for '/'
+	iDownloadUrl = HBufC8::NewL(iUrl->Length() + iFileName.Length() + 1 );
+	TPtr8 ptr(iDownloadUrl->Des());
+	ptr.Copy(*iUrl);
+
+	// Append forward slash if that's missing
+	if (ptr.Right(1)[0] != '/')
+		{
+		ptr.Append('/');
+		}
+	ptr.Append(iFileName);
+
+	iDownloadError = EDlErrNoError;
+	iConnectionAttempt = 0;
+
+	// Set download file name along with path
+	TChar systemDrive;
+	RFs::DriveToChar(RFs::GetSystemDrive(), systemDrive);
+
+	DELETE_IF_NONNULL( iDownloadFileName );
+	iDownloadFileName = HBufC::NewL(KDownloadFolder().Length() + iFileName.Length());
+	TPtr responseFilenamePtr = iDownloadFileName->Des();
+
+	responseFilenamePtr.Copy(KDownloadFolder);
+	responseFilenamePtr[0] = systemDrive;
+	responseFilenamePtr.Append(iFileName);
+
+	// Create new download
+	LOG2( "Downloading '%S'", iDownloadFileName );
+	LOG8_2( "  from '%S'", iDownloadUrl );
+
+	TBool isNewDl = ETrue, tried = EFalse;
+retry:
+	RHttpDownload& dl = iDownloadManager.CreateDownloadL( *iDownloadUrl, isNewDl );
+
+	ConeUtils::EnsurePathExistsL(*iDownloadFileName);
+
+	if (isNewDl)
+		{
+		LOG2( "Receiving '%S'", iDownloadFileName );
+		dl.SetStringAttribute( EDlAttrDestFilename, *iDownloadFileName );
+		User::LeaveIfError( dl.Start() );
+		}
+	else
+		{
+		LOG( "Dl exists." );
+		dl.Delete();
+		LOG( "Dl deleted." );
+		if (tried)
+			{
+			LOG( "Tried already, leaving" );
+			User::Leave(KErrAlreadyExists);
+			}
+		else
+			{
+			tried = ETrue;
+			goto retry;
+			}
+		}
+
+	LOG( "- Download()" );
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::StateParseChangesL
+// Enter in case EBSStateParseChanges
+//
+// Parse the given changes file.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::StateParseChangesL()
+	{
+	LOG2( "+ ParseFile('%S')", iDownloadFileName );
+	User::LeaveIfNull(iDownloadFileName);
+
+	// Initialize the parser
+	CSenXmlReader* XmlReader = CSenXmlReader::NewLC(EErrorOnUnrecognisedTags);
+	CSenDomFragment* DomFragment = CSenDomFragment::NewL();
+	CleanupStack::PushL(DomFragment);
+
+	XmlReader->SetContentHandler(*DomFragment);
+	DomFragment->SetReader(*XmlReader);
+
+	// Parse the provided changes file
+	XmlReader->ParseL(CEikonEnv::Static()->FsSession(), *iDownloadFileName);
+
+	// Get package version
+	CSenElement* packageElement;
+	packageElement = DomFragment->AsElement().Element(KFieldVersion);
+	if (packageElement == NULL)
+		{
+		User::Leave(EXmlErrorMissingVersion);
+		}
+	else
+		{
+		TPtrC8 versionPtr = packageElement->Content();
+		TVersion ver;
+		if (SetVersion(versionPtr, iAdmChangesInfo.iVersion) == EFalse)
+			{
+			User::Leave(EXmlErrorInvalidVersion);
+			}
+		}
+
+	// Get the ADM sis file name
+	packageElement = DomFragment->AsElement().Element(KFieldSisName);
+	if (packageElement)
+		{
+		iAdmChangesInfo.iSisName = packageElement->ContentUnicodeL();
+		}
+	else
+		{
+		User::Leave(EXmlErrorMissingSisFileName);
+		}
+
+	// URL read from ADM changes file.
+	// ADM.sis will be fetched from this url, if present. Or else default config url will be used.
+#if USE_ADMCHANGES_URL
+	// Get the optional URL
+	packageElement = DomFragment->AsElement().Element(KFieldUrl);
+	if (packageElement)
+		{
+		TPtrC8 urlPtr = packageElement->Content();
+		iAdmChangesInfo.iUrl = urlPtr.AllocL();
+		}
+#endif
+
+	CleanupStack::PopAndDestroy( DomFragment );
+	CleanupStack::PopAndDestroy( XmlReader );
+
+	// Delete no longer required changes file
+	DeleteFile(*iDownloadFileName);
+
+	LOG( "- ParseFile()" );
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::StateInstallAdmL
+// Enter in case EBSStateInstallAdm
+//
+// Silent Install the given sis file. This is asynchronous and the next state transition happens only in the handle function.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::StateInstallAdmL()
+	{
+	LOG( "+ InstallPackage()" );
+	SwiUI::TInstallOptions Options;
+
+	Options.iUpgrade = SwiUI::EPolicyAllowed;
+	Options.iOCSP    = SwiUI::EPolicyNotAllowed;
+	Options.iDrive   = 'c';
+	Options.iUntrusted = SwiUI::EPolicyNotAllowed;
+	Options.iCapabilities = SwiUI::EPolicyNotAllowed;
+	Options.iOverwrite = SwiUI::EPolicyAllowed;
+
+	iOptionsPckg = Options;
+
+	if (iInstallObsrv == NULL)
+		{
+		iInstallObsrv = new (ELeave) CInstallObserver(this);
+		}
+	iInstallObsrv->iStatus = KRequestPending;
+	iInstallObsrv->Start();
+	// Start asynchronous installation
+	iLauncher.SilentInstall(iInstallObsrv->iStatus, *iDownloadFileName, iOptionsPckg);
+
+	LOG( "- InstallPackage()" );
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::StateLaunchAdmL
+// Enter in case EBSStateLaunchAdm
+//
+// Launch ADM. A few command line args are passed and this depends on the bootstrap version.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::StateLaunchAdmL()
+	{
+	LOG( "+ LaunchAdm()" );
+
+	TUint32 protocolVer = KBootstrapAdmProtocolVersion;
+	TUint32 launchCtrl = 0;
+
+	// Command line arguments, version 15 specification:
+	//
+	//31               9  8  7  6  5  4  3  2  1  0
+	// +-------------+--+--+--+--+--+--+--+--+--+--+
+	// | reserved    |  |  |  |  |  |  |           |
+	// +-------------+--+--+--+--+--+--+--+--+--+--+
+	//
+	//      value
+	// bits range description
+	//  0-3  0-15 Command line parameter protocol version:
+	//             0 = not supported
+	//             1 = ADM.exe 1 <wrapper_uid> <iap> <depfile> <sisfile>
+	//             2 = ADM.exe 2 <wrapper_uid> <iap> <depfile> <sisfile>
+	//             3 = ADM.exe 3 <wrapper_uid> <iap> <depfile>
+	//             4 = ADM.exe 4 <wrapper_uid> <iap> <sisfile> (this was used in beta1, beta2)
+	//            15 = ADM.exe 15 [parameters as specified by other bits]
+	//
+	//         since
+	//  bit  version type command line parameter present
+	//    4      4     N  Bootstrap version number
+	//    5      4     N  Wrapper UID
+	//    6      4     N  IAP
+	//    7      4     N  ADM launch condition code:
+	//                    KCmdLineCancelAdm: ADM needs to cancel installation
+	//                    KCmdLineLaunchAdm: ADM starts normally
+	//    8      4     S  Full path to dependency XML file
+	//    9      4     S  Full path to application SIS file
+	//
+	// Types:
+	//  N  Natural decimal number (range 0 - 2^32-1, fits to TUint32)
+	//  S  UTF-8 string, must NOT contains spaces or other whitespaces
+	//
+	// Command line parameters appear in the order of the bits set, i.e.
+	// if bits 4, 8, 9 are set the command line parameters are:
+	// ADM.exe 784 <bootstrap_version> <dep_file> <sis_file>
+	//
+	// If command line protocol version is less than 15, it is assumed that
+	// old version command line parameter format is used.
+	//
+
+	// In case of approach 3 , cleanup of only BootStrap
+	// is required.
+	if (KBootstrapVersion == 3)
+		{
+		iWrapperPackageUid = KUidBootstrapApp.iUid;
+		}
+
+	// Set the launchCtrl based on Bootstrap Failure/Success
+	if ( iBootstrapFailed )
+		{
+		if (iSisFilename)
+			{
+			// SisFile exists -> resuming is possible
+			launchCtrl = KCmdLineCancelAdm;
+			}
+		else
+			{
+			launchCtrl = KCmdLineCancelAdmNoResume;
+			}
+		}
+	else
+		{
+		launchCtrl = KCmdLineLaunchAdm;
+		}
+
+	LOG2( "LaunchCtrl: %d", launchCtrl );
+
+	// By default, set the following bits:
+	// 1. BootstrapVersion,
+	// 2. WrapperUid
+	// 3. Launchctrl
+	// 4. IAP (If not set, the value is 0)
+	protocolVer |= (KCmdLineBitBootstrapVersion | KCmdLineBitWrapperUid)
+			| KCmdLineBitADMLaunchControl
+			| KCmdLineBitIAP;
+
+	// Set the mandatory command line parameters
+	//
+	// Size of 32-bit Bootstrap Version Value is 10 characters
+	// Size of 32-bit UID when converted to numeric string is 10 characters (4294967295)
+	// Size of 32-bit iIAP (TUint32) when converted to numeric string is 10 characters
+	// Size of 2 spaces is 2 characters
+	if ( (launchCtrl == KCmdLineCancelAdm) || (launchCtrl == KCmdLineLaunchAdm) )
+		{
+		switch (KBootstrapVersion)
+			{
+			case 1:
+			case 2:
+				{
+				User::LeaveIfNull(iSisFilename);
+				User::LeaveIfNull(iDepFilename);
+
+				protocolVer |= (KCmdLineBitFileSis | KCmdLineBitFileDep);
+				break;
+				}
+			case 3:
+				{
+				User::LeaveIfNull(iDepFilename);
+				protocolVer |= (KCmdLineBitFileDep);
+				break;
+				}
+			case 4:
+				{
+				User::LeaveIfNull(iSisFilename);
+				protocolVer |= (KCmdLineBitFileSis);
+				break;
+				}
+			default:
+				// Unsupported Bootstrap Version
+				User::Leave(KErrNotSupported);
+				break;
+			} // switch (KBootstrapVersion)
+		} // if ( (launchCtrl == KCmdLineCancelAdm) || (launchCtrl == KCmdLineLaunchAdm) )
+
+	// Build the command line parameter string
+	HBufC *processArgs = NULL;
+	TInt processArgsLen = 11; // obligatory protocol version number and ' '
+	TUint32 tmp = (protocolVer & ~KCmdLineBitProtocolVerMask) >> KCmdLineProtocolVerBits;
+	for (TInt i = 0; tmp != 0 || i < sizeof(KCmdLineParamLengths); tmp >>= 1, i++)
+		{
+		if (tmp & 1)
+			{
+			processArgsLen += KCmdLineParamLengths[i];
+			}
+		}
+	if (iDepFilename)
+		processArgsLen += iDepFilename->Length()+1; // +1 comes from the appended ' '
+	if (iSisFilename)
+		processArgsLen += iSisFilename->Length();
+	LOG2( "len %d", processArgsLen );
+	processArgs = HBufC::NewLC(processArgsLen);
+	TPtr ptr = processArgs->Des();
+
+	// append the obligatory protocol version number
+	ptr.AppendNum(protocolVer);
+	ptr.Append(' ');
+
+	if (protocolVer & KCmdLineBitBootstrapVersion)
+		{
+		ptr.AppendNum(KBootstrapVersion);
+		ptr.Append(' ');
+		}
+	if (protocolVer & KCmdLineBitWrapperUid)
+		{
+		ptr.AppendNum(iWrapperPackageUid);
+		ptr.Append(' ');
+		}
+	if (protocolVer & KCmdLineBitIAP)
+		{
+		ptr.AppendNum(iIAP);
+		ptr.Append(' ');
+		}
+	if (protocolVer & KCmdLineBitADMLaunchControl)
+		{
+		ptr.AppendNum(launchCtrl);
+		ptr.Append(' ');
+		}
+	if (protocolVer & KCmdLineBitFileDep)
+		{
+		ptr.Append(*iDepFilename);
+		ptr.Append(' ');
+		}
+	if (protocolVer & KCmdLineBitFileSis)
+		{
+		ptr.Append(*iSisFilename);
+		}
+
+	// Launch ADM
+	LOG3( "Launching %S '%S'", &KAdmExePath, processArgs);
+
+	RProcess process;
+	CleanupClosePushL<RProcess>( process );
+
+	const TInt err = process.Create( KAdmExePath, processArgs->Des() );
+	if (err != KErrNone)
+		{
+		LOG2( "ADM launch failed with error: %d", err );
+		CleanupStack::PopAndDestroy( &process );
+		CleanupStack::PopAndDestroy( processArgs );
+		User::Leave(err);
+		}
+	else
+		{
+		// ADM was launched properly, set it visible in the menu grid
+		LOG( "Revealing ADM menu icon" );
+		CUtils::HideApplicationFromMenuL( KUidAdm.iUid, EFalse );
+		}
+
+// Do not lower the priority: it will cause the "OK" note to be shown
+// on faster, more recent S60 devices
+//	process.SetPriority( EPriorityBackground );
+	process.Resume();
+
+	CleanupStack::PopAndDestroy( &process );
+	CleanupStack::PopAndDestroy( processArgs );
+
+	LOG2( "- LaunchAdmL(): %d", err );
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::HandleDMgrEventL
+// Callback to handle the download manager events
+// Called in EBSStateDownloadChanges, EBSStateDownloadAdm
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::HandleDMgrEventL( RHttpDownload& aDownload, THttpDownloadEvent aEvent )
+	{
+	TInt32 glErrId = KErrNone;
+	TInt32 errId = ENoError;
+
+	// Get error IDs
+	aDownload.GetIntAttribute( EDlAttrGlobalErrorId, glErrId );
+	aDownload.GetIntAttribute( EDlAttrErrorId, errId );
+
+#ifdef DO_LOG
+	_LIT(KFmt, ", GlErrId=%6d, ErrId=%d");
+	TBuf<64> buf;
+
+	if ( ((glErrId != KErrNone) || (errId != ENoError)) && glErrId != KErrUnknown )
+		{
+		buf.AppendFormat(KFmt, glErrId, errId);
+		}
+
+	if ( ( iDownloadState != aEvent.iDownloadState ) ||
+		 ( iProgressState != aEvent.iProgressState ) )
+		{
+		iDownloadState = aEvent.iDownloadState;
+		iProgressState = aEvent.iProgressState;
+
+		LOG4( "DlSt=%5d, PrSt=%5d%S", iDownloadState, iProgressState, &buf );
+		}
+#endif
+
+	switch ( aEvent.iDownloadState )
+		{
+		case EHttpDlCreated:
+		case EHttpDlInprogress:
+			{
+			//Nothing done.
+			break;
+			}
+		case EHttpDlPaused:
+		case EHttpDlFailed:
+// These two fill fold to EHttpDlFailed. We don't want to process failure events twice.
+//		case EHttpDlNonPausableNetworkLoss:
+//		case EHttpDlMultipleMOFailed:
+			{
+			//Continue download if paused in EHttpContentTypeReceived.
+			//Pause is received even in ProgNone state!
+			if( ( aEvent.iProgressState == EHttpContentTypeReceived ) ||
+				( (aEvent.iProgressState == EHttpProgNone ) && ( errId == ENoError ) ) )
+				{
+				LOG( "Starting download" );
+				aDownload.Start();
+				break;
+				}
+			if ( ProcessDlErrors(glErrId, errId, iDownloadError) )
+				{
+				if ( (iIapArrayIndex+1) < iIapArray.Count() )
+					{
+					// Try the next IAP
+					iIapArrayIndex++;
+					LOG3( "Starting download with next IAP[%d]=%d.", iIapArrayIndex, iIapArray[iIapArrayIndex] );
+					SetIAP( iIapArray[iIapArrayIndex] );
+					aDownload.Start();
+					break;
+					}
+				else if ( (iIapArrayIndex+1) == iIapArray.Count() )
+					{
+					// We've gone through all the IAPs in the SNAP, prompt the user for an access point
+					SetIAP( 0 );
+					// This ensures that this code path is taken only once
+					iIapArrayIndex++;
+					}
+				if (++iConnectionAttempt < KDownloadConnectionRetries)
+					{
+					LOG4( "Restarting download due to network failure (%d: %d, %d)", iConnectionAttempt, glErrId, errId );
+					// TODO: Do we need to do a Reset() before Start()?
+					aDownload.Start();
+					// We don't restart the download timer on purpose
+					//
+					// Clear the error id so it doesn't get caught below
+					// as this is not an error situation.
+					iDownloadError = EDlErrNoError;
+					}
+				else
+					{
+					LOG4( "Too many download retries, cancelling download (%d; %d, %d)", iDownloadError, glErrId, errId );
+					// iDownloadError has been set properly by ProcessDlErrors()
+					}
+				}
+			if ( iDownloadError != EDlErrNoError )
+				{
+				LOG2( "DlErr=%d", iDownloadError );
+
+				if ( iDownloadError == EDlErrCancelled )
+					{
+					HandleFailure(ETrue); // If user pressed cancel, then iIsIapCancelled is 1
+					}
+				else
+					{
+					HandleFailure(EFalse);
+					}
+				}
+			break;
+			}
+		case EHttpDlCompleted:
+			{
+			// TODO: Get the DownloadfileName??
+			iDownloadManager.GetIntAttribute( EDlMgrIap, iIAP );
+			LOG2( "IAP set to %d", iIAP );
+
+			switch (iAppState)
+				{
+				case EBSStateDownloadChanges:
+					RequestState(EBSStateParseChanges);
+					break;
+				case EBSStateDownloadAdm:
+					RequestState(EBSStateInstallAdm);
+					break;
+				default:
+					LOG2( "DlEvent from unknown state %d", iAppState );
+					// TODO: Fix the panic code
+					User::Panic(_L("SmartInst"), 42);
+					break;
+				}
+			break;
+			}
+		default:
+			{
+			break;
+			}
+		}
+	}
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool CStateMachine::ProcessDlErrors(const TInt32 aGlErrId, const TInt32 aErrId, EDownloadError& aDownloadError)
+	{
+	LOG4( "+ ProcessDlErrors(%d, %d, %d)", aGlErrId, aErrId, aDownloadError );
+	TBool requestRestart = EFalse;
+	const TUint count = iIapArray.Count();
+	// Process the error codes
+	switch (aErrId)
+		{
+		case KErrNone:
+			// everything a-OK!
+			break;
+		case EConnectionFailed:
+			// Request restart, if we haven't exhausted all the IAPs on the list.
+			if (count > 0 && iIapArrayIndex < count)
+				{
+				requestRestart = ETrue;
+				goto exit;
+				}
+			else
+				{
+				aDownloadError = EDlErrDownloadFailure;
+				}
+			break;
+		case ETransactionFailed:
+			// We set the download error to network failure as that's the
+			// error propagated to TState::DownloadFailed().
+			// The state machine will try to restart the download, if the
+			// error code is EDlErrDownloadFailure, but NOT for EDlErrNetworkFailure.
+			aDownloadError = EDlErrDownloadFailure;
+			requestRestart = ETrue;
+			break;
+		case EObjectNotFound:
+			aDownloadError = EDlErrFileNotFound;
+			break;
+		default:
+			LOG2( "Unhandled ErrId %d", aErrId );
+			aDownloadError = EDlErrDownloadFailure;
+			break;
+		}
+	// Process the global error code
+	switch (aGlErrId)
+		{
+		case KErrNone:
+			// everything a-OK!
+			break;
+		case KErrCancel:
+		case KErrAbort:
+			// The user has cancelled the download / IAP selection box
+			aDownloadError = EDlErrCancelled;
+			break;
+		case KErrDiskFull:
+			// Disk full
+			aDownloadError = EDlErrNotEnoughSpace;
+			break;
+		case KErrUnknown:
+			{
+			if( aErrId == KErrNone )
+				{
+				aDownloadError = EDlErrDownloadFailure;
+				requestRestart = ETrue;
+				}
+			}
+			break;
+		case KErrNotFound:
+		case KErrBadName:
+		case KErrNotSupported:
+		case KErrCommsLineFail:
+		case KErrTimedOut:
+		case KErrCouldNotConnect:
+		case KErrDisconnected:
+		case KErrGprsServicesNotAllowed:
+		case KErrGsmMMNetworkFailure:
+		case -8268: // KErrGsmOfflineOpNotAllowed:
+		// WLAN network related errors:
+		case KErrWlanNetworkNotFound:
+		case KErrWlanRoamingFailed:
+		case KErrWlanNetworkLost:
+#if 0
+		case KErrBadName:
+		case KErrNotSupported:
+		case KErrWlanOpenAuthFailed:
+		case KErrWlanSharedKeyAuthRequired:
+		case KErrWlanSharedKeyAuthFailed:
+		case KErrWlanWpaAuthRequired:
+		case KErrWlanIllegalEncryptionKeys:
+		case KErrWlanPskModeRequired:
+		case KErrWlanEapModeRequired:
+		case KErrWlanSimNotInstalled:
+		case KErrWlanNotSubscribed:
+		case KErrWlanAccessBarred:
+		case KErrWlanPasswordExpired:
+		case KErrWlanNoDialinPermissions:
+		case KErrWlanAccountDisabled:
+		case KErrWlanRestrictedLogonHours:
+		case KErrWlanServerCertificateExpired:
+		case KErrWlanCerficateVerifyFailed:
+		case KErrWlanNoUserCertificate:
+		case KErrWlanNoCipherSuite:
+		case KErrWlanUserRejected:
+		case KErrWlanUserCertificateExpired:
+		// less fatal, but still needs to fail the download:
+		case KErrWlanWpaAuthFailed:
+		case KErrWlan802dot1xAuthFailed:
+		case KErrWlanIllegalWpaPskKey:
+		case KErrWlanEapSimFailed:
+		case KErrWlanEapTlsFailed:
+		case KErrWlanEapPeapFailed:
+		case KErrWlanEapMsChapv2:
+		case KErrWlanEapAkaFailed:
+		case KErrWlanEapTtlsFailed:
+		case KErrWlanLeapFailed:
+		case KErrWlanEapGtcFailed:
+#endif
+			// A fatal network error has occured, don't retry the download
+			requestRestart = EFalse;
+			aDownloadError = EDlErrNetworkFailure;
+			break;
+		default:
+			if (!requestRestart)
+				{
+				// We assume all the other error codes to be 'hard' network errors
+				LOG2( "Unhandled GlErrId %d", aGlErrId );
+				aDownloadError = EDlErrNetworkFailure;
+				}
+			break;
+		}
+exit:
+	LOG3( "- ProcessDlErrors(): %d, %d", requestRestart, aDownloadError );
+	return requestRestart;
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::HandleInstallCompleteL
+// Callback to handle the Installation events
+// Called in EBSStateInstallAdm
+//
+// If SWI is busy, re attempt installation 6 times
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::HandleInstallCompleteL(const TInt& aStatus)
+	{
+	LOG2("+ HandleInstallCompleteL(%d)", aStatus);
+	TBool retrying = EFalse;
+
+	User::LeaveIfNull(iDownloadFileName);
+
+	// If the install server is busy , try connecting multiple times.
+	if ( (aStatus == SwiUI::KSWInstErrBusy ||
+			aStatus == KErrInUse ||
+			aStatus == KErrServerBusy)
+			&& ((++iInstallAttempt) <= KMaxInstallerConnectionAttempts))
+		{
+		LOG3( "Installer busy (%d), requesting retry (%d)", iInstallAttempt, aStatus );
+		retrying = ETrue;
+		User::After(KIterationTimer * iInstallAttempt);
+		RequestState(EBSStateInstallAdm);
+		}
+
+	if (aStatus == KErrNone)
+		{
+		LOG( "ADM installed OK, deleting SIS." );
+		// Delete no longer required sis file.
+		DeleteFile(*iDownloadFileName);
+		// ADM was installed succesfully, launch it!
+		RequestState(EBSStateLaunchAdm);
+		}
+	else if (!retrying)
+		{
+		LOG3( "Installation unsuccessful (%d) after %d attempts, leaving.", aStatus, iInstallAttempt );
+		// TODO: Better error handling
+		User::Leave(aStatus);
+		}
+
+	LOG("- HandleInstallCompleteL()");
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::IsPackagePresentL
+// Check whether the given Package (uid & version) is already present in the device.
+// Called in EBSStateInit to check for ADM Presence
+// ---------------------------------------------------------------------------
+//
+TBool CStateMachine::IsPackagePresentL(const TUid& aUid, TVersion& aVersion)
+	{
+	LOG( "+ ADMPresent()");
+
+	// Connect to SisRegistry to find if the package is
+	// already installed.
+	Swi::RSisRegistrySession registrySession;
+
+	User::LeaveIfError(registrySession.Connect());
+	CleanupClosePushL(registrySession);
+
+	const TBool isPkgInstalled = registrySession.IsInstalledL(aUid);
+
+	if (isPkgInstalled)
+		{
+		Swi::RSisRegistryEntry entry;
+
+		// Open registry entry
+		User::LeaveIfError(entry.Open(registrySession, aUid));
+		CleanupClosePushL(entry);
+		aVersion = entry.VersionL();
+
+		CleanupStack::PopAndDestroy(&entry);
+		}
+
+	CleanupStack::PopAndDestroy(&registrySession);
+
+	LOG3( "- ADMPresent(): 0x%x = %d", aUid.iUid, isPkgInstalled );
+
+	return isPkgInstalled;
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::DeleteFile
+// Delete the given file
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::DeleteFile(const TDesC& aFileName)
+	{
+	CCoeEnv::Static()->FsSession().Delete(aFileName);
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::HandleWaitNoteCancel
+// Call HandleFailure.
+// ---------------------------------------------------------------------------
+//
+//TODO: Can this be removed and call HandleFailure() directly?
+void CStateMachine::HandleWaitNoteCancel()
+	{
+	HandleFailure(ETrue);
+	}
+
+// ---------------------------------------------------------------------------
+// CStateMachine::HandleFailure
+// Perform the state specific cleanup incase of failure.
+// And then call AppUi Exit.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::HandleFailure(TInt aError)
+	{
+	LOG2( "+ HandleFailure(): %d", aError );
+
+	switch (iAppState)
+		{
+		case EBSStateInit:
+		case EBSStateSetup:
+		case EBSStateLaunchAdm:
+			// No cleanUp required here
+			break;
+		case EBSStateDownloadChanges:
+		case EBSStateDownloadAdm:
+			// Deletion of all downloads is taken care in destructor
+			break;
+		case EBSStateInstallAdm:
+			// Cancel the installation
+			iLauncher.CancelAsyncRequest(SwiUI::ERequestSilentInstall);
+			// fall-through
+		case EBSStateParseChanges:
+			{
+			// Delete the downloaded dep file
+			if (iDownloadFileName)
+				{
+				DeleteFile(*iDownloadFileName);
+				}
+			}
+			break;
+		default:
+			break;
+		}
+
+	// Even in case of any failure, launch ADM, if present in device.
+	// ADM needs to be launched in Cancel mode.
+	if( (iAppState < EBSStateLaunchAdm) && iIsAdmInstalled )
+		{
+		// If it is user press cancel or Filenames are itself not set, then remove the whole wrapper package.
+		// TODO: Should the failure reason be passed to ADM?
+		// TODO: or show the error note in bootstrap, but launch ADM to remove the wrapper?
+		if ( aError || ( iAppState <= EBSStateSetup) )
+			{
+			// No need to delete the files here, as the whole package will get removed.
+			iBootstrapFailed = ETrue;
+			}
+		RequestState(EBSStateLaunchAdm);
+		}
+	else
+		{
+		// Delete the dep file is present
+		if ( (KBootstrapVersion == 3) && iDepFilename )
+			{
+			DeleteFile(*iDepFilename);
+			}
+		else if ( (KBootstrapVersion == 4) && iSisFilename )
+			{
+			DeleteFile(*iSisFilename);
+			}
+
+		// Set the Error ID based on App State and User Cancel.
+		if( aError || ((iAppState != EBSStateDownloadChanges) && (iAppState != EBSStateDownloadAdm)) )
+			{
+			iAppUi.SetErrorId(EInstallationFailed);
+			}
+		else
+			{
+			iAppUi.SetErrorId(EDownloadFailed);
+			}
+
+		// Now call App Exit to display the error note and exit bootstrap.
+		RequestState(EBSStateExitWithError);
+		}
+
+	LOG( "- HandleFailure()" );
+	}
+
+#ifdef FEATURE_BOOTSTRAP_SETIAP
+// ---------------------------------------------------------------------------
+// Sets the used internet access point (IAP) to same that the Browser uses
+// with additional verification that the selected IAP actually exist.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::SetIAP(const TUint aIAP)
+	{
+	LOG2( "+ SetDlMgrIAP(): %d", aIAP );
+	iIAP = aIAP;
+	// Set the download manager to silent mode, if the IAP is valid
+	iDownloadManager.SetBoolAttribute( EDlMgrSilentMode, aIAP != 0 );
+	iDownloadManager.SetIntAttribute( EDlMgrIap, iIAP );
+	}
+
+// ---------------------------------------------------------------------------
+// Sets the used internet access point (IAP) to same that the Browser uses
+// with additional verification that the selected IAP actually exist.
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::SetAndValidateIAPL()
+	{
+	LOG( "+ CBootstrapAppUi::SetAndValidateIAPL()" );
+	// Use the browser default IAP, if available
+	TInt ret;
+	TInt browserIAP, browserIAPmode, browserSNAP;
+	TRequestStatus status;
+	RConnectionMonitor connMon;
+
+	// IsIapActive() requires this
+	CleanupClosePushL(connMon);
+	connMon.ConnectL();
+
+	CRepository *repository = CRepository::NewLC( KCRUidBrowser );
+	User::LeaveIfError( repository->Get(KBrowserAccessPointSelectionMode, browserIAPmode) );
+	User::LeaveIfError( repository->Get(KBrowserDefaultAccessPoint, browserIAP) );
+	ret = repository->Get( KBrowserNGDefaultSnapId, browserSNAP );
+	CleanupStack::PopAndDestroy( repository );
+
+	LOG5( "Browser IAP = %d, mode %d, SNAP %d (%d)", browserIAP, browserIAPmode, browserSNAP, ret );
+
+	if ( OviStoreRunning() && IsIapActive(connMon, browserIAP) )
+		{
+		LOG2( "Using Ovi Store IAP %d", browserIAP );
+		browserIAPmode = EBrowserCenRepApSelModeUserDefined;
+		// browserIAP now contains the IAP ID that OviStore is using
+		}
+
+	// Get the IAP IDs for the browser SNAP, if we got the SNAP ID properly
+	if (ret == KErrNone && browserSNAP > 0)
+		{
+		GetSnapIapsL(browserSNAP);
+		}
+
+	switch (browserIAPmode)
+		{
+		case EBrowserCenRepApSelModeDestination:
+			//LOG( "Destination network ");
+			break;
+		case EBrowserCenRepApSelModeUserDefined:
+			//LOG( "User defined IAP" );
+			if (browserIAP > 0)
+				{
+				SetIAP(browserIAP);
+				break;
+				}
+			// else fall-through
+		case EBrowserCenRepApSelModeAlwaysAsk:
+		default:
+			LOG( "'Always ask'" );
+			// if browser IAP is already active: then we utilise it directly, no prompting
+			if ( IsIapActive(connMon, browserIAP) )
+				{
+				LOG2( "Connection already up (%d)", browserIAP );
+				SetIAP(browserIAP);
+				}
+			else
+				{
+				LOG( "Prompting IAP" );
+				// Set to always ask, we obey it as well
+				}
+			// need to set this, if we ended up here with default:
+			browserIAPmode = EBrowserCenRepApSelModeAlwaysAsk;
+			break;
+		}
+	// Found a proper IAP?
+	if (iIAP != 0 || browserIAPmode == EBrowserCenRepApSelModeAlwaysAsk)
+		{
+#if 0
+		TBuf<64> iapName;
+		connMon.GetStringAttribute( iIAP, 0, KIAPName, iapName, status );
+		User::WaitForRequest( status );
+		if ( status.Int() != KErrNone )
+			{
+			// Try access point name
+			connMon.GetStringAttribute( iIAP, 0, KAccessPointName, iapName, status );
+			User::WaitForRequest( status );
+			if ( status.Int() != KErrNone )
+				{
+				LOG2( "ConnMon.GetStrAttr() ret = %d, ignoring.", status.Int() );
+				}
+			}
+		LOG3( "Using IAP %d ('%S')", iIAP, &iapName );
+#else
+		//LOG2( "Using IAP %d", iIAP );
+#endif
+		}
+	else
+		{
+		// set the IAP from SNAP, if it's valid
+		if (iIapArray.Count() > 0 && iIapArray[0] > 0)
+			{
+			LOG2( "Starting with IAP %d", iIapArray[0] );
+			SetIAP(iIapArray[0]);
+			}
+		}
+
+	CleanupStack::PopAndDestroy( &connMon );
+	LOG3( "- CBootstrapAppUi::SetAndValidateIAPL(): %d, %d", ret, iIAP );
+	}
+
+// ---------------------------------------------------------------------------
+// Get the default IAP for the selected SNAP. SNAP is available since 3.2
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::GetSnapIapsL(const TUint aSNAPId)
+	{
+	// Load the helper library dynamically
+	_LIT(KLibHelper, "smartinstaller.dll");
+	LOG( "Loading helper" );
+	RLibrary lib;
+	const TInt ret = lib.Load( KLibHelper() );
+	if (ret == KErrNone)
+		{
+		CleanupClosePushL(lib);
+		const TInt KHelperNewLC = 2;
+		CHelper* helper = (CHelper*)lib.Lookup(KHelperNewLC)();
+		TRAPD(ret, helper->GetSnapIapsL(aSNAPId, iIapArray) );
+		LOG3( "Got %d IAPs (%d)", iIapArray.Count(), ret );
+#ifdef DO_LOG
+		for (TInt i = 0; i < iIapArray.Count(); i++)
+			{
+			LOG3( "IAP[%d]=%d", i, iIapArray[i] );
+			}
+#endif
+		CleanupStack::PopAndDestroy(2, &lib); // helper, lib
+		}
+	else
+		{
+		LOG2( "Helper load failed %d", ret );
+		}
+	lib.Close();
+	}
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool CStateMachine::IsIapActive(RConnectionMonitor &aConnMon, TInt& aIAP)
+	{
+	LOG2( "+ IsIapActive(): %d", aIAP );
+
+	TBool ret = EFalse;
+	// Get the connection info for each connection
+	TUint id, iapId, count, countSubConn;
+	TRequestStatus status = KRequestPending;
+
+	aConnMon.GetConnectionCount( count, status );
+	User::WaitForRequest( status );
+
+	if (status.Int() != KErrNone)
+		{
+		LOG2( "GetConnCount() failed %d.", status.Int() );
+		return ret;
+		}
+
+	LOG2( "Active connections: %d", count );
+
+	TInt oviStoreIap = KErrNotFound;
+	for ( TInt i = 1; i <= count && !ret; i++ )
+		{
+		const TInt err = aConnMon.GetConnectionInfo( i, id, countSubConn );
+		if ( err == KErrNone )
+			{
+			LOG3( "ConnID[%d] = %d" , i, id );
+			// Get the IAP Id of the connection
+			aConnMon.GetUintAttribute( id, 0, KIAPId, iapId, status );
+			User::WaitForRequest( status );
+			if ( status.Int() != KErrNone )
+				{
+				LOG2( "GetIapId failed (%d), trying next", status.Int() );
+				// try next connection
+				continue;
+				}
+			else
+				{
+				LOG2( "Active IAP = %d", iapId );
+				}
+
+			// Find the UIDs using this connection
+			TConnMonClientEnumBuf clientBuf;
+			aConnMon.GetPckgAttribute( id, 0, KClientInfo, clientBuf, status );
+			User::WaitForRequest( status );
+			if ( status.Int() == KErrNone )
+				{
+				//LOG3( "%d clients sharing IAP %d", clientBuf().iCount, iapId );
+				for (TUint client = 0; client < clientBuf().iCount; client++)
+					{
+					//LOG2( "0x%08X", clientBuf().iUid[client].iUid );
+					const TInt KUidSecureWidgetUi = 0x102829A0;
+					if ( clientBuf().iUid[client].iUid == KUidSecureWidgetUi
+							&& OviStoreRunning() )
+						{
+						if (oviStoreIap == KErrNotFound)
+							{
+							//LOG2( "Possible OviStore IAP %d", iapId );
+							oviStoreIap = iapId;
+							}
+						else
+							{
+							// Another secure widget is running, we cannot determine
+							// which one is ovi store, default to browser IAP
+							oviStoreIap = 0;
+							}
+						}
+					}
+				}
+			else
+				{
+				LOG2( "GetClientInfo failed (%d)", status.Int() );
+				}
+			// ignore any errors in KClientInfo query
+
+			// If we found Ovi Store IAP, use that
+			if (oviStoreIap > 0)
+				{
+				LOG2( "Sharing Ovi Store IAP %d", oviStoreIap );
+				iapId = oviStoreIap;
+				}
+
+			if ( iIapArray.Count() > 0 )
+				{
+				// Go through all the SNAP's IAPs
+				for (TInt iap = 0; iap < iIapArray.Count(); iap++)
+					{
+					if ( iapId == iIapArray[iap] )
+						{
+						LOG3( "Using %d (SNAP idx %d)", iapId, iap );
+						// Update the IAP to match the found one
+						aIAP = iapId;
+						ret = ETrue;
+						break;
+						}
+					}
+				}
+			else if ( iapId == aIAP )
+				{
+				LOG2( "Using %d", iapId );
+				ret = ETrue;
+				// we found matching IAP ID, break out of the loop
+				break;
+				}
+			}
+		else
+			{
+			LOG3( "GetConnInfo[%d] failed (%d), trying next", i, err );
+			// try next connection
+			}
+		} // for
+#if 0
+	// If we didn't have any connections up, try to find the last used browser
+	// IAP from the SNAP and use that:
+	if (!ret && count == 0 && iIapArray.Count() > 0 )
+		{
+		// Go through all the SNAP's IAPs
+		for (TInt iap = 0; iap < iIapArray.Count(); iap++)
+			{
+			if ( iapId == iIapArray[iap] )
+				{
+				LOG3( "Using %d (SNAP idx %d)", iapId, iap );
+				// Update the IAP to match the found one
+				aIAP = iapId;
+				ret = ETrue;
+				break;
+				}
+			}
+		}
+#endif
+	LOG3( "- IsIapActive(): %d = %d", aIAP, ret );
+
+	return ret;
+	}
+#endif // FEATURE_BOOTSTRAP_SETIAP