/*
* 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;
    }

