installationservices/refswinstallationplugin/source/sifrefinstallertask.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:21:33 +0300
branchRCL_3
changeset 25 7333d7932ef7
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2008-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: 
* This  file implements Reference Install tasks for getting ComponentInfo, installation, uninstallation and activation/deactivation.
*
*/


#include "sifrefinstallertask.h"
#include "sifrefbinpkgextractor.h"
#include "usiflog.h"
#include <usif/usiferror.h>

using namespace Usif;

_LIT(KRefInstPrivateDir, "c:\\private\\1028634e\\");

/**
A set of helper functions for Reference Installer tasks.
*/
namespace InstallHelper
	{
	_LIT(KSifReferenceSoftwareType, "reference");
	_LIT(KUiConfirmationQuestion, "Are you sure you want to %S component: %S, vendor: %S");
	_LIT(KParamNameErrDesc, "Error Description");
	_LIT(KErrFileAlreadyExists, "File already exists: ");
	_LIT(KUiConfirmationTypeInstall, "install");
	_LIT(KUiConfirmationTypeUpgrade, "upgrade");
	_LIT(KUiConfirmationTypeUninstall, "uninstall");
	_LIT(KUiParserErrorDesc, "Installer encountered a problem when parsing a package file.");
	const TInt KMaxConfirmationTypeLengh = KUiConfirmationTypeUninstall.iTypeLength;

	// This Reference Installer uses Component Name and Vendor Name in order to
	// identify a component in the SCR database. This identification scheme doesn't provide
	// unique ids and its results depend on the current language. Hence, a real installer
	// must use the Unique Id mechanism provided by the SCR.
	void FindComponentL(RSoftwareComponentRegistry& aScr, TComponentSearchData& aCompSearchData, const CSifRefPkgParser& aParser)
		{
		DEBUG_PRINTF(_L8("InstallHelper::FindComponentL()"));
		
		// Get the index of the current language
		const TLanguage curLang = User::Language();
		TInt langIndex = aParser.GetLanguageIndex(curLang);
		if (langIndex == KErrNotFound)
			{
			ASSERT(aParser.Languages().Count() > 0); // The parser should have already rejected packages without languages
			langIndex = 0;
			}

		// Data for CComponentInfo
		aCompSearchData.iName = aParser.ComponentNames()[langIndex];
		aCompSearchData.iVersion = aParser.Version().Name();
		aCompSearchData.iVendor = aParser.VendorNames()[langIndex];
		aCompSearchData.iScomoState = EDeactivated;
		aCompSearchData.iInstallStatus = ENewComponent;
		aCompSearchData.iComponentId = 0;

		RSoftwareComponentRegistryView scrView;
		CComponentFilter* filter = CComponentFilter::NewLC();
		filter->SetNameL(*aCompSearchData.iName);
		filter->SetVendorL(*aCompSearchData.iVendor);
		filter->SetSoftwareTypeL(KSifReferenceSoftwareType);

		scrView.OpenViewL(aScr, filter);
		CleanupClosePushL(scrView);

		// Iterate over matching components in order to determine the status of the package being processed.
		CComponentEntry* component = NULL;
		while ((component = scrView.NextComponentL()) != NULL)
			{
			const TDesC& installedVersion = component->Version();
			const TInt cmp = RSoftwareComponentRegistry::CompareVersionsL(installedVersion, aCompSearchData.iVersion);
			if (cmp > 0)
				{
				aCompSearchData.iInstallStatus = ENewerVersionAlreadyInstalled;
				aCompSearchData.iScomoState = component->ScomoState();
				aCompSearchData.iComponentId = component->ComponentId();
				delete component;
				break;
				}
			else if (cmp == 0 && aCompSearchData.iInstallStatus < EAlreadyInstalled)
				{
				aCompSearchData.iInstallStatus = EAlreadyInstalled;
				aCompSearchData.iScomoState = component->ScomoState();
				aCompSearchData.iComponentId = component->ComponentId();
				}
			else if (cmp < 0 && aCompSearchData.iInstallStatus < EUpgrade)
				{
				aCompSearchData.iInstallStatus = EUpgrade;
				aCompSearchData.iScomoState = component->ScomoState();
				aCompSearchData.iComponentId = component->ComponentId();
				}
			delete component;
			}
		CleanupStack::PopAndDestroy(2, filter);
		}

	TBool UnregisterAndDeleteFileL(RSoftwareComponentRegistry& aScr, RSoftwareComponentRegistryFilesList& aFileList, RStsSession& aSts, TComponentId aComponentId)
		{
		DEBUG_PRINTF(_L8("InstallHelper::UnregisterAndDeleteFileL()"));
		
		// Get next file
		HBufC* file = aFileList.NextFileL();
		if (file != NULL)
			{
			// and remove it from the file system
			CleanupStack::PushL(file);
			aSts.RemoveL(*file);
			CleanupStack::PopAndDestroy(file);
			}
		else
			{
			// Remove the component from the SCR if there are no files left
			aFileList.Close();
			aScr.DeleteComponentL(aComponentId);
			
			// Copying complete
			return ETrue;
			}

		// Copying in progress
		return EFalse;
		}

	MInstallerUIHandler* CreateUiHandlerL(const COpaqueNamedParams* aCustomArguments, TInstallerUIHandlerFactory aUiHandlerFactory)
		{
		DEBUG_PRINTF(_L8("InstallHelper::CreateUiHandlerL()"));
		
		// Instantiate a UI handler for non-silent requests
		if (aCustomArguments != NULL)
			{
			TInt silent = EFalse;
			aCustomArguments->GetIntByNameL(_L("Silent"), silent);
			if (silent)
				{
				return NULL;
				}
			}

		return aUiHandlerFactory();
		}

	enum TConfirmationType
		{
		EConfirmationInstall,
		EConfirmationUpgrade,
		EConfirmationUninstall
		};

	void userConfirmationL(TConfirmationType aType, MInstallerUIHandler& uiHandler, const TDesC& aComponent, const TDesC& aVendor)
		{
		DEBUG_PRINTF(_L8("InstallHelper::userConfirmationL()"));
		
		const TInt maxLen = KUiConfirmationQuestion.iTypeLength + KMaxConfirmationTypeLengh + aComponent.Length() + aVendor.Length();
		HBufC* info = HBufC::NewLC(maxLen);
		TPtr bufInfo(info->Des());
		
		switch (aType)
			{
			case EConfirmationInstall:
				bufInfo.Format(KUiConfirmationQuestion, &KUiConfirmationTypeInstall, &aComponent, &aVendor);
				break;

			case EConfirmationUpgrade:
				bufInfo.Format(KUiConfirmationQuestion, &KUiConfirmationTypeUpgrade, &aComponent, &aVendor);
				break;

			case EConfirmationUninstall:
				bufInfo.Format(KUiConfirmationQuestion, &KUiConfirmationTypeUninstall, &aComponent, &aVendor);
				break;

			default:
				User::Leave(KErrArgument);
			}

		if (!uiHandler.ConfirmationUIHandler(*info))
			{
			User::Leave(KErrCancel);
			}

		CleanupStack::PopAndDestroy(info);
		}
	}

// =============================================================================================================

CSifRefGetComponentInfoTask* CSifRefGetComponentInfoTask::NewL(TTransportTaskParams& aParams)
	{
	DEBUG_PRINTF(_L8("CSifRefGetComponentInfoTask::NewL()"));
	
	// Validate the arguments first.
	if ((aParams.iFileName == NULL && aParams.iFileHandle == NULL) || aParams.iComponentInfo == NULL)
		{
		User::Leave(KErrArgument);
		}
		
	CSifRefGetComponentInfoTask* self = new (ELeave) CSifRefGetComponentInfoTask(aParams);
	return self;
	}

CSifRefGetComponentInfoTask::CSifRefGetComponentInfoTask(TTransportTaskParams& aParams)
: CSifTransportTask(aParams, EFalse), iStep(EExtractEmbeddedPkgs)
	{
	}

CSifRefGetComponentInfoTask::~CSifRefGetComponentInfoTask()
	{
	DEBUG_PRINTF(_L8("CSifRefGetComponentInfoTask::~CSifRefGetComponentInfoTask()"));
	
	iFile.Close();
	iFs.Close();
	iScr.Close();
	iSts.Close();
	iEmbeddedComponents.Close();
	if (iSifRequestInProgress)
		{
		iSif.CancelOperation();
		}
	iSif.Close();
	delete iParser;
	delete iComponentInfo;
	}

TBool CSifRefGetComponentInfoTask::ExecuteImplL()
	{
	DEBUG_PRINTF2(_L8("Exiting from CSifRefGetComponentInfoTask::ExecuteImplL(), iStep = %d"), iStep);
	
	TBool done = EFalse;
	
	switch (iStep)
		{
		case EExtractEmbeddedPkgs:
			ExtractEmbeddedPkgsL();
			++iStep;
			break;

		case EParsePkgFile:
			iStep = ParsePkgFileL();
			break;

		case EFindComponent:
			InstallHelper::FindComponentL(iScr, iCompSearchData, *iParser);
			++iStep;
			break;

		case ECreateComponentInfoNode:
			iStep = CreateComponentInfoNodeL();
			break;

		case ESetComponentInfo:
			SetComponentInfoL();
			done = ETrue;
			break;

		default:
			User::Leave(KErrGeneral);
		}

	if (!iSifRequestInProgress)
		{
		TRequestStatus* status(RequestStatus());
		User::RequestComplete(status, KErrNone);
		}
	
	DEBUG_PRINTF3(_L8("Exiting from CSifRefGetComponentInfoTask::ExecuteImplL(), done = %d, iStep = %d"), done, iStep);
	
	return done;
	}

void CSifRefGetComponentInfoTask::ExtractEmbeddedPkgsL()
	{
	DEBUG_PRINTF(_L8("CSifRefGetComponentInfoTask::ExtractEmbeddedPkgsL()"));
	
	// Start an STS transaction. The extraction of a package requires creation of temporary
	// files that must be deleted when the GetComponentInfo requiest is complete. This is why
	// we need this STS transaction here.
	iSts.CreateTransactionL();

	if (FileName())
		{
		SifRefBinPkgExtractor::BuildPkgTreeL(iSts, *FileName(), KRefInstPrivateDir, iEmbeddedComponents);
		}
	else if (FileHandle())
		{
		SifRefBinPkgExtractor::BuildPkgTreeL(iSts, *FileHandle(), KRefInstPrivateDir, iEmbeddedComponents);
		}
	else
		{
		ASSERT(0);
		}
	
	// Connect to the SCR. The installer needs this session to check if a component being queried
	// is already installed and, if yes, obtain its detials.
	User::LeaveIfError(iScr.Connect());
	}

TInt CSifRefGetComponentInfoTask::ParsePkgFileL()
	{
	DEBUG_PRINTF(_L8("CSifRefGetComponentInfoTask::ParsePkgFileL()"));
	
	delete iParser;
	iParser = NULL;

	// Check if the next component is of the type our installer supports. If yes, add it to the list of
	// the components to be processed. If not, use the SIF API to obtain its details.
	const SifRefBinPkgExtractor::CAuxNode& node = *iEmbeddedComponents[iCurrentComponent];
	if (node.Foreign())
		{
		// Connect to the SIF server
		iComponentInfo = CComponentInfo::NewL();
		User::LeaveIfError(iSif.Connect());

		// Our installer keeps temporary files under its private folder and therefore we have to
		// pass a file handle to the SIF API.
		User::LeaveIfError(iFs.Connect());
		iFs.ShareProtected();
		User::LeaveIfError(iFile.Open(iFs, node.FileNameL(), EFileShareReadersOnly));

		// Submit a SIF request 
		iSif.GetComponentInfo(iFile, *iComponentInfo, *RequestStatus());
		
		iSifRequestInProgress = ETrue;

		return ECreateComponentInfoNode;
		}
	else
		{
		iParser = CSifRefPkgParser::NewL(node.FileNameL());
		return EFindComponent;
		}
	}

TInt CSifRefGetComponentInfoTask::CreateComponentInfoNodeL()
	{
	DEBUG_PRINTF(_L8("CSifRefGetComponentInfoTask::CreateComponentInfoNodeL()"));
	
	SifRefBinPkgExtractor::CAuxNode& auxNode = *iEmbeddedComponents[iCurrentComponent];

	if (iSifRequestInProgress)
		{
		iSif.Close();
		iFile.Close();
		iFs.Close();
		
		iSifRequestInProgress = EFalse;
		
		// Add the root node of iComponentInfo to the tree
		User::LeaveIfError(RequestStatus()->Int());
		auxNode.SetCompInfoL(iComponentInfo);
		iComponentInfo = NULL;
		}
	else
		{
		// This reference installer uses the KExampleFileSize const value to calculate the maximum size of the installed
		// component on a phone. This is because the reference package file carries only the list of the files to be installed
		// without the files themselves. A real installer should use the size of the files to be installed.
		const TInt KExampleFileSize = 1024;
		const TInt maxInstalledSize = iParser->Files().Count() * KExampleFileSize;
		const TBool hasExe = EFalse;
		const TBool driveSelectionRequired = EFalse;
		RPointerArray<Usif::CComponentInfo::CApplicationInfo>* applications = NULL;
		// The example capabilities below are hardcoded due to the same reason. The reference package file doesn't contain
		// user grantable capabilities but a real package file should provide them.
		TCapabilitySet userGrantableCaps(ECapabilityReadUserData, ECapabilityWriteUserData);
	
		// Create a ComponentInfo node and set it as a root node.
		CComponentInfo::CNode* compInfoNode = CComponentInfo::CNode::NewLC(InstallHelper::KSifReferenceSoftwareType,
							*iCompSearchData.iName, iCompSearchData.iVersion, *iCompSearchData.iVendor,
							iCompSearchData.iScomoState, iCompSearchData.iInstallStatus, iCompSearchData.iComponentId,
							*iCompSearchData.iName, ENotAuthenticated, userGrantableCaps, maxInstalledSize, hasExe, driveSelectionRequired, applications);
		
		auxNode.SetNodeL(compInfoNode);
		CleanupStack::Pop(compInfoNode);
		}
	
	return (++iCurrentComponent < iEmbeddedComponents.Count()) ? EParsePkgFile : ESetComponentInfo;
	}

void CSifRefGetComponentInfoTask::SetComponentInfoL()
	{
	DEBUG_PRINTF(_L8("CSifRefGetComponentInfoTask::SetComponentInfoL()"));
	
	// At least one node must exist, otherwise we can't reach this point.
	ASSERT (iEmbeddedComponents.Count() > 0);
	
	// Build a real tree of the nodes from iEmbeddedComponents which is a flat list
	for (TInt i=iEmbeddedComponents.Count()-1; i>=1; --i)
		{
		iEmbeddedComponents[i]->RegisterChildToParentL();
		}
	
	// Set the tree built above as the root node of ComponentInfo().
	iEmbeddedComponents[0]->SetAsRootNodeL(*ComponentInfo());
	}

// =============================================================================================================

CSifRefInstallTask* CSifRefInstallTask::NewL(TTransportTaskParams& aParams, TInstallerUIHandlerFactory aUiHandlerFactory)
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::NewL()"));
	
	CSifRefInstallTask* self = new (ELeave) CSifRefInstallTask(aParams);
	CleanupStack::PushL(self);
	self->ConstructL(aUiHandlerFactory);
	CleanupStack::Pop(self);
	return self;
	}

CSifRefInstallTask::CSifRefInstallTask(TTransportTaskParams& aParams)
: CSifTransportTask(aParams, EFalse), iStep(EExtractEmbeddedPkgs)
	{
	}

CSifRefInstallTask::~CSifRefInstallTask()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::~CSifRefInstallTask()"));
	
	iFileList.Close();
	iFile.Close();
	iFs.Close();
	iScr.Close();
	iSts.Close();
	iEmbeddedComponents.Close();
	if (iSifRequestInProgress)
		{
		iSif.CancelOperation();
		}
	iSif.Close();
	delete iParser;
	delete iUiHandler;
	delete iOpaqueArguments;
	delete iOpaqueResults;
	}

void CSifRefInstallTask::ConstructL(TInstallerUIHandlerFactory aUiHandlerFactory)
	{
	if ((FileName() == NULL && FileHandle() == NULL) ||
		CustomArguments() == NULL ||
		CustomResults() == NULL)
		{
		User::Leave(KErrArgument);
		}

	iUiHandler = InstallHelper::CreateUiHandlerL(CustomArguments(), aUiHandlerFactory);
	}

TBool CSifRefInstallTask::ExecuteImplL()
	{
	DEBUG_PRINTF2(_L8("Exiting from CSifRefInstallTask::ExecuteImplL(), iStep = %d"), iStep);
	
	TBool done = EFalse;
	
	switch (iStep)
		{
		case EExtractEmbeddedPkgs:
			ExtractEmbeddedPkgsL();
			++iStep;
			break;

		case EParsePkgFile:
			iStep = ParsePkgFileL();
			break;

		case ELaunchForeignInstall:
			LaunchForeignInstallL();
			++iStep;
			break;

		case EFinishForeignInstall:
			FinishForeignInstallL();
			iStep = EParsePkgFile;
			break;

		case EFindAndCheckComponent:
			// Next step differs for ENewComponent and EUpgrade
			iStep = FindAndCheckComponentL();
			break;

		case EGetInstalledFileList:
			GetInstalledFileListL();
			++iStep;
			break;

		case EUnregisterAndDeleteFile:
			if (UnregisterAndDeleteFileL())
				{
				++iStep;
				}
			break;

		case ERegisterComponent:
			RegisterComponentL();
			++iStep;
			break;

		case ECopyFile:
			if (CopyFileL())
				{
				++iStep;
				}
			break;

		case ESetScomoState:
			iStep = SetScomoStateL();
			break;

		case ECommit:
			CommitL();
			done = ETrue;
			break;

		default:
			User::Leave(KErrGeneral);
		}

	if (!iSifRequestInProgress)
		{
		TRequestStatus* status(RequestStatus());
		User::RequestComplete(status, KErrNone);
		}
	
	DEBUG_PRINTF3(_L8("Exiting from CSifRefInstallTask::ExecuteImplL(), done = %d, iStep = %d"), done, iStep);
	
	return done;
	}

namespace
	{
	TInt AuxNodeSorter(const SifRefBinPkgExtractor::CAuxNode& aLeft, const SifRefBinPkgExtractor::CAuxNode& aRight)
		{
		const TBool l = aLeft.Foreign();
		const TBool r = aRight.Foreign();
		if (l == r)
			{
			return 0;
			}
		else if (!l && r)
			{
			return 1;
			}
		else
			{
			return -1;
			}
		}
	}

void CSifRefInstallTask::ExtractEmbeddedPkgsL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::ExtractEmbeddedPkgsL()"));
	
	// Start an STS transaction
	iSts.CreateTransactionL();

	if (FileName())
		{
		SifRefBinPkgExtractor::BuildPkgTreeL(iSts, *FileName(), KRefInstPrivateDir, iEmbeddedComponents);
		}
	else if (FileHandle())
		{
		SifRefBinPkgExtractor::BuildPkgTreeL(iSts, *FileHandle(), KRefInstPrivateDir, iEmbeddedComponents);
		}
	else
		{
		ASSERT(0);
		}
	
	// Sort the list of the embedded components in order to install foreign packages first
	 const TLinearOrder<SifRefBinPkgExtractor::CAuxNode> sortOrder(AuxNodeSorter);
	iEmbeddedComponents.Sort(sortOrder);
	}

TInt CSifRefInstallTask::ParsePkgFileL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::ParsePkgFileL()"));
	
	TInt nextStep = -1;
	TRAPD(err, nextStep = ParsePkgFileImplL());
	if (err != KErrNone)
		{
		if (iUiHandler)
			{
			iUiHandler->ErrorDescriptionUIHandler(InstallHelper::KUiParserErrorDesc);
			}
		User::Leave(err);
		}
	
	return nextStep;
	}

TInt CSifRefInstallTask::ParsePkgFileImplL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::ParsePkgFileImplL()"));
	
	delete iParser;
	iParser = NULL;

	// Check if the next component is of the type our installer supports. If yes, add it to the list of
	// the components to be processed. If not, use the SIF API to install it.
	const SifRefBinPkgExtractor::CAuxNode& node = *iEmbeddedComponents[iCurrentComponent];
	if (node.Foreign())
		{
		return ELaunchForeignInstall;
		}
	else
		{
		iParser = CSifRefPkgParser::NewL(node.FileNameL());
		return EFindAndCheckComponent;
		}
	}

void CSifRefInstallTask::LaunchForeignInstallL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::LaunchForeignInstallL()"));
	
	const SifRefBinPkgExtractor::CAuxNode& node = *iEmbeddedComponents[iCurrentComponent];
	
	// Connect to the SIF server
	User::LeaveIfError(iSif.Connect());

	// Our installer keeps temporary files under its private folder and therefore we have to
	// pass a file handle to the SIF API.
	User::LeaveIfError(iFs.Connect());
	iFs.ShareProtected();
	User::LeaveIfError(iFile.Open(iFs, node.FileNameL(), EFileShareReadersOnly));

	// Submit a SIF request 
	iOpaqueArguments = COpaqueNamedParams::NewL();
	iOpaqueResults = COpaqueNamedParams::NewL();
	iSif.Install(iFile, *iOpaqueArguments, *iOpaqueResults, *RequestStatus(), EFalse);

	iSifRequestInProgress = ETrue;
	}

void CSifRefInstallTask::FinishForeignInstallL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::FinishForeignInstallL()"));
	
	iSif.Close();
	iFile.Close();
	iFs.Close();
	delete iOpaqueArguments;
	iOpaqueArguments = NULL;
	delete iOpaqueResults;
	iOpaqueResults = NULL;
	
	// Check the result of the concurrent installation
	iSifRequestInProgress = EFalse;
	User::LeaveIfError(RequestStatus()->Int());
	
	// There must be at least one component left because we install foreign components first
	++iCurrentComponent;
	}

TInt CSifRefInstallTask::FindAndCheckComponentL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::FindAndCheckComponentL()"));
	
	// Connect to the SCR and create a new transaction to continue the installation of our own type
	if (!iScrTransaction)
		{
		User::LeaveIfError(iScr.Connect());
		iScr.CreateTransactionL();
		iScrTransaction = ETrue;
		}
	
	// Exit code
	TInt nextStep = ERegisterComponent;
	
	// Check if already installed
	InstallHelper::FindComponentL(iScr, iCompSearchData, *iParser);
	switch (iCompSearchData.iInstallStatus)
		{
		case ENewComponent:
			// nextStep already set to ERegisterComponent
			break;

		case EUpgrade:
			// Uninstall the previous version
			nextStep = EGetInstalledFileList;
			break;

		case EAlreadyInstalled:
			User::Leave(KErrSifSameVersionAlreadyInstalled);
			break;

		case ENewerVersionAlreadyInstalled:
			User::Leave(KErrSifNewerVersionAlreadyInstalled);
			break;

		default:
			ASSERT(0);
		}

	// Ask the user for the confirmation
	if (iUiHandler != NULL)
		{
		userConfirmationL(iCompSearchData.iInstallStatus == ENewComponent ? InstallHelper::EConfirmationInstall : InstallHelper::EConfirmationUpgrade, *iUiHandler, *iCompSearchData.iName, *iCompSearchData.iVendor);
		}

	return nextStep;
	}

void CSifRefInstallTask::GetInstalledFileListL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::GetInstalledFileListL()"));
	
	// Get a list of files to be deleted
	iFileList.OpenListL(iScr, iCompSearchData.iComponentId);
	}

TBool CSifRefInstallTask::UnregisterAndDeleteFileL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::UnregisterAndDeleteFileL()"));
	
	return InstallHelper::UnregisterAndDeleteFileL(iScr, iFileList, iSts, iCompSearchData.iComponentId);
	}

void CSifRefInstallTask::RegisterComponentL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::RegisterComponentL()"));
	
	// Register a new component in the SCR
	RCPointerArray<CLocalizableComponentInfo> componentInfoArray;
	CleanupClosePushL(componentInfoArray);

	// ...for each language
	const RLanguageArray& languages = iParser->Languages();
	const TInt langCount = languages.Count();
	for (TInt i=0; i<langCount; ++i)
		{
		const TDesC& locName = *iParser->ComponentNames()[i];
		const TDesC& locVendor = *iParser->VendorNames()[i];
		CLocalizableComponentInfo* componentInfo = CLocalizableComponentInfo::NewLC(locName, locVendor, languages[i]);
		componentInfoArray.AppendL(componentInfo);
		CleanupStack::Pop(componentInfo);
		}
	iCompSearchData.iComponentId = iScr.AddComponentL(componentInfoArray, InstallHelper::KSifReferenceSoftwareType);

	// Set the version of a new component
	iScr.SetComponentVersionL(iCompSearchData.iComponentId, iCompSearchData.iVersion);

	CleanupStack::PopAndDestroy(&componentInfoArray);

	iCopyFileIndex = 0;
	iComponentSize = 0;
	
	// Send the id if the installed component to the client. If this is a compound package we send the id of the root component only.
	if (iEmbeddedComponents[iCurrentComponent]->Root())
		{
		CustomResults()->AddIntL(KSifOutParam_ComponentId, iCompSearchData.iComponentId);
		}
	}

namespace
	{
	TBool CheckPathExistenceL(const TDesC& filePath)
		{
		TBool exists = EFalse;

		RFs fs;
		User::LeaveIfError(fs.Connect());
		CleanupClosePushL(fs);
		TEntry entry;
		TInt error = fs.Entry(filePath, entry);
		if (error == KErrNone)
			{
			exists = ETrue;
			}
		else if (error != KErrPathNotFound && error != KErrNotFound)
			{
			User::Leave(error);
			}
		
		CleanupStack::PopAndDestroy(&fs);
		
		return exists;
		}
	}

TBool CSifRefInstallTask::CopyFileL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::CopyFileL()"));
	
	// List of files to be copied from a package file 
	const RCHBufCArray& files = iParser->Files();

	// Register and copy a file if any left
	if (iCopyFileIndex < files.Count())
		{
		// The name of the current file
		const TDesC& filePath = *files[iCopyFileIndex];

		// Check if filePath already exists
		if (CheckPathExistenceL(filePath))
			{
			// Add a custom result describing the error
			HBufC* desc = HBufC::NewLC(InstallHelper::KErrFileAlreadyExists.iTypeLength + filePath.Length());
			TPtr bufDesc = desc->Des();
			bufDesc.Copy(InstallHelper::KErrFileAlreadyExists);
			bufDesc.Copy(filePath);
			CustomResults()->AddStringL(InstallHelper::KParamNameErrDesc, *desc);
			CleanupStack::PopAndDestroy(desc);
			}

		// Register the file in the SCR
		iScr.RegisterComponentFileL(iCompSearchData.iComponentId, filePath);

		// Copy the current file
		RFile file;
		iSts.CreateNewL(filePath, file, TFileMode(EFileShareExclusive |EFileWrite));
		_LIT8(KReferenceFootprint, "This file belongs to the SIF reference component.\n");
		const TInt numLines = 100; // The operation must take a while to simulate real copying
		for (TInt i=0; i<numLines; ++i)
			{
			User::LeaveIfError(file.Write(KReferenceFootprint));
			}
		iComponentSize += KReferenceFootprint.iTypeLength*numLines;
		file.Close();

		++iCopyFileIndex;
		}
	else
		{
		// Set the size of the component in the SCR
		iScr.SetComponentSizeL(iCompSearchData.iComponentId, iComponentSize);

		// Step complete, all the files have been copied
		return ETrue;
		}

	// Step not complete, there are still files left
	
	DEBUG_PRINTF(_L8("Exiting from CSifRefInstallTask::CopyFileL()"));
	
	return EFalse;
	}

TInt CSifRefInstallTask::SetScomoStateL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::SetScomoStateL()"));
	
	// Activate the newly added component
	TInt inactive = EFalse;
	if (!CustomArguments()->GetIntByNameL(_L("InstallInactive"), inactive) || !inactive)
		{
		iScr.SetScomoStateL(iCompSearchData.iComponentId, EActivated);
		}
	
	// Check if there are any components to be installed left
	return (++iCurrentComponent < iEmbeddedComponents.Count()) ? EParsePkgFile : ECommit;
	}

void CSifRefInstallTask::CommitL()
	{
	DEBUG_PRINTF(_L8("CSifRefInstallTask::CommitL()"));
	
	// Commit the STS & SCR transactions
	iSts.CommitL();
	iScr.CommitTransactionL();
	}

// =============================================================================================================

CSifRefUninstallTask* CSifRefUninstallTask::NewL(TTransportTaskParams& aParams, TInstallerUIHandlerFactory aUiHandlerFactory)
	{
	DEBUG_PRINTF(_L8("CSifRefUninstallTask::NewL()"));
	
	CSifRefUninstallTask* self = new (ELeave) CSifRefUninstallTask(aParams);
	CleanupStack::PushL(self);
	self->ConstructL(aUiHandlerFactory);
	CleanupStack::Pop(self);
	return self;
	}

CSifRefUninstallTask::CSifRefUninstallTask(TTransportTaskParams& aParams)
: CSifTransportTask(aParams), iStep(EGetFileList)
	{
	}

void CSifRefUninstallTask::ConstructL(TInstallerUIHandlerFactory aUiHandlerFactory)
	{
	if (ComponentId() == NULL || CustomArguments() == NULL || CustomResults() == NULL)
		{
		User::Leave(KErrArgument);
		}

	iUiHandler = InstallHelper::CreateUiHandlerL(CustomArguments(), aUiHandlerFactory);
	}

CSifRefUninstallTask::~CSifRefUninstallTask()
	{
	DEBUG_PRINTF(_L8("CSifRefUninstallTask::~CSifRefUninstallTask()"));
	
	// Make sure to close sub-session before the session
	iFileList.Close();	
	iScr.Close();
	iSts.Close();
	delete iUiHandler;
	}

TBool CSifRefUninstallTask::ExecuteImplL()
	{
	DEBUG_PRINTF2(_L8("CSifRefInstallTask::ExecuteImplL(), iStep = %d"), iStep);
	
	switch (iStep)
		{
		case EGetFileList:
			GetFileListL();
			break;

		case EUnregisterAndDeleteFile:
			if (!UnregisterAndDeleteFileL())
				{
				return EFalse;
				}
			break;

		case ECommit:
			CommitL();
			return ETrue;

		default:
			User::Leave(KErrGeneral);
		}

	++iStep;

	DEBUG_PRINTF2(_L8("Exiting from CSifRefInstallTask::ExecuteImplL(), iStep = %d"), iStep);
	
	return EFalse;
	}

void CSifRefUninstallTask::GetFileListL()
	{
	DEBUG_PRINTF(_L8("CSifRefUninstallTask::GetFileListL()"));
	
	// Connect to the SCR and start a transaction
	User::LeaveIfError(iScr.Connect());
	iScr.CreateTransactionL();

	// Ask the user for confirmation
	if (iUiHandler != NULL)
		{
		CComponentEntry* entry = CComponentEntry::NewLC();
		if (!iScr.GetComponentL(ComponentId(), *entry))
			{
			User::Leave(KErrNotFound);
			}
		userConfirmationL(InstallHelper::EConfirmationUninstall, *iUiHandler, entry->Name(), entry->Vendor());
		CleanupStack::PopAndDestroy(entry);
		}

	// Get a list of files to be deleted
	iFileList.OpenListL(iScr, ComponentId());

	// Start an STS transaction
	iSts.CreateTransactionL();
	}

TBool CSifRefUninstallTask::UnregisterAndDeleteFileL()
	{
	DEBUG_PRINTF(_L8("CSifRefUninstallTask::UnregisterAndDeleteFileL()"));
	
	return InstallHelper::UnregisterAndDeleteFileL(iScr, iFileList, iSts, ComponentId());
	}

void CSifRefUninstallTask::CommitL()
	{
	DEBUG_PRINTF(_L8("CSifRefUninstallTask::CommitL()"));
	
	// Commit the STS & SCR transactions
	iSts.CommitL();
	iScr.CommitTransactionL();
	}

// =============================================================================================================

CSifRefActivateDeactivateTask::CSifRefActivateDeactivateTask(TTransportTaskParams& aParams, TScomoState aScomoState)
: CSifTransportTask(aParams), iScomoState(aScomoState)
	{
	DEBUG_PRINTF(_L8("CSifRefActivateDeactivateTask::CSifRefActivateDeactivateTask()"));
	}

CSifRefActivateDeactivateTask::~CSifRefActivateDeactivateTask()
	{
	DEBUG_PRINTF(_L8("CSifRefActivateDeactivateTask::~CSifRefActivateDeactivateTask()"));
	
	iScr.Close();
	}

TBool CSifRefActivateDeactivateTask::ExecuteImplL()
	{
	DEBUG_PRINTF(_L8("CSifRefActivateDeactivateTask::ExecuteImplL()"));
	
	if (ComponentId() == NULL)
		{
		User::Leave(KErrArgument);
		}

	// Connect to SCR and activate/deactivate component
	User::LeaveIfError(iScr.Connect());
	iScr.SetScomoStateL(ComponentId(), iScomoState);

	return ETrue;
	}