email/pop3andsmtpmtm/imapservermtm/src/IMAPSYNC.CPP
changeset 25 84d9eb65b26f
equal deleted inserted replaced
23:238255e8b033 25:84d9eb65b26f
       
     1 // Copyright (c) 1998-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 // IMAP4 connect & synchronise operation control
       
    15 // This class deals with stepping through a synchronise operation - this
       
    16 // involves:
       
    17 // 1. Select inbox
       
    18 // 2. Perform any outstanding operations on inbox
       
    19 // 3. Synchronise inbox
       
    20 // 4. Synchronise folder list
       
    21 // 5. Build list of folders to synchronise, sorted by 'last sync' date
       
    22 // (oldest first), and outstanding operations (folders with outstanding
       
    23 // operations are first, whatever their date).
       
    24 // 6. Mirror subscription flags as necessary
       
    25 // 7. For each folder in the 'to synchronise' list...
       
    26 // i)   Select folder
       
    27 // ii)  Perform any outstanding operations
       
    28 // iii) Synchronise folder
       
    29 // 8. Reselect inbox
       
    30 // 
       
    31 //
       
    32 
       
    33 #include <e32base.h>
       
    34 #include <e32cons.h>
       
    35 #include <mentact.h>
       
    36 #include "impspan.h"
       
    37 #include "imapsess.h"
       
    38 #include "imapsync.h"
       
    39 #include "fldsync.h"
       
    40 #include <imapset.h>
       
    41 #include <offop.h>
       
    42 #include "imapcomp.h"
       
    43 #include "imapoffl.h"
       
    44 #include "impsutil.h"
       
    45 
       
    46 #ifdef _DEBUG
       
    47 #define DBG(a) iSession->LogText a
       
    48 #define PRINTING
       
    49 #else
       
    50 #define DBG(a)
       
    51 #undef PRINTING
       
    52 #endif
       
    53 
       
    54 // Inbox name for newly created one
       
    55 _LIT(KInbox, "Inbox");
       
    56 #ifdef PRINTING
       
    57 LOCAL_C const TText8* SynchroniseStateString(CImImap4Synchronise::TSynchroniseState aState)
       
    58 	{
       
    59 	switch (aState)
       
    60 		{
       
    61 	case CImImap4Synchronise::ESyncStateIdle:
       
    62 		return _S8("Idle");
       
    63 	case CImImap4Synchronise::EInboxSelect:
       
    64 		return _S8("InboxSelect");
       
    65 	case CImImap4Synchronise::EInboxPendingOps:
       
    66 		return _S8("InboxPendingOps");
       
    67 	case CImImap4Synchronise::EInboxSync:
       
    68 		return _S8("InboxSync");
       
    69 	case CImImap4Synchronise::ESynchroniseFolderTree:
       
    70 		return _S8("SynchroniseFolderTree");
       
    71 	case CImImap4Synchronise::ECheckRemoteSubscription:
       
    72 		return _S8("CheckRemoteSubscription");
       
    73 	case CImImap4Synchronise::EProcessRemoteSubscription:
       
    74 		return _S8("ProcessRemoteSubscription");
       
    75 	case CImImap4Synchronise::EUpdateRemoteSubscription:
       
    76 		return _S8("UpdateRemoteSubscription");
       
    77 	case CImImap4Synchronise::EFolderSelect:
       
    78 		return _S8("FolderSelect");
       
    79 	case CImImap4Synchronise::EFolderPendingOps:
       
    80 		return _S8("FolderPendingOps");
       
    81 	case CImImap4Synchronise::EFolderSynchronise:
       
    82 		return _S8("FolderSynchronise");
       
    83 	case CImImap4Synchronise::EInboxEarlyDeletes:
       
    84 		return _S8("InboxEarlyDeletes");
       
    85 	case CImImap4Synchronise::EFolderEarlyDeletes:
       
    86 		return _S8("FolderEarlyDeletes");
       
    87 	case CImImap4Synchronise::EFolderEarlyExpunge:
       
    88 		return _S8("FolderEarlyExpunge");
       
    89 	case CImImap4Synchronise::EInboxLateExpunge:
       
    90 		return _S8("InboxLateExpunge");
       
    91 	case CImImap4Synchronise::EFolderLateDeletes:
       
    92 		return _S8("FolderLateDeletes");
       
    93 	case CImImap4Synchronise::EFolderLateExpunge:
       
    94 		return _S8("FolderLateExpunge");
       
    95 #if 0
       
    96 	case CImImap4Synchronise::EInboxLateNewSync:
       
    97 		return _S8("InboxLateNewSync");
       
    98 	case CImImap4Synchronise::EFolderLateNewSync:
       
    99 		return _S8("FolderLateNewSync");
       
   100 #endif
       
   101 	case CImImap4Synchronise::EEndSelectInbox:
       
   102 		return _S8("EndSelectInbox");
       
   103 	case CImImap4Synchronise::EInboxLogMessage:
       
   104 		return _S8("InboxLogMessage");
       
   105 	case CImImap4Synchronise::EFolderLogMessage:
       
   106   		return _S8("FolderLogMessage");
       
   107 	case CImImap4Synchronise::EStartIdle:
       
   108 		return _S8("StartIdle");
       
   109 	case CImImap4Synchronise::ESynchronise:
       
   110 		return _S8("Synchronise");	
       
   111 	case CImImap4Synchronise::ESynchroniseTree:
       
   112 		return _S8("SynchroniseTree");		
       
   113 	case CImImap4Synchronise::ESynchroniseDeletes:
       
   114 		return _S8("SynchroniseDeletes");		
       
   115 		}
       
   116 	return _S8("Unknown");
       
   117 	}
       
   118 #endif
       
   119 
       
   120 CImImap4Synchronise::CImImap4Synchronise()
       
   121 	: CMsgActive(1), iState(ESyncStateIdle)
       
   122 	{
       
   123 	__DECLARE_NAME(_S("CImImap4Synchronise"));
       
   124 	}
       
   125 
       
   126 CImImap4Synchronise::~CImImap4Synchronise()
       
   127 	{
       
   128 	// Global bits
       
   129 	delete iFolderList;
       
   130 	delete iFolderListDest;
       
   131 	delete iFolderSync;
       
   132 	delete iSubscribeList;
       
   133 	delete iUnsubscribeList;
       
   134 	delete iOutstandingOps;
       
   135 	delete iCompound;
       
   136 	delete iOutstandingMoveTypeDeletes;
       
   137 	delete iOutstandingLocalDeletes;
       
   138 
       
   139 	// We don't delete iSession as we don't own it, we were just
       
   140 	// passed it to use.  similarly iOffLineControl
       
   141 	}
       
   142 
       
   143 CImImap4Synchronise* CImImap4Synchronise::NewLC(CImImap4Session *aSession)
       
   144 	{
       
   145 	CImImap4Synchronise* self=new (ELeave) CImImap4Synchronise();
       
   146 	CleanupStack::PushL(self);
       
   147 
       
   148 	// Non-trivial constructor
       
   149 	self->ConstructL(aSession);
       
   150 	return self;
       
   151 	}
       
   152 
       
   153 CImImap4Synchronise* CImImap4Synchronise::NewL(CImImap4Session *aSession)
       
   154 	{
       
   155 	CImImap4Synchronise* self=NewLC(aSession);
       
   156 	CleanupStack::Pop();
       
   157 	return self;
       
   158 	}
       
   159 
       
   160 // The non-trivial constructor
       
   161 void CImImap4Synchronise::ConstructL(CImImap4Session *aSession)
       
   162 	{
       
   163 	// Save session
       
   164 	iSession=aSession;
       
   165 
       
   166 	// We're an active object...
       
   167 	CActiveScheduler::Add(this);
       
   168 
       
   169 	// One-off bits
       
   170 	iFolderList=new (ELeave) CArrayFixFlat<TImImap4SyncList>(16);
       
   171 	iFolderListDest=new (ELeave) CArrayFixFlat<TImImap4SyncList>(16);
       
   172 	iFolderSync=CImImap4FolderSync::NewL(iSession);
       
   173 	iSubscribeList=new (ELeave) CArrayFixFlat<TMsvId>(4);
       
   174 	iUnsubscribeList=new (ELeave) CArrayFixFlat<TMsvId>(4);
       
   175 	iOutstandingMoveTypeDeletes=new (ELeave) CArrayFixFlat<TMsvId>(4);
       
   176 	iOutstandingLocalDeletes=new (ELeave) CArrayFixFlat<TMsvId>(4);
       
   177 
       
   178 	// Compound operation
       
   179 	iCompound=CImImap4Compound::NewL(iSession);
       
   180 
       
   181 	// Make a thread-local timer
       
   182 	iCheckMailbox.CreateLocal();
       
   183 
       
   184 	iProgress.iType=EImap4SyncProgressType;
       
   185 
       
   186 	iIdleBeforeCommand = EFalse;
       
   187 	}
       
   188 
       
   189 void CImImap4Synchronise::SetOffLineControl(CImap4OffLineControl* aOffLineControl)
       
   190 	{
       
   191 	iOffLineControl = aOffLineControl;
       
   192 	}
       
   193 
       
   194 void CImImap4Synchronise::SetUtils(CImap4Utils* aUtils)
       
   195 	{
       
   196 	iUtils = aUtils;
       
   197 	}
       
   198 
       
   199 // Set the entry to use to talk to the server
       
   200 void CImImap4Synchronise::SetEntry(CMsvServerEntry* aEntry)
       
   201 	{
       
   202 	// Save it
       
   203 	iEntry=aEntry;
       
   204 	
       
   205 	// Tell compound about it
       
   206 	iCompound->SetEntry(iEntry);
       
   207 	}
       
   208 
       
   209 // Do setentry, leave if there is an error
       
   210 void CImImap4Synchronise::SetEntryL(const TMsvId aId)
       
   211 	{
       
   212 	User::LeaveIfError(iEntry->SetEntry(aId));
       
   213 	}
       
   214 
       
   215 // Change entry, leave if error
       
   216 void CImImap4Synchronise::ChangeEntryL(const TMsvEntry& aEntry)
       
   217 	{
       
   218 	User::LeaveIfError(iEntry->ChangeEntry(aEntry));
       
   219 	}
       
   220 
       
   221 // Change entry in bulk mode (i.e no index file commit. no notify),
       
   222 // leave if error
       
   223 void CImImap4Synchronise::ChangeEntryBulkL(const TMsvEntry& aEntry)
       
   224 	{
       
   225 	User::LeaveIfError(iEntry->ChangeEntryBulk(aEntry));
       
   226 	}
       
   227 // Get children, leave if error
       
   228 void CImImap4Synchronise::GetChildrenL(CMsvEntrySelection& aSelection)
       
   229 	{
       
   230 	User::LeaveIfError(iEntry->GetChildren(aSelection));
       
   231 	}
       
   232 
       
   233 // Given an id of a folder or the service then restore the offline
       
   234 // operation array out of it. Returns the number of operations in the
       
   235 // array
       
   236 TBool CImImap4Synchronise::RefreshOutstandingOpsL(TMsvId aId)
       
   237 	{
       
   238 	if (iOutstandingOps)
       
   239 		{
       
   240 		delete iOutstandingOps;
       
   241 		iOutstandingOps=NULL;
       
   242 		}
       
   243 	
       
   244 	iOutstandingOps = iOffLineControl->OffLineOpArrayL(aId);
       
   245 	iOutstandingOpsFolder = aId;
       
   246 
       
   247 	// reset the count
       
   248 	iProgress.iMsgsToDo = iOutstandingOps->CountOperations();
       
   249 	iProgress.iMsgsDone = 0;
       
   250 	
       
   251 	iMovedId = KMsvNullIndexEntryId;
       
   252 	iShadowId = KMsvNullIndexEntryId;
       
   253 
       
   254 	return iProgress.iMsgsToDo;
       
   255 	}
       
   256 
       
   257 // Called when async child completes with an error
       
   258 #ifdef PRINTING
       
   259 void CImImap4Synchronise::DoComplete(TInt& aStatus)
       
   260 #else
       
   261 void CImImap4Synchronise::DoComplete(TInt& /*aStatus*/)
       
   262 #endif
       
   263 	{
       
   264 	DBG((_L8("CImImap4Synchronise::DoComplete(state=%s, istatus=%d)"),
       
   265 		 SynchroniseStateString(iState),aStatus));
       
   266 
       
   267 	// No alteration of the error code
       
   268 	}
       
   269 
       
   270 // This routine sets up iShadowId which will be deleted when the
       
   271 // operation completes successfully
       
   272 void CImImap4Synchronise::DoOpL(const CImOffLineOperation& aOp)
       
   273 	{
       
   274 	iShadowId = iMovedId = KMsvNullIndexEntryId;
       
   275 	
       
   276 	// clean the disconnected op flags and ensure its visible and get
       
   277 	// an entry copy
       
   278 	SetEntryL(aOp.MessageId());
       
   279 	TMsvEmailEntry entry = iEntry->Entry();
       
   280 	entry.SetVisible(ETrue);
       
   281 	entry.SetDisconnectedOperation(ENoDisconnectedOperations);
       
   282 	ChangeEntryBulkL(entry);
       
   283 
       
   284 	// check and see if there is a shadow and whether it has been
       
   285 	// removed or marked for deletion
       
   286 	TBool shadowOK = ETrue;
       
   287 	if ( aOp.OpType() != CImOffLineOperation::EOffLineOpMtmSpecific &&
       
   288 		 aOp.OpType() != CImOffLineOperation::EOffLineOpDelete )
       
   289 		{
       
   290 		iShadowId = iOffLineControl->FindShadowIdL(aOp);
       
   291 
       
   292 		shadowOK = iShadowId != KMsvNullIndexEntryId &&
       
   293 			iEntry->SetEntry(iShadowId) == KErrNone &&
       
   294 			((TMsvEmailEntry)iEntry->Entry()).DisconnectedOperation() != EDisconnectedDeleteOperation;
       
   295 		}
       
   296 
       
   297 	iUtils->ClearLogMessage();
       
   298 	
       
   299 	// Deal with operation
       
   300 	switch(aOp.OpType())
       
   301 		{
       
   302 	case CImOffLineOperation::EOffLineOpCopyToLocal:
       
   303 		// do the copy, if not a message
       
   304 		if (entry.iType != KUidMsvMessageEntry ||
       
   305 			// or the shadow exists
       
   306 			shadowOK )
       
   307 			{
       
   308 			iUtils->SetUpLogMessageL(aOp.MessageId());
       
   309 			SetActive();
       
   310 			iCompound->SyncCopyToLocalL(iStatus,aOp.MessageId(),aOp.TargetMessageId());
       
   311 			}
       
   312 		break;
       
   313 		
       
   314 	case CImOffLineOperation::EOffLineOpCopyFromLocal:
       
   315 		if (shadowOK)
       
   316 			{
       
   317 			SetActive();
       
   318 			iSession->Append(iStatus,aOp.MessageId(),aOp.TargetMessageId());
       
   319 			}
       
   320 		break;
       
   321 
       
   322 	case CImOffLineOperation::EOffLineOpCopyWithinService:
       
   323 		if (shadowOK)
       
   324 			{
       
   325 			SetActive();
       
   326 			iSession->Copy(iStatus,aOp.MessageId(),aOp.TargetMessageId(),EFalse);
       
   327 			}
       
   328 		break;
       
   329 		
       
   330 	case CImOffLineOperation::EOffLineOpMoveToLocal:
       
   331 		if (shadowOK)
       
   332 			{
       
   333 			iUtils->SetUpLogMessageL(aOp.MessageId());
       
   334 			SetActive();
       
   335 			iCompound->SyncCopyToLocalL(iStatus,aOp.MessageId(),aOp.TargetMessageId());
       
   336 			}
       
   337 		// even if the shadow has been removed we still want to delete
       
   338 		// the original
       
   339 		iMovedId=aOp.MessageId();
       
   340 		break;
       
   341 
       
   342 	case CImOffLineOperation::EOffLineOpMoveFromLocal:
       
   343 		if (shadowOK)
       
   344 			{
       
   345 			SetActive();
       
   346 			iSession->Append(iStatus,aOp.MessageId(),aOp.TargetMessageId());
       
   347 			}
       
   348 		// even if the shadow has been removed we still want to delete
       
   349 		// the original
       
   350 		iMovedId=aOp.MessageId();
       
   351 		break;
       
   352 
       
   353 	case CImOffLineOperation::EOffLineOpMoveWithinService:
       
   354 		if (shadowOK)
       
   355 			{
       
   356 			SetActive();
       
   357 			iSession->Copy(iStatus,aOp.MessageId(),aOp.TargetMessageId(),EFalse);
       
   358 			}
       
   359 		// even if the shadow has been removed we still want to delete
       
   360 		// the original, unless the folder itself has been removed
       
   361 		if (iEntry->SetEntry(aOp.TargetMessageId()) == KErrNone)
       
   362 			iMovedId=aOp.MessageId();
       
   363 		break;
       
   364 
       
   365 	case CImOffLineOperation::EOffLineOpMtmSpecific:
       
   366 		switch (aOp.MtmFunctionId())
       
   367 			{
       
   368 		case EFnOffLineOpPopulate:
       
   369 			{
       
   370 			TImap4GetMailOptions options;
       
   371 			TPckgC<TImap4GetMailOptions> package(options);
       
   372 			package.Set(aOp.MtmParameters());
       
   373 			
       
   374 			// Copy TImImap4GetMailOptions information into TImImap4GetPartialMailInfo
       
   375 			TImImap4GetPartialMailInfo imap4GetPartialMailInfo;	
       
   376 			imap4GetPartialMailInfo.iGetMailBodyParts = package();
       
   377 			// Set to default
       
   378 			imap4GetPartialMailInfo.iMaxEmailSize = KMaxTInt;
       
   379 			// Set the remaining members to default so that the server can check 
       
   380 			// if these are defaults, then this package is for TImImap4GetMailInfo
       
   381 			imap4GetPartialMailInfo.iTotalSizeLimit	= KMaxTInt;
       
   382 			imap4GetPartialMailInfo.iBodyTextSizeLimit = KMaxTInt;
       
   383 			imap4GetPartialMailInfo.iAttachmentSizeLimit = KMaxTInt;
       
   384 			imap4GetPartialMailInfo.iPartialMailOptions = ENoSizeLimits;
       
   385 			
       
   386 			TPckgBuf<TImImap4GetPartialMailInfo> partialPackage(imap4GetPartialMailInfo);
       
   387 	
       
   388 			iUtils->SetUpLogMessageL(aOp.MessageId());
       
   389 			SetActive();
       
   390 			iSession->FetchBody(iStatus,aOp.MessageId(),partialPackage());
       
   391 			break;
       
   392 			}
       
   393 		default:
       
   394 			break;
       
   395 			}
       
   396 		break;
       
   397 
       
   398 	case CImOffLineOperation::EOffLineOpDelete:
       
   399 	default:
       
   400 		break;
       
   401 		}
       
   402 	}
       
   403 
       
   404 void CImImap4Synchronise::MakeVisibleL(TMsvId aId)
       
   405 	{
       
   406 	DBG((_L8("  This folder isn't selectable, just making it visible")));
       
   407 
       
   408 	// Just make it visible
       
   409 	SetEntryL(aId);
       
   410 	TMsvEmailEntry mbcheck=iEntry->Entry();
       
   411 				
       
   412 	do
       
   413 		{
       
   414 		// Ensure visibility
       
   415 		if (!mbcheck.Visible())
       
   416 			{
       
   417 			mbcheck.SetVisible(ETrue);
       
   418 			ChangeEntryBulkL(mbcheck);
       
   419 			}
       
   420 
       
   421 		// Move up one
       
   422 		SetEntryL(mbcheck.Parent());
       
   423 		mbcheck=iEntry->Entry();
       
   424 		}
       
   425 	while(mbcheck.iType!=KUidMsvServiceEntry && mbcheck.Id()!=KMsvRootIndexEntryId);
       
   426 	}
       
   427 
       
   428 void CImImap4Synchronise::DonePendingOpL()
       
   429 	{
       
   430 	// if we've done one then...
       
   431 	if (iProgress.iMsgsDone != 0)
       
   432 		{
       
   433 		// if this was a move then append a delete
       
   434 		if (iMovedId != KMsvNullIndexEntryId)
       
   435 			{
       
   436 			SetEntryL(iMovedId);
       
   437 			if (iEntry->Entry().Parent() == iOutstandingOpsFolder)
       
   438 				{
       
   439 				DBG((_L8("Append MoveDelete for %x"), iMovedId));
       
   440 				iOutstandingMoveTypeDeletes->AppendL(iMovedId);
       
   441 				}
       
   442 			else
       
   443 				{
       
   444 				// if this id was from a MoveFrom (ie its parent is not
       
   445 				// this folder) then put it in a different pending array
       
   446 				DBG((_L8("Append LocalDelete for %x"), iMovedId));
       
   447 				iOutstandingLocalDeletes->AppendL(iMovedId);
       
   448 				}
       
   449 			}
       
   450 		
       
   451 		// delete the shadowid if there is one, ignore errors
       
   452 		if (iShadowId != KMsvNullIndexEntryId &&
       
   453 			iEntry->SetEntry(iShadowId) == KErrNone &&
       
   454 			iEntry->SetEntry(iEntry->Entry().Parent()) == KErrNone)
       
   455 			{
       
   456 			iEntry->DeleteEntry(iShadowId);
       
   457 			}
       
   458 
       
   459 		if (iUtils->SendLogMessageL(KErrNone,iStatus))
       
   460 			SetActive();
       
   461 		}
       
   462 	}
       
   463 
       
   464 TBool CImImap4Synchronise::NextPendingOpL()
       
   465 	{
       
   466 	TBool finished = EFalse;
       
   467 	
       
   468 	// Any operations in outstanding list?
       
   469 	if (iOutstandingOps->CountOperations())
       
   470 		{
       
   471 		DBG((_L8("Outstanding operations on this folder (%d)"),
       
   472 			 iOutstandingOps->CountOperations()));
       
   473 
       
   474 		// Fetch operation
       
   475 		CImOffLineOperation thisop;
       
   476 		thisop.CopyL(iOutstandingOps->Operation(0));
       
   477 
       
   478 		// when we get to one of the Delete operations then it is time
       
   479 		// to stop
       
   480 		if (thisop.OpType() == CImOffLineOperation::EOffLineOpDelete ||
       
   481 			(thisop.OpType() == CImOffLineOperation::EOffLineOpMtmSpecific &&
       
   482 			 thisop.MtmFunctionId() == EFnOffLineOpMoveDelete))
       
   483 			{
       
   484 			DBG((_L8("Reached delete op. Finished")));
       
   485 			finished = ETrue;
       
   486 			}
       
   487 		else
       
   488 			{
       
   489 			// remove from list and save back
       
   490 			iOutstandingOps->Delete(0);
       
   491 			iOffLineControl->SetOffLineOpArrayL(iOutstandingOpsFolder, *iOutstandingOps);
       
   492 
       
   493 			// and execute
       
   494 			DoOpL(thisop);
       
   495 			iProgress.iMsgsDone++;
       
   496 			}
       
   497 		}
       
   498 	else
       
   499 		{
       
   500 		// No more operations to do, return to what we should be doing next
       
   501 		finished = ETrue;
       
   502 		}
       
   503 
       
   504 	// when we are about to finish this folder then tidy up
       
   505 	if (finished)
       
   506 		{
       
   507 		// add the list of pending deletes to the front of the
       
   508 		// offline op array
       
   509 		for (TInt i = 0; i < iOutstandingMoveTypeDeletes->Count(); i++)
       
   510 			{
       
   511 			TMsvId id = (*iOutstandingMoveTypeDeletes)[i];
       
   512 			TBuf8<128> paramBuf(_L8(""));
       
   513 			CImOffLineOperation thisop;
       
   514 
       
   515 			// if we are doing deletes on connection then store this
       
   516 			// as a delete and we will do all deletes at the end of
       
   517 			// the sync.
       
   518 
       
   519 			// if we are doing deletes on disconnection then store
       
   520 			// this as a special code - it will still get done at end
       
   521 			// of sync, but real deletes will be done on
       
   522 			// disconnection.
       
   523 			if (iPerformDeletes)
       
   524 				thisop.SetDelete(id);
       
   525 			else
       
   526 				thisop.SetMtmSpecificCommandL(id, EFnOffLineOpMoveDelete, 0, paramBuf);
       
   527 
       
   528 			iOutstandingOps->InsertOperationL(thisop, 0);
       
   529 			}
       
   530 
       
   531 		// if there were outstanding move type deletes then clear
       
   532 		// their array and save back the main outstanding ops list
       
   533 		if (iOutstandingMoveTypeDeletes->Count())
       
   534 			{
       
   535 			iOutstandingMoveTypeDeletes->Reset();
       
   536 
       
   537 			iOffLineControl->SetOffLineOpArrayL(iOutstandingOpsFolder, *iOutstandingOps);
       
   538 			}
       
   539 		}
       
   540 
       
   541 	return finished;
       
   542 	}
       
   543 
       
   544 TBool CImImap4Synchronise::MatchDeleteOp(const CImOffLineOperation& aOp , TBool aMoveDeletesOnly )
       
   545 	{
       
   546 	return (aOp.OpType() == CImOffLineOperation::EOffLineOpMtmSpecific && aOp.MtmFunctionId() == EFnOffLineOpMoveDelete) ||
       
   547 		(!aMoveDeletesOnly && aOp.OpType() == CImOffLineOperation::EOffLineOpDelete);
       
   548 	}
       
   549 
       
   550 TBool CImImap4Synchronise::ProcessPendingDeleteOpsL( TMsvId aFolder, TBool aMoveDeletesOnly )
       
   551 	{
       
   552 	TBool hadDeletes = EFalse;
       
   553 
       
   554 	DBG((_L8("CImImap4Synchronise::ProcessPendingDeleteOpsL: Folder %x aMoveDeletesOnly=%d"),
       
   555 		 aFolder, aMoveDeletesOnly));
       
   556 		
       
   557 	// get the current offline operations of this folder
       
   558 	if (RefreshOutstandingOpsL(aFolder))
       
   559 		{
       
   560 		// Fetch operation
       
   561 		CImOffLineOperation thisop;
       
   562 		thisop.CopyL(iOutstandingOps->Operation(0));
       
   563 
       
   564 		// check delete type
       
   565 		if (MatchDeleteOp(thisop, aMoveDeletesOnly))
       
   566 			{
       
   567 			do
       
   568 				{
       
   569 				// if can't find the entry then just skip it so it is
       
   570 				// removed from array
       
   571 				if (iEntry->SetEntry(thisop.MessageId()) == KErrNone)
       
   572 					{
       
   573 					// set its server deleted flag
       
   574 					TMsvEmailEntry entry=iEntry->Entry();
       
   575 					entry.SetDeletedIMAP4Flag(ETrue);
       
   576 					iEntry->ChangeEntry(entry);
       
   577 					}
       
   578 
       
   579 				// remove from the array and write back immediately
       
   580 				iOutstandingOps->Delete(0);
       
   581 				iOffLineControl->SetOffLineOpArrayL(iOutstandingOpsFolder, *iOutstandingOps);
       
   582 
       
   583 				// check for finish
       
   584 				if (iOutstandingOps->CountOperations() == 0)
       
   585 					break;
       
   586 			
       
   587 				// get next op
       
   588 				thisop.CopyL(iOutstandingOps->Operation(0));
       
   589 				}
       
   590 			while (MatchDeleteOp(thisop, aMoveDeletesOnly));
       
   591 					
       
   592 			hadDeletes = ETrue;
       
   593 			}
       
   594 		}
       
   595 
       
   596 	return hadDeletes;
       
   597 	}
       
   598 
       
   599 TBool CImImap4Synchronise::ProcessPendingDeleteOpsListL( TBool aMoveDeletesOnly )
       
   600 	{
       
   601 	while (iProgress.iFoldersDone < iProgress.iFoldersToDo)
       
   602 		{
       
   603 		TImImap4SyncList next=(*iFolderList)[iProgress.iFoldersDone++];
       
   604 
       
   605 		if (ProcessPendingDeleteOpsL( next.iFolder, aMoveDeletesOnly ))
       
   606 			{
       
   607 			iSession->SelectL(iStatus, next.iFolder, ETrue);
       
   608 			SetActive();
       
   609 
       
   610 			return ETrue;
       
   611 			}
       
   612 		}
       
   613 	return EFalse;
       
   614 	}
       
   615 
       
   616 // Called when async child completes with >=KErrNone
       
   617 void CImImap4Synchronise::DoRunL()
       
   618 	{
       
   619 	DBG((_L8("CImImap4Synchronise::DoRunL(istatus=%d)"), iStatus.Int()));
       
   620 	
       
   621 	while (!IsActive() && !DoRunLoopL())
       
   622 		{
       
   623 		// do nothing in the body of this
       
   624 		}
       
   625 	}
       
   626 
       
   627 TBool CImImap4Synchronise::DoRunLoopL()
       
   628 	{
       
   629 	DBG((_L8("CImImap4Synchronise::DoRunLoopL(state=%s)"),
       
   630 		SynchroniseStateString(iState)));
       
   631 
       
   632 	TBool done = EFalse;
       
   633 	
       
   634 	// DoRunL is only called
       
   635 	switch(iState)
       
   636 		{
       
   637 	case EInboxSelect:
       
   638 		iProgress.iState=TImap4SyncProgress::ESyncInbox;
       
   639 
       
   640 		// if select failed then skip past INBOX ops
       
   641 		if (iStatus.Int() == KErrIMAPNO)
       
   642 			{
       
   643 			iState = ESynchroniseFolderTree;
       
   644 			iProgress.iFoldersNotFound++;
       
   645 			}
       
   646 		else
       
   647 			{
       
   648 			// Deal with operations in the array
       
   649 			if (RefreshOutstandingOpsL(iInbox))
       
   650 				iState=EInboxPendingOps;
       
   651 			else
       
   652 				iState=EInboxSync;
       
   653 			}
       
   654 		break;
       
   655 
       
   656 	case EInboxPendingOps:
       
   657 		iProgress.iState=TImap4SyncProgress::EProcessingPendingOps;
       
   658 		
       
   659 		iState = EInboxLogMessage;
       
   660 		DonePendingOpL();
       
   661 		break;
       
   662 		
       
   663 	case EInboxLogMessage:
       
   664 		if (NextPendingOpL())
       
   665 			iState = EInboxSync;
       
   666 		else
       
   667 			iState = EInboxPendingOps;
       
   668 		break;
       
   669 
       
   670 	case EInboxSync:
       
   671 		iProgress.iState=TImap4SyncProgress::ESyncInbox;
       
   672 		
       
   673 		//Once pending operations are done on folder/s, sync the Inbox 
       
   674 		if(iPendingOpOnFolder)
       
   675 			{
       
   676 			// reset iPendingOpOnFolder flag
       
   677 			iPendingOpOnFolder=EFalse;
       
   678 			if (iSession->ImapIdleSupported() && iIdleBeforeCommand)
       
   679 				{
       
   680 				// change the state to EStartIdle, if ImapIdle supported
       
   681 				iState = EStartIdle;
       
   682 				}
       
   683 			else
       
   684 				{
       
   685 				// else  change the state to EEndSelectInbox
       
   686 				iState = EEndSelectInbox;
       
   687 				}
       
   688 			}
       
   689 		else
       
   690 			{
       
   691 			// After inbox sync, start folder tree sync
       
   692 			iState=ESynchroniseFolderTree;
       
   693 			}
       
   694 
       
   695 		// mark inbox as having been done
       
   696 		iProgress.iFoldersDone++;
       
   697 
       
   698 		// Start the sync of the current folder (ie, the inbox)
       
   699 		DBG((_L8("CImImap4Sync::DoRunLoopL(): Calling iSession->SynchroniseL()")));
       
   700                 iSession->SynchroniseL(iStatus,EFalse);
       
   701 		SetActive();
       
   702 		break;
       
   703 
       
   704 	case ESynchroniseFolderTree:
       
   705 		iProgress.iState=TImap4SyncProgress::ESyncFolderTree;
       
   706 
       
   707 		// After this, check the remote folder subscription if needed
       
   708 		iState=ECheckRemoteSubscription;
       
   709 		
       
   710 		// Update folder tree
       
   711 		iFolderSync->SetEntry(iEntry);
       
   712 		iFolderSync->SynchroniseTreeL(iStatus,iServiceId,iNewFoldersAreInvisible);
       
   713 		SetActive();
       
   714 		break;
       
   715 
       
   716 	case ECheckRemoteSubscription:
       
   717 		iProgress.iState=TImap4SyncProgress::ECheckRemoteSubscription;
       
   718 
       
   719 		// Check the remote subscription/build local folder list,
       
   720 		// dependent on strategy in use
       
   721 		iState=EProcessRemoteSubscription;
       
   722 
       
   723 		// Do we need to know what folders are subscribed remotely?
       
   724 		if (iSynchroniseStrategy==EUseLocal && 
       
   725 			(iSubscribeStrategy==EUpdateNeither || iSubscribeStrategy==EUpdateLocal))
       
   726 			{
       
   727 			// No we don't: just add the folders (done in this state)
       
   728 			}
       
   729 		else
       
   730 			{
       
   731 			// Update our list of remotely subscribed folders
       
   732 			iSession->LsubL(iStatus);
       
   733 			SetActive();
       
   734 			}
       
   735 		break;
       
   736 
       
   737 	case EProcessRemoteSubscription:
       
   738 		iProgress.iState=TImap4SyncProgress::ECheckRemoteSubscription;
       
   739 
       
   740 		// Build (from local folders) and sort the list
       
   741 		SortFolderListL();
       
   742 
       
   743 		iProgress.iFoldersDone=0;
       
   744 		iProgress.iFoldersToDo=iFolderList->Count();
       
   745 
       
   746 		// Any remote subscribing/unsubscribing to do?
       
   747 		if (iSubscribeList->Count() || iUnsubscribeList->Count())
       
   748 			{
       
   749 			// Yes, do them
       
   750 			iState=EUpdateRemoteSubscription;
       
   751 			}
       
   752 		else
       
   753 			{
       
   754 			// Start folder selection
       
   755 			iState=EFolderSelect;
       
   756 			}
       
   757 		break;
       
   758 
       
   759 	case EUpdateRemoteSubscription:
       
   760 		iProgress.iState=TImap4SyncProgress::EUpdateRemoteSubscription;
       
   761 		
       
   762 		// Any subscription to do?
       
   763 		if (iSubscribeList->Count())
       
   764 			{
       
   765 			// Take it off the head
       
   766 			TMsvId folder=(*iSubscribeList)[0];
       
   767 			iSubscribeList->Delete(0,1);
       
   768 
       
   769 			// Subscribe to it
       
   770 			iSession->RemoteSubscribeL(iStatus,folder,ETrue);
       
   771 			SetActive();
       
   772 			}
       
   773 		// ...or unsubscription?
       
   774 		else if (iUnsubscribeList->Count())
       
   775 			{
       
   776 			// Take it off the head
       
   777 			TMsvId folder=(*iUnsubscribeList)[0];
       
   778 			iUnsubscribeList->Delete(0,1);
       
   779 
       
   780 			// Unsubscribe from it
       
   781 			iSession->RemoteSubscribeL(iStatus,folder,EFalse);
       
   782 			SetActive();
       
   783 			}
       
   784 		else
       
   785 			{
       
   786 			// All done, select the first folder
       
   787 			iState=EFolderSelect;
       
   788 			}
       
   789 		break;
       
   790 
       
   791 	case EFolderSelect:
       
   792 		iProgress.iState=TImap4SyncProgress::ESyncOther;
       
   793 
       
   794 		// Anything to do...
       
   795 		while (iProgress.iFoldersDone < iProgress.iFoldersToDo)
       
   796 			{
       
   797 			// Select the next folder
       
   798 			// Get next folder to-do
       
   799 			TImImap4SyncList next=(*iFolderList)[iProgress.iFoldersDone++];
       
   800 
       
   801 			DBG((_L8("Next folder to select is %x"),next.iFolder));
       
   802 
       
   803 			// Is this a selectable folder?
       
   804 			if (next.iNotSelectable)
       
   805 				{
       
   806 				MakeVisibleL(next.iFolder);
       
   807 				}
       
   808 			else
       
   809 				{
       
   810 				// Select it
       
   811                                 DBG((_L8("CImImap4Sync::DoRunLoopL(): Calling iSession->SelectL()")));
       
   812  				iSession->SelectL(iStatus,next.iFolder,ETrue);
       
   813 				SetActive();
       
   814 
       
   815 				// get the current offline operations of this folder
       
   816 				if (RefreshOutstandingOpsL(next.iFolder))
       
   817 					{
       
   818 					iState=EFolderPendingOps;
       
   819 					// set iPendingOpOnFolder flag, according this flag will syncing the Inbox.
       
   820   	  				iPendingOpOnFolder=ETrue;					
       
   821 					}
       
   822 				else
       
   823 					{
       
   824 					iState=EFolderSynchronise;
       
   825 					}
       
   826 
       
   827 				// stop loop
       
   828 				break;
       
   829 				}
       
   830 			}
       
   831 
       
   832 		// Run out of folders to sync?
       
   833 		if (iState == EFolderSelect)
       
   834 			iState = EInboxEarlyDeletes;
       
   835 		break;
       
   836 
       
   837 	case EFolderPendingOps:
       
   838 		iProgress.iState=TImap4SyncProgress::EProcessingPendingOps;
       
   839 
       
   840 		if (iStatus.Int() == KErrIMAPNO)
       
   841 			{
       
   842 			iState = EFolderSelect;
       
   843 			iProgress.iFoldersNotFound++;
       
   844 			}
       
   845 		else
       
   846 			{
       
   847 			iState = EFolderLogMessage;
       
   848 			DonePendingOpL();
       
   849 			}
       
   850 		break;
       
   851 
       
   852 	case EFolderLogMessage:
       
   853 		if (NextPendingOpL())
       
   854 			{
       
   855 			// Where a pending operation involves a folder that is also the currently
       
   856 			// selected mailbox, the IMAP session may have deselected the mailbox
       
   857 			// during the operation. Just in case this has happened, we need to select it
       
   858 			// again now.
       
   859 			DBG((_L8("CImImap4Sync::DoRunLoopL(): Calling select after pending ops")));
       
   860 			TImImap4SyncList next=(*iFolderList)[iProgress.iFoldersDone - 1];
       
   861 			iSession->SelectL(iStatus,next.iFolder,ETrue);
       
   862 			SetActive();
       
   863 
       
   864 			iState = EFolderSynchronise;
       
   865 			}
       
   866 		else
       
   867 			iState = EFolderPendingOps;
       
   868 		break;
       
   869 
       
   870 	case EFolderSynchronise:
       
   871 		iProgress.iState=TImap4SyncProgress::ESyncOther;
       
   872 
       
   873 		if (iStatus.Int() == KErrIMAPNO)
       
   874 			iProgress.iFoldersNotFound++;
       
   875 		else
       
   876 			{
       
   877 			iSession->SynchroniseL(iStatus,EFalse);
       
   878 			SetActive();
       
   879 			}
       
   880 
       
   881 		// back to select next folder
       
   882 		iState=EFolderSelect;
       
   883 		break;
       
   884 
       
   885 	case EInboxEarlyDeletes:
       
   886 		{
       
   887 		iProgress.iState=TImap4SyncProgress::EDeleting;
       
   888 
       
   889 		// get rid of the FromLocal message sources
       
   890 		for (TInt i = 0; i < iOutstandingLocalDeletes->Count(); i++)
       
   891 			{
       
   892 			TMsvId id = (*iOutstandingLocalDeletes)[i];
       
   893 			iSession->DeleteMessageL(id);
       
   894 			}
       
   895 
       
   896 		iOutstandingLocalDeletes->Reset();
       
   897 
       
   898 		// then do the inbox deletes
       
   899 		iProgress.iFoldersDone = 0;
       
   900 		if (ProcessPendingDeleteOpsL(iInbox, !iPerformDeletes))
       
   901 			{
       
   902 			iState = EFolderEarlyExpunge;
       
   903 
       
   904 			iSession->SelectL(iStatus, iInbox, ETrue);
       
   905 			SetActive();
       
   906 			}
       
   907 		else
       
   908 			{
       
   909 	        // DEF045009
       
   910             if (iSession->ServiceSettings()->DeleteEmailsWhenDisconnecting())
       
   911                  iState = EFolderLateDeletes;
       
   912             else
       
   913                  iState = EFolderEarlyDeletes;
       
   914 			}
       
   915   		break;
       
   916 		}
       
   917 
       
   918 	case EFolderEarlyDeletes:
       
   919 		iProgress.iState=TImap4SyncProgress::EDeleting;
       
   920 
       
   921 		// if we are doing deletes on connection then all deletes will
       
   922 		// be marked Delete
       
   923 		if (ProcessPendingDeleteOpsListL(!iPerformDeletes))
       
   924 			{
       
   925 			iState = EFolderEarlyExpunge;
       
   926 			}
       
   927 		else
       
   928 			{
       
   929 			if (iSession->ImapIdleSupported() && iIdleBeforeCommand)
       
   930 				{
       
   931 				iState = EStartIdle;
       
   932 				}
       
   933 			else
       
   934 				{
       
   935 				iState = EEndSelectInbox;
       
   936 				}
       
   937 
       
   938 			// All done: reselect inbox r/w
       
   939 			iSession->SelectL(iStatus,iInbox,ETrue);
       
   940 			SetActive();
       
   941 			}
       
   942 		break;
       
   943 
       
   944 	case EFolderEarlyExpunge:
       
   945 		iProgress.iState=TImap4SyncProgress::EDeleting;
       
   946 
       
   947 		if (iStatus.Int() == KErrIMAPNO)
       
   948 			iProgress.iFoldersNotFound++;
       
   949 		else
       
   950 			{
       
   951 			// expunge the folder
       
   952 			iSession->Close(iStatus, ETrue);
       
   953 			SetActive();
       
   954 			}
       
   955 
       
   956 		// back to select next folder
       
   957 		iState=EFolderEarlyDeletes;
       
   958 		break;
       
   959 		
       
   960 	case EEndSelectInbox:
       
   961 		iProgress.iState=TImap4SyncProgress::EIdle;
       
   962 
       
   963 		// Finish sync operation
       
   964 		iState=ESyncStateIdle;
       
   965 		Complete(KErrNone);
       
   966 		done = ETrue;
       
   967 		break;
       
   968 
       
   969 	case EInboxLateExpunge:
       
   970 		iProgress.iState=TImap4SyncProgress::EDeleting;
       
   971 
       
   972 		if (iStatus.Int() == KErrIMAPNO)
       
   973 			iProgress.iFoldersNotFound++;
       
   974 		else
       
   975 			{
       
   976 			iSession->Close(iStatus, ETrue);
       
   977 			SetActive();
       
   978 			}
       
   979 
       
   980 		iState = EFolderLateDeletes;
       
   981 		iProgress.iFoldersDone = 0;
       
   982 		break;
       
   983 
       
   984 	case EFolderLateDeletes:
       
   985 		iProgress.iState=TImap4SyncProgress::EDeleting;
       
   986 
       
   987 		if (ProcessPendingDeleteOpsListL( EFalse ) )
       
   988 			{
       
   989 			iState = EFolderLateExpunge;
       
   990 			}			
       
   991 		else
       
   992 			{
       
   993 			iProgress.iState=TImap4SyncProgress::EIdle;
       
   994 			
       
   995 			if(iPendingOpOnFolder)
       
   996 				{
       
   997 				iSession->SelectL(iStatus,iInbox,ETrue);
       
   998 				iState=EInboxSync;
       
   999 				SetActive();
       
  1000 				}
       
  1001 			else if (iSession->ImapIdleSupported() && iIdleBeforeCommand)
       
  1002 				{
       
  1003 				iSession->SelectL(iStatus,iInbox,ETrue);
       
  1004 				iState = EStartIdle;			
       
  1005 				SetActive();
       
  1006 				}
       
  1007 			else
       
  1008 				{
       
  1009 				iState=ESyncStateIdle;
       
  1010 				Complete(KErrNone);
       
  1011 				done = ETrue;
       
  1012 				}
       
  1013 			}
       
  1014 		break;
       
  1015 
       
  1016 	case EFolderLateExpunge:
       
  1017 		iProgress.iState=TImap4SyncProgress::EDeleting;
       
  1018 
       
  1019 		if (iStatus.Int() == KErrIMAPNO)
       
  1020 			{
       
  1021 			iState = EFolderLateDeletes;
       
  1022 			iProgress.iFoldersNotFound++;
       
  1023 			}
       
  1024 		else
       
  1025 			{
       
  1026 			iSession->Close(iStatus, ETrue);
       
  1027 			SetActive();
       
  1028 
       
  1029 			iState = EFolderLateDeletes;
       
  1030 			}
       
  1031 		break;
       
  1032 
       
  1033 	case EStartIdle:
       
  1034 		iState = EEndSelectInbox;
       
  1035 
       
  1036 		iSession->StartIdleL(iStatus);
       
  1037 		SetActive();
       
  1038 		break;
       
  1039 
       
  1040 	case ESynchronise:
       
  1041 		// Synchronise with the inbox
       
  1042 		iSession->SelectL(iStatus,iInbox,ETrue);
       
  1043 		iState=EInboxSelect;
       
  1044 		SetActive();
       
  1045 		break;
       
  1046 
       
  1047 	case ESynchroniseTree:
       
  1048 		if (iSession->ImapIdleSupported())
       
  1049 			{
       
  1050 			iState = EStartIdle;
       
  1051 			}
       
  1052 		else
       
  1053 			{
       
  1054 			iState = EEndSelectInbox;
       
  1055 			}
       
  1056 
       
  1057 		iFolderSync->SetEntry(iEntry);
       
  1058 		iFolderSync->SynchroniseTreeL(iStatus, iServiceId, iNewFoldersAreInvisible);
       
  1059 		SetActive();
       
  1060 		break;
       
  1061 
       
  1062 	case ESynchroniseDeletes:
       
  1063 		if (ProcessPendingDeleteOpsL( iInbox, EFalse ))
       
  1064 			{
       
  1065 			iSession->SelectL(iStatus,iInbox,ETrue);
       
  1066 
       
  1067 			iState = EInboxLateExpunge;
       
  1068 			SetActive();
       
  1069 			}
       
  1070 		else if (ProcessPendingDeleteOpsListL( EFalse ) )
       
  1071 			{
       
  1072 			iState = EFolderLateExpunge;
       
  1073 			}
       
  1074 		else
       
  1075 			{
       
  1076 			iProgress.iState=TImap4SyncProgress::EIdle;
       
  1077 
       
  1078 			iState=ESyncStateIdle;
       
  1079 			Complete(KErrNone);
       
  1080 			done = ETrue;
       
  1081 			}
       
  1082 		break;
       
  1083 
       
  1084 	default:
       
  1085 		gPanic(EUnknownState);
       
  1086 		done = ETrue;
       
  1087 		break;
       
  1088 		}
       
  1089 
       
  1090 	return done;
       
  1091 	}
       
  1092 
       
  1093 void CImImap4Synchronise::GetInboxL()
       
  1094 	{
       
  1095 	// First of all, synchronise the inbox
       
  1096 	CMsvEntrySelection *findinbox=new (ELeave) CMsvEntrySelection;
       
  1097 	CleanupStack::PushL(findinbox);
       
  1098 	SetEntryL(iServiceId);
       
  1099 	GetChildrenL(*findinbox);
       
  1100 	
       
  1101 	// Find inbox	
       
  1102 	TMsvId inboxid=0;
       
  1103 	for(TInt a=0;a<findinbox->Count();a++)
       
  1104 		{
       
  1105 		SetEntryL((*findinbox)[a]);
       
  1106 		if (iEntry->Entry().iDetails.CompareF(KIMAP_INBOX)==0)
       
  1107 			{
       
  1108 			inboxid=(*findinbox)[a];
       
  1109 			TMsvEmailEntry e=iEntry->Entry();
       
  1110 
       
  1111 			DBG((_L8("INBOX found with id %x (mailbox=%d)"),inboxid,e.Mailbox()));
       
  1112 
       
  1113 			// Mailbox flag not set? It always should be. This will 'repair' it.
       
  1114 			if (!e.Mailbox())
       
  1115 				{
       
  1116 				// Set it
       
  1117 				e.SetMailbox(ETrue);
       
  1118 				User::LeaveIfError(iEntry->ChangeEntry(e));
       
  1119 				}
       
  1120 
       
  1121 			break;
       
  1122 			}
       
  1123 		}
       
  1124 
       
  1125 	// Clean up
       
  1126 	CleanupStack::PopAndDestroy();
       
  1127 
       
  1128 	// Not found/no entries?
       
  1129 	if ((iInbox=inboxid)==0)
       
  1130 		{
       
  1131 		// Create an inbox entry below the service. This is a local-only
       
  1132 		// creation as the server *WILL* have an inbox.
       
  1133 		SetEntryL(iServiceId);
       
  1134 		TMsvEmailEntry entry;
       
  1135 
       
  1136 		entry.iType=KUidMsvFolderEntry;
       
  1137 		entry.iMtm=KUidMsgTypeIMAP4;
       
  1138 		entry.iServiceId=iServiceId;
       
  1139 		entry.SetMtmData1(0);
       
  1140 		entry.SetMtmData2(0);
       
  1141 		entry.SetMtmData3(0);
       
  1142 		entry.iSize=0;
       
  1143 		entry.SetUID(0);
       
  1144 		entry.SetValidUID(EFalse);
       
  1145 		entry.SetMailbox(ETrue);
       
  1146 		entry.SetLocalSubscription(ETrue);
       
  1147 		entry.SetComplete(ETrue);
       
  1148 		entry.iDetails.Set(KInbox);
       
  1149 		User::LeaveIfError(iEntry->CreateEntryBulk(entry));
       
  1150 
       
  1151 		// Set inbox ID
       
  1152 		iInbox=entry.Id();
       
  1153 
       
  1154 		DBG((_L8("INBOX created with id %x"),iInbox));
       
  1155 		}
       
  1156 	}
       
  1157 
       
  1158 void CImImap4Synchronise::SynchroniseTreeL(TRequestStatus& aStatus, TMsvId aServiceId, TBool aNewFoldersAreInvisible)
       
  1159 	{
       
  1160 	DBG((_L8("CImImap4Synchronise::SynchroniseTreeL")));
       
  1161 
       
  1162 	__ASSERT_DEBUG(aServiceId!=KMsvNullIndexEntryId, gPanic(EInvalidService));
       
  1163 
       
  1164 	Queue(aStatus);
       
  1165 
       
  1166 	iServiceId = aServiceId;
       
  1167 	iNewFoldersAreInvisible = aNewFoldersAreInvisible;
       
  1168 
       
  1169 	GetInboxL();
       
  1170 	ResetStats();
       
  1171 	iSession->SetInbox(iInbox);
       
  1172 
       
  1173 	iProgress.iState=TImap4SyncProgress::ESyncFolderTree;
       
  1174 	
       
  1175 	if (iSession->IsIdling())
       
  1176 		{
       
  1177 		iState=ESynchroniseTree;
       
  1178 		iSession->SyncStopIdleL(iStatus);
       
  1179 		SetActive();
       
  1180 		}
       
  1181 	else
       
  1182 		{
       
  1183 		iFolderSync->SetEntry(iEntry);
       
  1184 		iFolderSync->SynchroniseTreeL(iStatus, iServiceId, aNewFoldersAreInvisible);
       
  1185 
       
  1186 		iState=EEndSelectInbox;
       
  1187 		SetActive();
       
  1188 		}
       
  1189 	}
       
  1190 
       
  1191 void CImImap4Synchronise::ResetStats()
       
  1192 	{
       
  1193 	iProgress.iFoldersToDo = iProgress.iFoldersDone = 0;
       
  1194 	iProgress.iMsgsToDo = iProgress.iMsgsDone = 0;
       
  1195 	iProgress.iHeadersFetched = iProgress.iOrphanedFolders = 0;
       
  1196 	iProgress.iNewFolders = iProgress.iOrphanedMessages = 0;
       
  1197 	iProgress.iRemoteMessagesDeleteTagged = 0;
       
  1198 
       
  1199 	iProgress.iMessagesFetchedOK = iProgress.iMessagePartsFetchedOK = 0;
       
  1200 	iProgress.iMessagePartsNotFound = iProgress.iFoldersNotFound = 0;
       
  1201 	iProgress.iErrorCode = KErrNone;
       
  1202 
       
  1203 	// also reset the counts in the ImapSession
       
  1204 	iSession->ResetStats();
       
  1205 	iFolderSync->ResetStats();
       
  1206 	}
       
  1207 
       
  1208 void CImImap4Synchronise::SynchroniseDeletesL(TRequestStatus& aStatus, TMsvId aServiceId)
       
  1209 	{
       
  1210 	DBG((_L8("CImImap4Synchronise::SynchroniseDeletesL")));
       
  1211 
       
  1212 	__ASSERT_DEBUG(aServiceId!=KMsvNullIndexEntryId, gPanic(EInvalidService));
       
  1213 
       
  1214 	iServiceId = aServiceId;
       
  1215 
       
  1216 	ResetStats();
       
  1217 
       
  1218 	// Get the list of folders which need to be synchronized
       
  1219 	iProgress.iFoldersToDo=iFolderList->Count();
       
  1220 
       
  1221 	GetInboxL();
       
  1222 	iSession->SetInbox(iInbox);
       
  1223 	
       
  1224 	Queue(aStatus);
       
  1225 
       
  1226 	iProgress.iState=TImap4SyncProgress::EDeleting;
       
  1227 	
       
  1228 	if (iSession->IsIdling())
       
  1229 		{
       
  1230 		iState=ESynchroniseDeletes;
       
  1231 
       
  1232 		iSession->SyncStopIdleL(iStatus);
       
  1233 		SetActive();
       
  1234 		}
       
  1235 	else
       
  1236 		{
       
  1237 		if (ProcessPendingDeleteOpsL( iInbox, EFalse ))
       
  1238 			{
       
  1239 			iSession->SelectL(iStatus,iInbox,ETrue);
       
  1240 
       
  1241 			iState = EInboxLateExpunge;
       
  1242 			SetActive();
       
  1243 			}
       
  1244 		else if (ProcessPendingDeleteOpsListL( EFalse ) )
       
  1245 			{
       
  1246 			iState = EFolderLateExpunge;
       
  1247 			}
       
  1248 		else
       
  1249 			{
       
  1250 			iProgress.iState=TImap4SyncProgress::EIdle;
       
  1251 			Complete(KErrNone);
       
  1252 			}
       
  1253 		}
       
  1254 	}
       
  1255 
       
  1256 // Synchronise mirror tree with remote server
       
  1257 void CImImap4Synchronise::SynchroniseL(TRequestStatus& aStatus, TMsvId aService, TBool aNewInvisible, TBool aPerformDeletes, TBool aConnectAndSync)
       
  1258 	{
       
  1259 	DBG((_L8("CImImap4Synchronise::SynchroniseL(service=%x,newInvisible=%d,performDeletes=%d)"),
       
  1260 		 aService, aNewInvisible, aPerformDeletes));
       
  1261 
       
  1262 	Queue(aStatus);
       
  1263 
       
  1264 	// Note where this list came from
       
  1265 	iServiceId=aService;
       
  1266 	iFolderId=iServiceId;
       
  1267 
       
  1268 	// Note the invisibility
       
  1269 	iNewFoldersAreInvisible=aNewInvisible;
       
  1270 	iPerformDeletes = aPerformDeletes;
       
  1271 
       
  1272 	iIdleBeforeCommand = aConnectAndSync;
       
  1273 	
       
  1274 	// set iPendingOpOnFolder flag
       
  1275 	iPendingOpOnFolder=EFalse;
       
  1276 	
       
  1277 	// Get the synchronise settings
       
  1278 	iSynchroniseStrategy=iSession->ServiceSettings()->Synchronise();
       
  1279 	iSubscribeStrategy=iSession->ServiceSettings()->Subscribe();
       
  1280 
       
  1281 	DBG((_L8("iSynchroniseStrategy=%d, iSubscribeStrategy=%d"),
       
  1282 		iSynchroniseStrategy,iSubscribeStrategy));
       
  1283 
       
  1284 	GetInboxL();
       
  1285 	ResetStats();
       
  1286 	iSession->SetInbox(iInbox);
       
  1287 
       
  1288 	// Reset stats: 1 folder to do (inbox)
       
  1289 	iProgress.iFoldersToDo=1;
       
  1290 	iProgress.iState=TImap4SyncProgress::ESyncInbox;
       
  1291 	
       
  1292 	if (iSession->IsIdling())
       
  1293 		{
       
  1294 		iIdleBeforeCommand=ETrue;
       
  1295 		iState=ESynchronise;
       
  1296 
       
  1297 		iSession->SyncStopIdleL(iStatus);
       
  1298 		SetActive();
       
  1299 		}
       
  1300 	else
       
  1301 		{
       
  1302 		// Synchronise with the inbox
       
  1303 		iSession->SelectL(iStatus,iInbox,ETrue);
       
  1304 		iState=EInboxSelect;
       
  1305 		SetActive();
       
  1306 		}
       
  1307 	}
       
  1308 
       
  1309 void CImImap4Synchronise::SortFolderListL()
       
  1310 	{
       
  1311 	// Clear list of folders to sync, and subscribe/unsubscribe lists
       
  1312 	iFolderList->Reset();
       
  1313 	iFolderListDest->Reset();
       
  1314 	iSubscribeList->Reset();
       
  1315 	iUnsubscribeList->Reset();
       
  1316 
       
  1317 	// Add folders
       
  1318 	AddLocalFoldersL(iServiceId);
       
  1319 
       
  1320 	// Sort it by last-sync date (oldest first)
       
  1321 	TKeyArrayFix timeKey(_FOFF(TImImap4SyncList,iLastSync),ECmpTInt64);
       
  1322 
       
  1323 	// Perform the sort on each of the lists separately
       
  1324 	iFolderList->Sort(timeKey);
       
  1325 	iFolderListDest->Sort(timeKey);
       
  1326 
       
  1327 	// Merge the two lists and clear the second one
       
  1328 	for(TInt i=0; i<iFolderListDest->Count(); i++) 
       
  1329 		iFolderList->AppendL((*iFolderListDest)[i]);
       
  1330 	iFolderListDest->Reset();
       
  1331 	}
       
  1332 
       
  1333 void CImImap4Synchronise::AddIfNotThereL(TMsvId aFolder, CArrayFix<TImImap4SyncList>* aFolderList)
       
  1334 	{
       
  1335 	// first see if we already have this folder and return if we do
       
  1336 	for (TInt i=0; i < aFolderList->Count(); i++)
       
  1337 		{
       
  1338 		if ((*aFolderList)[i].iFolder == aFolder)
       
  1339 			return;
       
  1340 		}
       
  1341 
       
  1342 	// don't add the inbox or service
       
  1343 	if (aFolder == iInbox || aFolder == iServiceId)
       
  1344 		return;
       
  1345 	
       
  1346 	// visit folder
       
  1347 	SetEntryL(aFolder);
       
  1348 	TMsvEmailEntry entry=iEntry->Entry();
       
  1349 
       
  1350 	// not there so add it
       
  1351 	TImImap4SyncList add;
       
  1352 	add.iFolder=aFolder;
       
  1353 	add.iNotSelectable=EFalse;
       
  1354 	add.iLastSync=entry.iDate;
       
  1355 	// previously we adjusted the date of source folders to bring them
       
  1356 	// earlier in the list. No need to do this now as they
       
  1357 	// automatically appear before subscriptions/destinations
       
  1358 
       
  1359 	// If this is a \NoSelect marked folder, then we need to note this, so
       
  1360 	// that at sync time we just make the folder visible, as opposed to
       
  1361 	// trying to select it
       
  1362 	if (!entry.Mailbox())
       
  1363 		add.iNotSelectable=ETrue;
       
  1364 	
       
  1365 	DBG((_L8("Adding folder '%S' to synchronise todo list (mailbox=%d)"),
       
  1366 					   &entry.iDetails, entry.Mailbox()?1:0));
       
  1367 
       
  1368 	aFolderList->AppendL(add);
       
  1369 	}
       
  1370 
       
  1371 // Add local (subscribed) folders to the 'to do' iFolderList. Recursive.
       
  1372 void CImImap4Synchronise::AddLocalFoldersL(const TMsvId aFolder)
       
  1373 	{
       
  1374 	// Select the entry
       
  1375 	SetEntryL(aFolder);
       
  1376 	TMsvEmailEntry entry=iEntry->Entry();
       
  1377 
       
  1378 	// Is it actually a folder or service? If not, ignore it. 
       
  1379 	if (entry.iType!=KUidMsvServiceEntry &&
       
  1380 		entry.iType!=KUidMsvFolderEntry)
       
  1381 		return;
       
  1382 
       
  1383 	DBG((_L8("CImImap4Synchronise::AddLocalFolders(%x), iSync=%d iSubs=%d"),
       
  1384 					   aFolder,iSynchroniseStrategy,iSubscribeStrategy));
       
  1385 
       
  1386 	// What we do now depends on the strategy
       
  1387 	TBool addthisone=EFalse;
       
  1388 	switch(iSynchroniseStrategy)
       
  1389 		{
       
  1390 	case EUseLocal:
       
  1391 		// Is it locally subscribed?
       
  1392 		if (entry.LocalSubscription())
       
  1393 			addthisone=ETrue;
       
  1394 		break;
       
  1395 
       
  1396 	case EUseRemote:
       
  1397 		// Is it remotely subscribed?
       
  1398 		if (entry.Subscribed())
       
  1399 			addthisone=ETrue;
       
  1400 		break;
       
  1401 
       
  1402 	case EUseCombination:
       
  1403 		// Either will do
       
  1404 		if (entry.LocalSubscription() || entry.Subscribed())
       
  1405 			addthisone=ETrue;
       
  1406 		break;
       
  1407 		}
       
  1408 
       
  1409 	// Any outstanding operations?
       
  1410 	RefreshOutstandingOpsL(aFolder);
       
  1411 
       
  1412 	if (!entry.Orphan())
       
  1413 		{
       
  1414 		// check each and add the folder and destination folders. Add
       
  1415 		// source folders to one list, destination and just subscribed
       
  1416 		// ones to the second list, the two lists are merged
       
  1417 		// together before use
       
  1418 		if (iOutstandingOps->CountOperations())
       
  1419 			{
       
  1420 			AddIfNotThereL(aFolder, iFolderList);
       
  1421 		
       
  1422 			for(TInt a=0; a<iOutstandingOps->CountOperations(); a++)
       
  1423 				{
       
  1424 				TMsvId dest = iOutstandingOps->Operation(a).TargetMessageId();
       
  1425 				if (dest != KMsvNullIndexEntryId)
       
  1426 					AddIfNotThereL(dest, iFolderListDest);
       
  1427 				}
       
  1428 			}
       
  1429 
       
  1430 		// add subscribed afterwards
       
  1431 		if (addthisone)
       
  1432 			AddIfNotThereL(aFolder, iFolderListDest);
       
  1433 		}	
       
  1434 
       
  1435 	// Any children?
       
  1436 	CMsvEntrySelection *children=new (ELeave) CMsvEntrySelection;
       
  1437 	CleanupStack::PushL(children);
       
  1438 	GetChildrenL(*children);
       
  1439 	TInt noofchildren=children->Count();
       
  1440 
       
  1441 	if (!entry.Orphan() && aFolder != iInbox && aFolder != iServiceId)
       
  1442 		{
       
  1443 		if (addthisone)
       
  1444 			{
       
  1445 			// Do updating
       
  1446 			switch(iSubscribeStrategy)
       
  1447 				{
       
  1448 			case EUpdateNeither:
       
  1449 				break;
       
  1450 
       
  1451 			case EUpdateLocal:
       
  1452 			case EUpdateBoth:
       
  1453 				if (!entry.LocalSubscription())
       
  1454 					{
       
  1455 					// Update local subscription flag
       
  1456 					entry.SetLocalSubscription(ETrue);
       
  1457 					SetEntryL(aFolder);
       
  1458 					ChangeEntryBulkL(entry);
       
  1459 					}
       
  1460 
       
  1461 				// Doing both?
       
  1462 				if (iSubscribeStrategy!=EUpdateBoth)
       
  1463 					break;
       
  1464 
       
  1465 				// Fall through...
       
  1466 
       
  1467 			case EUpdateRemote:
       
  1468 				if (!entry.Subscribed())
       
  1469 					{
       
  1470 					// Queue subscribe command
       
  1471 					iSubscribeList->AppendL(aFolder);
       
  1472 
       
  1473 					DBG((_L8("Adding folder '%S' to remote subscribe todo list"),&entry.iDetails));
       
  1474 					}
       
  1475 				break;
       
  1476 				}
       
  1477 			}
       
  1478 		else // if (!addthisone)
       
  1479 			{
       
  1480 			// Do updating
       
  1481 			switch(iSubscribeStrategy)
       
  1482 				{
       
  1483 			case EUpdateNeither:
       
  1484 				break;
       
  1485 
       
  1486 			case EUpdateLocal:
       
  1487 			case EUpdateBoth:
       
  1488 				if (entry.LocalSubscription())
       
  1489 					{
       
  1490 					// Update local subscription flag
       
  1491 					entry.SetLocalSubscription(EFalse);
       
  1492 					SetEntryL(aFolder);
       
  1493 					ChangeEntryBulkL(entry);
       
  1494 					}
       
  1495 
       
  1496 				// Doing both?
       
  1497 				if (iSubscribeStrategy!=EUpdateBoth)
       
  1498 					break;
       
  1499 
       
  1500 				// Fall through...
       
  1501 
       
  1502 			case EUpdateRemote:
       
  1503 				if (entry.Subscribed())
       
  1504 					{
       
  1505 					// Queue subscribe command
       
  1506 					iUnsubscribeList->AppendL(aFolder);
       
  1507 
       
  1508 					DBG((_L8("Adding folder '%S' to remote unsubscribe todo list"),&entry.iDetails));
       
  1509 					}
       
  1510 				break;
       
  1511 				}
       
  1512 
       
  1513 			// This folder is not subscribed, but has children. 
       
  1514 			// If any children are messages, then delete.
       
  1515 			if (noofchildren)
       
  1516 				{
       
  1517 				DBG((_L8("Checking unsubscribed folder (%S) for messages"),&entry.iDetails));
       
  1518 
       
  1519 				// This folder is not subscribed to, so check if it has any messages.
       
  1520 				// Do each in turn
       
  1521 				TInt child = children->Count();
       
  1522 				while (child--)
       
  1523 					{
       
  1524 					SetEntryL((*children)[child]);
       
  1525 					TMsvEmailEntry entry=iEntry->Entry();
       
  1526 
       
  1527 					// Is it a message?
       
  1528 					if (entry.iType==KUidMsvMessageEntry)
       
  1529 						{
       
  1530 						DBG((_L8("Deleting unsubscribed folder message(%x)"),(*children)[child]));
       
  1531 
       
  1532 						// Yup its a message - delete it!
       
  1533 						iSession->DeleteMessageL((*children)[child]);
       
  1534 						}
       
  1535 					}
       
  1536 
       
  1537 				// If we've some children then get the children list
       
  1538 				// again
       
  1539 				SetEntryL(aFolder);
       
  1540 				GetChildrenL(*children);
       
  1541 				noofchildren=children->Count();
       
  1542 				}
       
  1543 			}
       
  1544 		}
       
  1545 	
       
  1546 	// Any children?
       
  1547 	if (noofchildren)
       
  1548 		{
       
  1549 		// Do each in turn
       
  1550 		for(TInt child=0;child<children->Count();child++)
       
  1551 			AddLocalFoldersL((*children)[child]);
       
  1552 		}
       
  1553 
       
  1554 	CleanupStack::PopAndDestroy(children);
       
  1555 	}
       
  1556 
       
  1557 // Report progress
       
  1558 TImap4SyncProgress CImImap4Synchronise::Progress()
       
  1559 	{
       
  1560 	TImap4SyncProgress progress = iProgress;
       
  1561 	
       
  1562 	// Make sure we don't get stuck in sync folder mode. Fix for DEF053846.
       
  1563 	if (iProgress.iState == TImap4SyncProgress::ESyncFolderTree && !iFolderSync->IsActive())
       
  1564 		{
       
  1565 		iProgress.iState = TImap4SyncProgress::EIdle;
       
  1566 		}
       
  1567 	
       
  1568 	// get the info from the folder sync
       
  1569 	// currently OrphanedFolders and NewFolders
       
  1570 	if (iState >= ESynchroniseFolderTree)
       
  1571 		iFolderSync->IncProgress(progress);
       
  1572 
       
  1573 	// get info from the session (note overwrites the msgs counts).
       
  1574 	iSession->IncSyncStats(progress);
       
  1575 
       
  1576 	// when synchronising (ie getting new headers) then we use the
       
  1577 	// counts from the session otherwise use our own count
       
  1578 	if (iProgress.iState != TImap4SyncProgress::ESyncOther &&
       
  1579 		iProgress.iState != TImap4SyncProgress::ESyncInbox )
       
  1580 		{
       
  1581 		progress.iMsgsDone=iProgress.iMsgsDone;
       
  1582 		progress.iMsgsToDo=iProgress.iMsgsToDo;
       
  1583 		}
       
  1584 
       
  1585 	// Return the modified progress
       
  1586 	return(progress);
       
  1587 	}
       
  1588 
       
  1589 // Called when parent wants to cancel current operation
       
  1590 void CImImap4Synchronise::DoCancel()
       
  1591 	{
       
  1592 	DBG((_L8("CImImap4Synchronise::DoCancel() called. Cancelling session")));
       
  1593 
       
  1594 	// Cancel any outstanding ops
       
  1595 	iFolderSync->Cancel();
       
  1596 	iCompound->Cancel();
       
  1597 	iSession->Cancel();
       
  1598 
       
  1599 	// Not doing nuffink
       
  1600 	iState=ESyncStateIdle;
       
  1601 
       
  1602 	// Parent
       
  1603 	CMsgActive::DoCancel();
       
  1604 	}