31
|
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 |
}
|