emailuis/emailui/src/FreestyleEmailDownloadInformationMediator.cpp
changeset 0 8466d47a6819
child 1 12c456ceeff2
equal deleted inserted replaced
-1:000000000000 0:8466d47a6819
       
     1 /*
       
     2 * Copyright (c) 2005 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:  Freestyle Email application attachment download info mediator
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 //  INCLUDE FILES
       
    20 #include "emailtrace.h"
       
    21 #include <e32svr.h>
       
    22 //<cmail>
       
    23 #include "CFSMailClient.h"
       
    24 //</cmail>
       
    25 #include <StringLoader.h>
       
    26 #include <FreestyleEmailUi.rsg>
       
    27 
       
    28 #include "FreestyleEmailUiConstants.h"
       
    29 #include "FreestyleEmailUiLiterals.h"
       
    30 #include "FreestyleEmailUiUtilities.h"
       
    31 #include "FreestyleEmailDownloadInformationMediator.h"
       
    32 #include "FreestyleEmailCenRepHandler.h"
       
    33 #include "FreestyleEmailUiAppui.h"
       
    34 #include "FSEmail.pan"
       
    35 
       
    36 
       
    37 // ============================ MEMBER FUNCTIONS ===============================
       
    38 
       
    39 // ----------------------------------------------------
       
    40 // CFSEmailDownloadInfoMediator::CFSEmailDownloadInfoMediator
       
    41 
       
    42 // Default class constructor.
       
    43 // ----------------------------------------------------
       
    44 //
       
    45 CFSEmailDownloadInfoMediator::CFSEmailDownloadInfoMediator( CFSMailClient& aMailClient )
       
    46     : CActive( EPriorityNormal ), iMailClient(aMailClient),
       
    47     iDownloadArray( KArrayGranularity, _FOFF(TDownload, iRequestId) ), iDownloadsStarted ( EFalse )
       
    48 	{
       
    49     FUNC_LOG;
       
    50 	CActiveScheduler::Add( this );
       
    51 	}
       
    52 
       
    53 // ----------------------------------------------------
       
    54 // CFSEmailDownloadInfoMediator::ConstructL
       
    55 // Second phase class constructor.
       
    56 // ----------------------------------------------------
       
    57 //
       
    58 void CFSEmailDownloadInfoMediator::ConstructL()
       
    59 	{
       
    60     FUNC_LOG;
       
    61 	}
       
    62 
       
    63 // ----------------------------------------------------
       
    64 // CFSEmailDownloadInfoMediator::NewL
       
    65 // Two-phased class constructor.
       
    66 // Singleton
       
    67 // ----------------------------------------------------
       
    68 //
       
    69 CFSEmailDownloadInfoMediator* CFSEmailDownloadInfoMediator::NewL( CFSMailClient& aMailClient )
       
    70 	{
       
    71     FUNC_LOG;
       
    72 
       
    73 	CFSEmailDownloadInfoMediator* singleton = NULL;
       
    74 
       
    75 	// Check Thread Local Storage for instance pointer
       
    76 	singleton = static_cast<CFSEmailDownloadInfoMediator*>( UserSvr::DllTls( KTlsHandleDownloadInfo ) );
       
    77 	if ( !singleton )
       
    78 		{
       
    79 		singleton = new ( ELeave ) CFSEmailDownloadInfoMediator( aMailClient );
       
    80 		CleanupStack::PushL( singleton );
       
    81 		singleton->ConstructL();
       
    82 		CleanupStack::Pop( singleton );
       
    83 		
       
    84 		// Store a pointer of a new instance in Thread Local Storage
       
    85 		TInt err = UserSvr::DllSetTls( KTlsHandleDownloadInfo, singleton );
       
    86 		if ( err )
       
    87 			{
       
    88 			delete singleton;
       
    89 			singleton = NULL;
       
    90 			User::Leave( err );
       
    91 			}
       
    92 		}
       
    93 
       
    94 	return singleton;
       
    95 	}
       
    96 
       
    97 
       
    98 void CFSEmailDownloadInfoMediator::AddObserver( MFSEmailDownloadInformationObserver* aObserver, TFSMailMsgId aMessageId )
       
    99 	{
       
   100     FUNC_LOG;
       
   101 	TRequestObserver newObserver = {aObserver, aMessageId };
       
   102 	iObserverArray.Append( newObserver );
       
   103 	}
       
   104 
       
   105 void CFSEmailDownloadInfoMediator::AddObserver( MFSEmailDownloadInformationObserver* aObserver )
       
   106 	{
       
   107 	iAllObserverArray.Append(aObserver);
       
   108 	}
       
   109 
       
   110 // ----------------------------------------------------
       
   111 // CFSEmailDownloadInfoMediator::~CFSEmailDownloadInfoMediator
       
   112 // Destructor of CFSEmailDownloadInfoMediator class.
       
   113 // ----------------------------------------------------
       
   114 //
       
   115 CFSEmailDownloadInfoMediator::~CFSEmailDownloadInfoMediator()
       
   116 	{
       
   117 	FUNC_LOG;
       
   118 	iAllObserverArray.Close();
       
   119 	iObserverArray.Close();
       
   120 	iDownloadArray.Close();
       
   121 	iDownloadCountArray.Close();
       
   122 	Cancel();
       
   123     }
       
   124 
       
   125 
       
   126 void CFSEmailDownloadInfoMediator::RequestResponseL(
       
   127 	TFSProgress aEvent, TInt aRequestId )
       
   128 	{
       
   129 	FUNC_LOG;
       
   130 	// Find the correct download structure
       
   131 	TDownload download( aRequestId, TPartData(), KNullDesC(), EFalse );
       
   132 	TInt idx = iDownloadArray.Find( download );
       
   133 	
       
   134     if ( idx >= 0 && idx < iDownloadArray.Count() )
       
   135     	{
       
   136     	// save the progress info from status events
       
   137     	if ( aEvent.iProgressStatus == TFSProgress::EFSStatus_Status )
       
   138     	    {
       
   139         	iDownloadArray[idx].iCounter = aEvent.iCounter;
       
   140         	iDownloadArray[idx].iMaxCount = aEvent.iMaxCount;
       
   141     	    }
       
   142     	
       
   143 		// Make a local copy of the download object as the object may be
       
   144 		// removed from the array before we are finished
       
   145 		download = iDownloadArray[idx];
       
   146         
       
   147     	// In case of error, show a note
       
   148 		if ( aEvent.iError && aEvent.iError != KErrCancel )
       
   149 		    {
       
   150 			// Download failed, show error note
       
   151 			if ( aEvent.iError == KErrCouldNotConnect ||
       
   152 				 aEvent.iError == KErrConnectionTerminated )
       
   153 			    { // connection error
       
   154 			    TFsEmailUiUtility::ShowErrorNoteL(
       
   155 			    	R_FREESTYLE_EMAIL_ERROR_GENERAL_CONNECTION_ERROR,
       
   156 			    	ETrue );
       
   157 			    }
       
   158 			else // other error
       
   159 			    {
       
   160 			    TFsEmailUiUtility::ShowErrorNoteL(
       
   161 			    	R_FREESTYLE_EMAIL_ERROR_GENERAL_UNABLE_TO_COMPLETE,
       
   162 			    	ETrue );
       
   163 			    }
       
   164 		    }
       
   165 		    
       
   166 		// Remove download from array if it has been cancelled or failed
       
   167 		if ( aEvent.iProgressStatus ==
       
   168 			 TFSProgress::EFSStatus_RequestCancelled || aEvent.iError )
       
   169 			{
       
   170 			iDownloadArray.Remove(idx);
       
   171 			}
       
   172 		// Mark download as completed if download just finished
       
   173 		else if ( aEvent.iProgressStatus ==
       
   174 				  TFSProgress::EFSStatus_RequestComplete )
       
   175 		    {
       
   176 		    if ( !iDownloadArray[idx].iMaxCount )
       
   177 		        {
       
   178 		        // Set max count to 1 if no single progress event has arrived
       
   179 		        // before download is finished.
       
   180 		        iDownloadArray[idx].iMaxCount = 1;
       
   181 		        }
       
   182 		    iDownloadArray[idx].iCounter = iDownloadArray[idx].iMaxCount;
       
   183 		    }
       
   184 		
       
   185 		TInt completedDownloadsToNotify = 0;        
       
   186 
       
   187 		// Find and update the count array entry
       
   188         TDownloadCount countObject( download.iPartData.iMessageId );
       
   189         GetAndUpdateDownloadCountL( countObject, aEvent );
       
   190 
       
   191 		// Notification may be given if all ongoing downloads from message
       
   192 		// have finished and there are some properly completed downloads
       
   193         if ( download.iNotifyComplete &&
       
   194              countObject.iDownloadsCompletedCount &&
       
   195              countObject.iDownloadsCompletedCount ==
       
   196              	countObject.iDownloadsStartedCount )
       
   197             {
       
   198 			completedDownloadsToNotify = countObject.iDownloadsCompletedCount;
       
   199             }
       
   200 					    
       
   201 		// if download is complete
       
   202 		if ( aEvent.iProgressStatus ==
       
   203 			 TFSProgress::EFSStatus_RequestComplete && !aEvent.iError )
       
   204 			{
       
   205             // if file was set to be saved after download
       
   206     		if ( download.iSaveFileName.CompareC( KNullDesC ) )
       
   207     			{
       
   208     			CFSMailMessage* mailMessage = iMailClient.GetMessageByUidL(
       
   209     				download.iPartData.iMailBoxId,
       
   210     				download.iPartData.iFolderId,
       
   211     				download.iPartData.iMessageId,
       
   212     				EFSMsgDataEnvelope );
       
   213         		CleanupStack::PushL( mailMessage );
       
   214         		CFSMailMessagePart* attachment = mailMessage->ChildPartL(
       
   215         			download.iPartData.iMessagePartId );
       
   216         		CleanupStack::PopAndDestroy( mailMessage );
       
   217         		CleanupStack::PushL( attachment );
       
   218         		if ( TFsEmailUiUtility::OkToSaveFileL( download.iSaveFileName, *attachment ) )
       
   219         			{
       
   220 	        		attachment->CopyContentFileL( download.iSaveFileName );       			
       
   221         			}
       
   222         		CleanupStack::PopAndDestroy( attachment );
       
   223     			}
       
   224 			}
       
   225 			
       
   226 		// relay the event to observers
       
   227 		NotifyObserversL( aEvent, download.iPartData );
       
   228 
       
   229         // <cmail> moved completion note after notifying so that observers can 
       
   230         // clear menus etc. before note is displayed
       
   231         // if download is complete
       
   232 		if ( aEvent.iProgressStatus ==
       
   233 			 TFSProgress::EFSStatus_RequestComplete && !aEvent.iError )
       
   234 			{
       
   235 			// Show "Download completed" if necessary
       
   236 			if ( CompletionNotesInUseL() && completedDownloadsToNotify )
       
   237 				{
       
   238 				LaunchDownloadCompleteNoteL( download.iPartData,
       
   239 					completedDownloadsToNotify );
       
   240 				}
       
   241             // Notification of saved attachments may be given if all downloads of the given message has been completed.
       
   242             if ( download.iNotifyComplete && countObject.iDownloadsCompletedCount &&
       
   243                  countObject.iDownloadsCompletedCount == countObject.iDownloadsStartedCount )
       
   244                  {
       
   245                  TFsEmailUiUtility::ShowFilesSavedToFolderNoteL( countObject.iSaveRequestedCount );
       
   246                  }        
       
   247 			}
       
   248 	    // </cmail>
       
   249         }
       
   250 	}
       
   251 	
       
   252 TBool CFSEmailDownloadInfoMediator::IsAnyAttachmentDownloads()
       
   253 	{
       
   254 	FUNC_LOG;
       
   255 	return iDownloadsStarted;
       
   256 	}
       
   257 
       
   258 
       
   259 TBool CFSEmailDownloadInfoMediator::IsAnyAttachmentDownloads( TFSMailMsgId aMessageId )
       
   260 	{
       
   261 	FUNC_LOG;
       
   262 	for ( TInt i=0; i<iDownloadArray.Count(); i++ )
       
   263 		{
       
   264 		if ( iDownloadArray[i].iPartData.iMessageId == aMessageId )
       
   265 			{
       
   266 			return ETrue;
       
   267 			}
       
   268 		}
       
   269 	return EFalse;
       
   270 	}
       
   271 
       
   272 TInt CFSEmailDownloadInfoMediator::GetDownloadPercentageL( TFSMailMsgId aMessageId )
       
   273     {
       
   274 	FUNC_LOG;
       
   275     TInt count = 0;
       
   276     TInt maxCount = 0;
       
   277     
       
   278     for ( TInt i=0; i<iDownloadArray.Count(); i++ )
       
   279         {
       
   280         if ( iDownloadArray[i].iPartData.iMessageId == aMessageId )
       
   281             {
       
   282             // In case we find an attachment for which maxCount is still missing,
       
   283             // update all the missing maxCounts to match the file size of
       
   284             // the attachment.
       
   285             if ( iDownloadArray[i].iMaxCount <= 0 )
       
   286                 {
       
   287                 // This should happen at most once per call to GetDownloadPercentageL().
       
   288                 UpdateAttachmentSizesL( iDownloadArray[i].iPartData );
       
   289                 }
       
   290 
       
   291             count += iDownloadArray[i].iCounter;
       
   292             maxCount += iDownloadArray[i].iMaxCount;
       
   293             }
       
   294         }
       
   295     
       
   296     if ( maxCount <= 0 )
       
   297         {
       
   298         return KErrNotFound;
       
   299         }
       
   300     else
       
   301         {
       
   302         return 100*count/maxCount;
       
   303         }
       
   304     }
       
   305 
       
   306 void CFSEmailDownloadInfoMediator::UpdateAttachmentSizesL( const TPartData& aMessageData )
       
   307     {
       
   308 	FUNC_LOG;
       
   309     CFSMailMessage* mailMessage = iMailClient.GetMessageByUidL( aMessageData.iMailBoxId, 
       
   310                                                                 aMessageData.iFolderId, 
       
   311                                                                 aMessageData.iMessageId, 
       
   312                                                                 EFSMsgDataEnvelope );
       
   313     CleanupStack::PushL( mailMessage );
       
   314     RPointerArray<CFSMailMessagePart> attachments;
       
   315     CleanupResetAndDestroyClosePushL( attachments );
       
   316     mailMessage->AttachmentListL( attachments );
       
   317     
       
   318     for ( TInt i=0; i<iDownloadArray.Count(); i++ )
       
   319         {
       
   320         if ( iDownloadArray[i].iPartData.iMessageId == aMessageData.iMessageId )
       
   321             {
       
   322             if ( iDownloadArray[i].iMaxCount <= 0 )
       
   323                 {
       
   324                 // Find the matching attachment object and retrieve the attachment size
       
   325                 for ( TInt j=0 ; j<attachments.Count() ; ++j )
       
   326                     {
       
   327                     if ( attachments[j]->GetPartId() == iDownloadArray[i].iPartData.iMessagePartId )
       
   328                         {
       
   329                         iDownloadArray[i].iMaxCount = attachments[j]->ContentSize();
       
   330                         break;
       
   331                         }
       
   332                     }
       
   333                 }
       
   334             }
       
   335         }
       
   336     
       
   337     CleanupStack::PopAndDestroy( &attachments );
       
   338     CleanupStack::PopAndDestroy( mailMessage );
       
   339     }
       
   340 
       
   341 TBool CFSEmailDownloadInfoMediator::IsDownloadableL( TPartData aPart )
       
   342 	{
       
   343 	FUNC_LOG;
       
   344 	TBool ret(EFalse);
       
   345 	// if part is downloading, no more checking is needed
       
   346 	if ( !IsDownloading( aPart.iMessagePartId ) )
       
   347 		{
       
   348 		CFSMailMessage* mailMessage = iMailClient.GetMessageByUidL(
       
   349 			aPart.iMailBoxId, aPart.iFolderId,
       
   350 			aPart.iMessageId, EFSMsgDataEnvelope );
       
   351 		if ( mailMessage )
       
   352 			{
       
   353 			CleanupStack::PushL( mailMessage );
       
   354 			CFSMailMessagePart* mailMessagePart =
       
   355 				mailMessage->ChildPartL( aPart.iMessagePartId );
       
   356 			// if the file is fetched full
       
   357 			if ( mailMessagePart &&
       
   358 			        mailMessagePart->FetchLoadState() == EFSFull )
       
   359 				{
       
   360 				ret = EFalse;
       
   361 				}
       
   362 			else
       
   363 				{
       
   364 				ret =  ETrue;
       
   365 				}
       
   366 			delete mailMessagePart;
       
   367 			CleanupStack::PopAndDestroy( mailMessage );			
       
   368 			}
       
   369 		}
       
   370 	return ret;
       
   371 	}
       
   372 
       
   373 
       
   374 void CFSEmailDownloadInfoMediator::Destroy()
       
   375 	{
       
   376 	FUNC_LOG;
       
   377     CFSEmailDownloadInfoMediator* self = 
       
   378         static_cast<CFSEmailDownloadInfoMediator*>( UserSvr::DllTls( KTlsHandleDownloadInfo ) );
       
   379 	UserSvr::DllFreeTls( KTlsHandleDownloadInfo );
       
   380     delete self;
       
   381     }
       
   382 
       
   383 void CFSEmailDownloadInfoMediator::StopObserving( MFSEmailDownloadInformationObserver* aObserver, TFSMailMsgId aMessageId )
       
   384 	{
       
   385 	FUNC_LOG;
       
   386     for (TInt i=0; i<iObserverArray.Count(); i++)
       
   387     	{
       
   388    		if ( iObserverArray[i].iObserver == aObserver && iObserverArray[i].iMessageId == aMessageId )
       
   389    			{
       
   390    			iObserverArray.Remove(i);
       
   391    			}
       
   392     	}
       
   393 	}
       
   394 
       
   395 void CFSEmailDownloadInfoMediator::StopObserving( MFSEmailDownloadInformationObserver* aObserver )
       
   396 	{
       
   397 	FUNC_LOG;
       
   398     for (TInt i=0; i<iObserverArray.Count(); i++)
       
   399     	{
       
   400    		if ( iObserverArray[i].iObserver == aObserver )
       
   401    			{
       
   402    			iObserverArray.Remove(i);
       
   403    			}
       
   404     	}
       
   405     for (TInt i=0; i<iAllObserverArray.Count(); i++)
       
   406     	{
       
   407 		if ( iAllObserverArray[i] == aObserver )
       
   408    			{
       
   409    			iAllObserverArray.Remove(i);
       
   410    			}
       
   411     	}
       
   412 	}
       
   413 
       
   414 void CFSEmailDownloadInfoMediator::DownloadL( TPartData aPart, TBool aCompleteNote )
       
   415 	{
       
   416 	FUNC_LOG;
       
   417 	TFileName emptyFileName;
       
   418 	DownloadAndSaveL( aPart, emptyFileName, aCompleteNote );
       
   419 	}
       
   420 
       
   421 void CFSEmailDownloadInfoMediator::DownloadAndSaveL( TPartData aPart, const TDesC& aSaveFileName, TBool aCompleteNote )
       
   422 	{
       
   423 	FUNC_LOG;
       
   424 	// now there is at least one download started 
       
   425 	iDownloadsStarted = ETrue;
       
   426 	// fetch message part
       
   427 	CFSMailMessage* mailMessage = iMailClient.GetMessageByUidL( aPart.iMailBoxId, aPart.iFolderId, aPart.iMessageId, EFSMsgDataEnvelope );
       
   428 	CleanupStack::PushL( mailMessage );
       
   429 	CFSMailMessagePart* messagePart = mailMessage->ChildPartL( aPart.iMessagePartId );
       
   430 	CleanupStack::PopAndDestroy( mailMessage );
       
   431 	
       
   432 	// Panic in udeb builds, the condition !messagePart should not be possible
       
   433     ASSERT( messagePart );	
       
   434 
       
   435 	// to be on the safer side only leave in urel builds
       
   436     if ( !messagePart )
       
   437 	    {
       
   438 	    User::Leave( KErrNotFound );
       
   439 	    }	
       
   440 	
       
   441 	CleanupStack::PushL( messagePart );
       
   442 	// start download and get request id
       
   443 	TInt requestId = messagePart->FetchMessagePartL( aPart.iMessagePartId, *this, 0 );
       
   444 	
       
   445 	// store download information
       
   446 	TDownload newDownload( requestId, aPart, aSaveFileName, aCompleteNote );
       
   447 	AppendDownloadToInternalArraysL( newDownload );
       
   448     CleanupStack::PopAndDestroy( messagePart );
       
   449 		
       
   450 	// It may take some time before the first progress event is received from 
       
   451 	// the protocol plug-in. This is true at least with the current Intellisync
       
   452 	// plug-in implementation. Send artificial "0% event" to the UI to ensure that
       
   453 	// the UI shows that the file is being downloaded.
       
   454 	TFSProgress zeroEvent = { TFSProgress::EFSStatus_Waiting, 0, 0, KErrNone };
       
   455 	NotifyObserversL( zeroEvent, aPart );
       
   456 	}
       
   457 
       
   458 void CFSEmailDownloadInfoMediator::CancelDownloadL(
       
   459 	TFSMailMsgId aMessagePartId )
       
   460 	{
       
   461 	FUNC_LOG;
       
   462 	// Find the corresponding download object
       
   463 	TDownload downloadToCancel;
       
   464 	downloadToCancel.iPartData.iMessagePartId = aMessagePartId;
       
   465     TInt idx = iDownloadArray.Find( downloadToCancel, 
       
   466                                     TIdentityRelation<TDownload>(EqualMessagePartId) );
       
   467     // Cancel if download object was found
       
   468     if ( idx >= 0 && idx < iDownloadArray.Count() )
       
   469         {
       
   470         iMailClient.CancelL( iDownloadArray[idx].iRequestId );
       
   471         }
       
   472 	}
       
   473 
       
   474 void CFSEmailDownloadInfoMediator::CancelAllDownloadsL( TFSMailMsgId aMailBoxId )
       
   475     {
       
   476     // Cancel all downloads within mailbox indicated with aMailBoxId
       
   477     for (TInt i=0 ; i < iDownloadArray.Count() ; i ++ )
       
   478         {
       
   479         if ( iDownloadArray[i].iPartData.iMailBoxId == aMailBoxId )
       
   480             {
       
   481             iMailClient.CancelL( iDownloadArray[i].iRequestId );
       
   482             }
       
   483         }    
       
   484     }
       
   485 
       
   486 TBool CFSEmailDownloadInfoMediator::IsDownloading(
       
   487 	TFSMailMsgId aMessagePartId )
       
   488 	{
       
   489 	FUNC_LOG;
       
   490 	TInt dlArrayCount = iDownloadArray.Count();
       
   491 	for ( TInt i = 0; i < dlArrayCount; i++ )
       
   492     	{
       
   493     	const TDownload& downloadObject = iDownloadArray[i];
       
   494    		if ( downloadObject.iPartData.iMessagePartId == aMessagePartId )
       
   495    			{
       
   496    			if ( downloadObject.iCounter < downloadObject.iMaxCount ||
       
   497    			     downloadObject.iMaxCount <= 0 )
       
   498    			    {
       
   499    			    // Only return ETrue if the corresponding download entry is
       
   500    			    // found and it's not yet finished.
       
   501    	            return ETrue;
       
   502    			    }
       
   503    			}
       
   504     	}
       
   505 	return EFalse;
       
   506 	}
       
   507 
       
   508 void CFSEmailDownloadInfoMediator::NotifyObserversIfAttachmentsDownloadedL(
       
   509 	TPartData aMessageId )
       
   510     {
       
   511 	FUNC_LOG;
       
   512 	CFSMailMessage* mailMessage = iMailClient.GetMessageByUidL(
       
   513 		aMessageId.iMailBoxId,
       
   514 		aMessageId.iFolderId,
       
   515 		aMessageId.iMessageId,
       
   516 		EFSMsgDataEnvelope );
       
   517 	CleanupStack::PushL( mailMessage );
       
   518 
       
   519 	RPointerArray<CFSMailMessagePart> attachments;
       
   520 	CleanupResetAndDestroyClosePushL( attachments );
       
   521 	mailMessage->AttachmentListL( attachments );
       
   522 	
       
   523 	for ( TInt i=0 ; i<attachments.Count() ; ++i )
       
   524 	    {
       
   525 	    TInt fetched = attachments[i]->FetchedContentSize();
       
   526 	    TInt totalSize = attachments[i]->ContentSize();
       
   527 	    
       
   528 	    if ( fetched == totalSize )
       
   529 	        {
       
   530 	        // download has happened => Download Manager should be available in menus
       
   531 	        iDownloadsStarted = ETrue;
       
   532 	        
       
   533 	        // notify observers about completed attachment download
       
   534     	    TFSProgress completeEvent = 
       
   535     	        {
       
   536     	        TFSProgress::EFSStatus_RequestComplete, 
       
   537     	        fetched,
       
   538     	        totalSize,
       
   539     	        KErrNone
       
   540     	        };
       
   541     	    aMessageId.iMessagePartId = attachments[i]->GetPartId();
       
   542     	    NotifyObserversL( completeEvent, aMessageId );
       
   543 	        }
       
   544 	    }
       
   545 	
       
   546 	CleanupStack::PopAndDestroy( &attachments );
       
   547 	CleanupStack::PopAndDestroy( mailMessage );
       
   548     }
       
   549 
       
   550 void CFSEmailDownloadInfoMediator::AppendDownloadToInternalArraysL( const TDownload& aNewDownload )
       
   551     {
       
   552 	FUNC_LOG;
       
   553     // In case of some unexpected errors, it's possible that we have an existing download object
       
   554     // with the same request ID as the new download. In that case, the original download has failed
       
   555     // and needs to be removed.
       
   556     TInt foundIdx = iDownloadArray.Find( aNewDownload );
       
   557     if ( foundIdx >= 0 )
       
   558         {
       
   559         TFSProgress cancelEvent = { TFSProgress::EFSStatus_RequestCancelled, 0, 0, KErrUnknown };
       
   560         TDownload obsoleteDownload = iDownloadArray[foundIdx];
       
   561         TDownloadCount countObject( obsoleteDownload.iPartData.iMessageId );
       
   562 
       
   563         iDownloadArray.Remove( foundIdx );
       
   564         GetAndUpdateDownloadCountL( countObject, cancelEvent );
       
   565         NotifyObserversL( cancelEvent, obsoleteDownload.iPartData );     
       
   566         }
       
   567     
       
   568     // Add the download object to array now when we know that there's no duplicate IDs.
       
   569     iDownloadArray.Append( aNewDownload );
       
   570 
       
   571     // Add the download to the download count array
       
   572     TDownloadCount newCountObject( aNewDownload.iPartData.iMessageId );
       
   573     TInt idx = iDownloadCountArray.Find( newCountObject, 
       
   574                                          TIdentityRelation<TDownloadCount>(EqualMessageId) );
       
   575     if ( idx >= 0 && idx < iDownloadCountArray.Count() )
       
   576         {
       
   577         // if there are already downloads going on on the same message
       
   578         iDownloadCountArray[idx].iDownloadsStartedCount++;
       
   579         if ( aNewDownload.iSaveFileName.CompareC( KNullDesC ) )
       
   580             {
       
   581             iDownloadCountArray[idx].iSaveRequestedCount++;
       
   582             }      
       
   583         }
       
   584     else
       
   585         {
       
   586         newCountObject.iDownloadsStartedCount = 1;
       
   587         if ( aNewDownload.iSaveFileName.CompareC( KNullDesC ) )
       
   588             {
       
   589             newCountObject.iSaveRequestedCount=1;
       
   590             } 
       
   591         iDownloadCountArray.Append( newCountObject );
       
   592         }
       
   593     }
       
   594 
       
   595 TBool CFSEmailDownloadInfoMediator::CompletionNotesInUseL() const
       
   596 	{
       
   597 	FUNC_LOG;
       
   598 	// singleton, do not destroy
       
   599 	CFSEmailCRHandler* cenRepHandler = CFSEmailCRHandler::InstanceL();
       
   600 	
       
   601 	return cenRepHandler->DownloadNotifications();
       
   602 	}
       
   603 
       
   604 void CFSEmailDownloadInfoMediator::LaunchDownloadCompleteNoteL(
       
   605         const TPartData& aPart, TInt aCompletedCount )
       
   606     {
       
   607 	FUNC_LOG;
       
   608 
       
   609     Cancel(); // deletes previous iGlobalMsgQuery
       
   610 
       
   611     iPopupLaunchData = aPart;
       
   612 
       
   613     // fetch message part
       
   614 	CFSMailMessage* mailMessage = iMailClient.GetMessageByUidL(
       
   615 	    aPart.iMailBoxId,
       
   616 	    aPart.iFolderId,
       
   617 	    aPart.iMessageId,
       
   618 	    EFSMsgDataEnvelope );
       
   619 
       
   620 	CleanupStack::PushL( mailMessage );
       
   621 
       
   622     // From:
       
   623 	HBufC* from = StringLoader::LoadLC(
       
   624 	    R_FSE_VIEWER_ATTACHMENTS_TEXT_FROM );
       
   625 
       
   626 	CFSMailAddress* senderData = mailMessage->GetSender(); // NOT OWNED
       
   627 
       
   628 	TDesC& mailSender = senderData->GetDisplayName(); 
       
   629 
       
   630 	// Subject:
       
   631 	HBufC* mailSubject =
       
   632 	    TFsEmailUiUtility::CreateSubjectTextLC( mailMessage );
       
   633 
       
   634 	HBufC* subj = StringLoader::LoadLC(
       
   635 	    R_FSE_VIEWER_ATTACHMENTS_TEXT_SUBJECT );
       
   636 
       
   637     // Attachment name or count
       
   638     HBufC* attachmentText = NULL;
       
   639 
       
   640 	CFSMailMessagePart* messagePart =
       
   641 	    mailMessage->ChildPartL( aPart.iMessagePartId );
       
   642 
       
   643     if ( messagePart )
       
   644         {
       
   645     	// create popup text
       
   646 
       
   647     	if ( aCompletedCount == 1 )
       
   648     		{
       
   649         	CleanupStack::PushL( messagePart );
       
   650 
       
   651     		attachmentText = messagePart->AttachmentNameL().AllocL(); 
       
   652 
       
   653         	CleanupStack::PopAndDestroy( messagePart );
       
   654         	
       
   655         	CleanupStack::PushL( attachmentText );
       
   656     		}
       
   657     	else if ( aCompletedCount > 1 )
       
   658     		{
       
   659     		attachmentText = StringLoader::LoadLC(
       
   660     		    R_FSE_VIEWER_ATTACHMENTS_DOWNLOADED, aCompletedCount );
       
   661     		iPopupLaunchData.iMessagePartId.SetNullId();
       
   662     		}
       
   663     	else
       
   664     	    {
       
   665     	    __ASSERT_DEBUG( EFalse, Panic(EFSEmailUiUnexpectedValue) );
       
   666     	    attachmentText = KNullDesC().AllocLC();
       
   667     	    }
       
   668 
       
   669         }
       
   670     else
       
   671         {
       
   672 		attachmentText = StringLoader::LoadLC(
       
   673 		    R_FSE_VIEWER_ATTACHMENTS_DOWNLOADED, aCompletedCount );
       
   674 		iPopupLaunchData.iMessagePartId.SetNullId();
       
   675         }
       
   676 
       
   677     // Combine the text parts into one descriptor
       
   678     TInt textLength = from->Length() +
       
   679                       KSpace().Length() + 
       
   680                       mailSender.Length() + 
       
   681                       KLineFeed().Length() + 
       
   682                       subj->Length() + 
       
   683                       KSpace().Length() + 
       
   684                       mailSubject->Length() + 
       
   685                       KLineFeed().Length() +
       
   686                       attachmentText->Length();
       
   687 
       
   688     HBufC* popupText = HBufC::NewL( textLength );
       
   689     TPtr textPtr = popupText->Des();
       
   690 
       
   691 	textPtr.Append( *from );
       
   692 	textPtr.Append( KSpace );					
       
   693 	textPtr.Append( mailSender );
       
   694 	textPtr.Append( KLineFeed );
       
   695 	textPtr.Append( *subj );
       
   696 	textPtr.Append( KSpace );					
       
   697 	textPtr.Append( *mailSubject );
       
   698 	textPtr.Append( KLineFeed );
       
   699 	textPtr.Append( *attachmentText );
       
   700 	
       
   701 	CleanupStack::PopAndDestroy( attachmentText );
       
   702 	CleanupStack::PopAndDestroy( subj );
       
   703 	CleanupStack::PopAndDestroy( mailSubject );
       
   704 	CleanupStack::PopAndDestroy( from );
       
   705 
       
   706 	CleanupStack::PopAndDestroy( mailMessage );
       
   707     
       
   708     CleanupStack::PushL( popupText );
       
   709 
       
   710 	HBufC* popupHeader = StringLoader::LoadLC(
       
   711 	    R_FSE_VIEWER_NOTE_ATTACHMENTS_DOWNLOAD_COMPLETE );
       
   712 
       
   713 	iGlobalMsgQuery = CAknGlobalMsgQuery::NewL();
       
   714 
       
   715     iGlobalMsgQuery->ShowMsgQueryL(
       
   716         iStatus,
       
   717         *popupText,
       
   718         R_AVKON_SOFTKEYS_OPEN_CLOSE,
       
   719         *popupHeader,
       
   720         KNullDesC );
       
   721 	    
       
   722 	CleanupStack::PopAndDestroy( popupHeader );
       
   723 
       
   724 	CleanupStack::PopAndDestroy( popupText );
       
   725 		
       
   726 	SetActive();
       
   727     }
       
   728 	
       
   729 void CFSEmailDownloadInfoMediator::NotifyObserversL( const TFSProgress& aEvent, const TPartData& aPart )
       
   730     {
       
   731 	FUNC_LOG;
       
   732 	// go through all observers
       
   733 	for ( TInt j=0; j<iObserverArray.Count(); j++)
       
   734 		{
       
   735 		// if observer is observing this message
       
   736 		if ( iObserverArray[j].iMessageId == aPart.iMessageId )
       
   737 			{
       
   738 			// send response to observer
       
   739 			iObserverArray[j].iObserver->RequestResponseL( aEvent, aPart );
       
   740 			}
       
   741 		}
       
   742 	// send response to every 'all observer'
       
   743 	for (TInt i=0; i<iAllObserverArray.Count(); i++)
       
   744 		{
       
   745 		iAllObserverArray[i]->RequestResponseL( aEvent, aPart );
       
   746 		}
       
   747     }
       
   748 
       
   749 void CFSEmailDownloadInfoMediator::RunL()
       
   750 	{
       
   751 	FUNC_LOG;
       
   752     // no close button pressed
       
   753     if (iStatus.Int() != EAknSoftkeyClose )
       
   754         {
       
   755         // open attachment list
       
   756         if ( iPopupLaunchData.iMessagePartId.IsNullId() )
       
   757             {
       
   758             TAttachmentListActivationData params;
       
   759             params.iMailBoxId = iPopupLaunchData.iMailBoxId;
       
   760             params.iFolderId = iPopupLaunchData.iFolderId;
       
   761             params.iMessageId = iPopupLaunchData.iMessageId;
       
   762             // use package buffer to pass the params
       
   763             TPckgBuf<TAttachmentListActivationData> buf( params );
       
   764             TUid emptyCustomMessageId = { 0 };
       
   765             CFreestyleEmailUiAppUi* appUi = (CFreestyleEmailUiAppUi*)CCoeEnv::Static()->AppUi();
       
   766             appUi->EnterFsEmailViewL( AttachmentMngrViewId, emptyCustomMessageId, buf );
       
   767             }
       
   768         // open attachment
       
   769         else
       
   770             {
       
   771             // Force FsEmailUI to foreground because global completion note may appear
       
   772             // while some other application is active and our local error notes are not shown
       
   773             // in that case. (This wouldn't be necessary in case of succesful file launching.)
       
   774             TFsEmailUiUtility::BringFsEmailToForeground();
       
   775             TFsEmailUiUtility::OpenAttachmentL( iPopupLaunchData );
       
   776             }
       
   777         }
       
   778     }
       
   779 
       
   780 void CFSEmailDownloadInfoMediator::DoCancel()
       
   781     {
       
   782     }
       
   783 
       
   784 void CFSEmailDownloadInfoMediator::Cancel()
       
   785     {
       
   786     FUNC_LOG;
       
   787     if ( iGlobalMsgQuery )
       
   788         {
       
   789         iGlobalMsgQuery->CancelMsgQuery();
       
   790         delete iGlobalMsgQuery;
       
   791         iGlobalMsgQuery = NULL;
       
   792         }
       
   793     if ( IsActive() )
       
   794         {
       
   795         CActive::Cancel();
       
   796         }
       
   797     }
       
   798 
       
   799 TInt CFSEmailDownloadInfoMediator::RunError( TInt /*aError*/ )
       
   800     {
       
   801     return KErrNone;
       
   802     }
       
   803 
       
   804 void CFSEmailDownloadInfoMediator::GetAndUpdateDownloadCountL( TDownloadCount& aCountObject, 
       
   805                                                                const TFSProgress& aEvent )
       
   806     {
       
   807     FUNC_LOG;
       
   808     TInt idx = iDownloadCountArray.Find( aCountObject, 
       
   809                                          TIdentityRelation<TDownloadCount>(EqualMessageId) );
       
   810     if ( idx >= 0 && idx < iDownloadCountArray.Count() )
       
   811         {
       
   812         // Set started save requests, it does not change depending on the event received 
       
   813         aCountObject.iDownloadsStartedCount = iDownloadCountArray[idx].iDownloadsStartedCount;
       
   814         
       
   815         // If download completed succesfully, increase the completed downlods count
       
   816         if ( aEvent.iProgressStatus == TFSProgress::EFSStatus_RequestComplete &&
       
   817              !aEvent.iError )
       
   818             {
       
   819             iDownloadCountArray[idx].iDownloadsCompletedCount++;
       
   820             }
       
   821         
       
   822         // If download was cancelled or failed, decrease started downloads count
       
   823         else if ( aEvent.iProgressStatus == TFSProgress::EFSStatus_RequestCancelled ||
       
   824                   aEvent.iError )
       
   825             {
       
   826             iDownloadCountArray[idx].iDownloadsStartedCount--;
       
   827             }
       
   828         else
       
   829             {
       
   830             // do nothing with other request status values
       
   831             }
       
   832         aCountObject = iDownloadCountArray[idx];
       
   833         
       
   834         if ( aCountObject.iDownloadsCompletedCount ==
       
   835              aCountObject.iDownloadsStartedCount )
       
   836             {
       
   837             // The count entry can be removed from the array when all ongoing
       
   838             // downloads have been completed or cancelled.
       
   839             iDownloadCountArray.Remove(idx);
       
   840             
       
   841             // Remove also all the connected download entries from the iDownloadArray.
       
   842             for ( TInt i = iDownloadArray.Count()-1 ; i >=0  ; --i )
       
   843                 {
       
   844                 if ( iDownloadArray[i].iPartData.iMessageId == aCountObject.iMessageId )
       
   845                     {
       
   846                     iDownloadArray.Remove(i);
       
   847                     }
       
   848                 }
       
   849             }
       
   850         }
       
   851     }
       
   852 
       
   853 TBool CFSEmailDownloadInfoMediator::EqualMessageId( const TDownloadCount& aFirst, const TDownloadCount& aSecond )
       
   854     {
       
   855     return (aFirst.iMessageId == aSecond.iMessageId);
       
   856     }
       
   857 
       
   858 TBool CFSEmailDownloadInfoMediator::EqualMessagePartId( const TDownload& aFirst, const TDownload& aSecond )
       
   859     {
       
   860     return (aFirst.iPartData.iMessagePartId == aSecond.iPartData.iMessagePartId);
       
   861     }
       
   862