commands/swi/swi.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 6 96d581d2147d
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// swi.cpp
// 
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//

#include "swi.h"
#include <fshell/common.mmh>
#include <fshell/ltkutils.h>

typedef TBuf<1> TUserInput;
_LIT(KSwiYes,	"y");
_LIT(KSwiNo,	"n");
_LIT(KSwiJarExtension,	"*.jar");
_LIT(KSwiJadExtension,	"*.jad");
#ifndef SYMBIAN_JAVA_NOT_INCLUDED
_LIT8(KDefaultJadMimeType, "text/vnd.sun.j2me.app-descriptor");
_LIT8(KDefaultJarMimeType, "application/java-archive");
#endif
_LIT(KDefaultMatch, "*");

//
// CCmdSwi
// class to handle the fshell console user interaction
//
CCommandBase* CCmdSwi::NewLC()
	{
	CCmdSwi* self = new(ELeave) CCmdSwi();
	CleanupStack::PushL(self);
	self->BaseConstructL();
	return self;
	}

CCmdSwi::~CCmdSwi()
	{
#ifndef SYMBIAN_JAVA_NOT_INCLUDED
	delete iMidletHandler;
#endif
	delete iSisHandler;
	delete iMatch;
	}

CCmdSwi::CCmdSwi():
CCommandBase(CCommandBase::EManualComplete)
	{
	SetExtension(this);
	}

const TDesC& CCmdSwi::Name() const
	{
	_LIT(KName, "swi");
	return KName;
	}

void CCmdSwi::ArgumentsL(RCommandArgumentList& aArguments)
	{
	aArguments.AppendEnumL((TInt&)iCommand, _L("operation"));

	_LIT(KArgFilename, "sis-file");
	aArguments.AppendFileNameL(iSisFile, KArgFilename);
	}
	
void CCmdSwi::OptionsL(RCommandOptionList& aOptions)
	{
	_LIT(KOptUid, "uid");
	aOptions.AppendUintL((TUint&)iUid.iUid, KOptUid);

	_LIT(KOptVerbose, "verbose");
	aOptions.AppendBoolL(iVerbose, KOptVerbose);

	_LIT(KOptQuiet, "quiet");
	aOptions.AppendBoolL(iQuiet, KOptQuiet);

	_LIT(KOptMatch, "match");
	aOptions.AppendStringL(iMatch, KOptMatch);
	}

void CCmdSwi::DoRunL()
	{
	if (iMatch == NULL)
		{
		iMatch = KDefaultMatch().AllocL();
		}

	iSisHandler = CSwiSisInstallerAO::NewL(*this, FsL(), iVerbose, iQuiet);
#ifndef SYMBIAN_JAVA_NOT_INCLUDED
	iMidletHandler = CSwiMidletInstallerAO::NewL(*this, FsL(), iVerbose, iQuiet);
#endif

	switch (iCommand)
		{
	case EList:
		//TODO matching
		TRAPL(iSisHandler->ListInstalledAppsL(iUid, *iMatch), _L("Couldn't list installed SIS files"));
#ifndef SYMBIAN_JAVA_NOT_INCLUDED
		TRAPL(iMidletHandler->ListInstalledAppsL(iUid, *iMatch), _L("Couldn't list installed midlets"));
#endif
		Complete(KErrNone);
		break;
		
	case EUninstall:
		if (!iOptions.IsPresent(&iUid))
			{
			LeaveIfErr(KErrArgument, _L("UID must be specified for \"uninstall\""));
			}
		TRAPD(error, iSisHandler->UninstallL(iUid));
		if (error != KErrNone)
			{
#ifndef SYMBIAN_JAVA_NOT_INCLUDED
			// possibly a midlet
			TRAP(error, iMidletHandler->UninstallL(iUid));
#endif
			}
		LeaveIfErr(error, _L("Failed to uninstall package 0x%08x"), iUid.iUid);
		break;
		
	case EInstall:
		if (!iArguments.IsPresent(1))
			{
			LeaveIfErr(KErrArgument, _L("SIS file must be specified for \"install\""));
			}
		User::LeaveIfError(Stdin().SetReadMode(RIoReadHandle::ELine));
#ifndef SYMBIAN_JAVA_NOT_INCLUDED
		if (IsMidlet())
			{
			TRAPL(iMidletHandler->InstallL(iSisFile), _L("Failed to install midlet '%S'"), &iSisFile);
			}
		else
#endif
			{
			TRAPL(iSisHandler->InstallL(iSisFile), _L("Failed to install sis '%S'"), &iSisFile);
			}
		break;
		}

	}
	
TBool CCmdSwi::IsMidlet()
	{
	if ((iSisFile.MatchF(KSwiJarExtension) != KErrNotFound) || (iSisFile.MatchF(KSwiJadExtension) != KErrNotFound))
		return ETrue;
	return EFalse;
	}

//
// CCmdSwi::GetAnswer
// only for use when not in quiet mode
// Reads input from stdin, determines whether it's a 'yes' or 'no', returning ETrue, EFalse respectively
//
TBool CCmdSwi::GetAnswer()
	{
	ASSERT(!iQuiet);
	TUserInput in;
	for (;;)
		{
		if (Stdin().Read(in) != KErrNone)
			{
			return EFalse;
			}
		Stdout().Write(in);
		if (in.MatchF(KSwiYes) == 0)
			{
			return ETrue;
			}
		if (in.MatchF(KSwiNo) == 0)
			{
			return EFalse;
			}
		// else it's an unrecognised response
		}
	}

//
// MCmdSwiParent hooks
//
RIoConsoleReadHandle& CCmdSwi::Input()
	{
	return Stdin();
	}

RIoConsoleWriteHandle& CCmdSwi::Output(TInt aError)
	{
	if (aError == KErrNone)
		{
		return Stdout();
		}
	return Stderr();
	}

//
// CCmdSwi::Finished
// callback from the underlying AO's RunL
//
void CCmdSwi::Finished(TInt aError)
	{
	Complete(aError);
	}

#define CASE_RETURN_LIT(XXX, YYY) case XXX: { _LIT(_KLit, #YYY); return &_KLit; }
const TDesC* CCmdSwi::StringifyError(TInt aError) const
	{
	switch (aError)
		{
		CASE_RETURN_LIT(-10100, KErrSISFieldIdMissing);
		CASE_RETURN_LIT(-10101, KErrSISFieldLengthMissing);
		CASE_RETURN_LIT(-10102, KErrSISFieldLengthInvalid);
		CASE_RETURN_LIT(-10103, KErrSISStringInvalidLength);
		CASE_RETURN_LIT(-10104, KErrSISSignedControllerSISControllerMissing);
		CASE_RETURN_LIT(-10105, KErrSISControllerSISInfoMissing);
		CASE_RETURN_LIT(-10106, KErrSISInfoSISUidMissing);
		CASE_RETURN_LIT(-10107, KErrSISInfoSISNamesMissing);
		CASE_RETURN_LIT(-10108, KErrSISFieldBufferTooShort);
		CASE_RETURN_LIT(-10109, KErrSISStringArrayInvalidElement);
		CASE_RETURN_LIT(-10110, KErrSISInfoSISVendorNamesMissing);
		CASE_RETURN_LIT(-10111, KErrSISInfoSISVersionMissing);
		CASE_RETURN_LIT(-10112, KErrSISControllerSISSupportedLanguagesMissing);
		CASE_RETURN_LIT(-10113, KErrSISSupportedLanguagesInvalidElement);
		CASE_RETURN_LIT(-10114, KErrSISLanguageInvalidLength);
		CASE_RETURN_LIT(-10115, KErrSISContentsSISSignedControllerMissing);
		CASE_RETURN_LIT(-10116, KErrSISContentsSISDataMissing);
		CASE_RETURN_LIT(-10117, KErrSISDataSISFileDataUnitMissing);
		CASE_RETURN_LIT(-10118, KErrSISFileDataUnitTargetMissing);
		CASE_RETURN_LIT(-10119, KErrSISFileOptionsMissing);
		CASE_RETURN_LIT(-10120, KErrSISFileDataUnitDescriptorMissing);
		CASE_RETURN_LIT(-10121, KErrSISFileDataDescriptionMissing);
		CASE_RETURN_LIT(-10122, KErrSISContentsMissing);
		CASE_RETURN_LIT(-10123, KErrSISEmbeddedControllersMissing);
		CASE_RETURN_LIT(-10124, KErrSISEmbeddedDataUnitsMissing);
		CASE_RETURN_LIT(-10125, KErrSISControllerOptionsMissing);
		CASE_RETURN_LIT(-10126, KErrSISExpressionMissing);
		CASE_RETURN_LIT(-10127, KErrSISExpressionStringValueMissing);
		CASE_RETURN_LIT(-10128, KErrSISOptionsStringMissing);
		CASE_RETURN_LIT(-10129, KErrSISFileOptionsExpressionMissing);
		CASE_RETURN_LIT(-10130, KErrSISExpressionHeadValueMissing);
		CASE_RETURN_LIT(-10131, KErrSISEmbeddedSISOptionsMissing);
		CASE_RETURN_LIT(-10132, KErrSISInfoSISUpgradeRangeMissing);
		CASE_RETURN_LIT(-10133, KErrSISDependencyMissingUid);
		CASE_RETURN_LIT(-10134, KErrSISDependencyMissingVersion);
		CASE_RETURN_LIT(-10135, KErrSISDependencyMissingNames);
		CASE_RETURN_LIT(-10136, KErrSISPrerequisitesMissingDependency);
		CASE_RETURN_LIT(-10137, KErrSISControllerMissingPrerequisites);
		CASE_RETURN_LIT(-10138, KErrSISUpgradeRangeMissingVersion);
		CASE_RETURN_LIT(-10139, KErrSISUnexpectedFieldType);
		CASE_RETURN_LIT(-10140, KErrSISExpressionUnknownOperator);
		CASE_RETURN_LIT(-10141, KErrSISArrayReadError);
		CASE_RETURN_LIT(-10142, KErrSISArrayTypeMismatch);
		CASE_RETURN_LIT(-10143, KErrSISInvalidStringLength);
		CASE_RETURN_LIT(-10144, KErrSISCompressionNotSupported);
		CASE_RETURN_LIT(-10145, KErrSISTooDeeplyEmbedded);
		CASE_RETURN_LIT(-10146, KErrSISInvalidTargetFile);
		CASE_RETURN_LIT(-10147, KErrSISWouldOverWrite);
		CASE_RETURN_LIT(-10148, KErrSISInfoMissingRemoveDirectories);
		CASE_RETURN_LIT(-10149, KErrSISNotEnoughSpaceToInstall);
		CASE_RETURN_LIT(-10200, KErrInstallerLeave);
		CASE_RETURN_LIT(-10250, KErrPolicyFileCorrupt);
		CASE_RETURN_LIT(-10251, KErrSignatureSchemeNotSupported);
		CASE_RETURN_LIT(-10252, KErrDigestNotSupported);
		CASE_RETURN_LIT(-10253, KErrBadHash);
		CASE_RETURN_LIT(-10254, KErrSecurityError);
		CASE_RETURN_LIT(-10263, KErrBadUsage);
		CASE_RETURN_LIT(-10260, KErrInvalidType); 
		CASE_RETURN_LIT(-10261, KErrInvalidExpression); 
		CASE_RETURN_LIT(-10262, KErrExpressionToComplex); 
		CASE_RETURN_LIT(-10255, KErrMissingBasePackage); 
		CASE_RETURN_LIT(-10256, KErrInvalidUpgrade); 
		CASE_RETURN_LIT(-10257, KErrInvalidEclipsing);
		CASE_RETURN_LIT(-10258, KErrWrongHeaderFormat);
		CASE_RETURN_LIT(-10259, KErrCapabilitiesMismatch); 
		CASE_RETURN_LIT(-10270, KErrLegacySisFile);
		CASE_RETURN_LIT(-10271, KErrInvalidSoftwareTypeRegistrationFile); 
		default:
			return NULL;
		}
	}

//
// Sis installer AO
//
CSwiSisInstallerAO* CSwiSisInstallerAO::NewL(MCmdSwiParent& aParent, RFs& aFs, TBool aVerbose, TBool aQuiet)
	{
	CSwiSisInstallerAO* self = new (ELeave) CSwiSisInstallerAO(aParent, aFs, aVerbose, aQuiet);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

CSwiSisInstallerAO::CSwiSisInstallerAO(MCmdSwiParent& aParent, RFs& aFs, TBool aVerbose, TBool aQuiet)
	: CActive(CActive::EPriorityStandard), iParent(aParent), iVerbose(aVerbose), iQuiet(aQuiet), iCurrentDrive('c')
	{
	TFileName sessionPath;
	TInt err = aFs.SessionPath(sessionPath);
	if (err == KErrNone)
		{
		iCurrentDrive = sessionPath[0];
		iCurrentDrive.LowerCase();
		}
	CActiveScheduler::Add(this);
	}

CSwiSisInstallerAO::~CSwiSisInstallerAO()
	{
	Cancel();
	delete iLauncher;
	delete iRegPackage;
	iRegistrySession.Close();
	delete iPrefs;
	}

void CSwiSisInstallerAO::ConstructL()
	{
	iLauncher = CAsyncLauncher::NewL();
	User::LeaveIfError(iRegistrySession.Connect());
	iPrefs = Swi::CInstallPrefs::NewL();
	iPrefs->SetPerformRevocationCheck(EFalse); // TODO - not currently supported in CCmdSwi
	}

void CSwiSisInstallerAO::RunL()
	{
	iParent.Finished(iStatus.Int());
	}

void CSwiSisInstallerAO::DoCancel()
	{
	iLauncher->CancelOperation();
	iParent.Finished(KErrCancel);
	}

void CSwiSisInstallerAO::PrintDetails(Swi::CSisRegistryPackage& aPackage)
	{
	if (iVerbose)
		{
		TName myBuf;
		myBuf.Format(_L("\r\nName:\t%S\r\n"), &aPackage.Name());
		Stdout().Write(myBuf);
		myBuf.Format(_L("Vendor:\t%S\r\n"), &aPackage.Vendor());
		Stdout().Write(myBuf);
		myBuf.Format(_L("Uid:\t0x%x\r\n"), aPackage.Uid());
		Stdout().Write(myBuf);
		}
	else
		{
		TBuf<256> buf; buf.Format(_L("0x%08x: "), aPackage.Uid());
		Stdout().Write(buf);
		Stdout().Write(aPackage.Name());
		Stdout().Write(_L("\r\n"));
		}
	}

void CSwiSisInstallerAO::InstallL(TFileName& aInstallFile)
	{
	// install regular sis file
	ASSERT(iPrefs);
	ASSERT(iLauncher);
	iLauncher->InstallL(*this, aInstallFile, *iPrefs, iStatus);
	SetActive();
	}

void CSwiSisInstallerAO::UninstallL(const TUid& aPackageUid)
	{
	// remove regular sis file
	ASSERT(iLauncher);
	ASSERT(!iRegPackage);
	Swi::CSisRegistryPackage* iRegPackage = GetSisRegistryPackageL(aPackageUid);
	iLauncher->UninstallL(*this, *iRegPackage, iStatus);
	SetActive();
	}

//
// CSwiSisInstallerAO::ListInstalledAppsL
// lists apps currently installed on the device
//
void CSwiSisInstallerAO::ListInstalledAppsL(const TUid& aAppUid, const TDesC& aMatchString)
	{
	if (aAppUid.iUid != 0)
		{
		DisplayPackageL(aAppUid);
		}
	else
		{
		ASSERT(iRegistrySession.Handle() > 0);
		RPointerArray<CSisRegistryPackage> packages;
		LtkUtils::CleanupResetAndDestroyPushL(packages);
		iRegistrySession.InstalledPackagesL(packages);
		if (packages.Count() <= 0)
			{
			User::Leave(KErrNotFound);
			}
		TInt count = 0;
		const TInt endCount = packages.Count();
		do
			{
			CSisRegistryPackage* current = packages[count++];
			if ((current->Name().MatchF(aMatchString) >= 0) || (current->Vendor().MatchF(aMatchString) >= 0))
				{
				PrintDetails(*current);
				}
			} while (count < endCount);
		CleanupStack::PopAndDestroy(&packages);
		}
	}

//
// CSwiSisInstallerAO::DisplayPackageL
// find information on the specified package uid and display it on the console
//
void CSwiSisInstallerAO::DisplayPackageL(const TUid& aPackageUid)
	{
	ASSERT(iRegistrySession.Handle() > 0);
	Swi::RSisRegistryEntry entry;
	User::LeaveIfError(entry.Open(iRegistrySession, aPackageUid));
	CleanupClosePushL(entry);
	Swi::CSisRegistryPackage* registryPackage = entry.PackageL();
	CleanupStack::PushL(registryPackage);
	PrintDetails(*registryPackage);
	CleanupStack::PopAndDestroy(2, &entry);	
	}

//
// CSwiSisInstallerAO::GetSisRegistryPackageL
// locate the sis registry package corresponding to the specified package ui
//
Swi::CSisRegistryPackage* CSwiSisInstallerAO::GetSisRegistryPackageL(const TUid& aPackageUid)
	{
	ASSERT(iRegistrySession.Handle() > 0);
	if (!iRegistrySession.IsInstalledL(aPackageUid))
		{
		User::Leave(KErrNotFound); // invalid uid
		}
	// else iterate through the installed packages to find ours
	RPointerArray<Swi::CSisRegistryPackage> packages;
	iRegistrySession.InstalledPackagesL(packages);
	if (packages.Count() <= 0)
		{
		User::Leave(KErrNotFound);
		}
	TInt count = 0;
	const TInt endCount = packages.Count();
	Swi::CSisRegistryPackage* found = NULL;
	do
		{
		Swi::CSisRegistryPackage* current = packages[count];
		 if (current->Uid() == aPackageUid)
			{
			found = current;
			break;
			}
		count++;
		} while (count < endCount);
	ASSERT(found); // IsInstalledL stated it's in there
	return found; 
	}

//
// SWI UI Hooks
//
TBool CSwiSisInstallerAO::DisplayTextL(const Swi::CAppInfo& /*aAppInfo*/, Swi::TFileTextOption /*aOption*/, const TDesC& aText)
	{
	TBool response = ETrue; // default, the user will continue with the installation/uninstallation
	if (!iQuiet)
		{
		Stdout().Write(aText);
		Stdout().Write(_L("Continue [y/n]?\r\n"));
		response = iParent.GetAnswer();
		}
	return response;
	}

void CSwiSisInstallerAO::DisplayErrorL(const Swi::CAppInfo& /*aAppInfo*/, Swi::TErrorDialog aType, const TDesC& /*aParam*/)
	{
	if (iVerbose)
		{
		switch (aType)
			{
			case Swi::EUiAlreadyInRom:
				Stderr().Write(_L("\r\nCannot overwrite a ROM component.\r\n"));
			break;
			
			case Swi::EUiMissingDependency:
				Stderr().Write(_L("\r\nMissing a dependency.\r\n"));
			break;
			
			case Swi::EUiRequireVer:
				Stderr().Write(_L("\r\nA dependency exists on a specific version of an application which is different from the one installed.\r\n"));
			break;

			case Swi::EUiFileCorrupt:
				Stderr().Write(_L("\r\nSISX file corrupt. Checksums stored in file do not match actual.\r\n"));
			break;

			case Swi::EUiDiskNotPresent:
				Stderr().Write(_L("\r\nAll your bases are belong to us. <disk not present>\r\n"));
			break;

			case Swi::EUiCannotRead:
				Stderr().Write(_L("\r\nCannot read a file which is needed in order to proceed.\r\n"));
			break;

			case Swi::EUiCannotDelete:
				Stderr().Write(_L("\r\nCannot delete a file.\r\n"));
			break;

			case Swi::EUiInvalidFileName:
				Stderr().Write(_L("\r\nA filename specified in the SISX package is not valid.\r\n"));
			break;

			case Swi::EUiInsufficientSpaceOnDrive:
				Stderr().Write(_L("\r\nInsufficient space on the drive.\r\n"));
			break;

			case Swi::EUiCapabilitiesCannotBeGranted:
				Stderr().Write(_L("\r\nApplication requires system capability it is not signed for.\r\n"));
			break;

			case Swi::EUiUnknownFile:
				Stderr().Write(_L("\r\nNot a recognised SISX file.\r\n"));
			break;

			case Swi::EUiMissingBasePackage:
				Stderr().Write(_L("\r\nA base package required for installation is not present.\r\n"));
			break;

			case Swi::EUiConstraintsExceeded:
				Stderr().Write(_L("\r\nConstraints imposed by a developer mode certificate have been exceeded.\r\n"));
			break;

			case Swi::EUiSIDViolation:
				Stderr().Write(_L("\r\nThe package contains a file with a protected SID which is not signed for.\r\n"));
			break;

			case Swi::EUiVIDViolation:
				Stderr().Write(_L("\r\nThe package contains a file with a protected VID which is not signed for.\r\n"));
			break;

			case Swi::EUiSIDMismatch:
				Stderr().Write(_L("\r\nMismatched SID.\r\n"));
			break;

			case Swi::EUiBlockingEclipsingFile:
				Stderr().Write(_L("\r\nThe package contains an invalid eclipsing file which is already in the device other than ROM.\r\n"));
			break;

			default:
				{
				TBuf<64> buf;
				buf.Format(_L("\r\nAn error %d has occured. Aborting.\r\n"), aType);
				Stderr().Write(buf);
				}
			break;
			};
		}
	}
	
TBool CSwiSisInstallerAO::DisplayDependencyBreakL(const Swi::CAppInfo& /*aAppInfo*/, const RPointerArray<TDesC>& /*aComponents*/)
	{
	TBool response = ETrue; // default response is to continue with uninstallation
	if (iVerbose)
		{
		Stdout().Write(_L("\r\nComponent being uninstalled has dependencies which may no longer work. Continue uninstalling [y/n]?\r\n"));
		response = iParent.GetAnswer();
		}
	return response;
	}

TBool CSwiSisInstallerAO::DisplayApplicationsInUseL(const Swi::CAppInfo& /*aAppInfo*/, const RPointerArray<TDesC>& /*aAppNames*/)
	{
	TBool response = EFalse; // EFalse indicates we don't continue with uninstallation
	if (!iQuiet)
		{
		Stdout().Write(_L("\r\nApplication is currently open. Continue uninstalling? [y/n]\r\n"));
		response = iParent.GetAnswer();
		}
	if (!response)
		{
		Stderr().Write(_L("Uninstall aborted. Application will not be closed.\r\n"));
		}
	return response;
	}

TBool CSwiSisInstallerAO::DisplayQuestionL(const Swi::CAppInfo& /* aAppInfo */, Swi::TQuestionDialog aQuestion, const TDesC& aDes)
	{
	TBool response = ETrue; // default behaviour assumes the user presses 'Yes' to any question
	if (!iQuiet)
		{
		if (aQuestion == Swi::EQuestionIncompatible)
			{
			Stdout().Write(_L("\r\nApplication is not compatible with this device. Install anyway [y/n]?"));
			}
		else if (aQuestion == Swi::EQuestionOverwriteFile)
			{
			Stdout().Write(_L("\r\nSome system files will be overwritten by this installation. Install anyway [y/n]?"));
			}
		else
			{
			TBuf<128> buf; buf.Format(_L("Unrecognised question from engine %d\r\n"), aQuestion);
			Stderr().Write(buf);
			User::Leave(KErrNotSupported);
			}

		if (aDes.Length() > 0)
			{
			Stdout().Write(aDes);
			}
		Stdout().Write(_L("\r\n"));
		response = iParent.GetAnswer();
		}
	return response;
	}
	
TBool CSwiSisInstallerAO::DisplayInstallL(const Swi::CAppInfo& aAppInfo, const CApaMaskedBitmap* /*aLogo*/, const RPointerArray<Swi::CCertificateInfo>& /*aCertificates*/)
	{
	if (iVerbose)
		{
		TBuf<256> myBuf;
		myBuf.Format(_L("NAME:\t\t%S\r\n"), &aAppInfo.AppName());
		Stdout().Write(myBuf);
		myBuf.Format(_L("VENDOR:\t\t%S\r\n"), &aAppInfo.AppVendor());
		Stdout().Write(myBuf);
		myBuf.Format(_L("VERSION:\t%d.%d.%d\r\n"), aAppInfo.AppVersion().iMajor, aAppInfo.AppVersion().iMinor, aAppInfo.AppVersion().iBuild);
		Stdout().Write(myBuf);
		}
	TBool response = ETrue; // default behaviour is to continue the install
	return response;
	}
	
TBool CSwiSisInstallerAO::DisplayGrantCapabilitiesL(const Swi::CAppInfo& /*aAppInfo*/, const TCapabilitySet& /*aCapabilitySet*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (iVerbose)
		{
		// todo verbose mode
		Stdout().Write(_L("\r\nTODO - CCmdSwi::DisplayGrantCapabilitiesL\r\n"));
		}
	return response;
	}
	
TInt CSwiSisInstallerAO::DisplayLanguageL(const Swi::CAppInfo& /*aAppInfo*/, const RArray<TLanguage>& /*aLanguages*/)
	{
	if (iVerbose)
		{
		// todo verbose mode
		Stdout().Write(_L("\r\nTODO - CCmdSwi::DisplayLanguageL\r\n"));
		}
	return 0; // the first language
	}
	
TInt CSwiSisInstallerAO::DisplayDriveL(const Swi::CAppInfo& /*aAppInfo*/, TInt64 aSize, const RArray<TChar>& aDriveLetters, const RArray<TInt64>& aDriveSpaces)
	{
	TInt response = 0; // default to the first known drive
	for (TInt i = 0; i < aDriveLetters.Count(); i++)
		{
		TChar letter = aDriveLetters[i];
		letter.LowerCase();
		if (letter == iCurrentDrive)
			{
			response = i; // Default to using the CWD drive, if it is in the list of available drives
			break;
			}
		}

	if (!iQuiet)
		{
		TBuf<128> info;
		info.Format(_L("Application requires %d bytes free space. Please select installation drive:\r\n"), aSize);
		Stdout().Write(info);
		for (TInt ii = 0 ; ii < aDriveLetters.Count() ; ii++)
			{
			info.Format(_L("%d. \'"), ii);		// pseudo-drive number
			info.Append(aDriveLetters[ii]);		// drive letter
			info.Append(_L("\' "));
			info.AppendNum(aDriveSpaces[ii]); // free space
			info.Append(_L(" bytes free\r\n"));
			Stdout().Write(info);
			}
		TUserInput in;
		User::LeaveIfError(Stdin().Read(in));
		TLex lex(in);
		User::LeaveIfError(lex.Val(response));
		}
	return response;
	}
	
TBool CSwiSisInstallerAO::DisplayUpgradeL(const Swi::CAppInfo& /*aAppInfo*/, const Swi::CAppInfo& /*aExistingAppInfo*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (!iQuiet)
		{
		Stdout().Write(_L("Do you wish to replace the existing installed application [y/n]?\r\n"));
		response = iParent.GetAnswer();
		}
	return response;
	}
	
TBool CSwiSisInstallerAO::DisplayOptionsL(const Swi::CAppInfo& /*aAppInfo*/, const RPointerArray<TDesC>& /*aOptions*/, RArray<TBool>& /*aSelections*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (iVerbose)
		{
		// todo verbose mode
		Stdout().Write(_L("TODO - CCmdSwi::DisplayOptionsL\r\n"));
		}
	return response;
	}
	
TBool CSwiSisInstallerAO::HandleInstallEventL(const Swi::CAppInfo& /*aAppInfo*/, Swi::TInstallEvent aEvent, TInt /*aValue*/, const TDesC& /*aDes*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (iVerbose)
		{
		switch (aEvent)
			{
			case Swi::EEventUpdateProgressBar:
				Stdout().Write(_L("."));
			break;
			
			case Swi::EEventCompletedInstall:
			case Swi::EEventCompletedUnInstall:
				{
				Stdout().Write(_L("\r\nComplete\r\n"));
				}
			break;

			default:
				// do nothing to inform the user of other cases
			break;
			};
		}
	return response;
	}
	
void CSwiSisInstallerAO::HandleCancellableInstallEventL(const Swi::CAppInfo& /*aAppInfo*/, Swi::TInstallCancellableEvent aEvent, Swi::MCancelHandler& /*aCancelHandler*/, TInt /*aValue*/, const TDesC& /*aDes*/)
	{
	if (iVerbose)
		{
		switch (aEvent)
			{
			case Swi::EEventRemovingFiles:
				{
				Stdout().Write(_L("\r\nRemoving files\r\n"));
				}
			break;
			
			case Swi::EEventShuttingDownApps:
				{
				Stdout().Write(_L("Closing App\r\n"));
				}
			break;

			case Swi::EEventCopyingFiles:
				{
				Stdout().Write(_L("Copying files\r\n"));
				}
			break;

			default:
			break;
			};
		}
	}

TBool CSwiSisInstallerAO::DisplaySecurityWarningL(const Swi::CAppInfo& /*aAppInfo*/, Swi::TSignatureValidationResult /*aSigValidationResult*/, RPointerArray<CPKIXValidationResultBase>& /*aPkixResults*/, RPointerArray<Swi::CCertificateInfo>& /*aCertificates*/, TBool /*aInstallAnyway*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (!iQuiet)
		{
		Stdout().Write(_L("\r\nApplication signature cannot be validated. Continue installing [y/n]?\r\n"));
		response = iParent.GetAnswer();
		}
	return response;
	}
	
TBool CSwiSisInstallerAO::DisplayOcspResultL(const Swi::CAppInfo& /*aAppInfo*/, Swi::TRevocationDialogMessage /*aMessage*/, RPointerArray<TOCSPOutcome>& /*aOutcomes*/, RPointerArray<Swi::CCertificateInfo>& /*aCertificates*/, TBool /*aWarningOnly*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (iVerbose)
		{
		// todo verbose mode
		Stdout().Write(_L("TODO - CCmdSwi::DisplayOcspResultL\r\n"));
		}
	return response;	
	}
	
void CSwiSisInstallerAO::DisplayCannotOverwriteFileL(const Swi::CAppInfo& /*aAppInfo*/, const Swi::CAppInfo& /*aInstalledAppInfo*/, const TDesC& aFileName)
	{
	if (iVerbose)
		{
		Stdout().Write(_L("\r\nCannot overwrite a file required for installation. Aborting -"));
		Stdout().Write(aFileName);
		Stdout().Write(_L(" - \r\n"));
		}
	}
	
TBool CSwiSisInstallerAO::DisplayMissingDependencyL(const Swi::CAppInfo& /*aAppInfo*/, const TDesC& aDependencyName, TVersion /*aWantedVersionFrom*/, TVersion /*aWantedVersionTo*/, TVersion /*aInstalledVersion*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (!iQuiet)
		{
		Stdout().Write(_L("Warning: Depedency is missing or has incorrect version - "));
		Stdout().Write(aDependencyName);
		Stdout().Write(_L(" - \r\n"));
		}
	return response;	
	}
	
TBool CSwiSisInstallerAO::DisplayUninstallL(const Swi::CAppInfo& aAppInfo)
	{
	if (iVerbose)
		{
		TName myBuf;
		myBuf.Format(_L("NAME:\t\t%S\r\n"), &aAppInfo.AppName());
		Stdout().Write(myBuf);
		myBuf.Format(_L("VENDOR:\t\t%S\r\n"), &aAppInfo.AppVendor());
		Stdout().Write(myBuf);
		myBuf.Format(_L("VERSION:\t%d.%d.%d\r\n"), aAppInfo.AppVersion().iMajor, aAppInfo.AppVersion().iMinor, aAppInfo.AppVersion().iBuild);
		Stdout().Write(myBuf);
		}
	TBool response = ETrue; // default behaviour is to continue the uninstall
	return response;	
	}

#ifndef SYMBIAN_JAVA_NOT_INCLUDED
//
// java ui installer
//
CSwiMidletInstallerAO* CSwiMidletInstallerAO::NewL(MCmdSwiParent& aParent, RFs& aFs, TBool aVerbose, TBool aQuiet)
	{
	CSwiMidletInstallerAO* self = new (ELeave) CSwiMidletInstallerAO(aParent, aFs, aVerbose, aQuiet);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

CSwiMidletInstallerAO::CSwiMidletInstallerAO(MCmdSwiParent& aParent, RFs& aFs, TBool aVerbose, TBool aQuiet)
	: CActive(CActive::EPriorityStandard), iParent(aParent), iFs(aFs), iVerbose(aVerbose), iQuiet(aQuiet)
	{
	CActiveScheduler::Add(this);
	}

CSwiMidletInstallerAO::~CSwiMidletInstallerAO()
	{
	Cancel();
	if (iInstaller)
		delete iInstaller;
	if (iJadHandle)
		iJadHandle->CloseFileHandle();
	if (iJarHandle)
		iJarHandle->CloseFileHandle();
	if (iInfo)
		delete iInfo;
	if (iRemover)
		delete iRemover;
	}

void CSwiMidletInstallerAO::ConstructL()
	{
	iInstaller = CJavaInstaller::NewL(*this, *this, KNullDesC8, EFalse, 0);
	}

TBool CSwiMidletInstallerAO::IsJad(TDes& aMidlet)
	{
	if (aMidlet.MatchF(KSwiJadExtension) > 0)
		return ETrue;
	return EFalse;
	}

TBool CSwiMidletInstallerAO::IsJar(TDes& aMidlet)
	{
	if (aMidlet.MatchF(KSwiJarExtension) > 0)
		return ETrue;
	return EFalse;
	}

void CSwiMidletInstallerAO::ListInstalledAppsL(TUid aAppUid, const TDesC& aMatchString)
	{
	MJavaRegistry* reg = MJavaRegistry::CreateL();
	RArray<TUid> list;
	TInt count = 0;
	CleanupStack::PushL(reg);
	if ((aAppUid.iUid != 0) && (reg->SuiteEntryExistsL(aAppUid)))
		{
		MJavaRegistrySuiteEntry* suite = reg->SuiteEntryL(aAppUid);
		CleanupStack::PushL(suite);
		suite->MIDletUidsL(list);
		while (count < list.Count())
			{
			MJavaRegistryMIDletEntry* entry = reg->MIDletEntryL(list[count++]);
			CleanupStack::PushL(entry);
			DisplayPackageL(*entry);
			CleanupStack::Pop(entry);
			entry->Release();
			}
		CleanupStack::Pop(suite);
		suite->Release();
		}
	else
		{
		reg->InstalledMIDletUidsL(list);
		while (count < list.Count())
			{
			MJavaRegistryMIDletEntry* entry = reg->MIDletEntryL(list[count++]);
			CleanupStack::PushL(entry);
			if ((entry->MIDletNameL().MatchF(aMatchString)>=0) || (entry->SuiteEntryL().VendorL().MatchF(aMatchString)>=0))
				{
				DisplayPackageL(*entry);
				}
			CleanupStack::Pop(entry);
			entry->Release();
			}
		}
	CleanupStack::Pop(reg);
	}

//
// CSwiMidleInstallerAO::DisplayPackageL
// find information on the specified package uid and display it on the console
//
void CSwiMidletInstallerAO::DisplayPackageL(MJavaRegistryMIDletEntry& aPackage)
	{
	TName myBuf;
	myBuf.Format(_L("\r\nNAME:\t%S\r\n"), &aPackage.MIDletNameL());
	Stdout().Write(myBuf);
	myBuf.Format(_L("VENDOR:\t%S\r\n"), &aPackage.SuiteEntryL().VendorL());
	Stdout().Write(myBuf);
	myBuf.Format(_L("UID:\t0x%x\r\n"), aPackage.SuiteEntryL().UidL());
	Stdout().Write(myBuf);
	}

//
// CSwiMidletInstallerAO::InstallL
// installs a jar/jad midp 1.0/2.0-compatible midlet
//
void CSwiMidletInstallerAO::InstallL(TFileName& aInstallFile)
	{
	ASSERT(iInstaller);
	ASSERT(!iInfo);
	ASSERT(!iJarHandle);
	ASSERT(!iJadHandle);
	if (aInstallFile.Length() <= 0)
		{
		User::Leave(KErrNotFound);
		}
	if (iVerbose)
		{
		Stdout().Write(_L("Installing Midlet...\r\n"));
		}
	const TInt length = aInstallFile.Length() - 3; // the java midlet filename minus the jad/jar extension name
	TFileName sisterFile(aInstallFile.Left(length));
	if (IsJad(aInstallFile))
		{
		iJadHandle = CJavaFileHandle::NewL(iFs, aInstallFile, KNullDesC, KDefaultJadMimeType());
		// name the associated jar file
		sisterFile.Append(_L("jar"));
		iJarHandle = CJavaFileHandle::NewL(iFs, sisterFile, KNullDesC, KDefaultJarMimeType());
		}
	else
		{
		ASSERT(IsJar(aInstallFile));
		iJarHandle = CJavaFileHandle::NewL(iFs, aInstallFile, KNullDesC, KDefaultJarMimeType());
		// name the associated jad file
		sisterFile.Append(_L("jad"));
		iJadHandle = CJavaFileHandle::NewL(iFs, sisterFile, KNullDesC, KDefaultJadMimeType());
		}
	iInfo = CMIDPInstallationLaunchInfo::NewL(iFs, *iJadHandle, *iJarHandle);
	iInstaller->Install(*iInfo, iStatus);
	SetActive();
	}

//
// CSwiMidletInstallerAO::Uninstall
// uninstalls a jar/jad midp 1.0/2.0-compatible midlet
//
void CSwiMidletInstallerAO::UninstallL(const TUid& aPackageUid)
	{
	ASSERT(!iRemover);
	if (iVerbose)
		{
		Stdout().Write(_L("Removing Midlet...\r\n"));
		}
	iRemover = CJavaRemover::NewL(aPackageUid, *this);
	iRemover->Remove(iStatus);
	SetActive();
	}

void CSwiMidletInstallerAO::RunL()
	{
	iParent.Finished(iStatus.Int());
	}

void CSwiMidletInstallerAO::DoCancel()
	{
	ASSERT(iInstaller);
	ASSERT(iRemover);
	iInstaller->Cancel();
	iRemover->Cancel();
	iParent.Finished(KErrCancel);
	}

//
// java installer UI hooks
//
TBool CSwiMidletInstallerAO::StartInstallL(const CMIDletSuiteAttributes& aMIDlet)
	{
	if (iVerbose)
		{
		TName myBuf;
		myBuf.Format(_L("\r\nNAME:\t\t%S\r\n"), &aMIDlet.MIDletName());
		Stdout().Write(myBuf);
		myBuf.Format(_L("VENDOR:\t\t%S\r\n"), &aMIDlet.MIDletVendor());
		Stdout().Write(myBuf);
		myBuf.Format(_L("VERSION:\t%d.%d.%d\r\n"), aMIDlet.MIDletVersion().iMajor, aMIDlet.MIDletVersion().iMinor, aMIDlet.MIDletVersion().iBuild);
		Stdout().Write(myBuf);
		}
	TBool response = ETrue; // default behaviour is to continue the install
	return response;
	}

TBool CSwiMidletInstallerAO::SelectDriveL(const CMIDletSuiteAttributes& /*aMIDlet*/, TInt aSpaceRequired, TChar& aDrive, TBool& aSufficientSpace)
	{
	aSufficientSpace = ETrue;
	aDrive = 'c';
	if (iQuiet)
		{
		// Default to CWD drive if writeable
		TFileName sessionPath;
		TInt err = iFs.SessionPath(sessionPath);
		if (err == KErrNone)
			{
			TChar drive = sessionPath[0];
			drive.LowerCase();
			TVolumeInfo volInfo;
			if (iFs.Volume(volInfo, ((TUint)drive)-'a') == KErrNone && volInfo.iFree >= aSpaceRequired && !(volInfo.iDrive.iDriveAtt & KDriveAttRom) && !(volInfo.iDrive.iMediaAtt & KMediaAttWriteProtected))
				{
				aDrive = drive;
				}
			}
		}
	else
		{
		// ask the question
		TBuf<128> info;
		info.Format(_L("Midlet requires %d bytes free space. Please select installation drive:\r\n"), aSpaceRequired);
		Stdout().Write(info);

		// cycle through drive list checking for existing drive
		TDriveList drives;
		TVolumeInfo volume;
		TChar driveChar;
		TBool displayed = EFalse;
		User::LeaveIfError(iFs.DriveList(drives));
		for (TInt ii = 0 ; ii < KMaxDrives ; ii++)
			{
			if (drives[ii])
				{
				// drive exists
				if (KErrNone == iFs.Volume(volume, ii))
					{
					// drive is present
					if (volume.iFree >= aSpaceRequired)
						{
						// drive has sufficient space
						aSufficientSpace = ETrue;
						if (!(volume.iDrive.iDriveAtt & KDriveAttRom) && 
							!(volume.iDrive.iMediaAtt & KMediaAttWriteProtected))
							{
							// drive is not a rom drive and is not write protected
							User::LeaveIfError(iFs.DriveToChar(ii, driveChar));
							info.Format(_L("%d. \'"), ii);		// drive number
							info.Append(driveChar);		// drive letter
							info.Append(_L("\' "));
							info.AppendNum(volume.iFree); // free space
							info.Append(_L(" bytes free\r\n"));
							Stdout().Write(info);
							displayed = ETrue;
							}
						}
					}
				}
			}
		// get the answer
		if (displayed)
			{
			TUserInput in;
			User::LeaveIfError(Stdin().Read(in));
			TLex lex(in);
			TInt response;
			User::LeaveIfError(lex.Val(response));
			User::LeaveIfError(iFs.DriveToChar(response, aDrive));
			}
		else
			{
			Stdout().Write(_L("Error. No drives capable of supporting midlet install. Aborting\r\n"));
			return EFalse;
			}
		}
	return ETrue;
	}

TBool CSwiMidletInstallerAO::ReplaceExistingMIDletL(const CMIDletSuiteAttributes& /*aMIDlet*/, const TAppVersion& /*aOldVersion*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (!iQuiet)
		{
		Stdout().Write(_L("Do you wish to replace the existing midlet [y/n]?\r\n"));
		response = iParent.GetAnswer();
		}
	return response;
	}
	
TBool CSwiMidletInstallerAO::UpgradeRMSL(const CMIDletSuiteAttributes& /*aMIDlet*/, const TAppVersion& /*aOldVersion*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (!iQuiet)
		{
		Stdout().Write(_L("Do you wish to upgrade the existing midlet [y/n]?\r\n"));
		response = iParent.GetAnswer();
		}
	return response;
	}

TBool CSwiMidletInstallerAO::MIDletUntrustedL(const CMIDletSuiteAttributes& /*aMIDlet*/)
	{
	TBool response = ETrue; // default behaviour is to continue the install
	if (!iQuiet)
		{
		Stdout().Write(_L("\r\nMidlet is untrusted. Continue installing [y/n]?\r\n"));
		response = iParent.GetAnswer();
		}
	return response;
	}

void CSwiMidletInstallerAO::CertificateHasNoRootL(const CMIDletSuiteAttributes& /*aMIDlet*/, const CPKIXCertChain& /*aCertChain*/, const CPKIXValidationResult& /*aValidationResult*/)
	{
	Stderr().Write(_L("\r\nCertificate attached to midlet has no identifiable root. Aborting installation.\r\n"));
	}

void CSwiMidletInstallerAO::BadSignatureL(const CMIDletSuiteAttributes& /*aMIDlet*/, const CPKIXCertChain& /*aCertChain*/, const CPKIXValidationResult& /*aValidationResult*/)
	{
	if (iVerbose)
		{
		Stdout().Write(_L("\r\nWarning: Midlet certificate chain is incomplete. Continuing installation\r\n"));
		}
	}

TBool CSwiMidletInstallerAO::PerformRevocationCheckL(TBool& aDoCheck)
	{
	aDoCheck = EFalse;
	return ETrue;
	}

void CSwiMidletInstallerAO::StartRevocationCheckL()
	{
	if (iVerbose)
		{
		Stdout().Write(_L("\r\nStarted: Revocation check\r\n"));
		}
	}

void CSwiMidletInstallerAO::FinishedRevocationCheckL()
	{
	if (iVerbose)
		{
		Stdout().Write(_L("\r\nFinished: Revocation check\r\n"));
		}
	}

void CSwiMidletInstallerAO::StartIconConversionL()
	{
	}

void CSwiMidletInstallerAO::FinishedIconConversionL()
	{
	}

TBool CSwiMidletInstallerAO::OCSPWarningL(const CMIDletSuiteAttributes& /*aMIDlet*/, TRevocationMsg /*aRevocationMsg*/, const TOCSPOutcome* /*aOCSPOutcome*/)
	{
	if (iVerbose)
		{
		Stdout().Write(_L("\r\nWarning: OCSP failure. Continuing installation.\r\n"));
		}
	return ETrue;
	}

void CSwiMidletInstallerAO::OCSPErrorL(const CMIDletSuiteAttributes& /*aMIDlet*/, TRevocationMsg /*aRevocationMsg*/, const TOCSPOutcome* /*aOCSPOutcome*/)
	{
	Stderr().Write(_L("\r\nOCSP Error. Aborting installation.\r\n"));
	}

TBool CSwiMidletInstallerAO::MIDletInUseL(const CMIDletSuiteAttributes& /*aMIDlet*/)
	{
	TBool response = EFalse; // EFalse indicates we don't continue with uninstallation
	if (!iQuiet)
		{
		// print the question
		Stdout().Write(_L("\r\nMidlet is currently open. Continue installing? [y/n]\r\n"));
		
		// get the answer
		TUserInput in;
		const TInt error = Stdin().Read(in);
		if ((error == KErrNone) && (in.MatchF(KSwiYes) == 0))
			{
			response = ETrue;
			}
		}
	if (!response)
		{
		Stderr().Write(_L("Uninstall aborted. Midlet has not been closed.\r\n"));
		}
	return response;
	}

void CSwiMidletInstallerAO::OTAReportResponseL(TInt aOTAResponseCode, const TDesC& /*aReportBody*/)
	{
	if (iVerbose)
		{
		switch (aOTAResponseCode)
			{
			case CJavaMIDletInstallationResult::EOkay:
				Stdout().Write(_L("\r\nComplete\r\n"));
			break;
			
			default:
				Stdout().Write(_L("Abort\r\n"));
			break;
			};
		}
	}

TInt CSwiMidletInstallerAO::CopyStarted(TInt /*aSize*/)
	{
	return KErrNone;
	}

TInt CSwiMidletInstallerAO::DownloadStarted(TInt /*aSize*/)
	{
	if (iVerbose)
		{
		Stdout().Write(_L("Downloading midlet\r\n"));
		}
	return KErrNone;
	}

TInt CSwiMidletInstallerAO::UpdateProgress(TInt /*aSize*/)
	{
	if (iVerbose)
		{
		Stdout().Write(_L("."));
		}
	return KErrNone;
	}

TBool CSwiMidletInstallerAO::GetUsernamePasswordL(HBufC8*& /*aUsername*/, HBufC8*& /*aPassword*/)
	{
	if (iVerbose)
		{
		Stdout().Write(_L("\r\nTODO: CCmdSwi::GetUsernamePasswordL\r\n"));
		}
	return EFalse;
	}

TBool CSwiMidletInstallerAO::ConfirmRemovalL(const TDesC& /*aRemovalMessage*/)
	{
	TBool response = ETrue; // default behaviour is to continue the uninstall
	return response;	
	}

void CSwiMidletInstallerAO::InitialiseProgressBarL(TInt /*aMaximumLength*/)
	{
	}

void CSwiMidletInstallerAO::UpdateProgressBarL(TInt /*aUnits*/)
	{
	if (iVerbose)
		{
		Stdout().Write(_L("."));
		}
	}

TBool CSwiMidletInstallerAO::MIDletInUseL()
	{
	TBool response = EFalse; // EFalse indicates we don't continue with uninstallation
	if (!iQuiet)
		{
		// print the question
		Stdout().Write(_L("\r\nApplication is currently open. Continue uninstalling? [y/n]\r\n"));
		
		// get the answer
		TUserInput in;
		const TInt error = Stdin().Read(in);
		if ((error == KErrNone) && (in.MatchF(KSwiYes) == 0))
			{
			response = ETrue;
			}
		}
	return response;
	}

TBool CSwiMidletInstallerAO::FileInUseL(const TDesC& /*aFileName*/)
	{
	TBool response = EFalse; // EFalse indicates we don't continue with uninstallation
	if (!iQuiet)
		{
		// print the question
		Stdout().Write(_L("\r\nApplication has a file handle open. Continue uninstalling? [y/n]\r\n"));
		
		// get the answer
		TUserInput in;
		const TInt error = Stdin().Read(in);
		if ((error == KErrNone) && (in.MatchF(KSwiYes) == 0))
			{
			response = ETrue;
			}
		}
	return response;
	}

#endif //  SYMBIAN_JAVA_NOT_INCLUDED

#ifdef EXE_BUILD
EXE_BOILER_PLATE(CCmdSwi)
#endif