email/imap4mtm/imapsyncmanager/src/cimapfolder.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
child 52 12db4185673b
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 // Copyright (c) 2007-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 "cimapfolder.h"
       
    17 #include "cimapsyncmanager.h"
       
    18 #include "cimapsession.h"
       
    19 #include "cimaprfc822headerfields.h"
       
    20 #include "cimapbodystructure.h"
       
    21 #include "cimapfolderinfo.h"
       
    22 #include "cimapfolderindex.h"
       
    23 #include "cimaplogger.h"
       
    24 #include <numberconversion.h>
       
    25 #include <imcvcodc.h>
       
    26 #include <miutconv.h>
       
    27 #include "cimapmimeheaderfields.h"
       
    28 #include "cimapcharconv.h"
       
    29 
       
    30 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
       
    31 #include "cimconvertheader.h"
       
    32 #include "cimconvertcharconv.h"
       
    33 #endif
       
    34 
       
    35 // For first stage download (to view in folder list)
       
    36 _LIT8(KImapFetchHeaderToEnd, "%d:*");
       
    37 _LIT8(KImapFetchHeaderRange,"%d:%d");
       
    38 _LIT8(KImapFetchHeaderUIDRange,"UID %d:%d");
       
    39 _LIT8(KImapFetchHeaderRangeSearch,"%d:%d %S");
       
    40 _LIT8(KImapSmallHeaderFields,"Received Date Subject From Priority X-MSMail-Priority X-Priority Importance");
       
    41 //_LIT8(KImapLargeHeaderFields,"Received Date Subject From Reply-to To Cc Bcc Message-ID Priority %S");
       
    42 
       
    43 _LIT(KQuoteChar, "\\");
       
    44 _LIT(KIMAP_INBOX, "INBOX");
       
    45 
       
    46 _LIT8(KImapTxtImage, "IMAGE");
       
    47 _LIT8(KImapTxtAudio, "AUDIO");
       
    48 _LIT8(KImapTxtVideo, "VIDEO");
       
    49 _LIT8(KImapTxtApplication, "APPLICATION");
       
    50 _LIT8(KImapTxtRelated, "RELATED");
       
    51 _LIT8(KImapTxtAlternative, "ALTERNATIVE");
       
    52 _LIT8(KImapTxtMixed, "MIXED");
       
    53 _LIT8(KImapTxtHtml, "HTML");
       
    54 _LIT8(KImapTxtAttachment, "ATTACHMENT");
       
    55 _LIT8(KImapTxtCalendar, "CALENDAR");
       
    56 _LIT8(KImapTxtXVCalendar, "X-VCALENDAR");
       
    57 _LIT8(KImapTxtDeliveryStatus, "DELIVERY-STATUS");
       
    58 _LIT8(KImapTxtBase64, "BASE64");
       
    59 
       
    60 // IMAP Priority fields
       
    61 //_LIT8(KImapPriorityFieldsSearch, "Priority Priority X-MSMail-Priority Precedence Importance");
       
    62 
       
    63 // Constants
       
    64 const TInt KImapUidSearchSize = 400;
       
    65 const TInt KImapMaxIntChars = 11; // the maximum number of characters needed to represent a 32-bit unsigned integer as a string.
       
    66 
       
    67 
       
    68 // Efficient and SAFE way of comparing TBools which might have different integers representing TRUE
       
    69 inline TBool BoolsAreEqual( TBool aA, TBool aB )
       
    70 	{
       
    71 	return ((aA && aB) || (!aA && !aB));
       
    72 	}
       
    73 	
       
    74 inline TBool BoolsAreNotEqual( TBool aA, TBool aB )
       
    75 	{
       
    76 	return ((!aA || !aB) && (aA || aB));
       
    77 	}
       
    78 
       
    79 /**
       
    80 Constructor
       
    81 */
       
    82 CImapFolder::CImapFolder(CImapSyncManager& aSyncMan, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings)
       
    83 : CMsgActive(EPriorityStandard), 
       
    84 iSyncManager(aSyncMan),
       
    85 iServerEntry(aServerEntry),
       
    86 iImapSettings(aImapSettings),
       
    87 iHeaderConverter(CImapUtils::GetRef().Charconv().HeaderConverter())
       
    88 	{
       
    89 	}
       
    90 
       
    91 /**
       
    92 Destructor
       
    93 */
       
    94 CImapFolder::~CImapFolder()
       
    95 	{
       
    96 	iMatchingMessageIds.Reset();
       
    97 	iDeletedMessageIds.Reset();
       
    98 	iMissingMessageIds.Reset();
       
    99 	delete iSelection;
       
   100 	iFolderIndex->Reset();
       
   101 	iMessageFlagInfoArray.Reset();
       
   102 	delete iFolderIndex;
       
   103 	delete iCachedEntryData;
       
   104 	delete iClearSeenList;
       
   105 	delete iSetSeenList;
       
   106 	iFullFolderPath.Close();
       
   107 	}
       
   108 
       
   109 /**
       
   110 Static factory constructor
       
   111 
       
   112 @param aSyncMan
       
   113 Reference to the owning Sync Manager (for access to offline control object)
       
   114 @param aEmailServerEntry
       
   115 The folder entry on the Message server that will be use to construct this folder object
       
   116 @return The constructed CImapFolder object pushed onto the cleanup stack
       
   117 */
       
   118 EXPORT_C CImapFolder* CImapFolder::NewLC(CImapSyncManager& aSyncMan, CMsvServerEntry& aServerEntry, TMsvEmailEntry& aEmailEntry, CImapSettings& aImapSettings, const TDesC& aFullFolderPath)
       
   119 	{
       
   120 	CImapFolder* self=new (ELeave) CImapFolder(aSyncMan, aServerEntry, aImapSettings);
       
   121 	CleanupStack::PushL(self);
       
   122 
       
   123 	// Non-trivial constructor
       
   124 	self->ConstructL(aServerEntry, aEmailEntry, aFullFolderPath);
       
   125 	return self;
       
   126 	}
       
   127 
       
   128 /**
       
   129 Static factory constructor with cleanup
       
   130 
       
   131 @param aSyncMan
       
   132 Reference to the owning Sync Manager (for access to offline control object)
       
   133 @param aEmailServerEntry
       
   134 The folder entry on the Message server that will be use to construct this folder object
       
   135 @return The constructed CImapFolder object
       
   136 */
       
   137 EXPORT_C CImapFolder* CImapFolder::NewL(CImapSyncManager& aSyncMan, CMsvServerEntry& aServerEntry, TMsvEmailEntry& aEmailEntry, CImapSettings& aImapSettings, const TDesC& aFullFolderPath)
       
   138 	{
       
   139 	CImapFolder* self=NewLC(aSyncMan, aServerEntry, aEmailEntry, aImapSettings, aFullFolderPath);
       
   140 	CleanupStack::Pop();
       
   141 	return self;
       
   142 	}
       
   143 
       
   144 /**
       
   145 The non-trival constructor
       
   146 
       
   147 @param aEmailServerEntry
       
   148 The folder entry on the Message server that will be use to construct this folder object
       
   149 */
       
   150 void CImapFolder::ConstructL(CMsvServerEntry& /*aServerEntry*/, TMsvEmailEntry& aEmailEntry, const TDesC& aFullFolderPath)
       
   151 	{
       
   152 	iSessionFolderInfo = NULL;
       
   153 	iMailboxId = aEmailEntry.Id();
       
   154 	iMailboxSize = aEmailEntry.RemoteFolderEntries();
       
   155 	iFolderIndex = new (ELeave) CImapFolderIndex();
       
   156 	iSelection   = new (ELeave) CMsvEntrySelection();
       
   157 	iSyncLimit = KImImapSynchroniseAll;
       
   158 
       
   159 	// Set the Path of folder object
       
   160 	SetFullFolderPathL(aFullFolderPath) ;
       
   161 	
       
   162 	// We're an active object...
       
   163 	CActiveScheduler::Add(this);
       
   164 	}
       
   165 
       
   166 /**
       
   167 Sets the full path name of the folder from the service entry downwards. Layout as on the remote IMAP Server.
       
   168 Should only be use by the CImapSyncManager.
       
   169 
       
   170 @param aFullFolderPath
       
   171 The new path to use as the full path of the folder.
       
   172 */
       
   173 void CImapFolder::SetFullFolderPathL(const TDesC& aFullFolderPath)
       
   174 	{
       
   175 	iFullFolderPath.Close(); // discard any previous data
       
   176 	iFullFolderPath.CreateL(aFullFolderPath);
       
   177 	}
       
   178 
       
   179 /**
       
   180 Processing message loop for the active object. Called by the active scheduler.
       
   181 */
       
   182 void CImapFolder::DoRunL()
       
   183 	{
       
   184 	// Finish if any server errors.
       
   185 	if(iStatus.Int()!=KErrNone)
       
   186 		{
       
   187 		Complete(iStatus.Int());
       
   188 		return;
       
   189 		}
       
   190 
       
   191 	switch(iNextAction)
       
   192 		{
       
   193 	case CImapSyncManager::ESyncNew:
       
   194 		{
       
   195 		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Starting SynchroniseNewL");				
       
   196 		SynchroniseNewL();
       
   197 		return;
       
   198 		}
       
   199 	case CImapSyncManager::ESyncFlags:
       
   200 		{
       
   201 		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Syncing flags for local messages");
       
   202 
       
   203 		// Whenever iSavedSession->FetchBodyStructureAndHeadersL() is called, this is the next step 
       
   204 		// (although this step can be reached without calling FetchBodyStructureAndHeadersL())
       
   205 		// This means that OnFetchLD() may have been called, in which case there are 
       
   206 		// outstanding BULK entry operations that need to be completed here.
       
   207 		iServerEntry.CompleteBulk();
       
   208 
       
   209 		// If there were message flags that has been changed locally and need upadting on the remote server
       
   210 		// then do those first.
       
   211 		if(iSetSeenList)
       
   212 			{
       
   213 			if(ProcessSeenFlagsL(ESetSeenFlag))
       
   214 				{
       
   215 				return;
       
   216 				}
       
   217 			}
       
   218 
       
   219 		if(iClearSeenList)
       
   220 			{
       
   221 			if(ProcessSeenFlagsL(EClearSeenFlag))
       
   222 				{
       
   223 				return;
       
   224 				}
       
   225 			}
       
   226 
       
   227 		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Syncing flags for remote messages");
       
   228 		// Creates the list of old messages then update the flags for them
       
   229 		GetMessageChildrenL(iMailboxId, iSelection);
       
   230 		MakeSortedFolderIndexL(ETrue);
       
   231 	
       
   232 		if(iSelection->Count() > 0)
       
   233 			{
       
   234 			iHighestUid = (*iFolderIndex)[iSelection->Count()-1].iUid;
       
   235 			}
       
   236 		else
       
   237 			{
       
   238 			iHighestUid = 0;
       
   239 			}
       
   240 
       
   241 		TInt localcount = iFolderIndex->Size();
       
   242 		iMatchingMessageIds.Reset();
       
   243 		for(TInt localloop = 0; localloop < localcount; ++localloop)
       
   244 			{
       
   245 			TMsvId localid = (*iFolderIndex)[localloop].iUid;
       
   246 			iMatchingMessageIds.Append(localid);
       
   247 			}
       
   248 			
       
   249 		iMessageFlagInfoArray.Reset();
       
   250 		
       
   251 		HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(iMatchingMessageIds);
       
   252 		
       
   253 		// Call the FETCHFLAGS function in the session
       
   254 		iNextAction = CImapSyncManager::EEndSyncFlags;
       
   255 		iSavedSession->FetchFlagsL(iStatus, *sequenceSetOnHeap, iMessageFlagInfoArray);
       
   256 		SetActive();
       
   257 		CleanupStack::PopAndDestroy(sequenceSetOnHeap);
       
   258 		}
       
   259 		break;		
       
   260 	case CImapSyncManager::EEndSyncFlags:
       
   261 		{
       
   262 		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Call to get the remote flags completed");
       
   263 		// Loop through the messages array and update the flags for each UID returned
       
   264 		// Get a clean version of the folder children
       
   265 		TInt resultscount = iMessageFlagInfoArray.Count();
       
   266 		for(TInt resultsloop = 0; resultsloop < resultscount; ++resultsloop)
       
   267 			{
       
   268 			TMessageFlagInfo *messageinfo = &(iMessageFlagInfoArray[resultsloop]);
       
   269 
       
   270 			TInt localmsgcount = iFolderIndex->Size();
       
   271 			// For each returned Uid go through the list of local index to find the matching TMsvId.
       
   272 			for(TInt localloop = 0; localloop < localmsgcount; ++localloop)
       
   273 				{
       
   274 				if((*iFolderIndex)[localloop].iUid == messageinfo->MessageUid())
       
   275 					{
       
   276 					SetEntryL((*iFolderIndex)[localloop].iMsvId);
       
   277 					TMsvEmailEntry entry = iServerEntry.Entry();
       
   278 
       
   279 					TBool messageInfoSeen = messageinfo->QueryFlag(TMessageFlagInfo::ESeen);
       
   280 					TBool oldEntrySeen = entry.SeenIMAP4Flag();
       
   281 
       
   282 					// Are we configured to update the \seen flag on the server?
       
   283 					// If so then we need to translate "read\unread" flags into "\\seen" or not "\\seen"
       
   284 					if (iImapSettings.UpdatingSeenFlags())
       
   285 						{
       
   286 						// Make a note to update the servers \Seen flag if "read\unread" has CHANGED on the client
       
   287 						// and is different to the server's version
       
   288 						if (BoolsAreEqual(entry.Unread(), messageInfoSeen) && BoolsAreEqual(oldEntrySeen, messageInfoSeen))
       
   289 							{
       
   290 							if (entry.Unread())
       
   291 								{
       
   292 								AppendClearSeenL(entry.UID());
       
   293 								}
       
   294 							else
       
   295 								{
       
   296 								AppendSetSeenL(entry.UID());
       
   297 								}								
       
   298 							}
       
   299 						}
       
   300 
       
   301 					entry.SetSeenIMAP4Flag(messageInfoSeen);
       
   302 					entry.SetFlaggedIMAP4Flag(messageinfo->QueryFlag(TMessageFlagInfo::EFlagged));
       
   303 					entry.SetDeletedIMAP4Flag(messageinfo->QueryFlag(TMessageFlagInfo::EDeleted));
       
   304 					entry.SetDraftIMAP4Flag(messageinfo->QueryFlag(TMessageFlagInfo::EDraft));
       
   305 					entry.SetRecentIMAP4Flag(messageinfo->QueryFlag(TMessageFlagInfo::ERecent));
       
   306 					
       
   307 					// Are we configured to update the \seen flag on the server?
       
   308 					if (iImapSettings.UpdatingSeenFlags())
       
   309 						{
       
   310 						// Now copy the inverse of the \Seen flag down to the phone's Unread flag 
       
   311 						//  except when LastSyncSeen is set (ie when the client version is more up to date)
       
   312 						//  This means that the client Read status ALWAYS reflects the IMAP \Seen state
       
   313 						if (BoolsAreEqual(entry.Unread(), messageInfoSeen) 		&& BoolsAreNotEqual(oldEntrySeen, messageInfoSeen))
       
   314 							{
       
   315 							// Phone and server disagree on whether the message has been read.
       
   316 							// And the seen flag on the server is different to that on the phone.
       
   317 							// Which means that a change has happened on the server that the phone was not aware of.
       
   318 							// So server is more up to date, and we take its value.
       
   319 							entry.SetUnread(!messageInfoSeen);
       
   320 							}
       
   321 						}
       
   322 					
       
   323 					ChangeEntryBulkL(entry); // completed after the outer for loop
       
   324 					break;
       
   325 					}
       
   326 				} // end of inner for loop
       
   327 			}
       
   328 			
       
   329 		iServerEntry.CompleteBulk();
       
   330 		
       
   331 		iNextAction = CImapSyncManager::ESyncProcessSeenFlagsAndComplete;
       
   332 		SetActive();
       
   333 		CompleteSelf();
       
   334 		}
       
   335 		break;		
       
   336 	case CImapSyncManager::ESyncProcessSeenFlagsAndComplete:
       
   337 		{
       
   338 		// If there were message flags that has been changed locally and need upadting on the remote server
       
   339 		// then do those now.
       
   340 		if(iSetSeenList)
       
   341 			{
       
   342 			if(ProcessSeenFlagsL(ESetSeenFlag))
       
   343 				{
       
   344 				return;
       
   345 				}
       
   346 			}
       
   347 
       
   348 		if(iClearSeenList)
       
   349 			{
       
   350 			if(ProcessSeenFlagsL(EClearSeenFlag))
       
   351 				{
       
   352 				return;
       
   353 				}
       
   354 			}
       
   355 			
       
   356 		SyncCompleteL();
       
   357 		Complete(iStatus.Int());
       
   358 		}
       
   359 		break;
       
   360 	case CImapSyncManager::ESyncSearch:
       
   361 		{
       
   362 		if(iStatus == KErrNone) 
       
   363 			{
       
   364 			if(iSyncState == CImapSyncManager::ESyncSearch)
       
   365 				{
       
   366 				// Process the seach results to see if any messages ids are left.
       
   367 				if(CheckAndProgressMessageSyncL())
       
   368 					{
       
   369 					// More messages and the search command has been sent so just return.
       
   370 					return;
       
   371 					}
       
   372 				}
       
   373 				
       
   374 			// If the sync action is syncing old messages then go through the list of found ids
       
   375 			// match it with the folder index and build a list of messages that are no longer on the server.
       
   376 			if(iSyncState == CImapSyncManager::ESyncOld)
       
   377 				{
       
   378 				// At this point the remote command to search out folder UIDs has completed. This
       
   379 				// list will contain all UIDs for messages in the remote folder. This may be too
       
   380 				// many, and if so, the list is truncated to only include the N most recent 
       
   381 				// messages in accordance with the synchronisation limit.
       
   382 
       
   383 				TInt syncThresh = GetSyncThreshold();
       
   384 				__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Syncing old. syncThresh = %d", syncThresh));
       
   385 
       
   386 				// Perform the check on the message ids to make sure that only messages that are within
       
   387 				// the sync limit will be left in iDeletedMessageIds.
       
   388 				CheckMessagesInRangeL(syncThresh);
       
   389 				
       
   390 				// Check the delete ids list and delete messages according to what's in the list	
       
   391 				TInt deletedcount = iDeletedMessageIds.Count();
       
   392 				// Remove message from the local server
       
   393 				for(TInt deleteloop = 0; deleteloop < deletedcount; ++deleteloop)
       
   394 					{
       
   395 					__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Local message (%d) deleting.", (*iFolderIndex)[iDeletedMessageIds[deleteloop]].iMsvId));
       
   396 					DeleteMessageL((*iFolderIndex)[iDeletedMessageIds[deleteloop]].iMsvId);
       
   397 					}
       
   398 
       
   399 				// Trim the list down to the most recent UIDs consistant with the sync limit.
       
   400 				if(iMatchingMessageIds.Count() > syncThresh)
       
   401 					{
       
   402 					for(TInt i = 0; i < syncThresh; ++i)
       
   403 						{
       
   404 						iMatchingMessageIds.Remove(0);
       
   405 						}
       
   406 					}
       
   407 
       
   408 				// Get a clean version of the folder children
       
   409 				GetMessageChildrenL(iMailboxId, iSelection);
       
   410 				
       
   411 				//update the progress object
       
   412 				iMsgsToDo = iMatchingMessageIds.Count();
       
   413 				
       
   414 				MakeSortedFolderIndexL(ETrue);
       
   415 			
       
   416 				if(iSelection->Count() > 0)
       
   417 					{
       
   418 					iHighestUid = (*iFolderIndex)[iSelection->Count()-1].iUid;
       
   419 					}
       
   420 				else
       
   421 					{
       
   422 					iHighestUid = 0;
       
   423 					}
       
   424 
       
   425 				// At this point, the remote command to fetch all old messages has completed. 
       
   426 				// Now we can look at fetching all new messages. 'iHighestUid' will contain the
       
   427 				// highest UID of the old messages. The top entry in 'iSearchList' will contain
       
   428 				// the highest UID in the remote folder. This gives us the range of UID to fetch
       
   429 				// for new messages.
       
   430 
       
   431 				// First check are there any new messages to fetch? If 'iHighestUid' is the highest
       
   432 				// UID locally and remotely, then we finished sync'ing when we completed the old
       
   433 				// sync.
       
   434 				if(iMatchingMessageIds.Count() == 0)
       
   435 					{
       
   436 					__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Search List is empty");				
       
   437 					}
       
   438 				else if(iHighestUid < iMatchingMessageIds[iMatchingMessageIds.Count()-1])
       
   439 					{
       
   440 					TUint32 uidLow = iHighestUid;
       
   441 					TUint32 uidHigh = iMatchingMessageIds[iMatchingMessageIds.Count()-1];
       
   442 
       
   443 					// Only want new messages.
       
   444 					uidLow++;
       
   445 
       
   446 					// Are there only new messages (and no old)?
       
   447 					if(iHighestUid == 0)
       
   448 						{
       
   449 						// Set this to ensure range is correct.
       
   450 						uidLow = iMatchingMessageIds[0];
       
   451 						}
       
   452 					
       
   453 					// Perform the new sync.
       
   454 					__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Synchronising new messages with range %d:%d", uidLow, uidHigh));
       
   455 					SynchroniseRangeL(uidLow, uidHigh);
       
   456 					return;
       
   457 					}
       
   458 
       
   459 				iSyncState = CImapSyncManager::ESyncNew;	
       
   460 				}
       
   461 
       
   462 			if((iSyncState == CImapSyncManager::ESyncNew) && (iImapSettings.SearchString().Length() == 0))
       
   463 				{
       
   464 				// Check for missing UIDs, ie. holes in the messages that we should have.
       
   465 				CheckForMissingMessagesUidsL();
       
   466 
       
   467 				// If there were any "missing" messages found during the sync that we should have
       
   468 				// mirrored previously, get these now.
       
   469 				if(iMissingMessageIds.Count() != 0)
       
   470 					{
       
   471 					__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Missing messages detected %d", iMissingMessageIds.Count()));
       
   472 					HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(iMissingMessageIds);
       
   473 					// Call the FETCH function in the session
       
   474 					iSavedSession->FetchBodyStructureAndHeadersL(iStatus, sequenceSetOnHeap->Des(), KImapSmallHeaderFields(), *this);
       
   475 					CleanupStack::PopAndDestroy(sequenceSetOnHeap);
       
   476 					SetActive();
       
   477 
       
   478 				 	iSyncState = CImapSyncManager::EFolderSynchronise;
       
   479 				 	iNextAction = CImapSyncManager::ESyncFlags;
       
   480 					return;
       
   481 					}
       
   482 
       
   483 				if(iSyncLimit <= KImImapSynchroniseAll)
       
   484 					{
       
   485 					__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Starting SynchroniseNewL");				
       
   486 					SynchroniseNewL();
       
   487 					return;
       
   488 					}
       
   489 				
       
   490 				// If we haven't returned yet, then no new messages to sync
       
   491 				// so just sync the flags of existing messages.
       
   492 				iSyncState = CImapSyncManager::EFolderSynchronise;
       
   493 			 	iNextAction = CImapSyncManager::ESyncFlags;
       
   494 			 	SetActive();
       
   495 			 	CompleteSelf();
       
   496 				return;
       
   497 				}
       
   498 			else
       
   499 				{
       
   500 				SyncCompleteL();
       
   501 				Complete(iStatus.Int());
       
   502 				}
       
   503 			}
       
   504 		}
       
   505 		break;
       
   506 	case CImapSyncManager::EFolderExpunge:
       
   507 		{
       
   508 		// Call expunge to delete messages marked for delete
       
   509 		__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: calling EXPUNGE in folder %S", &iFullFolderPath));
       
   510 
       
   511 		iSyncState = CImapSyncManager::EFolderExpunge;
       
   512 		iNextAction = CImapSyncManager::EFolderLocalExpunge;
       
   513 		iSavedSession->ExpungeL(iStatus);
       
   514 		SetActive();
       
   515 		}
       
   516 		break;
       
   517 	case CImapSyncManager::EFolderClose:
       
   518 		{
       
   519 		//Permanently removes all messages that have the deleted flag set
       
   520 		//from the currently selected mailbox
       
   521 		iSyncState = CImapSyncManager::EFolderClose;
       
   522 		iNextAction = CImapSyncManager::EFolderReSelect;
       
   523 		iSavedSession->CloseL(iStatus);
       
   524 		SetActive();
       
   525 		}
       
   526 		break;
       
   527 	case CImapSyncManager::EFolderReSelect:
       
   528 		{
       
   529 		//Selecting a mailbox so that messages in the mailbox can be accessed. 
       
   530 		iSyncState = CImapSyncManager::EFolderReSelect;
       
   531 		iNextAction = CImapSyncManager::EFolderLocalExpunge;
       
   532 		SelectL(iStatus, *iSavedSession);
       
   533 		SetActive();
       
   534 		}
       
   535 		break;
       
   536 	case CImapSyncManager::EFolderLocalExpunge:
       
   537 		{
       
   538 		// delete local messages locally
       
   539 		__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: local message delete in folder %S", &iFullFolderPath));
       
   540 		
       
   541 		// Check the delete ids list and delete messages according to what's in the list	
       
   542 		TInt deletedcount = iDeletedMessageIds.Count();
       
   543 		// Remove message from the local server
       
   544 		for(TInt deleteloop = 0; deleteloop < deletedcount; ++deleteloop)
       
   545 			{
       
   546 			__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Local message (%d) deleting.", (*iFolderIndex)[iDeletedMessageIds[deleteloop]].iMsvId));
       
   547 			DeleteMessageL((*iFolderIndex)[iDeletedMessageIds[deleteloop]].iMsvId);
       
   548 			}
       
   549 			
       
   550 		// clear the count of expunged messages to prevent a sync triggering
       
   551 		CImapFolderInfo* folderInfo = iSavedSession->SelectedFolderInfo();
       
   552 		if (folderInfo->ExpungedMessages().Count()==deletedcount)
       
   553 			{
       
   554 			folderInfo->ResetExpungedMessages();
       
   555 
       
   556 			// store updated remote mailbox size.
       
   557 			iMailboxSize = folderInfo->Exists();
       
   558 			SetEntryL(iMailboxId);
       
   559 			TMsvEmailEntry entry = iServerEntry.Entry();
       
   560 			entry.SetRemoteFolderEntries(folderInfo->Exists());
       
   561 			ChangeEntryL(entry);
       
   562 			}
       
   563 
       
   564 		iSyncState = CImapSyncManager::EFolderLocalExpunge;
       
   565 		iNextAction = CImapSyncManager::ENotSyncing;
       
   566 		}
       
   567 		// fall through...
       
   568 	case CImapSyncManager::ENotSyncing:
       
   569 		{
       
   570 		iSyncState = CImapSyncManager::ENotSyncing;
       
   571 		Complete(iStatus.Int());
       
   572 		}
       
   573 		break;
       
   574 	default:
       
   575 		break;
       
   576 		}
       
   577 	}
       
   578 
       
   579 /**
       
   580 Processing of the returned message ids after the completion of the IMAP SEARCH command.
       
   581 If there are more messages ids to be look at then the SEARCH commands will be call again.
       
   582 This call could set this folder object active
       
   583 
       
   584 @return ETrue if the call has resulted in the folder object being made Active.
       
   585 */
       
   586 TBool CImapFolder::CheckAndProgressMessageSyncL()
       
   587 	{
       
   588 	iFolderPosition += KImapUidSearchSize;
       
   589 
       
   590 	__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Session Search command completed: %d", iFolderPosition));
       
   591 
       
   592 	// Check to see if we have all the messages.
       
   593 	if(iFolderPosition >= iMailboxSize)
       
   594 		{
       
   595 		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: UID search complete");
       
   596 
       
   597 		//update the progress object
       
   598 		iMsgsToDo = iMatchingMessageIds.Count();
       
   599 
       
   600 		iSyncState = CImapSyncManager::ESyncOld;
       
   601 		// We have the full list of remote UIDs - fall through.
       
   602 		}
       
   603 	else
       
   604 		{
       
   605 		// Should be able to hit this code if KImapUidSearchSize is reduced to < the size
       
   606 		// of the remote mailbox (iMailboxSize)
       
   607 		// SearchString non 0 means a refined UID SEARCH is required
       
   608 		
       
   609 		if(iImapSettings.SearchString().Length() != 0)
       
   610 			{
       
   611 			// Refined search required
       
   612 			// Still uses the indexes but appends user specified search criteria
       
   613 			RBuf8 tempstr;
       
   614 			tempstr.CleanupClosePushL();
       
   615 					
       
   616 			TPtrC8 searchstr = iImapSettings.SearchString();
       
   617 			
       
   618 			TInt tempstrLen = KImapFetchHeaderRangeSearch().Length() + KImapMaxIntChars + KImapMaxIntChars + searchstr.Length();
       
   619  			tempstr.CreateL(tempstrLen);			
       
   620 			tempstr.Format(KImapFetchHeaderRangeSearch, iFolderPosition+1, Min(iMailboxSize,iFolderPosition+KImapUidSearchSize), &searchstr);
       
   621 			
       
   622 			__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Refined UID search - get next manageable block of UIDs: %S", &tempstr));
       
   623 			iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
       
   624 			
       
   625 			// Go active
       
   626 			SetActive();
       
   627 			
       
   628 			CleanupStack::PopAndDestroy(&tempstr);
       
   629 			return ETrue;
       
   630 			}
       
   631 		else
       
   632 			{
       
   633 			// Normal unrefined SEARCH. Will pull back all the UIDs between indexes
       
   634 			// Perform a UID search on this folder.
       
   635 			RBuf8 tempstr;
       
   636 			tempstr.CleanupClosePushL();
       
   637 				
       
   638 			TInt tempstrLen = KImapFetchHeaderRange().Length() + KImapMaxIntChars + KImapMaxIntChars;
       
   639 			tempstr.CreateL(tempstrLen);
       
   640 			tempstr.Format(KImapFetchHeaderRange, iFolderPosition+1, Min(iMailboxSize,iFolderPosition+KImapUidSearchSize));
       
   641 			
       
   642 			__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Unrefined UID search - get next manageable block of UIDs: %S", &tempstr));
       
   643 			iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
       
   644 			
       
   645 			// Go active
       
   646 			SetActive();
       
   647 			
       
   648 			CleanupStack::PopAndDestroy(&tempstr);
       
   649 			return ETrue;
       
   650 			}
       
   651 		}
       
   652 	return EFalse;
       
   653 	}
       
   654 
       
   655 /**
       
   656 Sets number of messages to be sync. If there is a search string or the sync limit is outside
       
   657 the mailbox size then everything will be sync. i.e. the sync limit will be set to 0.
       
   658 
       
   659 */
       
   660 TInt CImapFolder::GetSyncThreshold()
       
   661 	{
       
   662 	// If no UID Search string defined then the old logic is used
       
   663 	if((iImapSettings.SearchString().Length() == 0) && (iSyncLimit > KImImapSynchroniseAll))
       
   664 		{	
       
   665 		if(iSyncLimit < iMailboxSize)
       
   666 			{
       
   667 			return (iMailboxSize - iSyncLimit);
       
   668 			}
       
   669 		}
       
   670 
       
   671 	return 0;
       
   672 	}
       
   673 
       
   674 /**
       
   675 Go through the list of found message ids and work out if each message is within the sync limit
       
   676 as defined by the user. If a message isn't within the limit it will be removed if it hasn't been fetched.
       
   677 
       
   678 @param aSyncThreshold
       
   679 The number of messages that will define the sync limit
       
   680 */
       
   681 void CImapFolder::CheckMessagesInRangeL(TInt aSyncThreshold)
       
   682 	{
       
   683 	// At this stage (prior to truncation), we have a full list of all the message
       
   684 	// UIDs in the remote folder. We also have a list of all UIDs for messages in
       
   685 	// the local folder. With these lists, we can establish which local messages
       
   686 	// have been orphaned and which have not using the following rules.
       
   687 
       
   688 	// * If the remote message is no longer there:
       
   689 	//		(1) Then the local message is orphaned (always).
       
   690 	// * If the remote message is still there and it is not one of the N most recent:
       
   691 	//		(2) If the local message has body parts do nothing. - This Check has been removed as per new CMail UI.
       
   692 	//		(3) If the local message does not have body parts, then it is orphaned
       
   693 	//		    unless is is a message we have selected for download.
       
   694 	// * If the remote message is still there and it is one of the N most recent:
       
   695 	//		(4) Do nothing.
       
   696 
       
   697 	// Search through the local folder list while checking the remote folder list.
       
   698 
       
   699 	TInt localcount = iFolderIndex->Size();
       
   700 	TInt resultscount = iMatchingMessageIds.Count();
       
   701 
       
   702 	iFolderPosition = 0;
       
   703 
       
   704 	iDeletedMessageIds.Reset();
       
   705 	
       
   706 	for(TInt localloop = 0; localloop < localcount; ++localloop)
       
   707 		{
       
   708 		// Go through the list of index, if can't find matching in found ids then mark for delete.
       
   709 		TInt resultsloop = 0;//listprogress;
       
   710 		TBool removeThis = EFalse;
       
   711 		TBool folderPositionFound = EFalse;
       
   712 
       
   713 		while(resultsloop < resultscount)
       
   714 			{
       
   715 			TUint remoteUid = iMatchingMessageIds[resultsloop];
       
   716 			TUint localUid = (*iFolderIndex)[localloop].iUid;
       
   717 
       
   718 			// Check the synclimit
       
   719 			TBool inSyncRange = (resultsloop >= aSyncThreshold);
       
   720 			if((remoteUid > localUid) || (remoteUid > iHighestUid))
       
   721 				{
       
   722 				break;
       
   723 				}
       
   724 			if(remoteUid == localUid)
       
   725 				{
       
   726 				// Found id, sets new lower limit then exit loop
       
   727 				folderPositionFound = ETrue;
       
   728 				
       
   729 				// Check for if message is in the syncrange
       
   730 				if(!inSyncRange)
       
   731 					{
       
   732 					// Here the remote uid matches the local uid, but the message falls outside
       
   733 					// of the N most recent messages. See cases (2) & (3).
       
   734 					SetEntryL((*iFolderIndex)[localloop].iMsvId);
       
   735 					TMsvEmailEntry message(iServerEntry.Entry());
       
   736 					// Does message have any downloaded parts?
       
   737 					// The local message does not have any body parts and
       
   738 					// is not selected for download, so it is orphaned.
       
   739 					// See case (3) above.
       
   740 					__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Local message (%d) is only header and not selected for download, deleting", (*iFolderIndex)[localloop].iMsvId));
       
   741 					removeThis = ETrue;
       
   742 					iOrphanedMessages++;
       
   743 					}
       
   744 				break;
       
   745 				}
       
   746 
       
   747 			++resultsloop;
       
   748 			}
       
   749 		if(!folderPositionFound || removeThis)
       
   750 			{
       
   751 			// Saved the index position of the message to be deleted from the local view
       
   752 			__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Local message (%d) marked for deleting, loop = %d", (*iFolderIndex)[localloop].iMsvId, localloop));
       
   753 			iDeletedMessageIds.Append(localloop);
       
   754 			}
       
   755 		else
       
   756 			{
       
   757 				iMsgsDone++;
       
   758 			}
       
   759 			
       
   760 		}
       
   761 	
       
   762 	}
       
   763 	
       
   764 
       
   765 /**
       
   766 Go through the list of found remote message ids and work out if each message header has been fetched or not.
       
   767 Messages that are missing from the local index will be added to a list of messages to be fetch.
       
   768 */
       
   769 void CImapFolder::CheckForMissingMessagesUidsL()
       
   770 	{
       
   771 	iMissingMessageIds.Reset();
       
   772 
       
   773 	if(iFolderIndex->Size() == 0)
       
   774 		{
       
   775 		return;
       
   776 		}
       
   777 		
       
   778 	TInt remotecount = iMatchingMessageIds.Count();
       
   779 
       
   780 	for(TInt remoteloop = 0; remoteloop < remotecount; ++remoteloop)
       
   781 		{
       
   782 		TUint remoteUid = iMatchingMessageIds[remoteloop];
       
   783 
       
   784 		if(iFolderIndex->FindMsg(remoteUid) == 0)
       
   785 			{
       
   786 			iMissingMessageIds.Append(remoteUid);
       
   787 			}
       
   788 		}
       
   789 	}
       
   790 /**
       
   791 Cancels any outstanding asynchronous service requests.
       
   792 */
       
   793 void CImapFolder::DoCancel()
       
   794 	{
       
   795 	iSavedSession->Cancel();
       
   796 	CMsgActive::DoCancel();
       
   797 	}
       
   798 
       
   799 /**
       
   800 Called when the requested operation is completed.
       
   801 Cleans up data members used only during synchronisation
       
   802 */
       
   803 void CImapFolder::DoComplete(TInt& /*aStatus*/)
       
   804 	{
       
   805 	iCachedEntryData->Reset();
       
   806 	iSelection->Reset();
       
   807 	iFolderIndex->Reset();
       
   808 	iMatchingMessageIds.Reset();
       
   809 	iDeletedMessageIds.Reset();
       
   810 	iMessageFlagInfoArray.Reset();
       
   811 
       
   812 	// iSessionFolderInfo is not owned by this class,
       
   813 	// Set to NULL as it should never be assumed to exist.
       
   814 	iSessionFolderInfo = NULL;
       
   815 	}
       
   816 
       
   817 /**
       
   818 Returns the full mailbox path description from the Message server
       
   819 
       
   820 @return Pointer to the descriptor object
       
   821 */
       
   822 EXPORT_C TDesC& CImapFolder::FullFolderPathL()
       
   823 	{
       
   824 	if(iFullFolderPath.Length() == 0)
       
   825 		{
       
   826 		HBufC16* temp = MakePathL(ETrue);
       
   827 		iFullFolderPath.Close();
       
   828 		iFullFolderPath.Assign(temp);
       
   829 		}
       
   830 
       
   831 	return iFullFolderPath;
       
   832 	}
       
   833 
       
   834 /**
       
   835 Returns the mailbox uid from the Message server
       
   836 
       
   837 @return The mailbox UID;
       
   838 */
       
   839 EXPORT_C TMsvId CImapFolder::MailboxId()
       
   840 	{
       
   841 	return iMailboxId;
       
   842 	}
       
   843 
       
   844 /**
       
   845 Issue the IMAP select command to select this folder using the supplied session.
       
   846 The session must already have been opened and connected.
       
   847 
       
   848 NOTE:  The client TRequestStatus is passed through to the CImapSession.
       
   849        Therefore a CImapSession::Cancel() must be called to cancel the
       
   850        SELECT operation.
       
   851 NOTE:  UpdateSessionFolderInfoL() should be called following completion
       
   852 	   of the select operation. And definitely prior to synchronising
       
   853 	   the folder (see below)
       
   854 
       
   855 @param aStatus 
       
   856 The status request object to be use to send the completion signal. 
       
   857 This is passed through to the session object.
       
   858 @param aSession 
       
   859 The session to be use for the SELECT command
       
   860 */
       
   861 EXPORT_C void CImapFolder::SelectL(TRequestStatus& aStatus, CImapSession& aSession, TBool aSelectInbox)
       
   862 	{
       
   863 	// Construct the info object for the select command then just pass it on.
       
   864 	CImapFolderInfo* folderInfo = CImapFolderInfo::NewL();
       
   865 	CleanupStack::PushL(folderInfo);
       
   866 	folderInfo->SetMsvId(iMailboxId);
       
   867 	folderInfo->SetNameL(FullFolderPathL());
       
   868 	
       
   869 	// Issue the SELECT - the session takes immediate 
       
   870 	// ownership of the folder info object.
       
   871 	CleanupStack::Pop(folderInfo);
       
   872 	aSession.SelectL(aStatus, folderInfo, aSelectInbox);
       
   873 	}
       
   874 
       
   875 
       
   876 /**
       
   877 Issue the IMAP select command to select this folder using the supplied session.
       
   878 The session must already have been opened and connected.
       
   879 
       
   880 NOTE:  The client TRequestStatus is passed through to the CImapSession.
       
   881        Therefore a CImapSession::Cancel() must be called to cancel the 
       
   882        EXAMINE operation.
       
   883 NOTE:  UpdateSessionFolderInfoL() should be called following completion
       
   884 	   of the EXAMINE operation.
       
   885 
       
   886 @param aStatus 
       
   887 The status request object to be use to send the completion signal. 
       
   888 This is passed through to the session object.
       
   889 @param aSession 
       
   890 The session to be use for the EXAMINE command
       
   891 */
       
   892 EXPORT_C void CImapFolder::ExamineL(TRequestStatus& aStatus, CImapSession& aSession)
       
   893 	{
       
   894 	// Construct the info object for the select command then just pass it on.
       
   895 	CImapFolderInfo* folderInfo = CImapFolderInfo::NewL();
       
   896 	CleanupStack::PushL(folderInfo);
       
   897 	folderInfo->SetMsvId(iMailboxId);
       
   898 	folderInfo->SetNameL(FullFolderPathL());
       
   899 	
       
   900 	// Issue the EXAMINE - the session takes immediate 
       
   901 	// ownership of the folder info object.
       
   902 	CleanupStack::Pop(folderInfo);
       
   903 	aSession.ExamineL(aStatus, folderInfo);
       
   904 	}
       
   905 
       
   906 /**
       
   907 Updates the remote folder mirror with status information about the folder 
       
   908 on the remote server. Called at the start of the synchronisation process.
       
   909 
       
   910 Panics if the folder is not selected folder on the passed session.
       
   911 
       
   912 NOTE: MUST be called prior to synchronising (done internally)
       
   913 
       
   914 NOTE: updates the context of the CMsvServerEntry to the folder.
       
   915 
       
   916 @param aSession - the session that has SELECTed this folder
       
   917 */
       
   918 EXPORT_C void CImapFolder::UpdateSessionFolderInfoL(CImapSession& aSession)
       
   919 	{
       
   920 	iSessionFolderInfo = aSession.SelectedFolderInfo();
       
   921 	if(iSessionFolderInfo)
       
   922 		{
       
   923 		__ASSERT_ALWAYS(iSessionFolderInfo->MsvId()==iMailboxId, User::Invariant());
       
   924 		
       
   925 		iMailboxSize = iSessionFolderInfo->Exists();
       
   926 		// Need to be save away. NOT Done on Session.
       
   927 		SetEntryL(iMailboxId);
       
   928 		TMsvEmailEntry entry = iServerEntry.Entry();
       
   929 		entry.SetRemoteFolderEntries(iSessionFolderInfo->Exists());
       
   930 		if(entry.UID() != iSessionFolderInfo->UidValidity())
       
   931 			{
       
   932 			entry.SetValidUID(EFalse);
       
   933 			}
       
   934 		entry.SetRecentIMAP4Flag(iSessionFolderInfo->Recent());
       
   935 		entry.SetUnreadIMAP4Flag(iSessionFolderInfo->Unseen());
       
   936 		ChangeEntryL(entry);
       
   937 		}
       
   938 	}
       
   939 
       
   940 /**
       
   941 This can be called at any time with a given IMAP session to find out if the folder has 
       
   942 changed in any way since the last sync.
       
   943 
       
   944 Panics if the folder is not selected folder on the passed session.
       
   945 
       
   946 @return
       
   947 Returns true if any of Exists, Recent or Expunged counts are non-zero.
       
   948 */
       
   949 EXPORT_C TBool CImapFolder::Changed(CImapSession& aSession)
       
   950 	{
       
   951 	iSessionFolderInfo = aSession.SelectedFolderInfo();
       
   952 	if(iSessionFolderInfo)
       
   953 		{
       
   954 		__ASSERT_ALWAYS(iSessionFolderInfo->MsvId()==iMailboxId, User::Invariant());
       
   955 
       
   956 		// True if the exists count has changed
       
   957 		// or if recent or expunged counts are non-zero
       
   958 		TBool existChanged = (iMailboxSize != iSessionFolderInfo->Exists());
       
   959 		TBool flagChanged = iSessionFolderInfo->MessageFlagsChanged();
       
   960 		TBool otherChanged = (existChanged || 
       
   961 			     				iSessionFolderInfo->Recent() || 
       
   962 			     				iSessionFolderInfo->ExpungedMessages().Count());
       
   963 			     				
       
   964 		iFlagChangedOnly = (flagChanged && !(otherChanged));
       
   965 		
       
   966 		return ( otherChanged || flagChanged );
       
   967 		}
       
   968 	return EFalse;
       
   969 	}
       
   970 
       
   971 /**
       
   972 Clears the counts that indicate that an event has occurred on the remote server
       
   973 for the selected folder since the last sync operation.
       
   974 
       
   975 This method is called during synchronisation such that subsequent changes are
       
   976 identified.
       
   977 */
       
   978 void CImapFolder::ClearChangeCounts()
       
   979 	{
       
   980 	if(iSessionFolderInfo)
       
   981 		{
       
   982 		// Do not clear exists count 
       
   983 		iSessionFolderInfo->SetRecent(0);
       
   984 		iSessionFolderInfo->ResetExpungedMessages();
       
   985 		iSessionFolderInfo->SetMessageFlagsChanged(EFalse);
       
   986 		}
       
   987 	iFlagChangedOnly = EFalse;
       
   988 	}
       
   989 
       
   990 /** 
       
   991 Set the current entry context on the Message server
       
   992 
       
   993 @param aId
       
   994 The entry id to set in the Message server
       
   995 @leave KErrNotFound if the entry does not exist or KErrLocked if the entry is locked.
       
   996 */
       
   997 void CImapFolder::SetEntryL(const TMsvId aId)
       
   998 	{
       
   999 	User::LeaveIfError(iServerEntry.SetEntry(aId));
       
  1000 	}
       
  1001 
       
  1002 /**
       
  1003 Sets the context's index entry to the specified values on the Message server
       
  1004 
       
  1005 @param  aEntry
       
  1006 The new details for the entry.
       
  1007 @leave KErrAccessDenied - the entry is read only (deleted entry, standard folder, or locked); 
       
  1008 KErrNotSupported - aEntry is invalid or the ID specified in aEntry is not the same as the context ID
       
  1009 or no context has been set for the object; 
       
  1010 KErrNoMemory - a memory allocation failed. 
       
  1011 */
       
  1012 void CImapFolder::ChangeEntryL(const TMsvEntry& aEntry)
       
  1013 	{
       
  1014 	User::LeaveIfError(iServerEntry.ChangeEntry(aEntry));
       
  1015 	}
       
  1016 
       
  1017 /**
       
  1018 Change entry in bulk mode (i.e no index file commit. no notify)
       
  1019 
       
  1020 @param  aEntry
       
  1021 The new details for the entry.
       
  1022 @leave KErrAccessDenied - the entry is read only (deleted 
       
  1023 entry, standard folder, or locked); 
       
  1024 KErrNotSupported - aEntry is invalid or the 
       
  1025 ID specified in aEntry is not the same as the context ID or no context has been 
       
  1026 set for the object; 
       
  1027 KErrNoMemory - a memory allocation failed.
       
  1028 */
       
  1029 void CImapFolder::ChangeEntryBulkL(const TMsvEntry& aEntry)
       
  1030 	{
       
  1031 	User::LeaveIfError(iServerEntry.ChangeEntryBulk(aEntry));
       
  1032 	}
       
  1033 
       
  1034 /**
       
  1035 Get a list of ids of the children from the current context of the message server.
       
  1036 
       
  1037 @param aSelection
       
  1038 A reference to the email entries selection object which will be filled with the ids of the child entries.
       
  1039 @leave Error from CMsvServerEntry::GetChildren.
       
  1040 */
       
  1041 void CImapFolder::GetChildrenL(CMsvEntrySelection& aSelection)
       
  1042 	{
       
  1043 	User::LeaveIfError(iServerEntry.GetChildren(aSelection));
       
  1044 	}
       
  1045 
       
  1046 /**
       
  1047 Delete a local message.
       
  1048 
       
  1049 @param aMessage
       
  1050 The TMsvId of the message to be removed from the message server.
       
  1051 */
       
  1052 EXPORT_C void CImapFolder::DeleteMessageL(const TMsvId aMessage)
       
  1053 	{
       
  1054  	if(aMessage == KMsvNullIndexEntryId)
       
  1055 		{
       
  1056 		// Attempted delete of null entry
       
  1057  		return;
       
  1058 		}
       
  1059 	// Delete message and all subparts: first, move to parent
       
  1060 	SetEntryL(aMessage);
       
  1061 
       
  1062 	SetEntryL(iServerEntry.Entry().Parent());
       
  1063 
       
  1064 	// Do not leave when entry is in use 
       
  1065 	TInt err (iServerEntry.DeleteEntry(aMessage));
       
  1066 	if(err == KErrInUse)
       
  1067 		{
       
  1068 		// Dont leave if err = KErrInUse
       
  1069 		}
       
  1070 	else
       
  1071 		{
       
  1072 		User::LeaveIfError(err);
       
  1073 		}
       
  1074 	}
       
  1075 
       
  1076 /**
       
  1077 Add a message UID to the list of messages that should have the SEEN flag sets during the SYNC FLAGS stage.
       
  1078 
       
  1079 @param aMessage
       
  1080 The UID of the message to be added to the list of messages to have the SEEN flag set.
       
  1081 */
       
  1082 EXPORT_C void CImapFolder::AppendSetSeenL(const TUint32 aMessage)
       
  1083 	{
       
  1084 	if(iSetSeenList)
       
  1085 		{
       
  1086 		iSetSeenList->AppendL(aMessage);
       
  1087 		}
       
  1088 	else
       
  1089 		{
       
  1090 		iSetSeenList = new(ELeave) RArray<TUint>(4);
       
  1091 		iSetSeenList->AppendL(aMessage);
       
  1092 		}
       
  1093 	}
       
  1094 	
       
  1095 /**
       
  1096 Add a message UID to the list of messages that should have the SEEN flag cleared during the SYNC FLAGS stage.
       
  1097 
       
  1098 @param aMessage
       
  1099 The UID of the message to be added to the list of messages to have the SEEN flag cleared.
       
  1100 */
       
  1101 EXPORT_C void CImapFolder::AppendClearSeenL(const TUint32 aMessage)
       
  1102 	{
       
  1103 	if(iClearSeenList)
       
  1104 		{
       
  1105 		iClearSeenList->AppendL(aMessage);
       
  1106 		}
       
  1107 	else
       
  1108 		{
       
  1109 		iClearSeenList = new(ELeave) RArray<TUint>(4);
       
  1110 		iClearSeenList->AppendL(aMessage);
       
  1111 		}
       
  1112 	}
       
  1113 
       
  1114 /**
       
  1115 Get MESSAGE ONLY children of a folder. Ignore shadows as they are not going to be synced against the server
       
  1116 */
       
  1117 void CImapFolder::GetMessageChildrenL(const TMsvId aFolder, CMsvEntrySelection* aChildren)
       
  1118 	{	
       
  1119 	aChildren->Reset();
       
  1120 	// Get *all* the children
       
  1121 	SetEntryL(aFolder);
       
  1122 	GetChildrenL(*aChildren);
       
  1123 
       
  1124 	delete iCachedEntryData;
       
  1125 	iCachedEntryData = NULL;
       
  1126 
       
  1127 	iCachedEntryData = new(ELeave) RArray<TMsvCacheData>(5);
       
  1128 
       
  1129 	// Go through them, checking to see if they're messages and removing ones that aren't
       
  1130 	TInt pos = 0;
       
  1131 	while(pos < aChildren->Count())
       
  1132 		{
       
  1133 		TMsvEntry* entryPtr;
       
  1134 		TMsvId id = (*aChildren)[pos];
       
  1135 		User::LeaveIfError(iServerEntry.GetEntryFromId(id, entryPtr));
       
  1136 
       
  1137 		// Is it a message? And is it real (not shadow)
       
  1138 		if(entryPtr->iType != KUidMsvMessageEntry ||
       
  1139 			entryPtr->iRelatedId != KMsvNullIndexEntryId )
       
  1140 			{
       
  1141 			// No, remove it
       
  1142 			aChildren->Delete(pos,1);
       
  1143 			}
       
  1144 		else
       
  1145 			{
       
  1146 			//cache two parts of the TMsvEntry data to avoid having to refind it later
       
  1147 			TMsvCacheData data;
       
  1148 			data.iOrphan = ((TMsvEmailEntry)(*entryPtr)).Orphan();
       
  1149 			data.iUid = ((TMsvEmailEntry)(*entryPtr)).UID();
       
  1150 			iCachedEntryData->AppendL(data);
       
  1151 			// Next entry
       
  1152 			pos++;
       
  1153 			}
       
  1154 		}
       
  1155 	}
       
  1156 
       
  1157 /**
       
  1158 Populates the entry selection with messages that are eligible for auto-fetch.
       
  1159 Auto fetch is performed as a second synchronisation stage, following the header
       
  1160 synchronisation. Eligible messages are synchronised according to defined 
       
  1161 download rules. Note that this method does not filter the returned entry
       
  1162 selection according to these rules.
       
  1163 
       
  1164 @return TInt - number of meesages in the updated selection
       
  1165 */
       
  1166 EXPORT_C TInt CImapFolder::GetFetchMessageChildrenL(CMsvEntrySelection& aSelection)
       
  1167 	{	
       
  1168 	aSelection.Reset();
       
  1169 	// Get *all* the children
       
  1170 	SetEntryL(iMailboxId);
       
  1171 	GetChildrenL(aSelection);
       
  1172 
       
  1173 	// Go through them, checking to see if they're messages and removing ones that aren't
       
  1174 	TInt pos = 0;
       
  1175 	TMsvEntry* entryPtr;
       
  1176 	while(pos < aSelection.Count())
       
  1177 		{
       
  1178 		TMsvId id = (aSelection)[pos];
       
  1179 		User::LeaveIfError(iServerEntry.GetEntryFromId(id, entryPtr));
       
  1180 
       
  1181 		// Remove entry from the selection if:
       
  1182 		//   It is not a message
       
  1183 		//   It is not real (ie it is a shadow entry)
       
  1184 		//   If has been previously fetched.
       
  1185 		TBool previouslyFetched = ((TMsvEmailEntry*)entryPtr)->ValidUID();
       
  1186 		if(entryPtr->iType != KUidMsvMessageEntry ||
       
  1187 			entryPtr->iRelatedId != KMsvNullIndexEntryId ||
       
  1188 			previouslyFetched)
       
  1189 			{
       
  1190 			aSelection.Delete(pos,1);
       
  1191 			}
       
  1192 		else
       
  1193 			{
       
  1194 			++pos;
       
  1195 			}
       
  1196 		}
       
  1197 	
       
  1198 	return aSelection.Count();
       
  1199 	}
       
  1200 
       
  1201 /**
       
  1202 Transfers the current selection into the iFolderIndex, and sorts it by UID.
       
  1203 */
       
  1204 void CImapFolder::MakeSortedFolderIndexL(TBool aUseCachedEntryData)
       
  1205 	{
       
  1206 		
       
  1207 	TInt noofchildren = iSelection->Count();
       
  1208 	
       
  1209 	// Reset folder index
       
  1210 	iFolderIndex->SetSizeL(noofchildren);
       
  1211 	TInt acounter = 0;
       
  1212 
       
  1213 	if(!aUseCachedEntryData)
       
  1214 		{ //can't rely on iCachedEntryData
       
  1215 		TMsvEntry* entryPtr;
       
  1216 		TMsvId id;
       
  1217 		for(acounter = 0; acounter < noofchildren; acounter++)
       
  1218 			{
       
  1219 			// Save UID/TMsvId of this entry
       
  1220 			id = (*iSelection)[acounter];
       
  1221 			User::LeaveIfError(iServerEntry.GetEntryFromId(id, entryPtr));
       
  1222 			(*iFolderIndex)[acounter].iUid = ((TMsvEmailEntry)(*entryPtr)).UID();
       
  1223 			(*iFolderIndex)[acounter].iMsvId = id;
       
  1224 			}
       
  1225 		}
       
  1226 	else
       
  1227 		{
       
  1228 		for(acounter = 0; acounter < noofchildren; acounter++)
       
  1229 			{
       
  1230 			// Save UID/TMsvId of this entry
       
  1231 			(*iFolderIndex)[acounter].iUid = (*iCachedEntryData)[acounter].iUid;
       
  1232 			(*iFolderIndex)[acounter].iMsvId = (*iSelection)[acounter];
       
  1233 			}
       
  1234 		}
       
  1235 
       
  1236 	// Sort it by UID
       
  1237 	iFolderIndex->Sort();
       
  1238 
       
  1239 	// Check for any duplicate UIDs (ie, a dud netscape server)
       
  1240 	TMsvEntry* entryPtr;
       
  1241 	TMsvEntry* nextEntryPtr;
       
  1242 	for(acounter = 1; acounter < noofchildren; acounter++)
       
  1243 		{
       
  1244 		if((*iFolderIndex)[acounter].iUid != 0 && (*iFolderIndex)[acounter].iUid == (*iFolderIndex)[acounter-1].iUid)
       
  1245 			{
       
  1246 			if(!aUseCachedEntryData)
       
  1247 				{
       
  1248 				// Get the TMsvEntry for the message/folder
       
  1249 				User::LeaveIfError(iServerEntry.GetEntryFromId((*iFolderIndex)[acounter].iMsvId,entryPtr));
       
  1250 				User::LeaveIfError(iServerEntry.GetEntryFromId((*iFolderIndex)[acounter-1].iMsvId,nextEntryPtr));
       
  1251 				// Check if type of TMsvEntry and type of next TMsvEntry are both Messages
       
  1252 				if( entryPtr->iType.iUid == nextEntryPtr->iType.iUid && entryPtr->iType.iUid == KUidMsvMessageEntryValue)
       
  1253 					{
       
  1254 					User::Leave(KErrCorrupt);
       
  1255 					}
       
  1256 				}
       
  1257 			else
       
  1258 				{
       
  1259 				User::Leave(KErrCorrupt);
       
  1260 				}
       
  1261 			}
       
  1262 			
       
  1263 		}
       
  1264 	}
       
  1265 
       
  1266 /**
       
  1267 Synchronise the local view of the contents with that of the remote folder. 
       
  1268 If the folder is not the currently in SELECTED state on the CImapSesssion, 
       
  1269 the first step should be to issue a SELECT command via the IMAP Session
       
  1270 */
       
  1271 EXPORT_C void CImapFolder::SynchroniseL(TRequestStatus& aStatus, CImapSession& aSession, TBool aNewOnly, TInt aDeleteOption)
       
  1272 	{
       
  1273 	__LOG_TEXT(aSession.LogId(), "SyncMan: Starting full IMAP Sync");
       
  1274 	
       
  1275 	//initialise counters
       
  1276 	iMsgsDone=0;
       
  1277 	iMsgsToDo=0;
       
  1278 	
       
  1279 	iHeadersFetched=0;
       
  1280 	iOrphanedMessages=0;
       
  1281 	iRemoteMessagesDeleteTagged=0;
       
  1282 	
       
  1283 	// Saved the calling status request
       
  1284 	iSavedSession = &aSession;
       
  1285 	iDeleteOption = aDeleteOption;
       
  1286 	
       
  1287 	// Set the Synchronisation states
       
  1288 	iSyncState = CImapSyncManager::ESynchronise;
       
  1289 	iNextAction = CImapSyncManager::ESynchronise;
       
  1290 	iMatchingMessageIds.Reset();
       
  1291 	
       
  1292 	// Update the remote folder info and clear the change indication counts
       
  1293 	UpdateSessionFolderInfoL(*iSavedSession);
       
  1294 	ClearChangeCounts();
       
  1295 
       
  1296 	// Some pre-bits that need doing - get the children & count them
       
  1297 	// Get the folder info for the selected folder
       
  1298 	SetEntryL(iMailboxId);
       
  1299 	TMsvEmailEntry message = iServerEntry.Entry();
       
  1300 	GetMessageChildrenL(iMailboxId, iSelection);
       
  1301 	TInt noofchildren = iSelection->Count();
       
  1302 
       
  1303 	// Check if new flags for the current selection should be cleared.
       
  1304 	ClearNewFlagsIfRequiredL();
       
  1305 		
       
  1306 	/*
       
  1307 	First of all check the UIDVALIDITY of the mirror and the 
       
  1308 	remote folder match - this is indicated by message.ValidUID() returning true.
       
  1309 	If not, we have to delete everything in the local mirror and start again.
       
  1310 	We also do this if there are 0 messages in the remote mailbox (0 EXISTS)
       
  1311 	and there are messages locally
       
  1312 	*/
       
  1313 	if(!message.ValidUID() || iMailboxSize == 0)
       
  1314 		{
       
  1315 		/*
       
  1316 		They don't match: do we have local children?
       
  1317 		If we were doing a new-only sync, change this to a full sync as the 
       
  1318 		UIDVALIDITY shows major changes.
       
  1319 		*/
       
  1320 		aNewOnly = EFalse;
       
  1321 
       
  1322 		if(noofchildren)
       
  1323 			{
       
  1324 		    // We've got local children then delete them
       
  1325 			for(TInt a = 0; a < noofchildren; a++)
       
  1326 				{
       
  1327 				// We should be skipping locally generated messages. i.e. Offline operations
       
  1328 				DeleteMessageL((*iSelection)[a]);
       
  1329 				}
       
  1330 
       
  1331 			// Reset the number of children as this may have changed.
       
  1332 			GetMessageChildrenL(iMailboxId, iSelection);
       
  1333 			noofchildren = iSelection->Count();
       
  1334 			}
       
  1335 
       
  1336 		// Match the remote's UIDVALIDITY: 
       
  1337 		// reset the context as it may have been used by the deletion process.
       
  1338 		SetEntryL(iMailboxId);
       
  1339 		if(!message.ValidUID())
       
  1340 			{
       
  1341 			// Do the change if necessary
       
  1342 			message.SetUID(iSessionFolderInfo->UidValidity());
       
  1343 			message.SetValidUID(ETrue);
       
  1344 			ChangeEntryL(message);
       
  1345 			}
       
  1346 		}
       
  1347 
       
  1348 	// Any remote messages? If not, complete now as there's nothing else to do
       
  1349 	if(iMailboxSize == 0)
       
  1350 		{
       
  1351 		// This folder is now sync'ed
       
  1352 		// No need to set seen flags as no messages in remote mailbox
       
  1353 		SyncCompleteL(); 
       
  1354 		Queue(aStatus);
       
  1355 		Complete(KErrNone);
       
  1356 		return;
       
  1357 		}
       
  1358 
       
  1359 	// Start the synchronise with sync'ing old messages: are there any
       
  1360 	// messages in our mirror folder?
       
  1361  	iSyncState = CImapSyncManager::ESyncOld; //EImapStateSynchroniseWait;
       
  1362 	iNextAction = CImapSyncManager::ESyncOld;
       
  1363 
       
  1364 	iSomeUnread = EFalse;
       
  1365 	iHighestUid = 0;
       
  1366 
       
  1367 	// Any children?
       
  1368 	iFolderIndex->Reset();
       
  1369 	if(noofchildren > 0) 
       
  1370 		{
       
  1371 		// Children exist, we need to do an old-sync to check all the messages
       
  1372 		// are still there.
       
  1373 		
       
  1374 		// Build an index of UIDs/TMsvIds currently in the mirror folder, and
       
  1375 		// sort this by UID: this is the order in which we expect the fetch to
       
  1376 		// return UIDs - any missing have been deleted on the server. They may
       
  1377 		// well not be in UID order in the index because locally-appended
       
  1378 		// messages will not have been added to the index in UID order.
       
  1379 		TRAPD(err,MakeSortedFolderIndexL(ETrue));
       
  1380 		if(err != KErrNone)
       
  1381 			{
       
  1382 			// Children exist, need to do old sync
       
  1383 			Queue(aStatus);
       
  1384 			Complete(err);
       
  1385 			return;
       
  1386 			}
       
  1387 
       
  1388 		// Find the highest UID in the index
       
  1389 		iHighestUid = (*iFolderIndex)[noofchildren-1].iUid;
       
  1390 		}
       
  1391 
       
  1392 	// Retrieve folder synchronisation limit.
       
  1393 	if(iSyncManager.EntryIsInbox(iServerEntry.Entry()))
       
  1394 		{
       
  1395 		// Leave iSyncLimit at the maximum if a Search String is set
       
  1396 		// If no Search String is set and this is the inbox, then use the inbox sync limit.
       
  1397 		if(iImapSettings.SearchString().Length() == 0)
       
  1398 			{
       
  1399 			iSyncLimit = iImapSettings.InboxSynchronisationLimit();	
       
  1400 			}
       
  1401 		}
       
  1402 	else
       
  1403 		{
       
  1404 		// Otherwise use the folder sync limit.
       
  1405 		// Leave iSyncLimit at the maximum if a Search String is set
       
  1406 		if(iImapSettings.SearchString().Length() == 0)
       
  1407 			{
       
  1408 			iSyncLimit = iImapSettings.MailboxSynchronisationLimit();
       
  1409 			}
       
  1410 		}
       
  1411 	
       
  1412 	// Call function to create and send the search command for the remote server message ids
       
  1413 	// if there wasn't a command sent then a full sync is needed.
       
  1414 	if(CreateAndSendUIDSearchStringL(aStatus))
       
  1415 		{
       
  1416 		return;
       
  1417 		}
       
  1418 		
       
  1419 	if(noofchildren > 0) 
       
  1420 		{
       
  1421 		// A complete list of the message ids on the remote server is needed.
       
  1422 		if(!aNewOnly && iHighestUid > 0)
       
  1423 			{
       
  1424 			// Do old sync
       
  1425 			iSyncState = CImapSyncManager::ESyncOld;
       
  1426 			iNextAction = CImapSyncManager::ESyncSearch;
       
  1427 			
       
  1428 			iFolderPosition = 0;
       
  1429 			// If a UID Search String is used it looks like this is FULL sync only 
       
  1430 			// so leave as is
       
  1431 			RBuf8 tempstr;
       
  1432 			tempstr.CleanupClosePushL();
       
  1433 			
       
  1434 			TInt tempstrLen = KImapFetchHeaderUIDRange().Length() + KImapMaxIntChars; // KImapFetchHeaderUIDRange provides enough room for "1"
       
  1435 			tempstr.CreateL(tempstrLen);
       
  1436 			tempstr.Format(KImapFetchHeaderUIDRange, 1, iHighestUid);
       
  1437 
       
  1438 			__LOG_FORMAT((iSavedSession->LogId(), "CImapFolder SynchroniseL : Sending Search for old messages with no synclimits: %S", &tempstr));
       
  1439 			
       
  1440 			iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
       
  1441 			// Go active and note that a send has been queued
       
  1442 			Queue(aStatus);
       
  1443 			SetActive();
       
  1444 			
       
  1445 			CleanupStack::PopAndDestroy(&tempstr);
       
  1446 			return;
       
  1447 			}
       
  1448 		}
       
  1449 
       
  1450 	// There was no need to search for old ids hence do new sync
       
  1451 	SynchroniseNewL();
       
  1452 	Queue(aStatus);
       
  1453 	}
       
  1454 
       
  1455 /**
       
  1456 Find the messages available on the remote server by creating and send the string of messages
       
  1457 to be search for by the session SearchL command.
       
  1458 
       
  1459 @param aStatus
       
  1460 Reference to the request status object to be use for the Search command.
       
  1461 @return ETrue if the search command has been sent and the folder object has been made Active.
       
  1462 */
       
  1463 TBool CImapFolder::CreateAndSendUIDSearchStringL(TRequestStatus& aStatus)
       
  1464 	{
       
  1465 	// Get the user defined UID SEARCH string and if there is one
       
  1466 	// do a refined search.
       
  1467 	if(iImapSettings.SearchString().Length() != 0)
       
  1468 		{
       
  1469 		iSyncState = CImapSyncManager::ESyncSearch;
       
  1470 		iNextAction = CImapSyncManager::ESyncSearch;
       
  1471 		
       
  1472 		iFolderPosition = 0;
       
  1473 
       
  1474 		// Refined search
       
  1475 		RBuf8 tempstr;
       
  1476 		tempstr.CleanupClosePushL();
       
  1477 		
       
  1478 		TPtrC8 searchstr = iImapSettings.SearchString();
       
  1479 		
       
  1480 		TInt tempstrLen = KImapFetchHeaderRangeSearch().Length() + KImapMaxIntChars + searchstr.Length(); // KImapFetchHeaderRangeSearch provides enough room for "1"
       
  1481 		tempstr.CreateL(tempstrLen);		
       
  1482 		tempstr.Format(KImapFetchHeaderRangeSearch, 1, Min(iMailboxSize,KImapUidSearchSize), &searchstr);
       
  1483 		
       
  1484 		__LOG_FORMAT((iSavedSession->LogId(), "CImapFolder SynchroniseL : Sending Search for old messages with search string: %S", &searchstr));
       
  1485 		iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
       
  1486 		
       
  1487 		// Go active and note that a send has been queued
       
  1488 		Queue(aStatus);
       
  1489 		SetActive();
       
  1490 		
       
  1491 		CleanupStack::PopAndDestroy(&tempstr);
       
  1492 		return ETrue;
       
  1493 		}
       
  1494 	else
       
  1495 		{
       
  1496 		// if no search string we use the old behaviour
       
  1497 		// Check the folder synchronisation limit.
       
  1498 		if(iSyncLimit > KImImapSynchroniseNone)
       
  1499 			{
       
  1500 			// Limited folder synchronisation, perform a UID search.
       
  1501 			iSyncState = CImapSyncManager::ESyncSearch;
       
  1502 			iNextAction = CImapSyncManager::ESyncSearch;
       
  1503 			
       
  1504 			iFolderPosition = 0;
       
  1505 
       
  1506 			// Perform a UID search on this folder.
       
  1507 			RBuf8 tempstr;
       
  1508 			tempstr.CleanupClosePushL();
       
  1509 						
       
  1510 			TInt tempstrLen = KImapFetchHeaderRange().Length() + KImapMaxIntChars; // KImapFetchHeaderRange provides enough room for "1"
       
  1511 			tempstr.CreateL(tempstrLen);			
       
  1512 			tempstr.Format(KImapFetchHeaderRange, 1, Min(iMailboxSize,KImapUidSearchSize));
       
  1513 			
       
  1514 			__LOG_FORMAT((iSavedSession->LogId(), "CImapFolder SynchroniseL : Sending Search for old messages with synclimits: %S", &tempstr));
       
  1515 			iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
       
  1516 			
       
  1517 			// Go active and note that a send has been queued
       
  1518 			Queue(aStatus);
       
  1519 			SetActive();
       
  1520 			
       
  1521 			CleanupStack::PopAndDestroy(&tempstr);			
       
  1522 			return ETrue;
       
  1523 			}
       
  1524 		else if(iSyncLimit == KImImapSynchroniseNone)
       
  1525 			{
       
  1526 			// No synchronisation required.
       
  1527 			// This folder is now sync'ed
       
  1528 			SyncCompleteL();
       
  1529 			Queue(aStatus);
       
  1530 			iSyncState = CImapSyncManager::ENotSyncing;
       
  1531 			// iSyncLimit=KImImapSynchroniseNone, no sync required
       
  1532 			Complete(KErrNone);
       
  1533 			return ETrue;
       
  1534 			}
       
  1535 		// iSyncLimit <= KImImapSynchroniseAll so Full synchronisation required - fall through.
       
  1536 		}
       
  1537 	return EFalse;
       
  1538 	}
       
  1539 	
       
  1540 /**
       
  1541 Synchronise new messages for a given range.
       
  1542 */
       
  1543 void CImapFolder::SynchroniseRangeL(const TUint32 aLowUid,const TUint32 aHighUid)
       
  1544 	{
       
  1545   
       
  1546  	iSyncState = CImapSyncManager::EFolderSynchronise;
       
  1547  	iNextAction = CImapSyncManager::ESyncFlags;
       
  1548 	iFolderPosition = 0;
       
  1549 
       
  1550 	// First, resize folder index to hold all messages in the folder,
       
  1551 	// as opposed to the old sync list. This will preserve the old
       
  1552 	// contents of the index, which is what we want as it's up-to-date
       
  1553 	// and correct.
       
  1554 	iFolderIndex->SetSizeL(iMailboxSize);
       
  1555 	
       
  1556 	// Create list of priority fields to request
       
  1557 	// If a UID search string has been specified, the we should create the UID FETCH
       
  1558 	// string from the UID integer list.
       
  1559 	if(iImapSettings.SearchString().Length() != 0)
       
  1560 		{
       
  1561 		HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(iMatchingMessageIds);
       
  1562 		iSavedSession->FetchBodyStructureAndHeadersL(iStatus, *sequenceSetOnHeap, KImapSmallHeaderFields(), *this);
       
  1563 		CleanupStack::PopAndDestroy(sequenceSetOnHeap);
       
  1564 		}
       
  1565 	else
       
  1566 		{
       
  1567 		RBuf8 tempstr;
       
  1568 		tempstr.CleanupClosePushL();
       
  1569 		
       
  1570 		TInt tempstrLen = KImapFetchHeaderRange().Length() + KImapMaxIntChars + KImapMaxIntChars;
       
  1571 		tempstr.CreateL(tempstrLen);		
       
  1572 		tempstr.Format(KImapFetchHeaderRange, aLowUid, aHighUid);
       
  1573 		
       
  1574 		iSavedSession->FetchBodyStructureAndHeadersL(iStatus, tempstr, KImapSmallHeaderFields(), *this);
       
  1575 		
       
  1576 		CleanupStack::PopAndDestroy(&tempstr);
       
  1577 		}
       
  1578 	SetActive();
       
  1579 	}
       
  1580 
       
  1581 /**
       
  1582 Synchronise new mesasges from current highest UID to end.
       
  1583 */
       
  1584 void CImapFolder::SynchroniseNewL()
       
  1585 	{
       
  1586 	iSyncState = CImapSyncManager::ESyncNew;
       
  1587 	iNextAction = CImapSyncManager::ESyncFlags;
       
  1588 	iFolderPosition = 0;
       
  1589 
       
  1590 	// First, resize folder index to hold all messages in the folder,
       
  1591 	// as opposed to the old sync list. This will preserve the old
       
  1592 	// contents of the index, which is what we want as it's up-to-date
       
  1593 	// and correct.
       
  1594 	iFolderIndex->SetSizeL(iMailboxSize);
       
  1595 
       
  1596 	// Fetch just the header of the new mails
       
  1597 	RBuf8 tempstr;
       
  1598 	tempstr.CleanupClosePushL();
       
  1599 	
       
  1600 	TInt tempstrLen = KImapFetchHeaderToEnd().Length() + KImapMaxIntChars;
       
  1601 	tempstr.CreateL(tempstrLen);		
       
  1602 	tempstr.Format(KImapFetchHeaderToEnd, iHighestUid + 1);
       
  1603 	
       
  1604 	iSavedSession->FetchBodyStructureAndHeadersL(iStatus, tempstr, KImapSmallHeaderFields(), *this);
       
  1605 	SetActive();
       
  1606 	
       
  1607 	CleanupStack::PopAndDestroy(&tempstr);
       
  1608 	}
       
  1609 
       
  1610 /**
       
  1611 Update iDate in iMailboxId to show the time now (last sync time)
       
  1612 */
       
  1613 void CImapFolder::SyncCompleteL()
       
  1614 	{
       
  1615 	__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Starting SyncCompleteL");
       
  1616 	// Find entry
       
  1617 	SetEntryL(iMailboxId);
       
  1618 	TMsvEmailEntry message = iServerEntry.Entry();
       
  1619 
       
  1620 	// Find 'now'
       
  1621 	message.iDate.UniversalTime();
       
  1622 
       
  1623 	// Check to see if there has been a change in the number of messages in the remote folder.
       
  1624 	TBool folderSizeChanged = (message.RemoteFolderEntries()!=iMailboxSize);
       
  1625 
       
  1626 	// Set 'unread' flag on folder if there are any unread messages within it
       
  1627 	if(message.Unread() != iSomeUnread || !message.Visible() || folderSizeChanged)
       
  1628 		{
       
  1629 		// Update flags
       
  1630 		message.SetUnread(iSomeUnread);
       
  1631 		message.SetVisible(ETrue);
       
  1632 		message.SetRemoteFolderEntries(iMailboxSize);
       
  1633  		ChangeEntryBulkL(message); // completed at the end of this method
       
  1634 		}
       
  1635 
       
  1636 	// we need to ensure the hierarchy of folders containing this one
       
  1637 	// is now visible. Note previously this incorrectly only did this
       
  1638 	// when we were not in DisconncetedUserMode
       
  1639 	do
       
  1640 		{
       
  1641 		// Move up one
       
  1642 		SetEntryL(message.Parent());
       
  1643 		message=iServerEntry.Entry();
       
  1644 
       
  1645 		// Ensure visibility
       
  1646 		if(!message.Visible())
       
  1647 			{
       
  1648 			message.SetVisible(ETrue);
       
  1649 			ChangeEntryBulkL(message); // completed at the end of this method
       
  1650 			}
       
  1651 		}
       
  1652 	while(message.iType!=KUidMsvServiceEntry);
       
  1653 	
       
  1654 
       
  1655 	// commit any outstanding entries to the index file to complete the bulk
       
  1656 	// synchronization operation
       
  1657 	iServerEntry.CompleteBulk();
       
  1658 	
       
  1659 	// Set the current id to null so that we aren't locking any folders
       
  1660 	SetEntryL(KMsvNullIndexEntryId);
       
  1661 	}
       
  1662 
       
  1663 /**
       
  1664 Reset subscription flags for all children, and recurse into folders
       
  1665 */
       
  1666 void CImapFolder::ResetSubscriptionFlagsL(const TMsvId aFolder)
       
  1667 	{
       
  1668 	// Do this one
       
  1669 	SetEntryL(aFolder);
       
  1670 	TMsvEmailEntry entry = iServerEntry.Entry();
       
  1671 
       
  1672 	// A folder or service? If not, return
       
  1673 	if(entry.iType != KUidMsvServiceEntry &&
       
  1674 		entry.iType != KUidMsvFolderEntry)
       
  1675 		{
       
  1676 		return;
       
  1677 		}
       
  1678 
       
  1679 	// Reset flag if needed
       
  1680 	if(entry.Subscribed())
       
  1681 		{
       
  1682 		// Reset flag and save
       
  1683 		entry.SetSubscribed(EFalse);
       
  1684 		ChangeEntryL(entry);
       
  1685 		}
       
  1686 
       
  1687 	// Any children?
       
  1688 	CMsvEntrySelection *children = new (ELeave) CMsvEntrySelection;
       
  1689 	CleanupStack::PushL(children);
       
  1690 	GetChildrenL(*children);
       
  1691 	if(children->Count())
       
  1692 		{
       
  1693 		// Do each in turn
       
  1694 		for(TInt child = 0; child < children->Count(); child++)
       
  1695 			ResetSubscriptionFlagsL((*children)[child]);
       
  1696 		}
       
  1697 	CleanupStack::PopAndDestroy();
       
  1698 	}
       
  1699 
       
  1700 /**
       
  1701 Performs any outstanding offline delete operations
       
  1702 
       
  1703 deletes from the remote server any messages marked /deleted locally.
       
  1704 */
       
  1705 EXPORT_C void CImapFolder::SyncDeletesL(TRequestStatus& aStatus, CImapSession& aSession)
       
  1706 	{
       
  1707 	iSavedSession = &aSession;
       
  1708 
       
  1709 	SetEntryL(iMailboxId);
       
  1710 	GetMessageChildrenL(iMailboxId, iSelection);
       
  1711 	TRAPD(err,MakeSortedFolderIndexL(ETrue));
       
  1712 	if(err!=KErrNone)
       
  1713 		{
       
  1714 		Queue(aStatus);
       
  1715 		Complete(err);
       
  1716 		return;
       
  1717 		}
       
  1718 	TInt pos = 0;
       
  1719 	TInt deleted = 0;
       
  1720 
       
  1721 	// Build command
       
  1722 	HBufC8* command=HBufC8::NewLC(256);
       
  1723 	RArray<TUint>	deletingMessageIds;
       
  1724 	
       
  1725 	// Start command
       
  1726 	//command->Des().Append(_L8("UID STORE "));
       
  1727 	
       
  1728 	iDeletedMessageIds.Reset();
       
  1729 	iMessageFlagInfoArray.Reset();
       
  1730 
       
  1731 	while(pos < iFolderIndex->Size())
       
  1732 		{
       
  1733 		// Look for messages with deleted flag set
       
  1734 		SetEntryL((*iFolderIndex)[pos].iMsvId);
       
  1735 		if(((TMsvEmailEntry)iServerEntry.Entry()).DeletedIMAP4Flag())
       
  1736 			{
       
  1737 			__LOG_FORMAT((aSession.LogId(), "Message id %x marked as deleted",iServerEntry.Entry().Id()));
       
  1738 			++iRemoteMessagesDeleteTagged;
       
  1739 			
       
  1740 			// Append to the delete list
       
  1741 			TInt64 uid=(TUint)((TMsvEmailEntry)iServerEntry.Entry()).UID();
       
  1742 			deletingMessageIds.Append(uid);
       
  1743 			// index of local message in iFolderIndex to be deleted
       
  1744 			iDeletedMessageIds.Append(pos);
       
  1745 			++deleted;
       
  1746 			}
       
  1747 
       
  1748 		// Next message
       
  1749 		pos++;
       
  1750 		}
       
  1751 
       
  1752 	// Anything deleted?
       
  1753 	if(deleted)
       
  1754 		{
       
  1755 		// Append flags & send command
       
  1756 		_LIT8(KDeleteFlag,"+FLAGS");
       
  1757 		_LIT8(KDeleteItem,"(\\Deleted)");
       
  1758 		command->Des().Append(KDeleteFlag);
       
  1759 		
       
  1760 		HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(deletingMessageIds);
       
  1761 		// Call the STORE function in the session
       
  1762 		aSession.StoreL(iStatus, *sequenceSetOnHeap, KDeleteFlag(), KDeleteItem(), ETrue, iMessageFlagInfoArray);
       
  1763 		CleanupStack::PopAndDestroy(sequenceSetOnHeap);
       
  1764 		
       
  1765 		Queue(aStatus);
       
  1766 		SetActive();
       
  1767 		iSyncState = CImapSyncManager::EFolderEarlyExpunge;
       
  1768 				
       
  1769 		if (iImapSettings.UseExpunge())
       
  1770 			{
       
  1771 			iNextAction = CImapSyncManager::EFolderExpunge;
       
  1772 			}
       
  1773 		else
       
  1774 			{
       
  1775 			iNextAction = CImapSyncManager::EFolderClose;
       
  1776 			}
       
  1777 		}
       
  1778 	else
       
  1779 		{
       
  1780 		// Nothing to do just complete
       
  1781 		Queue(aStatus);
       
  1782 		Complete(KErrNone);
       
  1783 		}
       
  1784 
       
  1785 	// Get rid of command buffer
       
  1786 	CleanupStack::PopAndDestroy(command);
       
  1787 	}
       
  1788 
       
  1789 /**
       
  1790 Enquote a string (being sent as a string literal) if required
       
  1791 */
       
  1792 EXPORT_C void CImapFolder::DoQuoteL(HBufC16*& aBuffer)
       
  1793 	{
       
  1794 	// Null string? Nothing to do
       
  1795 	if(!aBuffer->Length() || !aBuffer->Des().Length())
       
  1796 		{
       
  1797 		return;
       
  1798 		}
       
  1799 
       
  1800 	// Anything needing quoting in there?
       
  1801 	if(aBuffer->Des().Locate('\\') == KErrNotFound &&
       
  1802 		aBuffer->Des().Locate('\"') == KErrNotFound)
       
  1803 		{
       
  1804 		return;
       
  1805 		}
       
  1806 
       
  1807 	// Run through string, inserting quote characters as needed
       
  1808 	for(TInt a = 0; a<aBuffer->Des().Length(); a++)
       
  1809 		{
       
  1810 		if(aBuffer->Des()[a] == '\\' || aBuffer->Des()[a] == '\"')
       
  1811 			{
       
  1812 			HBufC16 *newbuf = aBuffer->ReAllocL(aBuffer->Des().Length()+1);
       
  1813 
       
  1814 			// Been moved due to realloc?
       
  1815 			if(newbuf != aBuffer)
       
  1816 				{
       
  1817 				// In all cases when DoQuoteL() is called, the buffer is on the top of
       
  1818 				// the cleanup stack: change this to indicate the correct entry
       
  1819 				CleanupStack::Pop();
       
  1820 				CleanupStack::PushL(aBuffer = newbuf);
       
  1821 				}
       
  1822 
       
  1823 			aBuffer->Des().Insert(a, KQuoteChar);
       
  1824 			a++;
       
  1825 			}
       
  1826 		}
       
  1827 	}
       
  1828 
       
  1829 
       
  1830 /**
       
  1831 Implementation of the observer function for the session fetch command. For each call
       
  1832 creates the required entry tree.
       
  1833 */
       
  1834 void CImapFolder::OnFetchLD(CImapFetchResponse* aImapFetchResponse)
       
  1835 	{
       
  1836 	// Take ownership of parameter
       
  1837 	CleanupStack::PushL(aImapFetchResponse);
       
  1838 	
       
  1839 	CImapRfc822HeaderFields* headerinfo = aImapFetchResponse->HeaderFields();
       
  1840 	CImapBodyStructure* bodystructure = aImapFetchResponse->BodyStructure();
       
  1841 	
       
  1842 	//update the progress object
       
  1843 	++iMsgsDone;
       
  1844 	++iHeadersFetched;
       
  1845 
       
  1846 	if(headerinfo)
       
  1847 		{
       
  1848 		TUint remoteUid = aImapFetchResponse->MessageUid();
       
  1849 		if(iFolderIndex->Size() > 0)
       
  1850 			{
       
  1851 			if(iFolderIndex->FindMsg(remoteUid) != 0)
       
  1852 				{
       
  1853 				CleanupStack::PopAndDestroy(aImapFetchResponse);
       
  1854 				return;
       
  1855 				}
       
  1856 			}
       
  1857 		// Create an email entry in this folder.
       
  1858 		SetEntryL(iMailboxId);
       
  1859 
       
  1860 		// Skeleton for new entry
       
  1861 		TMsvEmailEntry entry;
       
  1862 		TFileName attachmentFilename;	//	Attachment filename
       
  1863 
       
  1864 		entry.iSize = 0;
       
  1865 		entry.iType = KUidMsvMessageEntry;
       
  1866 		entry.iMtm = KUidMsgTypeIMAP4;
       
  1867 		entry.iServiceId = iImapSettings.ServiceId();
       
  1868 		entry.SetValidUID(EFalse);		// reuse ValidUID Flag record if the message has ever been fetched
       
  1869 		entry.SetComplete(EFalse);
       
  1870 		entry.SetUnread(ETrue);
       
  1871 		entry.SetNew(ETrue);
       
  1872 		entry.SetUID(aImapFetchResponse->MessageUid());
       
  1873 
       
  1874 		// Set from line in TMsvEntry
       
  1875 		const TDesC8& temp2 = headerinfo->FieldValue(CImapRfc822HeaderFields::EImapFrom);
       
  1876 		HBufC* decodedFromBuffer = HBufC::NewLC(temp2.Length());
       
  1877 		TPtr decodedFromPtr(decodedFromBuffer->Des());
       
  1878 
       
  1879 		iHeaderConverter.DecodeHeaderFieldL(temp2, decodedFromPtr);
       
  1880 		entry.iDetails.Set(decodedFromPtr);
       
  1881 		
       
  1882 		// Set subject in TMsvEntry
       
  1883 		const TDesC8& temp3 = headerinfo->FieldValue(CImapRfc822HeaderFields::EImapSubject); 
       
  1884 		HBufC* decodedSubjectBuffer = HBufC::NewLC(temp3.Length());
       
  1885 		TPtr decodedSubjectPtr(decodedSubjectBuffer->Des());
       
  1886 
       
  1887 		iHeaderConverter.DecodeHeaderFieldL(temp3, decodedSubjectPtr);
       
  1888 		entry.iDescription.Set(decodedSubjectPtr);
       
  1889 
       
  1890 		// Set the Date
       
  1891 		entry.iDate = headerinfo->Date();
       
  1892 
       
  1893 		// Set the priority field
       
  1894 		entry.SetPriority(headerinfo->PriorityL());
       
  1895 
       
  1896 		if (bodystructure)
       
  1897 			{
       
  1898 			SetMessageFlagsL(entry, bodystructure);
       
  1899 			}
       
  1900 
       
  1901 		// Set the flags
       
  1902 		TBool messageInfoSeen = aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::ESeen);
       
  1903 
       
  1904 		entry.SetSeenIMAP4Flag(messageInfoSeen);
       
  1905 		entry.SetAnsweredIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::EAnswered));
       
  1906 		entry.SetFlaggedIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::EFlagged));
       
  1907 		entry.SetDeletedIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::EDeleted));
       
  1908 		entry.SetDraftIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::EDraft));
       
  1909 		entry.SetRecentIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::ERecent));
       
  1910 		
       
  1911 		// Are we configured to update the \seen flag on the server?
       
  1912 		if (iImapSettings.UpdatingSeenFlags())
       
  1913 			{
       
  1914 			// Now copy the inverse of the \Seen flag down to the clients Unread flag
       
  1915 			if (messageInfoSeen)
       
  1916 				{
       
  1917 				entry.SetUnread(EFalse);
       
  1918 				}
       
  1919 			}
       
  1920 		
       
  1921 		// note that an unread message has been spotted.
       
  1922 		if(!entry.SeenIMAP4Flag() || entry.RecentIMAP4Flag())
       
  1923 			{
       
  1924 			iSomeUnread	= ETrue;
       
  1925 			}
       
  1926 		
       
  1927 		// If sync'ing to download rules is disabled, mark that message as
       
  1928 		// "fetched"  using the re-used ValidUID flag. This prevents the
       
  1929 		// message from being sync'd according to download rules if rules
       
  1930 		// are subsequently enabled.
       
  1931 		if(!iImapSettings.UseSyncDownloadRules())
       
  1932 			{
       
  1933 			entry.SetValidUID(ETrue);
       
  1934 			}
       
  1935 
       
  1936 		// Create message
       
  1937 		User::LeaveIfError(iServerEntry.CreateEntryBulk(entry));
       
  1938 		// The matching CompleteBulk() is called in OnFetchCommit() and the ESyncFlags section of the DoRunL()
       
  1939 		// that is called after FetchBodyStructureAndHeadersL() has completed.
       
  1940 		__ASSERT_DEBUG(iNextAction == CImapSyncManager::ESyncFlags, User::Invariant());
       
  1941 		CleanupStack::PopAndDestroy(decodedSubjectBuffer);
       
  1942 		CleanupStack::PopAndDestroy(decodedFromBuffer);
       
  1943 		}
       
  1944 		
       
  1945 	CleanupStack::PopAndDestroy(aImapFetchResponse);
       
  1946 	}
       
  1947 	
       
  1948 void CImapFolder::OnFetchCommit()
       
  1949 	{
       
  1950 	iServerEntry.CompleteBulk();
       
  1951 	}
       
  1952 
       
  1953 /**
       
  1954 Set or clear the \\Seen flags on the server
       
  1955 
       
  1956 @param aUpdateMode
       
  1957 ETrue -> Sets the flag
       
  1958 @return False if no messages need to be processed
       
  1959 */
       
  1960 TBool CImapFolder::ProcessSeenFlagsL(TSeenFlagUpdateMode aUpdateMode)
       
  1961 	{
       
  1962 	RArray<TUint>* pendingList;
       
  1963 	TBool settingFlag = (aUpdateMode == ESetSeenFlag);
       
  1964 
       
  1965 	// Point pendingList to the correct list
       
  1966 	pendingList = (settingFlag ? iSetSeenList: iClearSeenList);
       
  1967 	
       
  1968 	// Exit if nothing to process
       
  1969 	if(!pendingList->Count())
       
  1970 		{
       
  1971 		return EFalse;
       
  1972 		}
       
  1973 	
       
  1974 	__LOG_FORMAT((iSavedSession->LogId(), "CImapFolder : ProcessSeenFlags(%d)", aUpdateMode));
       
  1975 
       
  1976 	_LIT8(KStoreFlagsSetCommand, "+FLAGS");
       
  1977 	_LIT8(KStoreFlagsClearCommand, "-FLAGS");
       
  1978 	_LIT8(KStoreFlagsSeenCommand,"(\\Seen)");
       
  1979 	
       
  1980 	iMessageFlagInfoArray.Reset();
       
  1981 
       
  1982 	HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(*pendingList);
       
  1983 
       
  1984 	// Call the STORE function in the session
       
  1985 	if(settingFlag)
       
  1986 		{
       
  1987 		iSavedSession->StoreL(iStatus, *sequenceSetOnHeap, KStoreFlagsSetCommand(), KStoreFlagsSeenCommand(), ETrue, iMessageFlagInfoArray);
       
  1988 		}
       
  1989 	else
       
  1990 		{
       
  1991 		iSavedSession->StoreL(iStatus, *sequenceSetOnHeap, KStoreFlagsClearCommand(), KStoreFlagsSeenCommand(), ETrue, iMessageFlagInfoArray);
       
  1992 		}
       
  1993 	
       
  1994 	CleanupStack::PopAndDestroy(sequenceSetOnHeap);
       
  1995 	
       
  1996 	SetActive();
       
  1997 
       
  1998 	// Reset the list
       
  1999 	pendingList->Reset();
       
  2000 
       
  2001 	return ETrue;
       
  2002 	}
       
  2003 
       
  2004 /**
       
  2005 Construct a full mailbox path for the folder object
       
  2006 This is expensive in memory movement terms, as it works UP the path,
       
  2007 inserting new data at the start. This is based on the principle that it's
       
  2008 more expensive to find an entry in the index with SetEntryL() than it is to
       
  2009 move some bytes about, otherwise we'd find the path upwards then create the
       
  2010 string downwards.
       
  2011 */
       
  2012 EXPORT_C HBufC16* CImapFolder::MakePathL(const TBool aIncludeLeaf)
       
  2013 	{
       
  2014 	// Making a path: we start with nothing
       
  2015 	HBufC16 *path = HBufC16::NewLC(256);
       
  2016 	TBool skipfirst = ETrue;
       
  2017 	TMsvId traverse = iMailboxId;
       
  2018 
       
  2019 	// Move to the entry
       
  2020 	User::LeaveIfError(iServerEntry.SetEntry(traverse));
       
  2021 
       
  2022 	// Skipping the leaf?
       
  2023 	if(!aIncludeLeaf && iServerEntry.Entry().iType != KUidMsvServiceEntry)
       
  2024 		{
       
  2025 		// Up a level before we generate the path
       
  2026 		traverse = iServerEntry.Entry().Parent();
       
  2027 		User::LeaveIfError(iServerEntry.SetEntry(traverse));
       
  2028 		}
       
  2029 
       
  2030 	// Check and see if we are dealing with the INBOX, in which case return immediately
       
  2031 	if (iSyncManager.EntryIsInbox(iServerEntry.Entry()))
       
  2032 		{
       
  2033 		path->Des().Insert(0,KIMAP_INBOX);
       
  2034 		CleanupStack::Pop(path);
       
  2035 		return path;
       
  2036 		}
       
  2037 
       
  2038 	// While we can still go up within this service...
       
  2039 	while(iServerEntry.Entry().iType != KUidMsvServiceEntry)
       
  2040 		{
       
  2041 		// Make sure the path maxlength is still ok with the added folder name and an extra separator character
       
  2042 		if((path->Length() + iServerEntry.Entry().iDetails.Length() + 1) > path->Des().MaxLength())
       
  2043 			{
       
  2044 			HBufC16* newpath = path->ReAllocL(path->Length() + iServerEntry.Entry().iDetails.Length() + 1);
       
  2045 			if(path != newpath)
       
  2046 				{
       
  2047 				CleanupStack::Pop(path);
       
  2048 				path = newpath;
       
  2049 				CleanupStack::PushL(path);
       
  2050 				}
       
  2051 			}
       
  2052 
       
  2053 		// Add the name of this component to the path
       
  2054 		if(!skipfirst)
       
  2055 			{
       
  2056 			path->Des().Insert(0,iImapSettings.PathSeparator());
       
  2057 			}
       
  2058 		else
       
  2059 			{
       
  2060 			skipfirst = EFalse;
       
  2061 			}
       
  2062 
       
  2063 		// Ensure uppercase 'INBOX' is used in folder name. This allows case
       
  2064 		// sensitive searches to be used later.
       
  2065 		if (iSyncManager.EntryIsInbox(iServerEntry.Entry()))
       
  2066 			{
       
  2067 			path->Des().Insert(0,KIMAP_INBOX);
       
  2068 			}
       
  2069 		else
       
  2070 			{
       
  2071 			path->Des().Insert(0,iServerEntry.Entry().iDetails);
       
  2072 			}
       
  2073 
       
  2074 		// Go up a level
       
  2075 		SetEntryL(traverse = iServerEntry.Entry().Parent());
       
  2076 		}
       
  2077 	
       
  2078 	// Add the path at the very start, if it exists
       
  2079 	if(iImapSettings.FolderPath().Length())
       
  2080 		{
       
  2081 		// Make sure the path maxlength is still ok with the added folder path and an extra separator character
       
  2082 		if((path->Length() + iImapSettings.FolderPath().Length() + 1) > path->Des().MaxLength())
       
  2083 			{
       
  2084 			HBufC16* newpath = path->ReAllocL(path->Length() + iImapSettings.FolderPath().Length() + 1);
       
  2085 			if(path != newpath)
       
  2086 				{
       
  2087 				CleanupStack::Pop(path);
       
  2088 				path = newpath;
       
  2089 				CleanupStack::PushL(path);
       
  2090 				}
       
  2091 			}
       
  2092 
       
  2093 		// Anything there already? If not, don't bother with the separator
       
  2094 		if(path->Des().Length()) 
       
  2095 			{
       
  2096 			path->Des().Insert(0,iImapSettings.PathSeparator());	
       
  2097 			}
       
  2098 		
       
  2099 		RBuf tempstr;
       
  2100 		tempstr.CleanupClosePushL();
       
  2101 		tempstr.CreateL(iImapSettings.FolderPath().Length());
       
  2102 		
       
  2103 		tempstr.Copy(iImapSettings.FolderPath());
       
  2104 		path->Des().Insert(0, tempstr);
       
  2105 		
       
  2106 		CleanupStack::PopAndDestroy(&tempstr);
       
  2107 		}
       
  2108 
       
  2109 	// Pop it off cleanup stack
       
  2110 	CleanupStack::Pop(path);
       
  2111 
       
  2112 	// Return the path
       
  2113 	return(path);
       
  2114 	}
       
  2115 
       
  2116 void CImapFolder::CompleteSelf()
       
  2117 	{
       
  2118 // Complete self.
       
  2119 	TRequestStatus* status = &iStatus;
       
  2120 	iStatus = KRequestPending;
       
  2121 	User::RequestComplete(status, KErrNone);
       
  2122 	}
       
  2123 
       
  2124 /**
       
  2125 Returns updated progress information on outstanding synchronisation operations.
       
  2126 */
       
  2127 EXPORT_C void CImapFolder::Progress(TImap4SyncProgress& aProgress)
       
  2128 	{
       
  2129 	//copy values from member progress ob into aProgress
       
  2130 	aProgress.iMsgsDone=iMsgsDone;
       
  2131 	aProgress.iMsgsToDo=iMsgsToDo;
       
  2132 	
       
  2133 	aProgress.iHeadersFetched = iHeadersFetched;	
       
  2134 	aProgress.iOrphanedMessages = iOrphanedMessages;
       
  2135 	aProgress.iRemoteMessagesDeleteTagged = iRemoteMessagesDeleteTagged;
       
  2136 	
       
  2137 	if(iImapSettings.SearchString().Length() != 0)
       
  2138 		{
       
  2139 		aProgress.iMsgsToDo=iMailboxSize;	
       
  2140 		}
       
  2141 	else
       
  2142 		{
       
  2143 		aProgress.iMsgsToDo=(iSyncLimit<=0)?iMailboxSize:Min(iMailboxSize,iSyncLimit);	
       
  2144 		}
       
  2145 	aProgress.iMsgsDone = Min(iMsgsDone,aProgress.iMsgsToDo);	
       
  2146 		
       
  2147 	}
       
  2148 
       
  2149 /**
       
  2150 Sets various flags in the message entry by doing a quick scan of the
       
  2151 bodystructure. This routine is intended to be relatively straightforward
       
  2152 so as not to impact performance during the sync phase too much.
       
  2153 
       
  2154 @param aEntry Entry to set flags for
       
  2155 @param aBodyStructure Message body structure 
       
  2156 */
       
  2157 void CImapFolder::SetMessageFlagsL(TMsvEmailEntry& aEntry, CImapBodyStructure* aBodyStructure)
       
  2158 	{
       
  2159 	TBool hasAttachments(EFalse);
       
  2160 	TBool hasHtml(EFalse);
       
  2161 	TBool afterRelated(EFalse);
       
  2162 	TBool afterAlternative(EFalse);
       
  2163 	TBool htmlAfterAltRel(EFalse);
       
  2164 	TBool hasICalendar(EFalse);
       
  2165 	TBool hasVCalendar(EFalse);
       
  2166 	TInt size(0);
       
  2167 
       
  2168 	// Check if top level of message contains attachment type
       
  2169 	if ((aBodyStructure->BodyStructureType() == CImapBodyStructure::ETypeBasic) &&
       
  2170 	    ((aBodyStructure->Type().CompareF(KImapTxtImage) == 0) ||
       
  2171 	     (aBodyStructure->Type().CompareF(KImapTxtAudio) == 0) ||
       
  2172 	     (aBodyStructure->Type().CompareF(KImapTxtVideo) == 0) ||
       
  2173 	     (aBodyStructure->Type().CompareF(KImapTxtApplication) == 0)))
       
  2174 		{
       
  2175 		hasAttachments = ETrue;
       
  2176 		}
       
  2177 
       
  2178 	RPointerArray<CImapBodyStructure> bodyStructureStack;
       
  2179 	bodyStructureStack.AppendL(aBodyStructure);
       
  2180 
       
  2181 	TInt count;
       
  2182 
       
  2183 	// A body structure stack is maintained. This avoids the use of recursion
       
  2184 	// when processing the embedded body structure list at each level, and also
       
  2185 	// maintains the order of processing that the old IMAP implementation used.
       
  2186 	// As nobody could explain exactly why the old code used this order, it was
       
  2187 	// felt that it was safer that the new implementation matched the old.
       
  2188 	while (bodyStructureStack.Count() > 0)
       
  2189 		{
       
  2190 		GetFlagsForBodyStructurePart(bodyStructureStack[0], hasAttachments, hasHtml, afterRelated, afterAlternative, htmlAfterAltRel, hasICalendar, hasVCalendar, size);
       
  2191 
       
  2192 		for (count = 0; count < bodyStructureStack[0]->EmbeddedBodyStructureList().Count(); ++count)
       
  2193 			{
       
  2194 			bodyStructureStack.AppendL(bodyStructureStack[0]->EmbeddedBodyStructureList()[count]);
       
  2195 			}
       
  2196 
       
  2197 		bodyStructureStack.Remove(0);
       
  2198 		}
       
  2199 
       
  2200 	aEntry.SetAttachment(hasAttachments);
       
  2201 	aEntry.SetMHTMLEmail(hasHtml || htmlAfterAltRel);
       
  2202 	aEntry.SetICalendar(hasICalendar);
       
  2203 	aEntry.SetVCalendar(hasVCalendar);
       
  2204 	aEntry.iSize = size;
       
  2205 	bodyStructureStack.Reset();
       
  2206 	}
       
  2207 
       
  2208 /**
       
  2209 Gets a set of flags for a body structure part
       
  2210 
       
  2211 @param aBodyStructure Body structure part
       
  2212 @param aHasAttachments Flag to indicate if message contains attachments
       
  2213 @param aHasHtml Flag to indicate if message has HTML part
       
  2214 @param aAfterRelated Flag to indicate a multipart/related part has been found
       
  2215 @param aAfterAlternative Flag to indicate a multipart/alternative part has been found
       
  2216 @param aHtmlAfterAltRel Flag to indicate a HTML part has been found after a multipart/related or multipart/alternative part
       
  2217 @param aHasICalendar Flag to indicate message contains ICalendar
       
  2218 @param aHasVCalendar Flag to indicate message contains VCalendar
       
  2219 @param aSize Running total of size of message
       
  2220 */
       
  2221 void CImapFolder::GetFlagsForBodyStructurePart(CImapBodyStructure* aBodyStructure,
       
  2222                                                TBool& aHasAttachments, TBool& aHasHtml,
       
  2223                                                TBool& aAfterRelated, TBool& aAfterAlternative,
       
  2224                                                TBool& aHtmlAfterAltRel, TBool& aHasICalendar,
       
  2225                                                TBool& aHasVCalendar, TInt& aSize)
       
  2226 	{
       
  2227 	switch (aBodyStructure->BodyStructureType())
       
  2228 		{
       
  2229 		case CImapBodyStructure::ETypeMultipart:
       
  2230 			{
       
  2231 			if (aBodyStructure->SubType().CompareF(KImapTxtRelated) == 0)
       
  2232 				{
       
  2233 				aAfterRelated = ETrue;
       
  2234 				}
       
  2235 			else if (aBodyStructure->SubType().CompareF(KImapTxtAlternative) == 0)
       
  2236 				{
       
  2237 				aAfterAlternative = ETrue;
       
  2238 				}
       
  2239 			else if (aBodyStructure->SubType().CompareF(KImapTxtMixed) == 0)
       
  2240 				{
       
  2241 				aHasAttachments = ETrue;
       
  2242 				}
       
  2243 			
       
  2244 			break;
       
  2245 			}
       
  2246 
       
  2247 		case CImapBodyStructure::ETypeText:
       
  2248 			{
       
  2249 			if (aBodyStructure->SubType().CompareF(KImapTxtHtml) == 0)
       
  2250 				{
       
  2251 				if (aBodyStructure->ExtDispositionName().CompareF(KImapTxtAttachment) != 0)
       
  2252 					{
       
  2253 					aHasHtml = ETrue;
       
  2254 					}
       
  2255 
       
  2256 				if (aAfterRelated || aAfterAlternative)
       
  2257 					{
       
  2258 					aHtmlAfterAltRel = ETrue;
       
  2259 					}
       
  2260 				}
       
  2261 			else if (aBodyStructure->SubType().CompareF(KImapTxtCalendar) == 0)
       
  2262 				{
       
  2263 				aHasICalendar = ETrue;
       
  2264 				}
       
  2265 			else if (aBodyStructure->SubType().CompareF(KImapTxtXVCalendar) == 0)
       
  2266 				{
       
  2267 				aHasVCalendar = ETrue;
       
  2268 				}
       
  2269 
       
  2270 			break;
       
  2271 			}
       
  2272 
       
  2273 		case CImapBodyStructure::ETypeMessageRfc822:
       
  2274 			{
       
  2275 			return;
       
  2276 			}
       
  2277 
       
  2278 		default:
       
  2279 			{
       
  2280 			if (aBodyStructure->SubType().CompareF(KImapTxtDeliveryStatus) == 0)
       
  2281 				{
       
  2282 				aHasAttachments = ETrue;
       
  2283 				}
       
  2284 
       
  2285 			break;
       
  2286 			}
       
  2287 		}
       
  2288 
       
  2289 	// Add size of this body part to the running total
       
  2290 	TInt size(0);
       
  2291 	TLex8 lex(aBodyStructure->BodySizeOctets());
       
  2292 	lex.Val(size);
       
  2293 
       
  2294 	// For Base64, use the pre encoding data size
       
  2295 	if (aBodyStructure->BodyEncoding().CompareF(KImapTxtBase64) == 0)
       
  2296 		{
       
  2297 		size = (size * 3) / 4;
       
  2298 		}
       
  2299 
       
  2300 	aSize += size;
       
  2301 	}
       
  2302 
       
  2303 /**
       
  2304 Checks if we need to clear the new flags on the messages in the folder,
       
  2305 and if so clears them.
       
  2306 @pre Current selection (iSelection) contains all the messages in the folder.
       
  2307 */
       
  2308 void CImapFolder::ClearNewFlagsIfRequiredL()
       
  2309 	{
       
  2310 	if (iSyncManager.EntryIsInbox(iServerEntry.Entry()))
       
  2311 		{
       
  2312 		if (iSyncManager.InboxClearNewFlags())
       
  2313 			{
       
  2314 			__LOG_TEXT(iSavedSession->LogId(), "CImapFolder: Clearing new flags (inbox)");
       
  2315 			
       
  2316 			// Change attributes on the current selection
       
  2317 			User::LeaveIfError(iServerEntry.ChangeAttributes(*iSelection, 0, KMsvNewAttribute));
       
  2318 
       
  2319 			// Set the flag to False to indicate that we have cleared the flags
       
  2320 			// on the inbox, and so any subsequent synchronise of the inbox
       
  2321 			// will not clear them again.
       
  2322 			iSyncManager.ResetInboxClearNewFlags();
       
  2323 			}
       
  2324 		}
       
  2325 	else
       
  2326 		{
       
  2327 		if (iSyncManager.NonInboxClearNewFlags())
       
  2328 			{
       
  2329 			__LOG_TEXT(iSavedSession->LogId(), "CImapFolder: Clearing new flags (non inbox)");
       
  2330 
       
  2331 			// Change attributes on the current selection
       
  2332 			User::LeaveIfError(iServerEntry.ChangeAttributes(*iSelection, 0, KMsvNewAttribute));
       
  2333 			
       
  2334 			// Note that we do not clear the flag here as it will be required
       
  2335 			// for any subsequent non inbox folders that are yet to be synced.
       
  2336 			}
       
  2337 		}
       
  2338 	}
       
  2339 
       
  2340 /**
       
  2341 Sets the folder matched flag
       
  2342 
       
  2343 @param aFolderMatched Value to set flag to
       
  2344 */
       
  2345 void CImapFolder::SetFolderMatched(TBool aFolderMatched)
       
  2346 	{
       
  2347 	iFolderMatched = aFolderMatched;
       
  2348 	}
       
  2349 
       
  2350 /**
       
  2351 Gets the folder matched flag
       
  2352 
       
  2353 @return Folder matched flag value
       
  2354 */
       
  2355 TBool CImapFolder::FolderMatched()
       
  2356 	{
       
  2357 	return iFolderMatched;
       
  2358 	}
       
  2359 
       
  2360 /**
       
  2361 Performs comparison between two folders by comparing their folder names.
       
  2362 
       
  2363 @param aFirst The first folder to compare
       
  2364 @param aSecond The second folder to compare
       
  2365 
       
  2366 @return The result of calling Compare on the folder names
       
  2367 */
       
  2368 TInt CImapFolder::CompareByFolderName(const CImapFolder& aFirst, const CImapFolder& aSecond)
       
  2369 // static method
       
  2370 	{
       
  2371 	return aFirst.iFullFolderPath.Compare(aSecond.iFullFolderPath);
       
  2372 	}