diff -r 000000000000 -r ba25891c3a9e ncdengine/provider/server/src/ncdnodeinstallimpl.cpp --- /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 +#include +#include + + +#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( 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 info ( aDetails.InstallInfoL() ); + + // Check download status + if ( !atLeastOneFile && !info.Count() ) + { + CleanupStack::PopAndDestroy( tempDownloads ); + DLINFO(("Nothing has been downloaded or installed")); + return EFalse; + } + + TArray dlInfo ( aDetails.DownloadInfoL() ); + + + DLTRACE(("Internalizing install infos, count: %d", info.Count() )); + + RPointerArray 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& 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& 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 ); + + }