|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <msventry.h> |
|
17 #include <miutset.h> |
|
18 #include <imapset.h> |
|
19 #include "cimapofflinecontrol.h" |
|
20 #include "cimaplogger.h" |
|
21 |
|
22 #ifdef __IMAP_LOGGING |
|
23 |
|
24 LOCAL_D TPtrC8 OffLineOpTypeString(const CImOffLineOperation& aOp) |
|
25 { |
|
26 switch (aOp.OpType()) |
|
27 { |
|
28 case CImOffLineOperation::EOffLineOpNone: |
|
29 return _L8("None"); |
|
30 |
|
31 case CImOffLineOperation::EOffLineOpCopyToLocal: |
|
32 return _L8("CopyToLocal"); |
|
33 case CImOffLineOperation::EOffLineOpCopyFromLocal: |
|
34 return _L8("CopyFromLocal"); |
|
35 case CImOffLineOperation::EOffLineOpCopyWithinService: |
|
36 return _L8("CopyWithinService"); |
|
37 |
|
38 case CImOffLineOperation::EOffLineOpMoveToLocal: |
|
39 return _L8("MoveToLocal"); |
|
40 case CImOffLineOperation::EOffLineOpMoveFromLocal: |
|
41 return _L8("MoveFromLocal"); |
|
42 case CImOffLineOperation::EOffLineOpMoveWithinService: |
|
43 return _L8("MoveWithinService"); |
|
44 |
|
45 case CImOffLineOperation::EOffLineOpDelete: |
|
46 return _L8("Delete"); |
|
47 |
|
48 case CImOffLineOperation::EOffLineOpChange: |
|
49 return _L8("Change"); |
|
50 case CImOffLineOperation::EOffLineOpCreate: |
|
51 return _L8("Create"); |
|
52 |
|
53 case CImOffLineOperation::EOffLineOpMtmSpecific: |
|
54 switch (aOp.MtmFunctionId()) |
|
55 { |
|
56 case EFnOffLineOpMoveDelete: |
|
57 return _L8("MoveDelete"); |
|
58 case EFnOffLineOpPopulate: |
|
59 return _L8("Populate"); |
|
60 default: |
|
61 return _L8("UnknownMtmSpecific"); |
|
62 } |
|
63 default: |
|
64 break; |
|
65 } |
|
66 return _L8("Unknown"); |
|
67 } |
|
68 |
|
69 LOCAL_D TPtrC8 Imap4OpTypeString(CImapOfflineControl::TImap4OpType aOpType) |
|
70 { |
|
71 switch (aOpType) |
|
72 { |
|
73 case CImapOfflineControl::EImap4OpCopyToLocal: |
|
74 return _L8("CopyToLocal"); |
|
75 case CImapOfflineControl::EImap4OpCopyFromLocal: |
|
76 return _L8("CopyFromLocal"); |
|
77 case CImapOfflineControl::EImap4OpCopyWithinService: |
|
78 return _L8("CopyWithinService"); |
|
79 case CImapOfflineControl::EImap4OpMoveToLocal: |
|
80 return _L8("MoveToLocal"); |
|
81 case CImapOfflineControl::EImap4OpMoveFromLocal: |
|
82 return _L8("MoveFromLocal"); |
|
83 case CImapOfflineControl::EImap4OpMoveWithinService: |
|
84 return _L8("MoveWithinService"); |
|
85 case CImapOfflineControl::EImap4OpDelete: |
|
86 return _L8("Delete"); |
|
87 case CImapOfflineControl::EImap4OpMoveTypeDelete: |
|
88 return _L8("MoveDelete"); |
|
89 case CImapOfflineControl::EImap4OpPopulate: |
|
90 return _L8("Populate"); |
|
91 default: |
|
92 break; |
|
93 } |
|
94 return _L8("Unknown"); |
|
95 } |
|
96 #endif |
|
97 |
|
98 |
|
99 EXPORT_C CImapOfflineControl* CImapOfflineControl::NewL(CMsvServerEntry& aEntry) |
|
100 { |
|
101 CImapOfflineControl* self = new (ELeave) CImapOfflineControl(aEntry); |
|
102 CleanupStack::PushL(self); |
|
103 self->ConstructL(); |
|
104 CleanupStack::Pop(self); |
|
105 return self; |
|
106 } |
|
107 |
|
108 CImapOfflineControl::CImapOfflineControl(CMsvServerEntry& aEntry) |
|
109 : CMsgActive(EPriorityStandard), iEntry(aEntry) |
|
110 { |
|
111 CActiveScheduler::Add(this); |
|
112 } |
|
113 |
|
114 void CImapOfflineControl::ConstructL() |
|
115 { |
|
116 iCopyDirect = new (ELeave) CMsvEntrySelection; |
|
117 iMoveDirect = new (ELeave) CMsvEntrySelection; |
|
118 iMoveToLocalDirect = new (ELeave) CMsvEntrySelection; |
|
119 } |
|
120 |
|
121 CImapOfflineControl::~CImapOfflineControl() |
|
122 { |
|
123 delete iCopyDirect; |
|
124 delete iMoveDirect; |
|
125 delete iMoveToLocalDirect; |
|
126 } |
|
127 |
|
128 /** |
|
129 public routines |
|
130 |
|
131 Store an offline copy/move/delete command: we need to determine which |
|
132 folder the offline command should be stored in dependent on the |
|
133 source of the command. |
|
134 |
|
135 CopyToLocal can contain whole messages or parts (but not embedded |
|
136 messages). It can also be a copy to NULL, in which case it means |
|
137 just populate the mirror |
|
138 |
|
139 Any item can contain whole messages, but not folders, and can |
|
140 contain shadow ids |
|
141 */ |
|
142 |
|
143 EXPORT_C void CImapOfflineControl::StoreOfflineCommandL(TImap4OpType aOperation, |
|
144 const CMsvEntrySelection& aSelection, |
|
145 TMsvId aDestination, |
|
146 TRequestStatus& aStatus) |
|
147 { |
|
148 TBuf8<128> params = _L8(""); |
|
149 StoreOfflineCommandL( aOperation, aSelection, aDestination, params, aStatus ); |
|
150 } |
|
151 |
|
152 EXPORT_C void CImapOfflineControl::StoreOfflineCommandL(TImap4OpType aOperation, |
|
153 const CMsvEntrySelection& aSelection, |
|
154 TMsvId aDestination, |
|
155 const TDesC8& aParams, |
|
156 TRequestStatus& aStatus) |
|
157 { |
|
158 #ifdef __IMAP_LOGGING |
|
159 TPtrC8 p = Imap4OpTypeString(aOperation); |
|
160 __LOG_FORMAT((KDefaultLog,"StoreOfflineCommand: op %S %d entries to %x param bytes %d", &p, aSelection.Count(), aDestination, aParams.Length())); |
|
161 #endif |
|
162 |
|
163 Queue(aStatus); |
|
164 |
|
165 iDestination = aDestination; |
|
166 |
|
167 // work our which service we are dealing with |
|
168 iServiceId = ServiceOfL( aOperation == EImap4OpCopyFromLocal || |
|
169 aOperation == EImap4OpMoveFromLocal ? |
|
170 aDestination : aSelection[0] ); |
|
171 |
|
172 // clear list of Direct operations to do after storing |
|
173 // commands |
|
174 iCopyDirect->Reset(); |
|
175 iMoveDirect->Reset(); |
|
176 iMoveToLocalDirect->Reset(); |
|
177 |
|
178 //update the progress info |
|
179 iProgressMsgsToDo=aSelection.Count(); |
|
180 |
|
181 for (TInt i = 0; i < aSelection.Count(); i++) |
|
182 { |
|
183 CImOffLineOperation* op = new(ELeave)CImOffLineOperation(); |
|
184 CleanupStack::PushL(op); |
|
185 |
|
186 // See if the message is in fact a shadow |
|
187 TMsvId origId = aSelection[i]; |
|
188 SetEntryL(origId); |
|
189 |
|
190 TMsvId shadowId = KMsvNullIndexEntryId; |
|
191 TMsvId shadowParentId = KMsvNullIndexEntryId; |
|
192 TMsvEmailEntry entry = iEntry.Entry(); |
|
193 if (entry.iRelatedId) |
|
194 { |
|
195 shadowId = origId; |
|
196 shadowParentId = entry.Parent(); |
|
197 origId = entry.iRelatedId; |
|
198 |
|
199 // it is possible that the original has been deleted by |
|
200 // now (if it were local). If so then skip this operation |
|
201 TInt err = iEntry.SetEntry(origId); |
|
202 if (err != KErrNone) |
|
203 origId = KMsvNullIndexEntryId; |
|
204 else |
|
205 entry = iEntry.Entry(); |
|
206 } |
|
207 |
|
208 if (origId != KMsvNullIndexEntryId) |
|
209 { |
|
210 // entry contains original (not shadow) message details |
|
211 |
|
212 // it is an undo type operation if we are copying or moving a |
|
213 // shadow back to its original folder and the original is |
|
214 // invisible or deleted |
|
215 TBool undeleteOp = shadowId != KMsvNullIndexEntryId && |
|
216 entry.Parent() == iDestination && |
|
217 (!entry.Visible() || entry.DisconnectedOperation() == EDisconnectedDeleteOperation); |
|
218 |
|
219 // Make operation & save it |
|
220 switch(aOperation) |
|
221 { |
|
222 case EImap4OpCopyToLocal: |
|
223 iRequestedOperation=TImap4GenericProgress::EOffLineCopyToLocal; |
|
224 if (undeleteOp) |
|
225 { |
|
226 UndeleteOperationL(origId, shadowParentId, ETrue); |
|
227 } |
|
228 else if (IdIsLocalL(origId) || entry.Complete()) |
|
229 { |
|
230 // either direct local copy or copy from mirror of completely populated message |
|
231 // either way, add new entry to array |
|
232 iCopyDirect->AppendL(origId); |
|
233 } |
|
234 else |
|
235 { |
|
236 op->SetCopyToLocal(origId,iDestination); |
|
237 SaveOperationL(*op); |
|
238 } |
|
239 break; |
|
240 |
|
241 case EImap4OpCopyFromLocal: |
|
242 iRequestedOperation=TImap4GenericProgress::EOffLineCopyFromLocal; |
|
243 case EImap4OpCopyWithinService: |
|
244 iRequestedOperation=TImap4GenericProgress::EOffLineCopyWithinService; |
|
245 if (undeleteOp) |
|
246 { |
|
247 UndeleteOperationL(origId, shadowParentId, ETrue); |
|
248 } |
|
249 else if (IdIsLocalL(origId)) |
|
250 { |
|
251 op->SetCopyFromLocal(origId,iDestination); |
|
252 SaveOperationL(*op); |
|
253 } |
|
254 else |
|
255 { |
|
256 op->SetCopyWithinService(origId,iDestination); |
|
257 SaveOperationL(*op); |
|
258 } |
|
259 break; |
|
260 |
|
261 case EImap4OpMoveToLocal: |
|
262 iRequestedOperation=TImap4GenericProgress::EOffLineMoveToLocal; |
|
263 if (undeleteOp) |
|
264 { |
|
265 UndeleteOperationL(origId, shadowParentId, EFalse); |
|
266 DeleteEntryL(shadowId); |
|
267 } |
|
268 else if (IdIsLocalL(origId)) |
|
269 { |
|
270 CImOffLineOperation* origOp = new(ELeave)CImOffLineOperation(); |
|
271 CleanupStack::PushL(origOp); |
|
272 |
|
273 if (FindOffLineOpByIdL( origId, shadowParentId, *origOp, ETrue /* delete op */) == 0) |
|
274 { |
|
275 User::Leave(KErrNotSupported); |
|
276 } |
|
277 |
|
278 if ( OffLineOpIsCopy(*origOp) ) |
|
279 { |
|
280 // add new local to local copy op |
|
281 iCopyDirect->AppendL(origId); |
|
282 } |
|
283 else |
|
284 { |
|
285 // direct local move |
|
286 iMoveDirect->AppendL(origId); |
|
287 } |
|
288 |
|
289 DeleteEntryL(shadowId); |
|
290 CleanupStack::PopAndDestroy(origOp); |
|
291 } |
|
292 else if (entry.Complete()) |
|
293 { |
|
294 // Not local, but completely populated |
|
295 iMoveToLocalDirect->AppendL(origId); |
|
296 } |
|
297 else |
|
298 { |
|
299 op->SetMoveToLocal(origId,iDestination); |
|
300 SaveOperationL(*op); |
|
301 } |
|
302 break; |
|
303 |
|
304 case EImap4OpMoveFromLocal: |
|
305 iRequestedOperation=TImap4GenericProgress::EOffLineMoveFromLocal; |
|
306 case EImap4OpMoveWithinService: |
|
307 iRequestedOperation=TImap4GenericProgress::EOffLineMoveWithinService; |
|
308 if (undeleteOp) |
|
309 { |
|
310 UndeleteOperationL(origId, shadowParentId, EFalse); |
|
311 |
|
312 // this one can fail depending on what kind of |
|
313 // undelete operation it was |
|
314 CImOffLineOperation* origOp = new(ELeave)CImOffLineOperation(); |
|
315 CleanupStack::PushL(origOp); |
|
316 |
|
317 FindOffLineOpByIdL( origId, shadowParentId, *origOp, ETrue /* delete op */); |
|
318 |
|
319 DeleteEntryL(shadowId); |
|
320 CleanupStack::PopAndDestroy(origOp); |
|
321 } |
|
322 else if (shadowId) |
|
323 { |
|
324 CImOffLineOperation* origOp = new(ELeave)CImOffLineOperation(); |
|
325 CleanupStack::PushL(origOp); |
|
326 |
|
327 if (FindOffLineOpByIdL( origId, shadowParentId, *origOp, ETrue /* delete op */) == 0) |
|
328 { |
|
329 User::Leave(KErrNotSupported); |
|
330 } |
|
331 |
|
332 // Clean disconnected flags |
|
333 SetEntryL(origId); |
|
334 TMsvEmailEntry entry = iEntry.Entry(); |
|
335 if (entry.DisconnectedOperation() != EDisconnectedMultipleOperation) |
|
336 { |
|
337 entry.SetDisconnectedOperation(ENoDisconnectedOperations); |
|
338 ChangeEntryL(entry); |
|
339 } |
|
340 |
|
341 // if shadow was the result of a copy then change |
|
342 // original copy to point to new destination |
|
343 |
|
344 // if shadow was result of a move then change move to |
|
345 // point to new destination |
|
346 if ( OffLineOpIsCopy(*origOp) ) |
|
347 { |
|
348 if (IdIsLocalL(origId)) |
|
349 op->SetCopyFromLocal(origId,iDestination); |
|
350 else |
|
351 op->SetCopyWithinService(origId,iDestination); |
|
352 } |
|
353 else |
|
354 { |
|
355 if (IdIsLocalL(origId)) |
|
356 op->SetMoveFromLocal(origId,iDestination); |
|
357 else |
|
358 op->SetMoveWithinService(origId,iDestination); |
|
359 } |
|
360 |
|
361 SaveOperationL(*op); |
|
362 |
|
363 DeleteEntryL(shadowId); |
|
364 CleanupStack::PopAndDestroy(origOp); |
|
365 } |
|
366 else |
|
367 { |
|
368 if (IdIsLocalL(origId)) |
|
369 op->SetMoveFromLocal(origId,iDestination); |
|
370 else |
|
371 op->SetMoveWithinService(origId,iDestination); |
|
372 SaveOperationL(*op); |
|
373 } |
|
374 break; |
|
375 |
|
376 case EImap4OpDelete: |
|
377 iRequestedOperation=TImap4GenericProgress::EOffLineDelete; |
|
378 // we treat shadows and real items the same for deletion |
|
379 // currently |
|
380 op->SetDelete( shadowId ? shadowId : origId ); |
|
381 SaveOperationL(*op); |
|
382 break; |
|
383 |
|
384 case EImap4OpUndelete: |
|
385 iRequestedOperation=TImap4GenericProgress::EOffLineUndelete; |
|
386 if (shadowId) |
|
387 { |
|
388 UndeleteOperationL(shadowId, shadowParentId, EFalse); |
|
389 } |
|
390 else |
|
391 { |
|
392 // if the entry is not a shadow then we need to |
|
393 // replace the disconnected op flags with the original |
|
394 // flags before it was deleted. |
|
395 CImOffLineOperation* origOp = new(ELeave)CImOffLineOperation(); |
|
396 CleanupStack::PushL(origOp); |
|
397 |
|
398 // this searches the list before the delete is |
|
399 // removed. However since deletes are stored at |
|
400 // the end of the list then if there are any other |
|
401 // operations it will return the other, and a |
|
402 // count of 2 or greater. |
|
403 TInt count = FindOffLineOpByIdL(origId, KMsvNullIndexEntryId, *origOp, EFalse); |
|
404 |
|
405 TImDisconnectedOperationType disconnectedType = ENoDisconnectedOperations; |
|
406 if (count == 2) |
|
407 disconnectedType = OffLineOpToDisconnectedOp( *origOp ); |
|
408 else if (count > 2) |
|
409 disconnectedType = EDisconnectedMultipleOperation; |
|
410 |
|
411 UndeleteOperationL(origId, KMsvNullIndexEntryId, EFalse, disconnectedType); |
|
412 |
|
413 CleanupStack::PopAndDestroy(origOp); |
|
414 } |
|
415 |
|
416 ++iProgressMsgsDone; // this is normally done in SaveOperationL() but the undelete op does not use that method. |
|
417 break; |
|
418 |
|
419 case EImap4OpPopulate: |
|
420 iRequestedOperation=TImap4GenericProgress::EOffLinePopulate; |
|
421 /* easy one, just populate the original */ |
|
422 op->SetMtmSpecificCommandL(origId, iDestination, EFnOffLineOpPopulate, aParams); |
|
423 SaveOperationL(*op); |
|
424 break; |
|
425 |
|
426 case EImap4OpMoveTypeDelete: |
|
427 __ASSERT_DEBUG(0, User::Invariant()); |
|
428 break; |
|
429 } |
|
430 } |
|
431 |
|
432 CleanupStack::PopAndDestroy(op); |
|
433 |
|
434 } // end of for loop |
|
435 |
|
436 // if there are entries left over then they are ones we added to |
|
437 // be done immediately |
|
438 if (!DoLocalOpL()) |
|
439 { |
|
440 // Request has been queued, complete immediately |
|
441 Complete(KErrNone); |
|
442 } |
|
443 } |
|
444 |
|
445 // Cancel offline operations queued in the folders/service mentioned |
|
446 // in the selection |
|
447 |
|
448 EXPORT_C void CImapOfflineControl::CancelOffLineOperationsL(const CMsvEntrySelection& aSelection) |
|
449 { |
|
450 __LOG_FORMAT((KDefaultLog, "CancelOfflineOperations: %d entries", aSelection.Count())); |
|
451 |
|
452 for (TInt i = 0; i < aSelection.Count(); i++) |
|
453 { |
|
454 TMsvId id = aSelection[i]; |
|
455 |
|
456 SetEntryL(id); |
|
457 TMsvEmailEntry entry = iEntry.Entry(); |
|
458 if (entry.iType == KUidMsvFolderEntry) |
|
459 { |
|
460 CImOffLineOperationArray* array = OffLineOpArrayL(id); |
|
461 CleanupStack::PushL(array); |
|
462 |
|
463 if (array->CountOperations()) |
|
464 { |
|
465 // remove the queued ops |
|
466 while (array->CountOperations()) |
|
467 { |
|
468 CImOffLineOperation* thisOp = new(ELeave)CImOffLineOperation(); |
|
469 CleanupStack::PushL(thisOp); |
|
470 |
|
471 thisOp->CopyL(array->Operation(0)); |
|
472 |
|
473 UndoOfflineOpL(*thisOp, ETrue); |
|
474 |
|
475 array->Delete(0); |
|
476 CleanupStack::PopAndDestroy(thisOp); |
|
477 } |
|
478 |
|
479 // write back empty array to store |
|
480 SetOffLineOpArrayL(id, *array); |
|
481 } |
|
482 |
|
483 CleanupStack::PopAndDestroy(); // array |
|
484 } |
|
485 } |
|
486 } |
|
487 |
|
488 |
|
489 TImDisconnectedOperationType CImapOfflineControl::OffLineOpToDisconnectedOp(const CImOffLineOperation& aOp) |
|
490 { |
|
491 TImDisconnectedOperationType type; |
|
492 switch (aOp.OpType()) |
|
493 { |
|
494 case CImOffLineOperation::EOffLineOpMoveToLocal: |
|
495 type = EDisconnectedMoveToOperation; |
|
496 break; |
|
497 case CImOffLineOperation::EOffLineOpMoveFromLocal: |
|
498 type = EDisconnectedMoveFromOperation; |
|
499 break; |
|
500 case CImOffLineOperation::EOffLineOpMoveWithinService: |
|
501 type = EDisconnectedMoveWithinServiceOperation; |
|
502 break; |
|
503 |
|
504 case CImOffLineOperation::EOffLineOpCopyToLocal: |
|
505 type = EDisconnectedCopyToOperation; |
|
506 break; |
|
507 case CImOffLineOperation::EOffLineOpCopyFromLocal: |
|
508 type = EDisconnectedCopyFromOperation; |
|
509 break; |
|
510 case CImOffLineOperation::EOffLineOpCopyWithinService: |
|
511 type = EDisconnectedCopyWithinServiceOperation; |
|
512 break; |
|
513 |
|
514 case CImOffLineOperation::EOffLineOpDelete: |
|
515 type = EDisconnectedDeleteOperation; |
|
516 break; |
|
517 |
|
518 case CImOffLineOperation::EOffLineOpMtmSpecific: |
|
519 type = EDisconnectedSpecialOperation; |
|
520 break; |
|
521 default: |
|
522 type = EDisconnectedUnknownOperation; |
|
523 break; |
|
524 } |
|
525 return type; |
|
526 } |
|
527 |
|
528 // This returns TRUE is it is a strict copy operation. Populate can be |
|
529 // considered False by the callers of this function. |
|
530 |
|
531 TBool CImapOfflineControl::OffLineOpIsCopy(const CImOffLineOperation& aOp) |
|
532 { |
|
533 switch (aOp.OpType()) |
|
534 { |
|
535 case CImOffLineOperation::EOffLineOpCopyToLocal: |
|
536 case CImOffLineOperation::EOffLineOpCopyFromLocal: |
|
537 case CImOffLineOperation::EOffLineOpCopyWithinService: |
|
538 return ETrue; |
|
539 default: |
|
540 break; |
|
541 } |
|
542 return EFalse; |
|
543 } |
|
544 |
|
545 TInt CImapOfflineControl::PosVal(const CImOffLineOperation& aOp) |
|
546 { |
|
547 switch (aOp.OpType()) |
|
548 { |
|
549 case CImOffLineOperation::EOffLineOpMtmSpecific: // populate |
|
550 switch (aOp.MtmFunctionId()) |
|
551 { |
|
552 case EFnOffLineOpMoveDelete: |
|
553 return 5; |
|
554 case EFnOffLineOpPopulate: |
|
555 return 0; |
|
556 } |
|
557 break; |
|
558 |
|
559 case CImOffLineOperation::EOffLineOpCopyToLocal: |
|
560 case CImOffLineOperation::EOffLineOpCopyWithinService: |
|
561 return 1; |
|
562 case CImOffLineOperation::EOffLineOpCopyFromLocal: |
|
563 return 2; |
|
564 |
|
565 case CImOffLineOperation::EOffLineOpMoveToLocal: |
|
566 case CImOffLineOperation::EOffLineOpMoveWithinService: |
|
567 return 3; |
|
568 |
|
569 case CImOffLineOperation::EOffLineOpMoveFromLocal: |
|
570 return 4; |
|
571 |
|
572 case CImOffLineOperation::EOffLineOpDelete: |
|
573 return 6; |
|
574 default: |
|
575 break; |
|
576 } |
|
577 return 6; |
|
578 } |
|
579 |
|
580 |
|
581 // Do setentry, leave if there is an error |
|
582 void CImapOfflineControl::SetEntryL(TMsvId aId) |
|
583 { |
|
584 User::LeaveIfError(iEntry.SetEntry(aId)); |
|
585 } |
|
586 |
|
587 // Change entry, leave if error |
|
588 void CImapOfflineControl::ChangeEntryL(TMsvEntry& aEntry) |
|
589 { |
|
590 User::LeaveIfError(iEntry.ChangeEntry(aEntry)); |
|
591 } |
|
592 |
|
593 // remove an id, leave if error, moves to the parent first |
|
594 void CImapOfflineControl::DeleteEntryL(TMsvId aId) |
|
595 { |
|
596 SetEntryL(aId); |
|
597 SetEntryL(iEntry.Entry().Parent()); |
|
598 User::LeaveIfError(iEntry.DeleteEntry(aId)); |
|
599 } |
|
600 |
|
601 // Find the folder that encloses this message or message part. Note |
|
602 // that this must be a real folder, not a folder component of a |
|
603 // message, and that it may not be in our service. |
|
604 TMsvId CImapOfflineControl::FolderOfL(TMsvId aId) |
|
605 { |
|
606 SetEntryL( MessageOfL(aId) ); |
|
607 return iEntry.Entry().Parent(); |
|
608 } |
|
609 |
|
610 // If the message is not in our service then return the destination |
|
611 // folder. Otherwise return its own parent folder. |
|
612 TMsvId CImapOfflineControl::FindOffLineSaveFolderL(TMsvId aId, TMsvId aDestId) |
|
613 { |
|
614 TMsvId folder = FolderOfL(aId); |
|
615 if (ServiceOfL(folder) == iServiceId) |
|
616 return folder; |
|
617 return aDestId; |
|
618 } |
|
619 |
|
620 // Find the top level message that holds this message part. Can be |
|
621 // itself if it is a real message itself. This is located by finding |
|
622 // the message that is highest up the tree. |
|
623 TMsvId CImapOfflineControl::MessageOfL(TMsvId aId) |
|
624 { |
|
625 TMsvId current=aId; |
|
626 TMsvId msg=aId; |
|
627 while(current!=KMsvRootIndexEntryIdValue) |
|
628 { |
|
629 // Visit this entry |
|
630 SetEntryL(current); |
|
631 |
|
632 TMsvEmailEntry entry = iEntry.Entry(); |
|
633 |
|
634 // if service then searched far enough |
|
635 if (entry.iType==KUidMsvServiceEntry) |
|
636 break; |
|
637 |
|
638 // if message type then store it |
|
639 if (entry.iType==KUidMsvMessageEntry) |
|
640 msg = entry.Id(); |
|
641 |
|
642 // Go upwards |
|
643 current=entry.Parent(); |
|
644 } |
|
645 |
|
646 return msg; |
|
647 } |
|
648 |
|
649 // return the id of the service containing this id |
|
650 TMsvId CImapOfflineControl::ServiceOfL(TMsvId aId) |
|
651 { |
|
652 TMsvId current=aId; |
|
653 while(current!=KMsvRootIndexEntryIdValue) |
|
654 { |
|
655 // Visit this entry |
|
656 SetEntryL(current); |
|
657 |
|
658 TMsvEmailEntry entry = iEntry.Entry(); |
|
659 |
|
660 // if service then searched far enough |
|
661 if (entry.iType==KUidMsvServiceEntry) |
|
662 break; |
|
663 |
|
664 // Go upwards |
|
665 current=entry.Parent(); |
|
666 } |
|
667 |
|
668 return current; |
|
669 } |
|
670 |
|
671 // is this id in the local service? |
|
672 EXPORT_C TMsvId CImapOfflineControl::IdIsLocalL(TMsvId aId) |
|
673 { |
|
674 return ServiceOfL(aId) == KMsvLocalServiceIndexEntryIdValue; |
|
675 } |
|
676 |
|
677 |
|
678 // simple functions to get and set the offline array on an id. More |
|
679 // efficient open and modify versions are possible and used elsewhere |
|
680 |
|
681 EXPORT_C CImOffLineOperationArray* CImapOfflineControl::OffLineOpArrayL(TMsvId aId) |
|
682 { |
|
683 SetEntryL(aId); |
|
684 |
|
685 CImOffLineOperationArray* array = CImOffLineOperationArray::NewL(); |
|
686 CleanupStack::PushL(array); |
|
687 |
|
688 // if no store then return an empty array (easier for higher |
|
689 // layers than a NULL pointer). |
|
690 if (iEntry.HasStoreL()) |
|
691 { |
|
692 CMsvStore* store = iEntry.ReadStoreL(); |
|
693 CleanupStack::PushL(store); |
|
694 |
|
695 CImOffLineArrayStore arraystore(*array); |
|
696 arraystore.RestoreL(*store); |
|
697 |
|
698 CleanupStack::PopAndDestroy(); // store |
|
699 } |
|
700 |
|
701 // DBG((_L8("OffLineOpArrayL: folder 0x%x count %d"), aId, array->CountOperations())); |
|
702 |
|
703 CleanupStack::Pop(); // array |
|
704 return array; |
|
705 } |
|
706 |
|
707 EXPORT_C void CImapOfflineControl::SetOffLineOpArrayL(TMsvId aId, CImOffLineOperationArray& aArray) |
|
708 { |
|
709 // DBG((_L8("SetOffLineOpArrayL: folder 0x%x count %d"), aId, aArray.CountOperations())); |
|
710 |
|
711 SetEntryL( aId ); |
|
712 |
|
713 CMsvStore* store=iEntry.EditStoreL(); |
|
714 CleanupStack::PushL(store); |
|
715 |
|
716 CImOffLineArrayStore arraystore(aArray); |
|
717 arraystore.StoreL(*store); |
|
718 |
|
719 store->CommitL(); |
|
720 |
|
721 CleanupStack::PopAndDestroy(); // store |
|
722 } |
|
723 |
|
724 |
|
725 // Save offline operation |
|
726 void CImapOfflineControl::SaveOperationL(const CImOffLineOperation& aOperation) |
|
727 { |
|
728 // DBG((_L8("SaveOperation:"))); |
|
729 |
|
730 // We need an array, to store the current offline operations of this folder |
|
731 CImOffLineOperationArray *array=CImOffLineOperationArray::NewL(); |
|
732 CleanupStack::PushL(array); |
|
733 CImOffLineArrayStore arraystore(*array); |
|
734 |
|
735 // find where to store the op |
|
736 TMsvId storehere = FindOffLineSaveFolderL(aOperation.MessageId(), aOperation.TargetMessageId()); |
|
737 SetEntryL(storehere); |
|
738 |
|
739 // open the store |
|
740 CMsvStore *store=iEntry.EditStoreL(); |
|
741 CleanupStack::PushL(store); |
|
742 |
|
743 arraystore.RestoreL(*store); |
|
744 |
|
745 // we add this operation after others of the same type |
|
746 TInt insertBefore = PosVal(aOperation) + 1; |
|
747 TBool done = EFalse; |
|
748 |
|
749 for(TInt a=0; a<array->CountOperations(); a++) |
|
750 { |
|
751 if (insertBefore <= PosVal(array->Operation(a))) |
|
752 { |
|
753 array->InsertOperationL(MUTABLE_CAST(CImOffLineOperation&, aOperation), a); |
|
754 done = ETrue; |
|
755 break; |
|
756 } |
|
757 } |
|
758 |
|
759 if (!done) |
|
760 array->AppendOperationL(aOperation); |
|
761 |
|
762 // write back |
|
763 arraystore.StoreL(*store); |
|
764 store->CommitL(); |
|
765 |
|
766 // Dispose of store & array |
|
767 CleanupStack::PopAndDestroy(2); |
|
768 |
|
769 // make the shadow |
|
770 MakeShadowL(aOperation); |
|
771 |
|
772 //update the progrees info |
|
773 ++iProgressMsgsDone; |
|
774 } |
|
775 |
|
776 // returns ETrue if a matching Op was found |
|
777 |
|
778 TInt CImapOfflineControl::FindOffLineOpByIdL(TMsvId aId, TMsvId aDestFolder, |
|
779 CImOffLineOperation& aOp, TBool aDelete) |
|
780 { |
|
781 CImOffLineOperationArray *array=CImOffLineOperationArray::NewL(); |
|
782 CleanupStack::PushL(array); |
|
783 CImOffLineArrayStore arraystore(*array); |
|
784 |
|
785 SetEntryL(FindOffLineSaveFolderL(aId, aDestFolder)); |
|
786 CMsvStore *store=aDelete ? iEntry.EditStoreL() : iEntry.ReadStoreL(); |
|
787 CleanupStack::PushL(store); |
|
788 |
|
789 arraystore.RestoreL(*store); |
|
790 |
|
791 // look in the array for an operation on this Id and optionally to |
|
792 // the matching folder |
|
793 TInt found = 0; |
|
794 TInt foundAt = -1; |
|
795 for(TInt a=0; a<array->CountOperations(); a++) |
|
796 { |
|
797 if (array->Operation(a).MessageId() == aId && |
|
798 (aDestFolder == KMsvNullIndexEntryId || |
|
799 aDestFolder == array->Operation(a).TargetMessageId()) ) |
|
800 { |
|
801 // only write out the first operation found |
|
802 if (found == 0) |
|
803 { |
|
804 foundAt = a; |
|
805 aOp.CopyL( array->Operation(a) ); |
|
806 } |
|
807 found++; |
|
808 } |
|
809 } |
|
810 |
|
811 // optionally now delete the operation from the array |
|
812 if (aDelete && foundAt != -1) |
|
813 { |
|
814 array->Delete(foundAt); |
|
815 |
|
816 arraystore.StoreL(*store); |
|
817 store->CommitL(); |
|
818 } |
|
819 |
|
820 CleanupStack::PopAndDestroy(2); // store, array |
|
821 |
|
822 return found; |
|
823 } |
|
824 |
|
825 // this means remove the cause of the delete, ie remove delete or |
|
826 // change move to copy, unless ConvertToCopy is False in which case |
|
827 // delete any move operation rather than convert it. |
|
828 |
|
829 // there can only be one relevant operation in the array as the UI or |
|
830 // MTM should have prevented further operations |
|
831 |
|
832 // Deleting any shadow entry should be done outside this function |
|
833 |
|
834 void CImapOfflineControl::UndeleteOperationL(TMsvId aId, TMsvId aDestId, TBool aConvertMoveToCopy, |
|
835 TImDisconnectedOperationType aDisconnected) |
|
836 { |
|
837 // DBG((_L8("UndeleteOperation: Id %x CvtMove %d type %d"), |
|
838 // aId, aConvertMoveToCopy, aDisconnected)); |
|
839 |
|
840 // We need an array, to store the current offline operations of this folder |
|
841 CImOffLineOperationArray *array=CImOffLineOperationArray::NewL(); |
|
842 CleanupStack::PushL(array); |
|
843 CImOffLineArrayStore arraystore(*array); |
|
844 |
|
845 SetEntryL(FindOffLineSaveFolderL(aId, aDestId)); |
|
846 // DBG((_L8("UndeleteOperation: opending savefolder store %x"), iEntry.Entry().Id() )); |
|
847 CMsvStore *store=iEntry.EditStoreL(); |
|
848 CleanupStack::PushL(store); |
|
849 |
|
850 arraystore.RestoreL(*store); |
|
851 |
|
852 // look in the array for a delete or move operation on this Id |
|
853 CImOffLineOperation* thisOp = new(ELeave)CImOffLineOperation(); |
|
854 CleanupStack::PushL(thisOp); |
|
855 |
|
856 for(TInt a=0; a<array->CountOperations(); a++) |
|
857 { |
|
858 thisOp->CopyL(array->Operation(a)); |
|
859 |
|
860 if (thisOp->MessageId() == aId) |
|
861 { |
|
862 TBool finish = ETrue; |
|
863 TBool isDelete = EFalse; |
|
864 |
|
865 switch (thisOp->OpType()) |
|
866 { |
|
867 // if move then convert it to an equivalent copy |
|
868 case CImOffLineOperation::EOffLineOpMoveToLocal: |
|
869 thisOp->SetCopyToLocal(aId, thisOp->TargetMessageId()); |
|
870 break; |
|
871 |
|
872 case CImOffLineOperation::EOffLineOpMoveFromLocal: |
|
873 thisOp->SetCopyFromLocal(aId, thisOp->TargetMessageId()); |
|
874 break; |
|
875 |
|
876 case CImOffLineOperation::EOffLineOpMoveWithinService: |
|
877 thisOp->SetCopyWithinService(aId, thisOp->TargetMessageId()); |
|
878 break; |
|
879 |
|
880 // if delete then get rid of the pending operation |
|
881 case CImOffLineOperation::EOffLineOpDelete: |
|
882 isDelete = ETrue; |
|
883 break; |
|
884 |
|
885 default: |
|
886 finish = EFalse; |
|
887 break; |
|
888 } |
|
889 |
|
890 if (finish) |
|
891 { |
|
892 // remove the existing operation |
|
893 array->Delete(a); |
|
894 |
|
895 // potentially add a new one |
|
896 if (!isDelete) |
|
897 { |
|
898 // it's become a copy so insert at head of list |
|
899 if (aConvertMoveToCopy) |
|
900 array->InsertOperationL(*thisOp, 0); |
|
901 } |
|
902 |
|
903 break; |
|
904 } |
|
905 } |
|
906 |
|
907 } // end of for loop |
|
908 |
|
909 // DBG((_L8("UndeleteOperation: write store"))); |
|
910 |
|
911 // write back offline op array |
|
912 arraystore.StoreL(*store); |
|
913 store->CommitL(); |
|
914 |
|
915 CleanupStack::PopAndDestroy(thisOp); |
|
916 thisOp = NULL; |
|
917 CleanupStack::PopAndDestroy(store); |
|
918 store = NULL; |
|
919 CleanupStack::PopAndDestroy(array); |
|
920 array = NULL; |
|
921 |
|
922 // DBG((_L8("UndeleteOperation: ensure visible"))); |
|
923 |
|
924 // then make the item visible and update its pending operation |
|
925 // type |
|
926 SetEntryL(aId); |
|
927 TMsvEmailEntry entry = iEntry.Entry(); |
|
928 |
|
929 entry.SetDisconnectedOperation(aDisconnected); |
|
930 entry.SetVisible(ETrue); |
|
931 |
|
932 ChangeEntryL(entry); |
|
933 |
|
934 // DBG((_L8("UndeleteOperation: done"))); |
|
935 } |
|
936 |
|
937 // Make shadow for offline operation - this shadow indicates what |
|
938 // *will* happen at the next sync |
|
939 |
|
940 // Note if we want to copy the entire structure of the message then |
|
941 // there is a ready made function Imap4Session->CopyMessageL() to do |
|
942 // this |
|
943 void CImapOfflineControl::MakeCopyMoveShadowL(const CImOffLineOperation& aOp) |
|
944 { |
|
945 // get copy of the original message |
|
946 SetEntryL(aOp.MessageId()); |
|
947 TMsvEmailEntry origMsg = iEntry.Entry(); |
|
948 |
|
949 // check this is a real message, we don't make shadows of parts |
|
950 if (origMsg.iType != KUidMsvMessageEntry) |
|
951 return; |
|
952 |
|
953 // if this is not a copy to mirror only operation then make shadow |
|
954 if ( aOp.OpType() != CImOffLineOperation::EOffLineOpMtmSpecific ) |
|
955 { |
|
956 // copy out the non embedded data |
|
957 HBufC* details = origMsg.iDetails.AllocL(); |
|
958 CleanupStack::PushL(details); |
|
959 HBufC* description = origMsg.iDescription.AllocL(); |
|
960 CleanupStack::PushL(description); |
|
961 |
|
962 // set up the new message, clearing any disconnected op flags |
|
963 // it may have |
|
964 TMsvEmailEntry newMsg = origMsg; |
|
965 newMsg.iRelatedId = aOp.MessageId(); |
|
966 newMsg.SetComplete(EFalse); |
|
967 newMsg.SetDisconnectedOperation(ENoDisconnectedOperations); |
|
968 // ensure that this one is visible (may be copied from one |
|
969 // that wasn't) |
|
970 newMsg.SetVisible(ETrue); |
|
971 |
|
972 // create shadow entry |
|
973 SetEntryL(aOp.TargetMessageId()); |
|
974 |
|
975 newMsg.iDetails.Set(details->Des()); |
|
976 newMsg.iDescription.Set(description->Des()); |
|
977 User::LeaveIfError(iEntry.CreateEntry(newMsg)); |
|
978 |
|
979 CleanupStack::PopAndDestroy(2); // description, details |
|
980 } |
|
981 |
|
982 // set flags on the original message |
|
983 SetEntryL(origMsg.Id()); |
|
984 |
|
985 if (origMsg.DisconnectedOperation() == ENoDisconnectedOperations) |
|
986 origMsg.SetDisconnectedOperation( OffLineOpToDisconnectedOp(aOp) ); |
|
987 else |
|
988 origMsg.SetDisconnectedOperation( EDisconnectedMultipleOperation ); |
|
989 |
|
990 // make original invisible if this was a move operation |
|
991 if (!OffLineOpIsCopy(aOp)) |
|
992 origMsg.SetVisible(EFalse); |
|
993 |
|
994 // write back changes |
|
995 ChangeEntryL(origMsg); |
|
996 } |
|
997 |
|
998 void CImapOfflineControl::MakeShadowL(const CImOffLineOperation& aOp) |
|
999 { |
|
1000 // DBG((_L8("MakeShadow: of %x in folder %x"), aOp.MessageId(), aOp.TargetMessageId())); |
|
1001 |
|
1002 switch (aOp.OpType()) |
|
1003 { |
|
1004 case CImOffLineOperation::EOffLineOpMtmSpecific: // populate |
|
1005 case CImOffLineOperation::EOffLineOpMoveToLocal: |
|
1006 case CImOffLineOperation::EOffLineOpMoveFromLocal: |
|
1007 case CImOffLineOperation::EOffLineOpMoveWithinService: |
|
1008 case CImOffLineOperation::EOffLineOpCopyToLocal: |
|
1009 case CImOffLineOperation::EOffLineOpCopyFromLocal: |
|
1010 case CImOffLineOperation::EOffLineOpCopyWithinService: |
|
1011 MakeCopyMoveShadowL(aOp); |
|
1012 break; |
|
1013 |
|
1014 case CImOffLineOperation::EOffLineOpDelete: |
|
1015 // Set the pending operation to Delete, we don't care if there |
|
1016 // were other operations already pending |
|
1017 { |
|
1018 SetEntryL(aOp.MessageId()); |
|
1019 TMsvEmailEntry msg = iEntry.Entry(); |
|
1020 msg.SetDisconnectedOperation(EDisconnectedDeleteOperation); |
|
1021 ChangeEntryL(msg); |
|
1022 } |
|
1023 break; |
|
1024 |
|
1025 case CImOffLineOperation::EOffLineOpNone: |
|
1026 case CImOffLineOperation::EOffLineOpChange: |
|
1027 case CImOffLineOperation::EOffLineOpCreate: |
|
1028 __ASSERT_DEBUG(0, User::Invariant()); |
|
1029 break; |
|
1030 } |
|
1031 |
|
1032 } |
|
1033 |
|
1034 // look in the folder for an item whose iRelatedId matches |
|
1035 TBool CImapOfflineControl::FindShadowIdsL(const CImOffLineOperation& aOp, CMsvEntrySelection& aSelection) |
|
1036 { |
|
1037 CMsvEntrySelection* selection=new (ELeave) CMsvEntrySelection; |
|
1038 CleanupStack::PushL(selection); |
|
1039 |
|
1040 SetEntryL(aOp.TargetMessageId()); |
|
1041 User::LeaveIfError(iEntry.GetChildren(*selection)); |
|
1042 |
|
1043 TBool foundOne = EFalse; |
|
1044 for(TInt child=0;child<selection->Count();child++) |
|
1045 { |
|
1046 TMsvId childId = (*selection)[child]; |
|
1047 SetEntryL(childId); |
|
1048 TMsvEntry message = iEntry.Entry(); |
|
1049 if (message.iRelatedId == aOp.MessageId()) |
|
1050 { |
|
1051 aSelection.InsertL(0, childId); |
|
1052 foundOne = ETrue; |
|
1053 } |
|
1054 } |
|
1055 |
|
1056 CleanupStack::PopAndDestroy(); |
|
1057 |
|
1058 return foundOne; |
|
1059 } |
|
1060 |
|
1061 EXPORT_C TMsvId CImapOfflineControl::FindShadowIdL(const CImOffLineOperation& aOp) |
|
1062 { |
|
1063 CMsvEntrySelection* selection=new (ELeave) CMsvEntrySelection; |
|
1064 CleanupStack::PushL(selection); |
|
1065 |
|
1066 TMsvId id = KMsvNullIndexEntryId; |
|
1067 |
|
1068 // the target folder might have been deleted - in which case just |
|
1069 // return that the id was not found |
|
1070 if (iEntry.SetEntry(aOp.TargetMessageId()) == KErrNone) |
|
1071 { |
|
1072 User::LeaveIfError(iEntry.GetChildren(*selection)); |
|
1073 for(TInt child=0;child<selection->Count();child++) |
|
1074 { |
|
1075 TMsvId childId = (*selection)[child]; |
|
1076 SetEntryL(childId); |
|
1077 TMsvEntry message = iEntry.Entry(); |
|
1078 if (message.iRelatedId == aOp.MessageId()) |
|
1079 { |
|
1080 id = childId; |
|
1081 break; |
|
1082 } |
|
1083 } |
|
1084 } |
|
1085 |
|
1086 CleanupStack::PopAndDestroy(); |
|
1087 |
|
1088 return id; |
|
1089 } |
|
1090 |
|
1091 void CImapOfflineControl::UndoOfflineOpL(const CImOffLineOperation& aOp, TBool aClearMultiples) |
|
1092 { |
|
1093 #ifdef __IMAP_LOGGING |
|
1094 TPtrC8 p = ::OffLineOpTypeString(aOp); |
|
1095 __LOG_FORMAT((KDefaultLog, "UndoOfflineOp: %S Id %x TargetFolder %x",&p, aOp.MessageId(), aOp.TargetMessageId())); |
|
1096 #endif |
|
1097 |
|
1098 // get the first id related to the source of this message, unless |
|
1099 // it has no destination (ie it is a delete op) |
|
1100 if (aOp.TargetMessageId()) |
|
1101 { |
|
1102 TMsvId id = FindShadowIdL(aOp); |
|
1103 if (id != KMsvNullIndexEntryId) |
|
1104 { |
|
1105 SetEntryL(aOp.TargetMessageId()); |
|
1106 iEntry.DeleteEntry(id); |
|
1107 } |
|
1108 } |
|
1109 |
|
1110 // remove the disconnected op flags from the source entry and make |
|
1111 // it visible (does't harm if it was visible anyway), if it has |
|
1112 // multiple ops then we leave it as we don't know what to do. |
|
1113 |
|
1114 // entry might not exist if it was a shadow |
|
1115 if (iEntry.SetEntry(aOp.MessageId()) == KErrNone) |
|
1116 { |
|
1117 TMsvEmailEntry entry = iEntry.Entry(); |
|
1118 if (!entry.Visible() || aClearMultiples || |
|
1119 entry.DisconnectedOperation() != EDisconnectedMultipleOperation) |
|
1120 { |
|
1121 entry.SetDisconnectedOperation(ENoDisconnectedOperations); |
|
1122 entry.SetVisible(ETrue); |
|
1123 ChangeEntryL(entry); |
|
1124 } |
|
1125 } |
|
1126 } |
|
1127 |
|
1128 void CImapOfflineControl::PrepareLocalOpL(TMsvId aId) |
|
1129 { |
|
1130 SetEntryL(aId); |
|
1131 |
|
1132 // clear the disconnected op flag |
|
1133 TMsvEmailEntry entry = iEntry.Entry(); |
|
1134 entry.SetDisconnectedOperation(ENoDisconnectedOperations); |
|
1135 ChangeEntryL(entry); |
|
1136 |
|
1137 SetEntryL(iEntry.Entry().Parent()); |
|
1138 } |
|
1139 |
|
1140 TBool CImapOfflineControl::DoLocalOpL() |
|
1141 { |
|
1142 |
|
1143 |
|
1144 |
|
1145 if (iCopyDirect->Count()) |
|
1146 { |
|
1147 TMsvId id = (*iCopyDirect)[0]; |
|
1148 |
|
1149 __LOG_FORMAT((KDefaultLog, "CImapOfflineControl::DoLocalOpL Copy id %x to do %d",id, iCopyDirect->Count())); |
|
1150 |
|
1151 PrepareLocalOpL(id); |
|
1152 |
|
1153 iEntry.CopyEntryL(id, iDestination, iStatus); |
|
1154 SetActive(); |
|
1155 return ETrue; |
|
1156 } |
|
1157 |
|
1158 if (iMoveDirect->Count()) |
|
1159 { |
|
1160 TMsvId id = (*iMoveDirect)[0]; |
|
1161 |
|
1162 __LOG_FORMAT((KDefaultLog, "CImapOfflineControl::DoLocalOpL Move id %x to do %d",id, iMoveDirect->Count())); |
|
1163 |
|
1164 PrepareLocalOpL(id); |
|
1165 |
|
1166 iEntry.MoveEntryL(id, iDestination, iStatus); |
|
1167 SetActive(); |
|
1168 return ETrue; |
|
1169 } |
|
1170 |
|
1171 if (iMoveToLocalDirect->Count()) |
|
1172 { |
|
1173 TMsvId id = (*iMoveToLocalDirect)[0]; |
|
1174 |
|
1175 __LOG_FORMAT((KDefaultLog, "CImapOfflineControl::DoLocalOpL MoveToLocal id %x to do %d",id, iMoveToLocalDirect->Count())); |
|
1176 |
|
1177 PrepareLocalOpL(id); |
|
1178 |
|
1179 iEntry.CopyEntryL(id, iDestination, iStatus); // I do mean Copy |
|
1180 SetActive(); |
|
1181 return ETrue; |
|
1182 } |
|
1183 |
|
1184 return EFalse; |
|
1185 } |
|
1186 |
|
1187 |
|
1188 void CImapOfflineControl::DoCancel() |
|
1189 { |
|
1190 CMsgActive::DoCancel(); |
|
1191 } |
|
1192 |
|
1193 void CImapOfflineControl::DoComplete(TInt& /*aStatus*/) |
|
1194 { |
|
1195 |
|
1196 } |
|
1197 |
|
1198 void CImapOfflineControl::DoRunL() |
|
1199 { |
|
1200 |
|
1201 // DBG((_L8("::DoRunL"))); |
|
1202 __LOG_FORMAT((KDefaultLog, "CImapOfflineControl::DoRunL")); |
|
1203 |
|
1204 // successfully copied/moved the item |
|
1205 |
|
1206 // Remove completed item from selection |
|
1207 if (iCopyDirect->Count()) |
|
1208 iCopyDirect->Delete(0,1); |
|
1209 else if (iMoveDirect->Count()) |
|
1210 iMoveDirect->Delete(0,1); |
|
1211 else |
|
1212 { |
|
1213 // We managed to do the copy portion of a move to local |
|
1214 // Now we need to queue up a delete of the original which |
|
1215 // is still in the remote mailbox. |
|
1216 CImOffLineOperation* op = new(ELeave)CImOffLineOperation(); |
|
1217 CleanupStack::PushL(op); |
|
1218 |
|
1219 op->SetDelete((*iMoveToLocalDirect)[0]); |
|
1220 iMoveToLocalDirect->Delete(0,1); |
|
1221 SaveOperationL(*op); |
|
1222 |
|
1223 CleanupStack::PopAndDestroy(op); |
|
1224 } |
|
1225 |
|
1226 // Operation done. Do next one in selection |
|
1227 DoLocalOpL(); |
|
1228 |
|
1229 //update the progrees info |
|
1230 ++iProgressMsgsDone; |
|
1231 } |
|
1232 |
|
1233 |
|
1234 EXPORT_C TImap4CompoundProgress CImapOfflineControl::Progress() |
|
1235 { |
|
1236 iProgress.iGenericProgress.iType=EImap4GenericProgressType; |
|
1237 iProgress.iGenericProgress.iOperation=iRequestedOperation; |
|
1238 iProgress.iGenericProgress.iMsgsToDo=iProgressMsgsToDo; |
|
1239 iProgress.iGenericProgress.iMsgsDone=iProgressMsgsDone; |
|
1240 |
|
1241 return iProgress; |
|
1242 } |