email/imap4mtm/imapprotocolcontroller/src/cimapcompoundsyncfolder.cpp
changeset 31 ebfee66fde93
parent 0 72b543305e3a
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "cimapcompoundsyncfolder.h"
       
    17 #include "cimapfolder.h"
       
    18 #include "cimapfolderinfo.h"
       
    19 #include "cimapsession.h"
       
    20 #include "cimapsessionconsts.h"
       
    21 #include "cimaplogger.h"
       
    22 #include "imappaniccodes.h"
       
    23 #include "cimapcompoundcopytolocal.h"
       
    24 
       
    25 #include "mobilitytestmtmapi.h"
       
    26 
       
    27 CImapCompoundSyncFolder::CImapCompoundSyncFolder(CImapSyncManager& aSyncManager, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, TBool aNewOnly, TMsvId aFolderId)
       
    28  : CImapCompoundBase(aSyncManager, aServerEntry, aImapSettings), 
       
    29  	iImapMailStore(aImapMailStore), iNewOnly(aNewOnly), iFolderId(aFolderId)
       
    30 	{
       
    31 	// Set default progress values here so that any progress request before
       
    32 	// the operation is started returns valid information.
       
    33 	iSyncProgressState=TImap4SyncProgress::ESyncOther;
       
    34 	}
       
    35 
       
    36 CImapCompoundSyncFolder::~CImapCompoundSyncFolder()
       
    37 	{
       
    38 	delete iImapCompound;
       
    39 	}
       
    40 	
       
    41 /**
       
    42 Static constructor for Sync Folder operations
       
    43 
       
    44 @param aSession      The IMAP Session to use
       
    45 @param aSyncManager  IMAP Sync Manager
       
    46 @param aServerEntry  CMsvServerEntry for messaging server operations
       
    47 @param aImapSettings The IMAP account service settings
       
    48 @param aNewOnly		 ETrue if only newly-received mail should be synchronised
       
    49 @param aFolderId     Folder to synchronise (default KMsvNullIndexEntryId 
       
    50 					   indicates the currently selected folder should be synchronised)
       
    51 */
       
    52 CImapCompoundSyncFolder* CImapCompoundSyncFolder::NewL(CImapSyncManager& aSyncManager, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, TBool aNewOnly, TMsvId aFolderId/* = KMsvNullIndexEntryId */)
       
    53 	{
       
    54 	CImapCompoundSyncFolder* self = new (ELeave) CImapCompoundSyncFolder(aSyncManager, aServerEntry, aImapSettings, aImapMailStore, aNewOnly, aFolderId);
       
    55 	CleanupStack::PushL(self);
       
    56 	self->ConstructL();
       
    57 	CleanupStack::Pop(self);
       
    58 	return self;
       
    59 	}
       
    60 
       
    61 void CImapCompoundSyncFolder::ConstructL()
       
    62 	{
       
    63 	CActiveScheduler::Add(this);
       
    64 	}
       
    65 
       
    66 void CImapCompoundSyncFolder::StartOperation(TRequestStatus& aStatus, CImapSession& aSession)
       
    67 	{
       
    68 	iSession = &aSession;
       
    69 	__LOG_TEXT(iSession->LogId(), "CImapCompoundSyncFolder::StartOperation()");
       
    70 	iNextStep = ESelectSourceMailboxRW;
       
    71 	Queue(aStatus);
       
    72 	CompleteSelf();
       
    73 	}
       
    74 
       
    75 /**
       
    76 Handles the compound operation state machine
       
    77 
       
    78 @return ETrue if compound operation is completed, 
       
    79 		EFalse otherwise (will be called again, unless active)
       
    80 */
       
    81 TBool CImapCompoundSyncFolder::DoRunLoopL()
       
    82 	{
       
    83 	SetCurrentStep();
       
    84 	switch (iCurrentStep)
       
    85 		{
       
    86 		case ESelectSourceMailboxRW:
       
    87 			{
       
    88 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapSyncFolder1);
       
    89 						
       
    90 			if(iFolderId==KMsvNullIndexEntryId)
       
    91 				{
       
    92 				// Get the selected folder
       
    93 				if(iSession->SelectedFolderInfo())
       
    94 					{
       
    95 					iFolderId = iSession->SelectedFolderInfo()->MsvId();	
       
    96 					}
       
    97 				else
       
    98 					{
       
    99 					Complete(KErrArgument);
       
   100 					return ETrue;
       
   101 					}
       
   102 				}
       
   103 			
       
   104 			iSyncFolder=iSyncManager.GetFolderL(iFolderId);
       
   105 			if (iSyncFolder==NULL)
       
   106 				{
       
   107 				Complete(KErrNotSupported);
       
   108 				return ETrue;
       
   109 				}
       
   110 			
       
   111 			iSyncFolder->SelectL(iStatus, *iSession);
       
   112 			iProgressState = TImap4GenericProgress::ESelecting;
       
   113 			iNextStep=ESyncFolder;
       
   114 			SetActive();
       
   115 			break;
       
   116 			}
       
   117 		
       
   118 		case ESyncFolder:
       
   119 			{
       
   120 			// suspend operation if stop for migrate has been requested
       
   121 			if (iStopForMigrate)
       
   122 				{
       
   123 				__LOG_TEXT(iSession->LogId(), "CImapCompoundDelete::Stopped for migrate");
       
   124 				iCurrentStep = ESuspendedForMigrate;
       
   125 				iNextStep = ESelectSourceMailboxRW;
       
   126 				Complete(KErrNone);
       
   127 				return ETrue;
       
   128 				}
       
   129 			
       
   130 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapSyncFolder2);
       
   131 
       
   132 			// Synchronise the folder
       
   133 			iSyncFolder->SynchroniseL(iStatus, *iSession, iNewOnly, ETrue);
       
   134 			iProgressState = TImap4GenericProgress::ESyncing;
       
   135 			
       
   136 			// update next step according to download rule usage.
       
   137 			iNextStep = EFinished;
       
   138 			if (iImapSettings.UseSyncDownloadRules())
       
   139 				{
       
   140 				iNextStep = ESyncFolderAutoFetch;
       
   141 				}
       
   142 			SetActive();
       
   143 			break;
       
   144 			}
       
   145 		
       
   146 		case ESyncFolderAutoFetch:
       
   147 			{
       
   148 			// suspend operation if stop for migrate has been requested
       
   149 			if (iStopForMigrate)
       
   150 				{
       
   151 				__LOG_TEXT(iSession->LogId(), "CImapCompoundDelete::Stopped for migrate");
       
   152 				iCurrentStep = ESuspendedForMigrate;
       
   153 				iNextStep = ESyncFolderAutoFetch;
       
   154 				// delete the compound fetch operation - we will create a new one on resume,
       
   155 				// using the download rules for the new bearer.
       
   156 				delete iImapCompound;
       
   157 				iImapCompound = NULL;
       
   158 				Complete(KErrNone);
       
   159 				return ETrue;
       
   160 				}
       
   161 			
       
   162 			// Set the next step, which is always EFinished
       
   163 			iNextStep = EFinished;
       
   164 
       
   165 			// Get download rules defined for this folder type/bearer type
       
   166 			TInt ruleId=0;
       
   167 			TImImap4GetPartialMailInfo mailInfo;
       
   168 
       
   169 			if (iFolderId == (iSyncManager.Inbox())->MailboxId())
       
   170 				{
       
   171 				ruleId = iImapSettings.GetSyncDownloadRuleL(CImapSyncDownloadRules::EInboxRulesType, mailInfo);
       
   172 				}
       
   173 			else
       
   174 				{
       
   175 				ruleId = iImapSettings.GetSyncDownloadRuleL(CImapSyncDownloadRules::EFolderRulesType, mailInfo);
       
   176 				}
       
   177 
       
   178 			// finish now if no download rules configured for this folder type/bearer type
       
   179 			if (ruleId == KErrNotFound)
       
   180 				{
       
   181 				return EFalse;
       
   182 				}
       
   183 			
       
   184 			// build a list of messages to be fetched...
       
   185 			CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
   186 			CleanupStack::PushL(selection);
       
   187 			TInt msgsToFetch = iSyncFolder->GetFetchMessageChildrenL(*selection);
       
   188 			__LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncFolder::Fetching %d messages in folder %d.", msgsToFetch, iSyncFolder->MailboxId()));
       
   189 			if (msgsToFetch>0)
       
   190 				{
       
   191 				delete iImapCompound;
       
   192 				iImapCompound = NULL;
       
   193 				// Create the compound operation object
       
   194 				iImapCompound = CImapCompoundCopyToLocal::NewL(iSyncManager, 
       
   195 				                    			               iServerEntry, 
       
   196 				                                			   iImapSettings,
       
   197 				                                			   iImapMailStore, 
       
   198 				                                               EFalse,
       
   199 				                                               *selection,
       
   200 				                                               KMsvNullIndexEntryId,
       
   201 				                                               mailInfo);
       
   202 				iImapCompound->StartOperation(iStatus, *iSession);
       
   203 				SetActive();
       
   204 				}
       
   205 			CleanupStack::PopAndDestroy(selection);
       
   206 			return EFalse; // If not active, will re-loop.
       
   207 			}
       
   208 			
       
   209 		case EFinished:
       
   210 			{
       
   211 			__LOG_TEXT(iSession->LogId(), "CImapCompoundSyncFolder::Completing OK");
       
   212 			iProgressState = TImap4GenericProgress::EIdle;
       
   213 			iSyncProgressState = TImap4SyncProgress::EIdle;
       
   214 			iSyncFolder = NULL;
       
   215 			Complete(KErrNone);
       
   216 			return ETrue;
       
   217 			}
       
   218 			
       
   219 		default:
       
   220 			{
       
   221 			
       
   222 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ESyncFolderCompoundUnexpectedState));
       
   223 			// unexpected state - complete the request
       
   224 			iProgressState = TImap4GenericProgress::EIdle;
       
   225 			iSyncProgressState = TImap4SyncProgress::EIdle;
       
   226 			return ETrue;
       
   227 			}
       
   228 		} // end of switch (iState)
       
   229 
       
   230 	return EFalse;
       
   231 	}
       
   232 	
       
   233 /**
       
   234 May be called in case of a genuine cancel or a cancel for migrate.
       
   235 Following a genuine cancel, the compound operation will be deleted.
       
   236 If a second stage sync/auto fetch is in progress, this is cancelled
       
   237 and the iImapCompound deleted. This will be re-created on resume,
       
   238 using the download rules appropriate to the new bearer. 
       
   239 
       
   240 iNextState is updated here to ensure the operation is
       
   241 correctly restarted.
       
   242 
       
   243 In either case, CMsgActive::DoCancel() is called to complete the
       
   244 user request with KErrCancel.
       
   245 
       
   246 Note that if the default CMsgActive::DoComplete() is overridden,
       
   247 then that must also be modified to handle either case described above.
       
   248 */
       
   249 void CImapCompoundSyncFolder::DoCancel()
       
   250 	{
       
   251 	switch (iCurrentStep)
       
   252 		{
       
   253 		case ESelectSourceMailboxRW:
       
   254 			{
       
   255 			// Outstanding request on session.
       
   256 			// Note that although select operations are performed on a folder they
       
   257 			// actually pass our iStatus to the session, so that is why we cancel
       
   258 			// the session for them.
       
   259 			iNextStep = ESelectSourceMailboxRW;
       
   260 			iSession->Cancel();
       
   261 			break;
       
   262 			}
       
   263 		case ESyncFolder:
       
   264 			{
       
   265 			// outstanding request on folder
       
   266 			if (iSyncFolder != NULL)
       
   267 				{
       
   268 				iSyncFolder->Cancel();
       
   269 				}
       
   270 			iNextStep = ESelectSourceMailboxRW;
       
   271 			break;
       
   272 			}
       
   273 		case ESyncFolderAutoFetch:
       
   274 			{
       
   275 			if (iImapCompound)
       
   276 				{
       
   277 				iImapCompound->Cancel();
       
   278 				delete iImapCompound;
       
   279 				iImapCompound = NULL;
       
   280 				}
       
   281 			// resume the autofetch with new bearer's download rules on reconnect.
       
   282 			iNextStep = ESyncFolderAutoFetch;
       
   283 			break;
       
   284 			}
       
   285 		case EFinished:
       
   286 			{
       
   287 			// self-completed or no outstanding request.
       
   288 			iNextStep = EFinished;
       
   289 			break;
       
   290 			}
       
   291 		case ESuspendedForMigrate:
       
   292 		default:
       
   293 			{
       
   294 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ESyncFolderCompoundCancelUnexpectedState));
       
   295 			iNextStep = EFinished;
       
   296 			break;	
       
   297 			}
       
   298 		} // end of switch (iCurrentStep)
       
   299 
       
   300 	if (!iCancelForMigrate)
       
   301 		{
       
   302 		// genuine cancel - update progress
       
   303 		iProgressErrorCode = KErrCancel;
       
   304 		}
       
   305 	CMsgActive::DoCancel();		
       
   306 	}
       
   307 
       
   308 void CImapCompoundSyncFolder::Progress(TImap4CompoundProgress& aCompoundProgress)
       
   309 	{
       
   310 	aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::ESync;
       
   311 	aCompoundProgress.iGenericProgress.iState = iProgressState;
       
   312 
       
   313 	//if currently syncing then get the latest progress
       
   314 	if((iSyncProgressState!=TImap4SyncProgress::EIdle) && (iSyncFolder != NULL))
       
   315 		{
       
   316 		iSyncFolder->Progress(aCompoundProgress.iSyncProgress);
       
   317 		}
       
   318 	aCompoundProgress.iSyncProgress.iState = iSyncProgressState;
       
   319 
       
   320 	// Put error into progress buffer
       
   321 	if( aCompoundProgress.iGenericProgress.iErrorCode == KErrNone )
       
   322 		{
       
   323 		aCompoundProgress.iGenericProgress.iErrorCode = iProgressErrorCode;
       
   324 		}
       
   325 	}
       
   326 
       
   327 /**
       
   328 Handles NO/BAD responses according to current step.
       
   329 Negative server responses are not fatal - the error is saved in
       
   330 the message currently being operated on and the state machine pushed
       
   331 on to process the next message in the requested selection.
       
   332 
       
   333 @return KErrNone if the error has been handled
       
   334 		Completion error code otherwise.
       
   335 */
       
   336 TInt CImapCompoundSyncFolder::ProcessNegativeServerResponse()
       
   337 	{
       
   338 	TInt err = iStatus.Int();
       
   339 	switch (iCurrentStep)
       
   340 		{
       
   341 		case ESelectSourceMailboxRW:
       
   342 			{
       
   343 			if (err == KErrImapNo)
       
   344 				{
       
   345 				err = KErrNotFound;
       
   346 				iNextStep = EFinished;
       
   347 				}
       
   348 			break;
       
   349 			}
       
   350 		case ESyncFolder:
       
   351 		case ESyncFolderAutoFetch:
       
   352 			{
       
   353 			// Just store the error code in the progress response.
       
   354 			break;
       
   355 			}
       
   356 		case ESuspendedForMigrate:
       
   357 		case EFinished:
       
   358 		default:
       
   359 			{
       
   360 			// positive error code not expected,
       
   361 			// self-completed states or no outstanding request.
       
   362 			TImapServerPanic::ImapPanic(TImapServerPanic::ESyncFolderCompoundUnexpectedState);
       
   363 			break;
       
   364 			}
       
   365 		} // end of switch (iCurrentStep)
       
   366 	iProgressErrorCode = err;
       
   367 	return KErrNone;
       
   368 	}
       
   369 
       
   370 /**
       
   371 Called when operation has completed and we are about to complete the caller.
       
   372 
       
   373 @param aErr Error code that we will complete with.
       
   374 */
       
   375 void CImapCompoundSyncFolder::DoComplete(TInt& aErr)
       
   376 	{
       
   377 	// call base class for logging
       
   378 	CImapCompoundBase::DoComplete(aErr);
       
   379 
       
   380 	// Reset the flags which show if the new flags should be cleared on the
       
   381 	// next sync.
       
   382 	if (!iCancelForMigrate)
       
   383 		{
       
   384 		iSyncManager.ResetInboxClearNewFlags();
       
   385 		iSyncManager.ResetNonInboxClearNewFlags();
       
   386 		}
       
   387 	}
       
   388 
       
   389 
       
   390 /**
       
   391 Resumes the operation following a migration.
       
   392 */
       
   393 void CImapCompoundSyncFolder::ResumeOperationL(TRequestStatus& aStatus, CImapSession& aSession)
       
   394 	{
       
   395 	iSession = &aSession;
       
   396 	__LOG_TEXT(iSession->LogId(), "CImapCompoundSyncFolder::Resuming");
       
   397 	__ASSERT_DEBUG(iCurrentStep==ESuspendedForMigrate, TImapServerPanic::ImapPanic(TImapServerPanic::ESyncFolderCompoundUnexpectedState));
       
   398 	iStopForMigrate = EFalse;
       
   399 	Queue(aStatus);
       
   400 	CompleteSelf();
       
   401 	}
       
   402 
       
   403 /**
       
   404 Indicates that the compound operation should complete as soon as it is possible
       
   405 for the operation to be re-started without requiring a significant amount of
       
   406 repeated communication.
       
   407 The operation will be restarted by a call to ResumeOperationL()
       
   408 Overrides the base-class implementation.
       
   409 */
       
   410 void CImapCompoundSyncFolder::StopForMigrate()
       
   411 	{
       
   412 	__LOG_TEXT(iSession->LogId(), "CImapCompoundSyncFolder::StopForMigrate()");
       
   413 	if (iCurrentStep==ESyncFolderAutoFetch && iImapCompound)
       
   414 		{
       
   415 		// if doing a download-rules based fetch, instruct it to stop.
       
   416 		iImapCompound->StopForMigrate();
       
   417 		}
       
   418 	iStopForMigrate = ETrue;
       
   419 	}