/*
* Copyright (c) 2004-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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: 
* Definition of the CInstallationPlanner
*
*/


/**
 @file
*/

#include "siscontroller.h"
#include "sisstring.h"
#include "sisinstallationresult.h"
#include "sissupportedlanguages.h"
#include "sislanguage.h"
#include "installationplanner.h"
#include "plan.h" 
#include "application.h"
#include "userselections.h"
#include "siscontentprovider.h"
#include "sishelperclient.h"
#include "securitypolicy.h"
#include "secutils.h"

#include <swi/msisuihandlers.h>

#include "sisinstallblock.h"
#include "sisproperties.h"
#include "sisproperty.h"
#include "siselseif.h"
#include "sisinfo.h"
#include "sisuid.h"

#include "sisuihandler.h"

#include "expressionevaluator.h"

#include "log.h"

#include "sisregistrywritableentry.h"
#include "sisregistrysession.h"
#include "sisregistrypackage.h"
#include "sisregistryfiledescription.h"
#include "sisregistrywritablesession.h"

#include "sisinstallerrors.h"
#include "cleanuputils.h"

#include "securitycheckutil.h"
#include "sistruststatus.h"
#include "securitypolicy.h"
#include "certchainconstraints.h"

#include "sisregistryserverconst.h"
#include "dessisdataprovider.h"
#include "adornedutilities.h"

using namespace Swi;
using namespace Swi::Sis;

_LIT(KSysBin, "\\sys\\bin\\");
_LIT(KPluginPath, "\\resource\\plugins\\");

CInstallationPlanner* CInstallationPlanner::NewL(RSisHelper& aSisHelper,
	RUiHandler& aInstallerUI, const CContentProvider& aContentProvider, 
	CInstallationResult& aInstallationResult)
	{
	CInstallationPlanner* self = CInstallationPlanner::NewLC(aSisHelper,
		aInstallerUI, aContentProvider, aInstallationResult);
	CleanupStack::Pop(self);
	return self;
	}

CInstallationPlanner* CInstallationPlanner::NewLC(RSisHelper& aSisHelper,
	RUiHandler& aInstallerUI, const CContentProvider& aContentProvider,
	CInstallationResult& aInstallationResult)
	{
	CInstallationPlanner* self = new (ELeave) CInstallationPlanner(aSisHelper,
		aInstallerUI, aContentProvider, aInstallationResult);
	CleanupStack::PushL(self);
	self->ConstructL(); 
	return self;
	}

CInstallationPlanner::~CInstallationPlanner()
	{
	iControllersToProcess.Close();
	delete iMainApplication;
	
	delete iExpressionEnvironment;
	delete iExpressionEvaluator;
	iPackagesToBeProcessed.ResetAndDestroy();
	iPackagesProcessed.Close();
	iEclipsableRomFiles.ResetAndDestroy();
	iOverwriteableFiles.ResetAndDestroy();
	iEclipsableOverwriteFiles.Close();
	iFilesFromPlannedControllers.ResetAndDestroy();
	iDrives.Close();
	iDriveSpaces.Close();
	}


CInstallationPlanner::CInstallationPlanner(RSisHelper& aSisHelper,
	RUiHandler& aInstallerUI, const CContentProvider& aContentProvider, 
	CInstallationResult& aInstallationResult) 
	: CPlanner(aInstallerUI, aInstallationResult) ,iSisHelper(aSisHelper), 
	  iContentProvider(aContentProvider), iStubFirstDriveLetter(KNoDriveSelected)
	{
	}

void CInstallationPlanner::ConstructL()
	{
	CPlanner::ConstructL();

	// Setup the application info to the default, until the user selects a language.
	Plan().SetAppInfoL(iContentProvider.DefaultLanguageAppInfoL());	
	
	// Add the main controller as the first in the list of controllers
	iControllersToProcess.AppendL(TControllerAndParentApplication(iContentProvider.Controller(), NULL));
	
	// Find out how much space is available on each drive before
	// installation commences. That way we can keep avaialble space
	// up to date as we plan embedded application installations
	iSisHelper.FillDrivesAndSpacesL(iDrives, iDriveSpaces);
	}

void CInstallationPlanner::FinalisePlanL(void)
	{
	// Transfer ownership of the main application
	Plan().SetApplication(iMainApplication);
	iMainApplication = NULL;
	ProcessRemainingPackagesL();
	// Note that the UninstallationPlanner informs the UI of the final progress
	// bar value here - this needs to be done after post-requisite checks for
	// an installation, since orphans to be overwritten will be planned for
	// removal in the post-requisite checks.
	}

void CInstallationPlanner::ChooseOptionsDialogL(CContentProvider& aContent, CApplication& aApplication)
	{
	TAppInfo info = aContent.LocalizedAppInfoL(iDisplayLanguageIndex);
	RPointerArray<TDesC> optionNames = aContent.LocalizedOptionsL(iDisplayLanguageIndex);
	RArray<TBool> optionSelections;

	CleanupClosePushL(optionNames);
	CleanupClosePushL(optionSelections);
	
	if (optionNames.Count() > 0)
		{
		CDisplayOptions* optionsCmd = CDisplayOptions::NewLC(info, optionNames, optionSelections);

		UiHandler().ExecuteL(*optionsCmd);
		TBool result = optionsCmd->ReturnResult();
		CleanupStack::PopAndDestroy(optionsCmd);

	    if (!result) // User pressed cancel
			{
			AbortL();
			}
			
		aApplication.UserSelections().SetOptionsL(optionSelections);		
		}
	CleanupStack::PopAndDestroy(2, &optionNames); //&optionSelections
	}

void CInstallationPlanner::ChooseDriveDialogL(CContentProvider& aContent, CApplication& aApplication, const TInt64  &aSize)
	{
	TAppInfo info = aContent.LocalizedAppInfoL(iDisplayLanguageIndex);

	TInt selectedDrive=0;	
		
	// Only call the dialog if there is more than one drive to choose from
	if (iDrives.Count() > 1)
		{
		CDisplayDrive* driveCmd = CDisplayDrive::NewLC(info, aSize, iDrives, iDriveSpaces);

		UiHandler().ExecuteL(*driveCmd);
		selectedDrive = driveCmd->ReturnResult();
		CleanupStack::PopAndDestroy(driveCmd);

		if ((selectedDrive < 0)||(selectedDrive >= iDrives.Count()))
			{
			// UI returned an out of bound index, abort installation please...
			AbortL();
			}

		aApplication.UserSelections().SetDrive(iDrives[selectedDrive]);
		}
	else 
		{
		// Only one drive, select it automatically.
		aApplication.UserSelections().SetDrive(iDrives[0]);
		}
	}

void CInstallationPlanner::ReclaimUninstallSpaceL(const CApplication& aApplication)
	{
	// Search through the files to remove and add the space saved
	// back to the free space on given drives.
	for(TInt i = 0; i < aApplication.FilesToRemove().Count(); i++)
		{
		CSisRegistryFileDescription& fileDescription = *aApplication.FilesToRemove()[i];
		TChar drive(fileDescription.Target()[0]);
		drive.UpperCase();
		TInt index = iDrives.Find(drive);
		if(index >= 0)
			{
			iDriveSpaces[index] += fileDescription.UncompressedLength();
			}
		}
	}


void CInstallationPlanner::ChooseLanguageDialogL(CContentProvider& aContent, CApplication& aApplication) 
	{
	if(aContent.AvailableLanguages().Count() > 1)
		{
		// Since we do not know the language to use yet, we use the default!
		TAppInfo info = aContent.DefaultLanguageAppInfoL();

		CDisplayLanguage* langCmd = CDisplayLanguage::NewLC(info, aContent.AvailableLanguages());
		UiHandler().ExecuteL(*langCmd);
		iDisplayLanguageIndex = langCmd->ReturnResult();

		CleanupStack::PopAndDestroy(langCmd);

		if((iDisplayLanguageIndex < 0) || (iDisplayLanguageIndex >= aContent.AvailableLanguages().Count()))
			{
			// UI returned an out of bound index, abort installation please...
			AbortL();
			}
		}
	else
		{
		// Only one language availble, no point asking the user to select it
		iDisplayLanguageIndex = 0;
		}
	aApplication.UserSelections().SetLanguage(aContent.AvailableLanguages()[iDisplayLanguageIndex]);
	//if it's the top level controller store the appinfo for this language in the plan
	if (iContentProvider.Controller().Info().Uid().Uid() == aContent.Controller().Info().Uid().Uid())
		{
		Plan().SetAppInfoL(aContent.LocalizedAppInfoL(iDisplayLanguageIndex));
		}
	}

TLanguage CInstallationPlanner::DisplayLanguage() const
	{
	return (iContentProvider.AvailableLanguages()[iDisplayLanguageIndex]);
	}

	
void CInstallationPlanner::DisplayUpgradeDialogL(const TAppInfo& aCurrentAppInfo, RSisRegistryEntry& aUpgradedApp)
	{
	HBufC* name=aUpgradedApp.PackageNameL();
	CleanupStack::PushL(name);
	HBufC* vendorName=aUpgradedApp.LocalizedVendorNameL();
	CleanupStack::PushL(vendorName);
	TVersion version=aUpgradedApp.VersionL();
	TAppInfo upgradedAppInfo(*name, *vendorName, version);

	CDisplayUpgrade* displayUpgrade=CDisplayUpgrade::NewLC(aCurrentAppInfo, upgradedAppInfo);
	UiHandler().ExecuteL(*displayUpgrade);
	if (!displayUpgrade->ReturnResult())
		{
		User::Leave(KErrCancel); // Installation cancelled
		}
	CleanupStack::PopAndDestroy(3, name);
	}

/// Functions for keeping track of packages which need to be processed

void CInstallationPlanner::NotePackageForProcessingL(CSisRegistryPackage& aPackage, CApplication& aApplication)
	{
	CPackageApplicationPair* processed=CPackageApplicationPair::NewLC(aPackage, aApplication);
	User::LeaveIfError(iPackagesToBeProcessed.Append(processed));
	CleanupStack::Pop(processed);
	}

void CInstallationPlanner::NotePackageProcessedL(TUid aUid)
	{
	// Add pacakge to processed list
	iPackagesProcessed.AppendL(aUid);
	
	// Remove package with UID=aUid
	for (TInt i=0; i < iPackagesToBeProcessed.Count(); ++i)
		{
		if (iPackagesToBeProcessed[i]->Package().Uid()==aUid)
			{
			CPackageApplicationPair* pair=iPackagesToBeProcessed[i];
			iPackagesToBeProcessed.Remove(i);
			delete pair;
			break;
			}
		}
	}

TBool CInstallationPlanner::IsPackageProcessed(TUid aUid) const
	{
	for (TInt i=0; i < iPackagesProcessed.Count(); ++i)
		{
		if (aUid == iPackagesProcessed[i])
			{
			return ETrue;
			}
		}
	return EFalse;
	}

void CInstallationPlanner::ProcessRemainingPackagesL()
	{
	// The packages remaining on the list need to be uninstalled, since they were present
	// on the device as an embedded package, but weren't present in the new install 
	// Also check that nothing depends on this before removing the package.
	for (TInt i=0; i < iPackagesToBeProcessed.Count(); ++i)
		{
		CApplication* application=UninstallPackageL(iPackagesToBeProcessed[i]->Package(), EFalse);
		CleanupStack::PushL(application);
		iPackagesToBeProcessed[i]->Application().AddEmbeddedApplicationL(application);
		CleanupStack::Pop(application); // ownership has been transferred
		}
	}


TBool CInstallationPlanner::IsValidSaUpgradeL(RSisRegistryWritableEntry& aRegistryEntry, const TBool aIsSisNonRemovable, const TBool aControllerFlag)
	{
	TBool isBaseNonRemovable = !aRegistryEntry.RemovableL();
	TBool isBaseSuSigned = aRegistryEntry.IsSignedBySuCertL();
	TBool isBaseInRom = aRegistryEntry.IsInRomL();
	TBool isSameNonRemovableState = (isBaseNonRemovable == aIsSisNonRemovable);
	TBool isRuFlag = aControllerFlag & EInstFlagROMUpgrade;
	TBool isNrFlag = aControllerFlag & EInstFlagNonRemovable;
	if (iIsValidSystemUpgrade)
		{
		// SU packages can upgrade all ROM packages and non-Rom packages regardless of their state. 
		return ETrue;
		}
	else
		{
		// Non-SU packages can upgrade ROM base only if they have the RU (ROM upgrade flag) and not have the NR flag. 
		// For non-ROM packages, they cannot upgrade if and only if the base is removable and 
		// the upgrade is non-removable, or if the base is non-removable and the upgrade is removable.
		// and also cannot upgrade if Upgrade is less trusted than the base package
		return (isBaseInRom ? (isRuFlag && !isNrFlag) : (isSameNonRemovableState && !isBaseSuSigned));	
		}
	}
	
TBool CInstallationPlanner::IsValidEclipsingUpgradeL(const Sis::CController& aController, RSisRegistryWritableEntry& aRegistryEntry,  const TBool aStubExistsInRom)
	{
	TBool paInstall = aController.Info().InstallType() == Sis::EInstPreInstalledApp;
	__ASSERT_DEBUG(!paInstall, User::Leave(KErrNotSupported));
	
	if (aController.Info().Uid().Uid() != aRegistryEntry.UidL())
		{
		return EFalse;	
		}

	if (CurrentController().TrustStatus().ValidationStatus() < EValidatedToAnchor)
		{
		return EFalse;
		}
	
	TBool isBaseInRom = aRegistryEntry.IsInRomL();
	TBool saInstall = aController.Info().InstallType() == EInstInstallation;
	TBool romUpgradeFlag = aController.Info().InstallFlags() & EInstFlagROMUpgrade;
	TBool romUpgradableSA = saInstall && romUpgradeFlag;
	TBool puInstall = aController.Info().InstallType() == Sis::EInstPartialUpgrade;
	if (isBaseInRom && !saInstall)
		{
		return ETrue;
		}
	return (aStubExistsInRom && (romUpgradableSA || puInstall));			 
	}

void CInstallationPlanner::SetDeviceSupportedLanguages(RArray<TInt>& aDeviceSupportedLanguages)
	{
	iDeviceSupportedLanguages = &aDeviceSupportedLanguages;
	}

/// Processing functions

CApplication* CInstallationPlanner::ProcessControllerL(const Sis::CController& aController, TInt aCumulativeDataIndex, RPointerArray<CFileDescription>& aFilesToCapabilityCheck, TUid aParentUid)
	{	
	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	// Skip all the chances of leaving, when the planner is in info collection mode.
	if(!IsInInfoCollectionMode())
		{
	#endif
		// Check to see that we are not trying to install a protected package
		// uid with an untrusted controller
		if(aController.TrustStatus().ValidationStatus() < EValidatedToAnchor
			&& SecurityCheckUtil::IsPackageUidProtected(aController.Info().Uid().Uid().iUid))
			{
			// Can't install a protected package Uid when the controller
			// is untrusted
			DisplayErrorL(EUiUIDPackageViolation, KNullDesC);
			User::Leave(KErrSecurityError);
			}
		
		// If this package is signed by a DevCert that constraints SIDs,
		// check the pUID is not in the protected range before installing.
		// Otherwise, do not install this package, since it could be upgraded
		if ( ! aController.CertChainConstraints()->SIDIsValid( aController.Info().Uid().Uid().iUid) )
			{
			// Not allowed to install a protected package when sids are constrained
			// e.g. this can occur when a package is signed by a devcert
			DisplayErrorL(EUiConstraintsExceeded, KNullDesC);
			User::Leave(KErrSecurityError);
			}
			
	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		// If this package is set to be 'hidden' and not trusted sufficiently,
		// do not install this package. Notify the user and leave from here.
		if ( (aController.Info().InstallFlags() & EInstFlagHide) && 
			 (aController.TrustStatus().ValidationStatus() < EValidatedToAnchor))
			{
			// Can't install a hidden package signed with a untrusted certificate chain.
			DisplayErrorL(EUiConstraintsExceeded, KNullDesC);
			User::Leave(KErrSecurityError);
			}
		}
	#endif	

	NotePackageProcessedL(aController.Info().Uid().Uid());
	
	// Reset the list of file allowed to be eclipsed and overwritten for
	// every embedded controller in the package
	iEclipsableRomFiles.ResetAndDestroy();
	iOverwriteableFiles.ResetAndDestroy();
	
	CApplication* application=CApplication::NewLC();
	application->SetController(aController);
	
	// Copy the set of device languages to CApplication data member
	application->CopyDeviceSupportedLanguagesL(*iDeviceSupportedLanguages);

	application->SetSisHelper(iSisHelper);
	
	if(aController.Info().InstallFlags() & EInstFlagShutdownApps)
		{
		application->SetShutdownAllApps(ETrue);
		}

	if (iSisHelper.IsStubL())	
		{
		CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();

		if (!(iSisHelper.IsSisFileReadOnlyL()) && securityPolicy->DeletePreinstalledFilesOnUninstall())
			{
			application->SetDeletablePreinstalled(ETrue);
			}
		
		iIsStub = ETrue;
		iIsPropagated = !((aController.Info().InstallType() == EInstPreInstalledPatch) || (aController.Info().InstallType() == EInstPreInstalledApp));
		application->SetStub(iIsPropagated);
		}
	
	Sis::TInstallType type = application->ControllerL().Info().InstallType();
	Sis::TInstallFlags flag = application->ControllerL().Info().InstallFlags();
	TBool ruFlag = (flag & EInstFlagROMUpgrade);
	TBool rejectedType = ( (type == EInstPreInstalledApp  ) || (type == EInstPreInstalledPatch ));
	 
	if ( ruFlag && rejectedType && aController.IsSignedBySuCert())
		{
		// reject PA or PP with RU flag System Upgrade packages ( signed by SU cert)
		DEBUG_PRINTF(_L8("Attempt made to install/preinstall/propagate System Upgrade package with RU flag"));
		User::Leave(KErrInvalidUpgrade);
		}
	
	iIsValidSystemUpgrade = IsValidSystemUpgradeL(*application);
	
	if (iIsValidSystemUpgrade)
		{
		application->SetInstallSuCertBased();
		}

	// Check to see if there is a package installed with this UID
	RSisRegistryWritableSession registrySession;
	User::LeaveIfError(registrySession.Connect());
	CleanupClosePushL(registrySession);
	
	RSisRegistryWritableEntry registryEntry;
	TInt error=registryEntry.Open(registrySession, aController.Info().Uid().Uid());	
	CleanupClosePushL(registryEntry);
	
	TBool isSisNonRemovable = ((aController.Info().InstallFlags() & EInstFlagNonRemovable) == EInstFlagNonRemovable);

	DEBUG_PRINTF2(_L8("Planning controller of type %d for install"), aController.Info().InstallType());
	//Index from the planned controllers for the base controller of the current controller
	TInt baseControllerIndex = 0;
	
	if (error == KErrNone)
		{
		CSisRegistryPackage* package=registryEntry.PackageL();
		CleanupStack::PushL(package);
		application->SetPackageL(*package);
		CleanupStack::PopAndDestroy(package);
		
		TBool isBaseRemovable = registryEntry.RemovableL();
		
		if (aController.Info().InstallType() == EInstInstallation)
			{
			// The package is already on the device so check whether it
			// is a valid upgrade
			// Stub SIS files cannot be used to perform an upgrade.
			TBool validUpgrade = IsValidSaUpgradeL(registryEntry, isSisNonRemovable, aController.Info().InstallFlags());
			if ((iIsPropagated || !validUpgrade))
				{
				DEBUG_PRINTF(_L8("Invalid Upgrade: SA Attempted"));				
				User::Leave(KErrInvalidUpgrade);
				}
			
			application->SetUpgrade(aController);
						
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			// Display the dialog only when the planner is not in info collection mode.
			if (!IsInInfoCollectionMode())
				{			
			#endif
				//if it's the top level controller display a dialog box
				if (iContentProvider.Controller().Info().Uid().Uid() == aController.Info().Uid().Uid())
					{
					DisplayUpgradeDialogL(Plan().AppInfoL(), registryEntry);
					}			
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK					
				}
			#endif
			
				
			/**
			 * Add the embedded packages to a list of packages which are yet to be processed. 
			 * At the end of the processing of all the controllers this list is checked to 
			 * see if theres some controllers which only need to be uninstalled, and the files 
			 * to be removed are added to the plan. 
			 * However this only applies when it's not a partial upgrade.
			 */
			RPointerArray<CSisRegistryPackage> embeddedPackages;
			CleanupResetAndDestroy<RPointerArray<CSisRegistryPackage> >::PushL(embeddedPackages);
			registryEntry.EmbeddedPackagesL(embeddedPackages);

			for (TInt i=0; i < embeddedPackages.Count(); ++i)
				{
				NotePackageForProcessingL(*embeddedPackages[i], *application);
				}
			CleanupStack::PopAndDestroy(&embeddedPackages);	
				
			}
		else if (aController.Info().InstallType() == EInstAugmentation)
			{ 
			if (isBaseRemovable && isSisNonRemovable)
				{
				DEBUG_PRINTF(_L8("Invalid Upgrade: SP Attempted"));
				User::Leave(KErrInvalidUpgrade);
				}			
						
			if (iIsPropagated)
				{
				// Treat an augmentation on a removable media stub as a
				// preinstalled patch
				application->SetPreInstalledPatch(aController);
				}
			else
				{
				application->SetAugmentation(aController);
				}
			}
		else if (aController.Info().InstallType() == EInstPreInstalledPatch)
			{
			// NR patches on pre-installed media are invalid
			if (isSisNonRemovable)
			{
				DEBUG_PRINTF(_L8("Invalid Upgrade: NR patches on pre-installed media are invalid"));
				User::Leave(KErrInvalidUpgrade);
			}
			
			application->SetPreInstalledPatch(aController);
			}
		else if (aController.Info().InstallType() == EInstPartialUpgrade)
			{
			// Do not allow partial upgrades to preinstalled applications
			// BR1863.1 and BR1863.2
			if (registryEntry.PreInstalledL())
				{
				User::Leave(KErrInvalidUpgrade);
				}
				
			// Stub SIS files cannot be used to perform an upgrade
			if (iIsPropagated)
				{
				User::Leave(KErrInvalidUpgrade);
				}
			
			// Upgrade package is less trusted than the base package
			if (!iIsValidSystemUpgrade && registryEntry.IsSignedBySuCertL())
				{
				DEBUG_PRINTF(_L8("Invalid Upgrade: PU Attempted"));
				User::Leave(KErrInvalidUpgrade);
				}
			// Partial Upgrade can only be installed to a base package of the same install flag type	
			// PU cannot change the non-removable status of a base package, i.e. a non-removable package 
			// cannot replace a removable one and visa versa. The only exception is ROM stub which is upgradable 
			// and non-removable by definition.
			if ((isBaseRemovable == isSisNonRemovable) && !registryEntry.IsInRomL())
				{
				DEBUG_PRINTF(_L8("Invalid Upgrade: PU Attempted"));
				User::Leave(KErrInvalidUpgrade);
				}	
							
			application->SetPartialUpgrade(aController);
			
			// If the parent application is in ROM, set this type to
			// be a ROM application too, so eclipsing rule
			if (registryEntry.IsInRomL())
				{
				application->SetInROM();
				}
			
			}
		else if (aController.Info().InstallType() == EInstPreInstalledApp)
			{
			
			// We can't install a preinstalled app over the top of 
			// another application.
			User::Leave(KErrInvalidUpgrade);
			
			}
		
		// Preinstalled apps will have errored out by this point,
		// regular installs will have their files removed,
		// others will have the files added to the list of eclipsable ROM files
		// if they satisfy the appropriate conditions.
		PrepareEclipsableFilesListL(aController);
	
		// Check to ensure all upgrades are sufficiently 
		// trusted to upgrade the base package
		// non System Upgrade SP upgrades, to a System Upgrade Package  shall only add files.
		TBool nonSuPkgSpUpgradeoverSu = !iIsValidSystemUpgrade && application->IsAugmentation() && registryEntry.IsSignedBySuCertL();
		if (!SecurityCheckUtil::IsSufficientlyTrusted(aController, 
				registryEntry.TrustStatusL().ValidationStatus()) && !nonSuPkgSpUpgradeoverSu)
			{
			DEBUG_PRINTF(_L8("Application not sufficiently trusted to upgrade its base"));
			User::Leave(KErrInvalidUpgrade);
			}
		}
	else if (error == KErrNotFound)
		{
		// SWI cannot intall non-removable packages if the sis file not signed with the trusted certificate
		if (isSisNonRemovable && !iIsValidSystemUpgrade)
			{
			DEBUG_PRINTF(_L8("Attempt made to install NR sis file which is not trusted by device"));
			User::Leave(KErrNotSupported);			
			}
		
		if (aController.Info().InstallType() == EInstInstallation)
			{
			// The application isn't on the device so an installation can proceed
			
			if(iIsPropagated)
				{
				// Treat an installation inside a stub SIS file as a
				// Pre-Installed App
				application->SetPreInstalledApp(aController);
				}
			else
				{
				application->SetInstall(aController);
				}	
			}
		else if (aController.Info().InstallType() == EInstAugmentation)
			{
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			// Skip all the chances of leaving, when the planner is in info collection mode.
			if(!IsInInfoCollectionMode())
				{
			#endif
				//The application isn't on the device so we have to check if the base 
				//package on the planned list. can't upgrade an augmentation in the list.
				if(!IsPlannedControllerL(aController, baseControllerIndex, aParentUid) ||
					IsAugmentationUpgrade(aController))
					{									
					// we needed the base package on the device, so fail
					DisplayErrorL(EUiMissingBasePackage, KNullDesC);
					User::Leave(KErrMissingBasePackage);					
					}
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
				}
			#endif			
				
			if (iIsPropagated)
				{
				// Treat an augmentation on a removable media stub as a
				// preinstalled patch
				application->SetPreInstalledPatch(aController);
				}
			else
				{
				application->SetAugmentation(aController);
				}
			}
		else if (aController.Info().InstallType() == EInstPartialUpgrade)
			{
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			// Skip all the chances of leaving, when the planner is in info collection mode.
			if(!IsInInfoCollectionMode())
				{
			#endif
				//The application isn't on the device so we have to check if the base 
				//package on the planned list
				if(!IsPlannedControllerL(aController, baseControllerIndex, aParentUid))
					{
					// we needed the base package on the device, so fail
					DisplayErrorL(EUiMissingBasePackage, KNullDesC);
					User::Leave(KErrMissingBasePackage);
					}
				// Stub SIS files cannot be used to perform an upgrade
				if (iIsPropagated)
					{
					User::Leave(KErrInvalidUpgrade);
					}
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
				}
			#endif
			application->SetPartialUpgrade(aController);
			}
		else if (aController.Info().InstallType() == EInstPreInstalledApp)
			{
			// The application isn't on the device so an installation can precede
			application->SetPreInstalledApp(aController);
			}
		else
			{
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			if(!IsInInfoCollectionMode())
				{
			#endif
				// we needed the base package on the device, so fail
				DisplayErrorL(EUiMissingBasePackage, KNullDesC);
				User::Leave(KErrMissingBasePackage);
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
				}
			#endif				
			}
			
		if ((aController.Info().InstallType() == EInstPartialUpgrade) || (aController.Info().InstallType() == EInstAugmentation))		
			{
			TInt baseControllerNum;
			TBool trusted = EFalse;
			//Find the base controller for the current controller
			if((baseControllerNum = GetControllerReference(aController.Info().Uid().Uid())) >= 0)
				{
				if(SecurityCheckUtil::IsSufficientlyTrusted(aController, iControllersToProcess[baseControllerNum].Controller()))
					{
					trusted = ETrue;
					}
				}
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			if(!IsInInfoCollectionMode())
				{
			#endif
				if(!trusted)
					{
					DEBUG_PRINTF(_L8("Application not sufficiently trusted to upgrade its base"));
					User::Leave(KErrInvalidUpgrade);
					}
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
				}
			#endif
			}
		}
	else
		{
		User::LeaveIfError(error);
		}
	
	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	// Check whether the package content is DRM protected.
	TBool isContentDrmProtected = iSisHelper.IsDrmProtectedL();
	application->SetDrmProtected(isContentDrmProtected);	
	#endif

	// Get the user selections
	CContentProvider* content = CContentProvider::NewLC(application->ControllerL());
	
	// If the count of Device supported languages is not equal to zero, then choose the 
	// language based on the sis supported languages and device supported languages.
	if ( 0 != iDeviceSupportedLanguages->Count()) 
		{
		// Sets the following flags, 
		// a) iHasDeviceSupportdLanguages, indicates whether a SIS file contains the Device
		//	  Language token or not.
		// b) iHasMatchingLanguages, indicates whether there is an exact match(any one) between  
		//	  the languages which device supports and languages which SIS file supports.	
		SetDeviceLanguagesL(aController.InstallBlock(), *application, *content);
		
		// If a SIS file contains Supported language token and iHasMatchingLanguages is TRUE
		// then either current device language is used or the lowest language id supported by 
		// the SIS file will be used else if iHasMatchingLanguages is FALSE then proceed  
		// with user language selection dialog box displaying sis supported languages.
	
		if ( application->IsDeviceSupportedLanguages())
			{
			TInt langIndex = 0;
			if ( application->IsLanguageMatch() ) //exact match 
				{					
				TLanguage currentLanguage = User::Language();    // Language of the current locale
				TBool isExactLanguageMatch = EFalse;
				
				// Check whether the current locale is in the list of available languages
				const RArray<TInt>& matchingLanguages = application->GetMatchingDeviceLanguages();
				const RArray<TLanguage>& availableLanguages = content->AvailableLanguages();
				
				TInt index = availableLanguages.Find(currentLanguage);
				TInt currentLanguageIndex = matchingLanguages.Find(currentLanguage);
	
				if( (index != KErrNotFound && currentLanguageIndex != KErrNotFound))
					{
					langIndex = index;
					isExactLanguageMatch = ETrue;
					}
				else
					{
					TInt leastExactMatchLanguagesIndex = 0;
					for(TInt i=0 ; i< availableLanguages.Count() ; i++)
						{
						TBool isFirstMatch = ETrue;
						if((matchingLanguages.Find(availableLanguages[i])!= KErrNotFound) && ((availableLanguages[i] <= availableLanguages[leastExactMatchLanguagesIndex])||isFirstMatch))
							{
							isFirstMatch = EFalse;
							leastExactMatchLanguagesIndex = i;
							isExactLanguageMatch = ETrue;
							}
						}
					if( isExactLanguageMatch )
						{
						langIndex = leastExactMatchLanguagesIndex;
						}
					else // Intersection of Matching Languages & SIS file's Language header is NULL
						{
						#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
						// Display the dialog only when the planner is not in info collection mode.
						if (!IsInInfoCollectionMode())
							{
						#endif
							ChooseLanguageDialogL(*content, *application);
						#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK		
							}
						#endif
						}
					}
				if( isExactLanguageMatch )
					{
					application->UserSelections().SetLanguage(content->AvailableLanguages()[langIndex]);
					iDisplayLanguageIndex = langIndex;
					
					//if it's the top level controller store the appinfo for this language in the plan
					if (iContentProvider.Controller().Info().Uid().Uid() == content->Controller().Info().Uid().Uid())
						{
						Plan().SetAppInfoL(content->LocalizedAppInfoL(iDisplayLanguageIndex));
						}
					DEBUG_PRINTF2(_L8("current device Language id is  %d"), content->AvailableLanguages()[langIndex]);
					}
				}
			else // No matching language with device
				{		
				//if no exact match is there the proceed with user language selection dialog box 
				//displaying sis supported languages.
				#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
				// Display the dialog only when the planner is not in info collection mode.
				if (!IsInInfoCollectionMode())
					{
				#endif
					ChooseLanguageDialogL(*content, *application);
				#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK		
					}
				#endif
				}
			}
		else // No Supported Language Token in SIS file
			{
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			// Display the dialog only when the planner is not in info collection mode.
			if (!IsInInfoCollectionMode())
				{
			#endif
				ChooseLanguageDialogL(*content, *application);
			#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK		
				}
			#endif
			}
		
		}
	else //Device Supported Languages is zero. Hence proceed with user language selection dialog box
		{
		#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		// Display the dialog only when the planner is not in info collection mode.
		if (!IsInInfoCollectionMode())
			{
		#endif
			ChooseLanguageDialogL(*content, *application);
		#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK		
			}
		#endif
		}

	
	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	// Display the dialog only when the planner is not in info collection mode.
	if (!IsInInfoCollectionMode())
		{
	#endif
		ChooseOptionsDialogL(*content, *application);
	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK		
		}
	#endif
	
	DEBUG_PRINTF4(_L("Application for install; UID: 0x%08x, Name: %S, Vendor: %S"),
		aController.Info().Uid().Uid().iUid, &(aController.Info().Names()[iDisplayLanguageIndex]->Data()),
		&(aController.Info().UniqueVendorName().Data()));
	
	// Check if this is an augmentation upgrade
	// This must be done after the language has been selected, so that we have the localised
	// name of the package.
	if (error == KErrNone && IsAugmentationUpgradeL(aController, registryEntry, registrySession))
		{
		// We have an augmentation upgrade, check that it's OK to upgrade the previous augmentation
		if (!SecurityCheckUtil::IsSufficientlyTrusted(aController, 
				registryEntry.TrustStatusL().ValidationStatus()))
			{
			DEBUG_PRINTF(_L8("Application not sufficiently trusted to upgrade its base"));
			User::Leave(KErrInvalidUpgrade);
			}
			
		#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		// Display the dialog only when the planner is not in info collection mode.
		if (!IsInInfoCollectionMode())
			{
		#endif
			// if this is the top level controller, display the upgrade dialog.
			if (iContentProvider.Controller().Info().Uid().Uid() == aController.Info().Uid().Uid())
				{
				DisplayUpgradeDialogL(Plan().AppInfoL(), registryEntry);
				}
		#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK				
			}
		#endif
		
		// The flags now mark this package as both an upgrade _and_ an augmentation
		application->SetUpgrade(aController);
		// entry has changed so change the package in the application
		CSisRegistryPackage* package=registryEntry.PackageL();
		CleanupStack::PushL(package);
		application->SetPackageL(*package);
		CleanupStack::PopAndDestroy(package);
		}

	// add files to the plan which may need to be removed.
	if(error == KErrNone)
		{
		ProcessFilesToRemoveL(*application, registryEntry);
		}

	// Setup the evaluation environment for the user selections
	SetupExpressionEnvironmentL(*application);
	
	// If we doing any kind of upgrade we can assume the space 
	// currently used by files that will be removed will be 
	// available for use by our installation
	ReclaimUninstallSpaceL(*application);

	// Size of this controller only!!
	TInt64 size = iContentProvider.TotalSizeL(aController.InstallBlock(), iExpressionEvaluator, EFalse);

	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	// Invoke the drive selection part when the planner is not in info collection mode. Otherwise do not.
	if (IsInInfoCollectionMode())
		{
		// for GetInfo purposes we select an existing system drive. We need to make sure that a valid drive is selected for installation planning,  and in any case no files will get copied there, 
		application->UserSelections().SetDrive(iSystemDriveChar);
		}
	else
		{
	#endif
		// If the package is partial upgrade, extract drive from the registry, and dont
		// display the drive selection option except where we are upgrading a ROM stub
		if(error == KErrNone && aController.Info().InstallType() == EInstPartialUpgrade && !registryEntry.IsInRomL())
			{
			TChar drive = registryEntry.SelectedDriveL();
			if(drive == TChar(KNoDriveSelected) && IsUserDriveSelectionRequiredL(aController.InstallBlock()))
				{
				// Base package had hard coded file paths so we can't make
				// any assumptions about where to install the upgrade
				// we need to ask the user where they would like to install 
				// this upgrade
				ChooseDriveDialogL(*content, *application, size);	
				}
			else
				{
				// install partial upgrade on the same drive as base package
				application->UserSelections().SetDrive(drive);
				}
			}
		else if(error == KErrNotFound && aController.Info().InstallType() == EInstPartialUpgrade &&
				iFilesFromPlannedControllers[baseControllerIndex]->Drive() != TChar(KNoDriveSelected))
				{
				//Use the base package's drive
				application->UserSelections().SetDrive(iFilesFromPlannedControllers[baseControllerIndex]->Drive());			
				}
		else if((aController.Info().InstallType() == EInstInstallation
				|| aController.Info().InstallType() == EInstAugmentation)
				&& iIsPropagated)
			{
			// This is a removable media card stub, the files must 
			// be on the same removable drive as the stub SIS file 
			application->UserSelections().SetDrive(iSisHelper.GetSisFileDriveL());
			}
		else if(aController.Info().InstallType() == EInstPreInstalledApp
				|| aController.Info().InstallType() == EInstPreInstalledPatch)
			{
			// This is a preinstalled application or patch. Installation is
			// performed "in place" so the only drive that makes sense to
			// select is the same one that the SIS file lives in.
			// Note: PA/PP stub sis files can only install files on the same
			// drive that the sis file is located on. See DEF084248
			application->UserSelections().SetDrive(iSisHelper.GetSisFileDriveL());
			}
		else if (IsUserDriveSelectionRequiredL(aController.InstallBlock()))
			{
			// User needs to choose which drive will be used for the installation
	 		ChooseDriveDialogL(*content, *application, size);	
			}
	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		}
	#endif
	CleanupStack::PopAndDestroy(content);

	// To accurately display the space avaialble for next controller 
	// we need to subtract the space used by this controller
	TChar drive = application->UserSelections().Drive();
	if(drive != TChar(KNoDriveSelected))
		{
		TInt index = iDrives.FindL(drive);
		iDriveSpaces[index] -= size;
		}

	application->SetAbsoluteDataIndex(aCumulativeDataIndex + aController.DataIndex());
	
	CFilesFromPlannedController* filesList = CFilesFromPlannedController::NewLC(aController.Info().Uid().Uid(), aParentUid, aController.Info().InstallType(), aController.Info().Names()[0]);
	//Set the selected drive for the package being planned
	filesList->SetDrive(drive);
	
	if (aController.Logo()!= NULL)
		{
 		const CFileDescription& aFileDescription = aController.Logo()->FileDescription();
		ProcessFileDescriptionL(aFileDescription, *application, aFilesToCapabilityCheck, *filesList);
		}
			
	// Process the actual controller, then return the application
	ProcessInstallBlockL(aController.InstallBlock(), *application, aFilesToCapabilityCheck, *filesList);
	
	//Publishing the UID of the associated package.
	TUid publishUid = aController.Info().Uid().Uid();
	if(!(Swi::SecUtils::IsPackageUidPresent(publishUid, iUidList)))
	    {
	    TInt err = Swi::SecUtils::PublishPackageUid(publishUid, iUidList);
	    if(err == KErrNone)
	        {
	        DEBUG_PRINTF2(_L("CInstallationPlanner::ProcessControllerL published Uid %x."), publishUid.iUid);
	        }
	    else if(err == KErrOverflow)
	         {
	         DEBUG_PRINTF2(_L("CInstallationPlanner::ProcessControllerL failed to publish Uid %x as the array, holding the uids, exceeded its upper limit."),publishUid.iUid);
	         }
        else if(err == KErrNotFound)
             {
             DEBUG_PRINTF2(_L("CInstallationPlanner::ProcessControllerL failed to publish Uid %x as the property is not been defined."),publishUid.iUid);
             }
        else
	        {
            DEBUG_PRINTF3(_L("CInstallationPlanner::ProcessControllerL failed to publish Uid %x with error %d."),publishUid.iUid, err);
            User::Leave(err);
	        }
	    }

	//Append planned controllers list
	iFilesFromPlannedControllers.AppendL(filesList);
	CleanupStack::Pop(filesList);

	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	// Some files may need to be questioned of overwrite only when the planner is not in info collection mode.
	if (!IsInInfoCollectionMode())	
	#endif
	 //Some files may need to be questioned of overwrite
		WarnEclipseOverWriteL(*application);
 	
 	// Reset the file list array for next controller use
 	iEclipsableOverwriteFiles.Reset();

	ProcessPropertiesL(aController.Properties(), Plan(), *application);
	
	CleanupStack::PopAndDestroy(2, &registrySession); // registryEntry, registrySession

  	CleanupStack::Pop(application); 
	return application;
	}


// Prepare the eclipsable files list from the right source according to the upgrade.	
void CInstallationPlanner::PrepareEclipsableFilesListL(const Sis::CController& aController)
	{
	// If the package is allowed to install based on SU Cert rule, then no need to generate 
	// eclipsable file list, it can eclipse any files from rom	
	// before reaching this place, NR upgrade check already done for SA, SP and PU
	if (iIsValidSystemUpgrade)
		{
		return;
		}

	RSisRegistryWritableSession registrySession;
	User::LeaveIfError(registrySession.Connect());
	CleanupClosePushL(registrySession);

	RSisRegistryWritableEntry registryEntry;
	
	TInt error=registryEntry.Open(registrySession, aController.Info().Uid().Uid());		
	CleanupClosePushL(registryEntry);
	if(error != KErrNone)	
		{
		CleanupStack::PopAndDestroy(2, &registrySession);
		return;				
		}
	
	
	CSisRegistryPackage* package = registryEntry.PackageL();
	CleanupStack::PushL(package);
	TBool stubExistsInRom = registrySession.PackageExistsInRomL(package->Uid());	
	CleanupStack::PopAndDestroy(package);
	
	// Break the conditions to be checked against the package in installation.		
	TBool puInstallation = aController.Info().InstallType() == EInstPartialUpgrade;
	TBool saInstallation = aController.Info().InstallType() == EInstInstallation;
	TBool romUpgradeFlag = aController.Info().InstallFlags() & EInstFlagROMUpgrade;
	TBool romUpgradableSA = saInstallation && romUpgradeFlag;
	TBool currentPkgIsInRom = registryEntry.IsInRomL();
		
	// Standard Apps (SA) with ROM Upgrade (RU) flag,
	// Partial upgrades, patches and preinstalled patches are all
	// allowed to eclipse ROM files.					
					
	// When an upgrade happens over a upgrade which has already upgraded the 
	// ROM based package (i.e, an upgrade SA_RU_2 happens over ROM+SA_RU_1), 
	// don't populate the eclipsable files from the SIS registry entry which 
	// may be in-complete. So, directly populate the eclipsable files list from 
	// the corresponding stub SIS file.		
	if (IsValidEclipsingUpgradeL(aController, registryEntry, stubExistsInRom))
		{
		if(!currentPkgIsInRom && stubExistsInRom && (romUpgradableSA || puInstallation))
			{
			registrySession.GetFilesForRomApplicationL(aController.Info().Uid().Uid(), iEclipsableRomFiles);
			}
		// Otherwise, populate the eclipsable files list from SIS registry entry.
		else
			{
			registryEntry.FilesL(iEclipsableRomFiles);
			}
		}
		CleanupStack::PopAndDestroy(2, &registrySession);			
	}

void CInstallationPlanner::SetupExpressionEnvironmentL(const CApplication& aApplication)
	{
	delete iExpressionEnvironment;
	iExpressionEnvironment = NULL;
	
	delete iExpressionEvaluator;
	iExpressionEvaluator=NULL;
		
	iExpressionEnvironment=CSwisExpressionEnvironment::NewL(aApplication);
	iExpressionEvaluator=CExpressionEvaluator::NewL(*iExpressionEnvironment);
	}
		
// Properties
void CInstallationPlanner::ProcessPropertiesL(const Sis::CProperties& aProperties, CPlan& /*aPlan*/, CApplication& aApplication)
	{
	for (TInt i = 0 ; i < aProperties.Count(); ++i)
		{
		// Add the property to the plan
		aApplication.AddPropertyL(CApplication::TProperty(aProperties[i].Key(), aProperties[i].Value()));
		}
	}

TBool CInstallationPlanner::IsUserDriveSelectionRequiredL(const Sis::CInstallBlock& aInstallBlock) const
	{
	// process the file descriptions
	const RPointerArray<CFileDescription>& files=aInstallBlock.FileDescriptions();
  	
  	TInt i;
  	for (i = 0; i < files.Count(); ++i)
  		{
  		CFileDescription& fileDescription = *files[i];
		if (fileDescription.Target().Data().Length() != 0)
			{
			// if a target file is specified check whether the 
			// target drive is hardcoded or the wildcard "!:\"
			if(fileDescription.Target().Data()[0] == '!')
  				{
  				// Target file drive is "!:\"
  				return ETrue;
	  			}
			}
		}

	// process the expressions
	for (i = 0 ; i < aInstallBlock.IfStatements().Count(); ++i)
		{
		Sis::CIf* ifBlock=aInstallBlock.IfStatements()[i];
		
		if (!ifBlock)
			{
			User::Leave(KErrCorrupt);
			}
		if(iExpressionEvaluator->EvaluateL(ifBlock->Expression()).BoolValueL())
		   	{
		   	// If the user has select the option search the install block
		   	// for wildcards
		   	if(IsUserDriveSelectionRequiredL(ifBlock->InstallBlock()))
		   		{
		   		return ETrue;
		   		}
			}
		else
			{
			// else if blocks
			const RPointerArray<CElseIf>& elseIfs = ifBlock->ElseIfs();
		
			for (TInt j = 0 ; j < elseIfs.Count(); ++j)
				{		
				if (!elseIfs[j])
				 	{
					User::Leave(KErrCorrupt);
					}
				if(iExpressionEvaluator->EvaluateL(elseIfs[j]->Expression()).BoolValueL())
					{
					// If the user selected this option, search the installblock
					// for wildcards
					if(IsUserDriveSelectionRequiredL(elseIfs[j]->InstallBlock()))
						{
						return ETrue;
						}
					}
				}
			}
		}
	// no wildcards found, all file target drives must be hardcoded
	return EFalse;
	}

void CInstallationPlanner::SetDeviceLanguagesL(const Sis::CInstallBlock& aInstallBlock, CApplication& aApplication, const CContentProvider& aContent)
	{	
	//Setting up the expression environment which includes setting up the values for User
	//Options available in the sis file,which are used while prossesing the expression block. 
	SetupExpressionEnvironmentL(aApplication);
	RPointerArray<TDesC> optionNames = aContent.LocalizedOptionsL(iDisplayLanguageIndex);
	RArray<TBool> optionSelections;
	CleanupClosePushL(optionNames);
	CleanupClosePushL(optionSelections);
	TInt opt_len = optionNames.Count();
	TInt i = 0;
	for ( i=0; i < opt_len; i++)
		{
			optionSelections.AppendL(EFalse);
		}
	aApplication.UserSelections().SetOptionsL(optionSelections);
	CleanupStack::PopAndDestroy(2, &optionNames); //&optionSelections	
	
	TInt ifStmtCount = aInstallBlock.IfStatements().Count();
	for ( i=0 ; i < ifStmtCount; ++i)
			{
		Sis::CIf* ifBlock=aInstallBlock.IfStatements()[i];
			
			if (!ifBlock)
				{
				User::Leave(KErrCorrupt);
				}
			 iExpressionEvaluator->EvaluateL(ifBlock->Expression());						
			}
	}

// Functions to process files	
void CInstallationPlanner::ProcessInstallBlockL(const Sis::CInstallBlock& aInstallBlock, CApplication& aApplication, RPointerArray<CFileDescription>& aFilesToCapabilityCheck, CFilesFromPlannedController& aPlannedFiles)
	{
	// process the file descriptions
	const RPointerArray<CFileDescription>& files=aInstallBlock.FileDescriptions();
  
  	TInt i;
  	for (i = 0; i < files.Count(); ++i)
  		{
  		ProcessFileDescriptionL(*files[i], aApplication, aFilesToCapabilityCheck, aPlannedFiles);
  		}
  	
	// process the expressions
	for (i = 0 ; i < aInstallBlock.IfStatements().Count(); ++i)
		{
		Sis::CIf* ifBlock=aInstallBlock.IfStatements()[i];
		
		if (!ifBlock)
			{
			User::Leave(KErrCorrupt);
			}
		
		// main expression
		if ( iExpressionEvaluator->EvaluateL(ifBlock->Expression()).BoolValueL() )
			{
			// suppose TextSkip precedes an IF block then TS won't work
			// since TS is only intended to work if it is immediately followed by a line that installs a file.
			iTextSkip = EFalse;
			ProcessInstallBlockL(ifBlock->InstallBlock(), aApplication, aFilesToCapabilityCheck, aPlannedFiles);
			}
		else
			{
			// else if blocks
			const RPointerArray<CElseIf>& elseIfs=ifBlock->ElseIfs();
		
			for (TInt j = 0 ; j < elseIfs.Count(); ++j)
				{				
				if (!elseIfs[j])
				 	{
					User::Leave(KErrCorrupt);
					}
				if (iExpressionEvaluator->EvaluateL(elseIfs[j]->Expression()).BoolValueL())
					{
					iTextSkip = EFalse;
					ProcessInstallBlockL(elseIfs[j]->InstallBlock(), aApplication, aFilesToCapabilityCheck, aPlannedFiles);					
					break;	// stop processing else if blocks
					}
				}
			}
		iTextSkip = EFalse;
		}
		
	// Embedded controllers
	
	for (i = 0 ; i < aInstallBlock.EmbeddedControllers().Count(); ++i)
		{
		if (aInstallBlock.EmbeddedControllers()[i]==NULL)
			{
			User::Leave(KErrCorrupt);
			}

		// Add these to the list of controllers we are going to "plan" as we move the the installmachine state machine
		// OWNERSHIP is NOT TRANSFERRED
		iControllersToProcess.AppendL(TControllerAndParentApplication(*aInstallBlock.EmbeddedControllers()[i], &aApplication));			
		}
	}
	
/** This function examines the list of files we may eclipse to see if the supplied name is among them.
    Here we have to options:
    1.)   file is to be installed to \sys\bin therefore we have to handle adorned filenames
          eclipsing is allowed if the filename that we are trying to install is a variant of any ROM filename 
          marked as eclipsable i.e: if we are trying to install c:\sys\bin\A{000A0001}.dll
          and a ROM stub lists z:\sys\bin\A.dll as an eclipsable file or any z:\sys\bin\A{????????}.dll
          then we are allowed to that so
    2.)   file is not to be installed to sys\bin\
          in this case we mustn't invoke special handling of adorned filenames so we are only
          interested in if that particular file is allowed to be eclipsed i.e: z:\somedirectory\a.txt
          Remark:
             in this case z:\somedirectory\a.txt and z:\somedirectory\a{ABCDEFGH}.txt are considered to be different filenames
             even if they might look to be variations of the same name
	@param aRomFile fully qualified filename in ROM that is to be checked for eclipising (i.e: z:\sys\bin\some.dll)
*/

TBool CInstallationPlanner::IsEclipsableL(const TDesC& aRomFile)
	{
	// exception : SA/SP/PU sis + RU flag + signed by SU root cert can continue installation
	if (iIsValidSystemUpgrade)
		{
		return ETrue;
		}
	TBool isEclipsable = EFalse;
	RBuf romFileName;
	romFileName.CreateL(aRomFile, aRomFile.Size());
	romFileName.CleanupClosePushL();

	TParsePtr parsedFileName(romFileName);
	RBuf path;
	path.CreateL(parsedFileName.Path().Length());
	path.CleanupClosePushL();
	path = parsedFileName.Path();
    TBool goesToSysBin = (path.CompareF(KSysBin) == 0);
	for (TInt i = 0; i < iEclipsableRomFiles.Count(); i++)
		{
		if (aRomFile.MatchF(*(iEclipsableRomFiles[i])) == 0)
			{
			isEclipsable = ETrue;
			break;
			}
		else if ( goesToSysBin )		
			{
			if(Swi::IsAdornedVariationOfL(*(iEclipsableRomFiles[i]), aRomFile))
				{
				isEclipsable = ETrue;
				break;
				}
			}
		}
	CleanupStack::PopAndDestroy(2, &romFileName);
	return isEclipsable;
	}

// This function ensures the file to be installed does not illegally
// eclipse a file already installed on ROM.
TBool CInstallationPlanner::ValidEclipseL(RFs& aFs, TFileName& aFileName, CApplication& aApplication)
	{
    DEBUG_PRINTF2(_L("CInstallationPlanner::ValidEclipseL() called aFileName='%S'"), &aFileName );
	// check every file to be installed for a possible eclipse	
	// This is done is two steps:
	// If installing to \sys\bin then first check for versioned (adorned name) copy of file
	// Then check for the unadorned version
    RArray<TFileName> eclipsableOverwriteFiles;
    CleanupClose<RArray<TFileName> >::PushL(eclipsableOverwriteFiles);
    
    TParsePtr parsedFileName(aFileName);

	// When installing to sys\bin check for adorned names
	RBuf searchNameUnadorned; // Holds the normalized unadorned filename (i.e. c:\sys\bin\a.exe for aFileName equal to c:\sys\bin\a{123456}.exe)
	searchNameUnadorned.CreateL(aFileName.Length()); //fully qualified unadorned search name is never longer than original fully qualified name (i.e aFileName)
	searchNameUnadorned.CleanupClosePushL();

	//Holds all adorned file names that match the adorned filename pattern calculated out of aFileName
	RPointerArray<HBufC> adornedFileNamesFound;
    CleanupResetAndDestroy<RPointerArray<HBufC> >::PushL(adornedFileNamesFound);
	RBuf path;
	path.CreateL(parsedFileName.Path().Length());
	path.CleanupClosePushL();
	path = parsedFileName.Path();
	
 	if ( path.CompareF(KSysBin) == 0 )		
		{
		// check for versioned (adorned) filenames
		AdornedProcessingOfFileL(aFs, aFileName, searchNameUnadorned, adornedFileNamesFound);
		}
	else
		{
		searchNameUnadorned = aFileName;
		}
		
	// Second check for the unadorned version
	TChar targetDisk = aFileName[0];
	targetDisk.Fold();
	
	// Find on which disks (if any) this file exists on
	TDriveList driveList;
	User::LeaveIfError(aFs.DriveList(driveList));
	
	TBool result=ETrue;
	TChar disk = 'a' - 1;
	TEntry* entryPtr = new (ELeave) TEntry;
	CleanupStack::PushL(entryPtr);
	
	for (TInt i = 0; i < driveList.Length(); i++)
		{
		disk+=1;
		
		if (driveList[i] == 0)
			{
			continue;
			}
		searchNameUnadorned[0] = disk;

		// check if adorned file version found on this disk
		TBool adornedFound = EFalse;
		TInt nrOfAdornedFilenamesFound = adornedFileNamesFound.Count();
		for (TInt index=0; index < nrOfAdornedFilenamesFound;  ++index)
			{
			TChar drive((*(adornedFileNamesFound[index]))[0]);
			drive.Fold();
			if ( drive == disk )
				{
				adornedFound = ETrue;
				break;
				}
			}

		TBool unadornedFound = aFs.Entry(searchNameUnadorned, *entryPtr) == KErrNone;
		TBool matchFound = unadornedFound || adornedFound;
		if (!matchFound)
			continue; // Nothing relevant found on this drive

		TBool processEclipsingSuspectsFoundOnThisDrive = EFalse;
		
		// The logic varies whether we found an eclipsable/overwritable file on: (1) The same disk as the one we are installing to
		// (2) The Z drive (ROM), (3) Any other drive
		if (disk == targetDisk) // Case (1)
			{
			TBool isOverwrite = aFs.Entry(aFileName, *entryPtr) == KErrNone;
			// At this point, we have 3 possible cases: (1.1) We are correctly overwriting the already present file (a PU), 
			// (1.2) We are incorrectly overwriting the file present, (1.3) We are eclipsing the file (if one of the file names is adorned)
			//Overwriting: it can be that we found either adorned or unadorned filenames on target drive
			//Since we don't know wheter the target filename is adorned or unadorned we have to specifically check
			//wheter we are trying to overwrite a file with that name or not.
			if (isOverwrite)
				{
				// Case 1.1 is handled here - we'll uninstall the old file if we have the right to do it.
				// Case 1.2 will be handled in CPostrequisitesChecker::WouldOverWriteL, as the error will be caught there
				HandleFileOverwritingL(aFileName, aApplication);
				}
			else
				{
				//Case 1.3 is handled here: 
				//we have found a matching filename (either unadorned or adorned); add it to eclipsing suspects
				processEclipsingSuspectsFoundOnThisDrive = ETrue;
				}
			}		
		else if (disk == 'z') // Case (2)
			{
			// we are eclipsing a rom file, check if this is authorised:
			//see implementation of IsEclipsable()
			if (!IsEclipsableL(searchNameUnadorned))
				{
				result = EFalse;
				break;
				}		
			}
		else // Case (3)
			{
			processEclipsingSuspectsFoundOnThisDrive = ETrue;
			}

		//now we need to check whether the unadorned or the adorned filenames found on this drive have to be added to iEclipsableOverwriteFiles
		if(processEclipsingSuspectsFoundOnThisDrive && unadornedFound && !SecurityCheckUtil::IsToBeUninstalledL(searchNameUnadorned, aApplication))
			{
			eclipsableOverwriteFiles.AppendL(searchNameUnadorned);
			}
		if(processEclipsingSuspectsFoundOnThisDrive && adornedFound)
			{
			nrOfAdornedFilenamesFound = adornedFileNamesFound.Count();
			for (TInt index=0; index < nrOfAdornedFilenamesFound; ++index)
				{
				TChar drive((*(adornedFileNamesFound[index]))[0]);
				drive.Fold();
				if ( (drive == disk) && !SecurityCheckUtil::IsToBeUninstalledL(*(adornedFileNamesFound[index]), aApplication))
					{
					eclipsableOverwriteFiles.AppendL(*(adornedFileNamesFound[index]));
					}
				}
			}
		}//end of for (TInt i = 0; i < driveList.Length(); i++)

	//Next step to remove all files from iEclipsableOverwriteFiles that we don't consider
	//blocking files (blocking files =  those that prevent this file from installing)
	//These non blocking files are those owned by the same package UID as the current one except
	//that filename that matches the actual filename ie: aFileName
	//i.e: if aFileName = c:\sys\bin\a.dll and e:\sys\bin\a.dll is found and put in iEclipsableOverwriteFiles earlier or
	//aFileName = c:\sys\bin\a{000A0004}.dll and e:\sys\bin\a{000A0004}.dll  is found and put in iEclipsableOverwriteFiles
	//then these matching filenames should not be taken out so that the installation will fail
	//later in CInstallationPlanner::WarnEclipseOverWriteL()
	//Reason: the installer maintains only one hash per filename, that's only one hash file is calculated for \sys\bin\a.dll and
	//for \sys\bin\a{000A0004}.dll and not individual ones for each instances on different drives
	//If result is FALSE there's a blocking file in ROM so no point in processing iEclipsableOverwriteFiles
	//because the the installation will fail regardless of what iEclipsableOverwriteFiles contains
	if (result && (eclipsableOverwriteFiles.Count() > 0) ) 
		{
		TUid uid = aApplication.ControllerL().Info().Uid().Uid();
		//filter out all suspected files that belong to this package
		SecurityCheckUtil::FilterNonBlockingFilesOfFilenameL(eclipsableOverwriteFiles, aFileName, aApplication.ControllerL().Info().Uid().Uid());
		}
	//iEclipsableOverwriteFiles will be searched through later in CInstallationPlanner::WarnEclipseOverWriteL()
	//looking for files that are not orphaned (ie. belong to any package (SecurityCheckUtil::LookForBlockingFilesL())
	
	for(TInt i = 0; i < eclipsableOverwriteFiles.Count(); i++)
		{
		iEclipsableOverwriteFiles.AppendL(eclipsableOverwriteFiles[i]);
		}
		
	CleanupStack::PopAndDestroy(5, &eclipsableOverwriteFiles); 
	return result;
	}

void CInstallationPlanner::WarnEclipseOverWriteL(CApplication& aApplication)
 	{
 	//Check if we need to pop up dialog to ask client for overwrite or report blocking
 	if (iEclipsableOverwriteFiles.Count()>0)
 		{
 		//See if the swi policy allow overwrite
 		CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
 		TBool allowOrphanedOverwrite = securityPolicy->AllowOrphanedOverwrite();
 		TBool allowProtectedOrphanOverwrite = securityPolicy->AllowProtectedOrphanOverwrite();
 		
 		if (allowOrphanedOverwrite)
 			{
			// check if there is any orphaned file
 			TInt index = SecurityCheckUtil::LookForBlockingFilesL(iEclipsableOverwriteFiles);
 			if (index != KErrNotFound) // if the list contains some non-orphaned file
 				{
 				DisplayErrorL(EUiBlockingEclipsingFile, iEclipsableOverwriteFiles[index]);
 				User::Leave(KErrInvalidEclipsing);	
 				}
 			else
 				{
 				TInt fileNameCount=iEclipsableOverwriteFiles.Count();
 				// Question user about all the Orphaned files
 				for (TInt i=0; i<fileNameCount; i++)
 					{
					TBool overwrite = EFalse;
					if (! (!allowProtectedOrphanOverwrite &&
						SecurityCheckUtil::IsProtectedDirectoryL(iEclipsableOverwriteFiles[i])))
						{
						CDisplayQuestion* cmd = CDisplayQuestion::NewLC(Plan().AppInfoL(), EQuestionOverwriteFile, iEclipsableOverwriteFiles[i]);
						UiHandler().ExecuteL(*cmd);
						if (cmd->ReturnResult())
							{
							// Add the file to list of files to remove in the
							// processing stage.  It should not actually be
							// removed until after security checks validate
							// that the target which eclipses this file is
							// valid for this package.
							aApplication.RemoveFileL(iEclipsableOverwriteFiles[i]);
							Plan().AddUninstallFileForProgress();
							overwrite = ETrue;
							}
						CleanupStack::PopAndDestroy(cmd);	
						}
					if (!overwrite)
 	 					{
 	 					// User say "no" to overwrite, so blocking
 						DisplayErrorL(EUiBlockingEclipsingFile, iEclipsableOverwriteFiles[i]);
 						User::Leave(KErrInvalidEclipsing);
						break;
 						}
 					}					
 				}			
 			}
 		else
 			{
 			// policy does not not allow overwrite, error Blocking 		
 			DisplayErrorL(EUiBlockingEclipsingFile, iEclipsableOverwriteFiles[0]);
 			User::Leave(KErrInvalidEclipsing);		
 			}
 		}
 	}

// This function is used to process all files in the controllers

void CInstallationPlanner::ProcessFileDescriptionL(const CFileDescription& aFileDescription, CApplication& aApplication, RPointerArray<CFileDescription>& aFilesToCapabilityCheck, CFilesFromPlannedController& aPlannedFiles)
	{
	
	// Check the installation path
	if (aFileDescription.Target().Data().Length() != 0)
		{
		DEBUG_PRINTF2(_L("Processing file for install '%S'"), &(aFileDescription.Target().Data()));

		RFs fs;
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);

		CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
		TText selDrive = aApplication.UserSelections().Drive();
		HBufC* targetFileName = securityPolicy->ResolveTargetFileNameLC(
			aFileDescription.Target().Data(), selDrive);

		// if it's a stub, rewrite it with the user drive selection
		// which includes pre-installed applications or patches.
		if (iIsStub)
			{
			// Previously, for PA and PP, if files to be "installed" were
			// on a different drive to the stub SIS file, this code would
			// leave with KErrSISInvalidTargetFile. See DEF084248/BR1857.1
			// Now, we re-write all stub file references to the drive where
			// the SIS file is located, as requested in INC109356. This allows
			// SIS files with "e:\foo.txt" to install on drives F, G, H, etc.
			// However, if the SIS file contains files which reference more
			// than one drive letter, we refuse to install.
			TPtr targetFileNamePtr(targetFileName->Des());
			
			if (iStubFirstDriveLetter == KNoDriveSelected)
				{
				iStubFirstDriveLetter = targetFileNamePtr[0];
				}
							
			if (iStubFirstDriveLetter == targetFileNamePtr[0])
				{
				targetFileNamePtr[0] = selDrive;
				}				
			else
				{
				User::Leave(KErrSISInvalidTargetFile);
				}
				
			
			targetFileNamePtr[0] = selDrive;
			
			// Additional re-writing happens in CInstallationProcessor::DoStateProcessFilesL()
			// since re-writing here is for checking in this method only
			}

		if(!SecurityCheckUtil::CheckFileName(*targetFileName, iSystemDriveChar) ||
			SecurityCheckUtil::IsSubstedDriveL(fs, *targetFileName))
			{
			DisplayErrorL(EUiInvalidFileName, *targetFileName);
			User::Leave(KErrSISInvalidTargetFile);		
			}

		// For operations other than filenull we need the drive to exist
		// and we need to check for invalid eclipsing.
		if (aFileDescription.Operation() != EOpNull) 
   			{
			// must be writable for ValidEclipseL
			TFileName installName = *targetFileName;

   			// check the target drive actually exists, and is mounted
			TInt driveNo;
			User::LeaveIfError(fs.CharToDrive(installName[0], driveNo));
			TVolumeInfo volInfo;
			if (KErrNone != fs.Volume(volInfo, driveNo))
				{
				DisplayErrorL(EUiDiskNotPresent, aFileDescription.Target().Data());
				User::Leave(KErrSISInvalidTargetFile);
				}
	
			// Check for invalid eclipsing of files already on the device.
			if (!ValidEclipseL(fs, installName, aApplication))
				{
				//The file is in ROM and not eclipsable
				DisplayErrorL(EUiAlreadyInRom, aFileDescription.Target().Data());
				User::Leave(KErrInvalidEclipsing);
				}
		
			// Check for clashes with other applications in the plan.
			CheckFilesFromPlannedControllersL(*targetFileName, aPlannedFiles);
			
			// Add file to list to check in subsequent applications.
			aPlannedFiles.AppendL(targetFileName);
			CleanupStack::Pop(targetFileName);

			aFilesToCapabilityCheck.AppendL(&aFileDescription);
			
			// check for plug-ins
			TInt len = KPluginPath().Length();
			if ((targetFileName->Length() >= len+2) && targetFileName->Mid(2,len).CompareF(KPluginPath) == 0)
				{
				Plan().SetContainsPlugins(ETrue);
				}
			// if it's an apparc file, record it in the plan for use later	
			AddApparcFilesToPlanL(targetFileName->Des());
   			}
		else
	   		{
   			CleanupStack::PopAndDestroy(targetFileName);
 	  		}

		CleanupStack::PopAndDestroy(&fs); // fs

		// it's a file to copy, add it to the current application
		if (!iTextSkip || aFileDescription.Operation() == EOpNull)
			{
			aApplication.AddFileL(aFileDescription, aApplication.UserSelections().Drive());
			Plan().AddInstallFileForProgress(aFileDescription.UncompressedLength());
			}
		else
			{
			aApplication.SkipFileOnInstallL(aFileDescription, aApplication.UserSelections().Drive());
			}				
		}
	
	
	//Add to files to run if we need to
	if (aFileDescription.Operation() == EOpRun)
		{
#ifdef SYMBIAN_SWI_RUN_ON_INSTALL_COMPLETE 

		// Can't run at install AND after install with the same file. FILEMIME compiles to FM,RI
		// we must block this or you can't get just (RUNAFTERINSTALL, FM) and this is the more 
		// common usecase. 
		if (aFileDescription.OperationOptions() & EInstFileRunOptionAfterInstall)
			{
			Plan().RunFileAfterInstallL(aFileDescription, aApplication.UserSelections().Drive(), aApplication.IsStub());
			}
		else if (aFileDescription.OperationOptions() & EInstFileRunOptionInstall)	
        	{			
			aApplication.RunFileOnInstallL(aFileDescription, aApplication.UserSelections().Drive());
			// running the app will force SWI to notify Apparc in advance so the current list
			// of files have already been processed.
			Plan().ResetAppArcRegFiles();
			}
#else 
        if (aFileDescription.OperationOptions() & EInstFileRunOptionInstall)	
			{			
			aApplication.RunFileOnInstallL(aFileDescription, aApplication.UserSelections().Drive());
			// running the app will force SWI to notify Apparc in advance so the current list
			// of files have already been processed.
			Plan().ResetAppArcRegFiles();
			}
#endif // SYMBIAN_SWI_RUN_ON_INSTALL_COMPLETE 
		}
	// Files to display
	else if (aFileDescription.Operation() == EOpText)
		{
		if ( !aApplication.IsStub() )
			aApplication.DisplayFileOnInstallL(aFileDescription, aApplication.UserSelections().Drive());
		}

	// Reset the iTextskip value as this is applicable for the next one file only.
	iTextSkip = EFalse;
	if (aFileDescription.OperationOptions() & EInstFileTextOptionSkipIfNo)
		{
		iTextSkip = ETrue;
		}
	}

void CInstallationPlanner::AddApparcFilesToPlanL(const TDesC& aTargetFileName)
	{
	_LIT(KApparcRegDir, "\\private\\10003a3f\\import\\apps\\");
	TParsePtrC filename(aTargetFileName);
	if (filename.Path().Left(KApparcRegDir().Length()).CompareF(KApparcRegDir) == 0)
		{
		// we're installing a reg file so add it to our list. 
		Plan().AddAppArcRegFileL(aTargetFileName);
		}
	}

void CInstallationPlanner::ProcessFilesToRemoveL(CApplication& aApplication, RSisRegistryWritableEntry& aRegistryEntry)
	{
	TBool romBasedFile(EFalse);
	if (aApplication.IsUpgrade() || aApplication.IsPartialUpgrade())
		{
		// There may be files to remove as part of the plan
		
		RPointerArray<CSisRegistryFileDescription> fileDescriptions;
		CleanupResetAndDestroy<RPointerArray<CSisRegistryFileDescription> >::PushL(fileDescriptions);
		aRegistryEntry.FileDescriptionsL(fileDescriptions);

		TInt count(fileDescriptions.Count());
		for (TInt i=0;i < count; ++i)
			{
			//Consider only non-ROM based files.
			CSisRegistryFileDescription* description = fileDescriptions[i];
			romBasedFile = ((description->Target().Mid(0,1) == _L("z")) ||
							(description->Target().Mid(0,1) == _L("Z")));
			// Skip filenull cases.
			if ((description->Operation() != EOpNull) && !romBasedFile)
				{
				// If this is either an SA upgrade or if its a PU
				// where the file is to be replaced, remove it first.
				if (aApplication.IsUpgrade())
					{
					DEBUG_PRINTF2(_L("Planning file for removal '%S'"), &(description->Target()));
					aApplication.RemoveFileL(*description);
					Plan().AddUninstallFileForProgress();
					}
				else
					{
					DEBUG_PRINTF2(_L("File '%S' may be legally overwritten"), &(description->Target()));
					// create a new copy and append it to the array
					CSisRegistryFileDescription* desc = CSisRegistryFileDescription::NewL(*description);
					CleanupStack::PushL(desc);
					iOverwriteableFiles.AppendL(desc);
					CleanupStack::Pop(desc);
					}
				}
			}
	
		CleanupStack::PopAndDestroy(&fileDescriptions);
		
		}
	}

// find the application is allowed to install based on SU Cert Rules if
// 1. if the sis file is signed by certificate trusted by the device (SU Cert)
// 2. if the sis file is of type SA/SP/PU with RU/RU+NR flag
// 3. the sis file validation status is trusted
TBool CInstallationPlanner::IsValidSystemUpgradeL(const CApplication& aApplication)
	{
	Sis::TInstallType type = aApplication.ControllerL().Info().InstallType();
	Sis::TInstallFlags flag = aApplication.ControllerL().Info().InstallFlags();
	TBool allowedType = (type == EInstInstallation || (type == EInstAugmentation) || type == EInstPartialUpgrade );
	TBool allowedFlag = (flag & EInstFlagROMUpgrade);
	// PA and PP is not allowed
	// Treat an SA/SP/PU on a removable media stub as a preinstalled apps/patch

	return (aApplication.ControllerL().IsSignedBySuCert() && allowedType && allowedFlag && 
			aApplication.ControllerL().TrustStatus().ValidationStatus()
			>= EValidatedToAnchor);
	}


// CInstallationPair::TUidApplicationPair functions

CInstallationPlanner::CPackageApplicationPair::CPackageApplicationPair(CApplication& aApplication)
	: iApplication(aApplication)
	{
	}

void CInstallationPlanner::CPackageApplicationPair::ConstructL(CSisRegistryPackage& aPackage)
	{
	iPackage=CSisRegistryPackage::NewL(aPackage);
	}

CInstallationPlanner::CPackageApplicationPair::~CPackageApplicationPair()
	{
	delete iPackage;
	}

CSisRegistryPackage& CInstallationPlanner::CPackageApplicationPair::Package() const
	{
	return *iPackage;
	}
	
CApplication& CInstallationPlanner::CPackageApplicationPair::Application()
	{
	return iApplication;
	}

CInstallationPlanner::CPackageApplicationPair* CInstallationPlanner::CPackageApplicationPair::NewLC(CSisRegistryPackage& aPackage, CApplication& aApplication)
	{
	CPackageApplicationPair* self=new(ELeave) CPackageApplicationPair(aApplication);
	CleanupStack::PushL(self);
	self->ConstructL(aPackage);
	return self;
	}

//CFilesFromPlannedController class functions
CInstallationPlanner::CFilesFromPlannedController::CFilesFromPlannedController(TUid aUid, TUid aParentUid, Sis::TInstallType aInstallType, Sis::CString* aName)
	:iUid(aUid),iParentUid(aParentUid),iCount(0),iInstallType(aInstallType),iName(aName)
	{
	}
	
CInstallationPlanner::CFilesFromPlannedController::~CFilesFromPlannedController()
	{
	iFileNames.ResetAndDestroy();
	}
	
CInstallationPlanner::CFilesFromPlannedController* CInstallationPlanner::CFilesFromPlannedController::NewLC(TUid aUid, TUid aParentUid, Sis::TInstallType aInstallType, Sis::CString* aName)
	{
	CFilesFromPlannedController* self = new (ELeave) CFilesFromPlannedController(aUid, aParentUid, aInstallType, aName);
	CleanupStack::PushL(self);
	return self;
	}

void CInstallationPlanner::CFilesFromPlannedController::AppendL(HBufC* aFileName)
	{
	iFileNames.AppendL(aFileName);
	++iCount;
	}

TUid CInstallationPlanner::CFilesFromPlannedController::Uid()
	{
	return iUid;
	}

TUid CInstallationPlanner::CFilesFromPlannedController::ParentUid()
	{
	return iParentUid;
	}
	
TInt CInstallationPlanner::CFilesFromPlannedController::Count()
	{
	return iCount;
	}
	
TChar CInstallationPlanner::CFilesFromPlannedController::Drive()
	{
	return iDrive;
	}
	
void CInstallationPlanner::CFilesFromPlannedController::SetDrive(TChar& aDrive)
	{
	iDrive = aDrive;
	}

Sis::CString* CInstallationPlanner::CFilesFromPlannedController::Name()
	{
	return iName;
	}

Sis::TInstallType CInstallationPlanner::CFilesFromPlannedController::InstallType()
	{
	return iInstallType;
	}

TBool CInstallationPlanner::CFilesFromPlannedController::IsMatched(const TDesC& aFileName)
	{
	TBool match = EFalse;
	TInt count = iFileNames.Count();
	for(TInt i=0; i<count; ++i)
		{
		if(!aFileName.CompareF(*iFileNames[i]))
			{
			match = ETrue;
			break;
			}
		}
	return match;
	}

TBool CInstallationPlanner::CFilesFromPlannedController::IsEclipsed(const TDesC& aFileName)
	{
	TBool eclipse = EFalse;
	TInt count = iFileNames.Count();
	for(TInt i=0; i<count; ++i)
		{
		if(aFileName.Mid(1).CompareF((*iFileNames[i]).Mid(1)) == 0)
			{
			eclipse = ETrue;
			break;
			}
		}
	return eclipse;
	}
	
const CController& CInstallationPlanner::CurrentController()
	{
	return iControllersToProcess[iCurrentController].Controller();
	}
	
const Sis::CController& CInstallationPlanner::MainController()
	{
	return iControllersToProcess[0].Controller();
	}

TInt CInstallationPlanner::GetControllerReference(TUid aUid)
	{
	TInt count = iControllersToProcess.Count();
	for(TInt i=0; i<count; ++i)
		{
		if(aUid == iControllersToProcess[i].Controller().Info().Uid().Uid())
			{
			return i;
			}
		}
	return KErrNotFound;
	}

void CInstallationPlanner::PlanCurrentControllerL(RPointerArray<CFileDescription>& aFilesToCapabilityCheck)
	{
	if(!iMainApplication)
		{
		// Plan main controller
		iMainApplication = ProcessControllerL(CurrentController(), 0, aFilesToCapabilityCheck, CurrentController().Info().Uid().Uid()); // Top-level controller has embedded data index of 0
		}
	else
		{
		CApplication* parentApplication = iControllersToProcess[iCurrentController].ParentApplication();
		User::LeaveIfNull(parentApplication);
		
		CApplication* application=ProcessControllerL(CurrentController(), parentApplication->AbsoluteDataIndex(), aFilesToCapabilityCheck, parentApplication->ControllerL().Info().Uid().Uid());
		CleanupStack::PushL(application);
		parentApplication->AddEmbeddedApplicationL(application); // ownership transferred
		CleanupStack::Pop(application);
		}
	}

TBool CInstallationPlanner::GetNextController()
	{
	// Find the next controller in our list of controllers
	if(++iCurrentController < iControllersToProcess.Count())
		{
		return ETrue;
		}
	else
		{
		return EFalse;	
		}
	}

void CInstallationPlanner::DisplayErrorL(TErrorDialog aType, const TDesC& aParam)
	{
	#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	// Display the error message only when the planner is not in info collection mode.
	if(!IsInInfoCollectionMode())
		{
		CDisplayError* displayError=CDisplayError::NewLC(Plan().AppInfoL(), aType, aParam);
		UiHandler().ExecuteL(*displayError);
		CleanupStack::PopAndDestroy(displayError);
		}
	#else
	CDisplayError* displayError=CDisplayError::NewLC(Plan().AppInfoL(), aType, aParam);
	UiHandler().ExecuteL(*displayError);
	CleanupStack::PopAndDestroy(displayError);
	#endif	
	}

void CInstallationPlanner::CheckFilesFromPlannedControllersL(const TDesC& aFileName, CFilesFromPlannedController& aPlannedFiles) const
	{
	TBool check = EFalse;
	
	// Check all files from already planned controllers to see if this file
	// will overwrite or eclipse.  Note that the array may contain files from
	// the current controller beyond the last index checked here; a single
	// package is allowed to overwrite or eclipse its own target files.
	TInt count = iFilesFromPlannedControllers.Count();	
	for(TInt i=0; i<count; ++i)
		{
		check = EFalse;
		
		if(aPlannedFiles.Uid() != iFilesFromPlannedControllers[i]->Uid())
			{//This is a different package so we should check files
			check = ETrue;
			}
		else
			{
			//Do not allow that two packages with the same UID are embedded by different base packages
			if(aPlannedFiles.ParentUid() != iFilesFromPlannedControllers[i]->ParentUid())
				{
				User::Leave(KErrAlreadyExists);
				}
			else
				{
				Sis::TInstallType plannedType = iFilesFromPlannedControllers[i]->InstallType();
				Sis::TInstallType currentType = aPlannedFiles.InstallType();
				
				if(currentType != plannedType)
					{
					//Augmentations can't overwrite files from the base package or its PU
					if((currentType == EInstAugmentation) || (plannedType == EInstAugmentation))
						{
						check = ETrue;
						}
					}
				else
					{
					//SA packages delivered within the embedding package can not be SA
					//upgraded from within the same package
					if(currentType == EInstInstallation)
						{
						User::Leave(KErrAlreadyExists);
						}
					//multiple partial upgrades to the base are supported
  					//multiple separate augmentations are supported
					}
				}
			}
			
		if(check)
			{
			if(iFilesFromPlannedControllers[i]->IsMatched(aFileName))
				{
				// File exactly matches one from another controller already
				// processed in this plan.
				User::Leave(KErrAlreadyExists);
				}
			else if(iFilesFromPlannedControllers[i]->IsEclipsed(aFileName))
				{
				// File would eclipse one from another controller already
				// processed in this plan.
				User::Leave(KErrInvalidEclipsing);
				}
			}
		}
	}

TBool CInstallationPlanner::IsAugmentationUpgradeL(const Sis::CController& aController, RSisRegistryEntry& aRegistryEntry,
		RSisRegistrySession& aRegistrySession)
	{
	TBool ret = EFalse;
	if (aController.Info().InstallType() == Sis::EInstAugmentation)
		{
		CSisRegistryPackage* package = CSisRegistryPackage::NewLC(aController.Info().Uid().Uid(),
			aController.Info().Names()[iDisplayLanguageIndex]->Data(),
			aController.Info().UniqueVendorName().Data());
		
		// first check this isn't exactly the same package name...
		CSisRegistryPackage* base = aRegistryEntry.PackageL();
		CleanupStack::PushL(base);
		if ((base->Uid() == package->Uid()) && (base->Name() == package->Name()))
			{
			// cannot upgrade a base package with an augmentation!
			User::Leave(KErrInvalidUpgrade);
			}
		CleanupStack::PopAndDestroy(base);
		
		// See if we can find this package in the augmentations to this entry
		RPointerArray<CSisRegistryPackage> augmentations;
		CleanupResetAndDestroyPushL(augmentations);
		aRegistryEntry.AugmentationsL(augmentations);
	
		TInt count(augmentations.Count());	
		for (TInt i = 0; i < count; ++i)
			{
			if ((package->Uid()  == augmentations[i]->Uid()) &&
				(package->Name()  == augmentations[i]->Name())) 
				{
				// close and reopen the registry entry as that for the augmentation
				aRegistryEntry.Close();
				aRegistryEntry.OpenL(aRegistrySession, *augmentations[i]);
			
				ret = ETrue;
				break;
				}
			}
		CleanupStack::PopAndDestroy(2, package); // augmentations
		}
		
	return ret;
	}	

TBool CInstallationPlanner::IsAugmentationUpgrade(const Sis::CController& aController)
	{
	TBool isUpgrade = EFalse;
	TInt count = iFilesFromPlannedControllers.Count();
	for(TInt i=0; i<count; i++)
		{
		if((aController.Info().Uid().Uid() == iFilesFromPlannedControllers[i]->Uid())
		   && (iFilesFromPlannedControllers[i]->InstallType() == EInstAugmentation))
			{
			//If augmentation has the same name with another augmentation in the list, it's a upgrade
			if(!iFilesFromPlannedControllers[i]->Name()->Data().CompareF(aController.Info().Names()[0]->Data()))
				{
				isUpgrade = ETrue;
				}	
			}
		}
	
	return isUpgrade;
	}
	
//Checks whether an SP/PU package's base package has already been planned		
TBool CInstallationPlanner::IsPlannedControllerL(const Sis::CController& aController, TInt& aIndex, TUid aParentUid)
	{
	TBool inList = EFalse;
	TInt i;
	for(i=0; i<iFilesFromPlannedControllers.Count(); i++)
		{
		if(aController.Info().Uid().Uid() == iFilesFromPlannedControllers[i]->Uid())
			{
			if(aController.Info().InstallType() == EInstAugmentation)
				{
				//If augmentation has the same name with the base package in the list, it's an invalid upgrade
				if(!iFilesFromPlannedControllers[i]->Name()->Data().CompareF(aController.Info().Names()[0]->Data())
				   && (iFilesFromPlannedControllers[i]->InstallType() == EInstInstallation))
					{
					User::Leave(KErrInvalidUpgrade);
					}
				}
			//Augmentations or partial upgrades must be embedded by the same base pacakge				
			if(aParentUid == iFilesFromPlannedControllers[i]->ParentUid())
				{
				inList = ETrue;
				break;	
				}
			}
		}
	aIndex = i;
	return inList;
	}

/** This function takes a fully qualified name and searches the filesystem through for all possible adorned filename matches.
 *  Besides that it calculates the unadorned version of the input filename as well and return it through the corresponding given 
 *  input reference variable.
 *  @param aFs A valid file server session handle
 *  @param aFileName The fully qualified filename (full path and name)
 *  @param aUnadornedName The calulated unadorned name is returned through this variable(full path and unadorned name calculated from aFileName)
 *  @param aAdornedFileNamesFound All the found adorned name matches are returned through this pointer array to descriptors
 */
void CInstallationPlanner::AdornedProcessingOfFileL(RFs& aFs, TDesC& aFileName, TDes& aUnadornedName, RPointerArray<HBufC>& aAdornedFileNamesFound)
	{
    TParsePtrC parsedFileName(aFileName);
	TInt originalNameAndExtLength = parsedFileName.NameAndExt().Length();
	RBuf searchNameWild;
	searchNameWild.CreateL(originalNameAndExtLength+Swi::FileNameUnadornedPartLength); //searchname wild is max 10 chars longer than original filename+ext
	searchNameWild.CleanupClosePushL();
	RBuf unadornedName;
	unadornedName.CreateL(originalNameAndExtLength); //unadorned name is never longer than original name
	unadornedName.CleanupClosePushL();

    Swi::GetUnadornedFileName(parsedFileName.NameAndExt(), unadornedName);
	aUnadornedName = parsedFileName.DriveAndPath();
	aUnadornedName.Append(unadornedName);
	Swi::GenerateSearchNameWildL(parsedFileName.NameAndExt(), searchNameWild);
	Swi::FindAllAdornedVariantsL(aFs, searchNameWild, parsedFileName.Path(), aAdornedFileNamesFound);
	CleanupStack::PopAndDestroy(2, &searchNameWild);
	}

/** This function handles overwriting situation (i.e: we are trying to install c:\somedir\somename.ext however it already exist)
 *  In this case we have two possible scenarios:
 *  1.) We are correctly overwriting the already present file (a PU)
 *  2.) We are incorrectly overwriting the file present (in this case the error will be caught later in CPostrequisitesChecker::WouldOverWriteL)
 *  @param aFileName The fully qualified filename (full path and name)
 *  @param aApplication installation plan
 */
void CInstallationPlanner::HandleFileOverwritingL(TDesC& aFileName, CApplication& aApplication)
	{
	// Case 1.1 is handled here - we'll uninstall the old file if we have the right to do it.
	// Case 1.2 will be handled in CPostrequisitesChecker::WouldOverWriteL, as the error will be caught there


	// sis file allowed to install based on SU Cert Rules and not of SP type 
	// are allowed to overwrite files owned by other packages. Add it to the plan for removal
	// Files are not removed at install time if is a propagation.
	TBool spInstall = (aApplication.ControllerL().Info().InstallType() == Sis::EInstAugmentation);		
	if (iIsValidSystemUpgrade && !spInstall && !iIsPropagated)
		{
		aApplication.RemoveFileL(aFileName);
		Plan().AddUninstallFileForProgress();
		}

	TInt count(iOverwriteableFiles.Count());
	for (TInt i = 0; i < count; i++)
		{
		CSisRegistryFileDescription* description = iOverwriteableFiles[i];
		if (aFileName.CompareF(description->Target()) == 0 && (description->Operation() != EOpNull))
			{
			aApplication.RemoveFileL(*description);
			Plan().AddUninstallFileForProgress();
			}
		}
	}

// store references to supplied Controller and application
TControllerAndParentApplication::TControllerAndParentApplication(
		const CController& aController, CApplication* aParentApplication) :
		iController(aController), iParentApplication(aParentApplication)
			{
			
			}
			
const CController& TControllerAndParentApplication::Controller()
	{
	return iController;
	}

CApplication* TControllerAndParentApplication::ParentApplication()
	{
	return iParentApplication;
	}

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK	
void CInstallationPlanner::SetInInfoCollectionMode(TBool aMode)
	{
	iIsInInfoCollectionMode = aMode;
	}
	
TBool CInstallationPlanner::IsInInfoCollectionMode()
	{
	return iIsInInfoCollectionMode;	
	}
#endif
