javatools/javarestoreconverter/src.s60/restoreconvertmidlet.cpp
branchRCL_3
changeset 14 04becd199f91
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javatools/javarestoreconverter/src.s60/restoreconvertmidlet.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1310 @@
+/*
+* Copyright (c) 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: Java platform 2.0 javarestoreconverter process
+*
+*/
+
+
+#include <apacmdln.h>
+#include <apgcli.h>
+#include <driveinfo.h>
+#include <e32base.h>
+#include <pathinfo.h>
+#include <utf.h>
+#include <zipfile.h>
+
+#include "restoreconvertmidlet.h"
+
+#include "javacommonutils.h"
+#include "javaprocessconstants.h"
+#include "javastorage.h"
+#include "javastorageentry.h"
+#include "javastoragenames.h"
+#include "javasymbianoslayer.h"
+#include "javauids.h"
+#include "logger.h"
+
+
+using namespace java::storage;
+using namespace java::util;
+
+// MIDlet name and vendor max size is 255,
+// +1 added for terminating zero needed for logging
+const TInt KMaxBufferSize = 256;
+
+// character constants needed when parsing java attributes
+const TUint32 HT = 9;  // horizontal tab
+const TUint32 LF = 10; // line feed
+const TUint32 CR = 13; // carriage return
+const TUint32 SP = 32; // space
+const TUint32 COLON = 58; // ':'
+
+
+_LIT(KJarFileNameSuffix, ".jar");
+_LIT(KJadFileNameSuffix, ".jad");
+_LIT(KFLJarFileNameSuffix, ".dm");
+_LIT(KSDJarFileNameSuffix, ".dcf");
+_LIT(KSMCBackSplash, "\\");
+_LIT(KDriveText, "drive");
+_LIT(KMidletName, "MIDlet-Name");
+_LIT(KMidletVendor, "MIDlet-Vendor");
+_LIT(KManifestEntryName, "META-INF/MANIFEST.MF");
+
+// The directory where the java applications to be converted are searched from
+_LIT(KMidletSuiteInstallBasePath, ":\\Private\\102033E6\\MIDlets\\");
+
+
+/**
+ * To create new instance of this class.
+ *
+ * @param aFs - A reference to the file server.
+ * @return Reference to the object of this class.
+ * @exception If construction fails.
+ *
+ */
+CRestoreConvertMIDlet* CRestoreConvertMIDlet::NewLC(RFs& aFs)
+{
+    CRestoreConvertMIDlet* self = new(ELeave) CRestoreConvertMIDlet(aFs);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+}
+
+/**
+ * To do 1st phase construction for this object.
+ *
+ * Adds this active object to the scheduler.
+ *
+ * @param aFs - A reference to the file server.
+ */
+CRestoreConvertMIDlet::CRestoreConvertMIDlet(RFs& aFs) :
+        CActive(EPriorityStandard), iFs(aFs), iNumberOfAppsToInstall(0)
+{
+    CActiveScheduler::Add(this);
+}
+
+/**
+ * To do 2nd phase construction for this object.
+ *
+ * @exception If the method is not able to allocate necessary buffers.
+ */
+void CRestoreConvertMIDlet::ConstructL()
+{
+    iConvertServer = new(ELeave) RestoreServer();
+    iMIDletName    = HBufC::NewL(KMaxBufferSize);
+    iMIDletVendor  = HBufC::NewL(KMaxBufferSize);
+}
+
+/**
+ * Deletes this object.
+ * All allocated resources are released.
+ */
+CRestoreConvertMIDlet::~CRestoreConvertMIDlet()
+{
+    Cancel();
+    iInstallFiles.ResetAndDestroy();
+    iInstallFiles.Close();
+
+    iUninstallUids.clear();
+
+    iDirs.ResetAndDestroy();
+    iDirs.Close();
+
+    iIsJad.Reset();
+
+    delete iMIDletName;
+    iMIDletName = NULL;
+
+    delete iMIDletVendor;
+    iMIDletVendor = NULL;
+
+    delete iConvertServer;
+    iConvertServer = NULL;
+}
+
+/**
+ * To start silent installation.
+ */
+void CRestoreConvertMIDlet::Start()
+{
+    iState = EFindOutDeviceDrives;
+    CompleteRequest();
+}
+
+/**
+ * To stop whole preinstaller.
+ * Stops the active scheduler.
+ */
+void CRestoreConvertMIDlet::Exit()
+{
+    Deque();
+    CActiveScheduler::Stop();
+}
+
+/**
+ * To complete the request for this object.
+ *
+ * @Postconditions The following conditions are true immediately after
+ * returning from this method.
+ * - iStatus == KErrNone
+ * - IsActive() == ETrue
+ */
+void CRestoreConvertMIDlet::CompleteRequest()
+{
+    TRequestStatus *status = &iStatus;
+    User::RequestComplete(status, KErrNone);
+    if (!IsActive())
+    {
+        SetActive();
+    }
+}
+
+/**
+ * To run this active object.
+ *
+ * The state logic is:
+ *
+ * EFindOutDeviceDrives:
+ *    - find out all non-remote drives in the device
+ *    - mark externally mountable drives (removable drives)
+ *    - mark read only drives (ROM)
+ *
+ * EGetDriveToBeScanned:
+ *    - the drive to be scanned has been given as command line argument,
+ *      store it to iDrive
+ *
+ * EAppsInInstalledDirectories:
+ *    - go through all directories in iDirs one by one
+ *      and find all java applications in the subdirectories of the directory
+ *    - if only .jar/.dcf/.dm file is found it is added to iInstallFiles
+ *    - if .jad file is found, it is added to iInstallFiles
+ *
+ * EUninstallFromOMJ:
+ *   - uninstall all OMJ java applications in drive iDrive using Java Installer
+ *     command line options 'uninstallall -drive=<iDrive>'
+ *   - then for each java application in iInstallFiles try to find it from
+ *     Java Storage based on MIDlet suite name and vendor name. If the MIDlet
+ *     is still installed to OMJ (to some other drive than iDrive), it must
+ *     be uninstalled from OMJ to reset the state of MIDlet (RMS data etc)
+ *     to original state. The actual uninstallation is not done in this
+ *     state, the uids of the applications to be uninstalled are just added to
+ *     iUninstallUids in string format
+ *
+ * EExecuteRestoreServer:
+ *  - give list of uninstall uids and list of install files to restore server
+ *  - start restore server in another thread (it will listen to Comms messages)
+ *  - start Java Installer in poll mode
+ *  - when Java Installer polls for operations to be executed, the restore server
+ *    will first ask it to uninstall each Java application in the list of uninstall uids,
+ *    then restore server will ask Java Installer to install each .jad or .jar/.dcf/.dm file
+ *    in the list of install files.
+ *    Restore server will log whether each uninstallation / installation succeeds.
+ *  - after all uninstallations and installations have been done, restore server will ask
+ *    Java Installer to exit.
+ *  - after that this active object moves to next state.
+ *
+ * EExit: free resources and exit
+ *
+ */
+void CRestoreConvertMIDlet::RunL()
+{
+    switch (iState)
+    {
+    case EFindOutDeviceDrives:
+    {
+        LOG(EJavaConverters, EInfo,
+            "CRestoreConvertMIDlet::RunL EFindOutDeviceDrives");
+        GetAllDeviceDrivesL();
+        iState = EGetDriveToBeScanned;
+        CompleteRequest();
+    }
+    break;
+
+    case EGetDriveToBeScanned:
+    {
+        LOG(EJavaConverters, EInfo,
+            "CRestoreConvertMIDlet::RunL EGetDriveToBeScanned");
+
+        HBufC *pBufCmdLine = HBufC::NewLC(User::CommandLineLength() + 10);
+        TPtr args = pBufCmdLine->Des();
+        User::CommandLine(args);
+        LOG1WSTR(EJavaConverters, EInfo,
+                 "Command line arguments of javarestoreconverter.exe are : %s",
+                 (wchar_t *)(args.PtrZ()));
+
+        // Check which drive is to be restored now from command line.
+        TDriveNumber drive = EDriveC;
+        TInt idx = args.Find(KDriveText());
+        if (KErrNotFound == idx)
+        {
+            LOG1WSTR(EJavaConverters, EError,
+                     "no -drive<X> argument in javarestoreconveter.exe command line (%s)",
+                     (wchar_t *)(args.PtrZ()));
+            User::Leave(KErrNotFound);
+        }
+
+        TChar driveChar = args[idx + KDriveText().Length()];
+        char argLetter = args[idx + KDriveText().Length()];
+        if (argLetter >= 'A' && argLetter <= 'J')
+        {
+            drive = (TDriveNumber)(argLetter - 'A');
+        }
+        else if (argLetter >= 'a' && argLetter <= 'j')
+        {
+            drive = (TDriveNumber)(argLetter - 'a');
+        }
+        else
+        {
+            User::Leave(KErrArgument);
+        }
+        CleanupStack::PopAndDestroy(pBufCmdLine);
+        iDrive = drive;
+
+        LOG1(EJavaConverters, EInfo, "Drive is %d", drive);
+
+        // forget old search directories
+        iDirs.ResetAndDestroy();
+
+        // The specified drive will be scanned for
+        // java applications to be converted
+        if (iDriveStatuses[drive] & DriveInfo::EDrivePresent)
+        {
+            (void)iFs.DriveToChar(drive, driveChar);
+
+            // The base Java application install directory in this
+            // drive must be scanned.
+            // Reserve memory also for drive letter and terminating zero
+            // for logging.
+            HBufC *baseInstallDir = HBufC::NewLC(KMidletSuiteInstallBasePath().Length() + 2);
+
+            TPtr dirPtr(baseInstallDir->Des());
+            dirPtr.Append(driveChar);
+            dirPtr.Append(KMidletSuiteInstallBasePath());
+
+            // Add new search directory
+            iDirs.AppendL(baseInstallDir);
+            CleanupStack::Pop(baseInstallDir);
+        }
+        else
+        {
+            // Restoring MIDlets to drive X but drive X is not present
+            ELOG1(EJavaConverters,
+                  "javarestoreconverter.exe: Drive number %d is not present", drive);
+            User::Leave(KErrDisMounted);
+        }
+
+        iState = EAppsInInstalledDirectories;
+        CompleteRequest();
+    }
+    break;
+
+    case EAppsInInstalledDirectories:
+    {
+        LOG(EJavaConverters, EInfo,
+            "CRestoreConvertMIDlet::RunL EAppsInInstalledDirectories");
+
+        GetInstallFilesL(iDirs);
+
+
+        iState = EUninstallFromOMJ;
+        CompleteRequest();
+    }
+    break;
+
+    case EUninstallFromOMJ:
+    {
+        LOG(EJavaConverters, EInfo,
+            "CRestoreConvertMIDlet::RunL EUninstallFromOMJ");
+
+        // Uninstall all Java applications in current drive
+        UninstallAllFromDriveL(iDrive);
+
+        // Check all Jad / Jar files in iInstallFiles and
+        // add the Uids of those MIDlets still installed into OMJ
+        // to iUninstallUids
+        FindRemainingMIDletsToBeUninstalledL();
+
+        iState = EExecuteRestoreServer;
+        CompleteRequest();
+    }
+    break;
+
+    case EExecuteRestoreServer:
+    {
+        LOG(EJavaConverters, EInfo,
+            "CRestoreConvertMIDlet::RunL EExecuteRestoreServer");
+
+        if (iNumberOfAppsToInstall > 0)
+        {
+            // Uninstall all MIDlet suites in iUninstallUids and then
+            // install all MIDlet suites in iInstallFiles.
+
+            // Tell RestoreServer what should be uninstalled and what
+            // should be converted
+            iConvertServer->setOperations(iInstallFiles, iUninstallUids);
+
+            // Start the server
+            int err = iConvertServer->start();
+            if (0 != err)
+            {
+                // server cannot be started
+                ELOG1(EJavaConverters,
+                      "Cannot start convert server, err %d", err);
+            }
+
+            // Starts Java Installer, waits until Java Installer exits
+            RunJavaInstallerL();
+
+            iState = EExit;
+        }
+        else
+        {
+            iState = EExit;
+            CompleteRequest();
+        }
+    }
+    break;
+
+    case EExit:
+    {
+        LOG(EJavaConverters, EInfo, "CRestoreConvertMIDlet::RunL EExit");
+
+        // Stops the server if it is running
+        iConvertServer->stop();
+
+        FullCleanup();
+
+        // The whole javaappconverter process is stopped.
+        Exit();
+    }
+    break;
+    }
+}
+
+/**
+ * To handle leave from RunL.
+ * This method exits this active object using normal state machine
+ * After calling this method this active object will exit.
+ *
+ * @param aError - A reason of error.
+ * @return KErrNone.
+ */
+TInt CRestoreConvertMIDlet::RunError(TInt aError)
+{
+    ELOG2(EJavaConverters,
+          "CRestoreConvertMIDlet::RunError(%d) from state %d", aError, iState);
+
+    Cancel();
+
+    iState = EExit;
+    CompleteRequest();
+
+    return KErrNone;
+}
+
+/**
+ * To do cancelling for this object.
+ *
+ */
+void CRestoreConvertMIDlet::DoCancel()
+{
+    ELOG1(EJavaConverters,
+          "CRestoreConvertMIDlet::DoCancel from state %d", iState);
+
+    // Check whether restore server must be stopped
+    if (iState == EExecuteRestoreServer)
+    {
+        // Stops the server if it is running
+        iConvertServer->stop();
+    }
+}
+
+/**
+ * Add .jad files in the directories specified in aDirs to iInstallFiles.
+ * If a directory does not contain a .jad file but it contains a .jar/.dcf/.dm file,
+ * add that file to iInstallFiles
+ *
+ * @param aDirs - An array of directories to be scanned.
+ * @exception Unable to alloc memory for the internal buffers.
+ * @exception Unable to get directory's contents.
+ */
+void CRestoreConvertMIDlet::GetInstallFilesL(RPointerArray<HBufC>& aDirs)
+{
+    // Number of MIDlet installation base directories to scan,
+    // one directory per local drive
+    const TInt nBaseDirs = aDirs.Count();
+
+    for (TInt i = 0; i < nBaseDirs; i++)
+    {
+        TFileName suitePath;
+
+        // Form base directory path, MIDlets have been installed
+        // to subdirectories of this directory
+        const TPtrC& dir = ((HBufC *)(aDirs[i]))->Des();
+        TFileName baseSuitePath = dir;
+
+        CDir *entryList;
+        CDir *dirList;
+        TInt err = iFs.GetDir(baseSuitePath, KEntryAttMatchMask, ESortNone, entryList, dirList);
+        if (KErrNone != err)
+        {
+            WLOG1WSTR(EJavaConverters,
+                      "CRestoreConvertMIDlet::GetInstallFilesL Cannot list directory %s",
+                      (wchar_t *)(baseSuitePath.PtrZ()));
+
+            // If no S60 Java application has been installed to the drive,
+            // the directory does not exist but it is OK
+            if (KErrPathNotFound != err)
+            {
+                User::Leave(err);
+            }
+            continue;
+        }
+
+        // Only midlet installation directory entries are meaningfull,
+        // discard other possible entries
+        delete entryList;
+
+        TInt   nCount = dirList->Count();
+        TEntry dirEntry;
+
+        for (TInt nInd = 0; nInd < nCount; nInd++)
+        {
+            dirEntry = (*dirList)[nInd];
+            // Just to make sure this really is subdirectory
+            if (dirEntry.IsDir())
+            {
+                // Is this midlet suite subdir?
+                // Midlet suite subdirs look like this "[102b567B]"
+                // Must parse the value of the Uid as unsigned int to avoid
+                // overflow
+                TUint32 nUid;
+                TLex   lexer(dirEntry.iName);
+                lexer.Inc();
+                err = lexer.Val(nUid, EHex);
+                if (KErrNone != err)
+                {
+                    // Not midlet suite subdir, skip it
+                    continue;
+                }
+
+                // Does the subdirectory contain any Jar files?
+                suitePath = baseSuitePath;
+                suitePath.Append(dirEntry.iName);
+                suitePath.Append(KSMCBackSplash);
+
+                CDir *suiteDirEntryList;
+                err = iFs.GetDir(suitePath, KEntryAttMatchMask, ESortNone, suiteDirEntryList);
+                if (KErrNone != err)
+                {
+                    LOG1WSTR(EJavaConverters, EError,
+                             "CRestoreConvertMIDlet::GetInstallFilesL Cannot list content of suite dir %s",
+                             (wchar_t *)(suitePath.PtrZ()));
+                    User::Leave(err);
+                    return;
+                }
+                // If there is .jad or Jar file in suiteDirEntryList, adds
+                // it to iInstallFiles.
+                // Recognizes also DRM protected Jar files (.dm, .dcf)
+                AddJadJarToInstallFilesL(suitePath, suiteDirEntryList);
+                delete suiteDirEntryList;
+            }
+        } // for - loop all directory entries in a base installation directories
+        delete dirList;
+
+    } // for - loop all base installation directories
+
+    if (iInstallFiles.Count() == 0)
+    {
+        WLOG(EJavaConverters,
+             "CRestoreConvertMIDlet::GetInstallFilesL No MIDlets to convert");
+    }
+
+    // how many applications to restore
+    iNumberOfAppsToInstall = iInstallFiles.Count();
+}
+
+/**
+ *  For each java application in iInstallFiles try to find it from
+ *  Java Storage based on MIDlet suite name and vendor name. If the MIDlet
+ *  is still installed to OMJ (to some other drive than iDrive), it must
+ *  be uninstalled from OMJ to reset the state of MIDlet (RMS data etc)
+ *  to original state. Add the uids of the applications to be uninstalled
+ *  to iUninstallUids in string format
+ */
+void CRestoreConvertMIDlet::FindRemainingMIDletsToBeUninstalledL()
+{
+    TBool namesParsed;
+    for (TInt nInd = 0; nInd < iNumberOfAppsToInstall; nInd++)
+    {
+        // Get the MIDlet-Name and MIDlet-Vendor from iInstallFiles[nInd]
+        if (iIsJad[nInd] == 1)
+        {
+            namesParsed = ParseJadL(*iInstallFiles[nInd]);
+        }
+        else
+        {
+            // If file is .jar file, get the names from Manifest
+            namesParsed = ParseJarL(*iInstallFiles[nInd]);
+        }
+
+        // Search for the MIDlet suite from Java Storage table APPLICATION_PACKAGE_TABLE
+        // If it is found, add the suite Uid in string format to iUninstallUids
+        if (namesParsed)
+        {
+            TPtr suite = iMIDletName->Des();
+            TPtr vendor = iMIDletVendor->Des();
+            std::wstring suiteUid = IsSuiteInstalled(suite, vendor);
+            if (!suiteUid.empty())
+            {
+                iUninstallUids.push_back(suiteUid);
+            }
+        }
+    }
+}
+
+/**
+ * Parse MIDlet-Name and MIDlet-Vendor parameters from JAD file.
+ * Parameters are stored to iMIDletName and iMIDletVendor
+ *
+ * @param ETrue if parsing succeeds otherwise EFalse.
+ */
+TBool CRestoreConvertMIDlet::ParseJadL(const TDesC& aJadFileName)
+{
+    HBufC *jadContent = NULL;
+    // Trap leave thrown if reading jad content fails
+    TRAPD(err, jadContent = GetJadContentL(aJadFileName));
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaConverters,
+              "CRestoreConvertMIDlet::ParseJadL Reading Jad content failed, error %d",
+              err);
+        return EFalse;
+    }
+    CleanupStack::PushL(jadContent);
+
+    HBufC *midletName = ParseAttribute(jadContent, KMidletName);
+    if (NULL == midletName)
+    {
+        ELOG(EJavaConverters,
+             "CRestoreConvertMIDlet::ParseJadL Parsing midlet name failed.");
+        CleanupStack::PopAndDestroy(jadContent);
+        return EFalse;
+    }
+    // store midlet name to member variable and log it
+    TPtr namePtr(iMIDletName->Des());
+    namePtr.Copy(*midletName);
+    LOG1WSTR(EJavaConverters, EInfo,
+             "CRestoreConvertMIDlet::ParseJadL MIDlet-Name %s",
+             (wchar_t *)(namePtr.PtrZ()));
+    delete midletName;
+
+    HBufC *midletVendor = ParseAttribute(jadContent, KMidletVendor);
+    if (NULL == midletVendor)
+    {
+        ELOG(EJavaConverters,
+             "CRestoreConvertMIDlet::ParseJadL Parsing midlet vendor failed.");
+        CleanupStack::PopAndDestroy(jadContent);
+        return EFalse;
+    }
+    // store midlet vendor to member variable and log it
+    TPtr vendorPtr(iMIDletVendor->Des());
+    vendorPtr.Copy(*midletVendor);
+    LOG1WSTR(EJavaConverters, EInfo,
+             "CRestoreConvertMIDlet::ParseJadL MIDlet-Vendor %s",
+             (wchar_t *)(vendorPtr.PtrZ()));
+    delete midletVendor;
+
+    CleanupStack::PopAndDestroy(jadContent);
+    return ETrue;
+}
+
+
+/**
+ * Reads the whole content of the Jad file and returns it in
+ * buffer in Symbian Unicode character set.
+ * @param[in] aJadFile
+ * @return pointer to HBufC that contains the Jad file,
+ * ownership is transferred to caller
+ * @exception If jad file content cannot be read
+ */
+HBufC *CRestoreConvertMIDlet::GetJadContentL(const TDesC& aJadFileName)
+{
+    RFile jadFile;
+    TInt err = jadFile.Open(iFs, aJadFileName, EFileRead);
+    User::LeaveIfError(err);
+    CleanupClosePushL(jadFile);
+
+    // Reserve buffer for Jad in UTF-8 char set
+    TInt jadSize = 0;
+    err = jadFile.Size(jadSize);
+    User::LeaveIfError(err);
+    HBufC8 *bufUtf8Jad  = HBufC8::NewL(jadSize);
+    CleanupStack::PushL(bufUtf8Jad);
+
+    // Read the content in Utf8 char set
+    TPtr8 tmpPtr(bufUtf8Jad->Des());
+    err = jadFile.Read(tmpPtr, jadSize);
+    User::LeaveIfError(err);
+
+    // Convert to Unicode
+    HBufC *bufUnicodeJad =
+        CnvUtfConverter::ConvertToUnicodeFromUtf8L(*bufUtf8Jad);
+
+    CleanupStack::PopAndDestroy(bufUtf8Jad);
+    CleanupStack::PopAndDestroy(&jadFile);
+
+    // Return to caller
+    return bufUnicodeJad;
+}
+
+
+/**
+ * Parse MIDlet-Name and MIDlet-Vendor parameters from Manifest inside
+ * a .jar file.
+ * Parameters are stored to iMIDletName and iMIDletVendor
+ *
+ * @param ETrue if parsing succeeds otherwise EFalse.
+ */
+TBool CRestoreConvertMIDlet::ParseJarL(const TDesC& aJarFileName)
+{
+    HBufC *manifestContent = NULL;
+    // Trap leave thrown if reading Manifest content fails
+    TRAPD(err, manifestContent = GetManifestContentL(aJarFileName));
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaConverters,
+              "CRestoreConvertMIDlet::ParseJarL Reading Manifest failed, error %d",
+              err);
+        return EFalse;
+    }
+    CleanupStack::PushL(manifestContent);
+
+    HBufC *midletName = ParseAttribute(manifestContent, KMidletName);
+    if (NULL == midletName)
+    {
+        ELOG(EJavaConverters,
+             "CRestoreConvertMIDlet::ParseJarL Parsing midlet name failed.");
+        CleanupStack::PopAndDestroy(manifestContent);
+        return EFalse;
+    }
+    // store midlet name to member variable and log it
+    TPtr namePtr(iMIDletName->Des());
+    namePtr.Copy(*midletName);
+    LOG1WSTR(EJavaConverters, EInfo,
+             "CRestoreConvertMIDlet::ParseJarL MIDlet-Name %s",
+             (wchar_t *)(namePtr.PtrZ()));
+    delete midletName;
+
+    HBufC *midletVendor = ParseAttribute(manifestContent, KMidletVendor);
+    if (NULL == midletVendor)
+    {
+        ELOG(EJavaConverters,
+             "CRestoreConvertMIDlet::ParseJarL Parsing midlet vendor failed.");
+        CleanupStack::PopAndDestroy(manifestContent);
+        return EFalse;
+    }
+    // store midlet vendor to member variable and log it
+    TPtr vendorPtr(iMIDletVendor->Des());
+    vendorPtr.Copy(*midletVendor);
+    LOG1WSTR(EJavaConverters, EInfo,
+             "CRestoreConvertMIDlet::ParseJarL MIDlet-Vendor %s",
+             (wchar_t *)(vendorPtr.PtrZ()));
+    delete midletVendor;
+
+    CleanupStack::PopAndDestroy(manifestContent);
+    return ETrue;
+}
+
+
+/**
+ * Reads the whole content of the Manifest inside Jar file
+ * and returns it in buffer in Symbian Unicode character set.
+ * @param[in] aJarFile
+ * @return pointer to HBufC that contains the Manifest,
+ * ownership is transferred to caller
+ * @exception If Manifest content cannot be read
+ */
+HBufC *CRestoreConvertMIDlet::GetManifestContentL(const TDesC& aJarFileName)
+{
+    CZipFile* zipFile = CZipFile::NewL(iFs, aJarFileName);
+    CleanupStack::PushL(zipFile);
+
+    // Seek manifest file
+    CZipFileMember* zippedFile =
+        zipFile->CaseSensitiveOrCaseInsensitiveMemberL(KManifestEntryName());
+    if (!zippedFile)
+    {
+        ELOG(EJavaConverters,
+             "CRestoreConvertMIDlet::GetManifestContentL Package is missing manifest");
+        User::Leave(KErrNotFound);
+    }
+    CleanupStack::PushL(zippedFile);
+
+    TUint uncompressedSize = zippedFile->UncompressedSize();
+    if ((TUint)uncompressedSize >= (KMaxTInt/2))
+    {
+        ELOG(EJavaConverters, "CRestoreConvertMIDlet::GetManifestContentL Invalid manifest");
+        User::Leave(KErrCorrupt);
+    }
+
+    // Buffer to read Manifest into
+    HBufC8* resultData = HBufC8::NewLC(uncompressedSize);
+
+    RZipFileMemberReaderStream* zippedStream = 0;
+    TInt err = zipFile->GetInputStreamL(zippedFile, zippedStream);
+    User::LeaveIfError(err);
+    CleanupStack::PushL(zippedStream);
+
+    TPtr8 ptr(resultData->Des());
+    User::LeaveIfError(zippedStream->Read(ptr, uncompressedSize));
+
+    CleanupStack::PopAndDestroy(zippedStream);
+
+    // Manifest buffer when converted to UCS-2
+    HBufC *manifestContent = HBufC16::NewL(uncompressedSize);
+    TPtr16 ucsPtr(manifestContent->Des());
+    err = CnvUtfConverter::ConvertToUnicodeFromUtf8(ucsPtr, ptr);
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaConverters,
+              "CRestoreConvertMIDlet::GetManifestContentL UTF-8 to unicode"
+              " conversion failed: %d", err);
+        User::Leave(err);
+    }
+    CleanupStack::PopAndDestroy(resultData);
+    CleanupStack::PopAndDestroy(zippedFile);
+    CleanupStack::PopAndDestroy(zipFile);
+
+    // Return to caller
+    return manifestContent;
+}
+
+
+std::wstring CRestoreConvertMIDlet::IsSuiteInstalled(TPtr& aSuiteName, TPtr& aVendorName)
+{
+    std::wstring suiteName(desToWstring(aSuiteName));
+    std::wstring vendorName(desToWstring(aVendorName));
+    std::wstring suiteUid;
+
+    // Find application uid based on names from Java Storage
+    JavaStorage *js = JavaStorage::createInstance();
+
+    try
+    {
+        js->open(JAVA_DATABASE_NAME);
+
+        JavaStorageEntry attribute;
+        JavaStorageApplicationEntry_t findPattern;
+        JavaStorageApplicationList_t  foundEntries;
+
+        // Get ID from APPLICATION_PACKAGE_TABLE  based on PACKAGE_NAME and VENDOR
+        attribute.setEntry(PACKAGE_NAME, suiteName);
+        findPattern.insert(attribute);
+        attribute.setEntry(VENDOR, vendorName);
+        findPattern.insert(attribute);
+        attribute.setEntry(ID, L"");
+        findPattern.insert(attribute);
+
+        js->search(APPLICATION_PACKAGE_TABLE , findPattern, foundEntries);
+
+        // Anything found?
+        if (foundEntries.size() > 0)
+        {
+            // The application package has been found, get the ID of the package
+            suiteUid = foundEntries.front().begin()->entryValue();
+            LOG1WSTR(EJavaConverters, EInfo,
+                     "CRestoreConvertMIDlet::IsSuiteInstalled: Found suite by name. Uid is %s",
+                     suiteUid.c_str());
+        }
+    }
+    catch (JavaStorageException& e)
+    {
+        ELOG1(EJavaConverters,
+              "CRestoreConvertMIDlet::IsSuiteInstalled: Java Storage exception %s", e.what());
+    }
+
+    try
+    {
+        js->close();
+    }
+    catch (JavaStorageException& e2)
+    {
+        WLOG1(EJavaConverters,
+              "CRestoreConvertMIDlet::IsSuiteInstalled: Java Storage exception "
+              "when closing storage %s", e2.what());
+    }
+
+    delete js;
+
+    // suiteUid is empty if suite was not found
+    return suiteUid;
+}
+
+
+/**
+ * Finds the java attribute specified by aAttributeName
+ * from aBuf and returns the value of that attribute
+ * in HBufC.
+ * @param[in] aBuf contents of .jad / Manifest file
+ * @param[in] aAttributeName the name of a java attribute
+ * @return the value of the attribute. Caller gets the ownership of the
+ * returned HBufC.
+ * If the attribute is not found, returns NULL
+ */
+HBufC *CRestoreConvertMIDlet::ParseAttribute(const HBufC *aBuf, const TDesC& aAttributeName)
+{
+    TInt    nInd(0);
+    TBool   fullNameFound(EFalse);
+    TUint32 ch;
+
+    // Start parsing from the beginning
+    TPtrC parsePtr = aBuf->Mid(nInd);
+
+    do
+    {
+        // Find attribute name
+        nInd = parsePtr.Find(aAttributeName);
+        if (nInd < 0)
+        {
+            // Returns NULL if the attribute cannot be found
+            return NULL;
+        }
+
+        // Check that the attribute name was preceded by line break or
+        // it was at the beginning
+        if (nInd == 0)
+        {
+            fullNameFound = ETrue;
+        }
+        else
+        {
+            ch = parsePtr[nInd-1];
+            if ((ch == CR) || (ch == LF))
+            {
+                fullNameFound = ETrue;
+            }
+            else
+            {
+                // Name was just a part of longer string (not 'word match')
+                fullNameFound = EFalse;
+                // Skip to the last character of the found match.
+                // We can skip because we are insterested only in 'word' matches
+                // so the next cannot start inside the area we are skipping now.
+                parsePtr.Set(parsePtr.Mid(nInd + aAttributeName.Length() - 1));
+                continue;
+            }
+        }
+
+        // Check whether buffer ends after attribute name
+        if (nInd + aAttributeName.Length() >= parsePtr.Length())
+        {
+            // Buffer ends immediately after the found
+            // attribute name instance. No attribute value
+            return NULL;
+        }
+
+        // Check that there is a white space character or colon after
+        // attribute name
+        ch = parsePtr[nInd + aAttributeName.Length()];
+        if ((ch == COLON) || (ch == SP) || (ch == HT))
+        {
+            fullNameFound = ETrue;
+        }
+        else
+        {
+            // Name was just a part of longer string (not 'word match')
+            fullNameFound = EFalse;
+            // Skip to the next character after the found match
+            parsePtr.Set(parsePtr.Mid(nInd + aAttributeName.Length()));
+            continue;
+        }
+    }
+    while (!fullNameFound);
+
+    // Skip to the end of the attribute name and find ':' after the name.
+    // The skipped characters must be white space chacraters, otherwise
+    // the attribute name is illegal and Java Installer will not accept
+    // the Jad file / Manifest.
+    parsePtr.Set(parsePtr.Mid(nInd + aAttributeName.Length() - 1));
+    nInd = parsePtr.Locate(COLON);
+    if (nInd < 0)
+    {
+        return NULL;
+    }
+    nInd++;
+
+    // Parse attribute value (CR or LF ends)
+    TInt nEndInd = parsePtr.Locate(CR);
+    TInt nTmpInd = parsePtr.Locate(LF);
+
+    if (KErrNotFound == nEndInd)
+    {
+        nEndInd = parsePtr.Length() - 1;
+    }
+    if (KErrNotFound == nTmpInd)
+    {
+        nTmpInd = parsePtr.Length() - 1;
+    }
+
+    if (nTmpInd < nEndInd)
+    {
+        nEndInd = nTmpInd;
+    }
+
+    if (nEndInd < nInd)
+    {
+        return NULL;
+    }
+
+    TPtrC attributeValue = parsePtr.Mid(nInd, (nEndInd - nInd));
+
+    // Remove possible white space from the beginning and end of the value
+    HBufC *bufValue = attributeValue.Alloc();
+    if (NULL == bufValue)
+    {
+        return NULL;
+    }
+    TPtr value = bufValue->Des();
+    value.Trim();
+
+    return bufValue;
+} // parseAttribute
+
+
+/**
+ * Uninstall all Java 2.x MIDlets from drive given in aDrive
+ *
+ * @param aDrive uninstallation drive
+ */
+void CRestoreConvertMIDlet::UninstallAllFromDriveL(TDriveNumber &aDrive)
+{
+    // Execute Java Installer with uninstallall -drive=X command line options
+
+    LOG1(EJavaConverters, EInfo,
+         "CRestoreConvertMIDlet::UninstallAllFromDriveL Going to uninstall "
+         "MIDlets from drive number %d", aDrive);
+
+    RProcess rJavaInstaller;
+    TBuf<256> commandLine;
+
+    // Build command line used to pass all necessary info to Java Installer
+    commandLine = _L("javainstallerstarter");
+    commandLine.Append(_L(" uninstallall -forceuninstall -captainmsgs=no"));
+
+    // Run installer silently, do not send uninstall notification messages
+    commandLine.Append(_L(" -silent -skipotastatus -drive="));
+
+    // Add drive letter
+    commandLine.Append((TChar)('A' + aDrive));
+
+    // start JavaInstaller
+#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
+    TBuf<128> processName = _L("j9midps60");
+#else // RD_JAVA_S60_RELEASE_5_0_IAD
+    TBuf<128> processName = _L("javamidp");
+#endif // RD_JAVA_S60_RELEASE_5_0_IAD
+
+    TInt err = rJavaInstaller.Create(processName, commandLine);
+    if (KErrNone == err)
+    {
+        LOG(EJavaConverters, EInfo, "CRestoreConvertMIDlet::UninstallAllFromDriveL calling Rendezvous");
+        // This call will wait until Java Installer exits (or panics)
+        TRequestStatus status;
+        rJavaInstaller.Logon(status);
+
+        LOG(EJavaConverters, EInfo, "CRestoreConvertMIDlet::UninstallAllFromDriveL calling Resume");
+        rJavaInstaller.Resume();
+
+        // now wait until Java Installer exits
+        User::WaitForRequest(status);
+        if (status.Int() != KErrNone)
+        {
+            ELOG1(EJavaConverters,
+                  "CRestoreConvertMIDlet::UninstallAllFromDriveL Installer exited with error %d",
+                  status.Int());
+        }
+    }
+    else
+    {
+        ELOG1(EJavaConverters,
+              "CRestoreConvertMIDlet::UninstallAllFromDriveL Cannot start Installer, error %d", err);
+    }
+
+    LOG(EJavaConverters, EInfo, "CRestoreConvertMIDlet::UninstallAllFromDriveL calling RProcess::Close");
+    // free resources before returning
+    rJavaInstaller.Close();
+}
+
+
+/**
+ * Scan the content of one directory entry and add the name of
+ * .jad / .jar /.dcf/.dm file to iInstallFiles if
+ * the directory contains a valid, installed Java application.
+ * Recognizes also DRM protected jar files (.dm, .dcf)
+ *
+ * @param aSuitePathName -  directory to be scanned.
+ * @param aSuiteDirEntryList - contents of the directory
+ * @exception Unable to alloc memory for the internal buffers.
+ */
+void CRestoreConvertMIDlet::AddJadJarToInstallFilesL(
+    const TFileName &aSuitePathName,
+    const CDir *aSuiteDirEntryList)
+{
+    if (NULL == aSuiteDirEntryList)
+    {
+        return;
+    }
+
+    TInt nCount = aSuiteDirEntryList->Count();
+    if (0 == nCount)
+    {
+        return;
+    }
+
+    TInt        suffixPos;
+    TEntry      dirEntry;
+    TBool       jarFileInSuiteDir = EFalse;
+    TBool       jadFileInSuiteDir = EFalse;
+    TFileName   jadFullPathName;
+    TFileName   jarFullPathName;
+
+    for (TInt nInd = 0; nInd < nCount; nInd++)
+    {
+        dirEntry = (*aSuiteDirEntryList)[nInd];
+        // Directory cannot be Jar file.
+        // Empty file cannot valid Jar file
+        if (dirEntry.IsDir() || (dirEntry.iSize == 0))
+        {
+            continue;
+        }
+        // get the suffix of the name
+        suffixPos = dirEntry.iName.LocateReverse('.');
+        if (suffixPos == KErrNotFound)
+        {
+            // File name does not contain '.' char
+            continue;
+        }
+        TPtrC suffix(dirEntry.iName.Mid(suffixPos));
+
+        // if the name ends with ".jar" the name is current candidate
+        // for the name to be added to iInstallFiles list
+        if (suffix.CompareF(KJarFileNameSuffix) == 0)
+        {
+            jarFullPathName = aSuitePathName;
+            jarFullPathName.Append(dirEntry.iName);
+            jarFileInSuiteDir = ETrue;
+        }
+        else if (suffix.CompareF(KJadFileNameSuffix) == 0)
+        {
+            // If .jad file is found, then it will be added
+            // to iInstallFiles list
+            jadFullPathName = aSuitePathName;
+            jadFullPathName.Append(dirEntry.iName);
+            jadFileInSuiteDir = ETrue;
+        }
+        else if (suffix.CompareF(KFLJarFileNameSuffix) == 0)
+        {
+            // forward locked and combined delivery DRM protected
+            // .jar files have suffix ".dm"
+            jarFullPathName = aSuitePathName;
+            jarFullPathName.Append(dirEntry.iName);
+            jarFileInSuiteDir = ETrue;
+        }
+        else if (suffix.CompareF(KSDJarFileNameSuffix) == 0)
+        {
+            // separate delivery DRM protected .jar files have suffix ".dcf"
+            jarFullPathName = aSuitePathName;
+            jarFullPathName.Append(dirEntry.iName);
+            jarFileInSuiteDir = ETrue;
+        }
+    }
+
+    // If directory contains a Jar file, then add something to iInstallFiles
+    if (jarFileInSuiteDir)
+    {
+        // If directory contains also .jad file, add .jad file name to iInstallFiles
+        if (jadFileInSuiteDir)
+        {
+            // Reserve one char for null terminator
+            HBufC* path = HBufC::NewLC(jadFullPathName.Length() + 1);
+            TPtr pathPtr(path->Des());
+            pathPtr.Append(jadFullPathName);
+
+            LOG1WSTR(EJavaConverters, EInfo,
+                     "CRestoreConvertMIDlet::AddJadJarToInstallFilesL Adding jad file %s",
+                     (wchar_t *)(pathPtr.PtrZ()));
+            iInstallFiles.Append(path);
+            CleanupStack::Pop(path);
+            iIsJad.AppendL(1);
+        }
+        else
+        {
+            // Reserve one char for null terminator
+            HBufC* path = HBufC::NewLC(jarFullPathName.Length() + 1);
+            TPtr pathPtr(path->Des());
+            pathPtr.Append(jarFullPathName);
+
+            LOG1WSTR(EJavaConverters, EInfo,
+                     "CRestoreConvertMIDlet::AddJadJarToInstallFilesL Adding jar file %s",
+                     (wchar_t *)(pathPtr.PtrZ()));
+            iInstallFiles.Append(path);
+            CleanupStack::Pop(path);
+            iIsJad.AppendL(0);
+        }
+    }
+}
+
+/**
+ * Start Java Installer in poll mode and then wait until it exits.
+ */
+void CRestoreConvertMIDlet::RunJavaInstallerL()
+{
+    LOG(EJavaConverters, EInfo, "CRestoreConvertMIDlet::RunJavaInstaller");
+
+    RProcess rJavaInstaller;
+    TFileName fileName;
+    TInt err;
+    // Max one path name, user name and password and some options ->
+    // 1536 is enough
+    TBuf<1536> commandLine;
+
+    // Build command line used to pass all necessary info to Java Installer
+    std::auto_ptr<HBufC> installerStarterDll(
+        stringToDes(java::runtime::JAVA_INSTALLER_STARTER_DLL));
+    commandLine = installerStarterDll->Des();
+    commandLine.Append(_L(" poll -address=convert"));
+
+    // Run installer silently
+    commandLine.Append(_L(" -silent -skipotastatus -silentconversion"));
+
+    // Convert old S60 applications so that applications uids,
+    // private data and RMS data are all preserved
+    commandLine.Append(_L(" -convert=yes"));
+
+    // Upgrading MIDlets is allowed
+    commandLine.Append(_L(" -upgrade=yes"));
+
+    // No OCSP checks for converted MIDlets
+    commandLine.Append(_L(" -ocsp=no"));
+
+    // Allow upgrade even if version number has not increased
+    commandLine.Append(_L(" -overwrite=yes"));
+
+    // Downloading .jar is not allowed.
+    commandLine.Append(_L(" -download=no"));
+
+    // If upgrade install, automatically upgrade also the data
+    commandLine.Append(_L(" -upgrade_data=yes"));
+
+    // MIDlets must be restored to the original drive
+    if (iDrive > -1)
+    {
+        TChar targetDrive;
+        err = RFs::DriveToChar(iDrive, targetDrive);
+        if (KErrNone == err)
+        {
+            commandLine.Append(_L(" -drive="));
+            commandLine.Append(targetDrive);
+        }
+    }
+
+    // start JavaInstaller
+    std::auto_ptr<HBufC> installerProcess(
+        stringToDes(java::runtime::JAVA_PROCESS));
+    err = rJavaInstaller.Create(installerProcess->Des(), commandLine);
+    if (KErrNone == err)
+    {
+        LOG(EJavaConverters, EInfo, "CRestoreConvertMIDlet::RunJavaInstaller calling Rendezvous");
+        // This call will wait until Java Installer exits (or panics)
+        rJavaInstaller.Logon(iStatus);
+
+        LOG(EJavaConverters, EInfo, "CRestoreConvertMIDlet::RunJavaInstaller calling Resume");
+        rJavaInstaller.Resume();
+    }
+    else
+    {
+        ELOG1(EJavaConverters,
+              "CRestoreConvertMIDlet::RunJavaInstaller Cannot start Installer, error %d", err);
+        // CActive will trap the following leave, execution will go to RunError
+        User::Leave(err);
+    }
+
+    LOG(EJavaConverters, EInfo, "CRestoreConvertMIDlet::RunJavaInstaller calling RProcess::Close");
+    // free resources before returning
+    rJavaInstaller.Close();
+
+    // now wait until Java Installer exits
+    SetActive();
+}
+
+/**
+ * To cleanup member variables.
+ */
+void CRestoreConvertMIDlet::FullCleanup()
+{
+    iDirs.ResetAndDestroy();
+    iInstallFiles.ResetAndDestroy();
+    iUninstallUids.clear();
+    iIsJad.Reset();
+}
+
+
+/**
+ * Checks all local drives in the device and stores the DriveInfo API drive
+ * status information for each drive to iDriveStatuses
+ * @exception Cannot get drive list.
+ */
+void CRestoreConvertMIDlet::GetAllDeviceDrivesL()
+{
+    TDriveList driveList;
+    // get all drives
+    TInt err = iFs.DriveList(driveList);
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaConverters,
+              "CRestoreConvertMIDlet::GetAllDeviceDrives cannot get drive list, err %d", err);
+        User::Leave(err);
+    }
+
+    // store status of the non-remote, non-substed drives
+    TUint  status = 0;
+    for (TInt drive = 0; drive < KMaxDrives; drive++)
+    {
+        iDriveStatuses[drive] = 0;
+
+        if (driveList[drive] == 0)
+        {
+            // no such drive in this device
+            continue;
+        }
+
+        err = DriveInfo::GetDriveStatus(iFs, drive, status);
+        if (KErrNone != err)
+        {
+            ELOG2(EJavaConverters,
+                  "CRestoreConvertMIDlet::GetAllDeviceDrivesL cannot get drive %d status, err %d",
+                  drive, err);
+            User::Leave(err);
+        }
+        // D drive is temporary RAM drive, skip it
+        // Drives J to Y are substed or remote drives, skip them
+        if ((drive == EDriveD) || ((drive >= EDriveJ) && (drive <= EDriveY)))
+        {
+            continue;
+        }
+
+        iDriveStatuses[drive] = status;
+    }
+}