ncdengine/provider/server/src/ncdnodeinstallimpl.cpp
changeset 0 ba25891c3a9e
child 18 3ba40be8e484
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdnodeinstallimpl.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1066 @@
+/*
+* Copyright (c) 2006 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:   Implements CNcdNodeInstall class
+*
+*/
+
+
+#include "ncdnodeinstallimpl.h"
+
+#include <f32file.h>
+#include <s32mem.h>
+#include <bautils.h>
+
+
+#include "catalogssession.h"
+#include "catalogsbasemessage.h"
+#include "ncdnodefunctionids.h"
+#include "ncdnodeclassids.h"
+#include "catalogsconstants.h"
+#include "ncd_pp_dataentity.h"
+#include "ncd_cp_query.h"
+#include "catalogsutils.h"
+#include "ncdutils.h"
+#include "ncdpurchaseinstallinfo.h"
+#include "ncdpurchasedetails.h"
+#include "ncdpurchasehistorydbimpl.h"
+#include "ncdinstallinfo.h"
+#include "ncdfileinfo.h"
+#include "ncdextendedinstallinfo.h"
+#include "ncdproviderutils.h"
+#include "ncdinstallationservice.h"
+#include "ncdnodemetadataimpl.h"
+#include "ncdnodecontentinfoimpl.h"
+#include "ncdpanics.h"
+#include "ncdpurchasehistoryutils.h"
+#include "ncdproviderdefines.h"
+#include "ncdnodecontentinfoimpl.h"
+#include "ncdnodemanager.h"
+#include "ncdnodeidentifier.h"
+
+#include "catalogsdebug.h"
+
+
+// Maximum number of content file opening attempts if the first
+// one fails with KErrInUse
+const TInt KMaxRetries = 3;
+
+// Delay between content file opening attempts if the first
+// one fails with KErrInUse
+const TInt KOpenDelay = 500000;
+
+static TInt CallBackOpenFile( TAny* aObject )
+    {
+    DLTRACEIN((""));
+    static_cast<CNcdNodeInstall*>( aObject )->OpenContentFileRunner();
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// CNcdNodeInstall
+// ---------------------------------------------------------------------------
+//  
+
+
+CNcdNodeInstall::CNcdNodeInstall( NcdNodeClassIds::TNcdNodeClassId aClassId,
+    const CNcdNodeMetaData& aMetadata )
+: CCatalogsCommunicable(),
+  iClassId( aClassId ),
+  iMetadata( aMetadata )
+    {
+    }
+
+void CNcdNodeInstall::ConstructL()
+    {
+    DLTRACEIN((""));    
+    iDownloadedFiles = new(ELeave) CDesCArrayFlat( KListGranularity );
+    DLTRACEOUT((""));
+    }
+
+
+CNcdNodeInstall* CNcdNodeInstall::NewL( const CNcdNodeMetaData& aMetadata )
+    {
+    CNcdNodeInstall* self =   
+        CNcdNodeInstall::NewLC( aMetadata );
+    CleanupStack::Pop( self );
+    return self;        
+    }
+
+CNcdNodeInstall* CNcdNodeInstall::NewLC( const CNcdNodeMetaData& aMetadata )
+    {
+    CNcdNodeInstall* self = 
+        new( ELeave ) CNcdNodeInstall( 
+            NcdNodeClassIds::ENcdNodeInstallClassId, aMetadata );
+    CleanupClosePushL( *self );
+    self->ConstructL();
+    return self;        
+    }
+
+
+CNcdNodeInstall::~CNcdNodeInstall()
+    {
+    DLTRACEIN((""));
+
+    // Delete member variables here
+    iInstallInfos.ResetAndDestroy();
+    delete iDownloadedFiles;
+    
+    delete iInstalledContent;
+    delete iPeriodic;
+
+    DLTRACEOUT((""));
+    }        
+
+NcdNodeClassIds::TNcdNodeClassId CNcdNodeInstall::ClassId() const
+    {
+    return iClassId;
+    }
+
+
+
+
+// ---------------------------------------------------------------------------
+// Set node data from purchase details
+// ---------------------------------------------------------------------------
+//  
+TBool CNcdNodeInstall::InternalizeL( const MNcdPurchaseDetails& aDetails )
+    {
+    DLTRACEIN(("this-ptr: %X", this));
+
+    if ( !aDetails.DownloadInfoL().Count() ) 
+        {
+        DLTRACEOUT(("No downloadinfos so there's nothing to install"));
+        return EFalse;
+        }
+
+    DLTRACE(("Copying paths of downloaded files"));
+    
+    CDesCArray* tempDownloads = new(ELeave) CDesCArrayFlat( KListGranularity );
+    CleanupStack::PushL( tempDownloads );
+    
+    TBool atLeastOneFile = EFalse;
+    // Get names of downloaded files
+    for ( TInt i = 0; i < aDetails.DownloadedFiles().MdcaCount(); ++i ) 
+        {
+        const TDesC& filepath( aDetails.DownloadedFiles().MdcaPoint( i ) );
+        atLeastOneFile = atLeastOneFile || filepath.Length();
+            
+        // append even empty descriptors so that the arrays stay identical
+        tempDownloads->AppendL( filepath );
+        
+        DLINFO(( _L("Downloaded: %S"), 
+            &aDetails.DownloadedFiles().MdcaPoint( i ) ));
+        }
+
+    TArray<MNcdPurchaseInstallInfo*> info ( aDetails.InstallInfoL() );
+        
+    // Check download status
+    if ( !atLeastOneFile && !info.Count() ) 
+        {
+        CleanupStack::PopAndDestroy( tempDownloads );
+        DLINFO(("Nothing has been downloaded or installed"));
+        return EFalse;
+        }
+           
+    TArray<MNcdPurchaseDownloadInfo*> dlInfo ( aDetails.DownloadInfoL() );               
+    
+
+    DLTRACE(("Internalizing install infos, count: %d", info.Count() ));
+
+    RPointerArray<CNcdExtendedInstallInfo> tempInfos;
+    CleanupResetAndDestroyPushL( tempInfos );
+    
+    tempInfos.ReserveL( info.Count() );
+    iLaunchable = EFalse;        
+    
+    CNcdExtendedInstallInfo* tempInstall = NULL;
+    TBool launchable = EFalse;
+    
+    TBool atLeastOneLauncher = EFalse;
+    TBool atLeastOneLaunchableLauncher = EFalse;
+    TBool atLeastOneLauncherOpen = EFalse;
+    
+    // If there are more install infos than download infos we assume that
+    // the first install infos are for rights files
+    TInt dlIndex = dlInfo.Count() - info.Count();
+    if ( dlIndex > 0 ) 
+        {
+        dlIndex = 0;
+        }
+    
+    // Internalize infos
+    for ( TInt i = 0; i < info.Count(); ++i, ++dlIndex )
+        {
+        const MNcdPurchaseInstallInfo& install( *info[i] );
+        
+        if ( dlIndex >= 0 ) 
+            {            
+            const MNcdPurchaseDownloadInfo& download( *dlInfo[dlIndex] );
+            
+            launchable = download.IsLaunchable();
+            DLTRACE(("Launchable from purchase history: %d", launchable ));
+            
+            TBool isLauncher = IsOneOf( download.ContentUsage(), 
+                       MNcdPurchaseDownloadInfo::ELauncher,
+                       MNcdPurchaseDownloadInfo::ELauncherOpen );
+            
+            // Themes are not launchable. This also checks for reinstalled themes            
+            if ( install.ThemeName() != KNullDesC || 
+                 ( install.ThemeName() == KNullDesC &&
+                   install.ApplicationUid() == TUid::Null() &&
+                   install.Filename() == KNullDesC ) )
+                {
+                launchable = EFalse;
+                }
+            // check launcher apps
+            else if ( isLauncher )
+                {
+                atLeastOneLauncher = ETrue;
+                // Can't use IsContentInstalledL since it uses iInstallInfos-array
+                // which is generated here
+                if ( CNcdProviderUtils::IsApplicationInstalledL(
+                        install.ApplicationUid(), 
+                        install.ApplicationVersion() ) <= ENcdApplicationNotInstalled  )
+                    {
+                    DLTRACE(("Setting launchable=EFalse"));
+                    launchable = EFalse;            
+                    }
+                else 
+                    {
+                    atLeastOneLaunchableLauncher = ETrue;
+                    }
+               }
+             
+            
+            tempInstall = CNcdExtendedInstallInfo::NewLC( install,
+                download.ContentMimeType(), launchable );
+
+            tempInstall->SetUriExists( download.ContentUri().Length() != 0 );
+            // Sets content type to tempInstall according to download's contentUsage
+            SetContentType( *tempInstall, download );
+            
+            
+            if ( download.ContentUsage() == 
+                    MNcdPurchaseDownloadInfo::ELauncherOpen ) 
+                {                
+                atLeastOneLauncherOpen = ETrue;
+                }
+             
+            // Set item as launchable if at least one file is launchable    
+            if ( launchable ) 
+                {
+                iLaunchable = ETrue;
+                }
+            }
+        else 
+            {
+            DLTRACE(("Rights file"));
+            tempInstall = CNcdExtendedInstallInfo::NewLC( install,
+                KNullDesC, ETrue );
+            }        
+        
+        tempInfos.AppendL( tempInstall );
+        CleanupStack::Pop( tempInstall );
+        tempInstall = NULL;        
+            
+        DLTRACE(("Info added, iInstallInfo count: %d", iInstallInfos.Count() ));
+        }
+    
+    if ( atLeastOneLauncher && !atLeastOneLaunchableLauncher )
+        {
+        DLTRACE(("No launchable launchers, setting everything unlaunchable"));
+        iLaunchable = EFalse;
+        TInt count = tempInfos.Count();
+        while ( count-- ) 
+            {
+            tempInfos[ count ]->SetLaunchable( EFalse );
+            }
+        }
+
+    // There was at least one launcher/open dependency so we need to go through
+    // the install infos and try to find a suitable file for opening
+    if ( atLeastOneLauncherOpen && 
+         tempInfos.Count() <= dlInfo.Count() ) 
+        {
+        DLTRACE(("Setting launcher param"));
+        TInt count = tempInfos.Count();
+        
+        for ( TInt i = 0; i < count; ++i )
+            {
+            const MNcdPurchaseDownloadInfo& download( *dlInfo[ i ] );
+            if ( download.ContentUsage() == MNcdPurchaseDownloadInfo::ELauncherOpen ) 
+                {
+                SetLaunchParameterL( tempInfos, i );
+                }            
+            }
+        }
+        
+    DLTRACE(("Replacing old values with new ones"));
+
+
+    // Read installed status
+    iInstalled = ( aDetails.State() == MNcdPurchaseDetails::EStateInstalled );
+        
+    DLINFO(( "Installed: %d", iInstalled ));
+    
+    // Get purpose
+    iPurpose = aDetails.ItemPurpose();
+    DLINFO(( "Purpose: %d", iPurpose ));        
+    
+    // Replace old values
+    iInstallInfos.ResetAndDestroy();    
+    iInstallInfos = tempInfos;
+    CleanupStack::Pop( &tempInfos );
+    
+    
+    delete iDownloadedFiles;
+    iDownloadedFiles = tempDownloads;
+    CleanupStack::Pop( tempDownloads );
+    
+    TInt depCount = DependencyCount( dlInfo );
+
+    if ( !iInstalled && 
+         depCount &&
+         // must be more download infos than just deps
+         dlInfo.Count() > depCount &&
+         // install info count must be at least the amount of dlInfos 
+         // since deps have equal number of install and dl infos and
+         // all content must have been installed before
+         info.Count() >= dlInfo.Count() )
+        {
+        iInstalled = ETrue;
+        DLTRACE(("Dependency has already been installed, setting iInstalled to ETrue"));
+        }
+
+    
+    if ( iInstalledContent ) 
+        {
+        DASSERT( iInstalledContent->ApplicationUid() != TUid::Null() );
+        
+        // Disable launching if protocol says so. 
+        // By default apps defined in content info are launchable
+        iInstalledContent->SetLaunchable( iLaunchable );
+        
+        // Delete iInstalledContent if it is duplicated in purchase history
+        for ( TInt i = 0; i < iInstallInfos.Count(); ++i ) 
+            {
+            
+            if ( iInstalledContent->ApplicationUid() == 
+                 iInstallInfos[i]->ApplicationUid() )
+                {
+                DLTRACE(("App has been bought and installed"));
+                delete iInstalledContent;
+                iInstalledContent = NULL;
+                break;
+                }
+            }        
+        }
+    
+    SetContentVersionL( aDetails.Version() );
+    DLTRACEOUT(("iLaunchable: %d", iLaunchable));
+    return ETrue;
+    }
+
+
+void CNcdNodeInstall::ReceiveMessage( MCatalogsBaseMessage* aMessage,
+                                      TInt aFunctionNumber )
+    {
+    DLTRACEIN(("this-ptr: %X", this));    
+
+    DASSERT( aMessage );
+
+    // Now, we can be sure that rest of the time iMessage exists.
+    // This member variable is set for the CounterPartLost function.
+    iMessage = aMessage;
+    
+    TInt trapError( KErrNone );
+    
+    // Check which function is called by the proxy side object.
+    // Function number are located in ncdnodefunctinoids.h file.
+    switch( aFunctionNumber )
+        {
+        case NcdNodeFunctionIds::ENcdInternalize:
+            // Internalize the proxy side according to the data
+            // of this object.
+            TRAP( trapError, InternalizeRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdRelease:
+            // The proxy does not want to use this object anymore.
+            // So, release the handle from the session.
+            ReleaseRequest( *aMessage );
+            break;
+            
+        case NcdNodeFunctionIds::ENcdInstallOpenFile:
+            TRAP( trapError, OpenContentFileL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdSetApplicationInstalled:
+            TRAP( trapError, SetApplicationInstalledRequestL( *aMessage ) );
+            break;
+                    
+        default:
+            DLERROR(("Unidentified function request"));
+            DASSERT( EFalse );
+            break;
+        }
+
+    if ( trapError != KErrNone )
+        {
+        // Because something went wrong, the complete has not been
+        // yet called for the message.
+        // So, inform the client about the error if the
+        // message is still available.
+        aMessage->CompleteAndRelease( trapError );
+        }
+
+    // Because the message should not be used after this, set it NULL.
+    // So, CounterPartLost function will know that no messages are
+    // waiting the response at the moment.
+    if ( !iPeriodic ) 
+        {        
+        iMessage = NULL;        
+        }
+    
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNodeInstall::CounterPartLost( const MCatalogsSession& aSession )
+    {
+    // This function may be called whenever -- when the message is waiting
+    // response or when the message does not exist.
+    // iMessage may be NULL here, because in the end of the
+    // ReceiveMessage it is set to NULL. The life time of the message
+    // ends shortly after CompleteAndRelease is called.
+    if ( iMessage != NULL )
+        {
+        iMessage->CounterPartLost( aSession );
+        }
+    }
+                
+
+
+const MDesCArray& CNcdNodeInstall::DownloadedFiles() const
+    {
+    DASSERT( iDownloadedFiles );
+    return *iDownloadedFiles;
+    }
+                
+
+TNcdApplicationStatus CNcdNodeInstall::IsContentInstalledL( 
+    TInt aIndex,
+    TBool aIgnoreMissingUri )
+    {
+    DLTRACEIN(("aIndex: %d", aIndex));
+    DASSERT( aIndex >= 0 );
+
+    if ( aIndex >= ContentCount() ) 
+        {
+        DLTRACEOUT(("Index out of range (count = %d), returning EFalse", 
+            ContentCount() ));
+        return ENcdApplicationNotInstalled;
+        }
+
+    CNcdExtendedInstallInfo& info = *iInstallInfos[aIndex];
+            
+    TNcdApplicationStatus status = ENcdApplicationNotInstalled;
+    
+    if ( info.Filename() != KNullDesC ) 
+        {
+        DLTRACE(("Content: file"));
+        if ( BaflUtils::FileExists( 
+                CNcdProviderUtils::FileSession(),
+                info.Filename() ) ) 
+            {
+            DLTRACE(( _L("File %S exists"), &info.Filename() ));
+            status = ENcdApplicationInstalled;
+            }
+        }
+    else if ( info.ApplicationUid() != TUid::Null() )
+        {
+        DLTRACE(("Content: application"));
+        if ( aIgnoreMissingUri && !info.UriExists() ) 
+            {
+            DLTRACE(("No uri and ignoring missing uris"));
+            status = ENcdApplicationInstalled;
+            }
+        else 
+            {            
+            status = CNcdProviderUtils::IsApplicationInstalledL(
+                info.ApplicationUid(), 
+                info.ApplicationVersion() );            
+            }
+        }
+    else if ( info.ThemeName() != KNullDesC )
+        {
+        DLTRACE(("Content: theme"));
+        if ( CNcdProviderUtils::InstallationServiceL().IsThemeInstalledL(
+            info.ThemeName() ) )
+            {
+            status = ENcdApplicationInstalled;
+            }
+        }
+    info.SetInstalledStatus( status );
+    
+    return status;
+    }
+
+
+TInt CNcdNodeInstall::ContentCount() const
+    {
+    return iInstallInfos.Count();
+    }
+
+    
+TBool CNcdNodeInstall::IsAllContentInstalledL()
+    {
+    DLTRACEIN((""));
+        
+    for ( TInt i = 0; i < iInstallInfos.Count(); ++i ) 
+        {        
+        // Don't care whether older or newer version is installed as long as
+        // some version is installed, ignores application that don't have content URIs
+
+        if ( IsContentInstalledL( i, ETrue ) == ENcdApplicationNotInstalled ) 
+            {
+            return EFalse;
+            }
+        }
+    DLTRACEOUT(("All installed"));
+    return ETrue;
+    }
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//  
+TBool CNcdNodeInstall::InternalizeContentInfoL()
+    {
+    DLTRACEIN((""));
+    
+    if ( iInstallInfos.Count() ) 
+        {
+        DLTRACEOUT(("Already installed something"));
+        return EFalse;
+        }
+    
+    const CNcdNodeContentInfo* info = NULL;
+    TRAPD( err, info = &iMetadata.ContentInfoL() );
+    
+    TBool installed = EFalse;
+    if ( err == KErrNone && info->Uid() != TUid::Null() ) 
+        {
+        DLINFO(("Uid: %x", info->Uid().iUid ));
+        TNcdApplicationStatus status = 
+            CNcdProviderUtils::IsApplicationInstalledL(
+                info->Uid(), 
+                info->Version() );
+        
+        // Application can be older version for it to be considered installed
+        // Upgrade will be available for the user
+        installed = status != ENcdApplicationNotInstalled;
+
+        delete iInstalledContent;
+        iInstalledContent = NULL;
+
+        iInstalled = installed;    
+        iLaunchable = installed;
+                            
+        if ( installed ) 
+            {
+            DLTRACE(("Application installed"));
+            CNcdExtendedInstallInfo* install = CNcdExtendedInstallInfo::NewLC();
+            install->SetApplicationUid( info->Uid() );
+            
+            // This ensures that CNcdInstalledApplication actually checks the 
+            // application's version number when it checks if it's installed
+            // or not
+            install->SetUriExists( ETrue );
+
+            // This will be used to determine whether the app is actually installed
+            // or not
+            install->SetApplicationVersionL( info->Version() );
+            install->SetLaunchable( ETrue );
+            
+            // don't set because it can mess upgrade handling in 
+            // CNcdNodeMetadata::HandleContentUpgradeL
+            iContentVersion = TCatalogsVersion();
+
+            iInstalledContent = install;
+            CleanupStack::Pop( install );
+            }
+        }
+    return installed;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Content version getter
+// ---------------------------------------------------------------------------
+//  
+const TCatalogsVersion& CNcdNodeInstall::ContentVersion() const
+    {
+    return iContentVersion;
+    }
+
+    
+
+void CNcdNodeInstall::InternalizeRequestL( MCatalogsBaseMessage& aMessage )
+    {
+    DLTRACEIN((""));
+    
+    CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+    CleanupStack::PushL( buf );
+    
+    RBufWriteStream stream( *buf );
+    CleanupClosePushL( stream );
+
+
+    // Include all the necessary node data to the stream
+    ExternalizeDataForRequestL( stream );     
+    
+    
+    // Commits data to the stream when closing.
+    CleanupStack::PopAndDestroy( &stream );
+
+
+    // If this leaves, ReceiveMessage will complete the message.
+    // NOTE: that here we expect that the buffer contains at least
+    // some data. So, make sure that ExternalizeDataForRequestL inserts
+    // something to the buffer.
+    aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );        
+        
+    
+    DLTRACE(("Deleting the buf"));
+    CleanupStack::PopAndDestroy( buf );
+        
+    DLTRACEOUT((""));
+    }
+    
+
+void CNcdNodeInstall::ExternalizeDataForRequestL( RWriteStream& aStream )
+    {
+    DLTRACEIN(("this-ptr: %X", this));
+
+    // Install existed. So, insert info that meta data was found.
+    aStream.WriteInt32L( ClassId() );
+
+    // Add additional content to the stream.
+    // Make sure that this matches to the order that is used in the proxy
+    // side when this stream is internalized.
+    // NOTE: Be careful with the 8- and 16-bit descriptors. Remember to check
+    // if the proxy wants the data in 16 or 8 bits?    
+
+    aStream.WriteInt32L( iPurpose );
+
+    aStream.WriteInt32L( iInstalled );
+    
+    aStream.WriteInt32L( iLaunchable );
+    
+    TInt count = iInstallInfos.Count();
+    
+    if ( iInstalledContent ) 
+        {
+        DLTRACE(("App from content info is installed, adding install info"));        
+        aStream.WriteInt32L( count + 1 );    
+        iInstalledContent->ExternalizeL( aStream );
+        }
+    else
+        {
+        aStream.WriteInt32L( count );
+        }
+        
+    DLTRACE(("Externalizing infos, count: %d", count ));
+        
+    for ( TInt i = 0; i < count; ++i )
+        {
+        iInstallInfos[i]->ExternalizeL( aStream );        
+        }  
+
+    DLTRACEOUT((""));
+    }
+    
+
+// ---------------------------------------------------------------------------
+// Handle release requests
+// ---------------------------------------------------------------------------
+//  
+void CNcdNodeInstall::ReleaseRequest( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((""));
+
+    // Decrease the reference count for this object.
+    // When the reference count reaches zero, this object will be destroyed
+    // and removed from the session.
+    MCatalogsSession& requestSession( aMessage.Session() );
+    TInt handle( aMessage.Handle() );
+
+    // Send complete information back to proxy.
+    aMessage.CompleteAndRelease( KErrNone );
+        
+    // Remove this object from the session.
+    requestSession.RemoveObject( handle );
+        
+    DLTRACEOUT((""));
+    }
+
+
+// ---------------------------------------------------------------------------
+// Opens a content file
+// ---------------------------------------------------------------------------
+//  
+void CNcdNodeInstall::OpenContentFileL( MCatalogsBaseMessage& aMessage )
+    {
+    DLTRACEIN((""));
+    RBuf8 buf;
+    buf.CreateL( aMessage.InputLength() );
+    CleanupClosePushL( buf );
+    User::LeaveIfError( aMessage.ReadInput( buf ) );
+    
+    // Read the requested file index    
+    TInt fileIndex = Des8ToInt( buf );
+    if ( fileIndex < 0 || fileIndex >= iInstallInfos.Count() ) 
+        {
+        DLERROR(( "Index: %d out of range 0-%d", 
+            fileIndex, iInstallInfos.Count() ));
+        User::Leave( KErrArgument );
+        }
+        
+    DLTRACE(( _L("Opening file %S from index: %d"), 
+        &iInstallInfos[fileIndex]->Filename(), fileIndex ));
+    
+    iRetryCount = 0;
+    iFileIndex = fileIndex;        
+    
+    // Try to open the file
+    TRAPD( err, OpenContentFileL() );
+    
+    // N-series hackfix: if the file is in use, 
+    // retry opening it about 0.5 seconds later
+    if ( err == KErrInUse ) 
+        {
+        DLTRACE(("File in use, retry a little bit later"));
+        if ( iPeriodic ) 
+            {
+            iPeriodic->Cancel();
+            }
+        else
+            {            
+            iPeriodic = CPeriodic::NewL( 0 );
+            }
+        TTimeIntervalMicroSeconds32 delay( KOpenDelay );
+        iPeriodic->Start( delay, delay, TCallBack( CallBackOpenFile, this ) );
+        }
+    else
+        {
+        User::LeaveIfError( err );
+        }
+    
+    CleanupStack::PopAndDestroy( &buf ); // buf    
+    DLTRACEOUT((""));
+    }
+
+
+void CNcdNodeInstall::SetApplicationInstalledRequestL( MCatalogsBaseMessage& aMessage )
+    {
+    DLTRACEIN((""));
+
+    // Note! 
+    // This function is only meant for the proxy side usage and for
+    // certain specific exception cases. Also, this will only allow 
+    // application info updates. For example, themes are not handled here.
+
+
+    // Get the data that was sent from the proxy side.
+    HBufC8* input = HBufC8::NewLC( aMessage.InputLength() );
+    TPtr8 inputPtr = input->Des();
+    aMessage.ReadInput( inputPtr );
+    RDesReadStream inputStream( *input );
+    CleanupClosePushL( inputStream );
+
+    TInt errorCode( inputStream.ReadInt32L() );
+    DLINFO(( "Error code from message: %d", errorCode ));
+
+    CleanupStack::PopAndDestroy( &inputStream );
+    CleanupStack::PopAndDestroy( input );    
+    
+    
+    CNcdPurchaseHistoryDb& purchaseHistoryDb( 
+        iMetadata.NodeManager().PurchaseHistory() );
+
+    CNcdPurchaseDetails* details( 
+        NcdPurchaseHistoryUtils::PurchaseDetailsLC(
+            purchaseHistoryDb,
+            iMetadata.Identifier().ClientUid(),
+            iMetadata.Identifier(),
+            EFalse ) );
+
+    if ( details == NULL )
+        {
+        // Because contents have already been downloaded, there should always
+        // be some details available. Because content has been installed, we
+        // suppose that the content is already downloaded also.
+        User::Leave( KErrNotFound );
+        }
+    else
+        {
+        // We got the newest details.
+        if ( errorCode == KErrNone )
+            {
+            if ( details->State() != MNcdPurchaseDetails::EStateInstalled )
+                {
+                DLINFO(("Content not installed yet"));
+                // Update the fileinfo only if the state is not already installed.
+                // If the state is installed, then the fileinfo is already
+                // up-to-date.
+                const CNcdNodeContentInfo& contentInfo(
+                    iMetadata.ContentInfoL() );
+                if ( ( contentInfo.Purpose() 
+                       & ENcdItemPurposeTheme ) != 0 )
+                    {
+                    DLINFO(("Content purpose is theme. Not allowed."));
+                    // A minor sanity check because themes may have an UID given.
+                    // So, if the metadata suggests that the content is theme,
+                    // then leave here. Otherwise, trust the user.
+                    User::Leave( KErrAbort );
+                    }
+                TUid contentUid( contentInfo.Uid() );
+                const TDesC& version( contentInfo.Version() );
+                // The item state is installed when installed info count
+                // corresponds the download info count
+                TInt installCount( details->InstallInfoCount() );
+                TInt downloadCount( details->DownloadInfoCount() );
+                for ( TInt i = installCount; i < downloadCount; ++i )
+                    {
+                    // Set missing install infos.
+                    // Notice, that we only know the main content UID and version.
+                    // So, if the content is a bundle, then we need to fake
+                    // the UIDs and version here and just use the one that 
+                    // metadata content info can provide us.
+                    CNcdPurchaseInstallInfo* installInfo(
+                        CNcdPurchaseInstallInfo::NewLC() );
+                    installInfo->SetApplicationUid( contentUid );
+                    installInfo->SetApplicationVersionL( version );
+                    // Insert new details in the end of the array.
+                    details->InsertInstallInfoL( installInfo, 
+                                                 details->InstallInfoCount() );
+                    CleanupStack::Pop( installInfo );
+                    }
+                }
+
+            // Because error code was KErrNone, the content is thought as
+            // successfully installed. So, delete unnecessary installation
+            // files. Notice, that there may be installation files available
+            // even if the details state is EStateInstalled because download
+            // could also  be done again even though installation has been 
+            // successfull already during the first time. 
+            // Get details file information.
+            const MDesCArray& files = details->DownloadedFiles();
+            for( TInt i = 0; i < files.MdcaCount(); ++i )
+                {
+                const TDesC& filePath( files.MdcaPoint( i ) );
+                DLINFO((_L("Delete file: %S"), &filePath));
+                // Notice, that we need to do the deletion here in the server side.
+                // The installation files may exist in the NCD Engine server
+                // private directory and that directory is normally
+                // accessable only by the NCD Engine server side.
+                TInt deleteError( 
+                    CNcdProviderUtils::InstallationServiceL().
+                        DeleteFile( filePath ) );
+                DLINFO(( "Files: %d, delete error: %d", i, deleteError ));
+                }            
+            }
+
+        // Set the error code and the lates operation time
+        details->SetLastOperationErrorCode( errorCode );
+        details->SetLastUniversalOperationTime();
+            
+        // Save purhcase details into the purchase history.
+        // This will replace the old detail.
+        // But, do not replace old icon, because we did not load it
+        // for the details above.
+        purchaseHistoryDb.SavePurchaseL( *details, EFalse );
+        
+        CleanupStack::PopAndDestroy( details );
+        details = NULL;
+        }
+
+    // Complete the message because everything went ok. 
+    // If some operations above left, then ReceiveMessage will handle
+    // those cases.
+    aMessage.CompleteAndRelease( KErrNone );
+    }
+
+// ---------------------------------------------------------------------------
+// Opens a content file, called by CallbackOpenFile
+// ---------------------------------------------------------------------------
+//  
+void CNcdNodeInstall::OpenContentFileRunner()
+    {
+    DLTRACEIN((""));
+    TRAPD( err, OpenContentFileL() );
+    iRetryCount++;
+    if ( err != KErrInUse || iRetryCount >= KMaxRetries ) 
+        {
+        DASSERT( iPeriodic ) 
+        DLTRACE(("Deleting periodic timer"));
+        delete iPeriodic;
+        iPeriodic = NULL;
+
+        if ( err != KErrNone )
+            {
+            DLTRACE(("Handling other errors"));
+            iMessage->CompleteAndRelease( err );
+            iMessage = NULL;
+            }
+        
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Opens a content file
+// ---------------------------------------------------------------------------
+//  
+void CNcdNodeInstall::OpenContentFileL()
+    {
+    DLTRACEIN((""));
+    RFs fs;
+    User::LeaveIfError( fs.Connect() );
+    CleanupClosePushL( fs );
+    
+    DLTRACE(("Sharing the file server"));
+    User::LeaveIfError( fs.ShareProtected() );
+    
+    DLTRACE(("Trying to open the file"));
+    RFile file;
+    CleanupClosePushL( file );
+    User::LeaveIfError( file.Open( fs, 
+        iInstallInfos[iFileIndex]->Filename(),
+        NcdProviderDefines::KNcdSharableFileOpenFlags ) );
+        
+        
+    DLTRACE(("File open, transferring to client"));
+    DASSERT( iMessage );
+    iMessage->CompleteAndReleaseL( fs, file );
+    iMessage = NULL;
+    DLTRACE(("File transferred"));
+    CleanupStack::PopAndDestroy( 2, &fs ); // file, fs    
+    }
+
+
+// ---------------------------------------------------------------------------
+// Calculate the number of dependencies
+// ---------------------------------------------------------------------------
+//  
+TInt CNcdNodeInstall::DependencyCount( 
+    const TArray<MNcdPurchaseDownloadInfo*>& aInfos ) const
+    {
+    DLTRACEIN((""));
+    TInt depCount = 0;
+    for ( TInt i = 0; i < aInfos.Count(); ++i )    
+        {
+        if ( NcdPurchaseHistoryUtils::IsDependency( *aInfos[i] ) )
+            {
+            depCount++;
+            }
+        }
+    return depCount;
+    }
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//  
+void CNcdNodeInstall::SetContentType( 
+    CNcdExtendedInstallInfo& aInstall,
+    const MNcdPurchaseDownloadInfo& aDownload ) const
+    {
+    DLTRACEIN((""));
+    switch( aDownload.ContentUsage() ) 
+        {
+        case MNcdPurchaseDownloadInfo::EDownloadable:
+            {
+            aInstall.SetContentType( MNcdInstalledContent::EInstalledContent );
+            break;
+            }
+
+        case MNcdPurchaseDownloadInfo::EDependency:
+            {
+            aInstall.SetContentType( MNcdInstalledContent::EInstalledDependency );
+            break;
+            }
+        
+        case MNcdPurchaseDownloadInfo::ELauncher:  // flowthrough      
+        case MNcdPurchaseDownloadInfo::ELauncherOpen:
+            {
+            aInstall.SetContentType( MNcdInstalledContent::EInstalledLauncher );
+            break;
+            }
+                
+        default: 
+            {
+            NCD_ASSERT_ALWAYS( 0, ENcdPanicIndexOutOfRange );
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//  
+void CNcdNodeInstall::SetLaunchParameterL( 
+    RPointerArray<CNcdExtendedInstallInfo>& aInstalls, 
+    TInt aIndex ) const
+    {
+    DLTRACEIN((""));
+    TInt count = aInstalls.Count();
+    CNcdExtendedInstallInfo& launcher( *aInstalls[ aIndex ] );
+    
+    // aIndex is the index of aInstall so increase it
+    aIndex++;
+    while ( aIndex < count ) 
+        {        
+        if ( aInstalls[ aIndex ]->Filename().Length() && 
+             aInstalls[ aIndex ]->IsLaunchable() ) 
+            {
+            DLTRACE(( _L("Found \"%S\", setting as parameter"), 
+                &aInstalls[ aIndex ]->Filename() ));
+            launcher.SetParameterL( aInstalls[ aIndex ]->Filename() );
+            break;
+            }
+        aIndex++;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//  
+void CNcdNodeInstall::SetContentVersionL( const TDesC& aVersion ) 
+    {
+    DLTRACEIN((""));
+    iContentVersion = TCatalogsVersion();    
+    
+    // Convert the version number in purchase history to TCatalogsVersion    
+    TRAPD( err, TCatalogsVersion::ConvertL( 
+        iContentVersion, aVersion ) );
+        
+    LeaveIfNotErrorL( err, KErrArgument, KErrGeneral );
+    
+    }