/*
* 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:
*
*/
#include "ncdinstalloperationimpl.h"
#include <s32mem.h>
#include <f32file.h>
#include <bautils.h>
#include "catalogsbasemessage.h"
#include "ncdnodemanager.h"
#include "ncdnodeimpl.h"
#include "ncdnodeidentifier.h"
#include "catalogsutils.h"
#include "catalogscontext.h"
#include "ncdproviderdefines.h"
#include "ncdnodeclassids.h"
#include "catalogsconstants.h"
#include "ncdinstallinfo.h"
#include "ncdfileinfo.h"
#include "ncdpurchasehistorydbimpl.h"
#include "ncdutils.h"
#include "ncderrors.h"
#include "ncdoperationremovehandler.h"
#include "ncdnodeinstallimpl.h"
#include "ncdnodedownloadimpl.h"
#include "ncdnodecontentinfoimpl.h"
#include "ncdnodemetadataimpl.h"
#include "ncdnodelink.h"
#include "ncdproviderutils.h"
#include "ncdpurchasehistoryutils.h"
#include "ncdinstallreportobserver.h"
#include "catalogsaccesspointmanager.h"
#include "catalogsconnectionmethod.h"
#include "catalogshttpconnectionmanager.h"
#include "ncdgeneralmanager.h"
#include "catalogsdebug.h"
// ======== MEMBER FUNCTIONS ========
// ---------------------------------------------------------------------------
// NewL
// ---------------------------------------------------------------------------
//
CNcdInstallOperation* CNcdInstallOperation::NewL(
MNcdOperationRemoveHandler& aRemoveHandler,
const CNcdNodeIdentifier& aNodeId,
CNcdGeneralManager& aGeneralManager,
MCatalogsHttpSession& aHttpSession,
MNcdInstallReportObserver& aReportObserver,
MCatalogsSession& aSession )
{
CNcdInstallOperation* self = new( ELeave ) CNcdInstallOperation(
aRemoveHandler,
aGeneralManager,
aHttpSession,
aReportObserver,
aSession );
CleanupClosePushL( *self );
self->ConstructL( aNodeId );
CleanupStack::Pop();
return self;
}
// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CNcdInstallOperation::~CNcdInstallOperation()
{
DLTRACEIN((""));
delete iNodeId;
// Deletes the JAD from disk and also deletes iJadFile
DeleteJad();
DLTRACEOUT((""));
}
// ---------------------------------------------------------------------------
// Node Id getter
// ---------------------------------------------------------------------------
//
const CNcdNodeIdentifier& CNcdInstallOperation::NodeIdentifier() const
{
return *iNodeId;
}
// ---------------------------------------------------------------------------
// Cancel
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::Cancel()
{
DLTRACEIN(( "" ));
// Nothing to do here. Most of the install operation
// functionality is in proxy side.
DLTRACEOUT(( "" ));
}
// ---------------------------------------------------------------------------
// Receive message
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::ReceiveMessage(
MCatalogsBaseMessage* aMessage,
TInt aFunctionNumber )
{
DLTRACEIN((""));
DASSERT( aMessage );
DLINFO(( "Handle: %i, aFunctionNumber=%d",
aMessage->Handle(),
aFunctionNumber));
// Now, we can be sure that rest of the time iMessage exists.
// This member variable is set for the CounterPartLost function.
iMessage = aMessage;
TRAPD( err, DoReceiveMessageL( aMessage, aFunctionNumber ) );
if ( err != KErrNone )
{
DLINFO(( ( "Error: %d" ), err ));
CompleteMessage( iMessage,
ENCDOperationMessageCompletionError,
err );
}
// 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.
iMessage = NULL;
DLTRACEOUT((""));
}
// ---------------------------------------------------------------------------
// Counter part lost
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::CounterPartLost( const MCatalogsSession& aSession )
{
DLTRACEIN((""));
// 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 );
}
DLTRACEOUT((""));
}
// ---------------------------------------------------------------------------
// RunOperation
// ---------------------------------------------------------------------------
//
TInt CNcdInstallOperation::RunOperation()
{
DLTRACEIN(( "Pending message: %X", iPendingMessage ));
DLTRACEOUT((""));
return KErrNone;
}
// ---------------------------------------------------------------------------
// Initializer
// ---------------------------------------------------------------------------
//
TInt CNcdInstallOperation::Initialize()
{
DLTRACEIN( ( "" ) );
TRAPD( err,
{
DLTRACE(("Writing initialize response"));
CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
CleanupStack::PushL( buf );
RBufWriteStream stream( *buf );
CleanupClosePushL( stream );
// write completion code
stream.WriteInt32L( ENCDOperationMessageCompletionInit );
// Get the file count from the node and return it to the proxy
// Notice here that the node has to have some kind of metadata
// in order the install operation to start.
DLINFO(("Get the metadata of the node"));
CNcdNode& node( iNodeManager->NodeL( *iNodeId ) );
CNcdNodeMetaData& metaData( node.NodeMetaDataL() );
DLINFO(("Get the install object of the metadata."));
CNcdNodeInstall& install( metaData.InstallL() );
stream.WriteInt32L( install.DownloadedFiles().MdcaCount() );
CleanupStack::PopAndDestroy( &stream );
DLINFO(("Create report"));
// Because everything has gone smoothly so far,
// create the install report for the server reports.
CreateReportL();
DLTRACE(("Response length: %i", buf->Size() ));
iPendingMessage->CompleteAndReleaseL( buf->Ptr(0), KErrNone );
iPendingMessage = NULL;
CleanupStack::PopAndDestroy( buf );
});
if ( err != KErrNone )
{
DLTRACE( ( "Err: %d", err ) );
iPendingMessage->CompleteAndRelease( err );
iPendingMessage = NULL;
}
DLTRACEOUT(( "err: %d", err ));
return err;
}
// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
//
CNcdInstallOperation::CNcdInstallOperation(
MNcdOperationRemoveHandler& aRemoveHandler,
CNcdGeneralManager& aGeneralManager,
MCatalogsHttpSession& aHttpSession,
MNcdInstallReportObserver& aReportObserver,
MCatalogsSession& aSession ) :
CNcdBaseOperation( aGeneralManager, &aRemoveHandler, EInstallOperation, aSession ),
iHttpSession( aHttpSession ),
iAccessPointManager( aGeneralManager.AccessPointManager() ),
iReportObserver( aReportObserver ),
iReportId( KNcdReportNotSupported )
{
}
// ---------------------------------------------------------------------------
// ConstructL
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::ConstructL( const CNcdNodeIdentifier& aNodeId )
{
DLTRACEIN( ( "" ) );
// Call ConstructL for the base class
CNcdBaseOperation::ConstructL();
// copy the identifier
iNodeId = CNcdNodeIdentifier::NewL( aNodeId );
iInstallService = &CNcdProviderUtils::InstallationServiceL();
DLTRACEOUT(( "" ));
}
// ---------------------------------------------------------------------------
// Gets info for an installable file from the node
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::GetFileInfoL( MCatalogsBaseMessage& aMessage )
{
DLTRACEIN((""));
TInt nextFile = ReadFileIndexL( aMessage );
CNcdNode& node( iNodeManager->NodeL( *iNodeId ) );
// Notice that in order the node to start install, the
// node has to have some kind of metadata
CNcdNodeMetaData& metaData( node.NodeMetaDataL() );
CNcdNodeDownload& nodeDl = metaData.DownloadL();
CNcdNodeInstall& install( metaData.InstallL() );
// Check that file index is in the valid range
if ( nextFile < 0 || nextFile >= install.DownloadedFiles().MdcaCount() )
{
DLERROR(("Invalid index"));
User::Leave( KErrArgument );
}
// Get item purpose
TUint completePurpose = 0;
TPtrC contentMime;
DeleteJad();
TRAPD( error,
{
const CNcdNodeContentInfo& contentInfo =
node.NodeMetaData()->ContentInfoL();
completePurpose = contentInfo.Purpose();
contentMime.Set( contentInfo.MimeType() );
DLINFO(( _L("Content mime: %S"), &contentMime ));
});
LeaveIfNotErrorL( error, KErrNotFound );
// By default, use unknown purpose since installer
// uses purpose for installing themes
TNcdItemPurpose purpose = ENcdItemPurposeUnknown;
// Check if the purpose includes theme or application
if ( completePurpose & ENcdItemPurposeTheme )
{
DLTRACE(("Purpose: Theme"));
purpose = ENcdItemPurposeTheme;
}
else if ( completePurpose & ENcdItemPurposeApplication
|| completePurpose & ENcdItemPurposeGame
|| completePurpose & ENcdItemPurposeScreensaver )
{
DLTRACE(("Purpose: Application"));
purpose = ENcdItemPurposeApplication;
}
// Used to index downloadInfos.
TInt downloadInfoIndex = nextFile;
// This check used to be for handling rights objects that were not really
// rights objects, eg. a picture given in the rights uri but now it has
// been removed
if ( install.DownloadedFiles().MdcaCount() >
nodeDl.DownloadInfo().Count() )
{
DLERROR(("Too many downloaded files, leaving with KErrCorrupt"));
User::Leave( KErrCorrupt );
}
DLTRACE(("File index: %d, downloadInfoIndex: %d", nextFile, downloadInfoIndex ));
CNcdFileInfo* fileInfo = NULL;
// Use normal install by default
CNcdInstallInfo::TNcdInstallType installType =
CNcdInstallInfo::ENcdInstallNormal;
// Skip files that have not been downloaded or are already installed
// Files that are downloaded are not skipped, doesn't matter
// if they are installed or not
while( nextFile < install.DownloadedFiles().MdcaCount() &&
( !install.DownloadedFiles().MdcaPoint( nextFile ).Length() ||
// Check if file is missing and is installed, if it's missing
// and not installed, we give an error by failing the installation
// on proxy side when the file is missing
( !BaflUtils::FileExists( CNcdProviderUtils::FileSession(),
install.DownloadedFiles().MdcaPoint( nextFile ) ) && (
install.IsContentInstalledL( nextFile, EFalse ) >= ENcdApplicationInstalled ||
// unless the file is launcher application which we can happily skip over
IsOneOf( nodeDl.DownloadInfo()[ downloadInfoIndex ]->ContentUsage(),
MNcdPurchaseDownloadInfo::ELauncher,
MNcdPurchaseDownloadInfo::ELauncherOpen,
MNcdPurchaseDownloadInfo::EConsumable ) ) ) ) )
{
DLTRACE(("Skipping installed files or not downloaded files"));
nextFile++;
downloadInfoIndex++;
}
// We may have skipped over the last possible file so we have to
// complete the operation
if ( nextFile == install.DownloadedFiles().MdcaCount() )
{
DLERROR(("Either nothing has been downloaded or everything is already installed"));
HandleAllFilesInstalledL( nextFile, aMessage );
DLTRACEOUT(("Operation complete because all files have been installed"));
return;
}
// Shortcut to correct download info
MNcdPurchaseDownloadInfo* downloadInfo(
nodeDl.DownloadInfo()[ downloadInfoIndex ] );
// Set dependency flag that we know not to update dependency/launcher
iIsDependency = NcdPurchaseHistoryUtils::IsDependency( *downloadInfo );
DLINFO(( _L("Descriptor type: %S"), &downloadInfo->DescriptorType() ));
DLINFO(( _L("Descriptor name: %S"), &downloadInfo->DescriptorName() ));
DLINFO(( _L("Descriptor URI: %S"), &downloadInfo->DescriptorUri() ));
if ( downloadInfo->ContentMimeType().MatchF(
KMimeTypeMatch1JavaApplication ) != KErrNotFound ||
downloadInfo->ContentMimeType().MatchF(
KMimeTypeMatch2JavaApplication ) != KErrNotFound ||
contentMime.MatchF(
KMimeTypeMatch1JavaApplication ) != KErrNotFound ||
contentMime.MatchF(
KMimeTypeMatch2JavaApplication ) != KErrNotFound )
{
if ( downloadInfo->DescriptorType().CompareF(
KDescriptorTypeJad ) == 0 )
{
DLINFO(("Java app with JAD"));
purpose = ENcdItemPurposeApplication;
installType = CNcdInstallInfo::ENcdInstallJad;
}
else
{
DLINFO(("Java-application"));
// Ensure that purpose is correct
purpose = ENcdItemPurposeApplication;
installType = CNcdInstallInfo::ENcdInstallJar;
}
}
else if ( downloadInfo->ContentMimeType().MatchF(
KMimeTypeMatchJad ) != KErrNotFound ||
contentMime.MatchF( KMimeTypeMatchJad ) != KErrNotFound )
{
DLINFO(("Java app with JAD"));
purpose = ENcdItemPurposeApplication;
installType = CNcdInstallInfo::ENcdInstallJad;
}
DLTRACE(("Creating fileinfo"));
// Create file info for proxy-side installer
fileInfo = CNcdFileInfo::NewLC(
install.DownloadedFiles().MdcaPoint( nextFile ),
nodeDl.DownloadInfo()[ downloadInfoIndex ]->ContentMimeType(),
purpose );
if ( installType == CNcdInstallInfo::ENcdInstallJad )
{
DLINFO(( _L("Descriptor type: %S"), &downloadInfo->DescriptorType() ));
DLINFO(( _L("Descriptor name: %S"), &downloadInfo->DescriptorName() ));
DLINFO(( _L("Descriptor URI: %S"), &downloadInfo->DescriptorUri() ));
DLINFO(( "Descriptor Data: %S", &downloadInfo->DescriptorData() ));
if ( downloadInfo->DescriptorData().Length() )
{
// This "if" is an ugly fix for embedded DD descriptors where
// the .dm file is given in downloaddetails
if ( !(downloadInfo->DescriptorType() == KDescriptorTypeOdd &&
downloadInfo->ContentUri().Length() ) )
{
// Writing JAD to file on this side because proxies can't
// write to engine's private dir
if ( iJadFile )
{
DeletePtr( iJadFile );
}
iJadFile =
CNcdProviderUtils::InstallationServiceL().WriteJadL(
fileInfo->FilePath(), downloadInfo->DescriptorData() );
}
}
else
{
DLINFO(("No descriptor for JAD install"));
}
// Ensure that mime is JAD
fileInfo->SetMimeTypeL( KMimeTypeMatchJad );
}
CNcdInstallInfo* info = CNcdInstallInfo::NewL( fileInfo,
installType );
CleanupStack::Pop( fileInfo );
CleanupStack::PushL( info );
info->SetIndex( nextFile );
MCatalogsBaseMessage* message = &aMessage;
// Send the info back
TInt err = CompleteMessage(
message,
ENCDOperationMessageCompletionComplete,
*info,
KErrNone );
CleanupStack::PopAndDestroy( info );
DLTRACEOUT(("err: %d", err));
}
// ---------------------------------------------------------------------------
// Completes the message correctly when all files have already been installed
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::HandleAllFilesInstalledL(
TInt aFinalIndex, MCatalogsBaseMessage& aMessage )
{
DLTRACEIN((""));
CNcdInstallInfo* info = CNcdInstallInfo::NewL( NULL,
CNcdInstallInfo::ENcdInstallNormal );
CleanupStack::PushL( info );
info->SetIndex( aFinalIndex );
MCatalogsBaseMessage* message = &aMessage;
// Send the info back
TInt err = CompleteMessage(
message,
ENCDOperationMessageCompletionComplete,
*info,
KErrNone );
CleanupStack::PopAndDestroy( info );
DLTRACEOUT(("Err: %d", err));
}
// ---------------------------------------------------------------------------
// Updates the info of an installed file
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::UpdateInstalledFileInfoL(
MCatalogsBaseMessage& aMessage )
{
DLTRACEIN((""));
RCatalogsMessageReader reader;
reader.OpenLC( aMessage );
// Read input message
DLTRACE(("Reading file index"));
TInt index = reader().ReadInt32L();
// Read the info from the stream
CNcdFileInfo* info = CNcdFileInfo::NewLC( reader() );
// Read uids of installed applications
TInt appUids = reader().ReadInt32L();
DLTRACE(( "Reading app uids: %d", appUids ));
RArray<TUid> uids;
CleanupClosePushL( uids );
uids.ReserveL( appUids );
while( appUids )
{
uids.AppendL( TUid::Uid( reader().ReadInt32L() ) );
DLINFO(("Read UID: %x", uids[uids.Count() - 1] ));
--appUids;
}
// Installed dependencies/upgrades are not updated to purchase history
if ( !iIsDependency )
{
//update purchase history with the info
UpdatePurchaseHistoryL( *info, uids,
aMessage.Session().Context().FamilyId() );
}
CleanupStack::PopAndDestroy( 3, &reader ); // uids, info, reader
DLTRACE(("Updating node from purchase history"));
// Update node from the purchase history
iNodeManager->InstallHandlerL( *iNodeId );
DLTRACE(("Completing message"));
MCatalogsBaseMessage* message = &aMessage;
TInt err = CompleteMessage(
message,
ENCDOperationMessageCompletionComplete,
KErrNone );
DLTRACEOUT((""));
}
void CNcdInstallOperation::CreateReportL()
{
DLTRACEIN((""));
CNcdNode& node( iNodeManager->NodeL( *iNodeId ) );
CNcdNodeMetaData& metaData( node.NodeMetaDataL() );
TNcdReportStatusInfo info( ENcdReportCreate, KErrNone );
// Use the node identifier to identify the content in install report.
// Node id uniquely identifies the node that contains contents
// that will be installed. One node may contains multiple contents but
// they are all thought as one bundle, in one operation. Also, notice that
// multiple nodes can contain same metadata and same content.
/**
* @ Get timestamp and purchase option id from purchase details and
* set them to the report
*/
iReportId =
iReportObserver.RegisterInstallL(
iNodeId->NodeId(),
metaData.Identifier(),
info,
metaData.Identifier().ServerUri(),
metaData.Identifier().NodeNameSpace() );
// Access point is set when report is started.
// Then base message is used to get required info.
}
void CNcdInstallOperation::StartReportL( MCatalogsBaseMessage& aMessage )
{
DLTRACEIN((""));
// Set access point for report.
UpdateReportAccessPointL( aMessage.Session().Context().FamilyId() );
TNcdReportStatusInfo info( ENcdReportStart, KErrNone );
iReportObserver.ReportInstallStatusL(
iReportId,
info );
// If this leaves, ReceiveMessge will complete the message.
aMessage.CompleteAndRelease( KErrNone );
}
void CNcdInstallOperation::CompleteReportL( MCatalogsBaseMessage& aMessage )
{
DLTRACEIN((""));
RCatalogsMessageReader reader;
reader.OpenLC( aMessage );
RReadStream& stream( reader() );
TInt errorCode( stream.ReadInt32L() );
CleanupStack::PopAndDestroy( &reader );
TNcdReportStatus status( ENcdReportSuccess );
if ( errorCode == KErrNone )
{
status = ENcdReportSuccess;
}
else if ( errorCode == KErrCancel )
{
status = ENcdReportCancel;
}
else
{
status = ENcdReportFail;
}
// Create the status info object with the given info.
TNcdReportStatusInfo info( status, errorCode );
iReportObserver.ReportInstallStatusL(
iReportId,
info );
// If this leaves, ReceiveMessge will complete the message.
aMessage.CompleteAndRelease( KErrNone );
}
// ---------------------------------------------------------------------------
// UpdateReportAccessPointL
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::UpdateReportAccessPointL( const TUid& aClientUid )
{
DLTRACEIN((""));
CNcdPurchaseHistoryDb& db = iNodeManager->PurchaseHistory();
CNcdNode& node( iNodeManager->NodeL( *iNodeId ) );
CNcdNodeMetaData& metadata( node.NodeMetaDataL() );
CNcdPurchaseDetails* purchase =
NcdPurchaseHistoryUtils::PurchaseDetailsLC(
db,
aClientUid,
metadata.Identifier(),
EFalse );
// Create origin identifier
CNcdNodeIdentifier* originIdentifier =
CNcdNodeIdentifier::NewL(
node.Identifier().NodeNameSpace(),
purchase->OriginNodeId(),
node.Identifier().ClientUid() );
CleanupStack::PopAndDestroy( purchase );
CleanupStack::PushL( originIdentifier );
// Get report ap
TUint32 apId( 0 );
TInt error =
iAccessPointManager.AccessPointIdL(
*originIdentifier,
MCatalogsAccessPointManager::EBrowse,
aClientUid,
apId );
TCatalogsConnectionMethod reportAp;
if ( error == KErrNone )
{
DLTRACE(( "Setting access point %d for reports", apId ))
reportAp =
TCatalogsConnectionMethod(
apId,
ECatalogsConnectionMethodTypeAccessPoint );
}
if ( reportAp.iId == 0 )
{
reportAp = iHttpSession.ConnectionManager().DefaultConnectionMethod();
}
CleanupStack::PopAndDestroy( originIdentifier );
iReportObserver.SetInstallReportAccessPoint(
iReportId,
reportAp );
}
// ---------------------------------------------------------------------------
// Updates purchase history
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::UpdatePurchaseHistoryL( const CNcdFileInfo& aInfo,
const RArray<TUid>& aAppUids, const TUid& aClientUid )
{
DLTRACEIN((""));
CNcdPurchaseHistoryDb& db = iNodeManager->PurchaseHistory();
CNcdNode& node( iNodeManager->NodeL( *iNodeId ) );
CNcdNodeMetaData& metadata( node.NodeMetaDataL() );
CNcdPurchaseDetails* purchase = NcdPurchaseHistoryUtils::PurchaseDetailsLC(
db,
aClientUid,
metadata.Identifier(),
EFalse );
CNcdPurchaseInstallInfo* installInfo = CNcdPurchaseInstallInfo::NewLC();
const CNcdNodeContentInfo* contentInfo = NULL;
TRAPD( err, contentInfo = &metadata.ContentInfoL() );
LeaveIfNotErrorL( err, KErrNotFound );
if ( aAppUids.Count() )
{
DLTRACE(("Updating installed application info"));
// Use application UID from the protocol if it exists
if ( contentInfo && contentInfo->Uid() != TUid::Null() )
{
DLINFO(( "Using UID from Content info: %x",
contentInfo->Uid().iUid ));
installInfo->SetApplicationUid( contentInfo->Uid() );
}
else
{
DLINFO(( "Using UID from installer: %x", aAppUids[0].iUid ));
installInfo->SetApplicationUid( aAppUids[0] );
}
// Theme version number's are not updated from sis registry
if ( aInfo.Purpose() != ENcdItemPurposeTheme &&
aInfo.FilePath().Length() )
{
DLTRACE(( _L("Got version number from sis registry: %S"),
&aInfo.FilePath() ));
installInfo->SetApplicationVersionL(
aInfo.FilePath() );
}
else if ( contentInfo )
{
DLTRACE(("Content info exists"));
// Use application version from the protocol
DLINFO(( _L("Setting app version: %S"),
&contentInfo->Version() ));
installInfo->SetApplicationVersionL(
contentInfo->Version() );
}
}
else if ( aInfo.Purpose() == ENcdItemPurposeTheme )
{
DLTRACE(("Updating installed theme info"));
installInfo->SetThemeNameL( aInfo.FilePath() );
}
else
{
DLTRACE(("Updating installed content info"));
DLINFO(( _L("Installed file: %S"), &aInfo.FilePath() ));
// Save the filename
installInfo->SetFilenameL( aInfo.FilePath() );
}
// update purpose to purchase history
// if purpose in content info was unknown, we use the one gotten from installer
// since it may have been updated to something more specific
if ( contentInfo && contentInfo->Purpose() != ENcdItemPurposeUnknown )
{
TUint newPurpose = contentInfo->Purpose();
if ( aInfo.Purpose() == ENcdItemPurposeApplication )
{
// This ensures that games etc. stuff that were installed like
// applications, are also handled like applications
newPurpose |= ENcdItemPurposeApplication;
}
DLTRACE(("Setting purpose as %d", newPurpose));
purchase->SetItemPurpose( newPurpose );
}
else
{
// backup in case we didn't get content info for some reason
DLINFO(("Didn't get ContentInfo, updating purpose from FileInfo"));
purchase->SetItemPurpose( purchase->ItemPurpose() | aInfo.Purpose() );
}
DLINFO(("Item purpose: %d", purchase->ItemPurpose() ));
// Add install info to purchase details. Ownership is transferred
if ( ReplaceInstallInfoL( *purchase, *installInfo ) )
{
CleanupStack::PopAndDestroy( installInfo );
}
else
{
DLTRACE(("Adding install info to purchase details"));
purchase->AddInstallInfoL( installInfo );
CleanupStack::Pop( installInfo );
}
DLTRACE(("Saving purchase details"));
db.SavePurchaseL( *purchase, EFalse );
CleanupStack::PopAndDestroy( purchase );
DLTRACEOUT((""));
}
// ---------------------------------------------------------------------------
// Checks if the details already contain a matching info
// ---------------------------------------------------------------------------
//
TBool CNcdInstallOperation::ReplaceInstallInfoL(
MNcdPurchaseDetails& aDetails,
const MNcdPurchaseInstallInfo& aInfo )
{
DLTRACEIN((""));
TArray< MNcdPurchaseInstallInfo* > installInfos(
aDetails.InstallInfoL() );
TParsePtrC path( aInfo.Filename() );
TPtrC installedFile( path.NameAndExt() );
DLTRACE(("Going through %d install infos", installInfos.Count() ));
for ( TInt i = 0; i < installInfos.Count(); ++i )
{
MNcdPurchaseInstallInfo& oldInfo( *installInfos[ i ] );
if ( ( oldInfo.ApplicationUid() == aInfo.ApplicationUid() &&
oldInfo.ApplicationVersion() == aInfo.ApplicationVersion() &&
oldInfo.ThemeName() == aInfo.ThemeName() ) ||
// also replace empty infos, hopefully this doesn't break anything
// because this is needed in order to correctly handle cancelled
// theme installations or more spefically successful theme installations
// after a cancelled theme installation
( oldInfo.ApplicationUid() == KNullUid &&
oldInfo.ApplicationVersion() == KNullDesC &&
// replace the old info if theme name is empty or if the old theme name
// is not empty but the new info is entirely empty == reinstalling a theme
( oldInfo.ThemeName() == KNullDesC ||
( aInfo.ApplicationUid() == KNullUid &&
aInfo.ApplicationVersion() == KNullDesC &&
aInfo.ThemeName() == KNullDesC ) ) ) )
{
// Parse the filename from the file path
TParsePtrC oldPath( oldInfo.Filename() );
if ( oldPath.NameAndExt() == installedFile )
{
DLTRACEOUT(("Info already exists"));
// Update the filename in case the file has been installed
// to a different drive than before
CNcdPurchaseInstallInfo* modInfo =
static_cast<CNcdPurchaseInstallInfo*>( installInfos[i] );
// This updates the theme name in the following case:
// 1. theme was already installed when bought and installed with the client
// 2. user uninstalled the theme
// 3. user downloaded and installed the theme again
if ( oldInfo.ThemeName() == KNullDesC )
{
modInfo->SetThemeNameL( aInfo.ThemeName() );
}
modInfo->SetFilenameL( aInfo.Filename() );
return ETrue;
}
}
}
// This tries to update an existing java app uid when we are reinstalling
// java apps
TArray< MNcdPurchaseDownloadInfo* > downloadInfos(
aDetails.DownloadInfoL() );
if ( installInfos.Count() &&
aInfo.ApplicationUid() != KNullUid &&
downloadInfos.Count() >= installInfos.Count() )
{
TBool isJava = EFalse;
for ( TInt i = 0; i < downloadInfos.Count(); ++i )
{
if ( IsJava( downloadInfos[i]->ContentMimeType(), ETrue ) )
{
isJava = ETrue;
break;
}
}
if ( !isJava )
{
DLTRACEOUT(("No java app"));
return EFalse;
}
DLTRACE(("Update the uid of the first existing app"));
for ( TInt i = 0; i < installInfos.Count(); ++i )
{
MNcdPurchaseInstallInfo& oldInfo( *installInfos[ i ] );
if ( oldInfo.ApplicationUid() != KNullUid )
{
DLTRACE(("Updating application uid from %x to %x",
oldInfo.ApplicationUid(), aInfo.ApplicationUid() ));
// Update the app uid for java app
CNcdPurchaseInstallInfo* modInfo =
static_cast<CNcdPurchaseInstallInfo*>( installInfos[i] );
modInfo->SetApplicationUid( aInfo.ApplicationUid() );
modInfo->SetApplicationVersionL( aInfo.ApplicationVersion() );
return ETrue;
}
}
}
return EFalse;
}
// ---------------------------------------------------------------------------
// Checks if the given mime type matches a java app
// ---------------------------------------------------------------------------
//
TBool CNcdInstallOperation::IsJava(
const TDesC& aMimeType,
TBool aAcceptJad ) const
{
DLTRACEIN(( _L("aMimeType: %S"), &aMimeType ));
TBool matches = aMimeType.MatchF( KMimeTypeMatch1JavaApplication ) != KErrNotFound ||
aMimeType.MatchF( KMimeTypeMatch2JavaApplication ) != KErrNotFound;
if ( !matches && aAcceptJad )
{
matches = aMimeType.MatchF( KMimeTypeMatchJad ) != KErrNotFound;
}
DLTRACEOUT(("Matched: %d", matches));
return matches;
}
// ---------------------------------------------------------------------------
// Gets the path to the file indexed by the message
// ---------------------------------------------------------------------------
//
HBufC* CNcdInstallOperation::FilePathLC(
MCatalogsBaseMessage& aMessage )
{
DLTRACEIN((""));
TInt fileIndex = ReadFileIndexL( aMessage );
CNcdNode& node( iNodeManager->NodeL( *iNodeId ) );
// Notice that in order the node to start install, the
// node has to have some kind of metadata
CNcdNodeMetaData& metaData( node.NodeMetaDataL() );
CNcdNodeInstall& install( metaData.InstallL() );
// Check that file index is in the valid range
if ( fileIndex < 0 || fileIndex >= install.DownloadedFiles().MdcaCount() )
{
DLERROR(("Invalid index: %d", fileIndex ));
User::Leave( KErrArgument );
}
DLTRACEOUT(( _L("Filepath %S from index: %d"),
&install.DownloadedFiles().MdcaPoint( fileIndex ), fileIndex ));
return install.DownloadedFiles().MdcaPoint( fileIndex ).AllocLC();
}
// ---------------------------------------------------------------------------
// Opens a file
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::OpenFileL(
MCatalogsBaseMessage& aMessage )
{
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 );
// Ugly hackfix for handling JADs
if ( iJadFile )
{
User::LeaveIfError( file.Open( fs,
*iJadFile,
NcdProviderDefines::KNcdSharableFileOpenFlags ) );
}
else
{
HBufC* path = FilePathLC( aMessage );
User::LeaveIfError( file.Open( fs,
*path,
NcdProviderDefines::KNcdSharableFileOpenFlags ) );
CleanupStack::PopAndDestroy( path );
}
DLTRACE(("File open, transferring to client"));
aMessage.CompleteAndReleaseL( fs, file );
DLTRACE(("File transferred"));
CleanupStack::PopAndDestroy( 2, &fs ); // file, fs
}
// ---------------------------------------------------------------------------
// Does the actual message handling
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::DoReceiveMessageL(
MCatalogsBaseMessage* aMessage,
TInt aFunctionNumber )
{
DLTRACEIN((""));
switch ( aFunctionNumber )
{
case ENCDOperationFunctionGetData:
{
GetFileInfoL( *aMessage );
break;
}
case ENCDOperationFunctionSetData:
{
UpdateInstalledFileInfoL( *aMessage );
break;
}
case ENcdOperationFunctionOpenFile:
{
OpenFileL( *aMessage );
break;
}
case ENcdOperationFunctionDeleteFile:
{
DeleteFileL( *aMessage );
break;
}
case ENCDOperationFunctionReportStart:
{
StartReportL( *aMessage );
break;
}
case ENCDOperationFunctionReportComplete:
{
CompleteReportL( *aMessage );
break;
}
default:
{
DLTRACE(("Calling baseclass"));
// Call implementation in the base class
CNcdBaseOperation::ReceiveMessage( aMessage, aFunctionNumber );
break;
}
}
DLTRACEOUT((""));
}
// ---------------------------------------------------------------------------
// Deletes a file index by the message. Also JAD is deleted if necessary
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::DeleteFileL( MCatalogsBaseMessage& aMessage )
{
DLTRACEIN((""));
HBufC* path = FilePathLC( aMessage );
// Delete installed SIS/JAR/content file
User::LeaveIfError( iInstallService->DeleteFile( *path ) );
CleanupStack::PopAndDestroy( path );
// If we installed JAD+JAR we must delete JAD separately.
DeleteJad();
aMessage.CompleteAndReleaseL( KErrNone, KErrNone );
}
// ---------------------------------------------------------------------------
// Reads a file index from the message
// ---------------------------------------------------------------------------
//
TInt CNcdInstallOperation::ReadFileIndexL( MCatalogsBaseMessage& aMessage )
{
RCatalogsMessageReader reader;
reader.OpenLC( aMessage );
// Read the requested file index
TInt fileIndex = reader().ReadInt32L();
CleanupStack::PopAndDestroy( &reader );
return fileIndex;
}
// ---------------------------------------------------------------------------
// Deletes JAD from disk and the filename
// ---------------------------------------------------------------------------
//
void CNcdInstallOperation::DeleteJad()
{
DLTRACEIN((""));
if ( iJadFile && iInstallService )
{
// Error is ignored because we can't handle disk errors in
// any special way and other errors will make themselves known
// anyway
iInstallService->DeleteFile( *iJadFile );
}
DeletePtr( iJadFile );
}