browserutilities/downloadmgr/DownloadMgrServEng/Src/HttpStorage.cpp
changeset 0 dd21522fd290
child 36 0ed94ceaa377
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/browserutilities/downloadmgr/DownloadMgrServEng/Src/HttpStorage.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,1217 @@
+/*
+* Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Implements storage functionality in the DownloadManager
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <bldvariant.hrh>
+#include <Browser_platform_variant.hrh>
+
+#include "FileExt.h"
+#include "HttpClientApp.h"
+#include "HttpDownload.h"
+#include "HttpStorage.h"
+#include "HttpDownloadManagerServerEngine.h"
+#include "HttpDownloadMgrLogger.h"
+#include "HeaderField.h"
+#include "BuffStorage.h"
+
+#include <SysUtil.h>
+#include <DocumentHandler.h>
+#include <APMSTD.H>
+
+#ifdef __SYNCML_DM_FOTA
+#include <fotaengine.h>
+#endif
+
+#ifdef RD_MULTIPLE_DRIVE
+#include <driveinfo.h>
+#endif //RD_MULTIPLE_DRIVE
+
+// EXTERNAL DATA STRUCTURES
+//extern  ?external_data;
+
+// EXTERNAL FUNCTION PROTOTYPES  
+//extern ?external_function( ?arg_type,?arg_type );
+
+// CONSTANTS
+//const ?type ?constant_var = ?constant;
+const TInt KDefaultStorageBufferSize = 128 * 1024;
+const TInt KFileNameExtensionMaxSize = 5; // practical maximum length of filename extension for renamed downloads
+const TInt KDefaultStorageBufferSizePD = 16 * 1024;
+// MACROS
+//#define ?macro ?macro_def
+
+// LOCAL CONSTANTS AND MACROS
+//const ?type ?constant_var = ?constant;
+//#define ?macro_name ?macro_def
+
+// MODULE DATA STRUCTURES
+//enum ?declaration
+//typedef ?declaration
+
+// LOCAL FUNCTION PROTOTYPES
+//?type ?function_name( ?arg_type, ?arg_type );
+
+// FORWARD DECLARATIONS
+//class ?FORWARD_CLASSNAME;
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::CHttpStorage
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CHttpStorage::CHttpStorage( CHttpDownload* aDownload )
+    :iDownload( aDownload )
+    ,iProgressiveDownload( EFalse )
+    ,iLength( KDefaultContentLength )
+    ,iStorageMethod( EStoreFile )
+    ,iBufferingEnabled( EFalse )
+    ,iBufferSize( KDefaultStorageBufferSize )
+    ,iPartialLength( KDefaultContentLength )
+    {
+    CLOG_WRITE_1( "Storage created: 0x%x", this );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::ConstructL()
+    {
+    iStorage = CBuffStorage::NewL(this);
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CHttpStorage* CHttpStorage::NewL( CHttpDownload* aDownload )
+    {
+    CHttpStorage* self = new( ELeave ) CHttpStorage( aDownload );
+    
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+    }
+
+    
+// Destructor
+CHttpStorage::~CHttpStorage()
+    {
+    delete iLocalFilename;
+    delete iDestFilename;
+    delete iDdFilename;
+    
+    
+	if(iStorage)
+		{
+		delete iStorage;
+		iStorage = NULL;	
+		}
+    if( iFile )
+        {
+        iFile->Close();
+        delete iFile;
+        }
+        
+#ifdef __SYNCML_DM_FOTA        
+    if( iFotaEngine )
+        {
+        iFotaEngine->UpdatePackageDownloadComplete( iDownload->iFotaPckgId);
+        iFotaStream = NULL;
+        iFotaEngine->Close();
+        delete iFotaEngine; iFotaEngine = NULL;
+        }
+#endif // __SYNCML_DM_FOTA
+
+    CLOG_WRITE_1( "Storage destroy: (0x%x)", this );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::SetStorageMethod
+// 
+// iDownloadedSize comes from the destination file size.
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::SetStorageMethod( TStorageMethod aMethod )
+    {
+    iStorageMethod = aMethod;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::CheckContentFileIntegrityL
+// 
+// iDownloadedSize comes from the destination file size.
+// -----------------------------------------------------------------------------
+//
+TBool CHttpStorage::CheckContentFileIntegrityL()
+    {
+    LOGGER_ENTERFN( "CheckContentFileIntegrityL" );
+    TBool retVal = ETrue;
+
+    if( iDestFilename && iDestFilename->Length() )
+        {
+        if( iDriveId == GetDestinationDriveId() )
+            // this is not the same drive as where content file was
+            // previously saved
+            {
+            TEntry entry;
+            RFs& fs = iDownload->ClientApp()->Engine()->Fs();
+
+            if( fs.Entry( *iDestFilename, entry ) == KErrNone )
+                {
+                //Check if PD was on and if the file was being downloaded to MMC when last time we exited the session
+                //Use the Downloaded size as stored in info file 
+                //because when we exited from prev session
+                //size was not set back to downloaded size from total size
+                //
+                
+                if( !iProgressiveDownload && !iDownload->iNoMedia)
+                    {
+                    iDownloadedSize = entry.iSize;
+                    } 
+                else 
+                    {
+                    iFile = new (ELeave) RFile;
+                    TInt err = iFile->Open( fs , 
+                                          *iLocalFilename, 
+                                          EFileShareAny | 
+                                          EFileStream | 
+                                           EFileWrite );
+                    if( !err )
+                        {
+                        iFile->SetSize( iDownloadedSize );
+                        iProgressiveDownload = EFalse; 
+                        iFile->Close();
+                        delete iFile; iFile = NULL;       
+                        }
+                        iDownload->iNoMedia = EFalse;
+                    }                    
+
+                CLOG_WRITE_2( "Length: %d, size: %d", iLength, iDownloadedSize );
+
+                // if full size is unknown, we can't decide
+                // if the content file integrity is ok, or wrong.
+                // Let's assume that it is ok.
+                if( iLength != KDefaultContentLength )
+                    // Full size is known
+                    {
+                    if( !((iDownload->iDlState == EHttpDlMultipleMOCompleted &&
+                        (iDownload->iProgState == EHttpProgContentFileMoved || 
+                        iDownload->iProgState == EHttpProgContentFileMovedAndDestFNChanged ||
+                        iLength == iDownloadedSize)) ||
+                        (iDownload->iDlState != EHttpDlMultipleMOCompleted &&
+                        iLength > iDownloadedSize)) )
+                        {
+                        CLOG_WRITE8( "Wrong file size" );
+                        retVal = EFalse;
+                        }
+                    }
+                }
+            else
+                // Entry failed but we can still assume that there's no problem
+                {
+                CLOG_WRITE8( "Unknown size" );
+                }
+            }
+        else
+            {
+            CLOG_WRITE8_1( "Different drive: %d", iDriveId );
+            // MMC removed.
+            iDownload->MediaRemoved( (TUint)KErrNotFound, ETrue );
+            }
+        }
+    else
+        {
+        CLOG_WRITE( "No dest filename");
+         iDownload->iNoMedia = EFalse; 
+        }
+
+    return retVal;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::CreateDestinationFileL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::CreateDestinationFileL()
+    {
+    LOGGER_ENTERFN( "CreateDestinationFileL" );
+
+    TInt err( KErrNone );
+    
+    if( iStorageMethod == EStoreFota )
+        {
+#ifdef __SYNCML_DM_FOTA        
+        iFotaEngine = new (ELeave) RFotaEngineSession;
+        iFotaEngine->OpenL();
+        User::LeaveIfError( iFotaEngine->OpenUpdatePackageStore( iDownload->iFotaPckgId, 
+                                                                 iFotaStream ) );
+        
+        CLOG_WRITE( "FOTA -> no file" );
+#else   // __SYNCML_DM_FOTA
+        DMPanic( KErrNotSupported );
+#endif  // __SYNCML_DM_FOTA   
+        }
+    else
+        {
+        if( iRFileSetByClient )
+            {
+            CLOG_WRITE( "RFile is adopted from client" );
+            
+            TBuf<KMaxFileName> tempFileName; 
+            iFile->FullName(tempFileName);           
+            ReallocateStringL( iLocalFilename, tempFileName, KMaxPath );
+
+            TBuf8<KMaxContentTypeLength> contentType;
+            contentType.Copy( *iDownload->iDDType );
+
+            if( (0 == contentType.Compare( KCodMimeType() )) ||
+            	(0 == contentType.Compare( KDdMimeType() ))	 ||
+            	(0 == contentType.Compare( KDd2MimeType() )) ||
+            	(0 == contentType.Compare( KMultiPartMimeType() )) )
+            	{
+            	iDdFilename = iLocalFilename->Des().AllocL();
+            	}            
+            
+            
+            // check how many bytes are already persisted
+            iFile->Size( (TInt&)iDownloadedSize );
+
+            CLOG_WRITE_1( "iDownloadedSize: %d", iDownloadedSize );
+
+            return;
+            }
+
+        CLOG_WRITE8_1( "iDownloadedSize: %d", iDownloadedSize );
+            
+        __ASSERT_DEBUG( !iFile, DMPanic( KErrInUse) );
+
+        CreateDestinationFilenameL();
+
+        iFile = new (ELeave) RFile;
+
+        for( TInt i = 0; i < 2; ++i )
+            {
+            if( !iDownloadedSize )
+                // nothing persisted yet. If there's a file with the same name,
+                // delete it.
+                {
+                err = iFile->Replace( iDownload->ClientApp()->Engine()->Fs(), 
+                                       *iLocalFilename, 
+                                       EFileShareAny | 
+                                       EFileStream | 
+#ifdef BRDO_RFILE_WRITE_DIRECT_IO_FF
+                                       EFileWrite |
+                                       EFileWriteDirectIO );
+#else
+                                       EFileWrite );
+#endif
+                }
+            else
+                {
+                err = iFile->Open( iDownload->ClientApp()->Engine()->Fs(), 
+                                   *iLocalFilename, 
+                                   EFileShareAny | 
+                                   EFileStream | 
+#ifdef BRDO_RFILE_WRITE_DIRECT_IO_FF
+                                   EFileWrite |
+                                   EFileWriteDirectIO );
+#else
+                                   EFileWrite );
+#endif
+
+                if( !err )
+                    {
+                    // append new chunks to the file
+                    TInt pos( 0 );
+                    iFile->Seek( ESeekEnd, pos );
+                    }
+                }
+
+            if( err == KErrPathNotFound )
+                {
+                TPath folder;
+
+                folder.Copy( *iLocalFilename );
+
+                TInt slash = folder.LocateReverse( '\\' );
+                if( slash != KErrNotFound )
+                    {
+                    folder.SetLength( slash+1 );
+                    iDownload->ClientApp()->Engine()->Fs().MkDirAll( folder );
+                    }
+                }
+            else 
+                {
+                break;
+                }
+            }
+        }
+    CLOG_WRITE8_1( "CreateDestinationFileL: %d", err );
+
+    if( !err )
+        {
+        if( iFile && iLength != KDefaultContentLength && iProgressiveDownload )
+            {
+            iFile->SetSize( iLength );
+            }
+        }
+    else
+        {
+        iDownload->OnError( err, EDestFileInUse );
+        User::Leave( err );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::CloseDestinationFile
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::CloseDestinationFile( TFileCloseOperation aOperation )
+    {
+    LOGGER_ENTERFN( "CloseDestinationFile" );
+
+    CLOG_WRITE_2( "iFile: %x, iRFileSetByClient: %d", iFile, iRFileSetByClient );
+    if( iFile )
+        // RFile received from client is not close only in
+        // destructor, because there's no way to reopen it.
+        {
+        CLOG_WRITE( "HttpStorage: Writing final data and deallocating buffer" );
+        
+        // Make sure everything is written on the file
+        TRAP_IGNORE(iStorage->FlushBuffersL()); // Might be good to somehow relay error somewhere?
+       
+        if( iProgressiveDownload && iDownloadedSize >= 0 )
+                {
+                iFile->SetSize( iDownloadedSize );
+                }
+
+        
+        // Free up memory
+        iStorage->ResetBuffers();
+        iStorage->ClearErrors();
+
+        if( iDownload->iDlState == EHttpDlMultipleMOCompleted || !iRFileSetByClient )
+            // do not close file of a progressive download,
+            // only on complete.
+            {
+            iFile->Close();
+            delete iFile; iFile = NULL;
+            }
+        }
+
+#ifdef __SYNCML_DM_FOTA        
+    if( iFotaEngine )
+        {
+        iFotaEngine->UpdatePackageDownloadComplete( iDownload->iFotaPckgId);
+        iFotaStream = NULL;
+        iFotaEngine->Close();
+        delete iFotaEngine; iFotaEngine = NULL;
+        }
+#endif  // __SYNCML_DM_FOTA
+
+    if( iLocalFilename )
+        {
+        if( aOperation == EDeleteFile )
+            {
+            CLOG_WRITE_1( "Delete: %S", iLocalFilename );
+            iDownload->ClientApp()->Engine()->Fs().Delete( *iLocalFilename );
+            iDownloadedSize = 0;
+            }
+        else if( aOperation == EReplaceFile )
+            {
+            CLOG_WRITE_1( "Replace: %S", iLocalFilename );
+            RFile file;
+            file.Replace( iDownload->ClientApp()->Engine()->Fs(), *iLocalFilename, EFileWrite );
+            file.Close();
+            iDownloadedSize = 0;
+            }
+        }
+        
+    if( iDestFilename )
+        {
+        if( aOperation == EDeleteFile )
+            {
+            CLOG_WRITE_1( "Delete: %S", iDestFilename );
+            iDownload->ClientApp()->Engine()->Fs().Delete( *iDestFilename );
+            }
+        else if( aOperation == EReplaceFile )
+            {
+            CLOG_WRITE_1( "Replace: %S", iDestFilename );
+            RFile file;
+            file.Replace( iDownload->ClientApp()->Engine()->Fs(), *iDestFilename, EFileWrite );
+            file.Close();  
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::WriteOutNextBodyDataL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CHttpStorage::WriteOutNextBodyDataL( const TDesC8& aBuf )
+    {
+
+    return iStorage->WriteOutNextBodyDataL(aBuf);
+
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::OnComplete
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::OnComplete()
+    {
+    LOGGER_ENTERFN( "CHttpStorage::OnComplete()" );
+
+    // If destination filename is not set by client app
+    // here we have to update it with the local filename
+    if( !iDestFNameSet && 
+        !iRFileSetByClient && 
+        iStorageMethod != EStoreFota )
+        {
+        TRAP_IGNORE( 
+            ReallocateStringL( iDestFilename, *iLocalFilename, KMaxPath ) );
+        }
+
+    CloseDestinationFile( CHttpStorage::EKeepFile );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::ResetAndDestroy
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::ResetAndDestroy()
+    {
+    LOGGER_ENTERFN( "CHttpStorage::ResetAndDestroy()" );
+
+    if( iFile && iRFileSetByClient )
+        // do not delete or close this file, only set its size to 0.
+        {
+        iFile->SetSize( 0 );
+        }
+
+#ifdef __SYNCML_DM_FOTA
+    if( iFotaEngine )
+        {
+        iFotaEngine->UpdatePackageDownloadComplete( iDownload->iFotaPckgId);
+        iFotaStream = NULL;
+        iFotaEngine->Close();
+        delete iFotaEngine; iFotaEngine = NULL;
+        }
+#endif  // __SYNCML_DM_FOTA        
+
+    CloseDestinationFile( EReplaceFile );
+
+    iLength = KDefaultContentLength;
+    iDownloadedSize = 0;
+    iMoDownloadedSize = 0;
+
+    iDriveId = (TUint)KErrNotFound;
+
+    if( iLocalFilename )
+        {
+        iLocalFilename->Des().SetLength( 0 );
+        }
+
+    HBufC* destName = iDestFilename;
+    if( destName && destName->Length() && !iDestFNameSet )
+        {
+        destName->Des().SetLength( 0 );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::AdoptFileHandleL
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::AdoptFileHandleL( RFile* aFile )
+    {
+    LOGGER_ENTERFN( "AdoptFileHandleL" );
+    
+    __ASSERT_DEBUG( !iRFileSetByClient, DMPanic( KErrInUse ) );
+    __ASSERT_DEBUG( !iFile, DMPanic( KErrInUse ) );
+#ifdef __SYNCML_DM_FOTA
+    if( iRFileSetByClient || iFile || iFotaEngine )
+#else
+    if( iRFileSetByClient || iFile )
+#endif
+        {
+        CLOG_WRITE_2( "iRFileSetByClient: %d, iFile: %d", iRFileSetByClient, iFile );
+        User::Leave( KErrInUse );
+        }
+
+    // forget any previously set filename
+    delete iDestFilename; iDestFilename = NULL;
+    delete iLocalFilename; iLocalFilename = NULL;
+    iDestFNameSet = EFalse;
+    
+    iFile = aFile;
+    
+    // check how many bytes are already persisted
+    iFile->Size( (TInt&)iDownloadedSize );
+
+    CLOG_WRITE_1( "File size: %d", iDownloadedSize );
+    
+    iRFileSetByClient = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::SetProgressiveMode
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::SetProgressiveMode( TBool aValue )
+    {
+    iProgressiveDownload = aValue;
+    if( iProgressiveDownload )
+        {
+        iBufferSize = KDefaultStorageBufferSizePD;
+        }
+    EnableBufferingL();    
+      
+    if( iFile )
+        {
+        if( iProgressiveDownload )
+            {
+            if( iLength != KDefaultContentLength )    
+                {
+                iFile->SetSize( iLength );
+                }
+            }
+        else
+            {
+            iFile->SetSize( iDownloadedSize );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::CheckFreeDiskSpaceL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CHttpStorage::CheckFreeDiskSpaceL()
+    {
+    LOGGER_ENTERFN( "CheckFreeDiskSpaceL" );
+    TInt err( KErrNone );
+    CHttpDownloadManagerServerEngine *DMSrvEngine = iDownload->ClientApp()->Engine();
+    RFs& fs = DMSrvEngine->Fs();
+    TInt bytesToWrite(0);
+    
+    if( iLength == KDefaultContentLength || iLength == 0 )
+        // we don't know the size of the content -> no way to check that it can
+        // fit into memory
+        {
+#ifdef RD_MULTIPLE_DRIVE
+        TVolumeInfo volInfoCurrent;
+        TInt driveSpaceMax;
+        TInt driveSpaceCurrent;
+        TInt64 freeSpaceCurrent( 0 );
+        TInt64 freeSpaceMax( 0 );
+        TInt errDrvStat;
+
+        // initializing Drive variables to Default System drive/memory
+        User::LeaveIfError(
+            DriveInfo::GetDefaultDrive( DriveInfo::EDefaultPhoneMemory, driveSpaceMax ) );
+        driveSpaceCurrent = driveSpaceMax;
+
+        HBufC8* drivesDynList = iDownload->ClientApp()->Engine()->QueryDynDriveListLC();
+        TPtrC8 drives( *drivesDynList );
+
+        // drive letters are separated by semicolons
+        for( TInt i = 0; i < drives.Length(); i = i + 2 )
+            {
+            if( (err = fs.CharToDrive( drives[i], driveSpaceCurrent )) == KErrNone )
+                {
+                TUint status;
+                CLOG_WRITE_1( " Current Drive: %d", driveSpaceCurrent );
+                errDrvStat = DriveInfo::GetDriveStatus( fs, driveSpaceCurrent, status );
+                if ( errDrvStat == KErrNone )
+                    {
+                    if ( ( status & ( DriveInfo::EDriveUserVisible | DriveInfo::EDrivePresent ) ) )
+                        {
+                        CLOG_WRITE_1( "Drive %d is present and visible", driveSpaceCurrent);
+                        TInt errVol = fs.Volume( volInfoCurrent, driveSpaceCurrent );
+                        if (( errVol != KErrNone ) || ( volInfoCurrent.iDrive.iType <= EMediaUnknown)) 
+                            {
+                            CLOG_WRITE_1( " errVol: %d", errVol );
+                            CLOG_WRITE_1( " Current Drive driveSpaceCurrent: %d", driveSpaceCurrent );
+                            CLOG_WRITE_1( " volInfoCurrent.iDrive.iType: %d", volInfoCurrent.iDrive.iType );
+                            continue;
+                            }
+                        else
+                            {
+                            CLOG_WRITE_1( " errVol: %d", errVol );
+                            CLOG_WRITE_1( " Current Drive driveSpaceCurrent: %d", driveSpaceCurrent );
+                            CLOG_WRITE_1( " volInfoCurrent.iDrive.iType: %d", volInfoCurrent.iDrive.iType );
+                            CLOG_WRITE_1( "        volInfoCurrent.iFree: %Ld", volInfoCurrent.iFree );
+                            freeSpaceCurrent = volInfoCurrent.iFree;
+                            if ( freeSpaceCurrent > freeSpaceMax ) 
+                                {
+                                freeSpaceMax = freeSpaceCurrent;
+                                driveSpaceMax = driveSpaceCurrent;
+                                }
+                            }
+                        }
+                    }
+                else
+                    {
+                    CLOG_WRITE_1( "GetDriveStatus return error code: %d", errDrvStat);
+                    CLOG_WRITE_1( "Current Drive: %d", driveSpaceCurrent );
+                    }
+                }
+            else
+                {
+                CLOG_WRITE_1( "RFS::CharToDrive failed with %d", err );
+                CLOG_WRITE8_1( "Bad drive letter [%c]", drives[i] );
+                }            
+            }
+        CleanupStack::PopAndDestroy( drivesDynList );
+        CLOG_WRITE_2( "Saving content to %d Drive with %d B free space", driveSpaceMax, freeSpaceMax );
+        
+        TDriveInfo driveInfo;
+    
+    	if( !iDownload->ClientApp()->Engine()->Fs().Drive( driveInfo, driveSpaceMax) )
+        	{
+        	iRemovableDest = (driveInfo.iDriveAtt & KDriveAttRemovable);
+        	CLOG_WRITE_1( "Removable: [%d]", iRemovableDest );
+        	CLOG_WRITE_1( "driveInfo.iDriveAtt: [%d]", driveInfo.iDriveAtt );
+        	}
+    	else
+        	{
+        	CLOG_WRITE("DriveInfo failed");
+        	}
+        	
+        return driveSpaceMax;
+#else
+        // If no MMC is inserted, this will leave (and not set mmcOk).
+        bytesToWrite = iLength;
+        if (bytesToWrite < 0)
+            bytesToWrite = 0;
+        
+        TBool mmcOk = EFalse;
+        TRAP_IGNORE( mmcOk = !SysUtil::MMCSpaceBelowCriticalLevelL
+        			       ( &fs, bytesToWrite ); )
+        if(!mmcOk)
+        	{
+        	CLOG_WRITE( "no MMC present" );
+        	return EDriveC;
+        	}
+        CLOG_WRITE( "MMC is present " );        
+        TVolumeInfo volInfoC;
+        TVolumeInfo volInfoE;
+        fs.Volume(volInfoC,EDriveC);
+        fs.Volume(volInfoE,EDriveE);
+        TInt64 freeC = volInfoC.iFree;//free memory available in that drive
+        TInt64 freeE = volInfoE.iFree;
+        return  freeC>=freeE?EDriveC:EDriveE;//put the file in which ever drive has more memory
+#endif
+        }
+
+    // Destination is FFS in default
+#ifdef RD_MULTIPLE_DRIVE
+    TInt drive;
+    User::LeaveIfError(
+        DriveInfo::GetDefaultDrive( DriveInfo::EDefaultPhoneMemory, drive ) );
+#else
+    TInt drive( EDriveC );
+#endif
+
+	TBool isSpace( EFalse );
+	
+	//Get size of currently ongoing downloads
+	TInt currentDownloadsLen (0);
+	
+    if( iDestFilename && iDestFilename->Length() )
+        // client app gave the destination filename -> only that drive needs
+        // to be checked
+        {
+        CLOG_WRITE8( "cfds1" );
+        if( (err = fs.CharToDrive( (*iDestFilename)[0], drive )) != KErrNone )
+            {
+            CLOG_WRITE8( "Bad drive letter" );
+            iDownload->OnError( KErrUnknown, EWrongDestFilename );
+            User::Leave( err );
+            }
+        else if( !fs.IsValidDrive( drive ) )
+            // invalid drive letter in filename
+            {
+            CLOG_WRITE8( "Invalid drive" );
+            iDownload->OnError( KErrUnknown, EWrongDestFilename );
+            User::Leave( KErrBadName );
+            }
+        if( iPartialLength ==  KDefaultContentLength )
+            //This is the case when web Server returns Partial Content Length 
+            //Hence Disk Critical level should checked against partial Content Length
+            {
+            iPartialLength = iLength;
+            }
+            
+        currentDownloadsLen = DMSrvEngine->AllDownloadsSizeInDriveL(iDownload, drive);
+
+        // Check if there's enough memory in the phone
+        bytesToWrite = iPartialLength + currentDownloadsLen;
+        if (bytesToWrite < 0)
+            bytesToWrite = 0;
+        
+	    TRAP( err, isSpace = !SysUtil::DiskSpaceBelowCriticalLevelL(
+                                                &iDownload->ClientApp()->Engine()->Fs(),
+			                                    bytesToWrite,
+                                                drive ));
+        }
+    else
+        {
+#ifdef RD_MULTIPLE_DRIVE
+        HBufC8* drivesDynList = iDownload->ClientApp()->Engine()->QueryDynDriveListLC();
+        TPtrC8 drives( *drivesDynList );
+#else
+        TPtrC drives( iDownload->ClientApp()->Engine()->iDriveLettersCenRep );
+#endif
+        
+        // drive letters are separated by semicolons
+        for( TInt i = 0; i < drives.Length() && (err || !isSpace); i = i + 2 )
+            {
+            if( (err = fs.CharToDrive( drives[i], drive )) == KErrNone )
+                {
+                currentDownloadsLen = DMSrvEngine->AllDownloadsSizeInDriveL(iDownload, drive);
+
+                // Check if there's enough memory in the phone
+                bytesToWrite = iLength + currentDownloadsLen;
+                if (bytesToWrite < 0)
+                    bytesToWrite = 0;
+                
+        	    TRAP( err, isSpace = !SysUtil::DiskSpaceBelowCriticalLevelL(
+                                                        &fs,
+        			                                    bytesToWrite,
+                                                        drive ));
+                }
+            else
+                {
+                CLOG_WRITE8_1( "Bad drive letter [%c]", drives[i] );
+                }            
+            }
+#ifdef RD_MULTIPLE_DRIVE
+        CleanupStack::PopAndDestroy( drivesDynList );
+#endif
+        }	
+
+    TDriveInfo driveInfo;
+    
+    if( !iDownload->ClientApp()->Engine()->Fs().Drive( driveInfo, drive) )
+        {
+        iRemovableDest = (driveInfo.iDriveAtt & KDriveAttRemovable);
+        CLOG_WRITE_1( "Removable: [%d]", iRemovableDest );
+        }
+    else
+        {
+        CLOG_WRITE("DriveInfo failed");
+        }
+
+    if( err || !isSpace )
+        {
+        CLOG_WRITE8( "OOD1" );
+        iDownload->OnError( KErrDiskFull, EDiskFull );
+        User::Leave( KErrDiskFull );
+        }
+
+    return drive;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::CreateDestinationFilenameL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::CreateDestinationFilenameL()
+    {
+    LOGGER_ENTERFN( "CreateDestinationFilenameL" );
+
+    TInt drive = CheckFreeDiskSpaceL();
+
+    if( iLocalFilename && iLocalFilename->Length() )
+        // Destination filename is already created, or set
+        // by client app -> nothing to do
+        {
+        CLOG_WRITE_1( "local: %S", iLocalFilename );
+        return;
+        }
+
+    if( iDestFNameSet )
+        // Use destination filename client app set
+        {
+        ReallocateStringL( iLocalFilename, *iDestFilename, KMaxPath );
+        }
+    else
+        {
+        TPath folder;
+
+        iDownload->ClientApp()->Engine()->DownloadContentFolder( iDownload->ClientApp(),
+                                                                 folder );
+
+        delete iLocalFilename; iLocalFilename = NULL;
+
+        TChar driveChar;
+
+        // this is surely works because we got the driver letter
+        // from the FS earlier
+        iDownload->ClientApp()->Engine()->Fs().DriveToChar( drive, driveChar );
+        // allocate filename buffer
+        TInt pathLen = folder.Length();
+        TInt dlNameLen = MIN( KDownloadNameMaxSize, iDownload->iDlName->Length() );
+        iLocalFilename = HBufC::NewL( pathLen + dlNameLen + KFileNameExtensionMaxSize );
+        TPtr locFilenamePtr = iLocalFilename->Des();
+        // copy path and name to buffer
+        locFilenamePtr.Copy( folder );
+        locFilenamePtr.Append( iDownload->iDlName->Left( dlNameLen ) );
+
+        // set drive letter
+        locFilenamePtr[0] = (TUint16)TUint(driveChar);
+
+        ReallocateStringL( iDestFilename, *iLocalFilename, KMaxPath );
+
+        UpdateExtensionL();
+
+		// Below code is to update the destination file path with new destination file name.
+		// Check if the iDlName and filename in iLocalFileName are same. If not update the 
+		// iLocalFilename and iDestFilename with iDlName. Note that iDlName has an unique file name.
+    	if( iLocalFilename->Des().Right( iDownload->iDlName->Length() ).CompareF( *iDownload->iDlName ) )
+        {
+        TInt slash = iLocalFilename->Des().LocateReverse( '/' );
+
+        if( slash == KErrNotFound )
+            {
+            slash = iLocalFilename->Des().LocateReverse( '\\' );
+            }
+           
+        if( slash != KErrNotFound )
+            {
+            TInt newDLNameLen = iDownload->iDlName->Length();
+            TInt newLength = slash + newDLNameLen + 1;
+            iLocalFilename = iLocalFilename->ReAllocL(newLength);
+            iLocalFilename->Des().SetLength( newLength );
+            iLocalFilename->Des().Replace( slash+1, newDLNameLen, iDownload->iDlName->Des() );            
+	        ReallocateStringL( iDestFilename, *iLocalFilename, KMaxPath );
+            }
+        }        
+        
+        }
+
+	TBuf8<KMaxContentTypeLength> contentType;
+	contentType.Copy( *iDownload->iDDType );
+	
+	if( (0 == contentType.Compare( KCodMimeType() )) ||
+		(0 == contentType.Compare( KDdMimeType() ))	 ||
+		(0 == contentType.Compare( KDd2MimeType() )) ||
+		(0 == contentType.Compare( KMultiPartMimeType() )) )
+		{
+		iDdFilename = iLocalFilename->Des().AllocL();
+		}
+
+    iDriveId = GetDestinationDriveId();
+    
+    TText badChar( 32 );
+    TBool isValid = iDownload->ClientApp()->Engine()->Fs().IsValidName( *iLocalFilename, badChar );
+    
+    CLOG_WRITE_1( "dest2: %S", iLocalFilename );
+    CLOG_WRITE_2( "Valid: %d - %c", isValid, badChar );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::GetDestinationDriveId
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TUint CHttpStorage::GetDestinationDriveId()
+    {
+    LOGGER_ENTERFN( "GetDestinationDriveId" );
+    TUint retVal( (TUint)KErrNotFound );
+
+    if( iDestFilename && iDestFilename->Length() )
+        {
+        TInt drive;
+        iDownload->ClientApp()->Engine()->Fs().CharToDrive( 
+                                                    (*iDestFilename)[0], drive );
+
+        TVolumeInfo info;
+
+        if( iDownload->ClientApp()->Engine()->Fs().Volume( info, drive ) 
+                                                                == KErrNone )
+            {
+            CLOG_WRITE_1( "Dest drive id: %x", info.iUniqueID );
+
+            retVal = info.iUniqueID;
+            }
+        else
+            {
+            CLOG_WRITE( "Volume failed" );
+            retVal = (TUint)KErrNotFound;
+            }
+        }
+    CLOG_WRITE_1( " retVal: %d", retVal );
+    return retVal;
+    }
+    
+// -----------------------------------------------------------------------------
+// CHttpStorage::UpdateDestinationFilenameL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::UpdateDestinationFilenameL( const TDesC16& aFilename, TBool aUserSet )
+	{
+	LOGGER_ENTERFN( "UpdateDestinationFilenameL" );
+	CLOG_WRITE_2( "FN: [%S], userSet: %d", &aFilename, aUserSet );
+    TBufC<KMaxFileName> oldFileName;
+	if( iDestFilename )
+		{
+		oldFileName = *iDestFilename;
+		}
+    ReallocateStringL( iDestFilename, aFilename, KMaxPath );
+    iDestFNameSet = aUserSet;
+    if ( aFilename.Length() == 0 )
+        {
+        return;
+        }
+        
+    iDriveId = GetDestinationDriveId();
+    TInt drive;
+    if( !iDownload->ClientApp()->Engine()->Fs().CharToDrive((*iDestFilename)[0], drive) )
+        {
+        TDriveInfo driveInfo;
+        if( !iDownload->ClientApp()->Engine()->Fs().Drive( driveInfo, drive) )
+            {
+            iRemovableDest = (driveInfo.iDriveAtt & KDriveAttRemovable);
+            CLOG_WRITE_1( "Removable: [%d]", iRemovableDest );
+            }
+        else
+            {
+            CLOG_WRITE("DriveInfo failed");
+            }
+        }
+    else
+        {
+        CLOG_WRITE("CharToDrive failed");
+        }
+    
+	}
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::AppendStorageInfoL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::AppendStorageInfoL( TPtr8& aBuf ) const
+    {
+    AppendBufL( aBuf, iDestFilename );
+    APPEND_BUF_INT( aBuf, iDestFNameSet );
+    AppendBufL( aBuf, iLocalFilename );    
+    APPEND_BUF_INT( aBuf, iLength );
+    APPEND_BUF_INT( aBuf, iDriveId );
+    APPEND_BUF_INT( aBuf, iStorageMethod );
+    APPEND_BUF_INT( aBuf, iProgressiveDownload);
+    APPEND_BUF_INT( aBuf, iDownloadedSize);
+    AppendBufL( aBuf, iDdFilename );    
+    APPEND_BUF_INT( aBuf, iDownload->iMoLength );
+    APPEND_BUF_INT( aBuf, iRemovableDest );
+
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::SaveStorageInfoL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::LoadStorageInfoL( RFile& aInFile )
+    {
+    ReadHBufCL( aInFile, iDestFilename );
+    READ_INT_L( aInFile, iDestFNameSet );
+    ReadHBufCL( aInFile, iLocalFilename );    
+    READ_INT_L( aInFile, iLength );
+    READ_INT_L( aInFile, iDriveId );
+    READ_INT_L( aInFile, iStorageMethod );
+    READ_INT_L( aInFile, iProgressiveDownload);
+    READ_INT_L( aInFile, iDownloadedSize );
+    ReadHBufCL( aInFile, iDdFilename );
+    READ_INT_L( aInFile, iDownload->iMoLength  );
+    READ_INT_L( aInFile, iRemovableDest  );
+
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::UpdateExtensionL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::UpdateExtensionL()
+    {
+    LOGGER_ENTERFN( "UpdateExtensionL" );
+    
+    TPtr fileName( iDestFilename->Des() );
+    TBool toDelete;
+    const HBufC8* contentType = NULL;
+
+#ifdef DRM_EXTENSION_SPECIAL_CASE
+    // Check if we have the original DRM content-type    
+    const CArrayPtrFlat<CHeaderField>* resp = iDownload->ResponseHeaders();
+    
+    TInt index = iDownload->FindHeaderField( resp, KDRMOldContentType );
+    
+    if( index != KErrNotFound )
+        // Yes, we have it. Use the content-type set to this field.
+        {
+        CLOG_WRITE( "Old DRM content type" );
+        contentType = (*resp)[index]->FieldRawData();
+        }
+    else
+        {
+        contentType = iDownload->GetString8AttributeL( EDlAttrContentType, toDelete );
+        }
+#else
+    contentType = iDownload->GetString8AttributeL( EDlAttrContentType, toDelete );
+#endif        
+
+    CLOG_WRITE8_1( "Content-Type: [%S]", contentType );
+    
+    TDataType dataType( *contentType );
+    
+    iDownload->ClientApp()->Engine()->DocHandler()->CheckFileNameExtension( fileName, dataType );
+
+    ReallocateStringL( iLocalFilename, *iDestFilename, KMaxPath );
+    
+    CLOG_WRITE_1( "filename: [%S]", &fileName );
+    CLOG_WRITE_1( "DlName: [%S]", iDownload->iDlName );
+    
+    if( fileName.Right( iDownload->iDlName->Length() ).CompareF( *iDownload->iDlName ) )
+        {
+        CLOG_WRITE("Updating DlName");
+        TInt slash = fileName.LocateReverse( '/' );
+
+        if( slash == KErrNotFound )
+            {
+            slash = fileName.LocateReverse( '\\' );
+            }
+           
+        if( slash != KErrNotFound )
+            {
+            iDownload->SetDownloadNameL( fileName.Right(fileName.Length()-slash-1) );
+            }
+        else
+            {
+            iDownload->SetDownloadNameL( fileName );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::SetBufferSize
+// set size of disk buffer: after this - call EnableBuffering() or buffering
+// will be disabled.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::SetBufferSizeL( TInt aBufferSize )
+    {
+    DisableBufferingL();
+    iBufferSize = aBufferSize;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::EnableBuffering
+// turn on buffered writing of data to disk
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::EnableBufferingL()
+    {
+    // first check if buffer exists, and if it does, has iBufferSize
+    // been changed since buffering was last enabled
+    
+    CLOG_WRITE("CHttpStorage::EnableBufferingL >>");
+    
+    if( iBufferingEnabled && iBufferSize != iStorage->CurrentBufferSize())
+        {
+        FlushL();
+        }
+
+    iBufferingEnabled = ETrue;
+    
+    CLOG_WRITE("CHttpStorage::EnableBufferingL <<");
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::DisableBuffering
+// turn off buffered writing of data to disk
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::DisableBufferingL()
+    {
+    FlushL();
+    iBufferingEnabled = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::Flush
+// Flush internal buffer to disk
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::FlushL()
+    {
+    iStorage->FlushBuffersL();
+    iStorage->ResetBuffers();
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpStorage::SetLocalFilenameL
+// -----------------------------------------------------------------------------
+//
+void CHttpStorage::SetLocalFilenameL(const TDesC16& aValue)
+{
+    TBool isCodDownload;
+    iDownload->GetBoolAttributeL( EDlAttrCodDownload, isCodDownload );
+    // allow to set the local file name only for OMA downloads in case PDL
+	// In this case the MP/VP is responsible for file move. This app should set 
+	// dest and local file names before move.
+	if (isCodDownload && iProgressiveDownload)
+	{
+	  TRAP_IGNORE(ReallocateStringL( iLocalFilename, aValue, KMaxPath ));
+	}
+}
+    
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+//  End of File