--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/engine/transport/src/catalogshttpdownload.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,2652 @@
+/*
+* Copyright (c) 2006-2007 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 "catalogshttpdownload.h"
+
+#include <bautils.h>
+#include <e32err.h>
+#include <DocumentHandler.h>
+#include <apmstd.h> // TDataType
+#include <escapeutils.h>
+
+#include "catalogshttpdownloadmanagerimpl.h"
+#include "catalogshttpobserver.h"
+#include "catalogshttpconfigimpl.h"
+#include "catalogskeyvaluepair.h"
+#include "catalogshttpheadersimpl.h"
+#include "catalogsutils.h"
+#include "catalogsdebug.h"
+#include "catalogsconstants.h"
+#include "catalogserrors.h"
+#include "catalogshttpconnectionmanager.h"
+#include "catalogsconnectionmethod.h"
+#include "catalogsconnection.h"
+#include "catalogshttputils.h"
+
+// Number of retries before giving up the download
+const TInt KReconnectAttempts = 3;
+
+const TInt KHttpErrorStatus = 400;
+const TInt KGenericSymbianHttpError = -20000;
+
+#define CATALOGS_DISABLE_DOWNLOAD_RESPONSE_HEADERS
+
+// HTTP header strings
+_LIT8( KHttpRequestAcceptHeader, "Accept" );
+_LIT8( KHttpRequestAcceptCharSetHeader, "Accept-Charset" );
+_LIT8( KHttpRequestAcceptLanguageHeader, "Accept-Language" );
+_LIT8( KHttpRequestExpectHeader, "Expect" );
+_LIT8( KHttpRequestFromHeader, "From" );
+_LIT8( KHttpRequestHostHeader, "Host" );
+_LIT8( KHttpRequestMaxForwardsHeader, "Max-Forwards" );
+_LIT8( KHttpRequestPragmaHeader, "Pragma" );
+_LIT8( KHttpRequestRefererHeader, "Referer" );
+_LIT8( KHttpRequestUserAgentHeader, "User-Agent" );
+_LIT8( KHttpRequestVaryHeader, "Vary" );
+
+_LIT8( KHttpGeneralCacheControlHeader, "Cache-Control" );
+_LIT8( KHttpGeneralDateHeader, "Date" );
+_LIT8( KHttpGeneralPragmaHeader, "Pragma" );
+_LIT8( KHttpGeneralViaHeader, "Via" );
+_LIT8( KHttpGeneralWarningHeader, "Warning" );
+
+
+_LIT8( KHttpEntityAllowHeader, "Allow" );
+_LIT8( KHttpEntityContentEncodingHeader, "Content-Encoding" );
+_LIT8( KHttpEntityContentLanguageHeader, "Content-Language" );
+_LIT8( KHttpEntityContentLocationHeader, "Content-Location" );
+_LIT8( KHttpEntityExpiresHeader, "Expires" );
+_LIT8( KHttpEntityLastModifiedHeader, "Last-Modified" );
+
+
+#ifndef CATALOGS_DISABLE_DOWNLOAD_RESPONSE_HEADERS
+ _LIT8( KHttpResponseCharSet, "Charset" );
+ _LIT8( KHttpResponseAge, "Age" );
+ _LIT8( KHttpResponseETag, "ETag" );
+ _LIT8( KHttpResponseLocation, "Location" );
+ _LIT8( KHttpResponseRetryAfter, "Retry-After" );
+ _LIT8( KHttpResponseServer, "Server" );
+ _LIT8( KHttpResponseVary, "Vary" );
+#endif
+
+
+
+// ======== MEMBER FUNCTIONS ========
+
+
+// ---------------------------------------------------------------------------
+// Creator
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpDownload* CCatalogsHttpDownload::NewLC(
+ CCatalogsHttpDownloadManager& aOwner,
+ RHttpDownload* aDownload,
+ const CCatalogsHttpConfig& aConfig )
+ {
+ CCatalogsHttpDownload* self = new( ELeave ) CCatalogsHttpDownload(
+ aOwner,
+ aDownload );
+
+ CleanupStack::PushL( self );
+ self->ConstructL( &aConfig );
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpDownload::~CCatalogsHttpDownload()
+ {
+ DLTRACEIN(( "this-ptr: %X", this ));
+
+ SetTransferring( EFalse );
+
+ if ( iTransaction )
+ {
+ DLTRACE(("Cancelling transaction"));
+ iTransaction->Cancel();
+ }
+
+ // Normally, iDownload is not deleted since it would also remove the
+ // incomplete files etc.
+ if ( iDownload )
+ {
+
+ DLTRACE(("RHttpDownload-ptr: %x", iDownload ));
+ if ( iNormalDelete &&
+ iState.iOperationState != ECatalogsHttpOpCompleted &&
+ iState.iOperationState != ECatalogsHttpOpFailed )
+ {
+ DLTRACE(("Setting download as paused"));
+ SetDeleteState( EDownloadPaused );
+ }
+ else
+ {
+ DLTRACE(( "Deleting download" ));
+ iDownload->Delete();
+
+ if ( iState.iOperationState != ECatalogsHttpOpCompleted )
+ {
+ // Ensure that temp files are really deleted
+ DeleteFiles();
+ }
+ }
+ }
+
+
+ ReleasePtr( iConnection );
+
+ DLTRACE(( "Removing from owner" ));
+ if ( iState.iOperationState != ECatalogsHttpOpCompleted &&
+ iState.iOperationState != ECatalogsHttpOpFailed )
+ {
+ iOwner.CompleteOperation( this );
+ }
+ else if ( iState.iOperationState == ECatalogsHttpOpFailed
+ && iState.iProgressState != ECatalogsHttpDone )
+ {
+ iOwner.CompleteOperation( this );
+ }
+ iOwner.RemoveDownload( this );
+
+
+ delete iConfig;
+ delete iResponseHeaders;
+ delete iAddedRequestHeaders;
+ delete iUri;
+ delete iEncodedUri;
+ delete iTempFilename;
+ iDdFile.Close();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Add a reference
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::AddRef()
+ {
+ iRefCount++;
+ return iRefCount;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Release a reference
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::Release()
+ {
+ DLTRACEIN(( "" ));
+ iRefCount--;
+ if ( !iRefCount )
+ {
+ // Ensures that iDownload is not deleted and therefore paused/ongoing
+ // downloads will be handled as determined by the quit operation
+ iNormalDelete = ETrue;
+ delete this;
+ return 0;
+ }
+ return iRefCount;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Reference count
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::RefCount() const
+ {
+ return iRefCount;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Cancel download
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::Cancel()
+ {
+ DLTRACEIN( ( "this: %x, ID: %d, Operation state: %i, Progress state: %d",
+ this, iId.Id(),
+ iState.iOperationState, iState.iProgressState ) );
+
+ iTransferredSize = 0;
+ if ( iTransaction )
+ {
+ iTransaction->Cancel();
+ iTransaction = NULL;
+ }
+
+#ifdef __SERIES60_31__
+
+ // Have to pause downloads before deleting. Otherwise progress events
+ // will stop coming because DL manager's event queue gets stuck in 3.1.
+ iCancelled = ETrue;
+ if ( iDownload )
+ {
+ iObserver = NULL;
+ TInt32 state = 0;
+ iDownload->GetIntAttribute( EDlAttrState, state );
+
+ if ( IsOneOf(
+ static_cast<THttpDownloadState>( state ),
+ EHttpDlCreated,
+ EHttpDlPaused,
+ EHttpDlCompleted,
+ EHttpDlFailed ) )
+ {
+ DLTRACE(("Deleting download"));
+ DeletePlatformDownload();
+ }
+ else
+ {
+ DLTRACE(("Pausing download"));
+ iDownload->Pause();
+ return RefCount();
+ }
+ }
+
+ DLTRACE(("No iDownload"));
+ ReleasePtr( iConnection );
+
+ SetTransferring( EFalse );
+ DeleteFiles();
+
+ iOwner.CompleteOperation( this );
+ iState.iOperationState = ECatalogsHttpOpDeleting;
+ iState.iProgressState = ECatalogsHttpDone;
+
+ return Release();
+
+#else
+
+ // DLMAIN-546, if the download was completed before cancel
+ // was executed then DL manager's download has already been deleted
+ DeletePlatformDownload();
+
+ ReleasePtr( iConnection );
+
+ SetTransferring( EFalse );
+ DeleteFiles();
+
+ // call CancelOperation only if the download had been started (or at least
+ // tried)
+ if ( iState.iProgressState != ECatalogsHttpNone &&
+ iState.iProgressState != ECatalogsHttpDone )
+ {
+ DLTRACE(("Cancelling the operation"));
+ iOwner.CompleteOperation( this );
+ iState.iOperationState = ECatalogsHttpOpDeleting;
+ iState.iProgressState = ECatalogsHttpDone;
+ }
+ return Release();
+#endif
+ }
+
+
+// ---------------------------------------------------------------------------
+// Download progress
+// ---------------------------------------------------------------------------
+//
+TCatalogsTransportProgress CCatalogsHttpDownload::Progress() const
+ {
+ if ( iState.iOperationState == ECatalogsHttpOpInProgress )
+ {
+ TInt32 contentSize = ContentSize();
+ if ( !contentSize )
+ {
+ // Prevent division by zero problems
+ contentSize = 1;
+ }
+ return TCatalogsTransportProgress( iState.iOperationState, TransferredSize(),
+ contentSize );
+ }
+
+ return TCatalogsTransportProgress( iState.iOperationState, 0, 1 );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Start download
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::Start( TResumeStartInformation aResumeOrigin )
+ {
+ DLTRACEIN(( "op state: %d, prog state: %d", iState.iOperationState,
+ iState.iProgressState ));
+
+ TInt err = KErrNone;
+ if ( iState.iProgressState == ECatalogsHttpNone )
+ {
+ DLTRACE(("Updating dl config"));
+ TRAP( err, UpdateDownloadConfigurationL() );
+ if ( err != KErrNone )
+ {
+ return err;
+ }
+ }
+
+ if ( aResumeOrigin == EAutomaticResume && iPaused )
+ {
+ // Download is continued automatically but
+ // it is paused, and we do not resume it
+ }
+ else if( iPausePending )
+ {
+ // Pausing is an asynchronous operation therefore we need to enqueue
+ // resume while pause is pending (we get an event from dlmgr when pause is done)
+ DLTRACE(("Enqueuing resume"));
+ iQueuedResume = ETrue;
+ }
+ // Start from the beginning or continue from paused
+ else if ( ( iState.iProgressState == ECatalogsHttpNone ||
+ iState.iOperationState == ECatalogsHttpOpPaused ||
+ iState.iOperationState == ECatalogsHttpOpQueued ) &&
+ !iTransaction )
+ {
+ DLTRACE(("Starting the operation"));
+ // Check if the download can be started or put it to queue
+
+ err = iOwner.StartOperation( this );
+ if ( err == KErrNone )
+ {
+ DLTRACE(("Starting the actual download"));
+ err = StartDownload();
+
+ if ( err == KErrNone )
+ {
+ DLTRACE(("DL started"));
+ iState.iOperationState = ECatalogsHttpOpInProgress;
+ iState.iProgressState = ECatalogsHttpStarted;
+ iPaused = EFalse;
+
+ if ( iObserver )
+ {
+ TRAP( err, iObserver->HandleHttpEventL(
+ *this,
+ iState ) );
+ }
+ }
+ else
+ {
+ DLTRACE(( "Start failed with: %i", err ));
+ }
+ }
+ else if ( err == KCatalogsHttpOperationQueued )
+ {
+ // Set state as queued and notify the observer
+ err = KErrNone;
+ iState.iOperationState = ECatalogsHttpOpQueued;
+ iPaused = EFalse;
+
+ if ( iObserver )
+ {
+ TRAP( err, iObserver->HandleHttpEventL( *this, iState ) );
+ }
+ }
+ }
+
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Pause download
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::Pause()
+ {
+ DLTRACEIN( ( "" ) );
+
+ if( iQueuedResume )
+ {
+ DLTRACE(("Removing queued resume"));
+ iQueuedResume = EFalse;
+ return KErrNone;
+ }
+ else if ( iTransaction )
+ {
+ DLTRACE(("Was getting the headers"));
+ iTransaction->Cancel();
+ iTransaction = NULL;
+
+ if ( iDdDownload )
+ {
+ DLTRACE(("DD download. Cannot really pause but we fake it"));
+ TFileName name;
+ iDdFile.FullName( name );
+ iDdFile.Close();
+ iFs.Delete( name );
+
+ // Reseting filename so that HTTP headers are taken again
+ // and DD download is restarted correctly.
+ //
+ // This is not the optimal solution but otherwise we would need
+ // to handle DD download resuming after client restart
+ // differently from resuming normal downloads
+ //
+ // SetFilenameL can't actually leave here because it just deletes
+ // the old filename without any new memory allocations
+ TRAP_IGNORE( iConfig->SetFilenameL( KNullDesC() ) );
+ iDdDownload = EFalse;
+ }
+
+ ReleasePtr( iConnection );
+ // Notify the session manager that there's room for executing
+ // another operation
+ iOwner.PauseOperation( this );
+ iState.iOperationState = ECatalogsHttpOpPaused;
+ iState.iProgressState = ECatalogsHttpNone;
+ iPaused = ETrue;
+ SetTransferring( EFalse );
+ return KErrNone;
+ }
+ else
+ {
+ // Set pending flag
+ if( iState.iOperationState == ECatalogsHttpOpInProgress)
+ {
+ DLTRACE(("Set pause pending flag"));
+ iPausePending = ETrue;
+ }
+ // It's possible that pause is not supported but then the download is
+ // just restarted when it's resumed
+ DLTRACE(("Thread semaphore count: %d", RThread().RequestCount() ));
+ TInt err = KErrNone;
+ if ( iDownload )
+ {
+ err = iDownload->Pause();
+ }
+
+ DLTRACE(("Pause err: %d", err ));
+ if ( err == KErrNone )
+ {
+ ReleasePtr( iConnection );
+ if ( !iPaused )
+ {
+ // Notify the session manager that there's room for executing
+ // another operation
+ iOwner.PauseOperation( this );
+ }
+ iState.iOperationState = ECatalogsHttpOpPaused;
+ iPaused = ETrue;
+ SetTransferring( EFalse );
+ }
+ DLTRACEOUT(("Operation paused"));
+ return err;
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::NotifyCancel()
+ {
+ DLTRACEIN((""));
+ if ( iObserver )
+ {
+ iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral, KErrCancel ) );
+ }
+ else
+ {
+ DLINFO(("No observer"));
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// NOT SUPPORTED
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetBodyL( const TDesC8& /* aBody */ )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+// ---------------------------------------------------------------------------
+// NOT SUPPORTED
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetBodyL( const TDesC16& /* aBody */ )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Body getter
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpDownload::Body() const
+ {
+ return KNullDesC8;
+ }
+
+
+// ---------------------------------------------------------------------------
+// URI setter
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetUriL( const TDesC8& aUri )
+ {
+ delete iUri;
+ iUri = NULL;
+ iUri = aUri.AllocL();
+ EncodeUriL();
+ }
+
+
+// ---------------------------------------------------------------------------
+// URI setter
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetUriL( const TDesC16& aUri )
+ {
+ delete iUri;
+ iUri = NULL;
+ iUri = ConvertUnicodeToUtf8L( aUri );
+ EncodeUriL();
+ }
+
+
+// ---------------------------------------------------------------------------
+// URI getter
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpDownload::Uri() const
+ {
+ if( iUri )
+ {
+ return *iUri;
+ }
+ return KNullDesC8();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Configuration
+// ---------------------------------------------------------------------------
+//
+MCatalogsHttpConfig& CCatalogsHttpDownload::Config() const
+ {
+ return *iConfig;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Request headers
+// ---------------------------------------------------------------------------
+//
+MCatalogsHttpHeaders& CCatalogsHttpDownload::RequestHeadersL() const
+ {
+ return iConfig->RequestHeaders();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Response headers
+// ---------------------------------------------------------------------------
+//
+const MCatalogsHttpHeaders& CCatalogsHttpDownload::ResponseHeadersL() const
+ {
+ return *iResponseHeaders;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Operation type
+// ---------------------------------------------------------------------------
+//
+TCatalogsHttpOperationType CCatalogsHttpDownload::OperationType() const
+ {
+ return ECatalogsHttpDownload;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Operation ID
+// ---------------------------------------------------------------------------
+//
+const TCatalogsTransportOperationId&
+ CCatalogsHttpDownload::OperationId() const
+ {
+ return iId;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Content type setter
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetContentTypeL( const TDesC8& aContentType )
+ {
+ DLTRACEIN(( "Content-type: %S", &aContentType ));
+
+ iContentType = aContentType;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Content type setter
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetContentTypeL( const TDesC16& aContentType )
+ {
+ DLTRACEIN(( _L("Content-type: %S"), &aContentType ));
+
+ HBufC8* contentType = ConvertUnicodeToUtf8L( aContentType );
+ iContentType = *contentType;
+ delete contentType;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Content type getter
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpDownload::ContentType() const
+ {
+ return iContentType;
+ }
+
+// ---------------------------------------------------------------------------
+// Content size getter
+// ---------------------------------------------------------------------------
+//
+TInt32 CCatalogsHttpDownload::ContentSize() const
+ {
+ DLTRACEIN((""));
+ // We get the content size only once in order to minimize
+ // client-server communication with the Download manager server
+ if ( iDownload && iContentSize <= 0 )
+ {
+ iDownload->GetIntAttribute( EDlAttrLength, iContentSize );
+ DLTRACE(("Content size from download: %i", iContentSize ));
+ }
+ return iContentSize;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Downloaded size getter
+// ---------------------------------------------------------------------------
+//
+TInt32 CCatalogsHttpDownload::TransferredSize() const
+ {
+ return iTransferredSize;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Is download pausable
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpDownload::IsPausable() const
+ {
+ TBool pausable = ETrue;
+ if ( iDownload )
+ {
+ iDownload->GetBoolAttribute( EDlAttrPausable, pausable );
+ }
+ return pausable;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Download status code
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::StatusCode() const
+ {
+ return 0;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Download status text
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpDownload::StatusText() const
+ {
+ return KNullDesC8();
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetConnection( CCatalogsConnection& aConnection )
+ {
+ DLTRACEIN((""));
+ ReleasePtr( iConnection );
+
+ iConnection = &aConnection;
+ iConnection->AddRef();
+ const TCatalogsConnectionMethod& method( aConnection.ConnectionMethod() );
+ DLTRACE(("Connection: %d, %u, %u",
+ method.iType, method.iId, method.iApnId ));
+
+ Config().SetConnectionMethod( method );
+
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::ReportConnectionError( TInt aError )
+ {
+ DLTRACEIN(("aError: %d", aError));
+ iObserver->HandleHttpError( *this,
+ TCatalogsHttpError( ECatalogsHttpErrorGeneral, aError ) );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpConnectionManager& CCatalogsHttpDownload::ConnectionManager()
+ {
+ return iOwner.ConnectionManager();
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::ExternalizeL( RWriteStream& aStream ) const
+ {
+ DLTRACEIN((""));
+ iConfig->ExternalizeL( aStream );
+ ExternalizeDesL( ContentType(), aStream );
+ ExternalizeDesL( *iTempFilename, aStream );
+ ExternalizeEnumL( iMode, aStream );
+ iId.ExternalizeL( aStream );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::InternalizeL( RReadStream& aStream )
+ {
+ DLTRACEIN((""));
+ iConfig->InternalizeL( aStream );
+ HBufC8* contentType = NULL;
+ InternalizeDesL( contentType, aStream );
+ if ( contentType->Length() > KMaxContentTypeLength )
+ {
+ DeletePtr( contentType );
+ DLERROR(("Content type was too long, leaving with KErrCorrupt"));
+ User::Leave( KErrCorrupt );
+ }
+ iContentType = *contentType;
+ DeletePtr( contentType );
+
+ InternalizeDesL( iTempFilename, aStream );
+ InternalizeEnumL( iMode, aStream );
+ iId.InternalizeL( aStream );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Operation state
+// ---------------------------------------------------------------------------
+//
+TCatalogsHttpOperationState CCatalogsHttpDownload::State() const
+ {
+ return iState.iOperationState;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Handles events from the configuration
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::HandleHttpConfigEvent(
+ MCatalogsHttpConfig* /* aConfig */,
+ const TCatalogsHttpConfigEvent& aEvent )
+ {
+ if ( aEvent == ECatalogsHttpCfgPriorityChanged )
+ {
+ return iOwner.OperationPriorityChanged( this );
+ }
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Handles events from the transaction
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::HandleHttpEventL(
+ MCatalogsHttpOperation& aOperation,
+ TCatalogsHttpEvent aEvent )
+ {
+ DLTRACEIN((""));
+ DLINFO( ("OP ID: %i, event op: %i, pr: %i, this-ptr: %X",
+ aOperation.OperationId().Id(), aEvent.iOperationState,
+ aEvent.iProgressState, this ) );
+
+
+ switch ( aEvent.iOperationState )
+ {
+ case ECatalogsHttpOpCompleted:
+ {
+
+ if ( !iDdDownload )
+ {
+ DLTRACE( ("Op completed") );
+ UpdateResponseHeadersL( aOperation );
+
+ DLTRACE(("Content type from op: %S", &aOperation.ContentType() ));
+ // Copy content type if didn't receive any from protocol
+ // or if the type received from HTTP headers is OMA DD when
+ // the type from protocol/previous purchase might not be
+ if ( !iContentType.Length() ||
+ aOperation.ContentType().MatchF( KMimeTypeMatchOdd8 ) == 0 )
+ {
+ DLTRACE(("Updating content type"));
+ SetContentTypeL( aOperation.ContentType() );
+ }
+
+ iTransaction = NULL;
+
+ // Tries to parse the target filename from the URI if it hasn't
+ // been set already. Doing this here because if it were done
+ // in UpdateDownloadConfigurationL, pausing before HTTP
+ // headers are received would prevent new HTTP HEAD request
+ // from being sent.
+ ParseFilenameFromUriL();
+
+ TRAPD( err, UpdateFilenameFromContentDispositionL() );
+ if ( err != KErrNone )
+ {
+ // Failed to update from content disposition,
+ // use tempfilename unless some name has already been set
+ UpdateFilenameL();
+ }
+
+ // No need to get headers again
+ iMode = ECatalogsHttpHeaderModeNoHead;
+
+ // Check if the download is a DD and if it is, use a
+ // transaction to download the descriptor so that Download
+ // manager doesn't try to mess with things
+
+ if ( iContentType.MatchF( KMimeTypeMatchOdd8 ) == 0 )
+ {
+ DLTRACE(("Content type matches DD download"));
+ iDdDownload = ETrue;
+
+ StartDescriptorDownloadL();
+ }
+ else
+ {
+ // Start the normal file download
+ User::LeaveIfError( Start() );
+ }
+
+ aOperation.Release();
+ }
+ else // iDdDownload == ETrue
+ {
+
+ DLTRACE(("Closing dd"));
+ iDdFile.Close();
+ iTransaction = NULL;
+ iState = aEvent;
+ iState.iOperationState = ECatalogsHttpOpCompleted;
+ iState.iProgressState = ECatalogsHttpDone;
+
+ iObserver->HandleHttpEventL( *this, iState );
+ aOperation.Release();
+ }
+ break;
+ }
+
+ case ECatalogsHttpOpInProgress:
+ {
+ if ( iDdDownload )
+ {
+ DLTRACE(("DD download"));
+ iState = aEvent;
+ switch ( aEvent.iProgressState )
+ {
+ case ECatalogsHttpResponseBodyReceived:
+ {
+ DLTRACE(("Received a body part"));
+ User::LeaveIfError( iDdFile.Write( iTransaction->Body() ) );
+ iObserver->HandleHttpEventL( *this, aEvent );
+ break;
+ }
+
+ default:
+ {
+ DLTRACE(("Default"));
+
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ {
+ }
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Handles events from the transaction
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpDownload::HandleHttpError(
+ MCatalogsHttpOperation& aOperation, TCatalogsHttpError aError )
+ {
+ DLTRACEIN((""));
+ DLERROR( ("Error type: %i, code: %i", aError.iType,
+ aError.iError ) );
+
+ iTransaction = NULL;
+ aOperation.Release();
+
+ iOwner.CompleteOperation( this );
+ iState.iOperationState = ECatalogsHttpOpFailed;
+ iState.iProgressState = ECatalogsHttpDone;
+ iObserver->HandleHttpError( *this, aError );
+
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// Handles events from the download manager
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::HandleEventL( THttpDownloadEvent aEvent )
+ {
+ DLTRACEIN((""));
+ DLINFO( ("DL id: %d, Dl state: %i, Pr: %i, this-ptr: %X, iState: %d, iProgress: %d, dl-ptr: %X",
+ OperationId().Id(),
+ aEvent.iDownloadState, aEvent.iProgressState,
+ this, iState.iOperationState, iState.iProgressState,
+ iDownload ) );
+
+
+#ifdef __SERIES60_31__
+ if ( IsCancelled() )
+ {
+ if ( IsOneOf(
+ aEvent.iDownloadState,
+ EHttpDlPaused,
+ EHttpDlCompleted,
+ EHttpDlFailed ) )
+ {
+ Cancel();
+ }
+ return;
+ }
+
+#endif
+
+ if ( iState.iProgressState == ECatalogsHttpNone )
+ {
+ DLTRACEOUT(("Not yet in progress"));
+ return;
+ }
+
+ TInt32 statusCode = -1;
+
+ iDownload->GetIntAttribute( EDlAttrStatusCode, statusCode );
+ DLINFO( ("Response status: %i", statusCode ) );
+
+#ifdef CATALOGS_BUILD_CONFIG_DEBUG
+ TInt32 errorId = 0;
+
+ iDownload->GetIntAttribute( EDlAttrErrorId, errorId );
+ DLINFO( ("Error id: %i", errorId ) );
+
+#endif
+
+ TInt32 globalErrorId = 0;
+ iDownload->GetIntAttribute(
+ EDlAttrGlobalErrorId, globalErrorId );
+ DLINFO( ("Global error id: %i", globalErrorId ) );
+
+
+ // was >=, DL manager should give us proper errors but it doesn't always
+ if ( ( statusCode == KHttpErrorStatus ||
+ globalErrorId == KGenericSymbianHttpError ) &&
+ aEvent.iDownloadState != EHttpDlFailed )
+ {
+ DLTRACE(("Setting download as failed because received a response >= 400" ));
+ aEvent.iDownloadState = EHttpDlFailed;
+ }
+
+ switch ( aEvent.iDownloadState )
+ {
+ case EHttpDlCreated:
+ {
+ iState.iOperationState = ECatalogsHttpOpCreated;
+ break;
+ }
+
+ case EHttpDlInprogress:
+ {
+ iState.iOperationState = ECatalogsHttpOpInProgress;
+ // Update progress info
+ HandleEventProgressL( aEvent );
+ break;
+ }
+
+ case EHttpDlPaused:
+ {
+ DLTRACE(("EHttpDlPaused"));
+ // For some reason restored downloads receive unwanted EHttpDlPaused
+ // event when they are started. Hopefully this doesn't break something else
+ if ( iState.iProgressState == ECatalogsHttpStarted )
+ {
+ DLTRACE(("Something funny happened, skip the event"));
+ break;
+ }
+
+ SetTransferring( EFalse );
+ if ( iReconnectWhenFail &&
+ iState.iProgressState == ECatalogsHttpDisconnected )
+ {
+ DLTRACE(("Try to reconnect"));
+ iReconnectWhenFail = EFalse;
+ iDownload->Start();
+ break;
+ }
+
+ if ( iState.iOperationState != ECatalogsHttpOpQueued )
+ {
+ iState.iOperationState = ECatalogsHttpOpPaused;
+ iPaused = ETrue;
+ }
+ ReleasePtr( iConnection );
+
+ if( aEvent.iProgressState == EHttpProgNone )
+ {
+ DLTRACE(("got pause event, resetting pause pending flag"));
+ iPausePending = EFalse;
+ if( iQueuedResume )
+ {
+ DLTRACE(("Handling queued resume"));
+ iQueuedResume = EFalse;
+ Start();
+ }
+ }
+ else
+ {
+ HandleEventProgressL( aEvent );
+ }
+ break;
+ }
+
+
+ case EHttpDlCompleted:
+ {
+ DLINFO( ("EHttpDlCompleted, progress state: %d", aEvent.iProgressState ) );
+ SetTransferring( EFalse );
+
+ // Release connection as soon as possible so that other APs
+ // can be raised in the observer callbacks if necessary
+ ReleasePtr( iConnection );
+
+ if ( iPaused )
+ {
+ DLTRACE(("iPaused == ETrue, setting state to paused"));
+ iState.iOperationState = ECatalogsHttpOpPaused;
+ }
+
+ // This ensures that CompleteOperation() works correctly if
+ // the download was just paused when it completes
+ if ( iState.iOperationState != ECatalogsHttpOpPaused )
+ {
+ iState.iOperationState = ECatalogsHttpOpCompleted;
+ }
+
+ // move/rename temp file as the target file
+ TRAPD( err, MoveFileL() );
+
+ // DLMAIN-546, delete DL manager's download before starting
+ // the next one so that downloads don't jam, again
+ if ( iDownload )
+ {
+ iDownload->GetIntAttribute(
+ EDlAttrDownloadedSize, iTransferredSize );
+
+ DLTRACE(("Deleting download"));
+ DeletePlatformDownload();
+ }
+
+ iState.iProgressState = ECatalogsHttpDone;
+ iOwner.CompleteOperation( this );
+ iState.iOperationState = ECatalogsHttpOpCompleted;
+
+ if ( err != KErrNone && iObserver )
+ {
+ DLERROR(("Error %d occurred when moving", err));
+ iState.iOperationState = ECatalogsHttpOpFailed;
+ iObserver->HandleHttpError(
+ *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral,
+ err ) );
+ }
+ else if ( iObserver )
+ {
+ iObserver->HandleHttpEventL( *this, iState );
+ }
+
+ DLINFO(("EHttpDlCompletedDone"));
+ break;
+ }
+
+
+ case EHttpDlFailed:
+ {
+ DLTRACE(( "Download failed" ));
+ TInt32 errorId = -1;
+ SetTransferring( EFalse );
+ iDownload->GetIntAttribute( EDlAttrErrorId, errorId );
+ DLINFO( ("Error id: %i", errorId ) );
+
+ DLINFO( ("Global error id: %i", globalErrorId ) );
+
+ if ( iReconnectWhenFail &&
+ ( errorId == EConnectionFailed ||
+ errorId == ETransactionFailed ))
+ {
+ DLTRACE(("Try to reconnect"));
+ iReconnectWhenFail = EFalse;
+ iDownload->Start();
+ break;
+ }
+ else if ( errorId == EContentExpired ||
+ errorId == EPartialContentModified )
+ {
+ DLTRACE(("Content has changed, reset and restart"));
+ iReconnectWhenFail = EFalse;
+ iDownload->Reset();
+ iDownload->Start();
+ break;
+ }
+
+ ReleasePtr( iConnection );
+ iState.iOperationState = ECatalogsHttpOpFailed;
+
+
+ TBool deleted = EFalse;
+ if ( iObserver )
+ {
+ // Determine whether failure was due to a HTTP error or some
+ // other error. HTTP errors are mapped to a negative range
+ if ( statusCode >= 400 )
+ {
+ deleted = iObserver->HandleHttpError(
+ *this, TCatalogsHttpError(
+ ECatalogsHttpErrorHttp,
+ KCatalogsErrorHttpBase - statusCode ) );
+ }
+ else
+ {
+ // 5.0 issue: some downloads fail without any error code
+ // so we have to give them some
+ if ( globalErrorId == KErrNone )
+ {
+ DLERROR(("Download failed without an error"));
+ globalErrorId = KErrUnknown;
+ }
+
+ AddRef();
+ iOwner.ConnectionManager().ReportConnectionError(
+ TCatalogsConnectionMethod(), globalErrorId );
+
+ if ( iRefCount > 1 )
+ {
+ deleted = iObserver->HandleHttpError(
+ *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral, globalErrorId ) );
+ }
+ else
+ {
+ deleted = ETrue;
+ }
+ Release();
+ }
+ }
+ if ( !deleted )
+ {
+ iOwner.CompleteOperation( this );
+ iState.iProgressState = ECatalogsHttpDone;
+ }
+ break;
+ }
+
+
+ /// MMC card or other storage media is removed from the phone.
+/*
+ case EHttpDlMediaRemoved:
+ {
+ iState.iOperationState = ECatalogsHttpOpMediaRemoved;
+ break;
+ }
+ */
+
+ /**
+ * MMC card or other storage media inserted and
+ * downloaded content file found on it.
+ * If MMC card inserted, but (partially) downloaded content file
+ * is not found on it, download is failed with error reason
+ * EContentFileIntegrity.
+ */
+/*
+ case EHttpDlMediaInserted:
+ {
+ iState.iOperationState = ECatalogsHttpOpMediaInserted;
+ break;
+ }
+*/
+ /**
+ * Download process can be paused again. This event only occurs after
+ * EHttpDlNonPausable.
+ */
+ case EHttpDlPausable:
+ {
+ DLTRACE(( "Pausable" ));
+ iState.iOperationState = ECatalogsHttpOpPausable;
+ HandleEventProgressL( aEvent );
+ break;
+ }
+
+ /// Download process cannot be paused, or the content will be lost.
+ case EHttpDlNonPausable:
+ {
+
+ iState.iOperationState = ECatalogsHttpOpNonPausable;
+ DLTRACE(( "Nonpausable" ));
+ // Update the download UI data.
+ HandleEventProgressL( aEvent );
+ break;
+ }
+
+ /// Download is started when it's already progressing
+ case EHttpDlAlreadyRunning:
+ {
+ DLTRACE(( "Already running" ));
+ iState.iOperationState = ECatalogsHttpOpAlreadyRunning;
+ HandleEventProgressL( aEvent );
+ // Nothing to do.
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::HandleEventProgressL( const
+ THttpDownloadEvent& aEvent )
+ {
+ DLTRACEIN(( "" ));
+ switch ( aEvent.iProgressState )
+ {
+ case EHttpStarted:
+ {
+ DLTRACE(( "Progress: Started" ));
+ // If the download was paused immediately, iPaused flag will be
+ // ETrue but the dl operation is not paused
+ // Try again to pause the download correctly
+ if ( iPaused )
+ {
+
+ Pause();
+ }
+ else
+ {
+ iState.iProgressState = ECatalogsHttpStarted;
+ iPaused = EFalse;
+ }
+ break;
+ }
+
+ case EHttpProgCreatingConnection:
+ {
+ DLTRACE(( "Progress: Creating connection" ));
+ iState.iProgressState = ECatalogsHttpCreatingConnection;
+ break;
+ }
+
+ case EHttpProgConnected:
+ {
+ DLTRACE(( "Progress: Connected" ));
+ iState.iProgressState = ECatalogsHttpConnected;
+ SetTransferring( ETrue );
+ break;
+ }
+
+ case EHttpProgConnectionSuspended:
+ {
+ DLTRACE(( "Progress: Connection suspended" ));
+ iState.iProgressState = ECatalogsHttpConnectionSuspended;
+ break;
+ }
+
+ case EHttpProgDisconnected:
+ {
+ DLINFO(( "Progress: Disconnected" ));
+
+ if ( iState.iProgressState == ECatalogsHttpCreatingConnection )
+ {
+ DLERROR(("Connection creation failed, no reconnecting"));
+ iReconnectCount = 0;
+ }
+
+ iState.iProgressState = ECatalogsHttpDisconnected;
+ DASSERT( iObserver );
+ SetTransferring( EFalse );
+ // Don't restart paused downloads or notify about disconnection
+ if ( !iPaused )
+ {
+ TInt32 globalErrorId = 0;
+ iDownload->GetIntAttribute(
+ EDlAttrGlobalErrorId, globalErrorId );
+ DLINFO( ("Global error id: %i", globalErrorId ) );
+
+ if ( globalErrorId == KErrCancel )
+ {
+ DLTRACE(("Cancelled"));
+ iState.iOperationState = ECatalogsHttpOpFailed;
+ iOwner.ConnectionManager().ReportConnectionError(
+ TCatalogsConnectionMethod(), globalErrorId );
+
+ }
+ else //if ( globalErrorId != KErrNone )
+ {
+
+ if ( iReconnectCount )
+ {
+ DLTRACE(("Reconnect, count left: %d", iReconnectCount ));
+ iReconnectCount--;
+ iReconnectWhenFail = ETrue;
+ }
+ else if ( iObserver )
+ {
+ DLTRACE(("No more reconnect attempts"));
+ TCatalogsHttpError error( ECatalogsHttpErrorGeneral, KErrDisconnected );
+ iObserver->HandleHttpError( *this, error );
+ }
+ }
+
+ }
+ break;
+ }
+
+ case EHttpProgDownloadStarted:
+ {
+ DLTRACE(( "Progress: Download started" ));
+ iState.iProgressState = ECatalogsHttpDownloadStarted;
+ DASSERT( iObserver );
+
+ if ( iObserver )
+ {
+ iObserver->HandleHttpEventL( *this,
+ iState );
+ }
+ break;
+ }
+
+
+ case EHttpContentTypeReceived:
+ // Start download again if content-type is acceptable
+ // and UiLib is not installed
+ {
+ // State is paused. The observer should continue
+ // the download if the content type is acceptable
+ // otherwise he should cancel it
+ DLTRACE( ( "Progress: Content type received" ) );
+ iState.iProgressState = ECatalogsHttpContentTypeReceived;
+ UpdateContentType();
+
+
+ if ( iObserver )
+ {
+
+ iObserver->HandleHttpEventL( *this,
+ iState );
+ }
+ break;
+ }
+
+
+ case EHttpProgSubmitIssued:
+ {
+ iState.iProgressState = ECatalogsHttpSubmitIssued;
+ break;
+ }
+
+
+ case EHttpProgResponseHeaderReceived:
+ {
+ DLTRACE(( "Progress: Response header received" ));
+ iState.iProgressState = ECatalogsHttpResponseHeaderReceived;
+
+ // Reset reconnect count
+ iReconnectCount = KReconnectAttempts;
+
+ // Read the response headers from platform DL manager
+ UpdateResponseHeadersL();
+ UpdateContentType();
+
+ if ( iObserver )
+ {
+ iObserver->HandleHttpEventL( *this,
+ iState );
+ }
+ break;
+ }
+
+
+ case EHttpProgResponseBodyReceived:
+ {
+ DLTRACE(( "Progress: Response body received" ));
+ iState.iProgressState = ECatalogsHttpResponseBodyReceived;
+
+ // Reset reconnect count
+ iReconnectCount = KReconnectAttempts;
+
+ TInt32 size = 0;
+ iDownload->GetIntAttribute( EDlAttrDownloadedSize, size );
+ DLTRACE(("Transferred size from download: %i", size));
+
+ if ( size != iTransferredSize )
+ {
+ DLTRACE(("Updating transferred size"));
+ iTransferredSize = size;
+ if ( iObserver )
+ {
+ iObserver->HandleHttpEventL( *this,
+ iState );
+ }
+ }
+
+ break;
+ }
+
+
+ case EHttpProgRedirectedPermanently:
+ {
+ DLTRACE(( "Progress: Redirected permanently" ));
+ iState.iProgressState = ECatalogsHttpRedirectedPermanently;
+
+ TRAPD( err,
+ {
+ UpdateUriL();
+ ParseFilenameFromUriL();
+ } );
+
+ if ( iObserver )
+ {
+ if ( err == KErrNone )
+ {
+ iObserver->HandleHttpEventL( *this, iState );
+ }
+ else
+ {
+ iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral, err ) );
+ }
+ }
+
+ break;
+ }
+
+
+ case EHttpProgRedirectedTemporarily:
+ {
+ DLTRACE(( "Progress: Redirected temporarily" ));
+ iState.iProgressState = ECatalogsHttpRedirectedTemporarily;
+
+ TRAPD( err,
+ {
+ UpdateUriL();
+ ParseFilenameFromUriL();
+ } );
+
+ if ( iObserver )
+ {
+ if ( err == KErrNone )
+ {
+ iObserver->HandleHttpEventL( *this, iState );
+ }
+ else
+ {
+ iObserver->HandleHttpError( *this, TCatalogsHttpError(
+ ECatalogsHttpErrorGeneral, err ) );
+ }
+ }
+
+ break;
+ }
+
+ case EHttpProgContentTypeChanged:
+ {
+ iState.iProgressState = ECatalogsHttpContentTypeChanged;
+ break;
+ }
+
+
+ case EHttpProgMovingContentFile:
+ {
+ DLINFO( ("Progress: Moving content file") );
+ iState.iProgressState = ECatalogsHttpMovingContentFile;
+ break;
+ }
+
+
+ case EHttpProgContentFileMoved:
+ {
+ DLINFO( ("Progress: Content file moved") );
+ iState.iProgressState = ECatalogsHttpContentFileMoved;
+ iOwner.CompleteOperation( this );
+ break;
+ }
+
+ default:
+ DLTRACE(("Default"));
+ DLTRACE(( "state: %d, progress: %d",aEvent.iDownloadState, aEvent.iProgressState));
+ break;
+ }
+ }
+
+
+
+// ---------------------------------------------------------------------------
+// Sets file server session
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetFileServerSession( RFs& aFs )
+ {
+ DLTRACEIN((""));
+ iFs = aFs;
+ }
+
+
+#ifdef __SERIES60_31__
+TBool CCatalogsHttpDownload::IsCancelled() const
+ {
+ return iCancelled;
+ }
+#endif
+
+
+
+// ---------------------------------------------------------------------------
+// Sets header mode
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetHeaderMode( TCatalogsHttpHeaderMode aMode )
+ {
+ iMode = aMode;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//
+CCatalogsHttpDownload::CCatalogsHttpDownload(
+ CCatalogsHttpDownloadManager& aOwner,
+ RHttpDownload* aDownload ) :
+ iOwner( aOwner ),
+ iDownload( aDownload ),
+ iState( ECatalogsHttpOpCreated, ECatalogsHttpNone ),
+ iRefCount( 1 ),
+ iNormalDelete( EFalse ),
+ iReconnectCount( KReconnectAttempts )
+ {
+ DLTRACEIN(( "this-ptr: %X", this ));
+ }
+
+
+// ---------------------------------------------------------------------------
+// 2nd phase constructor
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::ConstructL( const CCatalogsHttpConfig* aConfig )
+ {
+ // Get the id for the download and update iUri
+ if ( iDownload )
+ {
+ // id part will be updated from disk
+ iId = TCatalogsTransportOperationId( iOwner.SessionId(), KErrNotFound );
+
+ UpdateSecondaryIdL();
+
+ User::LeaveIfError( SetDeleteState( EDownloadCanBeDeleted ) );
+ // Update iUri to match the current URI
+ UpdateUriL();
+ iResponseHeaders = CCatalogsHttpHeaders::NewL();
+ }
+ else
+ {
+ iId = TCatalogsTransportOperationId(
+ iOwner.SessionId(),
+ iOwner.NewDownloadId() );
+ }
+
+ // Create a copy of the configuration
+ if ( aConfig )
+ {
+ iConfig = aConfig->CloneL();
+ }
+ else
+ {
+ // Or create a new configuration
+ iConfig = CCatalogsHttpConfig::NewL();
+ }
+
+ AssignDesL( iTempFilename, KNullDesC() );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates the content type
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateContentType()
+ {
+ DLTRACEIN(( "" ));
+ if ( !iContentType.Length() )
+ {
+ // Download always exists when this is called so no need to check
+ DLTRACE(("Updating the content type"));
+ iDownload->GetStringAttribute( EDlAttrContentType,
+ iContentType );
+ }
+ DLTRACEOUT(("Content-type: %S", &iContentType ));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates the filename either from content-disposition header or DL manager
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateFilenameFromContentDispositionL()
+ {
+ DLTRACEIN(( "" ));
+ const TDesC8& value = iResponseHeaders->HeaderByKeyL(
+ KCatalogsHttpHeaderContentDisposition );
+
+ DLTRACE( ( "Content-disposition: %S", &value ) );
+
+ TCatalogsContentDispositionParser parser( value );
+
+ //
+ HBufC* filename = parser.FilenameLC();
+
+ iConfig->SetFilenameL( *filename );
+ CleanupStack::PopAndDestroy( filename );
+
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateFilenameL()
+ {
+ DLTRACEIN( ("") );
+ if ( ContainsData( iTempFilename ) &&
+ // We don't want to overwrite existing name
+ !iConfig->Filename().Length() )
+ {
+ DLTRACE(( _L("Setting filename as temp filename: %S"), iTempFilename ));
+ TParsePtrC parse( *iTempFilename );
+ iConfig->SetFilenameL( parse.NameAndExt() );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates the platform download object to match the configuration
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateDownloadConfigurationL()
+ {
+ DASSERT( iEncodedUri );
+ DLTRACEIN(( "URI: %S", iEncodedUri ));
+ DASSERT( iConfig );
+
+ TCatalogsConnectionMethod currentAp = iConfig->ConnectionMethod();
+
+ // If no APN id is set, we need to use the default
+ if ( !currentAp.iApnId &&
+ !currentAp.iId )
+ {
+ currentAp = iOwner.ConnectionManager().DefaultConnectionMethod();
+ iConfig->SetConnectionMethod( currentAp );
+ }
+
+ // Ask for confirmation
+ if ( !iOwner.ConnectionManager().AskConnectionConfirmation( currentAp ) )
+ {
+ DLINFO(("Connection denied by the user"));
+ User::Leave( KCatalogsErrorHttpConnectionDenied );
+ }
+
+ // note that actual connection setting is done by the
+ // session manager according to operation's config
+ // so we don't set the accesspoint to DL manager here anymore
+
+ // Update the member variable
+ iObserver = iConfig->Observer();
+
+ // Directory MUST be set
+ if ( !iObserver || !iConfig->Directory().Length() )
+ {
+ DLERROR(("No directory path or observer set, leaving with KErrArgument"));
+ User::Leave( KErrArgument );
+ }
+
+ // Check if HEAD is required
+ UpdateHeadRequirement();
+
+ // Update the filename only if it has not been set yet and header mode
+ // is forced (like content downloads and previews) and
+ // HEAD is not prohibited by download options
+ if ( iMode == ECatalogsHttpHeaderModeForceHead &&
+ !iConfig->Filename().Length() &&
+ !( iConfig->Options() & ECatalogsHttpDisableHeadRequest ) )
+ {
+ DLTRACE(( "Forcing header getting with transactions" ) );
+
+ iTransaction = iOwner.CreateDlTransactionL( Uri(),
+ *this, *iConfig );
+ iTransaction->Config().SetHttpMethod( ECatalogsHttpHead );
+ iTransaction->Start();
+ DLTRACE(( "Transaction started" ));
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates the URI from the DL manager to iUri
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateUriL()
+ {
+ DLTRACEIN( ("") );
+ // Get the current url of the download
+ RBuf8 buf;
+ CleanupClosePushL( buf );
+ buf.CreateL( KMaxUrlLength );
+
+ User::LeaveIfError( iDownload->GetStringAttribute( EDlAttrCurrentUrl,
+ buf ) );
+
+ // DL manager has the encoded URI
+ AssignDesL( iEncodedUri, buf );
+ CleanupStack::PopAndDestroy( &buf );
+
+ DeletePtr( iUri );
+
+ iUri = EscapeUtils::EscapeDecodeL( EncodedUri() );
+ DLTRACE(( "URI: %S", &EncodedUri() ));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates the request headers to the platform DL manager
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateRequestHeadersL()
+ {
+ DLTRACEIN( ("") );
+ RPointerArray<CCatalogsKeyValuePair>& headers(
+ iConfig->RequestHeaders().Headers() );
+
+
+ // Iterate through headers and add them either to the request headers
+ // in DL manager or iAddedRequestHeaders if they don't have an enumeration
+ // in DL manager
+ for ( TInt i = 0; i < headers.Count(); ++i )
+ {
+ TUint predefined = MatchWithPredefinedRequestHeader(
+ headers[i]->Key() );
+
+ if ( !predefined )
+ {
+ predefined = MatchWithPredefinedGeneralHeader(
+ headers[i]->Key() );
+ }
+
+ if ( !predefined )
+ {
+ AddRequestHeaderL( iAddedRequestHeaders, *headers[i] );
+ }
+ else
+ {
+ User::LeaveIfError( iDownload->SetStringAttribute(
+ predefined, headers[i]->Value() ) );
+ }
+ }
+
+ // Add the headers that don't have a predefined enumeration in
+ // the platform DL manager
+ if ( iAddedRequestHeaders )
+ {
+ DLTRACE(( "added request headers: %S", iAddedRequestHeaders ));
+ User::LeaveIfError( iDownload->SetStringAttribute(
+ EDlAttrRequestHeaderAddon, *iAddedRequestHeaders ) );
+ delete iAddedRequestHeaders;
+ iAddedRequestHeaders = NULL;
+ }
+ DLTRACEOUT((""));
+ }
+
+
+// ---------------------------------------------------------------------------
+// Update the response headers from DL manager to the download
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateResponseHeadersL()
+ {
+ DLTRACEIN( ("") );
+#ifndef CATALOGS_DISABLE_DOWNLOAD_RESPONSE_HEADERS
+ RBuf8 buf;
+ buf.CreateL( KMaxGeneralHeaderFieldLength );
+ buf.CleanupClosePushL();
+
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrResponseCharSet, buf ) )
+ {
+ DLTRACE( ( "CharSet: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpResponseCharSet, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrResponseAge, buf ) )
+ {
+ DLTRACE( ( "Age: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpResponseAge, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrResponseETag, buf ) )
+ {
+ DLTRACE( ( "ETag: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpResponseETag, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrResponseLocation, buf ) )
+ {
+ DLTRACE( ( "Location: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpResponseLocation, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrResponseRetryAfter, buf ) )
+ {
+ DLTRACE( ( "RetryAfter: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpResponseRetryAfter, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrResponseServer, buf ) )
+ {
+ DLTRACE( ( "ResponseServer: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpResponseServer, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrResponseVary, buf ) )
+ {
+ DLTRACE( ( "ResponseVary: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpResponseVary, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrGeneralCacheControl, buf ) )
+ {
+ DLTRACE( ( "GeneralCacheControl: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpGeneralCacheControlHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrGeneralDate, buf ) )
+ {
+ DLTRACE( ( "Date: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpGeneralDateHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrGeneralPragma, buf ) )
+ {
+ DLTRACE( ( "Pragma: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpGeneralPragmaHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrGeneralVia, buf ) )
+ {
+ DLTRACE( ( "Via: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpGeneralViaHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrGeneralWarning, buf ) )
+ {
+ DLTRACE( ( "Warning: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpGeneralWarningHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrEntityAllow, buf ) )
+ {
+ DLTRACE( ( "Allow: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpEntityAllowHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrEntityContentEncoding, buf ) )
+ {
+ DLTRACE( ( "Content-Encoding: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpEntityContentEncodingHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrEntityContentLanguage, buf ) )
+ {
+ DLTRACE( ( "Content-Language: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpEntityContentLanguageHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrEntityContentLocation, buf ) )
+ {
+ DLTRACE( ( "Content-Location: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpEntityContentLocationHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrEntityExpires, buf ) )
+ {
+ DLTRACE( ( "Expires: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpEntityExpiresHeader, buf );
+ }
+
+ if ( KErrNone == iDownload->GetStringAttribute( EDlAttrEntityLastModified, buf ) )
+ {
+ DLTRACE( ( "Last modified: %S", &static_cast<TDesC8&>(buf) ) );
+ iResponseHeaders->AddHeaderL( KHttpEntityLastModifiedHeader, buf );
+ }
+
+
+ CleanupStack::PopAndDestroy( buf );
+
+#endif
+
+ DLTRACEOUT( ("") );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Update the response headers from the transaction to the download
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateResponseHeadersL(
+ MCatalogsHttpOperation& aOperation )
+ {
+ DLTRACEIN( ("") );
+ CCatalogsHttpHeaders* headers =
+ static_cast<const CCatalogsHttpHeaders&>(
+ aOperation.ResponseHeadersL() ).CloneL();
+
+ delete iResponseHeaders;
+ iResponseHeaders = headers;
+
+ DLTRACEOUT( ("") );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Checks if the given header matches any of the request headers that have
+// an predefined enumeration in the platform DL manager
+// ---------------------------------------------------------------------------
+//
+TUint CCatalogsHttpDownload::MatchWithPredefinedRequestHeader(
+ const TDesC8& aHeader ) const
+ {
+ if ( aHeader.CompareF( KHttpRequestAcceptHeader ) == 0 )
+ {
+ return EDlAttrRequestAccept;
+ }
+ else if ( aHeader.CompareF( KHttpRequestAcceptCharSetHeader ) == 0 )
+ {
+ return EDlAttrRequestAcceptCharSet;
+ }
+ else if ( aHeader.CompareF( KHttpRequestAcceptLanguageHeader ) == 0 )
+ {
+ return EDlAttrRequestAcceptLanguage;
+ }
+ else if ( aHeader.CompareF( KHttpRequestExpectHeader ) == 0 )
+ {
+ return EDlAttrRequestExpect;
+ }
+ else if ( aHeader.CompareF( KHttpRequestFromHeader ) == 0 )
+ {
+ return EDlAttrRequestFrom;
+ }
+ else if ( aHeader.CompareF( KHttpRequestHostHeader ) == 0 )
+ {
+ return EDlAttrRequestHost;
+ }
+ else if ( aHeader.CompareF( KHttpRequestMaxForwardsHeader ) == 0 )
+ {
+ return EDlAttrRequestMaxForwards;
+ }
+ else if ( aHeader.CompareF( KHttpRequestPragmaHeader ) == 0 )
+ {
+ return EDlAttrRequestPragma;
+ }
+ else if ( aHeader.CompareF( KHttpRequestRefererHeader ) == 0 )
+ {
+ return EDlAttrRequestReferer;
+ }
+ else if ( aHeader.CompareF( KHttpRequestUserAgentHeader ) == 0 )
+ {
+ return EDlAttrRequestUserAgent;
+ }
+ else if ( aHeader.CompareF( KHttpRequestVaryHeader ) == 0 )
+ {
+ return EDlAttrRequestVary;
+ }
+
+ return 0;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Checks if the given header matches any of the general headers that have
+// an predefined enumeration in the platform DL manager
+// ---------------------------------------------------------------------------
+//
+TUint CCatalogsHttpDownload::MatchWithPredefinedGeneralHeader(
+ const TDesC8& aHeader ) const
+ {
+ if ( aHeader.CompareF( KHttpGeneralCacheControlHeader ) == 0 )
+ {
+ return EDlAttrGeneralCacheControl;
+ }
+ else if ( aHeader.CompareF( KHttpGeneralDateHeader ) == 0 )
+ {
+ return EDlAttrGeneralDate;
+ }
+ else if ( aHeader.CompareF( KHttpGeneralPragmaHeader ) == 0 )
+ {
+ return EDlAttrGeneralPragma;
+ }
+ else if ( aHeader.CompareF( KHttpGeneralViaHeader ) == 0 )
+ {
+ return EDlAttrGeneralVia;
+ }
+ else if ( aHeader.CompareF( KHttpGeneralWarningHeader ) == 0 )
+ {
+ return EDlAttrGeneralWarning;
+ }
+ return 0;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Checks if the given header matches any of the entity headers that have
+// an predefined enumeration in the platform DL manager
+// ---------------------------------------------------------------------------
+//
+TUint CCatalogsHttpDownload::MatchWithPredefinedEntityHeader(
+ const TDesC8& aHeader ) const
+ {
+ if ( aHeader.CompareF( KHttpEntityAllowHeader ) == 0 )
+ {
+ return EDlAttrEntityAllow;
+ }
+ else if ( aHeader.CompareF( KHttpEntityContentEncodingHeader ) == 0 )
+ {
+ return EDlAttrEntityContentEncoding;
+ }
+ else if ( aHeader.CompareF( KHttpEntityContentLanguageHeader ) == 0 )
+ {
+ return EDlAttrEntityContentLanguage;
+ }
+ else if ( aHeader.CompareF( KHttpEntityContentLocationHeader ) == 0 )
+ {
+ return EDlAttrEntityContentLocation;
+ }
+ else if ( aHeader.CompareF( KHttpEntityExpiresHeader ) == 0 )
+ {
+ return EDlAttrEntityExpires;
+ }
+ else if ( aHeader.CompareF( KHttpEntityLastModifiedHeader ) == 0 )
+ {
+ return EDlAttrEntityLastModified;
+ }
+ return 0;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Adds the header from the pair to the target in the format used by
+// platform's DL manager
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::AddRequestHeaderL( HBufC8*& aTarget,
+ const CCatalogsKeyValuePair& aPair )
+ {
+ DLTRACEIN((""));
+ TInt headerLength = aPair.Key().Length() +
+ aPair.Value().Length() + 1;
+
+ TInt newSize = 0;
+
+
+ // Allocate or reallocate the buffer if necessary
+ if( !aTarget )
+ {
+ DLTRACE( ("Creating target buffer") );
+ aTarget = HBufC8::NewL( headerLength );
+ }
+ else if( aTarget->Length() )
+ {
+ DLTRACE( ( "Reallocating target buffer with new length" ) );
+ newSize = aTarget->Length() + headerLength + 1;
+ aTarget = aTarget->ReAllocL( newSize );
+ }
+ else
+ {
+ DLTRACE( ("Reallocating target buffer") );
+ aTarget = aTarget->ReAllocL( headerLength );
+ }
+
+ TPtr8 ptr( aTarget->Des() );
+
+ if( newSize )
+ {
+ DLTRACE( ("Appending to existing headers") );
+ // Append after the existing headers
+ ptr.Append( KHttpFieldSeparator );
+ ptr.Append( aPair.Key() );
+ ptr.Append( KColon );
+ ptr.Append( aPair.Value() );
+ }
+ else
+ {
+ DLTRACE( ("Creating the first header") );
+ // Add the first header
+ ptr.Append( aPair.Key() );
+ ptr.Append( KColon );
+ ptr.Append( aPair.Value() );
+
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::SetTransferring( TBool aTransferring )
+ {
+ DLTRACEIN(("aTransferring: %d, iTransferring: %d",
+ aTransferring,
+ iTransferring ));
+
+ if ( iTransferring != aTransferring )
+ {
+ iTransferring = aTransferring;
+ iOwner.ReportConnectionStatus( iTransferring );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates the connection to download manager and starts the download
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::StartDownload()
+ {
+ DLTRACEIN((""));
+ DASSERT( iConnection );
+
+ TRAPD( err,
+ {
+ iOwner.SetConnectionL( *iConnection );
+
+ // Update the configuration
+ if ( iState.iProgressState == ECatalogsHttpNone )
+ {
+ DLTRACE(("Updating dl config"));
+ InitializeDownloadL();
+ }
+ });
+
+ if ( err == KErrNone )
+ {
+ err = iDownload->Start();
+ }
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Starts a OMA DD download if necessary
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpDownload::StartDescriptorDownloadL()
+ {
+ DLTRACEIN((""));
+ if ( iDdDownload )
+ {
+ // This ensures that headers are re-get if the op is paused
+ iMode = ECatalogsHttpHeaderModeForceHead;
+ DLTRACE(("Content type matches DD download"));
+ HBufC* fullName = iConfig->FullPathLC();
+
+ DLTRACE(("Opening target file"));
+ User::LeaveIfError( iDdFile.Replace( iFs, *fullName, EFileWrite ) );
+ CleanupStack::PopAndDestroy( fullName );
+
+ DLTRACE(("Creating the transaction"));
+ // Download the descriptor without DL manager
+ // Use normal URI because transaction encodes it
+ iTransaction = iOwner.CreateDlTransactionL(
+ Uri(),
+ *this,
+ *iConfig );
+
+ iTransaction->Config().SetHttpMethod( ECatalogsHttpGet );
+ iTransaction->Start();
+
+ return ETrue;
+ }
+
+ DLTRACEOUT(("Not a DD download"));
+ return EFalse;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Delete downloaded files
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::DeleteFiles()
+ {
+ DLTRACEIN((""));
+ TInt err = KErrNotFound;
+ if ( ContainsData( iTempFilename ) )
+ {
+ DLTRACE(( _L("Deleting the temp file: %S"), iTempFilename ));
+ err = BaflUtils::DeleteFile( iFs, *iTempFilename );
+ }
+
+ // only delete target file if the temp file was not found in case
+ // we were re-downloading something
+ if ( err == KErrNotFound &&
+ // ensures that we don't accidentally delete whole directories
+ iConfig->Directory().Length() &&
+ iConfig->Filename().Length() )
+ {
+ TPath path;
+ path.Append( iConfig->Directory() );
+ path.Append( iConfig->Filename() );
+
+ DLTRACE(( _L("Deleting the final file: %S"), &path ));
+ BaflUtils::DeleteFile( iFs, path );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::MoveFileL()
+ {
+ DLTRACEIN((""));
+ if ( !iTempFilename )
+ {
+ DLERROR(("Tempfilename has not been set, leaving" ));
+ User::Leave( KErrGeneral );
+ }
+
+ if ( !iConfig->Filename().Length() )
+ {
+ // Update filename extension by using dochandler
+ if ( iConfig->Options() & ECatalogsHttpDisableHeadRequest )
+ {
+ UpdateExtensionL();
+ }
+ else
+ {
+ DLTRACE(("No target filename, no need to move" ));
+ UpdateFilenameL();
+ return;
+ }
+ }
+
+ HBufC* target = iConfig->FullPathLC();
+ if ( *target != *iTempFilename )
+ {
+ DLTRACE(( _L("Moving %S to %S"), iTempFilename, target ));
+ CFileMan* fileMan = CFileMan::NewL( iFs );
+ CleanupStack::PushL( fileMan );
+
+ User::LeaveIfError(
+ fileMan->Move( *iTempFilename, *target, CFileMan::EOverWrite ) );
+ CleanupStack::PopAndDestroy( fileMan );
+ }
+ CleanupStack::PopAndDestroy( target );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::ParseFilenameFromUriL()
+ {
+ DLTRACEIN((""));
+ if ( iConfig->Filename().Length() )
+ {
+ DLTRACEOUT(("Filename already set"));
+ return;
+ }
+
+ DASSERT( iUri );
+ // Note: Download manager actually does this same stuff, more or less,
+ //(done still in 3.1.50) but it's a bit clearer if we do it by ourselves.
+ TUriParser8 uriParser;
+ User::LeaveIfError( uriParser.Parse( Uri() ) );
+ HBufC* filename = uriParser.GetFileNameL( EUriFileNameTail );
+ DLTRACE(( _L("Parsed filename %S"), filename ));
+ CleanupStack::PushL( filename );
+ iConfig->SetFilenameL( *filename );
+ CleanupStack::PopAndDestroy( filename );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool CCatalogsHttpDownload::ContainsData( const HBufC* aDes ) const
+ {
+ return aDes && aDes->Length();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates file extension by using dochandler
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateExtensionL()
+ {
+ DLTRACEIN((""));
+ // UpdateFilenameL parses the filename from iTempFilename which contains
+ // the whole path and sets it to iConfig->Filename()
+ UpdateFilenameL();
+
+ TFileName filename = iConfig->Filename();
+ TDataType type( ContentType() );
+ iOwner.DocumentHandler().CheckFileNameExtension( filename, type );
+
+ iConfig->SetFilenameL( filename );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Forces HEAD if content-type requires so
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateHeadRequirement()
+ {
+ DLTRACEIN((""));
+ if ( ContentType().MatchF( KMimeTypeMatchOdd8 ) != KErrNotFound ||
+ ContentType().MatchF( KMimeTypeMatchDrm8 ) != KErrNotFound ||
+ ContentType().MatchF( KMimeTypeMatchJad8 ) != KErrNotFound )
+ {
+ DLTRACE(("Content is DD/JAD/DRM, forcing HEAD"));
+ // Clear HEAD flag
+ iConfig->SetOptions(
+ iConfig->Options() & ~ECatalogsHttpDisableHeadRequest );
+
+ SetHeaderMode( ECatalogsHttpHeaderModeForceHead );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Sets delete status and id to the platform download as user data
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::SetDeleteState(
+ const TDownloadDeleteState aStatus )
+ {
+ DLTRACEIN(( "aStatus: %x, id: %x", aStatus, OperationId().Id() ));
+
+ TInt err = KErrNone;
+ if ( iDownload )
+ {
+ err = iDownload->SetIntAttribute( EDlAttrUserData, aStatus );
+ }
+
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Gets delete status and download id from the platform download
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsHttpDownload::GetDeleteState(
+ TDownloadDeleteState& aStatus )
+ {
+ DLTRACEIN((""));
+ TInt32 data = 0;
+
+ TInt err = KErrNotReady;
+ if ( iDownload )
+ {
+ err = iDownload->GetIntAttribute( EDlAttrUserData, data );
+ DLTRACE(("Data: %d", data));
+ aStatus = static_cast<TDownloadDeleteState>( data );
+ }
+ DLTRACEOUT(("status: %x", aStatus ));
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Initializes download
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::InitializeDownloadL()
+ {
+ DLTRACEIN((""));
+ if ( !iFileIsSet )
+ {
+ RFile file;
+ CleanupClosePushL( file );
+ BaflUtils::EnsurePathExistsL( iFs, iConfig->Directory() );
+
+ if ( !iTempFilename->Length() )
+ {
+ // Create a temp name & file
+ DLTRACE(("Creating temp file"));
+
+ TFileName filename;
+ // Create a temp name
+ User::LeaveIfError( file.Temp(
+ iFs, iConfig->Directory(), filename, EFileWrite ) );
+
+ DLTRACE(( _L("Temp filename: %S"), &filename ));
+ AssignDesL( iTempFilename, filename );
+ }
+ else // tempfilename has been created, use it
+ {
+ DLTRACE(( _L("Using path: %S"), iTempFilename ));
+
+ TRAPD( err,
+ OpenOrCreateFileL( iFs, file, *iTempFilename, EFileWrite ) );
+
+ DLTRACE(("File open err: %d", err));
+ if ( err == KErrNone )
+ {
+ // Seek to end so that download manager doesn't overwrite
+ // already downloaded parts
+ TInt pos = 0;
+ file.Seek( ESeekEnd, pos );
+ }
+ else if ( err == KErrInUse )
+ {
+ // File is (hopefully) used by DL manager because it hasn't
+ // exited after we paused the download and thus we can't
+ // set the file handle to the download because it already exists
+ iFileIsSet = ETrue;
+ }
+ else
+ {
+ User::Leave( err );
+ }
+ }
+
+ if ( !iDownload )
+ {
+ DLTRACE(("Creating RHttpDownload"));
+ iDownload = &iOwner.CreatePlatformDownloadL( EncodedUri() );
+
+ // Platform download's id is used as a secondary id
+ UpdateSecondaryIdL();
+
+ // Sets delete status and also updates id to the download
+ User::LeaveIfError( SetDeleteState( EDownloadCanBeDeleted ) );
+
+ // Update the request headers to the download manager but do it
+ // only once
+ UpdateRequestHeadersL();
+ }
+
+ // Check if the download has been set progressive
+ TBool progressive = EFalse;
+ User::LeaveIfError( iDownload->GetBoolAttribute(
+ EDlAttrProgressive, progressive ) );
+
+
+ // We want to have progressive downloads because then DL manager uses
+ // a smaller download buffer which makes progress events much more
+ // frequent. However, something goes wrong if the progressive flag is
+ // set twice so we have to prevent that. Also we don't need progress
+ // events for icons so we use the download priority to determine whether
+ // we use progressive dls or not
+ if ( !progressive &&
+ iConfig->Priority() >= ECatalogsPriorityMedium &&
+ // for some reason EDlAttrProgressive returns EFalse after
+ // we restart engine but DL manager stays up. We must not
+ // set the flag if it has already been set because it
+ // messes the download
+ !iFileIsSet )
+ {
+ DLTRACE(("Setting download as progressive"));
+ User::LeaveIfError( iDownload->SetBoolAttribute(
+ EDlAttrProgressive, ETrue ) );
+ }
+
+ // Doesn't pause the download after content type has been received
+ User::LeaveIfError( iDownload->SetBoolAttribute(
+ EDlAttrNoContentTypeCheck, ETrue ) );
+
+ if ( !iFileIsSet )
+ {
+ DLTRACE(("Setting filehandle to download"));
+ User::LeaveIfError( iDownload->SetFileHandleAttribute( file ) );
+ iFileIsSet = ETrue;
+ }
+
+ CleanupStack::PopAndDestroy( &file );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Delete platform download and reset secondary id
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::DeletePlatformDownload()
+ {
+ if ( iDownload )
+ {
+ iDownload->Delete();
+ iDownload = NULL;
+ iId.SetSecondaryId( KErrNotFound );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates secondary id from the platform download
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::UpdateSecondaryIdL()
+ {
+ TInt32 secondaryId = KErrNotFound;
+ User::LeaveIfError(
+ iDownload->GetIntAttribute( EDlAttrId, secondaryId ) );
+ iId.SetSecondaryId( secondaryId );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Encodes the URI
+// ---------------------------------------------------------------------------
+//
+void CCatalogsHttpDownload::EncodeUriL()
+ {
+ DeletePtr( iEncodedUri );
+ iEncodedUri = CatalogsHttpUtils::EncodeUriL( Uri() );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Returns the encoded URI
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CCatalogsHttpDownload::EncodedUri() const
+ {
+ DASSERT( iEncodedUri );
+ return *iEncodedUri;
+ }
+