/*
* Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:   Definition of CNcdInstallationService
*
*/
 

#include "ncdinstallationserviceimpl.h"

#include <DocumentHandler.h>
#include <apmstd.h>
#include <apmrec.h>
#include <bautils.h>

#include <swi/sisregistrypackage.h>
#include <caf/caf.h>
#include <caf/supplier.h> 
#include <caf/importfile.h>
#include <Oma2Agent.h>
#include <s32file.h>
#include <e32property.h>
#include <sacls.h>

#ifdef USE_OLD_JAVA_API
    #include <mjavaregistry.h>
    #include <swi/minstalledappsregistry.h>
#else
    #include <javaregistry.h>
    #include <javaregistrypackageentry.h>

    using namespace Java;
#endif

#include "ncdinstallationserviceobserver.h"
#include "ncdactiveoperationobserver.h"
#include "ncdsilentinstallactiveobserver.h"
#include "ncderrors.h"
#include "catalogsutils.h"
#include "catalogsconstants.h"
#include "catalogsdebug.h"

_LIT( KJadFileExtension, ".jad" );
const TInt KDelayWhenAppListInvalid = 500000;

const TUint KFileOpenFlags = EFileShareReadersOrWriters;

#ifdef __SERIES60_31__

    const TInt32 KPSUidJavaLatestInstallation = KUidJmiLatestInstallation;

#else

    // Defined originally in /mw/java/inc/javauids.h
    // This should become available at some point in javadomainpskeys.h
    //const TInt32 KPSUidJavaLatestInstallation = 0x10282567;
    #include <javadomainpskeys.h>

#endif

// length taken from WidgetRegistryData.h
const TInt KWidgetBundleIdLength = KWidgetRegistryVal + 1;    

// ======== CALLBACK FUNCTION ========
 
static TInt InstallationCompleteCallback( TAny* aData )
    {
    DLTRACEIN((""));
    TRAPD( err,
        {
        CNcdInstallationService* service = 
            reinterpret_cast<CNcdInstallationService*>( aData );
        DASSERT( service );
        service->NotifyObserverL();
        } );
        
    DLTRACEOUT((""));
    return err;
    }


// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// Constructor.
// ---------------------------------------------------------------------------
//
CNcdInstallationService* CNcdInstallationService::NewL()
    {
    CNcdInstallationService* self = NewLC();
    CleanupStack::Pop();
    return self;
    }
    
// ---------------------------------------------------------------------------
// Constructor.
// ---------------------------------------------------------------------------
//
CNcdInstallationService* CNcdInstallationService::NewLC()
    {
    CNcdInstallationService* self =
        new (ELeave) CNcdInstallationService();
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }
    
// ---------------------------------------------------------------------------
// Destructor.
// ---------------------------------------------------------------------------
//
CNcdInstallationService::~CNcdInstallationService()
    {
    DLTRACEIN((""));
    delete iSilentInstallActiveObserver;
    iSilentInstallActiveObserver = NULL;
    delete iDocHandler;
    iRegistrySession.Close();
    iFs.Close();
    iAknsSrv.Close();
    delete iInstallationCompleteCallback;
    delete iJadFileName;
    delete iRecognizedMime;
#ifdef USE_OLD_JAVA_API    
    iMIDletUids.Close();
#endif    
    iApaLs.Close();
    if( iThemes )
        {
        iThemes->ResetAndDestroy();
        delete iThemes;        
        }
    
    // Deletes iInstallStatusObserver and closes iInstaller
    CancelInstall(); 
    iRomUids.Close();
    
    if ( iWidgetRegistry.Handle() )
        {
        // decreases widget server's refcount but this cannot be called
        // if Connect has not been called or we'll get a KERN-EXEC 0
        iWidgetRegistry.Disconnect();
        }
    else
        {
        iWidgetRegistry.Close();
        }
    iInstalledWidgets.ResetAndDestroy();
    iInstalledWidgetsInfos.ResetAndDestroy();
    }

// ---------------------------------------------------------------------------
// Constructor.
// ---------------------------------------------------------------------------
//
CNcdInstallationService::CNcdInstallationService()
    {
    }
    
// ---------------------------------------------------------------------------
// Constructor.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::ConstructL()
    {
    DLTRACEIN((""));
    iDocHandler = CDocumentHandler::NewL();
    iDocHandler->SetExitObserver( this );
    
    User::LeaveIfError( iFs.Connect() );
    User::LeaveIfError( iFs.ShareProtected() );
    User::LeaveIfError( iRegistrySession.Connect() );
    User::LeaveIfError( iAknsSrv.Connect() ); 

    iInstallationCompleteCallback = new(ELeave) CAsyncCallBack( 
        TCallBack( InstallationCompleteCallback, this ),
        CActive::EPriorityStandard );  
              
    InitializeRomApplicationListL();
    }


// ---------------------------------------------------------------------------
// Installs all kinds of files.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InstallL( const TDesC& aFileName,
                                        const TDesC& aMimeType,
                                        const TNcdItemPurpose& aPurpose )
    {
    DLTRACEIN((""));
    RFile file;
    CleanupClosePushL( file );
    User::LeaveIfError( file.Open( FileServerSession(), aFileName, KFileOpenFlags ) ); 
    InstallL( file, aMimeType, aPurpose, NULL );
    CleanupStack::PopAndDestroy( &file );
    DLTRACEOUT((""));        
    }

// ---------------------------------------------------------------------------
// Installs all kinds of files.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InstallL( RFile& aFile,
                                        const TDesC& aMimeType,
                                        const TNcdItemPurpose& aPurpose )
    {
    DLTRACEIN((""));
    InstallL( aFile, aMimeType, aPurpose, NULL );
    DLTRACEOUT((""));        
    }


// ---------------------------------------------------------------------------
// Installs java files.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InstallJavaL( const TDesC& aFileName,
                                            const TDesC& aMimeType,
                                            const TDesC8& aDescriptorData )
    {
    DLTRACEIN((""));
    RFile file;
    CleanupClosePushL( file );
    User::LeaveIfError( file.Open( FileServerSession(), aFileName, KFileOpenFlags ) );     
    InstallJavaL( file, aMimeType, aDescriptorData, NULL );
    CleanupStack::PopAndDestroy( &file );
    DLTRACEOUT((""));
    }

// ---------------------------------------------------------------------------
// Installs java files.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InstallJavaL( RFile& aFile,
                                            const TDesC& aMimeType,
                                            const TDesC8& aDescriptorData )
    {
    DLTRACEIN((""));    
    InstallJavaL( aFile, aMimeType, aDescriptorData, NULL );    
    DLTRACEOUT((""));
    }


// ---------------------------------------------------------------------------
// Installs all kinds of files silently.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::SilentInstallL( RFile& aFile,
                                        const TDesC& aMimeType,
                                        const TNcdItemPurpose& aPurpose,
                                        const SwiUI::TInstallOptionsPckg& aInstallOptionsPckg )
    {
    DLTRACEIN((""));

    if ( iSilentInstallActiveObserver == NULL )
        {
        DLINFO(("Create active observer for silent install"));
        iSilentInstallActiveObserver = CNcdSilentInstallActiveObserver::NewL( *this );        
        }

    InstallL( aFile, aMimeType, aPurpose, &aInstallOptionsPckg );

    DLTRACEOUT(("")); 
    }


// ---------------------------------------------------------------------------
// Installs java files silently.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::SilentInstallJavaL( RFile& aFile,
                                            const TDesC& aMimeType,
                                            const TDesC8& aDescriptorData,
                                            const SwiUI::TInstallOptionsPckg& aInstallOptionsPckg )
    {
    DLTRACEIN((""));

    if ( iSilentInstallActiveObserver == NULL )
        {
        DLINFO(("Create active observer for silent install"));
        iSilentInstallActiveObserver = CNcdSilentInstallActiveObserver::NewL( *this );        
        }

    InstallJavaL( aFile, aMimeType, aDescriptorData, &aInstallOptionsPckg );

    DLTRACEOUT((""));
    }

// ---------------------------------------------------------------------------
// Installs widget silently.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::SilentInstallWidgetL( RFile& aFile,
                                                    const SwiUI::TInstallOptionsPckg& aInstallOptionsPckg )
    {
    DLTRACEIN((""));
    
    if ( iSilentInstallActiveObserver == NULL )
        {
        DLINFO(("Create active observer for silent install"));
        iSilentInstallActiveObserver = CNcdSilentInstallActiveObserver::NewL( *this );        
        }

    InstallWidgetL( aFile, &aInstallOptionsPckg );
    
    DLTRACEOUT((""));
    }
// ---------------------------------------------------------------------------
// Cancell silent install.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::CancelSilentInstall( HBufC*& aFileName,
                                                   TUid& aAppUid,
                                                   TInt& aError )
    {
    DLTRACEIN((""));
    
    // Silent install can only be cancelled if silent is allowed.
    // The capability check makes sure of this.

    // Set intial values for the reference parameters.
    delete aFileName;
    aFileName = NULL;
    aAppUid = KNullUid;
    aError = KErrCancel;
    
    if ( iBusy )
        {
        DLINFO(("Install operation was busy"));
        
        // Some operation is on. Here we expect that it is silent.
        // Inform the installer that the asynchronous silent install request 
        // needs to be cancelled. 
        // Because we use a dummy active object to observe
        // completion of installation and that dummy object uses call backs
        // to inform completion to observer, we have to cancel the operation
        // by using the dummy object here.
        aError = iSilentInstallActiveObserver->CancelAsyncOperation();

        if ( aError == KErrNone )
            {
            DLINFO(("Installation was success even if cancel was issued."))
            
            // The installation was finished after all.
            TRAPD( trapError, 
                   HandleSilentInstallSuccessAfterCancelL( aFileName,
                                                           aAppUid,
                                                           aError ) );
            if ( trapError != KErrNone )
                {
                DLERROR(("Install success handling leave."));
                aError = trapError;
                }
            }

        // Do cleaning if necessary.
        if( iJadFileName != NULL )
            {
            // Delete tmp JAD file that was created in the beginning of
            // the install operation. It will be recreated in new install operation
            // if needed.
            BaflUtils::DeleteFile( iFs, *iJadFileName ); // NOTE, error ignored
            delete iJadFileName;
            iJadFileName = NULL;
            }
        
#ifdef USE_OLD_JAVA_API        
        // Clean the array.
        iMIDletUids.Reset();
#endif        

        // Reset information flags.            
        InstallationFinishedSetup( aError );
        }
    }


// ---------------------------------------------------------------------------
// Sets observer for installation services.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::SetObserver(
                            MNcdInstallationServiceObserver& aObserver )
    {
    iObserver = &aObserver;
    }


// ---------------------------------------------------------------------------
// Gets version of installed application by using its UID.
// ---------------------------------------------------------------------------
//
TInt CNcdInstallationService::ApplicationVersion( const TUid& aUid,
                                                  TCatalogsVersion& aVersion )
    {
    DLTRACEIN(("Uid=%X",aUid.iUid));

    // First case: see if the uid is directly in the sis registry.
    Swi::RSisRegistryEntry entry;
    
    TVersion version;
    TRAPD( err, 
        {
        SisRegistryEntryLC( entry, aUid );         
        // Get version number
        version = entry.VersionL();
        CleanupStack::PopAndDestroy( &entry );
        });

    if ( err != KErrNone ) 
        {
        DLTRACEOUT(("Error: %d", err));
        return err;
        }
        
    aVersion.iMajor = version.iMajor;
    aVersion.iMinor = version.iMinor;
    aVersion.iBuild = version.iBuild;        

    DLTRACEOUT(("err=%d",err));
    return err;
    }

// ---------------------------------------------------------------------------
// Checks whether an application is installed on the device.
// ---------------------------------------------------------------------------
//
TBool CNcdInstallationService::IsApplicationInstalledL( const TUid& aUid )
    {
    DLTRACEIN(("uid=%X",aUid.iUid));
    TBool result = EFalse;
    
    Swi::RSisRegistryEntry entry;
    
    // First case: See if the UID is directly in the SIS Registry.
    TRAPD( err, 
        {
        SisRegistryEntryLC( entry, aUid ); 
        
        DLTRACE(("Check that entry is present"));
        result = entry.IsPresentL();
        CleanupStack::PopAndDestroy( &entry );
        });
        
    LeaveIfNotErrorL( err, KErrNotFound );    

    // Third case: see if the UID is mapped to the Java Registry or is a Widget
    if ( !result )
        {
        result = ( JavaAppExistsL( aUid ) || 
                   WidgetExistsL( aUid ) );
        }
    
    
    // Check if the app is ROM only
    if ( !result ) 
        {
        result = IsRomApplication( aUid );
        }
    DLTRACEOUT(("result=%d",result));
    return result;
    }

// ---------------------------------------------------------------------------
// Opens SIS registry entry
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::SisRegistryEntryLC( 
    Swi::RSisRegistryEntry& aEntry,
    const TUid& aUid )
    {
    DLTRACEIN((""));    
    CleanupClosePushL( aEntry );
    
    if ( aEntry.Open( iRegistrySession, aUid ) == KErrNone )
        {
        DLTRACEOUT(("Entry opened"));
        return;
        }
        
    // Second case: See if the UID is mapped to a package/entry
    // in the registry ( -> APP UID that differs from SIS UID ).

    Swi::CSisRegistryPackage* sisRegistryPackage =
        iRegistrySession.SidToPackageL( aUid );
    CleanupStack::PushL( sisRegistryPackage );

    TInt err = aEntry.OpenL( iRegistrySession, *sisRegistryPackage );
    User::LeaveIfError( err );
        
    CleanupStack::PopAndDestroy( sisRegistryPackage );
    
    DLTRACEOUT(("Entry opened"));    
    }


// ---------------------------------------------------------------------------
// Open java suite entry
//
// ---------------------------------------------------------------------------
//
#ifdef USE_OLD_JAVA_API

TBool CNcdInstallationService::JavaAppExistsL( 
    const TUid& aUid )
    {
    DLTRACEIN((""));

    MJavaRegistry* javaRegistry = MJavaRegistry::CreateL();
    CleanupReleasePushL( *javaRegistry );
    
    TRAPD( err, 
        {
        // Leaves with KErrNotFound if not found
        MJavaRegistryMIDletEntry* midletEntry = javaRegistry->MIDletEntryL(
            aUid );    
        midletEntry->Release();
        });
    
    LeaveIfNotErrorL( err, KErrNotFound );
    
    CleanupStack::PopAndDestroy( javaRegistry );
    return err == KErrNone;
    }

#else

TBool CNcdInstallationService::JavaAppExistsL( 
    const TUid& aUid )
    {
    DLTRACEIN((""));

    CJavaRegistry* javaRegistry = CJavaRegistry::NewLC();    

    TBool exists = javaRegistry->RegistryEntryExistsL( aUid );
    
    CleanupStack::PopAndDestroy( javaRegistry );
    return exists;
    }

#endif

// Check via widget registry API
TNcdApplicationStatus CNcdInstallationService::IsWidgetInstalledL(const TDesC& aIdentifier, const TCatalogsVersion& aVersion)
    {
    DLTRACEIN((""));
    
    TNcdApplicationStatus status( ENcdApplicationNotInstalled );
    
    if ( aIdentifier.Length() == 0 )
        {
        DLTRACEOUT(("Null identifier"));
        return status;
        }
    
    
    TCatalogsVersion installedVersion;
    
    //check widget existance and get version number if it is installed
    if ( WidgetExistsL( aIdentifier, installedVersion ) )
        {
        status = ENcdApplicationInstalled;
        }
           
    //compare the version
    if ( status == ENcdApplicationInstalled &&
         aVersion != TCatalogsVersion() ) 
            {
            DLINFO(("Installed widget version: %d.%d.%d, comparing to: %d.%d.%d",
                installedVersion.iMajor,
                installedVersion.iMinor,
                installedVersion.iBuild,
                aVersion.iMajor,
                aVersion.iMinor,
                aVersion.iBuild ));
                
            if ( installedVersion > aVersion ) 
                {
                status = ENcdApplicationNewerVersionInstalled;
                }
            else if ( !( installedVersion == aVersion ) ) 
                {
                status = ENcdApplicationOlderVersionInstalled;
                }
            }
        
        DLTRACEOUT(("widget Status: %d", status));
        return status;    
    }

// ---------------------------------------------------------------------------
// Checks the application status
// ---------------------------------------------------------------------------
//
TNcdApplicationStatus CNcdInstallationService::IsApplicationInstalledL( 
    const TUid& aUid, const TCatalogsVersion& aVersion )
    {
    DLTRACEIN((""));

    TNcdApplicationStatus status( ENcdApplicationNotInstalled );
    
    if ( aUid == TUid::Null() ) 
        {
        DLTRACEOUT(("Null uid"));
        return status;
        }


    Swi::RSisRegistryEntry entry;    
    TCatalogsVersion installedVersion;
    
    // Get SIS-app version
    TRAPD( err, 
        {
        SisRegistryEntryLC( entry, aUid ); 
        
        DLTRACE(("Check that entry is present"));
        
        if ( entry.IsPresentL() ) 
            {
            DLTRACE(("Is present"));
            status = ENcdApplicationInstalled;
            }
        
        TVersion version = entry.VersionL();
        installedVersion = TCatalogsVersion(         
            version.iMajor,
            version.iMinor,
            version.iBuild );

        CleanupStack::PopAndDestroy( &entry );
        });
        
    // SIS app not found, try to get java
    if ( err == KErrNotFound &&
         ( JavaAppExistsL( aUid ) ||
           WidgetExistsL( aUid, installedVersion ) ) ) 
        {
        status = ENcdApplicationInstalled;
        err = KErrNone;
        }
        
    LeaveIfNotErrorL( err, KErrNotFound );  
    
    // Some app found, check version numbers if they are something else than 
    // 0.0.0
    if ( err == KErrNone && 
         status == ENcdApplicationInstalled &&
         aVersion != TCatalogsVersion() ) 
        {
        DLINFO(("Installed version: %d.%d.%d, comparing to: %d.%d.%d",
            installedVersion.iMajor,
            installedVersion.iMinor,
            installedVersion.iBuild,
            aVersion.iMajor,
            aVersion.iMinor,
            aVersion.iBuild ));
            
        if ( installedVersion > aVersion ) 
            {
            status = ENcdApplicationNewerVersionInstalled;
            }
        else if ( !( installedVersion == aVersion ) ) 
            {
            status = ENcdApplicationOlderVersionInstalled;
            }
        }
    
    // Checking if the app is ROM only
    if ( status == ENcdApplicationNotInstalled && 
         IsRomApplication( aUid ) ) 
        {
        status = ENcdApplicationInstalled;
        }
    
    DLTRACEOUT(("Status: %d", status));
    return status;
    }


// ---------------------------------------------------------------------------
// Gets the first SID from the SIS registry package
// ---------------------------------------------------------------------------
//
TUid CNcdInstallationService::SidFromSisRegistryL( const TUid& aUid )
    {
    DLTRACEIN(("uid=%X",aUid.iUid));
    Swi::RSisRegistryEntry entry;
    TUid sid( KNullUid );
    
    User::LeaveIfError( entry.Open( iRegistrySession, aUid ) );
    CleanupClosePushL( entry );

    RArray<TUid> sids;
    CleanupClosePushL( sids );
    entry.SidsL( sids );
        
    DLINFO(("sid count=%d",sids.Count()));

    if ( sids.Count() > 0 )
        {
        sid.iUid = sids[0].iUid;
        }
    else
        {
        DLERROR(("No SIDs found"));
        User::Leave( KErrNotFound );
        }

    CleanupStack::PopAndDestroy( &sids );
    CleanupStack::PopAndDestroy( &entry );

    DLTRACEOUT(("uid=%X",sid.iUid));
    return sid;
    }

// ---------------------------------------------------------------------------
// Appends rights into the rights database.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::AppendRightsL(
    const TDesC8& aRightsObject,
    const TDataType& aMimeType )
    {
    DLTRACEIN(("MimeType: %S", &aMimeType.Des8() ));
    
    ContentAccess::CSupplier* supplier = 
        ContentAccess::CSupplier::NewLC();
    ContentAccess::CMetaDataArray* metaData =
        ContentAccess::CMetaDataArray::NewLC();
    
    DLTRACE(("Creating CImportFile"));
    // Indicate what type of content we are importing.
    ContentAccess::CImportFile* file = supplier->ImportFileL( aMimeType.Des8(), *metaData );
    CleanupStack::PushL( file );
    
    DLTRACE(("Importing data"));
    // Start importing data. This can also be done in parts.
    User::LeaveIfError( file->WriteData( aRightsObject ) );
    
    DLTRACE(("Finished importing"));
    // Indicate that we are finished
    User::LeaveIfError( file->WriteDataComplete() );
    
    CleanupStack::PopAndDestroy( file );
    CleanupStack::PopAndDestroy( metaData );
    CleanupStack::PopAndDestroy( supplier );
    DLTRACEOUT((""));
    }


// ---------------------------------------------------------------------------
// Reads the package uid from a SISX file
// ---------------------------------------------------------------------------
//
TUid CNcdInstallationService::PackageUidFromSisL( RFile& aFile ) const
    {
    DLTRACEIN((""));
    RFileReadStream readStream( aFile );
    CleanupClosePushL( readStream );

    // Get Application UID
    //
    
    // NOTE: In 3.0 the SIS file format has changed
    // the UID is the third long word ( 32 bits ) of the file.
    TInt dummy = readStream.ReadUint32L();
    dummy = readStream.ReadUint32L();
            
    TUid uid( TUid::Uid( readStream.ReadUint32L() ) );
    
    // this closes the attached file too
    CleanupStack::PopAndDestroy( &readStream ); 
    DLTRACEOUT(( _L("Uid: %S"), &uid.Name() ));
    return uid;
    }


// ---------------------------------------------------------------------------
// IsThemeInstalled
// ---------------------------------------------------------------------------
//
TBool CNcdInstallationService::IsThemeInstalledL( const TDesC& aThemeName )
    {
    DLTRACEIN(( _L("Theme: %S"), &aThemeName ));
    TInt result = EFalse;

    if ( aThemeName != KNullDesC )
        {
        RAknsSrvSession skinSrvSession;
        User::LeaveIfError( skinSrvSession.Connect() );
        CleanupClosePushL( skinSrvSession );

        CArrayPtr<CAknsSrvSkinInformationPkg>* srvArray = NULL;
        // Look themes from C: and E: drives
        for ( TInt index = 0; index < 2; index++ )
            {
            //TUint skinLocation = 0;
            if ( index == 0 )
                {
                //skinLocation = EAknsSrvPhone;
                srvArray = skinSrvSession.EnumerateSkinPackagesL( EAknsSrvPhone );
                CleanupStack::PushL( srvArray );
                }
            else
                {
                //skinLocation = EAknsSrvMMC;
                srvArray = skinSrvSession.EnumerateSkinPackagesL( EAknsSrvMMC );
                CleanupStack::PushL( srvArray );
                }

            while ( srvArray && srvArray->Count() > 0 )
                {
                CAknsSrvSkinInformationPkg* info = srvArray->At( 0 );

                // If match is found, theme can be set
                if ( info->Name().Compare( aThemeName ) == 0 )
                    {
                    result = ETrue;
                    }
        
                delete info;
                srvArray->Delete( 0 );
                }

            CleanupStack::PopAndDestroy( srvArray );

            if ( result )
                {
                break;
                }
            }

        CleanupStack::PopAndDestroy();  // skinSrvSession
        }
    DLTRACEOUT(("Result: %d", result));
    return result;
    }


// ---------------------------------------------------------------------------
// Deletes the given file
// ---------------------------------------------------------------------------
//
TInt CNcdInstallationService::DeleteFile( const TDesC& aFilename )
    {
    DLTRACEIN(( _L("Filepath: %S"), &aFilename ));
    // Ensure that we don't accidentally delete whole directories
    // because of empty path
    if ( aFilename.Length() ) 
        {
        return BaflUtils::DeleteFile( iFs, aFilename );
        }
    return KErrArgument;
    }


// ---------------------------------------------------------------------------
// File server session getter
// ---------------------------------------------------------------------------
//
RFs& CNcdInstallationService::FileServerSession()
    {
    return iFs;
    }


// ---------------------------------------------------------------------------
// JAD writer
// ---------------------------------------------------------------------------
//
HBufC* CNcdInstallationService::WriteJadL( 
    const TDesC& aJarFileName, const TDesC8& aJad  )
    {
    DLTRACEIN(("Writing JAD"));
    TParsePtrC jarParse( aJarFileName );
    HBufC* jadFileName = HBufC::NewLC( 
            aJarFileName.Length() + KJadFileExtension().Length() );
    TPtr jadPtr( jadFileName->Des() );
    jadPtr.Append( jarParse.DriveAndPath() );
    jadPtr.Append( jarParse.Name() );
    jadPtr.Append( KJadFileExtension );

    RFile file;
    CleanupClosePushL( file );
    User::LeaveIfError( file.Replace( iFs, *jadFileName, EFileWrite | EFileShareAny ) );
    User::LeaveIfError( file.Write( aJad ) );
    DLINFO(( _L("JAD=%S"), jadFileName ));
    CleanupStack::PopAndDestroy( &file );
    CleanupStack::Pop( jadFileName );
    return jadFileName;
    }


// ---------------------------------------------------------------------------
// Documenthandler getter
// ---------------------------------------------------------------------------
//
CDocumentHandler& CNcdInstallationService::DocumentHandler()
    {
    return *iDocHandler;
    }


// ---------------------------------------------------------------------------
// Callback function of MNcdAsyncOperationObserver interface
// This is called when an async operation has finished.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::AsyncOperationComplete( TInt aError )
    {    
    DLTRACEIN(("aError: %d", aError));
    
    iInstaller.Close();
    
    if ( aError == SwiUI::KSWInstErrUserCancel ) 
        {
        DLTRACE(("User cancelled, converting error to KErrAbort" ) );
        aError = KErrAbort;        
        }
    
    // Handle this like in normal cases.
    HandleServerAppExit( aError );
    }


// ---------------------------------------------------------------------------
// Callback function of MNcdAsyncSilentInstallObserver interface
// This is called when the silent install has finished.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::AsyncSilentInstallComplete( TInt aError )
    {    
    DLTRACEIN(("aError: %d", aError));
    
    // Handle this like in normal cases.
    HandleServerAppExit( aError );
    }


// ---------------------------------------------------------------------------
// This function is called after application installer has finished.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::NotifyObserverL()
    {
    DLTRACEIN(("install error: %d", iInstallError ));        
    
    if ( iInstallType == EWidgetInstall )
        {
        HandleInstalledWidgetL();
        }
    else if ( iInstallType == EJavaInstall )
        {    
        if( iJadFileName )
            {
            BaflUtils::DeleteFile( iFs, *iJadFileName ); // NOTE, error ignored
            delete iJadFileName;
            iJadFileName = 0;
            }

        if ( iInstallError != KErrNone ) 
            {        
            DLTRACE(("Notify install error"));
#ifdef USE_OLD_JAVA_API            
            iMIDletUids.Reset();
#endif            
            iObserver->InstallationCompleteL( KNullDesC, TUid(), iInstallError );       
            return; 
            }

        TUid midletUid = InstalledMidletUidL();
        
        DLINFO(("Installed midlet uid=%X", midletUid.iUid ));
        
        iObserver->InstallationCompleteL( KNullDesC, midletUid, 
                                          // Return error if nothing found.
                                          midletUid == KNullUid ? KErrNotFound : KErrNone );
        }
    
    else if ( iInstallType == ESisInstall )
        {

        if ( iInstallError != KErrNone ) 
            {        
            DLTRACE(("Notify install error"));
            iObserver->InstallationCompleteL( KNullDesC, TUid(), iInstallError );       
            return; 
            }
        
        // Get theme name if such was installed
        const TDesC& name( LatestThemeL() );
                
        // Notify about theme installation
        if ( iPackageUid.iUid == KNcdThemeSisUid || name != KNullDesC ) 
            {            
            DLTRACE(( _L("Notify observer about theme installation, theme: %S"), 
                &name ));
            // Ensure that uid is theme uid
            iPackageUid.iUid = KNcdThemeSisUid;
            
            if ( name == KNullDesC && iThemePackageUid.iUid != KNcdThemeSisUid ) 
                {
                DLTRACE(("Checking theme installation status with package uid, %x", 
                    iThemePackageUid.iUid ));
                
                TBool themeInstalled = EFalse;
                
                // Check if the theme was indeed successfully installed
                TRAP_IGNORE( themeInstalled = IsApplicationInstalledL( 
                    iThemePackageUid ) );
                    
                if ( themeInstalled ) 
                    {
                    DLINFO(("Theme is installed but we didn't get the name"));
                        iObserver->InstallationCompleteL( 
                            name, 
                            iPackageUid,                     
                            KNcdThemeReinstalled );                    
                    }
                else
                    {
                    DLINFO(("Theme was not installed"));
                    iObserver->InstallationCompleteL( 
                        name, 
                        iPackageUid,                     
                        KErrGeneral );
                    
                    }
                }
            else 
                {
                DLTRACE(("Either theme name was acquired or package uid was theme"));
                iObserver->InstallationCompleteL( 
                    name, 
                    iPackageUid, 
                    // Consider missing theme name as a theme reinstallation
                    name == KNullDesC ? KNcdThemePossiblyReinstalled : KErrNone );    
                }
            }
        else 
            {            
            
            // Get the actual app UID from sis registry
            TRAPD( err, iAppUid = SidFromSisRegistryL( iPackageUid ) );
            
            DLTRACE(("Notify observer about application installation, uid: %x", 
                iAppUid.iUid ));
            
            if ( err == KErrNotFound ) 
                {
                DLTRACE(("Didn't get SID, using package UID: %x", 
                    iPackageUid.iUid));
                iAppUid.iUid = iPackageUid.iUid;
                err = KErrNone;
                }
            
            if ( err == KErrNone ) 
                {
                DLTRACE(("Check the application is actually installed"));          
                TBool installed = EFalse;      
                TRAP( err, installed = IsApplicationInstalledL( iAppUid ) );
                if ( err == KErrNone )
                    {                    
                    if ( !installed ) 
                        {                        
                        err = KErrGeneral;
                        }
                    else
                        {
                        TCatalogsVersion version;
                        err = ApplicationVersion( iAppUid, version );
                        if ( err == KErrNone ) 
                            {
                            DLTRACE(("Converting version to string"));
                            // Put application version as the filename
                            HBufC* versionString = 
                                TCatalogsVersion::ConvertLC( version );
                            // Notify about application installation
                            iObserver->InstallationCompleteL( 
                                *versionString, 
                                iAppUid, 
                                err );
                            CleanupStack::PopAndDestroy( versionString );
                            return;
                            }
                        }
                    }
                
                }

            // Notify about application installation
            iObserver->InstallationCompleteL( KNullDesC, iAppUid, err );
            }
        }
    else 
        {
        DLTRACE(("Was not Java nor SIS install"));
        // This is executed after a content file has been moved.
        // We don't set the exit observer as NULL since it panics in debug builds
        }
    DLTRACEOUT((""));
    }

    
// ---------------------------------------------------------------------------
// This function is called after application installer has finished.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::HandleServerAppExit( TInt aReason )
    {    
    DLTRACEIN(("aReason=%d",aReason));

    InstallationFinishedSetup( aReason );

    // If observer exists, notify it.
    iInstallationCompleteCallback->CallBack();
    }


// ---------------------------------------------------------------------------
// Update the list of installed themes
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::UpdateInstalledThemesL()
    {
    DLTRACEIN((""));
    if ( iThemes ) 
        {
        DLTRACE(("Delete old list"));
        iThemes->ResetAndDestroy();
        delete iThemes;
        iThemes = NULL;        
        }
        
    iThemes = iAknsSrv.EnumerateSkinPackagesL( EAknsSrvAll );

    DLTRACEOUT(("Got new theme list"));
    }


// ---------------------------------------------------------------------------
// Get name of the theme installed after the latest UpdateInstalledThemesL() 
// call
// ---------------------------------------------------------------------------
//
const TDesC& CNcdInstallationService::LatestThemeL()
    {  
    DLTRACEIN((""));  
    
    if ( !iThemes ) 
        {
        DLTRACEOUT(("Was not installing a theme"));
        return KNullDesC();
        }
        
    CArrayPtr<CAknsSrvSkinInformationPkg>* newThemes = 
        iAknsSrv.EnumerateSkinPackagesL( EAknsSrvAll );

#ifdef CATALOGS_BUILD_CONFIG_DEBUG
    DLTRACE(("Installed old themes, count: %d", iThemes->Count() ));
    for ( TInt i = 0; i < iThemes->Count(); ++i )
        {
        DLINFO(( _L("%S"), &iThemes->At( i )->Name() ));
        }

    DLTRACE(("Installed new themes, count: %d", newThemes->Count() ));
    for ( TInt i = 0; i < newThemes->Count(); ++i )
        {
        DLINFO(( _L("%S"), &newThemes->At( i )->Name() ));
        }            
#endif         

    // Empty previous information
    delete iThemeName;
    iThemeName = NULL;
    iPID.Set( TUid::Uid( 0 ) );
   
    // Check if new theme has been installed after last
    // call to the GetInstalledSkinPackagesL()
    if ( newThemes->Count() > iThemes->Count() )
        {
        DLTRACE(("New themes installed, count: %d", 
            newThemes->Count() - iThemes->Count() ));
            
        // New theme has been installed
        for ( TInt i = 0; i < newThemes->Count(); i++ )
            {
            TInt j = 0;
            
            for ( ; j < iThemes->Count(); j++ )
                {
                if ( newThemes->At( i )->PID() == iThemes->At( j )->PID() )
                    {
                    // PID found from old theme list. This is not the
                    // new theme.
                    break;
                    }
                }

            if ( j == iThemes->Count() )
                {
                DLTRACE(("Found new theme"));
                // PID was not found from old theme list. This is the
                // new theme.
                iPID = newThemes->At( i )->PID();
                TRAPD( err, iThemeName = newThemes->At( i )->Name().AllocL() );
                if ( err != KErrNone ) 
                    {
                    newThemes->ResetAndDestroy();
                    delete newThemes;
                    User::Leave( err );
                    }
                break;
                }
            }
        }

    newThemes->ResetAndDestroy();
    delete newThemes;
    if ( iThemeName ) 
        {
        DLTRACEOUT(( _L("Theme: %S"), iThemeName ));
        return *iThemeName;
        }
    DLTRACEOUT(("No theme"));
    return KNullDesC();
    }


// ---------------------------------------------------------------------------
// Try to recognize the data from the file
// ---------------------------------------------------------------------------
//
HBufC* CNcdInstallationService::RecognizeDataL( const TDesC& aFileName )
    {
    DLTRACEIN(( _L("Filename: %S"), &aFileName ));
    
    if ( aFileName.Length() == 0 )
        {
        DLTRACEOUT(("Empty filename"));
        return KNullDesC().AllocL();
        }

    ConnectApaLsL();

    TInt recognizeBufferLength = 0;
    User::LeaveIfError( iApaLs.GetPreferredBufSize( recognizeBufferLength ) );
    HBufC8* buffer = HBufC8::NewLC( recognizeBufferLength );
    TPtr8 ptr8( buffer->Des() );

    TDataRecognitionResult result;
    // Read necessary amount of bytes from the file
    User::LeaveIfError( iFs.ReadFileSection( 
        aFileName, 0, ptr8, recognizeBufferLength ) );
    
    
    // Try to recognize data
    User::LeaveIfError( iApaLs.RecognizeData( 
        aFileName, *buffer, result ) );
        
    HBufC* resultMime = Des8ToDes16L( result.iDataType.Des8() );
    CleanupStack::PopAndDestroy( buffer );
    iApaLs.Close();
    DLTRACEOUT(( _L("Determined MIME: %S"), resultMime ));        
    return resultMime;
    }

// ---------------------------------------------------------------------------
// Try to recognize the data from the file
// ---------------------------------------------------------------------------
//
HBufC* CNcdInstallationService::RecognizeDataL( RFile& aFile )
    {
    DLTRACEIN((""));    
    ConnectApaLsL();

    TDataRecognitionResult result;
    
    // Try to recognize data
    User::LeaveIfError( iApaLs.RecognizeData( 
        aFile, result ) );
        
    HBufC* resultMime = Des8ToDes16L( result.iDataType.Des8() );
    
    iApaLs.Close();
    DLTRACEOUT(( _L("Determined MIME: %S"), resultMime ));        
    return resultMime;
    }


void CNcdInstallationService::ConnectApaLsL()
    {
    DLTRACEIN((""));    
    User::LeaveIfError( iApaLs.Connect() );    
    DLTRACEOUT(("Connected successfully"));
    }


// ---------------------------------------------------------------------------
// Installs all kinds of files in normal or in silent way.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InstallL( RFile& aFile,
                                        const TDesC& aMimeType,
                                        const TNcdItemPurpose& aPurpose,
                                        const SwiUI::TInstallOptionsPckg* aSilentInstallOptionsPckg )
    {
    DLTRACEIN(( _L("iBusy=%d, MIME: %S"),iBusy, &aMimeType ));    
    DASSERT( iObserver );
    DASSERT( iDocHandler );

    
    // Check if some installation is already in progress.
    if ( iBusy )
        {
        DLERROR(("busy"));
        User::Leave( KErrInUse );
        }
    
    // Reset app uid info
    iAppUid.iUid = 0;
    iPackageUid.iUid = 0;
    iThemePackageUid.iUid = KNcdThemeSisUid;
    
    iPurpose = aPurpose;
    
    iInstallError = KErrNone;
    
    delete iRecognizedMime;
    iRecognizedMime = NULL;
        
    // Try to recognize the data if no mime given or it's DRM content
    // in which case we don't know the type of the actual content

    DLTRACE(("Recognizing mime type of the content"));
    TRAPD( err, iRecognizedMime = RecognizeDataL( aFile ) );
    if ( err != KErrNone ) 
        {
        DLERROR(("Couldn't recognize the mime type, error: %d", err));
        iRecognizedMime = KNullDesC().AllocL();
        }

    // Fail-safe in case someone tries to install a Java application
    // with this method
    if ( MatchJava( *iRecognizedMime ) )
        {
        DLTRACE(("Java"));
        InstallJavaL( 
            aFile, 
            *iRecognizedMime, 
            KNullDesC8, 
            aSilentInstallOptionsPckg );
        return;
        }
    else if ( MatchWidget( aFile, aMimeType ) )
        {
        DLTRACE(("Widget"));
        InstallWidgetL( 
            aFile,
            aSilentInstallOptionsPckg );
        return;
        }
    
    // Handle SIS(X) and DRM content which has a suitable purpose
    if ( aMimeType.MatchF( KMimeTypeMatchSymbianInstall ) != KErrNotFound
        || aMimeType.MatchF( KMimeTypeMatchSisx ) != KErrNotFound 
        || aMimeType.MatchF( KMimeTypeMatchApplicationStream ) != KErrNotFound 
        || iRecognizedMime->MatchF( KMimeTypeMatchSymbianInstall ) != KErrNotFound
        || iRecognizedMime->MatchF( KMimeTypeMatchSisx ) != KErrNotFound
        || iRecognizedMime->MatchF( KMimeTypeMatchApplicationStream ) != KErrNotFound )
        {
        DLINFO(("Installing SIS"));
        iInstallType = ESisInstall;
        // Get package UID     
        
        // PackageUidFromSisL( RFile& ) closes the filehandle so we need to make
        // a duplicate 
        RFile fileCopy;
        User::LeaveIfError( fileCopy.Duplicate( aFile ) );
        CleanupClosePushL( fileCopy );
        iPackageUid = PackageUidFromSisL( fileCopy );
        CleanupStack::PopAndDestroy( &fileCopy );
        
        // Check if the file is a theme sis
        if ( aPurpose == ENcdItemPurposeTheme ||
             iPackageUid.iUid == KNcdThemeSisUid )
            {           
            DLINFO(("This seems to be a theme"));
            iThemePackageUid = iPackageUid;
            // Ensure that package uid is a theme UID
            iPackageUid.iUid = KNcdThemeSisUid;             
            }        
    
        // Update the theme list in case it actually is a theme but purpose is wrong
        // and the package doesn't have the theme uid
        UpdateInstalledThemesL();
        
        TDataType dataType;    
        // Start application installation.
        DLINFO(( "Calling doc handler Open" ));

        if ( !aSilentInstallOptionsPckg )
            {
            DLINFO(("Normal install"));
            InitializeInstallerL();
            iCancelCode = SwiUI::ERequestInstallHandle;
            
            iInstaller.Install( iInstallStatusObserver->iStatus, aFile );
            iInstallStatusObserver->StartToObserve();            
            }
        else
            {
            DLINFO(("Silent install"));        
            // Set the observer active because it will be informed about the completion
            // of the silent install and it will forward the information for the callback
            // function of this class object.
            iSilentInstallActiveObserver->StartToObserveL( aFile,
                                                           *aSilentInstallOptionsPckg );
            }
            
        iBusy = ETrue;
 
        }
    else // Handle images etc. and DRM content that didn't have a matching purpose
        {
        DLINFO(("Installing content"));
        // File is some common format.
        iInstallType = EFileInstall;
        TDataType dataType;
    
        if ( aMimeType != KNullDesC )
            {
            // If mime type is given, it will be used in document handler.
            HBufC8* tempBuf = Des16ToDes8LC( aMimeType );
            dataType = TDataType( *tempBuf );
            CleanupStack::PopAndDestroy( tempBuf );
            DLINFO(("DataType: %S", &dataType.Des8() ));
            }
                
        TInt docHandlerError( KErrNone );
        
        DLINFO(("Normal install"));
        // Have to use CopyL since MoveL works only with filepaths
        // We can't use SilentMoveL either
        docHandlerError = 
            iDocHandler->CopyL( aFile, 
                                KNullDesC(),
                                dataType, 
                                KEntryAttNormal );            

        DLTRACE(("After move"));
        if( docHandlerError != KErrNone )
            {
            DLINFO(("error=%d",docHandlerError));
            
            // Use KErrAbort for user cancellation
            if ( docHandlerError == KUserCancel ) 
                {
                docHandlerError = KErrAbort;
                }
            iObserver->InstallationCompleteL( KNullDesC, KNullUid, docHandlerError );
            }
        else
            { 
            DLTRACE(("Installation successful"));
            
            RBuf installFileName;
            CleanupClosePushL( installFileName );
            
            installFileName.CreateL( KMaxPath );
                        
            User::LeaveIfError( iDocHandler->GetPath( installFileName ) );
            iObserver->InstallationCompleteL( installFileName, KNullUid, KErrNone );
            CleanupStack::PopAndDestroy( &installFileName );            

            }
        }
    DLTRACEOUT((""));    
    }

                   
// ---------------------------------------------------------------------------
// Installs java files in normal or in silent way.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InstallJavaL( RFile& aFile,
                                            const TDesC& /*aMimeType*/,
                                            const TDesC8& aDescriptorData,
                                            const SwiUI::TInstallOptionsPckg* aSilentInstallOptionsPckg )
    {
    DLTRACEIN((_L("iBusy=%d, descriptor=%d"),iBusy, aDescriptorData.Length() ));
    DASSERT( iObserver );

    // Check if some installation is already in progress.
    if ( iBusy )
        {
        DLERROR(("busy"));
        User::Leave( KErrInUse );
        }

    iInstallError = KErrNone;
    
#ifdef USE_OLD_JAVA_API
    // Store installed java app uids before installation to see
    // which one is a new java app later.
    MJavaRegistry* javaRegistry = MJavaRegistry::CreateL();
    CleanupReleasePushL( *javaRegistry );
    iMIDletUids.Reset();
    javaRegistry->InstalledMIDletUidsL( iMIDletUids );
    CleanupStack::PopAndDestroy( javaRegistry );
#endif
    
    // In platform security systems JAR and JAD has to be in same folder
    // to get the installation process work correctly.
    // First form the JAD filename from the JAR filename.

    delete iJadFileName;
    iJadFileName = 0;

    if( aDescriptorData != KNullDesC8 )
        {
        DLINFO(("Writing JAD"));
        TPath fileName;
        User::LeaveIfError( aFile.FullName( fileName ) );
        
        iJadFileName = WriteJadL( fileName, aDescriptorData );         
        }    

    
    iInstallType = EJavaInstall;
    TDataType dataType;    
            
    if ( aSilentInstallOptionsPckg == NULL )
        {
        DLINFO(("Normal install"));
        InitializeInstallerL();
        if( iJadFileName )
            {
            DLTRACE(("Installing JAD+JAR"));
            // JAD+JAR install
            iCancelCode = SwiUI::ERequestInstall;
            iInstaller.Install( iInstallStatusObserver->iStatus, *iJadFileName );
            }
        else
            {
            DLTRACE(("Installing JAR"));
            // JAR install
            iCancelCode = SwiUI::ERequestInstallHandle;
            iInstaller.Install( iInstallStatusObserver->iStatus, aFile );
            }
        
        iInstallStatusObserver->StartToObserve();
        }
    else
        {
        DLINFO(("Silent install"));            
        if( iJadFileName )
            {
            DLINFO(("Silent jad and jar"));
            // JAD+JAR install
            // Set the observer active because it will be informed about the completion
            // of the silent install and it will forward the information for the callback
            // function of this class object.
            iSilentInstallActiveObserver->StartToObserveL( *iJadFileName,
                                                           *aSilentInstallOptionsPckg );
            }
        else
            {
            DLINFO(("Silent jar"));
            // JAR install
            // Set the observer active because it will be informed about the completion
            // of the silent install and it will forward the information for the callback
            // function of this class object.
            iSilentInstallActiveObserver->StartToObserveL( aFile,
                                                           *aSilentInstallOptionsPckg );
            }        
        }

    iBusy = ETrue;

    DLTRACEOUT((""));
    }


// ---------------------------------------------------------------------------
// Installs Widgets files in normal or in silent way.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InstallWidgetL( 
    RFile& aFile,
    const SwiUI::TInstallOptionsPckg* aSilentInstallOptionsPckg )
    {
    DLTRACEIN((""));    
    
    iInstallType = EWidgetInstall;

    // Get the list of installed widgets so that we can
    // get the uid of the new widget after installation
    PopulateInstalledWidgetsL(iInstalledWidgetsInfos);

    TDataType dataType;    
    // Start application installation.
    DLINFO(( "Calling doc handler Open" ));

    if ( !aSilentInstallOptionsPckg )
        {
        DLINFO(("Normal install"));
        InitializeInstallerL();
        iCancelCode = SwiUI::ERequestInstallHandle;
        
        iInstaller.Install( iInstallStatusObserver->iStatus, aFile );
        iInstallStatusObserver->StartToObserve();            
        }
    else
        {
        DLINFO(("Silent install"));        
        // Set the observer active because it will be informed about the completion
        // of the silent install and it will forward the information for the callback
        // function of this class object.
        iSilentInstallActiveObserver->StartToObserveL( aFile,
                                                       *aSilentInstallOptionsPckg );
        }
        
    iBusy = ETrue;

    }

// ---------------------------------------------------------------------------
// Initializes installer
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InitializeInstallerL()
    {
    DLTRACEIN((""));
    DeletePtr( iInstallStatusObserver );
    iInstallStatusObserver = CNcdActiveOperationObserver::NewL( *this );
    
    if ( !iInstaller.Handle() ) 
        {
        User::LeaveIfError( iInstaller.Connect() );
        }
    }
    

// ---------------------------------------------------------------------------
// Cancels installation
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::CancelInstall()
    {
    DLTRACEIN((""));
    if ( iInstallStatusObserver &&
         iInstaller.Handle() ) 
        {
        DLTRACE(("Cancelling installation"));
        iInstaller.CancelAsyncRequest( iCancelCode );
        }
    
    DeletePtr( iInstallStatusObserver );
    iInstaller.Close();
    }


// ---------------------------------------------------------------------------
// Sets the flags after installation has been finished.
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InstallationFinishedSetup( TInt aReason )
    {
    DLTRACEIN(("aReason=%d",aReason));

    // Installation has finished.
    iBusy = EFalse;    

    iInstallError = aReason;    
    }


// ---------------------------------------------------------------------------
// Handles the situation when installation was finished even if cancel request
// was issued for silent install operation
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::HandleSilentInstallSuccessAfterCancelL( HBufC*& aFileName,
                                                                      TUid& aAppUid,
                                                                      TInt& aError )
    {
    DLTRACEIN((""));
    
    // Set the error to KErrNone.
    // So, initially we think that installation was success.
    // If we later notice that installation was not finished,
    // then we suppose that cancellation was success and set the
    // value to KErrCancel
    aError = KErrNone;
    
    if ( iInstallType == EJavaInstall )
        {    
        // Set the midlet UID for the aAppUid variable.
        aAppUid = InstalledMidletUidL();
        
        if ( aAppUid == KNullUid )
            {
            DLINFO(("Installed midlet was not found"));
            // Because the new midlet was not found, we can suppose that the
            // application was not installed. So, set the error as KErrCancel.
            aError = KErrCancel;
            }
        }
    else if ( iInstallType == EWidgetInstall )
        {    
        // Set the midlet UID for the aAppUid variable.
        aAppUid = InstalledWidgetUidL();
        
        if ( aAppUid == KNullUid )
            {
            DLINFO(("Installed widget was not found"));
            // Because the new widget was not found, we can suppose that the
            // application was not installed. So, set the error as KErrCancel.
            aError = KErrCancel;
            }
        }
    else if ( iInstallType == ESisInstall )
        {
        // Get theme name if such was installed
        const TDesC& name( LatestThemeL() );
                
        // Notify about theme installation
        if ( iPackageUid.iUid == KNcdThemeSisUid || name != KNullDesC ) 
            {            
            DLINFO(( _L("Theme installation, theme: %S"), &name ));
            // Ensure that uid is theme uid
            iPackageUid.iUid = KNcdThemeSisUid;

            // Set the uid value for the reference parameter
            aAppUid = iPackageUid;
            
            if ( name == KNullDesC && iThemePackageUid.iUid != KNcdThemeSisUid ) 
                {
                DLINFO(("Checking theme installation status with package uid, %x", 
                        iThemePackageUid.iUid ));
                
                // Check if the theme was indeed successfully installed
                TBool themeInstalled( EFalse );                
                TRAP_IGNORE( 
                    themeInstalled = IsApplicationInstalledL( iThemePackageUid ) );
                    
                if ( !themeInstalled )
                    {
                    DLINFO(("Theme was not installed"));
                    // Theme was not installed. So, let us suppose that cancel
                    // was success after all
                    aError = KErrCancel;
                    // Because name is KNullDesC, do not set the aFileName here
                    }
                }
            else 
                {
                DLTRACE(("Either theme name was acquired or package uid was theme"));
                if ( name != KNullDesC )
                    {                    
                    aFileName = name.AllocL();
                    }
                aAppUid = iPackageUid;
                }
            }
        else 
            {                    
            // Get the actual app UID from sis registry
            TRAPD( err, aAppUid = SidFromSisRegistryL( iPackageUid ) );
            
            DLTRACE(("Notify observer about application installation, uid: %x", 
                aAppUid.iUid ));
            
            if ( err == KErrNotFound ) 
                {
                DLINFO(("Didn't get SID, using package UID: %x", 
                        iPackageUid.iUid));
                aAppUid.iUid = iPackageUid.iUid;
                err = KErrNone;
                }
            
            if ( err == KErrNone ) 
                {
                DLTRACE(("Check the application is actually installed"));          
                TBool installed = IsApplicationInstalledL( aAppUid );
                if ( !installed ) 
                    {
                    aError = KErrCancel;
                    }
                }
            }
        }
    else 
        {
        DLTRACE(("Was not Java nor SIS install"));
        // This is executed after a content file has been moved.
        }
        
    DLTRACEOUT((""));
    }

 
// ---------------------------------------------------------------------------
// Creates a list of applications that are in ROM but that are not 
// in the SIS or Java registry
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::InitializeRomApplicationListL()
    {
    DLTRACEIN((""));
        
    TApaAppInfo info;
    ConnectApaLsL();    
    User::LeaveIfError( iApaLs.GetAllApps() );
    
    iRomUids.Reset();
    
    RArray<TUid> midletUids;
    CleanupClosePushL( midletUids );
    
    MidletUidsL( midletUids );
    
    DLTRACE(("%d Midlet UIDs", midletUids.Count() ));

#ifdef CATALOGS_BUILD_CONFIG_DEBUG
    TInt appCount = 0;
    iApaLs.AppCount( appCount );
    DLTRACE(("apps: %d", appCount));
#endif // CATALOGS_BUILD_CONFIG_DEBUG
    
    // If the application list is not OK after 5 tries, give up
    // Each break is 0.5 seconds
    TInt retryCount = 5;
    TInt appErr = KErrNone;    

    do
        {       
        appErr = iApaLs.GetNextApp( info );
        if ( appErr == KErrNone )
            {            
            // App is considered a ROM app if its not found either
            // in SIS registry or midlet registry
            // Note: ROM apps can be in SIS registry also but that doesn't
            // matter because we just want to get a list of apps that are
            // not found anywhere else but apparc
            if ( midletUids.Find( info.iUid ) == KErrNotFound &&
                 !iRegistrySession.IsSidPresentL( info.iUid ) ) 
                {
                
                DLTRACE(( _L("Found ROM app: %x, caption: %S, path: %S"), 
                    info.iUid.iUid,
                    &info.iCaption,
                    &info.iFullName ));
                iRomUids.AppendL( info.iUid );
                }
            }
        else if( appErr == RApaLsSession::EAppListInvalid )
            {
            // Application list is not yet fully populated
            // https://jira.bothi.fi/jira/browse/PRECLI-1364
            if ( retryCount > 0 )
                {
                DLINFO(( "Application list not yet populated, waiting" ));
                User::After( KDelayWhenAppListInvalid );
                retryCount--;
                appErr = KErrNone;
                }
            else
                {
                User::Leave( KErrNotReady );
                }
            }
        // Some unknown error. That shouldn't happen.
        else if( appErr != RApaLsSession::ENoMoreAppsInList ) 
            {
            DLERROR(("Unknown error with application list. %d", appErr));
            User::Leave( KErrGeneral );
            }
        }
    while( appErr == KErrNone && retryCount >= 0 );
        
    iApaLs.Close();
    CleanupStack::PopAndDestroy( &midletUids );    
    
    DLTRACEOUT(("ROM apps: %d", iRomUids.Count() ));
    }


// ---------------------------------------------------------------------------
// Gets a list of installed midlet UIDs
// ---------------------------------------------------------------------------
//
#ifdef USE_OLD_JAVA_API

void CNcdInstallationService::MidletUidsL( RArray<TUid>& aUids )
    {
    DLTRACEIN((""));
    MJavaRegistry* javaRegistry = MJavaRegistry::CreateL();
    CleanupReleasePushL( *javaRegistry );
    javaRegistry->InstalledMIDletUidsL( aUids );
    CleanupStack::PopAndDestroy( javaRegistry );    
    }

#else

void CNcdInstallationService::MidletUidsL( RArray<TUid>& aUids )
    {
    DLTRACEIN((""));
    CJavaRegistry* javaRegistry = CJavaRegistry::NewLC();
    javaRegistry->GetRegistryEntryUidsL( aUids );          
    CleanupStack::PopAndDestroy( javaRegistry );    
    }

#endif


// ---------------------------------------------------------------------------
// Checks if the application is in ROM
// ---------------------------------------------------------------------------
//
TBool CNcdInstallationService::IsRomApplication( const TUid& aUid ) const
    {
    DLTRACEIN(("UID: %x", aUid.iUid ));
    return iRomUids.Find( aUid ) != KErrNotFound;    
    }


// ---------------------------------------------------------------------------
// Returns the UID of the latest installed midlet, NULL UID if none have
// been installed since the last device restart
// ---------------------------------------------------------------------------
//
#ifdef USE_OLD_JAVA_API

TUid CNcdInstallationService::LatestMidletUidL( 
    MJavaRegistry& aJavaRegistry ) const
    {
    DLTRACEIN((""));
    TInt suiteUid = 0;            
    
    // Get UID for the latest installed Midlet suite
    // KPSUidJavaLatestInstallation = 0x10282567
    // Ignoring error in case the key or read policy change so that client
    // doesn't behave strangely
    RProperty::Get( KUidSystemCategory, 
        KPSUidJavaLatestInstallation, suiteUid );
    
    DLTRACE(("JMI UID: %x", suiteUid ));

    if ( !suiteUid )  
        {
        return KNullUid;
        }
    
    // Get entry for the installed suite
    MJavaRegistrySuiteEntry* suite = aJavaRegistry.SuiteEntryL( 
        TUid::Uid( suiteUid ) );
    CleanupReleasePushL( *suite );        
    RArray<TUid> suiteUids;
    CleanupClosePushL( suiteUids );

    TUid midletUid = KNullUid; 
    suite->MIDletUidsL( suiteUids );
    
    // Take first midlet UID from the suite
    if ( suiteUids.Count() ) 
        {
        midletUid = suiteUids[0];
        }
    DLTRACE(("Midlets in suite: %d", suite->NumberOfMIDletsL() ));
    CleanupStack::PopAndDestroy( &suiteUids );
    DLTRACE(("InstalledAppsEntryUid: %x", midletUid.iUid ));

    CleanupStack::PopAndDestroy( suite );    
    return midletUid;
    }

#else

TUid CNcdInstallationService::LatestMidletUidL( 
    CJavaRegistry& aJavaRegistry ) const
    {
    DLTRACEIN((""));
    TInt suiteUid = 0;            
    
    // Get UID for the latest installed Midlet suite
    // KPSUidJavaLatestInstallation = 0x10282567
    // Ignoring error in case the key or read policy change so that client
    // doesn't behave strangely
    RProperty::Get( KUidSystemCategory, 
        KPSUidJavaLatestInstallation, suiteUid );
    
    DLTRACE(("JMI UID: %x", suiteUid ));

    if ( !suiteUid )  
        {
        return KNullUid;
        }
    
    // Get entry for the installed suite
    CJavaRegistryEntry* suite = aJavaRegistry.RegistryEntryL( 
        TUid::Uid( suiteUid ) );
    
    if ( !suite )
        {
        return KNullUid;
        }
    
    CleanupStack::PushL( suite );        
    
    DASSERT( suite->Type() < EGeneralApplication && 
             suite->Type() >= EGeneralPackage );
    
    CJavaRegistryPackageEntry* entry = 
        static_cast<CJavaRegistryPackageEntry*>( suite );
    
    TUid midletUid = KNullUid;
    TInt count = entry->NumberOfEmbeddedEntries(); 
    TBool appFound = EFalse;
    TInt index = 0;
    
    // Find the first application from the suite
    while ( index < count && !appFound )
        {
        CJavaRegistryEntry* app = entry->EmbeddedEntryByNumberL( index );
        if ( app->Type() >= EGeneralApplication ) 
            {
            midletUid = app->Uid();
            appFound = ETrue;
            DLTRACE(( "Found app: %x", midletUid.iUid ));
            }
        delete app;
        ++index;
        }
    
    CleanupStack::PopAndDestroy( suite );    
    return midletUid;
    }


#endif

// ---------------------------------------------------------------------------
// Returns true if the MIME type matches a Java application or descriptor
// ---------------------------------------------------------------------------
//
TBool CNcdInstallationService::MatchJava( const TDesC& aMime )
    {
    return ( aMime.MatchF( KMimeTypeMatch1JavaApplication ) != KErrNotFound || 
             aMime.MatchF( KMimeTypeMatch2JavaApplication ) != KErrNotFound ||
             aMime.MatchF( KMimeTypeMatchJad ) != KErrNotFound );        
    }


#ifdef USE_OLD_JAVA_API

TUid CNcdInstallationService::InstalledMidletUidL()
    {
    DLTRACEIN((""));
    RArray<TUid> MIDletUids;
    CleanupClosePushL( MIDletUids );
    
    MJavaRegistry* javaRegistry = MJavaRegistry::CreateL();
    CleanupReleasePushL( *javaRegistry );
    javaRegistry->InstalledMIDletUidsL( MIDletUids );
    TUid MIDletUid = KNullUid;
    // Search for new uids in Java registry.
    for ( TInt i = 0 ; i < MIDletUids.Count() ; i++ )
        {
        if ( iMIDletUids.Find( MIDletUids[i] ) == KErrNotFound )
            {
            // A new uid found, this is the installed midlet's uid
            MIDletUid = MIDletUids[i];
            break;
            }
        }

    // We didn't get any new UID so we have to check Java installer's
    // P&S key for the installed suite UID and the get the midlet UID
    // from that. This happens when a midlet with predefined UID, 
    // eg. WidSets, is reinstalled. Midlet UIDs are predefined with
    // the attribute Nokia-MIDlet-UID-<n> in a JAD or JAR manifest
    if ( MIDletUid == KNullUid ) 
        {
        MIDletUid = LatestMidletUidL( *javaRegistry );
        }
    
    CleanupStack::PopAndDestroy( javaRegistry );
    CleanupStack::PopAndDestroy( &MIDletUids );

    iMIDletUids.Reset();
    return MIDletUid;
    }

#else // USE_OLD_JAVA_API

TUid CNcdInstallationService::InstalledMidletUidL()
    {
    DLTRACEIN((""));
    CJavaRegistry* registry = CJavaRegistry::NewLC();
    TUid midletUid = LatestMidletUidL( *registry );
    CleanupStack::PopAndDestroy( registry );
    return midletUid;
    }

#endif // USE_OLD_JAVA_API


// ---------------------------------------------------------------------------
// Populates the list of installed widgets
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::PopulateInstalledWidgetUidsL() 
    {
    DLTRACEIN((""));

    if ( !iWidgetRegistry.Handle() )
        {
        User::LeaveIfError( iWidgetRegistry.Connect() );
        }
    
    iInstalledWidgets.ResetAndDestroy();
    User::LeaveIfError( iWidgetRegistry.InstalledWidgetsL( iInstalledWidgets ) );    
    }

// ---------------------------------------------------------------------------
// Populates the list of installed widgets
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::PopulateInstalledWidgetsL
         (RExtendedWidgetInfoArray& aWidgets) 
    {
    DLTRACEIN((""));
    
    // Get the list of installed widget uids 
    PopulateInstalledWidgetUidsL();
    
    const TInt count = iInstalledWidgets.Count();
    
    // Create array with UID & Version infos
    for ( TInt i = 0; i < count; ++i )
        {
        CExtendedWidgetInfo* tempInfo = new ( ELeave ) CExtendedWidgetInfo();
        CleanupStack::PushL( tempInfo );
        
        CWidgetInfo* widgetInfo = iInstalledWidgets[i];
        
        CWidgetPropertyValue* version = iWidgetRegistry.GetWidgetPropertyValueL
            (widgetInfo->iUid, EBundleVersion );
        CleanupStack::PushL( version );

        // Fill info
        tempInfo->iUid = widgetInfo->iUid;
        if (!version->iValue.s)
            *(tempInfo->iVersion) = KDefVersion;
        else
            *(tempInfo->iVersion) = *(version->iValue.s);
        
        // Append to arrayt
        aWidgets.AppendL( tempInfo );

        CleanupStack::PopAndDestroy( version );
        CleanupStack::Pop( tempInfo );
        }
   
        DLTRACEOUT((""));

    }

// ---------------------------------------------------------------------------
// Gets the name of widget that was installed last
// ---------------------------------------------------------------------------
//
HBufC* CNcdInstallationService::InstalledWidgetNameLC()
    {
    DLTRACEIN((""));
    
    TUid widgetUid = InstalledWidgetUidL();
    
    if ( widgetUid == KNullUid )
        {
        DLERROR(("No widget uid"));
        // No new UID was found, so we assume user canceled the installation.
        // Installer does not give any error code in that case.
        return NULL;
        }

    HBufC* bundleId = HBufC::NewLC( KWidgetBundleIdLength );
    TPtr des( bundleId->Des() );
    iWidgetRegistry.GetWidgetBundleId( widgetUid, des );            

    DLTRACEOUT(( _L("Widget bundle id: %S"), bundleId ));
    return bundleId;
    }
    

// ---------------------------------------------------------------------------
// Gets the UID of the widget that was just installed 
// ---------------------------------------------------------------------------
//
TUid CNcdInstallationService::InstalledWidgetUidL()
    {
    DLTRACEIN((""));
    
    RExtendedWidgetInfoArray widgets;
    PopulateInstalledWidgetsL(widgets);
    CleanupResetAndDestroyPushL( widgets );
        

    DLINFO(("widget count: %d", widgets.Count() ));
    
    TUid uid( KNullUid );
    
    const TInt count = widgets.Count();
    const TInt installedCount = iInstalledWidgetsInfos.Count();
    
    // Try to find a widget that was not installed earlier.
    for ( TInt i = 0; i < count; ++i )
        {
        TBool wasInstalled = EFalse;
        CExtendedWidgetInfo * widgetInfo = widgets[ i ];
        for ( TInt j = 0; j < installedCount; j++ )
            {
          
            TCatalogsVersion versionBefore, versionAfter;
            TCatalogsVersion::ConvertL
                ( versionBefore, *(iInstalledWidgetsInfos[ j ]->iVersion) );
            TCatalogsVersion::ConvertL( versionAfter, *(widgetInfo->iVersion) );
            
            if ( iInstalledWidgetsInfos[ j ]->iUid == widgetInfo->iUid &&
                 versionBefore >= versionAfter) 
                {
                wasInstalled = ETrue;
                break;
                }
            }
        
        if ( !wasInstalled ) 
            {
            DLTRACE(("Found installed widget"));
            uid = widgets[ i ]->iUid;
            break;
            }
        }
        
    CleanupStack::PopAndDestroy( &widgets );        

    DLTRACEOUT(("Installed uid: %x", uid.iUid ));
    return uid;
    }


// ---------------------------------------------------------------------------
// Checks from the MIME type and file extension and returns ETrue if
// either of them matches widgets
// ---------------------------------------------------------------------------
//
TBool CNcdInstallationService::MatchWidget( RFile& aFile, const TDesC& aMime )
    {
    DLTRACEIN((""));
    if ( aMime.CompareF( KMimeTypeMatchWidget ) == 0 )
        {
        DLTRACEOUT(( "Mime type matches" ));
        return ETrue;
        }
    
    TBool match = EFalse;
    TFileName filename;
    TInt err = aFile.Name( filename );
    if ( err == KErrNone )
        {
        TParsePtrC parse( filename );
        match = parse.ExtPresent() &&
                ( KWidgetExtension().CompareF( parse.Ext() ) == 0 );            
        }
    DLTRACEOUT(( "Filename match: %d", match ));
    return match;
    }


// ---------------------------------------------------------------------------
//  
// ---------------------------------------------------------------------------
//
void CNcdInstallationService::HandleInstalledWidgetL()
    {
    DLTRACEIN((""));
    TUid uid( KNullUid );
    if ( iInstallError == KErrNone )
        {
        uid = InstalledWidgetUidL();
        if ( uid == KNullUid )
            {
            iInstallError = KErrAbort;
            }        
        }
    
    iObserver->InstallationCompleteL( KNullDesC, uid, iInstallError );
    }


// ---------------------------------------------------------------------------
//   
// ---------------------------------------------------------------------------
//
TBool CNcdInstallationService::WidgetExistsL( const TUid& aUid )
    {
    DLTRACEIN((""));

    if ( !iWidgetRegistry.Handle() )
        {
        User::LeaveIfError( iWidgetRegistry.Connect() );
        }
    
    if ( iWidgetRegistry.IsWidget( aUid ) )
        {
        TBuf<KWidgetBundleIdLength> id;
        iWidgetRegistry.GetWidgetBundleId( aUid, id );
        return iWidgetRegistry.WidgetExistsL( id );
        }
    return EFalse;         
    }

// ---------------------------------------------------------------------------
//Calling widget registry API to check if a widget with given uid is installed 
//already
// ---------------------------------------------------------------------------
//
TBool CNcdInstallationService::WidgetExistsL( 
        const TUid& aUid, TCatalogsVersion& aVersion )
    {
    DLTRACEIN((""));
    
    if ( !iWidgetRegistry.Handle() )
        {
        User::LeaveIfError( iWidgetRegistry.Connect() );
        }
    
    if ( iWidgetRegistry.IsWidget( aUid ) )
        {
        TBuf<KWidgetBundleIdLength> id;
        iWidgetRegistry.GetWidgetBundleId( aUid, id );
        if (iWidgetRegistry.WidgetExistsL( id ))
            {
            // Get version
            CWidgetPropertyValue* version = 
                iWidgetRegistry.GetWidgetPropertyValueL(aUid, EBundleVersion );
            CleanupStack::PushL( version );
            TCatalogsVersion::ConvertL( aVersion, *(version->iValue.s) );
            CleanupStack::PopAndDestroy( version ); 
            return (ETrue);
            }
        else
            {
            return (EFalse);
            }
        }
    else
       return(EFalse);

    }
    
// ---------------------------------------------------------------------------
// Calling widget registry API to check if a widget with given identifier is 
// installed already
// ---------------------------------------------------------------------------
//
TBool CNcdInstallationService::WidgetExistsL
          ( const TDesC& aIdentifier, TCatalogsVersion& aVersion )
    {
    DLTRACEIN((""));
    
    if ( !iWidgetRegistry.Handle() )
          {
          User::LeaveIfError( iWidgetRegistry.Connect() );
          }

    RPointerArray<CWidgetInfo> widgetInfoArr;
    
    CleanupResetAndDestroyPushL( widgetInfoArr );
    TInt err = iWidgetRegistry.InstalledWidgetsL(widgetInfoArr);
    
    for( TInt i( widgetInfoArr.Count() - 1 ); i >= 0; --i ) 
        {
        CWidgetInfo* widgetInfo( widgetInfoArr[i] );                  
        CWidgetPropertyValue* bundleId = 
            iWidgetRegistry.GetWidgetPropertyValueL
                (widgetInfo->iUid, EBundleIdentifier );
        CleanupStack::PushL( bundleId );
        
        if( aIdentifier.Compare( *(bundleId->iValue.s) )== 0 )
            {
            CWidgetPropertyValue* version = 
                iWidgetRegistry.GetWidgetPropertyValueL
                    (widgetInfo->iUid, EBundleVersion );
            CleanupStack::PushL( version );
            TCatalogsVersion::ConvertL( aVersion, *(version->iValue.s) );
            
            CleanupStack::PopAndDestroy( version );
            CleanupStack::PopAndDestroy( bundleId );
            CleanupStack::PopAndDestroy( &widgetInfoArr );
                        
            return ETrue;
            }
        CleanupStack::PopAndDestroy( bundleId );
        }
    CleanupStack::PopAndDestroy( &widgetInfoArr );
    return EFalse;
    }

// ---------------------------------------------------------------------------
//  Calling widget registry API to return the Uid of the widget
//  with given identifier.
// ---------------------------------------------------------------------------
//
TUid CNcdInstallationService::WidgetUidL( const TDesC& aIdentifier)
    {
    DLTRACEIN((""));
    
    TUid id = TUid::Uid(0);
    
   if ( !iWidgetRegistry.Handle() )
          {
          User::LeaveIfError( iWidgetRegistry.Connect() );
          }
    
    id.iUid = iWidgetRegistry.GetWidgetUidL( aIdentifier);

    return id;
    
    }

    
