diff -r 000000000000 -r dd21522fd290 browserutilities/downloadmgr/DownloadMgrServEng/Src/HttpStorage.cpp --- /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 +#include + +#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 +#include +#include + +#ifdef __SYNCML_DM_FOTA +#include +#endif + +#ifdef RD_MULTIPLE_DRIVE +#include +#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 tempFileName; + iFile->FullName(tempFileName); + ReallocateStringL( iLocalFilename, tempFileName, KMaxPath ); + + TBuf8 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 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 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* 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