smartinstaller/adm/src/ADMDownloadHandler.cpp
branchADM
changeset 48 364021cecc90
equal deleted inserted replaced
47:3f419852be07 48:364021cecc90
       
     1 /*
       
     2 * Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *     CDownloadHandler implementation
       
    16 *
       
    17 *
       
    18 */
       
    19 
       
    20 
       
    21 #include <aknappui.h>
       
    22 #include <COEUTILS.H>
       
    23 #include <wlanerrorcodes.h> //For download error handling
       
    24 #include <etelpckt.h>       //For download error handling
       
    25 #include <exterror.h>       //For download error handling
       
    26 #include <httpdownloadmgrcommon.h> // For download error handling (not in S60 5.0 SDK)
       
    27 
       
    28 #include "ADM.hrh"
       
    29 #include "ADMDownloadHandler.h"
       
    30 #include "ADMAppUi.h"
       
    31 #include "networkstatuslistener.h"
       
    32 
       
    33 #include "globals.h"
       
    34 #include "macros.h"
       
    35 /*
       
    36 #ifdef USE_LOGFILE
       
    37 #include "debug.h"
       
    38 #undef LOG
       
    39 #undef LOG2
       
    40 #undef LOG3
       
    41 #undef LOG4
       
    42 #undef LOG5
       
    43 #undef LOG6
       
    44 #undef LOG7
       
    45 #undef LOG8
       
    46 #undef LOG8_2
       
    47 
       
    48 #define LOG( aMsg ) { _LIT(KMsg, aMsg); iAppUi.iLog.Write( KMsg ); RDebug::Print( KMsg ); }
       
    49 #define LOG2( aMsg, aParam1 ) { _LIT(KMsg, aMsg); iAppUi.iLog.WriteFormat( KMsg, aParam1 ); RDebug::Print( KMsg, aParam1 ); }
       
    50 #define LOG3( aMsg, aParam1, aParam2 ) { _LIT(KMsg, aMsg); iAppUi.iLog.WriteFormat( KMsg, aParam1, aParam2 ); RDebug::Print( KMsg, aParam1, aParam2 ); }
       
    51 #define LOG4( aMsg, aParam1, aParam2, aParam3 ) { _LIT(KMsg, aMsg); iAppUi.iLog.WriteFormat( KMsg, aParam1, aParam2, aParam3 ); RDebug::Print( KMsg, aParam1, aParam2, aParam3 ); }
       
    52 #define LOG5( aMsg, aParam1, aParam2, aParam3, aParam4 ) { _LIT(KMsg, aMsg); iAppUi.iLog.WriteFormat( KMsg, aParam1, aParam2, aParam3, aParam4 ); RDebug::Print( KMsg, aParam1, aParam2, aParam3, aParam4 ); }
       
    53 #define LOG6( aMsg, aParam1, aParam2, aParam3, aParam4, aParam5 ) { _LIT(KMsg, aMsg); iAppUi.iLog.WriteFormat( KMsg, aParam1, aParam2, aParam3, aParam4, aParam5 ); RDebug::Print( KMsg, aParam1, aParam2, aParam3, aParam4, aParam5 ); }
       
    54 #define LOG7( aMsg, aParam1, aParam2, aParam3, aParam4, aParam5, aParam6 ) { _LIT(KMsg, aMsg); iAppUi.iLog.WriteFormat( KMsg, aParam1, aParam2, aParam3, aParam4, aParam5, aParam6 ); RDebug::Print( KMsg, aParam1, aParam2, aParam3, aParam4, aParam5, aParam6 ); }
       
    55 #define LOG8( aMsg, aParam1, aParam2, aParam3, aParam4, aParam5, aParam6, aParam7 ) { _LIT(KMsg, aMsg); iAppUi.iLog.WriteFormat( KMsg, aParam1, aParam2, aParam3, aParam4, aParam5, aParam6, aParam7 ); RDebug::Print( KMsg, aParam1, aParam2, aParam3, aParam4, aParam5, aParam6, aParam7 ); }
       
    56 #define LOG8_2( aMsg, aParam1 ) { _LIT8(KMsg, aMsg); iAppUi.iLog.WriteFormat( KMsg, aParam1 ); RDebug::Print(_L("RDebug _L8() at line %d"), __LINE__); }
       
    57 #endif
       
    58 */
       
    59 #ifdef USE_LOGFILE
       
    60 // Logging version
       
    61 // ---------------------------------------------------------------------------
       
    62 //
       
    63 // ---------------------------------------------------------------------------
       
    64 //
       
    65 CDownloadHandler* CDownloadHandler::NewL(MDownloadClient* aDlClient, RFileLogger& aLogger, const TBool aMasterInstance)
       
    66 	{
       
    67 	CDownloadHandler* object = new ( ELeave ) CDownloadHandler(aDlClient, aLogger, aMasterInstance);
       
    68 	CleanupStack::PushL( object );
       
    69 	object->ConstructL();
       
    70 	CleanupStack::Pop();
       
    71 	return object;
       
    72 	}
       
    73 
       
    74 // ---------------------------------------------------------------------------
       
    75 //
       
    76 // ---------------------------------------------------------------------------
       
    77 //
       
    78 CDownloadHandler::CDownloadHandler(MDownloadClient* aDlClient, RFileLogger& aLogger, const TBool aMasterInstance) :
       
    79 	iLog(aLogger),
       
    80 	iDlClient(aDlClient),
       
    81 	iMasterInstance(aMasterInstance),
       
    82 	iPtrToResponseBodyFileName(0,0)
       
    83 	{
       
    84 	}
       
    85 #else
       
    86 // ---------------------------------------------------------------------------
       
    87 //
       
    88 // ---------------------------------------------------------------------------
       
    89 //
       
    90 CDownloadHandler* CDownloadHandler::NewLC(MDownloadClient* aDlClient, const TBool aMasterInstance)
       
    91 	{
       
    92 	CDownloadHandler* object = new ( ELeave ) CDownloadHandler(aDlClient, aMasterInstance);
       
    93 	CleanupStack::PushL( object );
       
    94 	object->ConstructL();
       
    95 	return object;
       
    96 	}
       
    97 
       
    98 CDownloadHandler* CDownloadHandler::NewL(MDownloadClient* aDlClient, const TBool aMasterInstance)
       
    99 	{
       
   100 	CDownloadHandler* object = CDownloadHandler::NewLC(aDlClient, aMasterInstance);
       
   101 	CleanupStack::Pop();
       
   102 	return object;
       
   103 	}
       
   104 
       
   105 CDownloadHandler::CDownloadHandler(MDownloadClient* aDlClient, const TBool aMasterInstance) :
       
   106 	iDlClient(aDlClient),
       
   107 	iMasterInstance(aMasterInstance),
       
   108 	iPtrToResponseBodyFileName(0,0)
       
   109 	{
       
   110 	}
       
   111 #endif
       
   112 
       
   113 // ---------------------------------------------------------------------------
       
   114 // Default destructor
       
   115 // ---------------------------------------------------------------------------
       
   116 //
       
   117 CDownloadHandler::~CDownloadHandler()
       
   118 	{
       
   119 	DELETE_IF_NONNULL( iUrl );
       
   120 	DELETE_IF_NONNULL( iResponseBodyFileName );
       
   121 
       
   122 	delete iNetworkStatusListener;
       
   123 	iDownloadManager.DeleteAll();
       
   124 	iDownloadManager.Close();
       
   125 	}
       
   126 
       
   127 // ---------------------------------------------------------------------------
       
   128 //
       
   129 // ---------------------------------------------------------------------------
       
   130 //
       
   131 void CDownloadHandler::ConstructL()
       
   132 	{
       
   133 //	TBool masterInstance(!(iADMAppUiObj->EikonEnv()->StartedAsServerApp()));
       
   134 	const TUid uid = {_UID3};
       
   135 	iDownloadManager.ConnectL(uid , *this, iMasterInstance );
       
   136 	iNetworkStatusListener = CNetworkStatusListener::NewL( *this );
       
   137 	}
       
   138 
       
   139 // ---------------------------------------------------------------------------
       
   140 //
       
   141 // ---------------------------------------------------------------------------
       
   142 //
       
   143 void CDownloadHandler::SetIAP(TUint32 aIAP)
       
   144 	{
       
   145 	iIAP = aIAP;
       
   146 	if ( iIAP > 0)
       
   147 		{
       
   148 		LOG2( "CDownloadHandler::SetIap(): %d", aIAP );
       
   149 		// Set the download manager to silent mode
       
   150 		iDownloadManager.SetBoolAttribute( EDlMgrSilentMode, ETrue );
       
   151 		iDownloadManager.SetIntAttribute( EDlMgrIap, iIAP );
       
   152 		iNetworkStatusListener->SetIapIdToMonitor(iIAP);
       
   153 		}
       
   154 	}
       
   155 
       
   156 #ifdef USE_LOGFILE
       
   157 void CDownloadHandler::Log(TRefByValue<const TDesC16> aFmt, ...)
       
   158 	{
       
   159 	VA_LIST list;
       
   160 	VA_START(list, aFmt);
       
   161 	TBuf<0x100> buf;
       
   162 	buf.AppendFormatList(aFmt, list);
       
   163 	iLog.Write(buf);
       
   164 	}
       
   165 #endif
       
   166 
       
   167 // -----------------------------------------------------------------------------
       
   168 // Callback for CNetworkStatusObserver
       
   169 //
       
   170 // Called when the connection status changes
       
   171 // -----------------------------------------------------------------------------
       
   172 //
       
   173 void CDownloadHandler::HandleNetworkStatusChangedL(const TInt aStatus)
       
   174 	{
       
   175 	LOG2( "+ HandleNetworkStatusChangedL(): %d", aStatus );
       
   176 
       
   177 	// Did we lose the network connection?
       
   178 	if (aStatus == EConnMonStatusNotAvailable)
       
   179 		{
       
   180 		iNetworkLost = ETrue;
       
   181 		}
       
   182 
       
   183 	//LOG2( "- HandleNetworkStatusChangedL(): %d", iNetworkLost );
       
   184 	}
       
   185 
       
   186 // -----------------------------------------------------------------------------
       
   187 // Processes download errors and sets aDownloadError
       
   188 //
       
   189 // @param aGlErrId Global error ID from download manager.
       
   190 // @param aErrId Error ID from download manager.
       
   191 // @param aDownloadError Reference to the download error variable function is
       
   192 //      going to set in case of known error.
       
   193 // -----------------------------------------------------------------------------
       
   194 //
       
   195 TBool CDownloadHandler::ProcessDlErrors(const TInt32 aGlErrId, const TInt32 aErrId, EDownloadError& aDownloadError)
       
   196 	{
       
   197 	if (iFetchType && (aGlErrId || aErrId))
       
   198 		LOG4( "+ ProcessDlErrors(%d, %d, %d)", aGlErrId, aErrId, aDownloadError );
       
   199 	TBool requestRestart = EFalse;
       
   200 	// Process the error codes
       
   201 	switch (aErrId)
       
   202 		{
       
   203 		case KErrNone:
       
   204 			// everything a-OK!
       
   205 			break;
       
   206 		case EConnectionFailed:
       
   207 			aDownloadError = EDlErrDownloadFailure;
       
   208 			break;
       
   209 		case ETransactionFailed:
       
   210 			// We set the download error to network failure as that's the
       
   211 			// error propagated to TState::DownloadFailed().
       
   212 			// The state machine will try to restart the download, if the
       
   213 			// error code is EDlErrDownloadFailure, but NOT for EDlErrNetworkFailure.
       
   214 			aDownloadError = EDlErrDownloadFailure;
       
   215 			requestRestart = ETrue;
       
   216 			break;
       
   217 		case EObjectNotFound:
       
   218 			aDownloadError = EDlErrFileNotFound;
       
   219 			break;
       
   220 		default:
       
   221 			LOG2( "Unhandled ErrId %d", aErrId );
       
   222 			aDownloadError = EDlErrDownloadFailure;
       
   223 			break;
       
   224 		}
       
   225 	// Process the global error code
       
   226 	switch (aGlErrId)
       
   227 		{
       
   228 		case KErrNone:
       
   229 			// everything a-OK!
       
   230 			break;
       
   231 		case KErrCancel:
       
   232 		case KErrAbort:
       
   233 			// The user has cancelled the download / IAP selection box
       
   234 			aDownloadError = EDlErrCancelled;
       
   235 			break;
       
   236 		case KErrDiskFull:
       
   237 			// Disk full
       
   238 			aDownloadError = EDlErrNotEnoughSpace;
       
   239 			break;
       
   240 		case KErrUnknown:
       
   241 			// act on KErrUnknown only, if error ID is not set
       
   242 			if (aErrId == KErrNone)
       
   243 				{
       
   244 				aDownloadError = EDlErrDownloadFailure;
       
   245 				requestRestart = ETrue;
       
   246 				}
       
   247 			break;
       
   248 		case KErrNotFound:
       
   249 		case KErrBadName:
       
   250 		case KErrNotSupported:
       
   251 		case KErrCommsLineFail:
       
   252 		case KErrTimedOut:
       
   253 		case KErrCouldNotConnect:
       
   254 		case KErrDisconnected:
       
   255 		case KErrGprsServicesNotAllowed:
       
   256 		case KErrGsmMMNetworkFailure:
       
   257 		// WLAN network related errors:
       
   258 		case KErrWlanNetworkNotFound:
       
   259 		case KErrWlanRoamingFailed:
       
   260 		case KErrWlanNetworkLost:
       
   261 #if 0
       
   262 		case KErrBadName:
       
   263 		case KErrNotSupported:
       
   264 		case KErrWlanOpenAuthFailed:
       
   265 		case KErrWlanSharedKeyAuthRequired:
       
   266 		case KErrWlanSharedKeyAuthFailed:
       
   267 		case KErrWlanWpaAuthRequired:
       
   268 		case KErrWlanIllegalEncryptionKeys:
       
   269 		case KErrWlanPskModeRequired:
       
   270 		case KErrWlanEapModeRequired:
       
   271 		case KErrWlanSimNotInstalled:
       
   272 		case KErrWlanNotSubscribed:
       
   273 		case KErrWlanAccessBarred:
       
   274 		case KErrWlanPasswordExpired:
       
   275 		case KErrWlanNoDialinPermissions:
       
   276 		case KErrWlanAccountDisabled:
       
   277 		case KErrWlanRestrictedLogonHours:
       
   278 		case KErrWlanServerCertificateExpired:
       
   279 		case KErrWlanCerficateVerifyFailed:
       
   280 		case KErrWlanNoUserCertificate:
       
   281 		case KErrWlanNoCipherSuite:
       
   282 		case KErrWlanUserRejected:
       
   283 		case KErrWlanUserCertificateExpired:
       
   284 		// less fatal, but still needs to fail the download:
       
   285 		case KErrWlanWpaAuthFailed:
       
   286 		case KErrWlan802dot1xAuthFailed:
       
   287 		case KErrWlanIllegalWpaPskKey:
       
   288 		case KErrWlanEapSimFailed:
       
   289 		case KErrWlanEapTlsFailed:
       
   290 		case KErrWlanEapPeapFailed:
       
   291 		case KErrWlanEapMsChapv2:
       
   292 		case KErrWlanEapAkaFailed:
       
   293 		case KErrWlanEapTtlsFailed:
       
   294 		case KErrWlanLeapFailed:
       
   295 		case KErrWlanEapGtcFailed:
       
   296 #endif
       
   297 			// A fatal network error has occured, don't retry the download
       
   298 			requestRestart = EFalse;
       
   299 			aDownloadError = EDlErrNetworkFailure;
       
   300 			break;
       
   301 		default:
       
   302 			if (!requestRestart)
       
   303 				{
       
   304 				// We assume all the other error codes to be 'hard' network errors
       
   305 				LOG2( "Unhandled GlErrId %d", aGlErrId );
       
   306 				aDownloadError = EDlErrNetworkFailure;
       
   307 				}
       
   308 			break;
       
   309 		}
       
   310 	if (iFetchType && aDownloadError != ENoError)
       
   311 		LOG3( "- ProcessDlErrors(): %d, %d", requestRestart, aDownloadError );
       
   312 	return requestRestart;
       
   313 	}
       
   314 
       
   315 // ---------------------------------------------------------------------------
       
   316 //
       
   317 // ---------------------------------------------------------------------------
       
   318 //
       
   319 void CDownloadHandler::HandleDMgrEventL( RHttpDownload& aDownload, THttpDownloadEvent aEvent )
       
   320 	{
       
   321 	TInt32 glErrId = KErrNone;
       
   322 	TInt32 errId = ENoError;
       
   323 
       
   324 	// Get error IDs
       
   325 	aDownload.GetIntAttribute( EDlAttrGlobalErrorId, glErrId );
       
   326 	aDownload.GetIntAttribute( EDlAttrErrorId, errId );
       
   327 
       
   328 #ifdef DO_LOG
       
   329 	if (iFetchType)
       
   330 		{
       
   331 		_LIT(KFmt, ", GlErrId=%6d, ErrId=%d");
       
   332 		TBuf<64> buf;
       
   333 
       
   334 		if ( ((glErrId != KErrNone) || (errId != ENoError)) && glErrId != KErrUnknown )
       
   335 			{
       
   336 			buf.AppendFormat(KFmt, glErrId, errId);
       
   337 			}
       
   338 
       
   339 		if ( ( iDownloadState != aEvent.iDownloadState ) ||
       
   340 			 ( iProgressState != aEvent.iProgressState ) )
       
   341 			{
       
   342 			iDownloadState = aEvent.iDownloadState;
       
   343 			iProgressState = aEvent.iProgressState;
       
   344 
       
   345 			LOG5( "DlSt=%5d, PrSt=%5d, L=%d%S", iDownloadState, iProgressState, iNetworkLost, &buf );
       
   346 			}
       
   347 		}
       
   348 #endif
       
   349 
       
   350 	if (iNetworkLost && !iCancelled)
       
   351 		{
       
   352 		TBuf<KMaxPath> fn;
       
   353 		aDownload.GetStringAttribute( EDlAttrDestFilename, fn );
       
   354 		iDownloadError = EDlErrNetworkFailure;
       
   355 		LOG2( "Connection lost! Cancelling '%S' download.", &fn );
       
   356 		DoHandleHttpFetchFailure(fn, glErrId, errId);
       
   357 		return;
       
   358 		}
       
   359 
       
   360 	switch ( aEvent.iDownloadState )
       
   361 		{
       
   362 		case EHttpDlCreated:
       
   363 			{
       
   364 			break;
       
   365 			}
       
   366 		case EHttpDlInprogress:
       
   367 			{
       
   368 			// Already downloaded content size
       
   369 			TInt32 downloadedSize( 0 );
       
   370 			// Total download size
       
   371 			TInt32 dlLength( 0 );
       
   372 
       
   373 			if ( aEvent.iProgressState == EHttpProgConnected )
       
   374 				{
       
   375 				TInt32 iap;
       
   376 				// Get the selected IAP (ignore any errors from Get())
       
   377 				iDownloadManager.GetIntAttribute( EDlMgrIap, iap );
       
   378 				if (iIAP != iap)
       
   379 					{
       
   380 					LOG2( "* Using IAP %d", iap );
       
   381 					iIAP = iap;
       
   382 					iDlClient->HandleIapChanged(iIAP);
       
   383 					}
       
   384 				}
       
   385 
       
   386 			aDownload.GetIntAttribute( EDlAttrDownloadedSize, downloadedSize );
       
   387 			aDownload.GetIntAttribute( EDlAttrLength, dlLength );
       
   388 
       
   389 			UpdateDownloadSpeed(downloadedSize);
       
   390 
       
   391 			iDlClient->HandleHttpFetchInProgress( downloadedSize, dlLength, iDlAvgSpeed );
       
   392 			break;
       
   393 			}
       
   394 		case EHttpDlPaused:
       
   395 		case EHttpDlFailed:
       
   396 // These two fill fold to EHttpDlFailed. We don't want to process failure events twice.
       
   397 //		case EHttpDlNonPausableNetworkLoss:
       
   398 //		case EHttpDlMultipleMOFailed:
       
   399 			{
       
   400 			TBuf<KMaxPath> buf;
       
   401 
       
   402 			aDownload.GetStringAttribute( EDlAttrDestFilename, buf );
       
   403 
       
   404 			// We just monitor the progress state and start download, when
       
   405 			// content-type is received. Any errors are ignored in this state.
       
   406 			if (
       
   407 				// we have to check error codes in EHttpProgNone state, otherwise
       
   408 				// we'll end up infinite loop, for instance, in AP selection cancellation
       
   409 				 ( aEvent.iProgressState == EHttpContentTypeReceived ) ||
       
   410 				 ( ( aEvent.iProgressState == EHttpProgNone ) && ( errId == ENoError) ) )
       
   411 				{
       
   412 				// TODO: Should we check glErrId and do Reset() before starting download?
       
   413 				// need to start the download if not already started
       
   414 				LOG( "Starting download" );
       
   415 				aDownload.Start();
       
   416 				// Start timing the download
       
   417 				iDlStartTime.UniversalTime();
       
   418 				// ignore any errors, so we can start the download
       
   419 				break;
       
   420 				}
       
   421 			if ( ProcessDlErrors(glErrId, errId, iDownloadError) )
       
   422 				{
       
   423 				if (++iConnectionAttempt < KDownloadConnectionRetries)
       
   424 					{
       
   425 					LOG4( "Restarting download due to network failure (%d: %d, %d)", iConnectionAttempt, glErrId, errId );
       
   426 					// TODO: Do we need to do a Reset() before Start()?
       
   427 					aDownload.Start();
       
   428 					// We don't restart the download timer on purpose
       
   429 					//
       
   430 					// Clear the error id so it doesn't get caught below
       
   431 					// as this is not an error situation.
       
   432 					iDownloadError = EDlErrNoError;
       
   433 					}
       
   434 				else
       
   435 					{
       
   436 					LOG4( "Too many retries, cancelling download (%d; %d, %d)", iDownloadError, glErrId, errId );
       
   437 					// iDownloadError has been set properly by ProcessDlErrors()
       
   438 					}
       
   439 				}
       
   440 			if ( iDownloadError != KErrNone )
       
   441 				{
       
   442 				if (iFetchType)
       
   443 					LOG2( "DlErr=%d", iDownloadError );
       
   444 				// Inform about it
       
   445 				DoHandleHttpFetchFailure(buf, glErrId, errId);
       
   446 				// TODO: Just in case: don't delete the download in HandleDMgrEventL
       
   447 				// That seems to cause problems on different devices.
       
   448 				// Download failed, delete it
       
   449 				// aDownload.Delete();
       
   450 				}
       
   451 			break;
       
   452 			}
       
   453 		case EHttpDlCompleted:
       
   454 			{
       
   455 			TBuf<KMaxPath> buf;
       
   456 			// Download Manager total Length of the download
       
   457 			TInt32 dlLength( 0 );
       
   458 			aDownload.GetIntAttribute( EDlAttrLength, dlLength );
       
   459 			aDownload.GetStringAttribute( EDlAttrDestFilename, buf );
       
   460 			const TInt64 dlTime = UpdateDownloadSpeed(dlLength);
       
   461 			iDlClient->HandleHttpFetchCompleted(buf, iFetchType, dlLength, iDlAvgSpeed, dlTime);
       
   462 			break;
       
   463 			}
       
   464 		case EHttpDlDeleting:
       
   465 			// Signal that we're deleting the download
       
   466 			iDlClient->HandleDownloadDeleting();
       
   467 			break;
       
   468 		default:
       
   469 			{
       
   470 			break;
       
   471 			}
       
   472 		} // switch
       
   473 	}
       
   474 
       
   475 // -----------------------------------------------------------------------------
       
   476 // Updates the average download speed counter
       
   477 // @param aBytesDownloaded Bytes downloaded during this download
       
   478 // @returns Time in microseconds spend in this download
       
   479 // -----------------------------------------------------------------------------
       
   480 //
       
   481 TInt64 CDownloadHandler::UpdateDownloadSpeed(const TInt32 aBytesDownloaded)
       
   482 	{
       
   483 	TInt64 fromDlStart = 0;
       
   484 	if (aBytesDownloaded > 0)
       
   485 		{
       
   486 		TTime time;
       
   487 		time.UniversalTime();
       
   488 
       
   489 		fromDlStart = time.MicroSecondsFrom(iDlStartTime).Int64();
       
   490 
       
   491 		// Use ifs to avoid divide-by-zero
       
   492 		if (fromDlStart > 0)
       
   493 			{
       
   494 			iDlAvgSpeed = aBytesDownloaded*1000000.0 / fromDlStart;
       
   495 			}
       
   496 		}
       
   497 	return fromDlStart;
       
   498 	}
       
   499 
       
   500 // -----------------------------------------------------------------------------
       
   501 //
       
   502 // -----------------------------------------------------------------------------
       
   503 //
       
   504 void CDownloadHandler::CancelAllDownloads()
       
   505 	{
       
   506 	// Remove all downloads
       
   507 	iDownloadManager.DeleteAll();
       
   508 	}
       
   509 
       
   510 // -----------------------------------------------------------------------------
       
   511 // Handles client callback when download fails
       
   512 // -----------------------------------------------------------------------------
       
   513 //
       
   514 void CDownloadHandler::DoHandleHttpFetchFailure(const TDesC& aDlFilename, const TInt aGlobalErrorId, const TInt aErrorId)
       
   515 	{
       
   516 	if (!iCancelled)
       
   517 		{
       
   518 		iDlClient->HandleHttpFetchFailure(aDlFilename, aGlobalErrorId, aErrorId, iFetchType);
       
   519 		iCancelled = ETrue;
       
   520 		}
       
   521 	else
       
   522 		{
       
   523 		LOG( "DoHandleHttpFetchFailure(): Called, but already cancelled" );
       
   524 		}
       
   525 	}
       
   526 
       
   527 // -----------------------------------------------------------------------------
       
   528 //
       
   529 // -----------------------------------------------------------------------------
       
   530 //
       
   531 void CDownloadHandler::StartDownloadL(const TDesC8& aDepUrl, const TDesC& aFileName,
       
   532 								const TDesC& aDownloadPath, const TInt aFetchType)
       
   533 	{
       
   534 	__ASSERT_ALWAYS( (aDepUrl.Length() > 0) && (aFileName.Length() > 0) && (aDownloadPath.Length() > 0), User::Leave( KErrArgument) );
       
   535 
       
   536 	// Cleanup is required in case the API is called
       
   537 	// multiple times.
       
   538 	DELETE_IF_NONNULL( iUrl );
       
   539 	DELETE_IF_NONNULL( iResponseBodyFileName );
       
   540 
       
   541 	// Set the full Url after appending the filename. +1 for '/'
       
   542 	iUrl = HBufC8::NewL( aDepUrl.Length() + aFileName.Length() + 1 );
       
   543 	TPtr8 ptr(iUrl->Des());
       
   544 	ptr.Copy(aDepUrl);
       
   545 	// Append forward slash if that's missing
       
   546 	if (ptr.Right(1)[0] != '/')
       
   547 		ptr.Append('/');
       
   548 
       
   549 	ptr.Append(aFileName);
       
   550 
       
   551 	iDownloadError = EDlErrNoError;
       
   552 	iCancelled = EFalse;
       
   553 	iConnectionAttempt = 0;
       
   554 
       
   555 	// Create a new download
       
   556 	TBool retried = EFalse;
       
   557 	TBool isNewDl = ETrue;
       
   558 	iPtrToUrl.Set(*iUrl);
       
   559 
       
   560 	// Set the full response body file name
       
   561 	// based on the actual filename to be downloaded.
       
   562 	iResponseBodyFileName = HBufC::NewL(aDownloadPath.Length()+ aFileName.Length());
       
   563 	iPtrToResponseBodyFileName.Set(iResponseBodyFileName->Des());
       
   564 	iPtrToResponseBodyFileName.Copy(aDownloadPath);
       
   565 	iPtrToResponseBodyFileName.Append(aFileName);
       
   566 
       
   567 	ConeUtils::EnsurePathExistsL(iPtrToResponseBodyFileName);
       
   568 
       
   569 	TBuf<KMaxFileName> buf;
       
   570 	buf.Copy(ptr);
       
   571 retry:
       
   572 	if (aFetchType)
       
   573 		{
       
   574 		LOG2( "+ StartDownload(): '%S'", &buf );
       
   575 		LOG2( "  to '%S'", &iPtrToResponseBodyFileName );
       
   576 		}
       
   577 
       
   578 	RHttpDownload& dl = iDownloadManager.CreateDownloadL( iPtrToUrl, isNewDl );
       
   579 
       
   580 	if (isNewDl)
       
   581 		{
       
   582 		// Start download
       
   583 		dl.SetStringAttribute( EDlAttrDestFilename, iPtrToResponseBodyFileName );
       
   584 		User::LeaveIfError( dl.Start() );
       
   585 		// This timer will be reset, when content-type is received, but if it's not
       
   586 		// we need to have a sane starting time, otherwise dl avg speed calculation
       
   587 		// does not work properly.
       
   588 		iDlStartTime.UniversalTime();
       
   589 		iFetchType = aFetchType;
       
   590 		iDlAvgSpeed = 0.0;
       
   591 		}
       
   592 	else
       
   593 		{
       
   594 		LOG( "Download exists, deleting all" );
       
   595 		// Remove any downloads
       
   596 		iDownloadManager.DeleteAll();
       
   597 		if (!retried)
       
   598 			{
       
   599 			LOG( "Download exists, retrying.." );
       
   600 			retried = ETrue;
       
   601 			// we leave isNewDl set to ETrue, so we would accept any existing download for the same URL
       
   602 			goto retry;
       
   603 			}
       
   604 		LOG( "Download exists, retry failed. Panic!" );
       
   605 		User::Leave( KErrAlreadyExists );
       
   606 		}
       
   607 	}
       
   608 // EOF