/*
* 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(®istrySession);
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(®istrySession);
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