--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdcontentdownloadoperation.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,2142 @@
+/*
+* Copyright (c) 2006-2008 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 "ncdcontentdownloadoperation.h"
+
+#include <s32mem.h>
+#include <f32file.h>
+#include <apmstd.h>
+#include <e32math.h>
+
+#include "catalogsbasemessage.h"
+#include "catalogshttpsession.h"
+#include "catalogshttpconfig.h"
+#include "catalogshttpoperation.h"
+#include "catalogsconstants.h"
+#include "ncdnodemanager.h"
+#include "ncdnodeimpl.h"
+#include "ncdnodemetadataimpl.h"
+#include "ncdnodeidentifier.h"
+#include "ncdsessionhandler.h"
+#include "ncdhttpheaders.h"
+#include "catalogsutils.h"
+#include "catalogshttpheaders.h"
+#include "ncdconfigurationmanager.h"
+#include "catalogscontext.h"
+#include "ncdproviderdefines.h"
+#include "ncdnodeclassids.h"
+#include "ncdnodelink.h"
+#include "ncdoperationremovehandler.h"
+#include "ncddownloadsuboperation.h"
+#include "ncddescriptordownloadsuboperation.h"
+#include "ncdnodedownloadimpl.h"
+#include "ncdpurchasedetails.h"
+#include "ncdpurchasedownloadinfo.h"
+#include "ncdpurchasehistorydbimpl.h"
+#include "ncdutils.h"
+#include "ncderrors.h"
+#include "ncdpanics.h"
+#include "ncdstorageitem.h"
+#include "ncddatabasestorage.h"
+#include "ncdcontentdescriptor.h"
+#include "ncdproviderutils.h"
+#include "ncdengineconfiguration.h"
+#include "ncdnodecontentinfoimpl.h"
+#include "ncdnodeinstallimpl.h"
+#include "catalogshttpconnectionmanager.h"
+#include "ncdpurchasehistoryutils.h"
+#include "ncdnodedependencyimpl.h"
+#include "catalogsaccesspointmanager.h"
+#include "ncdgeneralmanager.h"
+
+#include "catalogsdebug.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+
+const TInt KNoDownloads = 25000;
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CNcdContentDownloadOperation* CNcdContentDownloadOperation::NewL(
+ MNcdOperationRemoveHandler& aRemoveHandler,
+ const CNcdNodeIdentifier& aNodeId,
+ CNcdGeneralManager& aGeneralManager,
+ MCatalogsHttpSession& aHttpSession,
+ MNcdDownloadReportObserver& aReportObserver,
+ MNcdSessionHandler* aSessionHandler,
+ MNcdDatabaseStorage& aDownloadStorage,
+ MCatalogsSession& aSession,
+ TInt aDownloadIndex )
+ {
+ CNcdContentDownloadOperation* self = new( ELeave )
+ CNcdContentDownloadOperation(
+ aRemoveHandler,
+ aGeneralManager,
+ aHttpSession,
+ aReportObserver,
+ aSessionHandler,
+ aSession,
+ aDownloadStorage );
+
+ CleanupClosePushL( *self );
+ self->ConstructL( aNodeId, aDownloadIndex );
+
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CNcdContentDownloadOperation* CNcdContentDownloadOperation::NewLC(
+ MNcdOperationRemoveHandler& aRemoveHandler,
+ CNcdGeneralManager& aGeneralManager,
+ MCatalogsHttpSession& aHttpSession,
+ MNcdDownloadReportObserver& aReportObserver,
+ MNcdDatabaseStorage& aDownloadStorage,
+ MCatalogsSession& aSession )
+ {
+ CNcdContentDownloadOperation* self = new( ELeave )
+ CNcdContentDownloadOperation(
+ aRemoveHandler,
+ aGeneralManager,
+ aHttpSession,
+ aReportObserver,
+ NULL,
+ aSession,
+ aDownloadStorage );
+
+ CleanupClosePushL( *self );
+
+ self->ConstructL();
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CNcdContentDownloadOperation::~CNcdContentDownloadOperation()
+ {
+ DLTRACEIN( ( "" ) );
+
+ if ( iDownloadState == ENcdDownloadInProgress )
+ {
+ if ( iDownload )
+ {
+ DLTRACE(("Pausing download"));
+ iDownload->Pause();
+ }
+ iDownloadState = ENcdDownloadPaused;
+ }
+
+ if ( iDownloadState == ENcdDownloadPaused &&
+ iOperationState != EStateCancelled )
+ {
+ DLINFO(("Externalizing the download since it's paused"));
+
+ TRAP_IGNORE( SaveStateL() );
+ }
+ else
+ {
+ TRAP_IGNORE( RemoveTempInfoL() );
+ }
+
+ if ( iDownload )
+ {
+ iDownload->Close();
+ iDownload = NULL;
+ }
+
+ if ( iDescriptorDownload )
+ {
+ iDescriptorDownload->Close();
+ iDescriptorDownload = NULL;
+ }
+
+ delete iDescriptor;
+ delete iMimeType;
+
+ delete iSessionId;
+ delete iContentDescriptor;
+
+ delete iContentFilename;
+ delete iStorageUid;
+ DLTRACEOUT((""));
+ }
+
+
+
+// ---------------------------------------------------------------------------
+// Cancel
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::Cancel()
+ {
+ DLTRACEIN(( "" ));
+
+ // Can't handle leaves in cancel
+ TNcdReportStatusInfo info( ENcdReportCancel, KErrCancel );
+ TRAP_IGNORE( ReportStatusL( info ) );
+ TRAP_IGNORE( SendOmaNotificationL( info ) );
+
+ if ( iDownload )
+ {
+ // Content downloads should be cancelled only when the client says so
+ if ( iDeleting )
+ {
+ iDownload->Pause();
+ }
+ else
+ {
+ iDownload->Cancel();
+ ClosePtr( iDownload );
+ }
+ }
+
+ if ( iDescriptorDownload )
+ {
+ iDescriptorDownload->Cancel();
+ iDescriptorDownload = NULL;
+ }
+
+ DLTRACEOUT(( "" ));
+ }
+
+
+// ---------------------------------------------------------------------------
+// ReceiveMessage
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::ReceiveMessage(
+ MCatalogsBaseMessage* aMessage,
+ TInt aFunctionNumber )
+ {
+ DLTRACEIN(( "Function: %d", aFunctionNumber ));
+ TNcdOperationMessageCompletionId completionId;
+ TInt err = KErrNone;
+
+ TBool requireStart = EFalse;
+ // Response to pause and resume messages, other messages are handled
+ // by the base class
+ switch ( aFunctionNumber )
+ {
+ // GetData which in fact is pausable check
+ case ENCDOperationFunctionGetData:
+ {
+ DLTRACE(( "ENCDOperationFunctionGetData "));
+ // Only error will come from CompleteMessageL
+ TRAP_IGNORE( GetPausableStateL( *aMessage ) );
+ return;
+ }
+
+ case ENCDOperationFunctionStart:
+ {
+ // Resume if paused, otherwise start
+ if ( iDownload && iDownload->Progress().iState
+ == ECatalogsHttpOpPaused )
+ {
+ DLTRACE(("Resuming download"));
+ err = iDownload->Start();
+ if ( err == KErrNone )
+ {
+ iDownloadState = ENcdDownloadInProgress;
+ }
+
+ completionId = ENCDOperationMessageCompletionResume;
+ }
+ else
+ {
+ CNcdBaseOperation::ReceiveMessage( aMessage, aFunctionNumber );
+ return;
+ }
+ break;
+ }
+
+ // Pause download if it's pausable
+ case ENCDOperationFunctionPause:
+ {
+ DLTRACE( ( "ENCDOperationFunctionPause" ) );
+ if ( iOperationState != EStateComplete &&
+ iOperationState != EStateCancelled )
+ {
+ err = KErrNone;
+ if ( iDownload )
+ {
+ // Don't care about pausable status since the user wants to pause
+ // we must pause the operation. If the download is not pausable,
+ // it will be started from the beginning
+ err = iDownload->Pause();
+ }
+
+ if ( iDescriptorDownload )
+ {
+ iDescriptorDownload->Cancel();
+ iDescriptorDownload = NULL;
+ }
+
+ if ( err == KErrNone )
+ {
+ iDownloadState = ENcdDownloadPaused;
+ TNcdReportStatusInfo info( ENcdReportPause, KErrNone );
+ TRAP( err, ReportStatusL( info, EFalse ) );
+ }
+ }
+ completionId = ENCDOperationMessageCompletionPause;
+ break;
+ }
+
+
+ // Resume download
+ case ENCDOperationFunctionResume:
+ {
+ DLTRACE( ( "ENCDOperationFunctionResume" ) );
+
+ if ( iOperationState != EStateComplete &&
+ iOperationState != EStateCancelled )
+ {
+ if ( iDownload )
+ {
+ err = iDownload->Start();
+ if ( err == KErrNone )
+ {
+ iDownloadState = ENcdDownloadInProgress;
+ iOperationState = EStateRunning;
+ }
+ }
+ else
+ {
+ DLTRACE(("No download, should Start"));
+ iDownloadState = ENcdDownloadStopped;
+ iOperationState = EStateStopped;
+ requireStart = ETrue;
+ }
+ }
+ completionId = ENCDOperationMessageCompletionResume;
+
+ break;
+ }
+
+ default:
+ {
+ DLTRACE(("Calling baseclass"));
+ // Call implementation in the base class
+ CNcdBaseOperation::ReceiveMessage( aMessage, aFunctionNumber );
+ DLTRACEOUT(( "Called baseclass" ));
+ return;
+ }
+ }
+
+
+ if ( iDownload )
+ {
+ iProgress = iDownload->Progress();
+ }
+
+ iProgress.iState = iDownloadState;
+ if ( !iPendingMessage &&
+ iDownloadState != ENcdDownloadPaused )
+ {
+ DLTRACE(("No pending message, ask for one"));
+ if ( requireStart )
+ {
+ iProgress.iState = KNcdDownloadStartMessageRequired;
+ }
+ else
+ {
+ iProgress.iState = KNcdDownloadContinueMessageRequired;
+ }
+ }
+
+ if ( err == KErrNone )
+ {
+ TRAP( err, SaveStateL() );
+ }
+
+ // Complete pause/resume message
+ // If this fails then it fails
+ CompleteMessage( aMessage, completionId, iProgress, err );
+
+ // Ensure that iState stays valid
+ iProgress.iState = iCurrentFile;
+ iProgress.iOperationId = iTotalFileCount;
+
+ // The operation will halt if we don't do this because it has been paused
+ // when there was a pending event so the proxy side won't send a new
+ // message until we complete the pending message
+ if ( iPendingMessage &&
+ requireStart )
+ {
+ DLTRACE(("There was a pending message when resume was called -> Run"));
+ RunOperation();
+ }
+
+ DLTRACEOUT(( "" ));
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::CounterPartLost(
+ const MCatalogsSession& aSession )
+ {
+ DLTRACEIN((""));
+ iDeleting = ETrue;
+ CNcdBaseOperation::CounterPartLost( aSession );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Externalize the download
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::ExternalizeL( RWriteStream& aStream )
+ {
+ DLTRACEIN((""));
+
+ // Externalize node id
+ iNode->Identifier().ExternalizeL( aStream );
+
+ // Externalize metadata id
+ iNode->NodeMetaDataL().Identifier().ExternalizeL( aStream );
+
+ ExternalizeDesL( *iStorageUid, aStream );
+
+ // Externalize node type so that we can create a correct kind of
+ // a temp node when we restore the download
+ ExternalizeEnumL( CNcdNodeFactory::NodeTypeL( *iNode ), aStream );
+
+ if ( iSessionId )
+ {
+ ExternalizeDesL( *iSessionId, aStream );
+ }
+ else
+ {
+ ExternalizeDesL( KNullDesC, aStream );
+ }
+
+ aStream.WriteInt32L( iDownloadIndex );
+
+ aStream.WriteInt32L( iContentDownloadState );
+
+ aStream.WriteInt32L( iDownloadState );
+
+ aStream.WriteInt32L( iDependenciesUpdated );
+
+ if ( iDownload )
+ {
+ DLTRACE(("Download exists"));
+ aStream.WriteInt8L( 1 );
+ iDownload->ExternalizeL( aStream );
+ }
+ else
+ {
+ DLTRACE(("No download"));
+ // no download
+ aStream.WriteInt8L( 0 );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Internalize the download
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::InternalizeL( RReadStream& aStream )
+ {
+ DLTRACEIN((""));
+ iIsOk = EFalse;
+ CNcdNodeIdentifier* nodeId = CNcdNodeIdentifier::NewLC( aStream );
+ DLINFO(( _L("Internalized nodeid: %S::%S"), &nodeId->NodeNameSpace(),
+ &nodeId->NodeId() ));
+
+ CNcdNodeIdentifier* metadataId = CNcdNodeIdentifier::NewLC( aStream );
+ DLINFO(( _L("Internalized nodeid: %S::%S"), &metadataId->NodeNameSpace(),
+ &metadataId->NodeId() ));
+
+ InternalizeDesL( iStorageUid, aStream );
+
+ CNcdNodeFactory::TNcdNodeType nodeType( CNcdNodeFactory::ENcdNodeItem );
+ InternalizeEnumL( nodeType, aStream );
+
+ CNcdNodeManager::TNcdTemporaryNodeType tempNodeType(
+ CNcdNodeManager::ENcdTemporaryNodeItem );
+
+ switch( nodeType )
+ {
+ case CNcdNodeFactory::ENcdNodeItem:
+ {
+ tempNodeType = CNcdNodeManager::ENcdTemporaryNodeItem;
+ break;
+ }
+
+ case CNcdNodeFactory::ENcdNodeFolder:
+ {
+ tempNodeType = CNcdNodeManager::ENcdTemporaryNodeFolder;
+ break;
+ }
+
+ default:
+ {
+ DLERROR(("Corrupt data, leave"));
+ User::Leave( KErrCorrupt );
+ }
+ };
+
+ // Get node pointer and NodeDownload-pointer
+
+ DLINFO(( "Node was not found. Must create a temp node" ));
+ // Create temp node and update temp node usage status
+ // nodeId is a temp node id because content downloads always use
+ // temp nodes so we don't have to create a new temp node id from metadata id
+ iNode = &iNodeManager->CreateTemporaryNodeL(
+ *nodeId, tempNodeType, ETrue );
+
+ DLTRACE(("Updating access point"));
+ UpdateAccessPointsL( *nodeId );
+
+ CleanupStack::PopAndDestroy( 2, nodeId ); // metadataId, nodeId
+
+ DLTRACE(("Getting metadata reference"));
+ // Notice that the node has always some kind of metadata
+ // when content is available
+ CNcdNodeMetaData& metaData( iNode->NodeMetaDataL() );
+ iNodeDownload = &metaData.DownloadL();
+
+
+ // Sets iSessionId only if the original session ID != NULL
+ HBufC* sessionId = NULL;
+ InternalizeDesL( sessionId, aStream );
+ if ( *sessionId == KNullDesC )
+ {
+ delete sessionId;
+ sessionId = NULL;
+ }
+ iSessionId = sessionId;
+
+ iDownloadIndex = aStream.ReadInt32L();
+
+ iContentDownloadState = static_cast<TContentDownloadState>(
+ aStream.ReadInt32L() );
+
+ iDownloadState = static_cast<TNcdDownloadState>(
+ aStream.ReadInt32L() );
+
+ if ( iDownloadState != ENcdDownloadComplete &&
+ iDownloadState != ENcdDownloadFailed )
+ {
+ DLTRACE(("Setting iDownloadState to ENcdDownloadPaused"));
+ iDownloadState = ENcdDownloadPaused;
+ }
+
+ iDependenciesUpdated = aStream.ReadInt32L();
+
+ TInt8 downloadExists = aStream.ReadInt8L();
+ if ( downloadExists )
+ {
+ DLTRACE(("Internalizing download suboperation"));
+ TRAPD( err,
+ iDownload = CNcdDownloadSubOperation::NewL(
+ iGeneralManager,
+ iHttpSession,
+ *this,
+ aStream,
+ iSession ) );
+
+ if ( err == KErrNone )
+ {
+ // Register download to report manager, iReportId will be the old one
+ // if the manager still has the old report
+ HBufC* uri = ConvertUtf8ToUnicodeL( iDownload->HttpOperation().Uri() );
+ CleanupStack::PushL( uri );
+
+ // This also update the accesspoint though that's unnecessary
+ // since it has been saved by the report itself
+ RegisterDownloadL( *uri, metaData.Identifier() );
+ CleanupStack::PopAndDestroy( uri );
+ }
+ // CNcdDownloadSubOperation::NewL leaves with KErrNotFound if the
+ // platform download is not found but we don't want to let it
+ // go any further than this
+ else if ( err != KErrNotFound )
+ {
+ DLERROR(("Leaving with err: %d", err ));
+ User::Leave( err );
+ }
+ }
+ iIsOk = ETrue;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Checks if the download matches the given criteria
+// ---------------------------------------------------------------------------
+//
+TBool CNcdContentDownloadOperation::MatchDownload(
+ const CNcdNodeIdentifier& aId,
+ TNcdDownloadDataType& aType,
+ TInt /* aIndex */ ) const
+ {
+ return aType == ENcdContentDownload &&
+ aId.Equals( MetadataId() );
+ //&& aIndex == iDownloadIndex;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Node ID getter
+// ---------------------------------------------------------------------------
+//
+const CNcdNodeIdentifier& CNcdContentDownloadOperation::NodeId() const
+ {
+ return iNode->Identifier();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Metadata id getter
+// ---------------------------------------------------------------------------
+//
+const CNcdNodeIdentifier& CNcdContentDownloadOperation::MetadataId() const
+ {
+
+ return iNode->NodeMetaData()->Identifier();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Ok status getter
+// ---------------------------------------------------------------------------
+//
+TBool CNcdContentDownloadOperation::IsOk() const
+ {
+ return iIsOk;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Current download index
+// ---------------------------------------------------------------------------
+//
+TInt CNcdContentDownloadOperation::CurrentDownload() const
+ {
+ return iDownloadIndex;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Progress
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::Progress( CNcdBaseOperation& aOperation )
+ {
+ DLTRACEIN((""));
+
+ // Report operation start to report manager
+ if ( aOperation.Progress().iState == ENcdDownloadStarted )
+ {
+ TNcdReportStatusInfo info( ENcdReportStart, KErrNone );
+ TRAPD( err, ReportStatusL( info, EFalse ) );
+ if ( err != KErrNone )
+ {
+ DLERROR(("Error: %d", err));
+ iError = err;
+ RunOperation();
+ }
+ }
+
+ if ( !iDescriptorDownload && iContentDownloadState == EContentDownload )
+ {
+ iProgress = aOperation.Progress();
+ iProgress.iState = iCurrentFile;
+ iProgress.iOperationId = iTotalFileCount;
+ iUnhandledEvent = ETrue;
+ RunOperation();
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// QueryReceived
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::QueryReceived(
+ CNcdBaseOperation& /* aOperation */,
+ CNcdQuery* /* aQuery */ )
+ {
+ DLTRACEIN((""));
+ }
+
+// ---------------------------------------------------------------------------
+// OperationComplete
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::OperationComplete(
+ CNcdBaseOperation* aOperation,
+ TInt aError )
+ {
+ DLTRACEIN(( "aError: %d", aError ));
+ iProgress = aOperation->Progress();
+ iProgress.iState = iCurrentFile;
+ iProgress.iOperationId = iTotalFileCount;
+
+ // Ignore errors in notification sending
+ if ( aError == KErrNone )
+ {
+ TRAPD( err,
+ {
+
+ if ( iDescriptorDownload )
+ {
+ DLTRACE(("Descriptor download finished"));
+ DASSERT( aOperation == static_cast<CNcdBaseOperation*>(
+ iDescriptorDownload ) );
+ FinishDescriptorDownloadL();
+ ReleaseDownload( aOperation );
+
+ // Initialize & start next descriptor/content download
+ InitializeDownloadL( iDownloadIndex );
+
+ StartDownloadL();
+ }
+ else
+ {
+ TBool contentDownloaded = FinishDownloadL();
+
+ ReleaseDownload( aOperation );
+
+ if ( contentDownloaded && iContentDownloadState == EDownloadDone )
+ {
+ iContentDownloadState = ENoDownload;
+ DLTRACE(("Content file downloaded"));
+ ++iDownloadIndex;
+ if ( iDownloadIndex == iNodeDownload->DownloadInfo().Count() )
+ {
+ DLTRACE(("Download is complete"));
+ iDownloadState = ENcdDownloadComplete;
+
+ // Remove state information from the download db
+ RemoveTempInfoL();
+ }
+ else
+ {
+ DLTRACE(("Starting the next file from index: %d",
+ iDownloadIndex ));
+ iCurrentFile++;
+ iDownloadState = ENcdDownloadInProgress;
+ iUnhandledEvent = ETrue;
+ iStartNextFile = ETrue;
+ }
+ }
+ else
+ {
+ DLTRACE(("Start downloading the actual content file/send notification"));
+ iDownloadState = ENcdDownloadInProgress;
+ iStartNextFile = ETrue;
+ }
+ }
+ });
+
+ if ( err != KErrNone )
+ {
+ if ( err == KNoDownloads )
+ {
+ DLTRACE(("Everything has already been downloaded & installed"));
+ iError = KErrNone;
+ iDownloadState = ENcdDownloadComplete;
+ iContentDownloadState = ENoDownload;
+ }
+ else
+ {
+ DLERROR(("Error %d when handling a completed download", err ));
+ iError = err;
+ iDownloadState = ENcdDownloadFailed;
+ }
+ }
+ RunOperation();
+ }
+ else
+ {
+ DLERROR(( "Handling error: %d", aError ));
+
+ // Already handling an error so we can forget about this one
+ TNcdReportStatusInfo info( ENcdReportFail, aError );
+ TRAP_IGNORE( ReportStatusL( info ) );
+ ReleaseDownload( aOperation );
+
+ iError = aError;
+ iDownloadState = ENcdDownloadFailed;
+ RunOperation();
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// RunOperation
+// ---------------------------------------------------------------------------
+//
+TInt CNcdContentDownloadOperation::RunOperation()
+ {
+ DLTRACEIN(( "Pending message: %X", iPendingMessage ));
+
+ if ( !iPendingMessage )
+ {
+ DLTRACE(("No pending message"));
+ return KErrNotReady;
+ }
+
+ TInt err = KErrNone;
+ DLTRACE(("DL state: %i", iDownloadState ));
+
+ switch( iDownloadState )
+ {
+ // Start the download
+ case ENcdDownloadStopped:
+ {
+ DLTRACE(("ENcdDownloadStopped"));
+ TRAP( err,
+ {
+ InitializeDownloadL( iDownloadIndex );
+ DLTRACE(("Starting the download"));
+ StartDownloadL();
+ });
+
+ if ( err == KNoDownloads )
+ {
+ DLTRACE(("No downloads"));
+ iDownloadState = ENcdDownloadComplete;
+ RunOperation();
+ // error handled
+ err = KErrNone;
+ }
+ DLTRACE(("ENcdDownloadStopped done, err: %d", err));
+ break;
+ }
+
+ case ENcdDownloadInProgress:
+ {
+ DLTRACE(("ENcdDownloadInProgress"));
+ if ( iUnhandledEvent )
+ {
+ CompleteMessage( iPendingMessage,
+ ENCDOperationMessageCompletionProgress,
+ iProgress, err );
+ iUnhandledEvent = EFalse;
+ }
+
+ if ( iStartNextFile )
+ {
+ DLTRACE(("Starting the next file"));
+ iStartNextFile = EFalse;
+
+ TRAP( err,
+ {
+ InitializeDownloadL( iDownloadIndex );
+ DLTRACE(("Starting the download"));
+ StartDownloadL();
+ });
+
+ if ( err == KNoDownloads )
+ {
+ DLTRACE(("No more downloads"));
+ iDownloadState = ENcdDownloadComplete;
+ RunOperation();
+ // error handled
+ err = KErrNone;
+ }
+ }
+
+ DLTRACE(("ENcdDownloadInProgress done"));
+ break;
+ }
+
+ case ENcdDownloadComplete:
+ {
+ DLTRACE(("ENcdDownloadComplete"));
+ CompleteMessage(
+ iPendingMessage,
+ ENCDOperationMessageCompletionComplete,
+ iProgress, err );
+
+ // This prevents download pausing/resuming problems after
+ // the download has been completed
+ iOperationState = EStateComplete;
+ break;
+ }
+
+ case ENcdDownloadFailed:
+ {
+ DLTRACE(("ENcdDownloadFailed"));
+ // Send error message in case didn't have any pending
+ // messages when the download actually failed
+
+ CompleteMessage( iPendingMessage,
+ ENCDOperationMessageCompletionError, iProgress,
+ iError );
+
+ // This prevents download pausing/resuming problems after
+ // the download has been completed
+ iOperationState = EStateComplete;
+
+ DLTRACE(("ENcdDownloadFailed done"));
+ break;
+ }
+
+ case ENcdDownloadPaused:
+ {
+ DLTRACE(("Operation paused"));
+ break;
+ }
+
+ default:
+ {
+ DLTRACE(("Default"));
+ DASSERT( 0 );
+ }
+ }
+
+ if ( err != KErrNone )
+ {
+ DLTRACE(("error: %d", err));
+ Cancel();
+ iDownloadState = ENcdDownloadFailed;
+ iError = err;
+ if ( iPendingMessage )
+ {
+ CompleteMessage( iPendingMessage,
+ ENCDOperationMessageCompletionError, iError );
+ }
+ // call observers
+ CompleteCallback();
+ }
+ DLTRACEOUT(("err: %d", err));
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Initializer
+// ---------------------------------------------------------------------------
+//
+TInt CNcdContentDownloadOperation::Initialize()
+ {
+ DLTRACEIN( ( "" ) );
+
+ TRAPD( err, DoInitializationL() );
+
+ if ( err != KErrNone )
+ {
+ DLTRACE( ( "Err: %d", err ) );
+ iPendingMessage->CompleteAndRelease( err );
+ iPendingMessage = NULL;
+ }
+ DLTRACEOUT(( "err: %d", err ));
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Actual initializer
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::DoInitializationL()
+ {
+ DLTRACEIN(("Writing initialize response"));
+
+ // Write the response
+ RCatalogsBufferWriter writer;
+ writer.OpenLC();
+ writer().WriteInt32L( ENCDOperationMessageCompletionInit );
+
+ if ( !iDependenciesUpdated )
+ {
+ TRAPD( err, UpdateDependenciesL() );
+ LeaveIfNotErrorL( err, KErrNotFound );
+ }
+
+ iCurrentFile = 1;
+ iTotalFileCount = CalculateMissingFilesL();
+
+ writer().WriteInt32L( iTotalFileCount );
+ // write pause-status
+ writer().WriteInt32L( iDownloadState == ENcdDownloadPaused );
+
+ iPendingMessage->CompleteAndReleaseL( writer.PtrL(), KErrNone );
+ iPendingMessage = NULL;
+ CleanupStack::PopAndDestroy( &writer );
+
+ }
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//
+CNcdContentDownloadOperation::CNcdContentDownloadOperation(
+ MNcdOperationRemoveHandler& aRemoveHandler,
+ CNcdGeneralManager& aGeneralManager,
+ MCatalogsHttpSession& aHttpSession,
+ MNcdDownloadReportObserver& aReportObserver,
+ MNcdSessionHandler* aSessionHandler,
+ MCatalogsSession& aSession,
+ MNcdDatabaseStorage& aDownloadStorage ) :
+ CNcdBaseOperation( aGeneralManager, &aRemoveHandler, EContentDownloadOperation,
+ aSession ),
+ iHttpSession( aHttpSession ),
+ iReportObserver( aReportObserver ),
+ iSessionHandler( aSessionHandler ),
+ iConfigurationManager( aGeneralManager.ConfigurationManager() ),
+ iAccessPointManager( aGeneralManager.AccessPointManager() ),
+ iStorage( aDownloadStorage ),
+ iContext( aSession.Context() ),
+ iDownloadState( ENcdDownloadStopped )
+ {
+ }
+
+
+// ---------------------------------------------------------------------------
+// ConstructL
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::ConstructL(
+ const CNcdNodeIdentifier& aNodeId,
+ TInt aDownloadIndex )
+ {
+ DLTRACEIN(( "DL index: %i", aDownloadIndex ));
+ (void) aDownloadIndex; // prevents compiler warning of unused parameter
+
+ ConstructL();
+
+ GenerateStorageUidL();
+
+ // Get pointer to node, using NodeL since it leaves if the node is not found
+ iNode = &iNodeManager->NodeL( aNodeId );
+
+ if ( iSessionHandler && iNode->NodeLink() )
+ {
+ // Get server URI from the node
+ const TDesC& serverUri = iNode->NodeLink()->ServerUri();
+
+ if ( iSessionHandler->DoesSessionExist(
+ serverUri,
+ aNodeId.NodeNameSpace() ) )
+ {
+ // Get session ID for the URI
+ iSessionId = iSessionHandler->Session(
+ serverUri,
+ aNodeId.NodeNameSpace() ).AllocL();
+ }
+ }
+
+
+ UpdateAccessPointsL( aNodeId );
+
+ // Get NodeDownload-interface
+ // Notice that if content is available the node has some kind of
+ // metadata.
+ CNcdNodeMetaData& metaData( iNode->NodeMetaDataL() );
+ iNodeDownload = &metaData.DownloadL();
+
+ SaveStateL();
+ iIsOk = ETrue;
+ DLTRACEOUT(( "" ));
+ }
+
+
+// ---------------------------------------------------------------------------
+// ConstructL
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::ConstructL()
+ {
+ // Call ConstructL for the base class
+ CNcdBaseOperation::ConstructL();
+ iContentDescriptor = CNcdContentDescriptor::NewL();
+ iProgress.iMaxProgress = 1;
+ }
+
+// ---------------------------------------------------------------------------
+// FinishDescriptorDownloadL
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::FinishDescriptorDownloadL()
+ {
+ DLTRACEIN((""));
+
+ DLTRACE(("Reporting successful download"));
+ TNcdReportStatusInfo info( ENcdReportSuccess, KErrNone );
+ ReportStatusL( info );
+ iReportId = KNcdReportNotSupported;
+
+ if ( iContentDownloadState == ERightsDownload )
+ {
+ const TDesC8& contentType(
+ iDescriptorDownload->HttpOperation().ContentType() );
+
+ // Get download info for the current DL
+ const MNcdPurchaseDownloadInfo& info = *iNodeDownload->DownloadInfo()[
+ iDownloadIndex ];
+
+
+ TDataType dataType;
+
+ // Try to find out the correct mime type for the rights object
+ DLTRACE(("Handling rights object"));
+ if( contentType.MatchF( KMimeTypeMatchDrmRightsXml8 ) != KErrNotFound ||
+ contentType.MatchF( KMimeTypeMatchDrmRightsWbxml8 ) != KErrNotFound )
+ {
+ DLTRACE(("Rights type: %S", &contentType ));
+ dataType = TDataType( contentType );
+ }
+ else if ( info.RightsType().MatchF( KMimeTypeMatchDrmRightsXml ) != KErrNotFound ||
+ info.RightsType().MatchF( KMimeTypeMatchDrmRightsWbxml ) != KErrNotFound )
+ {
+ HBufC8* tempBuf = Des16ToDes8LC( info.RightsType() );
+ dataType = TDataType( *tempBuf );
+ CleanupStack::PopAndDestroy( tempBuf );
+ DLINFO(("Rights: %S", &dataType.Des8() ));
+ }
+
+ CNcdProviderUtils::InstallationServiceL().AppendRightsL(
+ iDescriptorDownload->Body(),
+ dataType );
+
+ }
+ else if ( iContentDownloadState == EDescriptorDownload )
+ {
+ DLTRACE(("Handling downloaded descriptor"));
+ delete iDescriptor;
+ iDescriptor = NULL;
+ iDescriptor = iDescriptorDownload->Body().AllocL();
+
+ HBufC* mime = Des8ToDes16L(
+ iDescriptorDownload->HttpOperation().ContentType() );
+
+ TDescriptorType descType( MatchDescriptor( *mime ) );
+ delete mime;
+
+ if ( descType == EDescriptorDd )
+ {
+ HandleDescriptorL( KDescriptorTypeOdd, *iDescriptor );
+ }
+ else
+ {
+ HandleDescriptorL( KDescriptorTypeJad, *iDescriptor );
+ }
+
+ UpdatePurchaseHistoryL( KNullDesC() );
+ }
+ else
+ {
+ DASSERT( 0 );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// StartDownloadL
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::StartDownloadL()
+ {
+ DLTRACEIN((""));
+
+ if ( iDescriptorDownload )
+ {
+ DLTRACE(("Start descriptor download"));
+ User::LeaveIfError( iDescriptorDownload->Start() );
+ iProgress = iDescriptorDownload->Progress();
+ }
+ else
+ {
+ DLTRACE(("Start file download"));
+ // Set these before start so that if a progress callback is
+ // called during start the operation functions correctly in
+ // RunOperation
+ iDownloadState = ENcdDownloadInProgress;
+ iOperationState = EStateRunning;
+ TInt err = iDownload->Start();
+ if ( err != KErrNone )
+ {
+ DLERROR(("Failed: %d", err))
+ iDownloadState = ENcdDownloadFailed;
+ iOperationState = EStateComplete;
+ User::Leave( err );
+ }
+ iProgress = iDownload->Progress();
+ }
+
+ DLTRACE(("Download started successfully"));
+ iDownloadState = ENcdDownloadInProgress;
+ iProgress.iState = iCurrentFile;
+ iProgress.iOperationId = iTotalFileCount;
+
+ iOperationState = EStateRunning;
+ SaveStateL();
+ }
+
+
+// ---------------------------------------------------------------------------
+// FinishDownloadL
+// ---------------------------------------------------------------------------
+//
+TBool CNcdContentDownloadOperation::FinishDownloadL()
+ {
+ DLTRACEIN((""));
+
+ DLTRACE(("Reporting successful download"));
+ TNcdReportStatusInfo info( ENcdReportSuccess, KErrNone );
+ ReportStatusL( info );
+
+ // iDownload doesn't exist if we are sending the notification
+ if ( iDownload && !iContentFilename )
+ {
+ DLTRACE(("Get target filename"));
+ iContentFilename = iDownload->Config().FullPathLC();
+ CleanupStack::Pop( iContentFilename );
+ }
+
+ HBufC* mimeType = NULL;
+ TBool mimeOwned = EFalse;
+ if ( iDownload )
+ {
+ mimeType = Des8ToDes16LC( iDownload->HttpOperation().ContentType() );
+ }
+ else if ( iMimeType && iMimeType->Length() )
+ {
+ mimeType = iMimeType->AllocLC();
+ }
+ else
+ {
+ mimeType = KNullDesC().AllocLC();
+ }
+
+
+ // No MIME type, update from HTTP headers
+ if ( !iMimeType || !iMimeType->Length() )
+ {
+ DLTRACE(("Update mime type"));
+ delete iMimeType;
+ iMimeType = NULL;
+ iMimeType = mimeType;
+ DLTRACE(( _L("MIME type: %S"), iMimeType ));
+ iMimeUpdated = ETrue;
+ mimeOwned = ETrue;
+ }
+
+ if ( !iContentMime.Length() )
+ {
+ iContentMime.Set( *iMimeType );
+ }
+
+ // Using the actual mime from the response
+ TDescriptorType descType( MatchDescriptor(
+ *mimeType ) );
+
+ if ( !mimeOwned )
+ {
+ CleanupStack::PopAndDestroy( mimeType );
+ }
+ else
+ {
+ CleanupStack::Pop( mimeType );
+ }
+
+ // iDownloadType is checked so that the actual content file is not handled like
+ // the downloaded descriptor
+ if ( descType != EDescriptorUnknown &&
+ iDownloadType == EDescriptorUnknown )
+ {
+ DLTRACE(("Downloaded a descriptor in a file"));
+ DASSERT( iContentFilename );
+ delete iDescriptor;
+ iDescriptor = NULL;
+ iDescriptor = ReadFileL( CNcdProviderUtils::FileSession(),
+ *iContentFilename );
+
+ // Beware: this debug print can easily panic if the descriptor is long
+ // enough
+ //DLINFO(( "Descriptor: %S", iDescriptor ));
+ CNcdProviderUtils::FileSession().Delete( *iContentFilename );
+ delete iContentFilename;
+ iContentFilename = NULL;
+
+ if ( descType == EDescriptorDd )
+ {
+ HandleDescriptorL( KDescriptorTypeOdd, *iDescriptor );
+ }
+ else
+ {
+ HandleDescriptorL( KDescriptorTypeJad, *iDescriptor );
+ }
+
+ // Writes the descriptor to purchase history and updates
+ // content type
+ UpdatePurchaseHistoryL( KNullDesC() );
+
+ return EFalse;
+ }
+
+ // Notice that purchase history has to be updated before sending any
+ // notifications to server to prevent situations where purchase history
+ // could not be updated after notification sending.
+ // (examples of such situations: out of memory, user cancellation)
+ // Notice also that the update is not done if download state is
+ // ESendNotification to prevent double update (before notification
+ // sending and after).
+ DASSERT( iContentFilename );
+ UpdatePurchaseHistoryL( *iContentFilename );
+
+ // Update node's status from the purchase history
+ DLTRACE(("Updating node from purchase history"));
+ iNodeManager->DownloadDataHandlerL( iNode->Identifier() );
+
+
+ SendOmaNotificationL( info );
+
+ delete iContentFilename;
+ iContentFilename = NULL;
+
+ // Reset URI and mime
+ iContentUri.Set( KNullDesC );
+ iContentMime.Set( KNullDesC );
+ iNotificationUri.Set( KNullDesC );
+ iDownloadType = EDescriptorUnknown;
+ iContentDownloadState = EDownloadDone;
+ iReportId = KNcdReportNotSupported;
+ SaveStateL();
+ return ETrue;
+ }
+
+
+// ---------------------------------------------------------------------------
+// UpdatePurchaseHistoryL
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::UpdatePurchaseHistoryL(
+ const TDesC& aDownloadedFile )
+ {
+ DLTRACEIN(("Updating download in index: %d", iDownloadIndex ));
+
+ CNcdPurchaseDetails* purchase = GetPurchaseDetailsLC();
+
+ if ( !purchase->DownloadInfo( iDownloadIndex ).ContentMimeType().Length() )
+ {
+ DLTRACE(( _L("Updating mime type to purchase details, Mime: %S"),
+ &iContentMime ));
+ purchase->DownloadInfo( iDownloadIndex ).SetContentMimeTypeL(
+ iContentMime );
+ }
+
+ if ( iDescriptor )
+ {
+ DLTRACE(("Setting descriptor data, length: %d", iDescriptor->Length() ));
+
+ if ( iDownloadType == EDescriptorDd )
+ {
+ purchase->DownloadInfo( iDownloadIndex ).SetDescriptorTypeL(
+ KDescriptorTypeOdd );
+ }
+ else if ( iDownloadType == EDescriptorJad )
+ {
+ purchase->DownloadInfo( iDownloadIndex ).SetDescriptorTypeL(
+ KDescriptorTypeJad );
+ }
+
+ // Write the descriptor data only if it's of a known type
+ if ( iDownloadType != EDescriptorUnknown )
+ {
+ purchase->DownloadInfo( iDownloadIndex ).SetDescriptorDataL(
+ *iDescriptor );
+ }
+
+ delete iDescriptor;
+ iDescriptor = NULL;
+ }
+
+ // This download needs to be handled afterwards
+ purchase->DownloadInfo( iDownloadIndex ).SetAttributeL(
+ MNcdPurchaseDownloadInfo::EDownloadAttributeRequiredDownload, 1 );
+
+
+ DASSERT( iDownloadIndex < purchase->DownloadedFiles().MdcaCount() );
+
+ //
+ purchase->ReplaceDownloadedFileL( iDownloadIndex, aDownloadedFile );
+
+ DLTRACE(("Saving purchase history"));
+ iNodeManager->PurchaseHistory().SavePurchaseL( *purchase, EFalse );
+
+ CleanupStack::PopAndDestroy( purchase );
+ DLTRACEOUT(("Purchase history updated"));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates a skipped download to purchase history
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::UpdateSkippedDownloadToPurchaseHistoryL(
+ TInt aIndex )
+ {
+ DLTRACEIN(("Updating download in index: %d", aIndex ));
+
+ CNcdPurchaseDetails* purchase = GetPurchaseDetailsLC();
+
+ purchase->DownloadInfo( aIndex ).SetAttributeL(
+ MNcdPurchaseDownloadInfo::EDownloadAttributeRequiredDownload, 0 );
+
+ purchase->ReplaceDownloadedFileL( aIndex, KNullDesC );
+
+ DLTRACE(("Saving purchase history"));
+ iNodeManager->PurchaseHistory().SavePurchaseL( *purchase, EFalse );
+
+ CleanupStack::PopAndDestroy( purchase );
+ DLTRACEOUT(("Purchase history updated"));
+
+ }
+
+// ---------------------------------------------------------------------------
+// Updates the download headers
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::UpdateHeadersL(
+ MCatalogsHttpHeaders& aHeaders )
+ {
+ DLTRACEIN((""));
+
+ DLTRACE(( _L("Client id: %S"), &iConfigurationManager.ClientIdL(
+ iContext) ));
+
+ // Add ClientId, SSID and sessionId to file downloads
+ aHeaders.AddHeaderL( NcdHttpHeaders::KClientIdHeader,
+ iConfigurationManager.ClientIdL( iContext) );
+ aHeaders.AddHeaderL( NcdHttpHeaders::KSsidHeader,
+ iConfigurationManager.SsidL( iContext) );
+
+ if ( iSessionId )
+ {
+ DLTRACE(( _L("Adding session id: %S"), iSessionId ));
+ aHeaders.AddHeaderL( NcdHttpHeaders::KSessionIdHeader, *iSessionId );
+ }
+ DLTRACEOUT(( "" ));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Resets the correct pointer
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::ReleaseDownload(
+ CNcdBaseOperation* aOperation )
+ {
+ if ( aOperation == static_cast<CNcdBaseOperation*>( iDownload ) )
+ {
+ iDownload = NULL;
+ }
+ else if ( aOperation == static_cast<CNcdBaseOperation*>(
+ iDescriptorDownload ) )
+ {
+ iDescriptorDownload = NULL;
+ }
+ else
+ {
+ NCD_ASSERT_ALWAYS( 0, ENcdPanicInvalidArgument );
+ }
+ aOperation->Close();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Handles a download descriptor
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::HandleDescriptorL(
+ const TDesC& aDescriptorType, const TDesC8& aDescriptor )
+ {
+ DLTRACEIN((""));
+ DLINFO(("Descriptor: %S", &aDescriptor));
+ // Start descriptor parsing
+ iContentDescriptor->SetDescriptorL(
+ aDescriptorType,
+ aDescriptor );
+
+ if ( iContentDescriptor->DataUriL().Length() )
+ {
+ DLINFO(( _L("Data URI from descriptor: %S"),
+ &iContentDescriptor->DataUriL() ));
+ iContentUri.Set( iContentDescriptor->DataUriL() );
+ }
+
+ if ( iContentDescriptor->MimeType().Length() )
+ {
+ DLINFO(( _L("Setting content mime as: %S"),
+ &iContentDescriptor->MimeType() ));
+
+ iContentMime.Set( iContentDescriptor->MimeType() );
+ }
+
+ // Update type of the download
+ iDownloadType = MatchDescriptor( aDescriptorType );
+
+ if ( iContentDescriptor &&
+ iContentDescriptor->InstallNotificationUri().Length() )
+ {
+ // Send notification only for DDs because installer
+ // handles JADs
+ if ( iDownloadType == EDescriptorDd )
+ {
+ DLTRACEOUT(("Setting state as ESendNotification, using URI from descriptor"));
+ iNotificationUri.Set(
+ iContentDescriptor->InstallNotificationUri() );
+ }
+ else
+ {
+ iNotificationUri.Set( KNullDesC );
+ }
+ }
+
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::InitializeDownloadL( TInt aIndex )
+ {
+ DLTRACEIN(( "Download index: %d", aIndex ));
+
+ DASSERT( aIndex >= 0 );
+
+ // Find the next file that needs to be downloaded
+ if ( aIndex >= iNodeDownload->DownloadInfo().Count() ||
+ SkipInstalledFilesL() )
+ {
+ DLTRACEOUT(("Everything has been installed already"));
+ User::Leave( KNoDownloads );
+ }
+
+ aIndex = iDownloadIndex;
+
+ // Get download info for the current DL
+ const MNcdPurchaseDownloadInfo& info = *iNodeDownload->DownloadInfo()[
+ aIndex ];
+
+
+ HBufC* clientDataPath = CNcdProviderUtils::EngineConfig().ClientDataPathLC(
+ iGeneralManager.FamilyName(), EFalse );
+
+ DASSERT( clientDataPath );
+ DLINFO(( _L("Client data path: %S"), clientDataPath ));
+ WouldDiskSpaceGoBelowCriticalLevelL( *clientDataPath,
+ CNcdProviderUtils::FileSession(),
+ info.ContentSize() );
+
+ DLTRACE(("Reset progress to -1"));
+ iProgress.iState = iCurrentFile;
+ iProgress.iOperationId = iTotalFileCount;
+
+ iProgress.iProgress = -1;
+ iProgress.iMaxProgress = -1;
+
+ const CNcdNodeIdentifier& identifier =
+ iNode->NodeMetaDataL().Identifier();
+
+ // Handle required descriptors
+ if ( iContentDownloadState < ERightsDownload && info.RightsUri().Length() )
+ {
+ DLTRACE(( _L("Creating descriptor download operation for Rights-URI: %S"),
+ &info.RightsUri() ));
+ iContentDownloadState = ERightsDownload;
+ iDescriptorDownload = CNcdDescriptorDownloadSubOperation::NewL(
+ iGeneralManager,
+ iHttpSession,
+ info.RightsUri(),
+ *this,
+ iSession );
+
+ iDescriptorDownload->Config().SetConnectionMethod( iApId );
+ UpdateHeadersL( iDescriptorDownload->RequestHeaders() );
+ CleanupStack::PopAndDestroy( clientDataPath );
+
+ RegisterDownloadL( info.RightsUri(), identifier );
+ return;
+ }
+
+ else if ( info.RightsUri().Length() <= 0 && info.RightsType().Length() )
+ {
+ DLERROR(( _L("Rights type set but no Rights Uri available -> ERROR!") ));
+ User::Leave( KErrNotFound );
+ }
+
+ // Handle descriptor embedded in the protocol response
+ // Embedded descriptors don't have DescriptorUris
+ else if ( iContentDownloadState < EEmbeddedDescriptor &&
+ info.DescriptorData().Length() &&
+ !info.DescriptorUri().Length() )
+ {
+ DLTRACE(("Handling embedded descriptor"));
+ HandleDescriptorL( info.DescriptorType(), info.DescriptorData() );
+ iContentDownloadState = EEmbeddedDescriptor;
+ }
+ // Handle descriptor URI from the protocol response
+ else if ( iContentDownloadState < EDescriptorDownload &&
+ info.DescriptorUri().Length() )
+ {
+ DLTRACE(( _L("Download descriptor from URI: %S"),
+ &info.DescriptorUri() ));
+
+ iDescriptorDownload = CNcdDescriptorDownloadSubOperation::NewL(
+ iGeneralManager,
+ iHttpSession,
+ info.DescriptorUri(),
+ *this,
+ iSession );
+
+ iDescriptorDownload->Config().SetConnectionMethod( iApId );
+
+ UpdateHeadersL( iDescriptorDownload->RequestHeaders() );
+ iContentDownloadState = EDescriptorDownload;
+ CleanupStack::PopAndDestroy( clientDataPath );
+
+ RegisterDownloadL( info.DescriptorUri(), identifier );
+ // Don't start content download just yet
+ return;
+ }
+
+ // Note: embedded descriptor handling continues in here -> no "else if"
+ if ( iContentDownloadState <= EContentDownload )
+ {
+
+ // Content download
+ DLTRACE(("Handling content download"));
+ if ( !iContentUri.Length() )
+ {
+ iContentUri.Set( info.ContentUri() );
+
+ DLTRACE(( _L("Content URI from protocol response: %S"),
+ &iContentUri ));
+ }
+
+ if ( !iContentMime.Length() )
+ {
+ iContentMime.Set( info.ContentMimeType() );
+ DLTRACE(( _L("Content mimetype from protocol response: %S"),
+ &iContentMime ));
+
+ // Dependencies and upgrades don't necessarily share the mime type
+ // with the actual content so we don't update it from the protocol for
+ // them
+ if ( !iContentMime.Length() &&
+ info.ContentUsage() != MNcdPurchaseDownloadInfo::EDependency )
+ {
+ const CNcdNodeContentInfo* contentInfo = NULL;
+
+ TRAP_IGNORE( contentInfo =
+ &iNode->NodeMetaDataL().ContentInfoL() );
+ if ( contentInfo )
+ {
+ DLTRACE(( _L("Content mimetype from content info: %S"),
+ &iContentMime ));
+ iContentMime.Set( contentInfo->MimeType() );
+ }
+ }
+ }
+ iContentDownloadState = EContentDownload;
+
+ if ( info.InstallNotificationUri().Length() )
+ {
+ iNotificationUri.Set( info.InstallNotificationUri() );
+ DLINFO(( _L("Set install notification URI: %S"),
+ &iNotificationUri ));
+ }
+
+ iDownload = CNcdDownloadSubOperation::NewL(
+ iGeneralManager,
+ iHttpSession,
+ iContentUri,
+ *clientDataPath,
+ *this,
+ iSession );
+
+ iDownload->HttpOperation().SetContentTypeL( iContentMime );
+
+ // Force HTTP header getting with transactions because DL manager doesn't
+ // support content-disposition for file names etc.
+
+ iDownload->HttpOperation().SetHeaderMode(
+ ECatalogsHttpHeaderModeForceHead );
+ iDownload->Config().SetConnectionMethod( iApId );
+
+ // Ensure that we use HEAD when downloading content files from
+ // URIs that we got from descriptors even if HEAD has been
+ // disabled
+ if ( iDownloadType != EDescriptorUnknown )
+ {
+ iDownload->Config().SetOptions(
+ iDownload->Config().Options() & ~ECatalogsHttpDisableHeadRequest );
+ }
+
+ // Get mime type set in the protocol/descriptor
+ AssignDesL( iMimeType, info.ContentMimeType() );
+ iMimeUpdated = EFalse;
+
+ UpdateHeadersL( iDownload->RequestHeaders() );
+
+ const CNcdNodeIdentifier& identifier =
+ iNode->NodeMetaDataL().Identifier();
+
+ RegisterDownloadL( iContentUri, identifier );
+ }
+
+ CleanupStack::PopAndDestroy( clientDataPath );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool CNcdContentDownloadOperation::IsFileInstalledL(
+ TInt aIndex,
+ TBool aCheckOnly )
+ {
+ DLTRACEIN((""));
+ const MNcdPurchaseDownloadInfo& info =
+ *iNodeDownload->DownloadInfo()[ aIndex ];
+
+ // AttributeInt32L leaves only with KErrNotFound and if that happens,
+ // it means that this file has not been handled before -> Buy
+ TRAPD( isFirstDownload, info.AttributeInt32L(
+ MNcdPurchaseDownloadInfo::EDownloadAttributeRequiredDownload ) );
+
+ // If handling buy, we can not skip content downloads
+ if ( isFirstDownload &&
+ info.ContentUsage() == MNcdPurchaseDownloadInfo::EDownloadable )
+ {
+ DLTRACEOUT(("Not a dependency"));
+ return EFalse;
+ }
+
+ // If launcher is defined but there's no URI, there's no point
+ // checking whether it is installed or not because can't download it
+ // anyway
+ if ( !info.ContentUri().Length() &&
+ IsOneOf( info.ContentUsage(),
+ MNcdPurchaseDownloadInfo::ELauncher,
+ MNcdPurchaseDownloadInfo::ELauncherOpen ) )
+ {
+ DLTRACEOUT(("Launcher without URI, skip"));
+ // This ensures that for instance MNcdNodeDownload::IsDownloadedL
+ // ignores these files
+ if ( !aCheckOnly )
+ {
+ UpdateSkippedDownloadToPurchaseHistoryL( aIndex );
+ }
+ return ETrue;
+ }
+
+ CNcdNodeInstall* install = NULL;
+ TRAPD( err, install = &iNode->NodeMetaData()->InstallL() );
+
+ if ( err != KErrNone )
+ {
+ DLERROR(("Error %d when getting CNcdNodeInstall", err));
+ if ( err == KErrNotFound )
+ {
+ return EFalse;
+ }
+ User::Leave( err );
+ }
+
+ TBool available =
+ ( install->IsContentInstalledL( aIndex, EFalse ) >= ENcdApplicationInstalled );
+
+ if ( available && !aCheckOnly )
+ {
+ // This ensures that for instance MNcdNodeDownload::IsDownloadedL
+ // ignores these files
+ UpdateSkippedDownloadToPurchaseHistoryL( aIndex );
+ }
+ DLTRACEOUT(("Content installed: %d", available));
+ return available;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool CNcdContentDownloadOperation::SkipInstalledFilesL()
+ {
+ DLTRACEIN((""));
+ TBool installed = ETrue;
+ TInt count = iNodeDownload->DownloadInfo().Count();
+
+ while ( installed && iDownloadIndex < count )
+ {
+ DLTRACE(("Checking deps for index: %d", iDownloadIndex ));
+ // Get download info for the current DL
+
+ // Check if dependency/upgrade has already been installed
+ if ( !IsFileInstalledL( iDownloadIndex, EFalse ) )
+ {
+ installed = EFalse;
+ }
+ else
+ {
+ ++iDownloadIndex;
+ }
+ }
+
+ if ( installed )
+ {
+ DLTRACE(("All files have been downloaded or installed"));
+ //iOperationState = EStateComplete;
+ iDownloadState = ENcdDownloadComplete;
+ }
+ return installed;
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt CNcdContentDownloadOperation::CalculateMissingFilesL()
+ {
+ DLTRACEIN((""));
+ TInt count = iNodeDownload->DownloadInfo().Count();
+ TInt missing = 0;
+
+ while ( count-- )
+ {
+ // Check if the file is already installed
+ if ( !IsFileInstalledL( count, ETrue ) )
+ {
+ missing++;
+ }
+ }
+
+ DLTRACEOUT(("Missing: %d files", missing));
+ return missing;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Saves the current state of the download to db
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::SaveStateL()
+ {
+ DLTRACEIN((""));
+ DASSERT( iStorageUid );
+ // Externalize the download
+ MNcdStorageItem* item = iStorage.StorageItemL( *iStorageUid,
+ NcdProviderDefines::ENcdDownloadData );
+ item->SetDataItem( this );
+ item->OpenL();
+ item->WriteDataL();
+
+ item->SaveL();
+ iStorage.CommitL();
+ DLTRACEOUT(("Download state saved"));
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::GenerateStorageUidL()
+ {
+ DLTRACEIN((""));
+
+ // Enough for timestamp (64bit) + rand (32bit)
+ HBufC* id = HBufC::NewLC( NcdProviderDefines::KClientIdMaxLength );
+
+ TTime now;
+ now.HomeTime();
+ TInt64 int64 = now.Int64();
+
+ TInt64 ptrInt = reinterpret_cast<TInt64>( this );
+ // Use both timestamp and free disk space to get a unique seed
+ TInt rand = Math::Rand( ptrInt );
+
+ TPtr ptr( id->Des() );
+
+
+ ptr.NumFixedWidth( int64 >> 32, EHex, 8 );
+ ptr.AppendNumFixedWidth( int64 & 0xffffffff, EHex, 8 );
+ ptr.AppendNumFixedWidth( rand, EHex, 8 );
+
+ delete iStorageUid;
+ iStorageUid = id;
+ CleanupStack::Pop( id );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Removes state information from the download db
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::RemoveTempInfoL()
+ {
+ DLTRACEIN((""));
+ MNcdStorageItem* item = iStorage.StorageItemL( *iStorageUid,
+ NcdProviderDefines::ENcdDownloadData );
+
+ item->RemoveFromStorageL();
+ iStorage.CommitL();
+ DLTRACEOUT(("Temp info removed successfully"));
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CNcdContentDownloadOperation::TDescriptorType
+ CNcdContentDownloadOperation::MatchDescriptor(
+ const TDesC& aMimeType ) const
+ {
+ DLTRACEIN((""));
+ if ( aMimeType.MatchF( KMimeTypeMatchJad ) != KErrNotFound ||
+ aMimeType.CompareF( KDescriptorTypeJad ) == 0 )
+ {
+ DLTRACEOUT(("Jad"));
+ return EDescriptorJad;
+ }
+ else if ( aMimeType.MatchF( KMimeTypeMatchOdd ) != KErrNotFound ||
+ aMimeType.CompareF( KDescriptorTypeOdd ) == 0 )
+ {
+ DLTRACEOUT(("DD"));
+ return EDescriptorDd;
+ }
+ DLTRACEOUT(("Unknown/not a descriptor"));
+ return EDescriptorUnknown;
+ }
+
+
+// ---------------------------------------------------------------------------
+// GetPurchaseDetailsLC
+// ---------------------------------------------------------------------------
+//
+CNcdPurchaseDetails* CNcdContentDownloadOperation::GetPurchaseDetailsLC()
+ {
+ DLTRACEIN((""))
+
+ return NcdPurchaseHistoryUtils::PurchaseDetailsLC(
+ iNodeManager->PurchaseHistory(),
+ iContext.FamilyId(),
+ iNode->NodeLinkL().MetaDataIdentifier(),
+ EFalse );
+ }
+
+
+// ---------------------------------------------------------------------------
+// UpdateAccessPointsL
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::UpdateAccessPointsL(
+ const CNcdNodeIdentifier& aNodeId )
+ {
+ DLTRACEIN((""));
+ // Get origin node id from purchase history
+ CNcdPurchaseDetails* purchase = GetPurchaseDetailsLC();
+
+ // Create origin identifier
+ CNcdNodeIdentifier* originIdentifier = CNcdNodeIdentifier::NewL(
+ aNodeId.NodeNameSpace(), purchase->OriginNodeId(), aNodeId.ClientUid() );
+ CleanupStack::PopAndDestroy( purchase );
+
+ CleanupStack::PushL( originIdentifier );
+
+ // Get download ap
+ TUint32 apId = 0;
+
+ TInt error = iAccessPointManager.AccessPointIdL(
+ *originIdentifier,
+ MCatalogsAccessPointManager::EDownload,
+ iContext.FamilyId(),
+ apId );
+
+ if ( error == KErrNone )
+ {
+ DLTRACE(( "Setting access point %d for content download", apId ))
+ iApId = TCatalogsConnectionMethod(
+ apId,
+ ECatalogsConnectionMethodTypeAccessPoint );
+ }
+
+ // Get report ap
+ apId = 0;
+ error = iAccessPointManager.AccessPointIdL(
+ *originIdentifier,
+ MCatalogsAccessPointManager::EBrowse,
+ iContext.FamilyId(),
+ apId );
+
+ if ( error == KErrNone )
+ {
+ DLTRACE(( "Setting access point %d for reports", apId ))
+ iReportAp = TCatalogsConnectionMethod(
+ apId,
+ ECatalogsConnectionMethodTypeAccessPoint );
+ }
+
+ if ( iReportAp.iId == 0 )
+ {
+ iReportAp = iHttpSession.ConnectionManager().DefaultConnectionMethod();
+ }
+ CleanupStack::PopAndDestroy( originIdentifier );
+
+ }
+
+
+// ---------------------------------------------------------------------------
+// Report download status
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::ReportStatusL(
+ const TNcdReportStatusInfo& aStatus,
+ TBool aSendable )
+ {
+ DLTRACEIN(("aStatus: %d", aStatus.iStatus));
+ iReportObserver.ReportDownloadStatusL(
+ iReportId,
+ aStatus,
+ aSendable );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::SendOmaNotificationL(
+ const TNcdReportStatusInfo& aStatus )
+ {
+ DLTRACEIN((""));
+ if ( ( aStatus.iStatus != ENcdReportCancel && aStatus.iStatus != ENcdReportSuccess ) ||
+ !iContentUri.Length() ||
+ !iNotificationUri.Length() )
+ {
+ DLTRACEOUT(("Nothing to report"));
+ return;
+ }
+
+ const CNcdNodeIdentifier& identifier =
+ iNode->NodeMetaDataL().Identifier();
+
+ TNcdReportStatusInfo info( ENcdReportCreate, KErrNone );
+ TNcdReportId omaReportId = iReportObserver.RegisterOmaDownloadL(
+ iContentUri,
+ identifier,
+ info,
+ iNotificationUri );
+
+ iReportObserver.SetDownloadReportAccessPoint(
+ omaReportId,
+ iApId );
+
+ DLTRACE(("Report registered, now trigger sending"));
+ iReportObserver.ReportDownloadStatusL(
+ omaReportId,
+ aStatus,
+ ETrue );
+ DLTRACEOUT(("Report sending initiated"));
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::UpdateDependenciesL()
+ {
+ DLTRACEIN((""));
+ CNcdPurchaseDetails* purchase = GetPurchaseDetailsLC();
+
+ iNode->NodeMetaDataL().DependencyL().UpdateDependenciesL( *purchase );
+
+ DLTRACE(("Saving purchase history"));
+ iNodeManager->PurchaseHistory().SavePurchaseL( *purchase, EFalse );
+
+ DLTRACE(("Updating node download from purchase details"));
+ iNodeDownload->InternalizeL( *purchase );
+
+ DLTRACE(("Updating node install from purchase details"));
+ CNcdNodeInstall& install = iNode->NodeMetaData()->InstallL();
+ install.InternalizeL( *purchase );
+
+ CleanupStack::PopAndDestroy( purchase );
+ iDependenciesUpdated = ETrue;
+ DLTRACEOUT(("Purchase history updated"));
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::GetPausableStateL(
+ MCatalogsBaseMessage& aMessage )
+ {
+ DLTRACEIN((""));
+ TInt pausableState = KNcdDownloadIsNotPausable;
+ if ( iDownload && iDownload->HttpOperation().IsPausable() )
+ {
+ DLTRACE(("Download is pausable"));
+ pausableState = KNcdDownloadIsPausable;
+ }
+
+ aMessage.CompleteAndReleaseL(
+ pausableState,
+ KErrNone );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CNcdContentDownloadOperation::RegisterDownloadL(
+ const TDesC& aUri,
+ const CNcdNodeIdentifier& aIdentifier )
+ {
+ DLTRACEIN((""));
+ TNcdReportStatusInfo statusInfo( ENcdReportCreate, KErrNone );
+ iReportId = iReportObserver.RegisterDownloadL(
+ aUri,
+ aIdentifier,
+ statusInfo,
+ aIdentifier.ServerUri(),
+ aIdentifier.NodeNameSpace() );
+
+ iReportObserver.SetDownloadReportAccessPoint(
+ iReportId,
+ iReportAp );
+ }