/*
* Copyright (c) 1997-2009 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: 
* Application Processor.
*
*/


/**
 @file 
 @released
 @internalTechnology 
*/

#include <hash.h>
#include "installationprocessor.h"

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
#include <usif/sts/sts.h>
#include "swtypereginfo.h"
#include "installswtypehelper.h"
#else
#include "integrityservices.h"
#endif

#include "sisregistryentry.h"
#include "sishelperclient.h"
#include "sisregistryfiledescription.h"
#include "sisregistrypackage.h"
#include "sisstring.h"
#include "hashcontainer.h"
#include "siscontroller.h"
#include "application.h"
#include "userselections.h"
#include "log.h"
#include "secutils.h"
#include "sisuihandler.h"
#include "filesisdataprovider.h"
#include "securitymanager.h"
#include "securitypolicy.h"
#include "sislauncherclient.h"
#include "sisinfo.h"
#include "sisuid.h"
#include "plan.h"
#include "sidcache.h"
#include "sistruststatus.h"
#include "securitycheckutil.h"
#include "sisfieldtypes.h"
#include "progressbar.h"
#include "fileextractor.h"
#include "securitycheckutil.h"

using namespace Swi;


_LIT(KApparcRegDir, "\\private\\10003a3f\\import\\apps\\");
_LIT(KSisExt, ".sis");


const TInt KSwiDaemonUid = 0x10202DCE;

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
CInstallationProcessor* CInstallationProcessor::NewL(const CPlan& aPlan, CSecurityManager &aSecurityManager, 
	RSisHelper& aSisHelper, RUiHandler& aUiHandler, 
	Usif::RStsSession& aStsSession, CRegistryWrapper& aRegistryWrapper,
	const TDesC8& aControllerData, RSwiObserverSession& aObserver)
	{
	CInstallationProcessor* self = CInstallationProcessor::NewLC(aPlan, 
		aSecurityManager, aSisHelper, aUiHandler, aStsSession, aRegistryWrapper, 
		aControllerData, aObserver);
	CleanupStack::Pop(self);
	return self;
	}
#else
CInstallationProcessor* CInstallationProcessor::NewL(const CPlan& aPlan, CSecurityManager &aSecurityManager, 
	RSisHelper& aSisHelper, RUiHandler& aUiHandler, 
	CIntegrityServices& aIntegrityServices, const TDesC8& aControllerData, RSwiObserverSession& aObserver)
	{
	CInstallationProcessor* self = CInstallationProcessor::NewLC(aPlan, 
		aSecurityManager, aSisHelper, aUiHandler, aIntegrityServices, aControllerData, aObserver);
	CleanupStack::Pop(self);
	return self;
	}
#endif

CInstallationProcessor* CInstallationProcessor::NewL(CInstallationProcessor& aProcessor)
	{
	CInstallationProcessor* self = CInstallationProcessor::NewLC(aProcessor.Plan(), 
		aProcessor.iSecurityManager, aProcessor.iSisHelper, aProcessor.UiHandler(), 
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		aProcessor.TransactionSession(), aProcessor.iRegistryWrapper,
#else
		aProcessor.IntegrityServices(),
#endif
		aProcessor.iControllerData, aProcessor.Observer());
	CleanupStack::Pop(self);
	return self;
	}

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
CInstallationProcessor* CInstallationProcessor::NewLC(
	const CPlan& aPlan, CSecurityManager &aSecurityManager, 
	RSisHelper& aSisHelper, RUiHandler& aUiHandler, 
	Usif::RStsSession& aStsSession, CRegistryWrapper& aRegistryWrapper,
	const TDesC8& aControllerData, RSwiObserverSession& aObserver)
	{
	CInstallationProcessor* self = new(ELeave) CInstallationProcessor(aPlan, 
		aSecurityManager, aSisHelper, aUiHandler, aStsSession, aRegistryWrapper, 
		aControllerData, aObserver);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}
#else
CInstallationProcessor* CInstallationProcessor::NewLC(
	const CPlan& aPlan, CSecurityManager &aSecurityManager, 
	RSisHelper& aSisHelper, RUiHandler& aUiHandler, 
	CIntegrityServices& aIntegrityServices, const TDesC8& aControllerData, RSwiObserverSession& aObserver)
	{
	CInstallationProcessor* self = new(ELeave) CInstallationProcessor(aPlan, 
		aSecurityManager, aSisHelper, aUiHandler, aIntegrityServices, aControllerData, aObserver);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}
#endif

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
CInstallationProcessor::CInstallationProcessor(const CPlan& aPlan, 
	CSecurityManager &aSecurityManager, RSisHelper& aSisHelper, 
	RUiHandler& aUiHandler, Usif::RStsSession& aStsSession, 
	CRegistryWrapper& aRegistryWrapper,
	const TDesC8& aControllerData, RSwiObserverSession& aObserver)
	: CProcessor(aPlan, aUiHandler, aStsSession, aRegistryWrapper, aObserver), 
	iSecurityManager(aSecurityManager), 
	iSisHelper(aSisHelper),
	iControllerData(aControllerData)
	{
	}
#else
CInstallationProcessor::CInstallationProcessor(const CPlan& aPlan, 
	CSecurityManager &aSecurityManager, RSisHelper& aSisHelper, 
	RUiHandler& aUiHandler, CIntegrityServices& aIntegrityServices, 
	const TDesC8& aControllerData, RSwiObserverSession& aObserver)
	: CProcessor(aPlan, aUiHandler, aIntegrityServices, aObserver), 
	iSecurityManager(aSecurityManager), 
	iSisHelper(aSisHelper),
	iControllerData(aControllerData)
	{
	}
#endif

CInstallationProcessor::~CInstallationProcessor()
	{
	Cancel();
	
	delete iEmbeddedProcessor;
	delete iFileExtractor;
		
	iFilesToCopy.ResetAndDestroy();
	iApparcRegFiles.ResetAndDestroy();
	
	iLoader.Close();
	iSkipFile.Close();
	
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	iSoftwareTypeRegInfoArray.Close();
#endif
	}

void CInstallationProcessor::ConstructL()
	{
	User::LeaveIfError(iLoader.Connect());
		
	CProcessor::ConstructL();
	
	iFileExtractor=CFileExtractor::NewL(Fs(), iSisHelper, UiHandler(), Plan().AppInfoL());
	}

void CInstallationProcessor::DoCancel()
	{
	CProcessor::DoCancel();
	if (iEmbeddedProcessor && iEmbeddedProcessor->IsActive())
		{
		iEmbeddedProcessor->Cancel();
		}
	
	if (iFileExtractor->IsActive())
		{
		iFileExtractor->Cancel();
		}
	}

void CInstallationProcessor::DisplayFileL(const CSisRegistryFileDescription& aFileDescription, Sis::TSISFileOperationOptions aFileOperationOption)
	{
	// Default to continue
	TFileTextOption fileTextOption(EInstFileTextOptionContinue);
	bool forceAbortFlag = EFalse;
	if (aFileOperationOption & Sis::EInstFileTextOptionSkipIfNo)
		{
		fileTextOption=EInstFileTextOptionSkipOneIfNo;
		}
	else if (aFileOperationOption & Sis::EInstFileTextOptionAbortIfNo)
		{
		fileTextOption=EInstFileTextOptionAbortIfNo;
		}
	else if (aFileOperationOption & Sis::EInstFileTextOptionExitIfNo)
		{
		fileTextOption=EInstFileTextOptionExitIfNo;
		}
	else if (aFileOperationOption & Sis::EInstFileTextOptionForceAbort)
		{
		//converts FA option to TC option.
		fileTextOption=EInstFileTextOptionContinue;
		forceAbortFlag = ETrue;
		}
			
	TFileName temporaryFileName;
		
	TemporaryFileNameLC(aFileDescription, temporaryFileName);

	EnsureTemporaryInstallDirExistsL(temporaryFileName);

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	TransactionSession().RegisterTemporaryL(temporaryFileName);
#else
	IntegrityServices().TemporaryL(temporaryFileName);
#endif
		
	//	Extract this file to its temporary location.
	// However this file may have already been extracted, due to displaying it as
	// text, so we don't need to extract it again under this circumstance
	RFile temporaryFile;
	TInt err = temporaryFile.Create(Fs(), temporaryFileName, EFileWrite);
	if (err==KErrNone)
		{
		// We are passing the file handle to SISHelper but still need to close 
		// it here.
		CleanupClosePushL(temporaryFile);
		User::LeaveIfError(iSisHelper.ExtractFileL(Fs(), temporaryFile,
			aFileDescription.Index(), ApplicationL().AbsoluteDataIndex(), UiHandler()));
		CleanupStack::PopAndDestroy(&temporaryFile);
		}
	else if (err != KErrAlreadyExists)
		{
		User::Leave(err);
		}
		
	User::LeaveIfError(temporaryFile.Open(Fs(), temporaryFileName, EFileRead));
	CleanupClosePushL(temporaryFile);
	
	TInt fileSize=0;
	User::LeaveIfError(temporaryFile.Size( fileSize));
	HBufC8* text=HBufC8::NewMaxLC(fileSize);
	TPtr8 textPtr(text->Des());

	User::LeaveIfError(temporaryFile.Read(textPtr));	

	CDisplayText* displayText = NULL;

	displayText = CDisplayText::NewLC(Plan().AppInfoL(), fileTextOption, textPtr);
	UiHandler().ExecuteL(*displayText);

	switch (fileTextOption)
		{
		case EInstFileTextOptionContinue:
		//for FA option ,raise a TC dialog and abort the installation.
		if(forceAbortFlag)
			{
			User::Leave(KErrCancel);
			}
		break;
		
		case EInstFileTextOptionSkipOneIfNo:
			{
			iSkipFile.AppendL(displayText->ReturnResult());
			}
		break;
	
		case EInstFileTextOptionAbortIfNo:
		case EInstFileTextOptionExitIfNo:
		if (!displayText->ReturnResult())	
			{
			User::Leave(KErrCancel);
			}
		break;			
		}

	CleanupStack::PopAndDestroy(3, &temporaryFile);
	}

TBool CInstallationProcessor::ExtractFileL(CSisRegistryFileDescription& aFileToExtract)
	{
	DEBUG_PRINTF2(_L("Install Server - Installation Processor Extracting File '%S'"),
		&aFileToExtract.Target());
	
	if (ApplicationL().IsPreInstalledApp() || ApplicationL().IsPreInstalledPatch()
			|| aFileToExtract.Operation() == Sis::EOpNull)
		{
		// This file will not really be copied, but still need to update the progress bar.
		// Increment for extract stage (scaled by file size)
		TInt ammount = ProgressBarFileIncrement(aFileToExtract.UncompressedLength());
		// Increment for install/copy stage
		ammount += KProgressBarEndIncrement;
		UiHandler().UpdateProgressBarL(Plan().AppInfoL(), ammount);
		// move onto next file
		return EFalse;	
		}

	TFileName temporaryFileName;
		
	TemporaryFileNameLC(aFileToExtract, temporaryFileName);

	// Add to the list of files to copy
	CFileCopyDescription* fileCopyDescription=CFileCopyDescription::NewLC(
		temporaryFileName, aFileToExtract);
	User::LeaveIfError(iFilesToCopy.Append(fileCopyDescription));
	CleanupStack::Pop(fileCopyDescription);	// Ownership is transferred

	EnsureTemporaryInstallDirExistsL(temporaryFileName);

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	TransactionSession().RegisterTemporaryL(temporaryFileName);
#else
	IntegrityServices().TemporaryL(temporaryFileName);
#endif

	iFileExtractor->ExtractFileL(ApplicationL().AbsoluteDataIndex(), aFileToExtract, temporaryFileName, iStatus);
	return ETrue;
	}


void CInstallationProcessor::DoExtractHashL(const CSisRegistryFileDescription& aFileToProcess)
	{
	TParsePtrC targetPath(aFileToProcess.Target());
	// If the target is in sys\bin, write its hash into \sys\hash and name
	// it after the file.  The check in the process file state will ensure
	// that it must be a valid exe or dll to get this far.
	if (targetPath.Path().CompareF(KBinPath) == 0)
		{
		ExtractHashL(aFileToProcess.Target(), aFileToProcess.Hash());
		}	
	}

void CInstallationProcessor::CheckHashL(const CSisRegistryFileDescription& aFileToProcess, const TDesC& aCurrentFileName)
	{
	const CHashContainer& hash = aFileToProcess.Hash();
	
	// Calculate and check correct hash value
	CFileSisDataProvider* fileDataProvider=CFileSisDataProvider::NewLC(Fs(), aCurrentFileName);
	TBool hashIsValid=iSecurityManager.VerifyFileHashL(*fileDataProvider,hash);
	CleanupStack::PopAndDestroy(fileDataProvider);
	if (!hashIsValid)
		{
		User::Leave(KErrCorrupt);
		}
	}

	

void CInstallationProcessor::EnsureTemporaryInstallDirExistsL(const TDesC& aFileTarget)
	{
	TInt err = Fs().MkDirAll(aFileTarget);
	if (err!= KErrNone && err != KErrAlreadyExists)
		{
		User::LeaveIfError(err);
		}
	}

void CInstallationProcessor::TemporaryFileNameLC(const CSisRegistryFileDescription& aFileToExtract, TDes& aTemporaryFileName)
	{
	static TInt localTempCnt = 0;
	TChar drive;
	if(aFileToExtract.Target().Length())
		{
		// set temporary drive to be same as final target
		drive = aFileToExtract.Target()[0];
		}
	else
		{
		// set temporary drive to the user selected drive
		drive = ApplicationL().UserSelections().Drive();
		}
	 		
 	// If no drive has been selected then use the C drive for
 	// temporary files. This should only happen if the SIS file
 	// just contains text files to display but not install.
 	if (drive == TChar(KNoDriveSelected))
 		{
 		drive = iSystemDriveChar;
		}
	
	// construct the temporary filename
	// Format is  {Drive}:\sys\install\temp\file-{Data Unit}-{File Index}-{LocalCounter}
	_LIT(KTemporaryFileFormat, "%c:%Sfile-%d-%d-%d");
	TUint driveCh(drive); // Can't pass TChar to Format.
	
	aTemporaryFileName.Format(KTemporaryFileFormat, driveCh, &KSysInstallTempPath, 
							 ApplicationL().AbsoluteDataIndex(), aFileToExtract.Index(),
							 localTempCnt++);
	}

///\short Extracts executable hash from controller to file for the loader
void CInstallationProcessor::ExtractHashL(const TFileName& aFileName, 
	const CHashContainer& aHash)
	{	
	const TDesC8& hashData = aHash.Data();
		
	TBuf<32> hashPath;	
	TUint driveCh(iSystemDriveChar); // can't pass TChar to Format
	hashPath.Format(KHashPathFormat, driveCh, &KHashPath);	
	
	TParse hashFileName;
	hashFileName.Set(hashPath, &aFileName, NULL);
	TInt err = Fs().MkDirAll(hashFileName.DriveAndPath());
	if (err!=KErrNone && err!=KErrAlreadyExists)
		{
		User::LeaveIfError(err);
		}
	
	// If the hash already exists, leave with KErrAlreadyExists
	TEntry hashEntry;
	if ( KErrNone == Fs().Entry(hashFileName.FullName(), hashEntry))
		{
		User::Leave( KErrAlreadyExists );
		}

	DEBUG_PRINTF2(_L("Install Server - Installation Processor, extracting hash file '%S'"), 
		&(hashFileName.FullName()));

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	TransactionSession().RegisterNewL(hashFileName.FullName());
#else
	IntegrityServices().AddL(hashFileName.FullName());
#endif

	RFile file;
	User::LeaveIfError(file.Create(Fs(), hashFileName.FullName(), 
		EFileWrite|EFileShareExclusive|EFileStream));
	CleanupClosePushL(file);
	User::LeaveIfError(file.Write(hashData));
	CleanupStack::PopAndDestroy(&file);
	//Write a SWI event log for this hash file
	TUint8 fileFlag(EFileAdded);
	CObservationData *event = CObservationData::NewLC(hashFileName.FullName(),TUid::Null(),fileFlag);
	Observer().AddEventL(*event);
	CleanupStack::PopAndDestroy(event);
	}

void CInstallationProcessor::VerifyInstallPathL(const CSisRegistryFileDescription& aFileDescription)
	{
	// Check the target path of every file is legal
	SecurityCheckUtil::TProtectedDirectoryCheckError targetError;
	// sis file signed by Su Cert are allowed to install files in private dir 
	// without corresponding executable in the package.
	if (ApplicationL().IsInstallSuCertBased())
		{
		return;
		}

	TBool pathOk = SecurityCheckUtil::CheckProtectedDirectoriesL(
		aFileDescription.Target(), aFileDescription.Operation(), iSidsAdded, targetError);
	if (!pathOk)
		{
		/// Initialized to  EUiSIDMismatch to make RVCT Compiler happy / supress the warnings during ARM build.
		TErrorDialog uiError = EUiSIDMismatch;
		switch(targetError)
			{
			case SecurityCheckUtil::ESIDMismatch:
			uiError = EUiSIDMismatch;
			break;
			
			case SecurityCheckUtil::EInvalidFileName:
			uiError = EUiInvalidFileName;
			break;
			
			default:
			User::Leave(KErrNotSupported);
			}
		CDisplayError* cmd=CDisplayError::NewLC(Plan().AppInfoL(),uiError,KNullDesC);
		UiHandler().ExecuteL(*cmd);
		CleanupStack::PopAndDestroy(cmd);
		User::Leave(KErrAccessDenied);			
		}		
	}

void CInstallationProcessor::InstallFileL(const CFileCopyDescription& aFileCopyDescription)
	{
	DEBUG_PRINTF2(_L("Install Server - Installation Processor, installing file to '%S'"),
		&aFileCopyDescription.FileDescription().Target());
	
	// move file to it's final location
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	TransactionSession().RegisterNewL(aFileCopyDescription.FileDescription().Target());
#else
	IntegrityServices().AddL(aFileCopyDescription.FileDescription().Target());
#endif
	
	// Move try 1 of 3
	TInt err =Fs().Rename(aFileCopyDescription.TemporaryFileName(), aFileCopyDescription.FileDescription().Target());
	if(err != KErrNone)
		{
		// Move failed - maybe dir did not exist
		(void) Fs().MkDirAll(aFileCopyDescription.FileDescription().Target());
		// Move try 2 of 3
		err =Fs().Rename(aFileCopyDescription.TemporaryFileName(), aFileCopyDescription.FileDescription().Target());
		if(err != KErrNone)
			{
			// Maybe destination already exists?
			// Is this possible? Or would install have deleted file earlier!?!?

			// Clear Read only attributes and delete the file
			Fs().SetAtt(aFileCopyDescription.FileDescription().Target(), 0, KEntryAttReadOnly);
			
			iLoader.Delete(aFileCopyDescription.FileDescription().Target()); // ignore failure here since the rename will fail instead
			
			// Move try 3 of 3
			err =Fs().Rename(aFileCopyDescription.TemporaryFileName(), aFileCopyDescription.FileDescription().Target());
			}
		}

	User::LeaveIfError(err); // Did we manage to do the move?

	// Update progress bar for the copy/install of this file
	UiHandler().UpdateProgressBarL(Plan().AppInfoL(), KProgressBarEndIncrement);
	
	AddApparcFilesInListL(aFileCopyDescription.FileDescription().Target());

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	// Parse the file if it carries software type registration info
	if (InstallSoftwareTypeHelper::IsValidSwRegFileL(aFileCopyDescription.FileDescription().Target(),
													 ApplicationL().ControllerL().Info().Uid().Uid().iUid))
		{
		InstallSoftwareTypeHelper::ParseRegFileL(Fs(),
												 aFileCopyDescription.FileDescription().Target(),
												 iSoftwareTypeRegInfoArray);
		}
#endif

	// Launch the file if RI flag is set.
	if(ShouldLaunchL(aFileCopyDescription.FileDescription()))
		{
		LaunchFileL(aFileCopyDescription.FileDescription());
		}
	
	}

// State processing functions

TBool CInstallationProcessor::DoStateInitializeL()
	{
	iUiState = EInitialize;
	iCurrent = 0;
	iFilesToCopyCurrent = 0;
	iFilesToCopy.ResetAndDestroy();
	iApparcRegFiles.ResetAndDestroy();
	return ETrue;
	}
	
TBool CInstallationProcessor::DoStateProcessEmbeddedL()
	{
	if (iCurrent < ApplicationL().EmbeddedApplications().Count())
		{
		EmbeddedProcessorL().ProcessApplicationL(*ApplicationL().EmbeddedApplications()[iCurrent++], iStatus);
		WaitState(ECurrentState);
		return EFalse;
		}
	else
		{
		iCurrent = 0;
		return ETrue;
		}
	}
	
TBool CInstallationProcessor::DoStateProcessSkipFilesL()
	{
	TInt count = ApplicationL().FilesToSkipOnInstall().Count();
	// create a modifyable reference
	CApplication& app = const_cast <CApplication&>(ApplicationL());
	CPlan& plan = const_cast <CPlan&>(Plan());

	for (TInt i = 0; i < count; ++i)		
		{
		if (iSkipFile[i])
			{
			CSisRegistryFileDescription& fileDescription = *ApplicationL().FilesToSkipOnInstall()[i];
			app.AddFileL(fileDescription);
			plan.AddInstallFileForProgress(fileDescription.UncompressedLength());
			}
		}
	iCurrent = 0;
	return ETrue;	
	}
	
TBool CInstallationProcessor::DoStateExtractFilesL()
	{
	if (iCurrent < ApplicationL().FilesToAdd().Count())
		{
		if (iUiState != EExtractFiles)
			{
			iUiState = EExtractFiles;
			// Signal to UI we are extracting files
			CHandleCancellableInstallEvent* cmd = CHandleCancellableInstallEvent::NewLC(Plan().AppInfoL(), EEventCopyingFiles, 0, KNullDesC);
			UiHandler().ExecuteL(*cmd);
			CleanupStack::PopAndDestroy(cmd);
			}
			
		CSisRegistryFileDescription& fileDescription = *ApplicationL().FilesToAdd()[iCurrent++];
		
		if(ExtractFileL(fileDescription))
			{
			WaitState(ECurrentState);
			}
		else
			{
			SwitchState(ECurrentState);
			}
		return EFalse;
		}
	else
		{
		iCurrent = 0;
		return ETrue;
		}
	}

bool CInstallationProcessor::FileIsApparcReg(const TDesC& aFilename) const
	{
	TParsePtrC filename(aFilename);

	return filename.Path().CompareF(KApparcRegDir) == 0;
	}

TBool CInstallationProcessor::DoStateProcessFilesL()
	{
	DEBUG_PRINTF(_L8("Install Server - Processing Files"));
	if (iCurrent < ApplicationL().FilesToAdd().Count() )
		{
		CSisRegistryFileDescription& fileDescription = *ApplicationL().FilesToAdd()[iCurrent];
		
		if(fileDescription.Operation() != Sis::EOpNull)
			{
			if (ApplicationL().IsPreInstalledApp() || ApplicationL().IsPreInstalledPatch())
				{
				// For pre-installed SISes, filenames could be "e:\foo.txt", but we
				// want them to install successfully on "f:". So re-write stub file
				// references to be the same drive as where the SIS file is located
				TChar drive = ApplicationL().UserSelections().Drive();
				TFileName target = fileDescription.Target();
				target[0] = drive;
				
				// use filenames from the file descriptions
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
				TInt error = SecurityCheckUtil::ProcessFileL(ApplicationL(), Fs(), iSidsAdded,
					TransactionSession(), fileDescription, target);
#else
				TInt error = SecurityCheckUtil::ProcessFileL(ApplicationL(), Fs(), iSidsAdded,
					IntegrityServices(), fileDescription, target);
#endif
				if (error != KErrNone)
					{
					ReportErrorL(TErrorDialog(error));
					}
				
				// This is either preinstalled or is a propagation and as of Pdef115573 only files under /sys, /resource or 
				// which have the VERIFY tag set need to have their hashes checked.
				if ((fileDescription.OperationOptions() & Swi::Sis::EInstVerifyOnRestore) || SecurityCheckUtil::IsTargetTcbWriteProtected(fileDescription.Target()))
					{
					CheckHashL(fileDescription, target);
					}
				}
			else
				{
				// use temporary file names
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
				TInt error = SecurityCheckUtil::ProcessFileL(ApplicationL(), Fs(),
					iSidsAdded, TransactionSession(), fileDescription,
					iFilesToCopy[iFilesToCopyCurrent]->TemporaryFileName());
#else
				TInt error = SecurityCheckUtil::ProcessFileL(ApplicationL(), Fs(),
					iSidsAdded, IntegrityServices(), fileDescription,
					iFilesToCopy[iFilesToCopyCurrent]->TemporaryFileName());
#endif
				if (error != KErrNone)
					{
					ReportErrorL(TErrorDialog(error));
					}	
				CheckHashL(fileDescription, iFilesToCopy[iFilesToCopyCurrent]->TemporaryFileName());
				iFilesToCopyCurrent++;
				}
			}

		++iCurrent;
		SwitchState(ECurrentState);
		return EFalse;
		}
	else
		{
		
		// Finally, if this is an addition to an existing package, add SIDs from that
		// package to the list of SIDs attached to this package
		
		if (ApplicationL().IsPartialUpgrade() ||
			ApplicationL().IsAugmentation()	||
			ApplicationL().IsPreInstalledPatch())
			{
#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			RSisRegistrySession session;
			User::LeaveIfError(session.Connect());
			CleanupClosePushL(session);
#endif
			
			RSisRegistryEntry entry;
			// Planning stage already established the entry exists
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			TInt err = entry.Open(iRegistryWrapper.RegistrySession(), ApplicationL().ControllerL().Info().Uid().Uid());
#else
			TInt err = entry.Open(session, ApplicationL().ControllerL().Info().Uid().Uid());
#endif
			if (err == KErrNotFound)
			{
			  User::Leave(KErrMissingBasePackage);	
			}
			
			User::LeaveIfError(err);	
		  
			CleanupClosePushL(entry);
			
			RArray<TUid> preinstalledSids;
			CleanupClosePushL(preinstalledSids);
			entry.SidsL(preinstalledSids);
			
			TInt sids(preinstalledSids.Count());
			for (TInt i = 0; i < sids; ++i)
				{
				DEBUG_PRINTF2(_L("Install Server - Processing Files - Appending SID %08x"), preinstalledSids[i]);
				iSidsAdded.Append(preinstalledSids[i]);
				}
			
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			CleanupStack::PopAndDestroy(2, &entry); // presintalledSids
#else
			CleanupStack::PopAndDestroy(3, &session); // entry, presintalledSids
#endif
			
			}
		
		iCurrent = 0;
		return ETrue;
		}
	}

TBool CInstallationProcessor::DoStateVerifyPathsL()
	{
	if (iCurrent < ApplicationL().FilesToAdd().Count())
		{
		CSisRegistryFileDescription& fileDescription = *ApplicationL().FilesToAdd()[iCurrent++];
		VerifyInstallPathL(fileDescription);	
		SwitchState(ECurrentState);
		return EFalse;
		}
	else
		{
		iCurrent = 0;
		return ETrue;
		}
	}
	
TBool CInstallationProcessor::DoStateInstallFilesL()
	{
	if (ApplicationL().IsPreInstalledApp() || ApplicationL().IsPreInstalledPatch())
		{
		// Only need to install hash for files in pre-installed application.
		if (iCurrent < ApplicationL().FilesToAdd().Count())
			{
			const CSisRegistryFileDescription& fileDescription = *ApplicationL().FilesToAdd()[iCurrent++];
			
			if(fileDescription.Operation() != Sis::EOpNull)
				{
				DoExtractHashL(fileDescription);
				
				// Add apparc registerd files in list.
				AddApparcFilesInListL(fileDescription.Target());
				
				// Launch the file if RI flag is set.
				if(ShouldLaunchL(fileDescription))
					{
					LaunchFileL(fileDescription);
					}
					
				AddEventToLogL(fileDescription);
				}
				
			SwitchState(ECurrentState);
			return EFalse;
			}
		}
	else if (iCurrent < iFilesToCopy.Count())
		{
		const CFileCopyDescription& fileCopyDescription = *iFilesToCopy[iCurrent++];
		DoExtractHashL(fileCopyDescription.FileDescription());
		InstallFileL(fileCopyDescription);
		AddEventToLogL(fileCopyDescription.FileDescription());
		SwitchState(ECurrentState);
		return EFalse;
		}
	iCurrent = 0;
	return ETrue;
	}



TBool CInstallationProcessor::DoStateDisplayFilesL()
	{
	if (ApplicationL().IsPreInstalledApp() || ApplicationL().IsPreInstalledPatch())
		{
		return ETrue;
		}
	if (iCurrent < ApplicationL().FilesToDisplayOnInstall().Count())
		{		
		const CSisRegistryFileDescription& fileDescription = *ApplicationL().FilesToDisplayOnInstall()[iCurrent++];		
		DisplayFileL(fileDescription, fileDescription.OperationOptions());
		SwitchState(ECurrentState);
		return EFalse;
		}
	else
		{
		iCurrent = 0;
		return ETrue;
		}		
	}

TBool CInstallationProcessor::DoStateUpdateRegistryL()
	{
	// destroy the memory heavy file copy descriptions
	iFilesToCopy.ResetAndDestroy();

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	// Now that we are ready to make changes to the registry we start a transaction
	// Note that the commit/rollback action is subsequently taken by the later steps of the state machine
	iRegistryWrapper.StartMutableOperationsL();
#else
	RSisRegistryWritableSession session;
	User::LeaveIfError(session.Connect());
	CleanupClosePushL(session);
#endif
	
	TInt64 offset = 0;
	if (!ApplicationL().IsUninstall())
		{
		
		const Swi::Sis::CController& controller = ApplicationL().ControllerL();
	
		// If this is the top level controller, strip the type field from it
		// all controllers must be registered as if they were contained in a SIS
		// array
	
		offset = controller.DataOffset();
		if (offset == 0)
			{
			// top level controller
			offset = 4;
			TFileName fileName;
			// Check whether we should create a SIS stub
			if(IsApplicationPermittedInStub(ApplicationL())
				&& !iSisHelper.IsStubL()
				&& iSecurityManager.SecurityPolicy().AllowPackagePropagate() &&  IsStubSisFileRequiredL())  
				{
				TChar drive = ApplicationL().StubDrive();
				if(CheckEmbeddedAppsInstalledOnSameDrive(ApplicationL().EmbeddedApplications(), drive))
					{
					// Create a stub SIS file for the auto-propagation feature.
					CreateStubSisFileL(fileName);
					// Register the stub SIS file at SWI registry, so that it will be removed on unistallation.
					RegisterStubSisFileL(fileName);
					}
				}			
			
			// Check whether we are installing from an existing SIS stub
			if(iSisHelper.IsStubL())
				{
				// Check whether the controller was a preinstalled type
				// if so then it's a preinstalled stub, not a propagated app stub
				Sis::TInstallType installType = ApplicationL().ControllerL().Info().InstallType();
				if(installType != Sis::EInstPreInstalledPatch && installType != Sis::EInstPreInstalledApp)
					{
					// If we are installing from a removable media stub
					// we need to add the stub to the list of files to
					// remove during uninstall
					// we don't need to create it because we are 
					// already installing from a SIS stub
					iSisHelper.GetSisFileNameL(fileName);
					RegisterStubSisFileL(fileName);
					}
				else
					{
					// If this preinstalled package is deletable and the policy
					// allows deletion of pre-installed files, add the stub sis
					// file to the files to remove on uninstall.
					CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
					if (securityPolicy->DeletePreinstalledFilesOnUninstall()
						&& ApplicationL().IsDeletablePreinstalled())
						{
						// Get filename of stub sis file
						TFileName stubFile;
						iSisHelper.GetSisFileNameL(stubFile);
						RegisterStubSisFileL(stubFile);
						}
					}
				}
			}
		}
	
	TPtrC8 thisController(iControllerData.Mid(offset));
	
	if (ApplicationL().IsUpgrade() 
		 || ApplicationL().IsPartialUpgrade())
		{
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		if (iSoftwareTypeRegInfoArray.Count() > 0)
			{
			iRegistryWrapper.RegistrySession().UpdateEntryL(ApplicationL(), thisController, iSoftwareTypeRegInfoArray, TransactionSession().TransactionIdL());
			}
		else
			{
			iRegistryWrapper.RegistrySession().UpdateEntryL(ApplicationL(), thisController, TransactionSession().TransactionIdL());
			}
#else
		session.UpdateEntryL(ApplicationL(), thisController, IntegrityServices().TransactionId());
#endif
		}
	else if (ApplicationL().IsInstall()
				|| ApplicationL().IsAugmentation() 
				|| ApplicationL().IsPreInstalledApp()
				|| ApplicationL().IsPreInstalledPatch())
		{
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		if (iSoftwareTypeRegInfoArray.Count() > 0)
			{
			iRegistryWrapper.RegistrySession().AddEntryL(ApplicationL(), thisController, iSoftwareTypeRegInfoArray, TransactionSession().TransactionIdL());
			}
		else
			{
			iRegistryWrapper.RegistrySession().AddEntryL(ApplicationL(), thisController, TransactionSession().TransactionIdL());
			}
#else
		session.AddEntryL(ApplicationL(), thisController, IntegrityServices().TransactionId());
#endif
		}
	else if (ApplicationL().IsUninstall())
		{
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		iRegistryWrapper.RegistrySession().DeleteEntryL(ApplicationL().PackageL() , TransactionSession().TransactionIdL()); 
#else
		session.DeleteEntryL(ApplicationL().PackageL() , IntegrityServices().TransactionId());
#endif
		}

#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	CleanupStack::PopAndDestroy(&session);
#else
	// Registration of MIME types of the software types being installed to AppArc.
	// This operation is not transactional so it must be done after the software types
	// have been successfully registered to the SCR by the following calls:
	// RSisRegistryWritableSession::AddEntryL()
	// RSisRegistryWritableSession::UpdateEntryL()
	InstallSoftwareTypeHelper::RegisterMimeTypesL(iSoftwareTypeRegInfoArray);
#endif
	return ETrue;
	}

// CFileCopyDescription 

/*static*/ CInstallationProcessor::CFileCopyDescription* CInstallationProcessor::CFileCopyDescription::NewL(const TDesC& aTemporaryFileName, const CSisRegistryFileDescription& aFileDescription)
	{
	CFileCopyDescription* self=CFileCopyDescription::NewLC(aTemporaryFileName, aFileDescription);
	CleanupStack::Pop(self);
	return self;
	}

/*static*/ CInstallationProcessor::CFileCopyDescription* CInstallationProcessor::CFileCopyDescription::NewLC(const TDesC& aTemporaryFileName, const CSisRegistryFileDescription& aFileDescription)
	{
	CFileCopyDescription* self=new (ELeave) CFileCopyDescription(aFileDescription);
	CleanupStack::PushL(self);
	self->ConstructL(aTemporaryFileName);
	return self;
	}

CInstallationProcessor::CFileCopyDescription::CFileCopyDescription(const CSisRegistryFileDescription& aFileDescription)
	:iFileDescription(aFileDescription)
	{
	}

void CInstallationProcessor::CFileCopyDescription::ConstructL(const TDesC& aTemporaryFileName)
	{
	iTemporaryFileName=aTemporaryFileName.AllocL();
	}

CInstallationProcessor::CFileCopyDescription::~CFileCopyDescription()
	{
	delete iTemporaryFileName;	
	}

CInstallationProcessor& CInstallationProcessor::EmbeddedProcessorL()
	{
	if (!iEmbeddedProcessor)
		{
		iEmbeddedProcessor=CInstallationProcessor::NewL(*this);
		}
	return *iEmbeddedProcessor;
	}
	
void CInstallationProcessor::ReportErrorL(TErrorDialog aError)
	{
	CDisplayError* cmd=CDisplayError::NewLC(Plan().AppInfoL(),aError,KNullDesC);
	UiHandler().ExecuteL(*cmd);
	CleanupStack::PopAndDestroy(cmd);
	User::Leave(KErrSecurityError);	
	}

TBool CInstallationProcessor::CheckEmbeddedAppsInstalledOnSameDrive(RPointerArray<CApplication> aArray, TChar aDrive)
	{
	for(TInt i = 0; i < aArray.Count(); i++)
		{
		CApplication& application = *aArray[i];
		
		if(!IsApplicationPermittedInStub(application))
			{
			return EFalse;
			}	
		else if(application.StubDrive() != aDrive)
			{
			// Embedded Application must be installed on the same drive
			// as the parent application otherwise the removable media
			// stub will reference files outside the media card
			return EFalse;
			}
		else if(!CheckEmbeddedAppsInstalledOnSameDrive(application.EmbeddedApplications(), aDrive))
			{
			return EFalse;
			}
		}
	return ETrue;
	}

TBool CInstallationProcessor::IsApplicationPermittedInStub(const CApplication& aApplication)
	{
	if(	aApplication.IsPreInstalledApp() || 
		aApplication.IsPreInstalledPatch() ||
		aApplication.IsUninstall() ||
		aApplication.IsPartialUpgrade() ||
		!aApplication.CanPropagate())
		{
		// These installation types are not permitted in
		// a removable media stub
		// We cannot be certain that all required files will be present
		// on the media card when it is inserted into another device
		return EFalse;
		}
	else
		{
		return ETrue;
		}
	}


void CInstallationProcessor::CreateStubSisFileL(TFileName &aFileName)
	{
	// Do all this file stuff in SWI so we have necessary capabilities
	_LIT(KStubDelimiter,      "_");
	
	TUid appUid = ApplicationL().ControllerL().Info().Uid().Uid();
	TChar drive = ApplicationL().StubDrive();
	// build SwiDaemon Pathname
	aFileName.Append(drive);
	aFileName.Append(KDriveDelimiter);
	aFileName.Append(KPrivatePath);
	aFileName.AppendNumFixedWidth(KSwiDaemonUid, EHex, 8);
	aFileName.Append(KPathDelimiter);
	aFileName.AppendNumFixedWidth(appUid.iUid, EHex, 8);	
		
		
	Swi::Sis::TInstallType installType = ApplicationL().ControllerL().Info().InstallType();	
		
	switch(installType)
		{
		/* 
		If a device has more than one slot, we may install a PA/PP to a different media card. 
		In this case,we'll still create a stub SIS file even though we're installing from a media card.
		*/

		// If an Installation type is SA/PA then append _0 after the stub UID.
		case Swi::Sis::EInstInstallation:
		case Swi::Sis::EInstPreInstalledApp:
			{
			aFileName.Append(KStubDelimiter);
			aFileName.Append('0');	
			break;
			}
				
		// If an Installation type is SP/PP then append _augNumber+1 after the stub UID.
		case Swi::Sis::EInstPreInstalledPatch:
		case Swi::Sis::EInstAugmentation:
			{
#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			RSisRegistrySession session;
			User::LeaveIfError(session.Connect());
			CleanupClosePushL(session);
#endif

			RSisRegistryEntry entry;
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			User::LeaveIfError(entry.Open(iRegistryWrapper.RegistrySession(), appUid));
#else
			User::LeaveIfError(entry.Open(session, appUid));
#endif
			CleanupClosePushL(entry);	

			/*
			Get the Augmentations number and append the number in stub file name(DEF107470).
			This way we impose order on the installation sequence when the card is inserted on another device.
			Since SWI daemon processes stub files in alphabetic order, it will install augmentations only after the original package
			*/
			TInt augNumber = entry.AugmentationsNumberL();	
			User::LeaveIfError(augNumber);
			aFileName.Append(KStubDelimiter);
			aFileName.AppendFormat(_L("%d"),augNumber+1);
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
			CleanupStack::PopAndDestroy(&entry);
#else
			CleanupStack::PopAndDestroy(2, &session);
#endif
			break;
			}

		default: 
			/* 
			If it is not SA/PA/SP/PP, then this function shouldn't have been invoked, 
			as these are the only package types which can appear according to Functional Specification 
			on a media card.
			*/
			ASSERT(EFalse);
		}

	aFileName.Append(KSisExt);

	TEntry entry;
	if (KErrNone == Fs().Entry(aFileName, entry))
		{
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		TransactionSession().RemoveL(aFileName);
#else
		IntegrityServices().RemoveL(aFileName);	
#endif
		}

	// Notify integrity support that we've created a stub
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
	TransactionSession().RegisterNewL(aFileName);
#else
	IntegrityServices().AddL(aFileName);
#endif
			
	// create SwiDaemon Private directory on the target drive
	TInt ret = Fs().MkDirAll(aFileName);
	if (ret!= KErrNone && ret != KErrAlreadyExists)
		{
		User::Leave(ret);
		}

			
	// Create the stub file if required
	RFile file;
	User::LeaveIfError(file.Create(Fs(), aFileName, EFileStream | EFileWrite | EFileShareExclusive));
	CleanupClosePushL(file);
			
	TInt err = iSisHelper.CreateSisStub(file);
	CleanupStack::PopAndDestroy(&file);
		
	if(err != KErrNone)
		{
		// something went wrong while creating the stub
		// delete the incorrectly created file
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
		TransactionSession().RemoveL(aFileName);
#else
		IntegrityServices().RemoveL(aFileName);
#endif
		User::Leave(err);
		}
	}

void CInstallationProcessor::RegisterStubSisFileL(const TFileName &aFileName)
	{
	// Add the stub file to the list of files to be removed during uninstall
	CSisRegistryFileDescription* fileDescription 
			= CreateSisStubRegistryFileDescriptionLC(Fs(),aFileName);
		
	// cast away constness because we need to add a file to remove into the application
	CApplication& application  = const_cast<CApplication&>(ApplicationL());
	application.AddSisStubFileL(*fileDescription);
		
	CleanupStack::PopAndDestroy(fileDescription);
	}


TBool CInstallationProcessor::IsStubSisFileRequiredL()
	{
	// Check that drive is removable
	// we only write Stubs to removable media so they
	// will install when the same media card is inserted
	// in a different Symbian OS device
	TChar drive = ApplicationL().StubDrive();
	
	TDriveInfo driveInfo;
	TInt driveNum;
	RFs::CharToDrive(drive, driveNum);
	Fs().Drive(driveInfo, driveNum);
	
	if(driveInfo.iDriveAtt & KDriveAttRemovable)
		return ETrue;
	else
		return EFalse;
	}

CSisRegistryFileDescription* CInstallationProcessor::CreateSisStubRegistryFileDescriptionLC(RFs& aFs, const TDesC& aFileName)
	{
	_LIT(KDataTypeSisx, "x-epoc/x-sisx-app");
	
	// This will leave if the file does not exist
	CFileSisDataProvider* dataProvider = CFileSisDataProvider::NewLC(aFs, aFileName);
	
	// create a SHA1 hash of the Sis Stub file 
	HBufC8* hash = iSecurityManager.CalculateHashLC(*dataProvider, CMessageDigest::ESHA1);
	CHashContainer* hashContainer = CHashContainer::NewLC(CMessageDigest::ESHA1, *hash);

	TInt64 fileLength = 0;
	dataProvider->Seek(ESeekCurrent, fileLength);
	Sis::TSISFileOperationOptions options = static_cast<Sis::TSISFileOperationOptions>(0);
	
	CSisRegistryFileDescription *fileDescription = 
				CSisRegistryFileDescription::NewL(*hashContainer,
													aFileName,
													KDataTypeSisx(),
													Sis::EOpInstall,
													options,
													fileLength,
													0,
													KNullUid);
													

	CleanupStack::PopAndDestroy(3, dataProvider); // hashContainer, hash, dataProvider
	CleanupStack::PushL(fileDescription);
	return fileDescription; 
	}


void CInstallationProcessor::AddEventToLogL(const CSisRegistryFileDescription& aFileDescription)
/**
	Write an install file event into the swi observation log file.
	
	@param aFileDescription The file whose name will be written into the log file.
 */
	{
	TUint8 fileFlag(EFileAdded);
	TParsePtrC targetPath(aFileDescription.Target());
				
	if (0 == targetPath.Path().CompareF(KBinPath))
		{
		TEntry entry;
		TInt err = Fs().Entry(aFileDescription.Target(), entry);
		
		if(KErrNone == err && entry.IsTypeValid())
			{
			if(SecUtils::IsExe(entry))
				{//Set file exe flag.
				fileFlag |= Swi::EFileExe;
				}
			else if(SecUtils::IsDll(entry))
				{//Set file dll flag.
				fileFlag |= Swi::EFileDll;
				}
			}
		}
		
	CObservationData *event = CObservationData::NewLC(aFileDescription.Target(),aFileDescription.Sid(),fileFlag);
	Observer().AddEventL(*event);
	CleanupStack::PopAndDestroy(event);
	}

void CInstallationProcessor::LaunchFileL(const CSisRegistryFileDescription& aFileDescription)
	{
	if (iApparcRegFiles.Count() > 0)
		{
		// Ask the launcher to notify Apparc of any new reg files
		RSisLauncherSession launcher;
		CleanupClosePushL(launcher);
		User::LeaveIfError(launcher.Connect());
	
		launcher.NotifyNewAppsL(iApparcRegFiles);
		// clean up our list so we don't notify of the files twice
		iApparcRegFiles.ResetAndDestroy();
		
		CleanupStack::PopAndDestroy(&launcher);
		}

	// run the file
	RunFileL(aFileDescription.Target(), aFileDescription.MimeType(),
			aFileDescription.OperationOptions());
	}
	
TBool CInstallationProcessor::ShouldLaunchL(const CSisRegistryFileDescription& aFileDescription)
	{
	if (aFileDescription.Operation() == Sis::EOpRun && 
		aFileDescription.OperationOptions() & Sis::EInstFileRunOptionInstall)
		{
#ifdef SYMBIAN_SWI_RUN_ON_INSTALL_COMPLETE 
		return !(aFileDescription.OperationOptions() & Sis::EInstFileRunOptionAfterInstall);
#else
		return ETrue;
#endif	
		}
	return EFalse;
	}
	
void CInstallationProcessor::AddApparcFilesInListL(const TDesC& aTargetFileName)
	{
	if (FileIsApparcReg(aTargetFileName))
		{
		// we're installing a reg file so add it to our list. 
		HBufC* tmp = aTargetFileName.AllocLC();
		iApparcRegFiles.AppendL(tmp);
		CleanupStack::Pop(tmp);
		}		
	}
