|
1 // Copyright (c) 2008-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 <imapset.h> |
|
17 #include <mentact.h> |
|
18 #include <miut_err.h> |
|
19 |
|
20 #include "cimapprotocolcontroller.h" |
|
21 #include "cimapsettings.h" |
|
22 #include "cimapsessionmanager.h" |
|
23 #include "cimapsession.h" |
|
24 #include "cimapsessionconsts.h" |
|
25 #include "cimapmailstore.h" |
|
26 #include "cimapofflinecontrol.h" |
|
27 #include "cimapsyncmanager.h" |
|
28 #include "cimapfolder.h" |
|
29 |
|
30 #include "cimapcompoundcopyfromlocal.h" |
|
31 #include "cimapcompoundcopytolocal.h" |
|
32 #include "cimapcompoundcopywithinservice.h" |
|
33 #include "cimapcompoundcreate.h" |
|
34 #include "cimapcompounddelete.h" |
|
35 #include "cimapcompounddeletefolder.h" |
|
36 #include "cimapcompounddisconnect.h" |
|
37 #include "cimapcompoundrename.h" |
|
38 #include "cimapcompoundselect.h" |
|
39 #include "cimapcompoundsyncfolder.h" |
|
40 #include "cimapcompoundsynctree.h" |
|
41 #include "cimapcompoundsyncservice.h" |
|
42 |
|
43 #include "cimapopbackgroundsync.h" |
|
44 #include "cimapidlecontroller.h" |
|
45 #include "cimapupdateflagoperation.h" |
|
46 |
|
47 #include "cimaplogger.h" |
|
48 |
|
49 #include "mobilitytestmtmapi.h" |
|
50 |
|
51 // at the moment we do not need more than 2 sessions |
|
52 const TInt KImapSessionArrayGranularity = 2; |
|
53 |
|
54 const TUid KUidImapServerMtm = {0x10003C4E}; |
|
55 |
|
56 CImapProtocolController::CImapProtocolController(CMsvServerEntry& aEntry,CImapOfflineControl& aImapOfflineControl): |
|
57 CMsgActive(EPriorityStandard), |
|
58 iEntry(aEntry), |
|
59 iImapSessionArray(KImapSessionArrayGranularity), |
|
60 iImapOfflineControl(aImapOfflineControl) |
|
61 { |
|
62 } |
|
63 |
|
64 CImapProtocolController::~CImapProtocolController() |
|
65 { |
|
66 Cancel(); |
|
67 |
|
68 // The mail store needs to be deleted before DisconnectAll() as its destructor |
|
69 // uses the session that DisconnectAll() destroys. |
|
70 delete iImapMailStore; |
|
71 |
|
72 //serviceid indicates that we are online |
|
73 if(iServiceId!=0) |
|
74 { |
|
75 DisconnectAll(); |
|
76 } |
|
77 |
|
78 delete iBackgroundSyncOp; |
|
79 delete iImapCompound; |
|
80 delete iMigrateCompound; |
|
81 delete iImapSyncManager; |
|
82 delete iImapIdleController; |
|
83 delete iImapSettings; |
|
84 |
|
85 delete iMobilityManager; |
|
86 |
|
87 // Need to destroy the sessions before the session manager is deleted. |
|
88 // This is because session manager will cleanup transport handler code, |
|
89 // and it is important to ensure that the sockets are not being used |
|
90 // by the session when that happens. |
|
91 iImapSessionArray.ResetAndDestroy(); |
|
92 delete iImapSessionManager; |
|
93 } |
|
94 |
|
95 EXPORT_C CImapProtocolController* CImapProtocolController::NewL(CMsvServerEntry& aEntry,CImapOfflineControl& aImapOfflineControl) |
|
96 { |
|
97 CImapProtocolController* self = new (ELeave) CImapProtocolController(aEntry,aImapOfflineControl); |
|
98 CleanupStack::PushL(self); |
|
99 self->ConstructL(); |
|
100 CleanupStack::Pop(self); |
|
101 return self; |
|
102 } |
|
103 |
|
104 /** |
|
105 Part of two phase construction |
|
106 Note that syncmanager is not constructed until a connection is made. |
|
107 */ |
|
108 void CImapProtocolController::ConstructL() |
|
109 { |
|
110 iImapSettings = CImapSettings::NewL(iEntry); |
|
111 iImapMailStore = CImapMailStore::NewL(iEntry); |
|
112 iImapSessionManager = CImapSessionManager::NewL(*iImapSettings, *iImapMailStore); |
|
113 |
|
114 iFlushPrimary = EFalse; |
|
115 // We're an active object... |
|
116 CActiveScheduler::Add(this); |
|
117 } |
|
118 |
|
119 /** |
|
120 Query connection status - return true if at least one IMAP Session exists and is |
|
121 connected. Also return true if migrating. |
|
122 This is not a compound operation. |
|
123 |
|
124 @return |
|
125 */ |
|
126 EXPORT_C TBool CImapProtocolController::Connected() const |
|
127 { |
|
128 if (iImapSessionArray.Count() > 0 || iMigrateState != ENotMigrating) |
|
129 { |
|
130 // Sessions are deleted if a disconnect is observed, |
|
131 // therefore the existance of any sessions indicates |
|
132 // that the Protocol Controller is connected. |
|
133 return ETrue; |
|
134 } |
|
135 return EFalse; |
|
136 } |
|
137 |
|
138 /** |
|
139 If a connected session already exists, this API shall complete immediately with |
|
140 KErrServerBusy. Otherwise, this API uses the IMAP Session Manager to create and connect |
|
141 an IMAP Session object that can be used for subsequent commands. |
|
142 On successful connection, the passed request status is completed. This API can not |
|
143 be used to instantiate further IMAP Session objects. |
|
144 |
|
145 Sequence For Connect |
|
146 CreateSession |
|
147 SelectInboxRW |
|
148 Finished |
|
149 |
|
150 @param aStatus |
|
151 @param aSelection |
|
152 @leave KErrServerBusy if a connected session already exists |
|
153 */ |
|
154 EXPORT_C void CImapProtocolController::ConnectL( TRequestStatus& aStatus, |
|
155 CMsvEntrySelection& aSelection ) |
|
156 { |
|
157 __LOG_TEXT(KDefaultLog, "CImapProtocolController::ConnectL()"); |
|
158 |
|
159 ResetProgress(); |
|
160 |
|
161 if (Connected()) |
|
162 { |
|
163 // Do not call Complete() - this would result in the Protocol |
|
164 // Controller disconnecting all sessions. |
|
165 TRequestStatus* pStatus = &aStatus; |
|
166 User::RequestComplete(pStatus, KErrServerBusy); |
|
167 } |
|
168 else |
|
169 { |
|
170 // Load the Service Settings |
|
171 iServiceId = aSelection[0]; |
|
172 iImapSettings->LoadSettingsL(iServiceId); |
|
173 |
|
174 // We're going online - create a session manager if none exists |
|
175 if (iImapSessionManager==NULL) |
|
176 { |
|
177 // session manage may have been deleted due to a mobility error |
|
178 iImapSessionManager = CImapSessionManager::NewL(*iImapSettings, *iImapMailStore); |
|
179 } |
|
180 |
|
181 // create a sync manager |
|
182 delete iImapSyncManager; |
|
183 iImapSyncManager = NULL; |
|
184 iImapSyncManager = CImapSyncManager::NewL( iEntry, *iImapSettings); |
|
185 |
|
186 // create the mobility manager if mobility supported |
|
187 delete iMobilityManager; |
|
188 iMobilityManager = NULL; |
|
189 |
|
190 if (iImapSettings->BearerMobility()) |
|
191 { |
|
192 iMobilityManager = CImMobilityManager::NewL(KUidImapServerMtm, iServiceId, *this); |
|
193 } |
|
194 |
|
195 // Create the primary session pointer |
|
196 CImapSession* imapSession = NULL; |
|
197 iImapSessionArray.AppendL(imapSession); |
|
198 |
|
199 // Request the session manager to connect the session |
|
200 iImapSessionManager->GetSessionL(iStatus, iImapSessionArray[0]); |
|
201 |
|
202 iForegroundSession = 0; |
|
203 iRequestedOp = EConnect; |
|
204 iCurrentOp = iRequestedOp; |
|
205 |
|
206 Queue(aStatus); |
|
207 SetActive(); |
|
208 } |
|
209 } |
|
210 |
|
211 /** |
|
212 This method allows the client to connect to an IMAP account and initialise a |
|
213 background synchronisation of the account once connection has completed. If a |
|
214 connected IMAP Session already exists, the API shall complete immdediately with |
|
215 KErrServerBusy. |
|
216 On successful connection, a background synchronisation is started and the passed |
|
217 request status is completed. The background synchronisation is processed by a |
|
218 CImapBackgroundSyncOp object, which will notify the Protocol Controller that |
|
219 the process has completed via a callback function void |
|
220 BackgroundSyncCompleted( TInt aError ) |
|
221 |
|
222 Sequence For ConnectAndSynchronise |
|
223 CreateSession |
|
224 StartBackgroundSyncOp |
|
225 Finished |
|
226 |
|
227 @param aStatus |
|
228 @param aSelection |
|
229 @leave KErrServerBusy if a connected session already exists |
|
230 */ |
|
231 EXPORT_C void CImapProtocolController::ConnectAndSynchroniseL( TRequestStatus& aStatus, |
|
232 CMsvEntrySelection& aSelection ) |
|
233 { |
|
234 __LOG_TEXT(KDefaultLog, "CImapProtocolController::ConnectAndSynchroniseL()"); |
|
235 |
|
236 // Issue the connect request (this will cause ResetProgress() to be called) |
|
237 ConnectL(aStatus, aSelection); |
|
238 |
|
239 // Create the Background Sync Operation object |
|
240 if (IsActive()) |
|
241 { |
|
242 __ASSERT_DEBUG(iBackgroundSyncOp==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EConnectAndSyncBgSyncOpIsNotNull)); |
|
243 iBackgroundSyncOp = CImapOpBackgroundSync::NewL(*this, iEntry, *iImapSyncManager, *iImapSettings, *iImapMailStore, iImapOfflineControl); |
|
244 } |
|
245 } |
|
246 |
|
247 /** |
|
248 Logs out and disconnects all connected sessions with the remote server. |
|
249 |
|
250 Disconnect request is handled and acted upon during migration, unlike other |
|
251 client-requested operations which are rejected (with KErrServerBusy). |
|
252 |
|
253 The Bearer Mobility Manager is deleted prior to acting on this request, |
|
254 effectively de-registering the server MTM from the mobility framework |
|
255 |
|
256 @param aStatus |
|
257 */ |
|
258 EXPORT_C void CImapProtocolController::DisconnectL(TRequestStatus& aStatus) |
|
259 { |
|
260 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectL()"); |
|
261 |
|
262 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EDisconnectCompoundIsNotNull)); |
|
263 |
|
264 // de-register for mobility notifications |
|
265 delete iMobilityManager; |
|
266 iMobilityManager = NULL; |
|
267 |
|
268 // Disconnect allowed to happen even if we are migrating... |
|
269 switch (iMigrateState) |
|
270 { |
|
271 case ENotMigrating: |
|
272 case EHandlingConnectError: |
|
273 { |
|
274 // normal behaviour... |
|
275 DoDisconnectL(aStatus); |
|
276 break; |
|
277 } |
|
278 case EConnectingAfterMigrate: // Cancel connecting of new session |
|
279 case EStartingReconnect: // already disconnected. Cancel dummy request |
|
280 case EWaitingForNewCarrier: // already disconnected. Cancel dummy request |
|
281 case EWaitingInitialCarrierRejected: // already disconnected. Cancel dummy request |
|
282 { |
|
283 Cancel(); |
|
284 // mark offline and complete |
|
285 DisconnectAll(); |
|
286 Queue(aStatus); |
|
287 Complete(KErrNone); |
|
288 break; |
|
289 } |
|
290 case EDisconnectingForMigrate: |
|
291 { |
|
292 // already doing a graceful disconnect, switch to main state machine. |
|
293 iMigrateState = ENotMigrating; |
|
294 iRequestedOp = EDisconnect; |
|
295 iCurrentOp = EDisconnect; |
|
296 // however, using the iMigrateCompound pointer... |
|
297 iImapCompound = iMigrateCompound; |
|
298 iMigrateCompound = NULL; |
|
299 Queue(aStatus); |
|
300 break; |
|
301 } |
|
302 case EWaitingForOpToComplete: |
|
303 case EWaitingForOpToStop: |
|
304 default: |
|
305 { |
|
306 __ASSERT_DEBUG(iBackgroundSyncOp==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EDisconnectUnexpectedMigrateState)); |
|
307 break; |
|
308 } |
|
309 } |
|
310 } |
|
311 |
|
312 void CImapProtocolController::DoDisconnectL(TRequestStatus& aStatus) |
|
313 { |
|
314 // Unlike the other async methods, DisconnectL() will wait for any flush operation to finish |
|
315 // and then initiate the disconnect. |
|
316 // Consequently there is no need to call CompleteIfBackgroundOpInProgress() |
|
317 ResetProgress(); |
|
318 |
|
319 iImapCompound = CImapCompoundDisconnect::NewL( *iImapSyncManager, |
|
320 iEntry, |
|
321 *iImapSettings, |
|
322 *iImapSessionManager, |
|
323 *iImapMailStore, |
|
324 iImapSessionArray, |
|
325 iImapOfflineControl, |
|
326 ETrue ); |
|
327 iRequestedOp = EDisconnect; |
|
328 |
|
329 if (iCurrentOp != ECancelRecoverPrimary) |
|
330 { |
|
331 // Cancel any outstanding background sync |
|
332 if (iBackgroundSyncOp!=NULL) |
|
333 { |
|
334 iBackgroundSyncOp->Cancel(); |
|
335 delete iBackgroundSyncOp; |
|
336 iBackgroundSyncOp=NULL; |
|
337 |
|
338 // Flush the session, now that it has been cancelled |
|
339 iCurrentOp = ECancelRecoverPrimary; |
|
340 CImapSession* session = iImapSessionArray[0]; |
|
341 session->FlushCancelledCommand(iStatus); |
|
342 SetActive(); |
|
343 } |
|
344 else |
|
345 { |
|
346 StartPrimaryOperation(); |
|
347 SetActive(); |
|
348 } |
|
349 } |
|
350 |
|
351 // NOTE: In the case of iCurrentOp == ECancelRecoverPrimary, DoRunL() will start the async |
|
352 // iImapCompound operation after the flush has completed. |
|
353 // The iImapCompound will expect aStatus to have been queued so that it can be Completed later. |
|
354 |
|
355 Queue(aStatus); |
|
356 } |
|
357 |
|
358 /** |
|
359 Checks the status of the CImapSessions |
|
360 |
|
361 @return ETrue if a backgroundsync is in progress and the second session is busy, |
|
362 EFalse otherwise. |
|
363 */ |
|
364 EXPORT_C TBool CImapProtocolController::Busy() const |
|
365 { |
|
366 // second session is busy if a compound operation exists. |
|
367 if (BackgroundSyncInProgress() && iImapCompound!=NULL) |
|
368 { |
|
369 return ETrue; |
|
370 } |
|
371 return EFalse; |
|
372 |
|
373 } |
|
374 |
|
375 /** |
|
376 Gets the access point ID in use for the connection to the server |
|
377 |
|
378 @param aIap On return stores the access point ID value |
|
379 |
|
380 @return KErrNone if successful, or a system wide error code |
|
381 */ |
|
382 EXPORT_C TInt CImapProtocolController::GetAccessPointIdForConnection(TUint32& aAccessPointId) const |
|
383 { |
|
384 if (iImapSessionManager) |
|
385 { |
|
386 return iImapSessionManager->GetAccessPointIdForConnection(aAccessPointId); |
|
387 } |
|
388 |
|
389 return KErrNotFound; |
|
390 } |
|
391 |
|
392 /** |
|
393 Returns whether a Background synchronisation is in progress |
|
394 |
|
395 @return ETrue if a Background synchronisation is in progress, EFalse otherwise |
|
396 */ |
|
397 EXPORT_C TBool CImapProtocolController::BackgroundSyncInProgress() const |
|
398 { |
|
399 return (iBackgroundSyncOp != NULL); |
|
400 } |
|
401 |
|
402 /** |
|
403 Cancels an outstanding background synchronise operation. Calls |
|
404 CImapOpBackgroundSync::Cancel() to propagate the cancel and kicks off |
|
405 an asynchronous cleanup operation. |
|
406 The cancel request is completed immediately with KErrNone if no background |
|
407 sync was in operation, otherwise it is completed with KErrCancel when |
|
408 the cleanup process is complete. |
|
409 */ |
|
410 EXPORT_C void CImapProtocolController::CancelBackgroundSync(TRequestStatus& aStatus) |
|
411 { |
|
412 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CancelBackgroundSync()"); |
|
413 |
|
414 ResetProgress(); |
|
415 |
|
416 Queue(aStatus); |
|
417 if (BackgroundSyncInProgress()) |
|
418 { |
|
419 if (iMigrateState != ENotMigrating && iBackgroundSyncOp->IsSuspendedForMigrate()) |
|
420 { |
|
421 delete iBackgroundSyncOp; |
|
422 iBackgroundSyncOp = NULL; |
|
423 Complete(KErrCancel); |
|
424 } |
|
425 else |
|
426 { |
|
427 iBackgroundSyncOp->CancelAndCleanup(); |
|
428 iWaitForBackgroundSync = ETrue; |
|
429 } |
|
430 } |
|
431 else |
|
432 { |
|
433 Complete(KErrNone); |
|
434 } |
|
435 } |
|
436 |
|
437 /** |
|
438 Wait for background sync operation to complete. This effectively makes a background |
|
439 synchronise a foreground operation blocking subsequent Server MTM requests until the |
|
440 synchonise is completed. |
|
441 |
|
442 @param aStatus |
|
443 */ |
|
444 EXPORT_C void CImapProtocolController::WaitForBackground(TRequestStatus& aStatus) |
|
445 { |
|
446 __LOG_TEXT(KDefaultLog, "CImapProtocolController::WaitForBackground()"); |
|
447 |
|
448 ResetProgress(); |
|
449 |
|
450 Queue(aStatus); |
|
451 // Wait for background operation to complete: is one running? |
|
452 if (!BackgroundSyncInProgress()) |
|
453 { |
|
454 // No, complete immediately |
|
455 Complete(KErrNone); |
|
456 } |
|
457 else |
|
458 { |
|
459 // Otherwise, wait for completion |
|
460 iWaitForBackgroundSync = ETrue; |
|
461 } |
|
462 } |
|
463 |
|
464 |
|
465 /** |
|
466 Completes the passed request status if a background operation is in progress, |
|
467 or if the primary session is being recovered following a cancel operation. |
|
468 This should be called prior to starting a compound operation that requires the |
|
469 primary session to be performed. |
|
470 |
|
471 This method must be called before assigning iRequestedOp, |
|
472 for any operation that requires the primary session. |
|
473 |
|
474 @return ETrue if the user request has been completed |
|
475 EFalse otherwise. |
|
476 */ |
|
477 TBool CImapProtocolController::CompleteIfBackgroundOpInProgress(TRequestStatus& aStatus) |
|
478 { |
|
479 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CompleteIfBackgroundOpInProgress()"); |
|
480 if (BackgroundSyncInProgress() || iCurrentOp==ECancelRecoverPrimary || iMigrateState!=ENotMigrating) |
|
481 { |
|
482 // Complete the user request |
|
483 // Do not call Complete() - this would result in the Protocol |
|
484 // Controller disconnecting all sessions. |
|
485 TRequestStatus* status = &aStatus; |
|
486 User::RequestComplete(status, KErrServerBusy); |
|
487 return ETrue; |
|
488 } |
|
489 return EFalse; |
|
490 } |
|
491 |
|
492 /** |
|
493 Synchronise Folder Tree - calls CImapSyncManager::SynchroniseTreeL() |
|
494 Sequence For SynchroniseTree |
|
495 StopIdle |
|
496 SynchroniseTree // CImapSyncManager Operation |
|
497 |
|
498 @param aStatus |
|
499 @leave |
|
500 */ |
|
501 EXPORT_C void CImapProtocolController::SynchroniseTreeL(TRequestStatus& aStatus) |
|
502 { |
|
503 __LOG_TEXT(KDefaultLog, "CImapProtocolController::SynchroniseTreeL()"); |
|
504 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESynchroniseTreeCompoundIsNotNull)); |
|
505 |
|
506 ResetProgress(); |
|
507 |
|
508 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
509 { |
|
510 iImapCompound = CImapCompoundSyncTree::NewL( *iImapSyncManager, |
|
511 iEntry, |
|
512 *iImapSettings ); |
|
513 |
|
514 iRequestedOp = ESync; |
|
515 StartPrimaryOperation(); |
|
516 Queue(aStatus); |
|
517 SetActive(); |
|
518 } |
|
519 } |
|
520 |
|
521 |
|
522 /** |
|
523 Perform a full account synchronisation - calls CImapSyncManager::SynchroniseL() |
|
524 Sequence For SynchroniseAll |
|
525 StopIdle |
|
526 SynchroniseL // CImapSyncManager Operation |
|
527 |
|
528 @param aStatus |
|
529 @leave |
|
530 */ |
|
531 EXPORT_C void CImapProtocolController::SynchroniseAllL( TRequestStatus& aStatus ) |
|
532 { |
|
533 __LOG_TEXT(KDefaultLog, "CImapProtocolController::SynchroniseAllL()"); |
|
534 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESynchroniseAllCompoundIsNotNull)); |
|
535 |
|
536 ResetProgress(); |
|
537 |
|
538 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
539 { |
|
540 iImapCompound = CImapCompoundSyncService::NewL( *iImapSyncManager, |
|
541 iEntry, |
|
542 *iImapSettings, |
|
543 *iImapMailStore, |
|
544 iImapOfflineControl, |
|
545 EFalse); |
|
546 |
|
547 iRequestedOp = ESync; |
|
548 StartPrimaryOperation(); |
|
549 Queue(aStatus); |
|
550 SetActive(); |
|
551 } |
|
552 } |
|
553 |
|
554 /** |
|
555 Callback function to notify Protocol Controller that a background sync |
|
556 operation has completed. |
|
557 Deletes the CImapOpBackgroundComplete object that has just completed. |
|
558 If WaitForBackground has been previously called, completes the user request. |
|
559 |
|
560 @param aError |
|
561 */ |
|
562 EXPORT_C void CImapProtocolController::BackgroundSyncComplete(TInt aError) |
|
563 { |
|
564 __LOG_TEXT(KDefaultLog, "CImapProtocolController::BackgroundSyncComplete()"); |
|
565 __ASSERT_DEBUG(iBackgroundSyncOp!=NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ENoBackgroundSyncInProgress)); |
|
566 |
|
567 // get final sync progress... |
|
568 // unless a foreground operation is being performed |
|
569 if (iImapCompound == NULL) |
|
570 { |
|
571 iBackgroundSyncOp->Progress(iProgress); |
|
572 } |
|
573 |
|
574 if (iMigrateState != ENotMigrating) |
|
575 { |
|
576 // If the protocol controller is not active, then there is no |
|
577 // operation currently in progress. Therefore we are now ready to |
|
578 // migrate. Complete the request here, and then Disconnect current sockets in DoMigrateRunL(). |
|
579 // We cannot just test existance of a compound operation object, as there may be a "paused" operation. |
|
580 if (!IsActive()) |
|
581 { |
|
582 // Complete the request so that, we migrate from DoMigrateRunL() |
|
583 SetActive(); |
|
584 TRequestStatus* pStatus = &iStatus; |
|
585 User::RequestComplete(pStatus, KErrNone); |
|
586 } |
|
587 |
|
588 // the background sync may have been completed early to allow |
|
589 // a migration to occur. If that is the case, then we do not want |
|
590 // to delete the background sync operation object - it will need |
|
591 // to be restarted once the migrate has occurred. Otherwise, just |
|
592 // process the completion of the background sync normally. |
|
593 if (iBackgroundSyncOp->IsSuspendedForMigrate()) |
|
594 { |
|
595 return; |
|
596 } |
|
597 } |
|
598 |
|
599 // Deleting the background sync op. |
|
600 // CImapOpBackgroundComplete must finish immediately after calling this API |
|
601 delete iBackgroundSyncOp; |
|
602 iBackgroundSyncOp = NULL; |
|
603 |
|
604 if (aError>0) |
|
605 { |
|
606 // translate positive error codes, weed out non-fatal errors |
|
607 ThranslateSessionError(aError); |
|
608 } |
|
609 |
|
610 TBool foregroundOpCancelled = EFalse; |
|
611 if (aError==KErrNone || aError==KErrCancel) |
|
612 { |
|
613 if (iImapCompound==NULL && iMigrateState == ENotMigrating) |
|
614 { |
|
615 // only start IDLE if foreground operation not in progress |
|
616 StartIdle(); |
|
617 MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStateImapIdle); |
|
618 } |
|
619 } |
|
620 else |
|
621 { |
|
622 // Cancel any foreground operation - the primary session has |
|
623 // failed, so all sessions are to be torn down. |
|
624 if (iImapCompound != NULL) |
|
625 { |
|
626 iImapCompound->Cancel(); |
|
627 foregroundOpCancelled = ETrue; |
|
628 delete iImapCompound; |
|
629 iImapCompound=NULL; |
|
630 } |
|
631 |
|
632 // DisconnectAll will be process by DoComplete if a client request is outstanding. |
|
633 if (!iWaitForBackgroundSync && !foregroundOpCancelled) |
|
634 { |
|
635 // Drop all session connections and mark the service offline. |
|
636 DisconnectAll(); |
|
637 } |
|
638 } |
|
639 |
|
640 // Store the error in the progress object |
|
641 iProgress.iGenericProgress.iErrorCode=aError; |
|
642 iProgress.iGenericProgress.iState=TImap4GenericProgress::EIdle; |
|
643 |
|
644 // Complete the client request if it was waiting for notification of |
|
645 // bg sync complete, or if we have cancelled an foreground operation |
|
646 if (iWaitForBackgroundSync || foregroundOpCancelled) |
|
647 { |
|
648 iCancelInProgress = ETrue; |
|
649 Complete(aError); |
|
650 iCancelInProgress = EFalse; |
|
651 } |
|
652 |
|
653 iWaitForBackgroundSync = EFalse; |
|
654 } |
|
655 |
|
656 /** |
|
657 CopyToLocalL() is used to fetch a selection of messages from the remote |
|
658 server as a single operation, without return to idle state between handling each |
|
659 message. The email is fetched to the local mirror of the containing folder. Optionally |
|
660 this function can also copy the message to a local folder, specified in aDestination. |
|
661 A fetch to mirror only is performed by calling with aDestination set to |
|
662 KMsvNullIndexEntryId |
|
663 |
|
664 Sequence For CopyToLocal |
|
665 StopIdle |
|
666 SelectSourceMailboxRO |
|
667 FetchMessage(s) |
|
668 InboxDuplicateCopy |
|
669 |
|
670 @param aStatus |
|
671 @param aSourceSel |
|
672 @param aDestination |
|
673 */ |
|
674 EXPORT_C void CImapProtocolController::CopyToLocalL(TRequestStatus& aStatus, |
|
675 const CMsvEntrySelection& aSourceSel, |
|
676 const TMsvId aDestination) |
|
677 { |
|
678 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CopyToLocalL()"); |
|
679 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyToLocalCompoundIsNotNull)); |
|
680 |
|
681 ResetProgress(); |
|
682 |
|
683 // Instead of calling CompleteIfBackgroundOpInProgress(), just check whether a flush is occurring |
|
684 // on the primary session (always index 0). |
|
685 // If a background op is in progress, then the copy will be performed on a secondary session. |
|
686 if (iCurrentOp == ECancelRecoverPrimary || iMigrateState != ENotMigrating) |
|
687 { |
|
688 // Do not call Complete() - this would result in the Protocol |
|
689 // Controller disconnecting all sessions. |
|
690 TRequestStatus* pStatus = &aStatus; |
|
691 User::RequestComplete(pStatus, KErrServerBusy); |
|
692 |
|
693 return; |
|
694 } |
|
695 |
|
696 // must be set before calling SelectSession |
|
697 iRequestedOp = ECopyToLocal; |
|
698 |
|
699 // request the session to use. |
|
700 TBool startNow = SelectSessionL(iForegroundSession); |
|
701 |
|
702 if (iBackgroundSyncOp && iImapSettings->UseSyncDownloadRules()) |
|
703 { |
|
704 // we need a non-const copy of the message selection to operate on. |
|
705 CMsvEntrySelection* selection = aSourceSel.CopyLC(); |
|
706 |
|
707 // show the list to the background sync controller |
|
708 iBackgroundSyncOp->RemoveFromSelectionL(*selection); |
|
709 // Create the copy to local operation object using the (possibly) updated selection |
|
710 iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, |
|
711 iEntry, |
|
712 *iImapSettings, |
|
713 *iImapMailStore, |
|
714 EFalse, |
|
715 *selection, |
|
716 aDestination); |
|
717 CleanupStack::PopAndDestroy(selection); |
|
718 } |
|
719 else |
|
720 { |
|
721 // Create the compound operation object |
|
722 iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, |
|
723 iEntry, |
|
724 *iImapSettings, |
|
725 *iImapMailStore, |
|
726 EFalse, |
|
727 aSourceSel, |
|
728 aDestination); |
|
729 } |
|
730 |
|
731 if (startNow) |
|
732 { |
|
733 // A session is ready - start the command |
|
734 // otherwise a request to connect a secondary session has been issued |
|
735 if (iForegroundSession==0) |
|
736 { |
|
737 // Primary session |
|
738 StartPrimaryOperation(); |
|
739 } |
|
740 else |
|
741 { |
|
742 // Secondary session |
|
743 iCurrentOp = iRequestedOp; |
|
744 iImapCompound->StartOperation(iStatus, *iImapSessionArray[iForegroundSession]); |
|
745 } |
|
746 } |
|
747 |
|
748 Queue(aStatus); |
|
749 SetActive(); |
|
750 } |
|
751 |
|
752 |
|
753 /** |
|
754 PopulateL() performs the same action as CopyToLocalL(), however uses the passed |
|
755 TImImap4GetPartialMailInfo object instead of using the default parameters. This |
|
756 allows the client application to specify the parts of the message that are to be |
|
757 fetched, and to impose limits to on the amount of data that can be transferred. |
|
758 |
|
759 Sequence For Populate |
|
760 StopIdle |
|
761 SelectSourceMailboxRO |
|
762 FetchMessage(s) |
|
763 InboxDuplicateCopy |
|
764 |
|
765 @param aStatus |
|
766 @param aSourceSel |
|
767 @param aGetPartialMailInfo |
|
768 */ |
|
769 EXPORT_C void CImapProtocolController::PopulateL(TRequestStatus& aStatus, |
|
770 const CMsvEntrySelection& aSourceSel, |
|
771 TImImap4GetPartialMailInfo aGetPartialMailInfo) |
|
772 { |
|
773 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::PopulateL() - START - iCurrentOp: %d, iRequestedOp: %d", iCurrentOp, iRequestedOp )); |
|
774 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EPopulateCompoundIsNotNull)); |
|
775 |
|
776 // Instead of calling CompleteIfBackgroundOpInProgress(), just check whether a flush is occurring |
|
777 // on the primary session (always index 0). |
|
778 // If a background op is in prgoress, then the copy will be performed on a secondary session. |
|
779 ResetProgress(); |
|
780 |
|
781 // If a flush is occurring on the primary session (always index 0) then we are busy |
|
782 if (iCurrentOp == ECancelRecoverPrimary || iMigrateState != ENotMigrating) |
|
783 { |
|
784 // Do not call Complete() - this would result in the Protocol |
|
785 // Controller disconnecting all sessions. |
|
786 TRequestStatus* pStatus = &aStatus; |
|
787 User::RequestComplete(pStatus, KErrServerBusy); |
|
788 __LOG_TEXT(KDefaultLog, "CImapProtocolController::PopulateL() - END - KErrServerBusy..."); |
|
789 return; |
|
790 } |
|
791 |
|
792 // must be set before calling SelectSessionL() |
|
793 iRequestedOp = EPopulate; |
|
794 |
|
795 // request the session to use. |
|
796 TBool startNow = SelectSessionL(iForegroundSession); |
|
797 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::PopulateL() - iCurrentOp: %d, iRequestedOp: %d, startNow: %d", iCurrentOp, iRequestedOp, startNow )); |
|
798 |
|
799 if (iBackgroundSyncOp && iImapSettings->UseSyncDownloadRules()) |
|
800 { |
|
801 // we need a non-const copy of the message selection to operate on. |
|
802 CMsvEntrySelection* selection = aSourceSel.CopyLC(); |
|
803 |
|
804 // show the list to the background sync controller |
|
805 iBackgroundSyncOp->RemoveFromSelectionL(*selection); |
|
806 // Create the copy to local operation object using the (possibly) updated selection |
|
807 iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, |
|
808 iEntry, |
|
809 *iImapSettings, |
|
810 *iImapMailStore, |
|
811 EFalse, |
|
812 *selection, |
|
813 KMsvNullIndexEntryId, |
|
814 aGetPartialMailInfo); |
|
815 CleanupStack::PopAndDestroy(selection); |
|
816 } |
|
817 else |
|
818 { |
|
819 // Create the compound operation object |
|
820 iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, |
|
821 iEntry, |
|
822 *iImapSettings, |
|
823 *iImapMailStore, |
|
824 EFalse, |
|
825 aSourceSel, |
|
826 KMsvNullIndexEntryId, |
|
827 aGetPartialMailInfo); |
|
828 } |
|
829 |
|
830 __LOG_TEXT(KDefaultLog, "CImapProtocolController::PopulateL() - done creation of CompoundCopyToLocal..."); |
|
831 if (startNow) |
|
832 { |
|
833 // A session is ready - start the command |
|
834 // otherwise a request to connect a secondary session has been issued |
|
835 if (iForegroundSession==0) |
|
836 { |
|
837 // Primary session |
|
838 __LOG_TEXT(KDefaultLog, "CImapProtocolController::PopulateL() - starting primary op..."); |
|
839 StartPrimaryOperation(); |
|
840 } |
|
841 else |
|
842 { |
|
843 // Secondary session |
|
844 __LOG_TEXT(KDefaultLog, "CImapProtocolController::PopulateL() - starting compound op..."); |
|
845 iCurrentOp = iRequestedOp; |
|
846 iImapCompound->StartOperation(iStatus, *iImapSessionArray[iForegroundSession]); |
|
847 } |
|
848 } |
|
849 |
|
850 Queue(aStatus); |
|
851 SetActive(); |
|
852 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::PopulateL() - END - iCurrentOp: %d, iRequestedOp: %d, startNow: %d", iCurrentOp, iRequestedOp, startNow )); |
|
853 } |
|
854 |
|
855 /** |
|
856 MoveToCopyL() shall enable a selection of messages to be moved as a single operation, |
|
857 without return to idle state between handling each message. If a message has not been |
|
858 previously fetched (ie is not complete on the local mirror of the IMAP folder) the |
|
859 message is fetched to the local mirror and a copy is then made in the local service |
|
860 folder. The message is then deleted from the IMAP folder on the remote server and the |
|
861 local mirror. |
|
862 |
|
863 Sequence For MoveToLocal |
|
864 StopIdle |
|
865 SelectSourceMailbox |
|
866 FetchMessage |
|
867 InboxDuplicateCopy |
|
868 DeleteMessage |
|
869 |
|
870 @param aStatus |
|
871 @param aSourceSel |
|
872 @param aDestination |
|
873 */ |
|
874 EXPORT_C void CImapProtocolController::MoveToLocalL(TRequestStatus& aStatus, |
|
875 const CMsvEntrySelection& aSourceSel, |
|
876 const TMsvId aDestination) |
|
877 { |
|
878 __LOG_TEXT(KDefaultLog, "CImapProtocolController::MoveToLocalL()"); |
|
879 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EMoveToLocalCompoundIsNotNull)); |
|
880 |
|
881 ResetProgress(); |
|
882 |
|
883 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
884 { |
|
885 // We can't do a 'movetolocal' with the destination being the same as the |
|
886 // source, as then the mirror will be out of sync. We must be moving to somewhere |
|
887 // outside this service. Check this. |
|
888 if (!IdIsLocalL(aDestination)) |
|
889 { |
|
890 // Complete the user request |
|
891 // Do not call Complete() - this would result in the Protocol |
|
892 // Controller disconnecting all sessions. |
|
893 TRequestStatus* status = &aStatus; |
|
894 User::RequestComplete(status, KErrNotSupported); |
|
895 } |
|
896 else |
|
897 { |
|
898 iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, |
|
899 iEntry, |
|
900 *iImapSettings, |
|
901 *iImapMailStore, |
|
902 ETrue, |
|
903 aSourceSel, |
|
904 aDestination); |
|
905 |
|
906 iRequestedOp = EMoveToLocal; |
|
907 StartPrimaryOperation(); |
|
908 Queue(aStatus); |
|
909 SetActive(); |
|
910 } |
|
911 } |
|
912 } |
|
913 |
|
914 /** |
|
915 Copy within service is the operation of moving a message or selection of messages from |
|
916 one mailbox to another on the remote IMAP server. This is done by issuing a COPY IMAP |
|
917 command to the remote server, followed by a sync operation on the destination folder. |
|
918 |
|
919 Sequence For CopyWithinService |
|
920 StopIdle |
|
921 SelectSourceMailboxRO |
|
922 CopyMessage |
|
923 SelectDestinationMailboxRO |
|
924 NewSyncFolder |
|
925 |
|
926 @param aStatus |
|
927 @param aSourceSel |
|
928 @param aDestination |
|
929 */ |
|
930 EXPORT_C void CImapProtocolController::CopyWithinServiceL( TRequestStatus& aStatus, |
|
931 const CMsvEntrySelection& aSourceSel, |
|
932 const TMsvId aDestination ) |
|
933 { |
|
934 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CopyWithinServiceL()"); |
|
935 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWithinServiceCompoundIsNotNull)); |
|
936 |
|
937 ResetProgress(); |
|
938 |
|
939 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
940 { |
|
941 iImapCompound = CImapCompoundCopyWithinService::NewL( *iImapSyncManager, |
|
942 iEntry, |
|
943 *iImapSettings, |
|
944 EFalse, |
|
945 aSourceSel, |
|
946 aDestination); |
|
947 |
|
948 iRequestedOp = ECopyWithinService; |
|
949 StartPrimaryOperation(); |
|
950 Queue(aStatus); |
|
951 SetActive(); |
|
952 } |
|
953 } |
|
954 |
|
955 /** |
|
956 Move within service is the same as Copy Within Service, however the message is deleted |
|
957 from the original location following the copy operation. |
|
958 |
|
959 Sequence For MoveWithinService |
|
960 StopIdle |
|
961 SelectSourceMailboxRW |
|
962 CopyMessage |
|
963 DeleteMessage |
|
964 SelectDestinationMailboxRO |
|
965 NewSyncFolder |
|
966 |
|
967 @param aStatus |
|
968 @param aSourceSel |
|
969 @param aDestination |
|
970 */ |
|
971 EXPORT_C void CImapProtocolController::MoveWithinServiceL( TRequestStatus& aStatus, |
|
972 const CMsvEntrySelection& aSourceSel, |
|
973 const TMsvId aDestination ) |
|
974 { |
|
975 __LOG_TEXT(KDefaultLog, "CImapProtocolController::MoveWithinServiceL()"); |
|
976 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EMoveWithinServiceCompoundIsNotNull)); |
|
977 |
|
978 ResetProgress(); |
|
979 |
|
980 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
981 { |
|
982 iImapCompound = CImapCompoundCopyWithinService::NewL( *iImapSyncManager, |
|
983 iEntry, |
|
984 *iImapSettings, |
|
985 ETrue, |
|
986 aSourceSel, |
|
987 aDestination ); |
|
988 |
|
989 iRequestedOp = EMoveWithinService; |
|
990 StartPrimaryOperation(); |
|
991 Queue(aStatus); |
|
992 SetActive(); |
|
993 } |
|
994 } |
|
995 |
|
996 /** |
|
997 Copy from local is the action of copying an email from a local service folder (for |
|
998 example the local inbox) to a folder on the remote IMAP service. This is done using |
|
999 the IMAP APPEND command. |
|
1000 |
|
1001 Sequence For CopyFromLocal |
|
1002 AppendMessage |
|
1003 SelectDestinationMailboxRO |
|
1004 NewSyncFolder |
|
1005 |
|
1006 @param aStatus |
|
1007 @param aSourceSel |
|
1008 @param aDestination |
|
1009 */ |
|
1010 EXPORT_C void CImapProtocolController::CopyFromLocalL( TRequestStatus& aStatus, |
|
1011 const CMsvEntrySelection& aSourceSel, |
|
1012 const TMsvId aDestination ) |
|
1013 { |
|
1014 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CopyFromLocalL()"); |
|
1015 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundIsNotNull)); |
|
1016 |
|
1017 ResetProgress(); |
|
1018 |
|
1019 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1020 { |
|
1021 iImapCompound = CImapCompoundCopyFromLocal::NewL( *iImapSyncManager, |
|
1022 iEntry, |
|
1023 *iImapSettings, |
|
1024 EFalse, |
|
1025 aSourceSel, |
|
1026 aDestination ); |
|
1027 |
|
1028 iRequestedOp = ECopyFromLocal; |
|
1029 StartPrimaryOperation(); |
|
1030 Queue(aStatus); |
|
1031 SetActive(); |
|
1032 } |
|
1033 } |
|
1034 |
|
1035 /** |
|
1036 Move from local is the action of moving an email from a local service folder (for |
|
1037 example the local inbox) to a folder on the remote IMAP service. It is performed |
|
1038 by following the same steps as for a Copy From Local operation, using the IMAP APPEND |
|
1039 command, however the local copy of the message is deleted after the APPEND has |
|
1040 successfully completed. |
|
1041 |
|
1042 Sequence For MoveFromLocal |
|
1043 StopIdle |
|
1044 AppendMessage |
|
1045 DeleteLocalMessage |
|
1046 SelectDestinationMailboxRO |
|
1047 NewSyncFolder |
|
1048 |
|
1049 @param aStatus |
|
1050 @param aSourceSel |
|
1051 @param aDestination |
|
1052 */ |
|
1053 EXPORT_C void CImapProtocolController::MoveFromLocalL( TRequestStatus& aStatus, |
|
1054 const CMsvEntrySelection& aSourceSel, |
|
1055 const TMsvId aDestination ) |
|
1056 { |
|
1057 __LOG_TEXT(KDefaultLog, "CImapProtocolController::MoveFromLocalL()"); |
|
1058 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundIsNotNull)); |
|
1059 |
|
1060 ResetProgress(); |
|
1061 |
|
1062 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1063 { |
|
1064 iImapCompound = CImapCompoundCopyFromLocal::NewL( *iImapSyncManager, |
|
1065 iEntry, |
|
1066 *iImapSettings, |
|
1067 ETrue, |
|
1068 aSourceSel, |
|
1069 aDestination ); |
|
1070 |
|
1071 iRequestedOp = EMoveFromLocal; |
|
1072 StartPrimaryOperation(); |
|
1073 Queue(aStatus); |
|
1074 SetActive(); |
|
1075 } |
|
1076 } |
|
1077 |
|
1078 /** |
|
1079 Deletes the specified messages from the remote server. |
|
1080 |
|
1081 Sequence For Delete |
|
1082 StopIdle |
|
1083 SelectSourceMailboxRW |
|
1084 Store /delete flags for each message |
|
1085 Expunge remote messages |
|
1086 Delete local messages |
|
1087 |
|
1088 @param aStatus |
|
1089 @param aSourceSel |
|
1090 */ |
|
1091 EXPORT_C void CImapProtocolController::DeleteL(TRequestStatus& aStatus, |
|
1092 const CMsvEntrySelection& aSourceSel) |
|
1093 { |
|
1094 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DeleteL()"); |
|
1095 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EDeleteCompoundIsNotNull)); |
|
1096 |
|
1097 ResetProgress(); |
|
1098 |
|
1099 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1100 { |
|
1101 // Create the compound object for message delete |
|
1102 iImapCompound = CImapCompoundDelete::NewL(*iImapSyncManager, |
|
1103 iEntry, |
|
1104 *iImapSettings, |
|
1105 aSourceSel); |
|
1106 |
|
1107 iRequestedOp = EDelete; |
|
1108 StartPrimaryOperation(); |
|
1109 Queue(aStatus); |
|
1110 SetActive(); |
|
1111 } |
|
1112 } |
|
1113 |
|
1114 /** |
|
1115 Deletes the specified folder(s) on the remote IMAP Server. |
|
1116 |
|
1117 Sequence For DeleteFolder |
|
1118 StopIdle |
|
1119 SelectSourceMailboxRW |
|
1120 DeleteAllMessages |
|
1121 CloseFolder |
|
1122 DeleteLocalFolder |
|
1123 |
|
1124 @param aStatus |
|
1125 @param aSelection |
|
1126 */ |
|
1127 EXPORT_C void CImapProtocolController::DeleteFolderL( TRequestStatus& aStatus, |
|
1128 const CMsvEntrySelection& aSelection ) |
|
1129 { |
|
1130 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DeleteFolderL()"); |
|
1131 __ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EDeleteFolderCompoundIsNotNull)); |
|
1132 |
|
1133 ResetProgress(); |
|
1134 |
|
1135 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1136 { |
|
1137 iImapCompound = CImapCompoundDeleteFolder::NewL( *iImapSyncManager, |
|
1138 iEntry, |
|
1139 *iImapSettings, |
|
1140 aSelection ); |
|
1141 |
|
1142 iRequestedOp = EDelete; |
|
1143 StartPrimaryOperation(); |
|
1144 Queue(aStatus); |
|
1145 SetActive(); |
|
1146 } |
|
1147 } |
|
1148 |
|
1149 /** |
|
1150 NewOnlySyncL() is used to synchronise recent messages in the specified folder, |
|
1151 i.e. any messages that have arrived in the remote IMAP mailbox since the last |
|
1152 synchronisation. This is done by requesting (FETCHing) the header details for |
|
1153 messages with UID's that are greater than the highest UID of the messages present |
|
1154 in the local mirror of the folder. The message's header summary information, |
|
1155 flags etc are stored as new entries in the Message Server entry array under the |
|
1156 folder entry, and the header information is streamed to the Mailstore using the |
|
1157 Mailstore API. |
|
1158 |
|
1159 Sequence For NewSyncFolder |
|
1160 StopIdle |
|
1161 SelectSourceMailboxRW |
|
1162 NewSyncFolder |
|
1163 |
|
1164 @param aStatus |
|
1165 */ |
|
1166 EXPORT_C void CImapProtocolController::NewOnlySyncFolderL( TRequestStatus& aStatus ) |
|
1167 { |
|
1168 __LOG_TEXT(KDefaultLog, "CImapProtocolController::NewOnlySyncFolderL()"); |
|
1169 __ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ENewOnlySyncFolderCompoundIsNotNull)); |
|
1170 |
|
1171 ResetProgress(); |
|
1172 |
|
1173 if (iMigrateState!=ENotMigrating) |
|
1174 { |
|
1175 // Complete the user request if migrating. |
|
1176 // Do not call Complete() - this would result in the Protocol |
|
1177 // Controller disconnecting all sessions. |
|
1178 TRequestStatus* status = &aStatus; |
|
1179 User::RequestComplete(status, KErrServerBusy); |
|
1180 return; |
|
1181 } |
|
1182 |
|
1183 // If we support idle, and the server we are talking to supports idle, |
|
1184 // then we don't need to do the new only sync as IMAP idle will take |
|
1185 // care of it for us. |
|
1186 // Just complete the user request with KErrNone. |
|
1187 if (iImapSettings->ImapIdle() && iImapSessionArray[0]->ImapIdleSupported()) |
|
1188 { |
|
1189 __LOG_TEXT(KDefaultLog, "CImapProtocolController::NewOnlySyncFolderL() - Immediate complete as idle is in use"); |
|
1190 Queue(aStatus); |
|
1191 Complete(KErrNone); |
|
1192 return; |
|
1193 } |
|
1194 |
|
1195 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1196 { |
|
1197 CImapFolder* folder = iImapSyncManager->Inbox(); |
|
1198 TMsvId inboxId = folder->MailboxId(); |
|
1199 |
|
1200 iImapCompound = CImapCompoundSyncFolder::NewL( *iImapSyncManager, |
|
1201 iEntry, |
|
1202 *iImapSettings, |
|
1203 *iImapMailStore, |
|
1204 ETrue, |
|
1205 inboxId); |
|
1206 |
|
1207 iRequestedOp = ESync; |
|
1208 StartPrimaryOperation(); |
|
1209 Queue(aStatus); |
|
1210 SetActive(); |
|
1211 } |
|
1212 } |
|
1213 |
|
1214 /** |
|
1215 The full synchronisation of a folder involves the synchronisation of messages newly |
|
1216 received at the IMAP server, as described for NewOnlySyncL, above, and the |
|
1217 synchronisation of "old messages", ie messages that have previously been synchronised |
|
1218 to the local mirror of the folder. |
|
1219 When synchronising old messages, messages that have been marked for delete locally |
|
1220 are marked such on the remote folder (the actual delete occurs either at the end of |
|
1221 the synchronisation process, or is deferred until the connection is cancelled), |
|
1222 messages that have been removed from the remote server (by another client) are |
|
1223 deleted locally and any outstanding offline operations are performed, for example |
|
1224 move operations may be outstanding, etc. |
|
1225 |
|
1226 Sequence For FullSyncFolder |
|
1227 StopIdle |
|
1228 SelectSourceMailboxRW |
|
1229 SyncFolder |
|
1230 |
|
1231 @param aStatus |
|
1232 @param aFolder |
|
1233 */ |
|
1234 EXPORT_C void CImapProtocolController::FullSyncFolderL( TRequestStatus& aStatus, |
|
1235 const TMsvId aFolder ) |
|
1236 { |
|
1237 __LOG_TEXT(KDefaultLog, "CImapProtocolController::FullSyncFolderL()"); |
|
1238 __ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EFullSyncFolderCompoundIsNotNull)); |
|
1239 |
|
1240 ResetProgress(); |
|
1241 |
|
1242 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1243 { |
|
1244 iImapCompound = CImapCompoundSyncFolder::NewL( *iImapSyncManager, |
|
1245 iEntry, |
|
1246 *iImapSettings, |
|
1247 *iImapMailStore, |
|
1248 EFalse, |
|
1249 aFolder ); |
|
1250 |
|
1251 iRequestedOp = ESync; |
|
1252 StartPrimaryOperation(); |
|
1253 Queue(aStatus); |
|
1254 SetActive(); |
|
1255 } |
|
1256 } |
|
1257 |
|
1258 /** |
|
1259 SELECT is made available to the client application directly via an IMAP MTM command |
|
1260 which is handled by this function. It allows the client to specifically SELECT a |
|
1261 mailbox and then, using the Synchronise MTM command, to specifically request the |
|
1262 selected mailbox is synchronised. |
|
1263 |
|
1264 Sequence For Select |
|
1265 StopIdle |
|
1266 SelectSourceMailboxRW |
|
1267 |
|
1268 @param aStatus |
|
1269 @param aFolder |
|
1270 */ |
|
1271 EXPORT_C void CImapProtocolController::SelectL(TRequestStatus& aStatus, const TMsvId aFolder) |
|
1272 { |
|
1273 __LOG_TEXT(KDefaultLog, "CImapProtocolController::SelectL()"); |
|
1274 __ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESelectCompoundIsNotNull)); |
|
1275 |
|
1276 ResetProgress(); |
|
1277 |
|
1278 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1279 { |
|
1280 iImapCompound = CImapCompoundSelect::NewL( *iImapSyncManager, |
|
1281 iEntry, |
|
1282 *iImapSettings, |
|
1283 aFolder ); |
|
1284 |
|
1285 iRequestedOp = ESelect; |
|
1286 StartPrimaryOperation(); |
|
1287 Queue(aStatus); |
|
1288 SetActive(); |
|
1289 } |
|
1290 } |
|
1291 |
|
1292 /** |
|
1293 Performs a full sync on the currently selected mailbox. |
|
1294 |
|
1295 Sequence For FullSyncSelectedFolder |
|
1296 StopIdle |
|
1297 SyncFolder |
|
1298 |
|
1299 @param aStatus |
|
1300 */ |
|
1301 EXPORT_C void CImapProtocolController::FullSyncSelectedFolderL( TRequestStatus& aStatus ) |
|
1302 { |
|
1303 __LOG_TEXT(KDefaultLog, "CImapProtocolController::FullSyncSelectedFolderL()"); |
|
1304 __ASSERT_DEBUG( iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EFullSyncSelectedFolderCompoundIsNotNull)); |
|
1305 |
|
1306 ResetProgress(); |
|
1307 |
|
1308 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1309 { |
|
1310 iImapCompound = CImapCompoundSyncFolder::NewL( *iImapSyncManager, |
|
1311 iEntry, |
|
1312 *iImapSettings, |
|
1313 *iImapMailStore, |
|
1314 EFalse ); |
|
1315 |
|
1316 iRequestedOp = ESync; |
|
1317 StartPrimaryOperation(); |
|
1318 Queue(aStatus); |
|
1319 SetActive(); |
|
1320 } |
|
1321 } |
|
1322 |
|
1323 /** |
|
1324 Creates a new folder on the remote IMAP service with the given name. |
|
1325 |
|
1326 Sequence For Create |
|
1327 StopIdle |
|
1328 Create |
|
1329 |
|
1330 @param aStatus |
|
1331 @param aParent |
|
1332 @param aLeafName |
|
1333 @param aFolder |
|
1334 */ |
|
1335 EXPORT_C void CImapProtocolController::CreateL( TRequestStatus& aStatus, |
|
1336 const TMsvId aParent, |
|
1337 const TDesC& aLeafName, |
|
1338 const TBool aFolder ) |
|
1339 { |
|
1340 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CreateL()"); |
|
1341 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundIsNotNull)); |
|
1342 |
|
1343 ResetProgress(); |
|
1344 |
|
1345 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1346 { |
|
1347 iImapCompound = CImapCompoundCreate::NewL( *iImapSyncManager, |
|
1348 iEntry, |
|
1349 *iImapSettings, |
|
1350 aParent, |
|
1351 aLeafName, |
|
1352 aFolder ); |
|
1353 |
|
1354 iRequestedOp = ECreate; |
|
1355 StartPrimaryOperation(); |
|
1356 Queue(aStatus); |
|
1357 SetActive(); |
|
1358 } |
|
1359 } |
|
1360 |
|
1361 /** |
|
1362 Renames the specified folder. Note that although this does cause a write to the |
|
1363 remote folder, it does not change the contents of the folder and hence does not |
|
1364 force a re-synchronisation of the folder. |
|
1365 |
|
1366 Sequence For Rename |
|
1367 StopIdle |
|
1368 RenameRemote |
|
1369 RenameLocal |
|
1370 |
|
1371 @param aStatus |
|
1372 @param aTarget |
|
1373 @param aNewName |
|
1374 */ |
|
1375 EXPORT_C void CImapProtocolController::RenameL( TRequestStatus& aStatus, |
|
1376 const TMsvId aTarget, |
|
1377 const TDesC& aNewName ) |
|
1378 { |
|
1379 __LOG_TEXT(KDefaultLog, "CImapProtocolController::RenameL()"); |
|
1380 __ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ERenameCompoundIsNotNull)); |
|
1381 |
|
1382 ResetProgress(); |
|
1383 |
|
1384 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
1385 { |
|
1386 iImapCompound = CImapCompoundRename::NewL( *iImapSyncManager, |
|
1387 iEntry, |
|
1388 *iImapSettings, |
|
1389 aTarget, |
|
1390 aNewName ); |
|
1391 |
|
1392 iRequestedOp = ERename; |
|
1393 StartPrimaryOperation(); |
|
1394 Queue(aStatus); |
|
1395 SetActive(); |
|
1396 } |
|
1397 } |
|
1398 |
|
1399 |
|
1400 EXPORT_C void CImapProtocolController::DoRunL() |
|
1401 { |
|
1402 // Handle all migration operations in a separate state machnine. |
|
1403 if (iMigrateState != ENotMigrating) |
|
1404 { |
|
1405 DoMigrateRunL(); |
|
1406 return; |
|
1407 } |
|
1408 |
|
1409 // ProcessError completes and returns ETrue if an error occured |
|
1410 if (ProcessError(iStatus.Int())) |
|
1411 { |
|
1412 return; |
|
1413 } |
|
1414 |
|
1415 switch (iCurrentOp) |
|
1416 { |
|
1417 case EConnect: |
|
1418 { |
|
1419 TRAP_IGNORE(MarkOnOrOfflineL(ETrue)); |
|
1420 |
|
1421 // Collect the final connect progress information |
|
1422 iImapSessionManager->Progress(iProgress.iGenericProgress); |
|
1423 |
|
1424 // Set last socket activity timeout to iMtmData1. This is used by Imcm. |
|
1425 User::LeaveIfError( iEntry.SetEntry( iServiceId ) ); |
|
1426 TMsvEntry entry=iEntry.Entry(); |
|
1427 entry.SetMtmData1(iImapSessionManager->LastSocketActivityTimeout()); |
|
1428 User::LeaveIfError( iEntry.ChangeEntry( entry ) ); |
|
1429 |
|
1430 // Create an IMAP IDLE controller |
|
1431 delete iImapIdleController; |
|
1432 iImapIdleController=NULL; |
|
1433 iImapIdleController = CImapIdleController::NewL(*this, iImapSessionArray[0], *iImapSyncManager, iEntry, *iImapSettings, *iImapMailStore); |
|
1434 |
|
1435 // Register the connection with the mobility manager, |
|
1436 // if we are a mobile service |
|
1437 if (iMobilityManager) |
|
1438 { |
|
1439 iMobilityManager->SetConnection(iImapSessionManager->GetConnectionL()); |
|
1440 } |
|
1441 |
|
1442 // kick off a background sync if it was requested. |
|
1443 if (iBackgroundSyncOp != NULL) |
|
1444 { |
|
1445 iBackgroundSyncOp->StartSync(*iImapSessionArray[0]); |
|
1446 iCurrentOp = EIdle; |
|
1447 } |
|
1448 else |
|
1449 { |
|
1450 StartIdle(); |
|
1451 } |
|
1452 |
|
1453 // complete the connect request |
|
1454 Complete(iStatus.Int()); |
|
1455 break; |
|
1456 } |
|
1457 |
|
1458 case EConnectSecondary: |
|
1459 { |
|
1460 // perform the user-requested operation using the |
|
1461 // newly created imap session |
|
1462 iCurrentOp = iRequestedOp; |
|
1463 if(iImapCompound->Suspended()) |
|
1464 { |
|
1465 // if the operation was previously suspended for migration, resume it... |
|
1466 iImapCompound->ResumeOperationL(iStatus, *iImapSessionArray[iForegroundSession]); |
|
1467 } |
|
1468 else |
|
1469 { |
|
1470 // otherwise, just start the operation. |
|
1471 iImapCompound->StartOperation(iStatus, *iImapSessionArray[iForegroundSession]); |
|
1472 } |
|
1473 SetActive(); |
|
1474 break; |
|
1475 } |
|
1476 |
|
1477 case EStopIdle: |
|
1478 { |
|
1479 // Idle has been cancelled, the primary session is available |
|
1480 // Kick off the requested operation |
|
1481 iCurrentOp = iRequestedOp; |
|
1482 iImapCompound->StartOperation(iStatus, *iImapSessionArray[0]); |
|
1483 SetActive(); |
|
1484 break; |
|
1485 } |
|
1486 |
|
1487 case EDisconnect: |
|
1488 { |
|
1489 TRAP_IGNORE( MarkOnOrOfflineL( EFalse ) ); |
|
1490 |
|
1491 iImapSessionArray.ResetAndDestroy(); |
|
1492 |
|
1493 // update last operation progress state |
|
1494 iImapCompound->Progress(iProgress); |
|
1495 |
|
1496 delete iImapCompound; |
|
1497 iImapCompound = NULL; |
|
1498 iServiceId=0; |
|
1499 |
|
1500 Complete(iStatus.Int()); |
|
1501 break; |
|
1502 } |
|
1503 |
|
1504 case ECancelRecoverPrimary: |
|
1505 { |
|
1506 // Primary session is successfully recovered |
|
1507 // Start the next requested operation |
|
1508 |
|
1509 if (iRequestedOp == EIdle) |
|
1510 { |
|
1511 // We should only go into Idle if no async operations have been requested. |
|
1512 // Consequently, CMsgActive::iReport should be NULL. |
|
1513 // We can't ASSERT this here as it is a private member of CMsgActive, but it is worth checking while debugging. |
|
1514 StartIdle(); |
|
1515 } |
|
1516 else if (iRequestedOp == EDisconnect) |
|
1517 { |
|
1518 // We should only start a primary operation if an async operation has been requested, and an aStatus Queue()ed. |
|
1519 // Consequently, CMsgActive::iReport should NOT be NULL. |
|
1520 // We can't ASSERT this here as it is a private member of CMsgActive, but it is worth checking while debugging. |
|
1521 StartPrimaryOperation(); |
|
1522 SetActive(); |
|
1523 } |
|
1524 else |
|
1525 { |
|
1526 __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProtocolControllerUnexpectedRequestedOp)); |
|
1527 } |
|
1528 |
|
1529 break; |
|
1530 } |
|
1531 |
|
1532 case ESync: |
|
1533 case ESelect: |
|
1534 case ECopyToLocal: |
|
1535 case ECopyWithinService: |
|
1536 case ECopyFromLocal: |
|
1537 case EMoveToLocal: |
|
1538 case EMoveWithinService: |
|
1539 case EMoveFromLocal: |
|
1540 case EPopulate: |
|
1541 case EDelete: |
|
1542 case EDeleteFolder: |
|
1543 case ECreate: |
|
1544 case ERename: |
|
1545 case EUpdateFlag: |
|
1546 { |
|
1547 // update last operation progress state |
|
1548 iImapCompound->Progress(iProgress); |
|
1549 |
|
1550 delete iImapCompound; |
|
1551 iImapCompound = NULL; |
|
1552 |
|
1553 if ((iRequestedOp==ESelect) && (iProgress.iGenericProgress.iErrorCode==KErrNone)) |
|
1554 { |
|
1555 // Do not start IDLE following a select request |
|
1556 Complete(iStatus.Int()); |
|
1557 } |
|
1558 else |
|
1559 { |
|
1560 // Start idle and complete the server mtm request. |
|
1561 StartIdle(); |
|
1562 Complete(iStatus.Int()); |
|
1563 } |
|
1564 break; |
|
1565 } |
|
1566 |
|
1567 case EIdle: // shouldn't happen |
|
1568 default: |
|
1569 { |
|
1570 Complete(iStatus.Int()); |
|
1571 break; |
|
1572 } |
|
1573 |
|
1574 } // end of switch (iCurrentOp) |
|
1575 } |
|
1576 |
|
1577 /** |
|
1578 This variation on DoRunL() presents a super-state machine, that replaces |
|
1579 the default state machine during a migration process. |
|
1580 */ |
|
1581 void CImapProtocolController::DoMigrateRunL() |
|
1582 { |
|
1583 // waiting for existing operation to stop to allow migration to occur. |
|
1584 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::DoMigrateRunL(iMigrateState = %d) CurrentOp = %d", iMigrateState, iCurrentOp)); |
|
1585 switch (iMigrateState) |
|
1586 { |
|
1587 case EWaitingForOpToStop: |
|
1588 case EWaitingForOpToComplete: |
|
1589 { |
|
1590 // operation has completed (is either finished, or has "paused" |
|
1591 // to allow migration to complete. Do any tidying up necessary. |
|
1592 ProcessOpCompleteForMigrate(); |
|
1593 |
|
1594 // is there also a background sync op in progress? if not (or if the |
|
1595 // background sync op is suspended, we are now ready to migrate, |
|
1596 // otherwise wait for the background op to complete. |
|
1597 // |
|
1598 if (!iBackgroundSyncOp || iBackgroundSyncOp->IsSuspendedForMigrate()) |
|
1599 { |
|
1600 // Asynch disconnect current sockets. |
|
1601 DisconnectForMigrateL(); |
|
1602 } |
|
1603 break; |
|
1604 } |
|
1605 case EDisconnectingForMigrate: |
|
1606 { |
|
1607 // The disconnect operation has completed. Delete IMAP Sessions. |
|
1608 iImapSessionArray.ResetAndDestroy(); |
|
1609 |
|
1610 // delete the migration compound object |
|
1611 delete iMigrateCompound; |
|
1612 iMigrateCompound = NULL; |
|
1613 |
|
1614 // Notify the mobility framework that we are ready to migrate. |
|
1615 iMigrateState = EWaitingForNewCarrier; |
|
1616 iMobilityManager->MigrateToNewCarrier(); |
|
1617 |
|
1618 // do not set waiting if NewCarrierActive has been called synchronously. |
|
1619 if (iMigrateState == EWaitingForNewCarrier) |
|
1620 { |
|
1621 // Now in a waiting state, set self active |
|
1622 iStatus = KRequestPending; |
|
1623 SetActive(); |
|
1624 } |
|
1625 break; |
|
1626 } |
|
1627 case EHandlingConnectError: |
|
1628 { |
|
1629 // register with the mobility framework |
|
1630 iMobilityManager->SetConnection(iImapSessionManager->GetConnectionL()); |
|
1631 |
|
1632 // empty the session array |
|
1633 TInt numSessions = iImapSessionArray.Count(); |
|
1634 for (TInt i=0; i<numSessions; ++i) |
|
1635 { |
|
1636 if (iImapSessionArray[i]) |
|
1637 { |
|
1638 iImapSessionManager->Disconnect(*(iImapSessionArray[i])); |
|
1639 } |
|
1640 } |
|
1641 iImapSessionArray.ResetAndDestroy(); |
|
1642 |
|
1643 // reject the initial carrier |
|
1644 iMigrateState = EWaitingInitialCarrierRejected; |
|
1645 iMobilityManager->NewCarrierRejected(); |
|
1646 |
|
1647 if (iMigrateState == EWaitingInitialCarrierRejected) |
|
1648 { |
|
1649 iStatus = KRequestPending; |
|
1650 SetActive(); |
|
1651 } |
|
1652 break; |
|
1653 } |
|
1654 case EStartingReconnect: |
|
1655 { |
|
1656 NewPrimarySessionL(); |
|
1657 break; |
|
1658 } |
|
1659 case EConnectingAfterMigrate: |
|
1660 { |
|
1661 if (iStatus.Int()!=KErrNone) |
|
1662 { |
|
1663 // An error has occurred while attempting to re-connect |
|
1664 // - reject this new carrier, wait to see if a new one turns up. |
|
1665 iMigrateState = EWaitingForNewCarrier; |
|
1666 iMobilityManager->NewCarrierRejected(); |
|
1667 |
|
1668 // Now in a waiting state, set self active |
|
1669 if (iMigrateState == EWaitingForNewCarrier) |
|
1670 { |
|
1671 iStatus = KRequestPending; |
|
1672 SetActive(); |
|
1673 } |
|
1674 } |
|
1675 else |
|
1676 { |
|
1677 iMobilityManager->NewCarrierAccepted(); |
|
1678 RestartAfterMigrateL(); |
|
1679 } |
|
1680 break; |
|
1681 } |
|
1682 case ENotMigrating: |
|
1683 case EWaitingForNewCarrier: |
|
1684 case EWaitingInitialCarrierRejected: |
|
1685 // DoRunMigrateL() Should never be called in this state. |
|
1686 default: |
|
1687 { |
|
1688 __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProtocolControllerUnexpectedMigrateState)); |
|
1689 break; |
|
1690 } |
|
1691 } |
|
1692 } |
|
1693 |
|
1694 |
|
1695 /** |
|
1696 Called when completing an outstanding client request. |
|
1697 Handles negative (system-wide) error codes returned |
|
1698 on completion of asynchronous service requests. |
|
1699 */ |
|
1700 void CImapProtocolController::DoComplete(TInt& aErr) |
|
1701 { |
|
1702 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::DoComplete() - START - aErr = %d, CurrentOp = %d, iCancelInProgress: %d", aErr, iCurrentOp, iCancelInProgress)); |
|
1703 |
|
1704 // Requested operation is completed. |
|
1705 iRequestedOp = EIdle; |
|
1706 |
|
1707 // return if everything is OK |
|
1708 if (aErr==KErrNone) |
|
1709 { |
|
1710 __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - END - KErrNone" ); |
|
1711 return; |
|
1712 } |
|
1713 |
|
1714 // First retrieve the progress information |
|
1715 this->Progress(); |
|
1716 |
|
1717 // log that a cancel has occurred and return |
|
1718 if (aErr==KErrCancel) |
|
1719 { |
|
1720 __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - dealing with cancel case..." ); |
|
1721 iProgress.iGenericProgress.iErrorCode=aErr; |
|
1722 if(!iCancelInProgress) |
|
1723 { |
|
1724 __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - no cancel in progress, so disconnecting all..." ); |
|
1725 DisconnectAll(); |
|
1726 } |
|
1727 |
|
1728 __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - END - KErrCancel" ); |
|
1729 return; |
|
1730 } |
|
1731 |
|
1732 // Non-fatal errors should have been handled prior to this. |
|
1733 __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - fatal error - disconnect all..." ); |
|
1734 // iServiceId = 0, indicates we are already disconnected. |
|
1735 if(iServiceId!=0) |
|
1736 { |
|
1737 DisconnectAll(); |
|
1738 } |
|
1739 |
|
1740 // Save error code in progress and flag the disconnect |
|
1741 iProgress.iGenericProgress.iState=TImap4GenericProgress::EDisconnected; |
|
1742 iProgress.iGenericProgress.iErrorCode=aErr; |
|
1743 |
|
1744 __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - END - fatal error" ); |
|
1745 } |
|
1746 |
|
1747 |
|
1748 /** |
|
1749 Cancels any outstanding client requested asynchronous operations and recovers |
|
1750 the primary session if required. |
|
1751 |
|
1752 This function is exclusively for the use of the CImapServerMtm, and only calls |
|
1753 Cancel() if the PC is currently active performing the requested operation. |
|
1754 If the PC is active for other reasons (for example, waiting for a bearer |
|
1755 migration to complete), the appropriate action is taken. |
|
1756 */ |
|
1757 EXPORT_C void CImapProtocolController::CancelAndCleanup() |
|
1758 { |
|
1759 __LOG_FORMAT( (KDefaultLog, "CImapProtocolController::CancelAndCleanup() - START - iCurrentOp: %d, iRequestedOp: %d, iFlushPrimary: %d", iCurrentOp, iRequestedOp, iFlushPrimary ) ); |
|
1760 if ( iMigrateState == ENotMigrating || |
|
1761 iMigrateState == EWaitingForOpToComplete || |
|
1762 iMigrateState == EWaitingForOpToStop ) |
|
1763 { |
|
1764 // In these states the protocol controller is currently doing something |
|
1765 // at the clients request. |
|
1766 // iCancelInProgress |
|
1767 iCancelInProgress = ETrue; |
|
1768 Cancel(); |
|
1769 |
|
1770 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CancelAndCleanup() - done DoCancel"); |
|
1771 |
|
1772 // DoCancel() will set iFlushPrimary to ETrue for operations that require |
|
1773 // a flush after being cancelled. This will cause DoRunL() to be called when the |
|
1774 // session has been flushed. In the case of bearer migration, the next step will |
|
1775 // be started in DoRunL. |
|
1776 if (iFlushPrimary) |
|
1777 { |
|
1778 iRequestedOp = EIdle; // We want to return to idle when the flush has completed. |
|
1779 iCurrentOp = ECancelRecoverPrimary; |
|
1780 CImapSession* session = iImapSessionArray[0]; |
|
1781 session->FlushCancelledCommand(iStatus); |
|
1782 SetActive(); |
|
1783 iFlushPrimary = EFalse; |
|
1784 } |
|
1785 // clear the cancelling flag |
|
1786 iCancelInProgress = EFalse; |
|
1787 } |
|
1788 else |
|
1789 { |
|
1790 // in other migration states, we don't want to cancel because we |
|
1791 // are active for migration purposes. However, we do need to clean |
|
1792 // compound operation objects and complete the user. |
|
1793 iRequestedOp = iCurrentOp = EIdle; |
|
1794 |
|
1795 // Update the progress object |
|
1796 iProgress.iGenericProgress.iState = TImap4GenericProgress::EIdle; |
|
1797 iProgress.iGenericProgress.iErrorCode = KErrCancel; |
|
1798 |
|
1799 delete iImapCompound; |
|
1800 iImapCompound = NULL; |
|
1801 CMsgActive::DoCancel(); // completes the user request. |
|
1802 } |
|
1803 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CancelAndCleanup() - END"); |
|
1804 } |
|
1805 |
|
1806 |
|
1807 /** |
|
1808 DoCancel - called by CMsgActive::Cancel() to cancel asychronous services: |
|
1809 |
|
1810 Cancel() must not be called on this class to cancel a requested async |
|
1811 service - CancelAndCleanup() should be used instead. CancelAndCleanup() |
|
1812 provides support for cancelling requested operations while this class |
|
1813 has become active for migration purposes. |
|
1814 |
|
1815 However, Cancel() must always be called eventually as the iStatus needs |
|
1816 to be cleared. Hence this function must support all cancel operations. |
|
1817 |
|
1818 This class is allows for Cancel() to be called internally to cancel |
|
1819 async operations that have been launched internally for migration |
|
1820 purposes, without completing the CImapServerMtm. |
|
1821 */ |
|
1822 void CImapProtocolController::DoCancel() |
|
1823 { |
|
1824 __LOG_FORMAT( (KDefaultLog, "CImapProtocolController::DoCancel() - START - iCurrentOp: %d, iRequestedOp: %d, iFlushPrimary: %d", iCurrentOp, iRequestedOp, iFlushPrimary ) ); |
|
1825 |
|
1826 if (iMigrateState==ENotMigrating) |
|
1827 { |
|
1828 DoCancelClientOp(); |
|
1829 } |
|
1830 else |
|
1831 { |
|
1832 switch (iMigrateState) |
|
1833 { |
|
1834 case ESuspendingForMigrate: |
|
1835 { |
|
1836 // Special handling for cancelling current operation to allow |
|
1837 // migration to occur. |
|
1838 DoCancelForMigrate(); |
|
1839 break; |
|
1840 } |
|
1841 case EWaitingForOpToComplete: |
|
1842 case EWaitingForOpToStop: |
|
1843 { |
|
1844 // we have an outstanding request on the compound operation |
|
1845 // call the default DoCancelClientOp(). This will also |
|
1846 // complete the client's iStatus with KErrCancel |
|
1847 DoCancelClientOp(); |
|
1848 break; |
|
1849 } |
|
1850 case EDisconnectingForMigrate: |
|
1851 { |
|
1852 // outstanding op is on the iMigrateCompound |
|
1853 iMigrateCompound->Cancel(); |
|
1854 delete iMigrateCompound; |
|
1855 iMigrateCompound = NULL; |
|
1856 break; |
|
1857 } |
|
1858 case EConnectingAfterMigrate: |
|
1859 { |
|
1860 // This state represents re-connection of the primary session, |
|
1861 // it is safe to simply clear the imap session array. |
|
1862 iImapSessionManager->Cancel(); |
|
1863 iImapSessionArray.ResetAndDestroy(); |
|
1864 break; |
|
1865 } |
|
1866 case EWaitingForNewCarrier: |
|
1867 case EWaitingInitialCarrierRejected: |
|
1868 { |
|
1869 // in these states, we are in a self-induced active state |
|
1870 // Cancel it: |
|
1871 TRequestStatus* status = &iStatus; |
|
1872 User::RequestComplete(status, KErrCancel); |
|
1873 break; |
|
1874 } |
|
1875 |
|
1876 case EStartingReconnect: // nothing to cancel |
|
1877 case EHandlingConnectError: // nothing to cancel |
|
1878 case ENotMigrating: // somethings gone wrong |
|
1879 default: |
|
1880 { |
|
1881 __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProtocolControllerCancelBadMigrateState)); |
|
1882 } |
|
1883 } // switch (iMigrateState) |
|
1884 } |
|
1885 |
|
1886 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancel() - END"); |
|
1887 } |
|
1888 |
|
1889 void CImapProtocolController::DoCancelClientOp() |
|
1890 { |
|
1891 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - START"); |
|
1892 |
|
1893 // Update the requested and current operations |
|
1894 // the implication is that a return to EIdle is required |
|
1895 // current op may be updated later if an async op is issued. |
|
1896 TImapProtocolOp cancelledOp = iCurrentOp; |
|
1897 iRequestedOp = iCurrentOp = EIdle; |
|
1898 |
|
1899 switch (cancelledOp) |
|
1900 { |
|
1901 case EConnect: |
|
1902 { |
|
1903 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - EConnect"); |
|
1904 iImapSessionManager->Cancel(); |
|
1905 |
|
1906 // As this state represents connection of the primary session, |
|
1907 // it is safe to simply clear the imap session array. |
|
1908 iImapSessionArray.ResetAndDestroy(); |
|
1909 |
|
1910 // delete the background sync operation if it exists. |
|
1911 if (iBackgroundSyncOp != NULL) |
|
1912 { |
|
1913 iBackgroundSyncOp->Cancel(); |
|
1914 delete iBackgroundSyncOp; |
|
1915 iBackgroundSyncOp=NULL; |
|
1916 } |
|
1917 |
|
1918 // delete the sync manager |
|
1919 delete iImapSyncManager; |
|
1920 iImapSyncManager = NULL; |
|
1921 |
|
1922 break; |
|
1923 } |
|
1924 |
|
1925 case EConnectSecondary: |
|
1926 { |
|
1927 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - EConnectSecondary"); |
|
1928 // Cancel the connect request |
|
1929 iImapSessionManager->Cancel(); |
|
1930 iForegroundSession=0; |
|
1931 |
|
1932 // Remove the session pointer from the array |
|
1933 // The session has already been deleted - see note above. |
|
1934 TInt numSessions = iImapSessionArray.Count(); |
|
1935 iImapSessionArray.Remove(numSessions-1); |
|
1936 |
|
1937 if (iImapCompound!=NULL) |
|
1938 { |
|
1939 // The requested op hasn't actually started yet |
|
1940 // so don't cancel on the compound operation.. |
|
1941 // update last operation progress state |
|
1942 iImapCompound->Progress(iProgress); |
|
1943 |
|
1944 delete iImapCompound; |
|
1945 iImapCompound = NULL; |
|
1946 } |
|
1947 |
|
1948 // The progress will not report cancel at this stage - force it here. |
|
1949 iProgress.iGenericProgress.iState = TImap4GenericProgress::EIdle; |
|
1950 iProgress.iGenericProgress.iErrorCode = KErrCancel; |
|
1951 |
|
1952 break; |
|
1953 } |
|
1954 |
|
1955 case EDisconnect: |
|
1956 { |
|
1957 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - EDisconnect"); |
|
1958 // Cancel the disconnect compound operation |
|
1959 iImapCompound->Cancel(); |
|
1960 |
|
1961 delete iImapCompound; |
|
1962 iImapCompound = NULL; |
|
1963 |
|
1964 // A cancelled disconnect will leave the sessions disconnected |
|
1965 // but not deleted. Reset and destroy the session array. |
|
1966 iImapSessionArray.ResetAndDestroy(); |
|
1967 |
|
1968 break; |
|
1969 } |
|
1970 |
|
1971 case EIdle: |
|
1972 { |
|
1973 // This is unexpected - in this state there should be no |
|
1974 // outstanding asynconous requests on the Protocol Controller. |
|
1975 // Protocol Controller has no outstanding requests in this state |
|
1976 // however a sync may be running in the background. This is |
|
1977 // cancelled when the background sync object's destructor is called. |
|
1978 // So.. Nothing to do. |
|
1979 break; |
|
1980 } |
|
1981 |
|
1982 case EStopIdle: |
|
1983 { |
|
1984 if (iImapCompound!=NULL) |
|
1985 { |
|
1986 // The requested op hasn't actually started yet |
|
1987 // so don't cancel on the compound operation.. |
|
1988 // update last operation progress state |
|
1989 iImapCompound->Progress(iProgress); |
|
1990 |
|
1991 delete iImapCompound; |
|
1992 iImapCompound = NULL; |
|
1993 } |
|
1994 |
|
1995 // The progress will not report cancel at this stage - force it here. |
|
1996 iProgress.iGenericProgress.iState = TImap4GenericProgress::EIdle; |
|
1997 iProgress.iGenericProgress.iErrorCode = KErrCancel; |
|
1998 |
|
1999 // Cancel the idle controller. |
|
2000 iImapIdleController->Cancel(); |
|
2001 |
|
2002 // Cancelling the idle controller is likely to leave the IMAP Session |
|
2003 // with data left on the input stream to be dealt with. We need to |
|
2004 // flush the session if we wish to re-use it. |
|
2005 iFlushPrimary = ETrue; |
|
2006 |
|
2007 break; |
|
2008 } |
|
2009 |
|
2010 case ESync: |
|
2011 case ESelect: |
|
2012 case ECopyToLocal: |
|
2013 case ECopyWithinService: |
|
2014 case ECopyFromLocal: |
|
2015 case EMoveToLocal: |
|
2016 case EMoveWithinService: |
|
2017 case EMoveFromLocal: |
|
2018 case EPopulate: |
|
2019 case EDelete: |
|
2020 case EDeleteFolder: |
|
2021 case ECreate: |
|
2022 case ERename: |
|
2023 case EUpdateFlag: |
|
2024 { |
|
2025 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - ESync/ESelect/ECopyToLocal/ECopyWithinService/ECopyFromLocal/EMoveToLocal/EMoveWithinService/EMoveFromLocal/EPopulate/EDelete/EDeleteFolder/ECreate/ERename/"); |
|
2026 // This is the normal case, a requested operation is |
|
2027 // being performed by a compound operation object. |
|
2028 // First of all, check one exists. |
|
2029 if (iImapCompound!=NULL) |
|
2030 { |
|
2031 // Cancel the compound operation |
|
2032 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - cancelling iImapCompound..."); |
|
2033 iImapCompound->Cancel(); |
|
2034 |
|
2035 // update last operation progress state |
|
2036 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - getting progres..."); |
|
2037 iImapCompound->Progress(iProgress); |
|
2038 |
|
2039 // Delete the compound object |
|
2040 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - deleting compound..."); |
|
2041 delete iImapCompound; |
|
2042 iImapCompound = NULL; |
|
2043 |
|
2044 // Cancelling the compound operation is likely to leave |
|
2045 // the IMAP Session in an incomplete state. We need to |
|
2046 // flush the session if we wish to re-use it. |
|
2047 if (iForegroundSession==0) |
|
2048 { |
|
2049 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - flush primary = ETrue..."); |
|
2050 iFlushPrimary = ETrue; |
|
2051 } |
|
2052 else |
|
2053 { |
|
2054 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - drop session..."); |
|
2055 DropSession(iForegroundSession); |
|
2056 iForegroundSession=0; |
|
2057 } |
|
2058 |
|
2059 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - main iImapCompound handling complete..."); |
|
2060 } |
|
2061 break; |
|
2062 } |
|
2063 |
|
2064 case ECancelRecoverPrimary: |
|
2065 { |
|
2066 // The recover must be taking too long. |
|
2067 // cancel the recover request.. |
|
2068 (iImapSessionArray[0])->Cancel(); |
|
2069 // Delete all sessions, go offline etc. |
|
2070 DisconnectAll(); |
|
2071 break; |
|
2072 } |
|
2073 default: |
|
2074 { |
|
2075 // nothing to do.. |
|
2076 break; |
|
2077 } |
|
2078 } // end of switch (cancelledOp) |
|
2079 |
|
2080 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - about to call CMsgActive::DoCancel()..."); |
|
2081 CMsgActive::DoCancel(); |
|
2082 |
|
2083 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - END"); |
|
2084 } |
|
2085 |
|
2086 |
|
2087 /** |
|
2088 Performs a fast disconnect on all sessions |
|
2089 |
|
2090 Ensures that the compound, background sync and sync manager objects are |
|
2091 deleted following the disconnect. |
|
2092 @param aMarkOffline - indicates if the service is to be marked offline. |
|
2093 */ |
|
2094 void CImapProtocolController::DisconnectAll() |
|
2095 { |
|
2096 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - START"); |
|
2097 |
|
2098 // Delete the background sync op |
|
2099 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - deleting iBackgroundSyncOp"); |
|
2100 delete iBackgroundSyncOp; |
|
2101 iBackgroundSyncOp=NULL; |
|
2102 |
|
2103 // Delete the imap compound operation |
|
2104 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - deleting iImapCompound"); |
|
2105 delete iImapCompound; |
|
2106 iImapCompound=NULL; |
|
2107 |
|
2108 // Delete the migrate compound operation |
|
2109 delete iMigrateCompound; |
|
2110 iMigrateCompound = NULL; |
|
2111 |
|
2112 // delete the sync manager |
|
2113 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - deleting iImapSyncManager"); |
|
2114 delete iImapSyncManager; |
|
2115 iImapSyncManager = NULL; |
|
2116 |
|
2117 // delete the mobility manager (de-register for mobility notifications) |
|
2118 delete iMobilityManager; |
|
2119 iMobilityManager = NULL; |
|
2120 |
|
2121 // delete the imap idle controller |
|
2122 delete iImapIdleController; |
|
2123 iImapIdleController = NULL; |
|
2124 |
|
2125 // Drop connection on each of the imap sessions |
|
2126 TInt numSessions = iImapSessionArray.Count(); |
|
2127 for (TInt i=0; i<numSessions; ++i) |
|
2128 { |
|
2129 if (iImapSessionArray[i]) |
|
2130 { |
|
2131 __LOG_FORMAT( (KDefaultLog, "CImapProtocolController::DisconnectAll() - disconnecting session: %d/%d", i, numSessions ) ); |
|
2132 iImapSessionManager->Disconnect(*(iImapSessionArray[i])); |
|
2133 } |
|
2134 } |
|
2135 |
|
2136 // The current network connection will be closed |
|
2137 iImapSessionManager->CloseNetworkConnection(); |
|
2138 |
|
2139 |
|
2140 // empty the session array |
|
2141 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - resetting and destroying sessions..."); |
|
2142 iImapSessionArray.ResetAndDestroy(); |
|
2143 |
|
2144 // force the state to IDLE |
|
2145 iRequestedOp = EIdle; |
|
2146 iCurrentOp = EIdle; |
|
2147 |
|
2148 // Clear serviceid and mark the service as offline |
|
2149 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - about to MarkOnOrOffline..."); |
|
2150 TRAP_IGNORE(MarkOnOrOfflineL(EFalse)); |
|
2151 iServiceId=0; |
|
2152 |
|
2153 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - END"); |
|
2154 } |
|
2155 |
|
2156 /** |
|
2157 Performs an immediate disconnect of specifed session and removes it from |
|
2158 the session array. |
|
2159 |
|
2160 @param sessionId - the index in the session array of the session to drop. |
|
2161 */ |
|
2162 void CImapProtocolController::DropSession(TInt sessionId) |
|
2163 { |
|
2164 if (sessionId < iImapSessionArray.Count()) |
|
2165 { |
|
2166 CImapSession* tempSession = iImapSessionArray[sessionId]; |
|
2167 if (tempSession) |
|
2168 { |
|
2169 iImapSessionManager->Disconnect(*tempSession); |
|
2170 delete tempSession; |
|
2171 } |
|
2172 iImapSessionArray.Remove(sessionId); |
|
2173 } |
|
2174 } |
|
2175 |
|
2176 /** |
|
2177 Private method to select session from the session array for use for operations |
|
2178 that are supported while background operations are in progress. |
|
2179 Issues a request to connect a secondary session if the primary session is busy |
|
2180 and a secondary session is not already available. In this case the requested op |
|
2181 is updated to show a secondary connect request, and the original requested op |
|
2182 is saved. |
|
2183 |
|
2184 @param aIndexToUse updated to indicate the index of the session to be used |
|
2185 @return ETrue if the session is connected and ready to use immediately. |
|
2186 EFalse if a request to connect a secondary session has been issued. |
|
2187 */ |
|
2188 TBool CImapProtocolController::SelectSessionL(TInt& aIndexToUse) |
|
2189 { |
|
2190 __ASSERT_DEBUG(iCurrentOp != ECancelRecoverPrimary, TImapServerPanic::ImapPanic(TImapServerPanic::EProtocolControllerUnexpectedCurrentOp)); |
|
2191 |
|
2192 aIndexToUse = 0; // default to primary session. |
|
2193 TBool sessionReady = ETrue; |
|
2194 if (iBackgroundSyncOp != NULL) |
|
2195 { |
|
2196 TInt sessionCount = iImapSessionArray.Count(); |
|
2197 if (sessionCount>=2) |
|
2198 { |
|
2199 // already a secondary session available - use this |
|
2200 aIndexToUse = sessionCount-1; |
|
2201 } |
|
2202 else |
|
2203 { |
|
2204 // Create a new session and get it connected. |
|
2205 iCurrentOp = EConnectSecondary; |
|
2206 |
|
2207 CImapSession* imapSession = NULL; |
|
2208 iImapSessionArray.AppendL(imapSession); |
|
2209 iImapSessionManager->GetSessionL(iStatus, iImapSessionArray[sessionCount]); |
|
2210 aIndexToUse = sessionCount; |
|
2211 sessionReady = EFalse; |
|
2212 } |
|
2213 } |
|
2214 return sessionReady; |
|
2215 } |
|
2216 |
|
2217 /** |
|
2218 Called to kick off a foreground operation, ie a user requested |
|
2219 operation that is being performed on the primary IMAP session. |
|
2220 |
|
2221 If the session is in IMAP IDLE, a request is issued to stop this |
|
2222 and the requested operation is started when the stop-idle operation |
|
2223 has completed. Otherwise the operation is started immediately. |
|
2224 */ |
|
2225 void CImapProtocolController::StartPrimaryOperation() |
|
2226 { |
|
2227 // Make sure the foreground session id is correct |
|
2228 iForegroundSession = 0; |
|
2229 // imap idle controller is active in any state after |
|
2230 // idle has been requested. |
|
2231 if (iImapIdleController->IsActive()) |
|
2232 { |
|
2233 iCurrentOp = EStopIdle; |
|
2234 iImapIdleController->StopIdle(iStatus); |
|
2235 } |
|
2236 else |
|
2237 { |
|
2238 iCurrentOp = iRequestedOp; |
|
2239 iImapCompound->StartOperation(iStatus, *iImapSessionArray[iForegroundSession]); |
|
2240 } |
|
2241 } |
|
2242 |
|
2243 /** |
|
2244 Starts the background IDLE process. |
|
2245 If IDLE is not supported by the server, or if IDLE is disabled via the |
|
2246 account settings, a "dummy read" is issued, to manage any unsolicited |
|
2247 server messages. |
|
2248 |
|
2249 This is called when user-requested compound operations have completed |
|
2250 to return the primary session to IDLE state. Note that some operations |
|
2251 require that IDLE is not re-issued, eg "select". It is also called |
|
2252 when a background sync operation has completed, if there is no foreground |
|
2253 operation currently in progress |
|
2254 |
|
2255 Idle is only issued on the primary session. |
|
2256 |
|
2257 Idle is not started if there is a background operation in progress |
|
2258 */ |
|
2259 void CImapProtocolController::StartIdle() |
|
2260 { |
|
2261 iCurrentOp = EIdle; |
|
2262 if (iBackgroundSyncOp==NULL) |
|
2263 { |
|
2264 iImapIdleController->StartIdle(); |
|
2265 } |
|
2266 } |
|
2267 |
|
2268 /** |
|
2269 Called by the CImapIdleController in the case of an error being observed |
|
2270 while in IDLE state. |
|
2271 |
|
2272 @param aError - the observed error |
|
2273 */ |
|
2274 void CImapProtocolController::OnIdleError(TInt aError) |
|
2275 { |
|
2276 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::OnIdleError(aError = %d)", aError)); |
|
2277 if (aError>0) |
|
2278 { |
|
2279 aError = KErrImapServerFail; |
|
2280 } |
|
2281 iProgress.iGenericProgress.iErrorCode = aError; |
|
2282 iProgress.iGenericProgress.iState=TImap4GenericProgress::EDisconnected; |
|
2283 DisconnectAll(); |
|
2284 // Nothing to complete. |
|
2285 } |
|
2286 |
|
2287 /** |
|
2288 Returns the progress information for the outstanding command. |
|
2289 |
|
2290 @return progress information |
|
2291 */ |
|
2292 EXPORT_C TImap4CompoundProgress CImapProtocolController::Progress() |
|
2293 { |
|
2294 // Progress of foreground operation is returned over that of a |
|
2295 // background sync operation. |
|
2296 // Do not refresh the progress while migrating. |
|
2297 if (iCurrentOp!=EIdle && iMigrateState == ENotMigrating) |
|
2298 { |
|
2299 // do not update if IDLEing - return the stored progress object |
|
2300 // this should have been populated correctly on completion of |
|
2301 // requested operation, whether successful or otherwise. |
|
2302 switch (iCurrentOp) |
|
2303 { |
|
2304 case EConnect: |
|
2305 { |
|
2306 iImapSessionManager->Progress(iProgress.iGenericProgress); |
|
2307 break; |
|
2308 } |
|
2309 case EStopIdle: |
|
2310 case ESync: |
|
2311 case ESelect: |
|
2312 case ECopyToLocal: |
|
2313 case ECopyWithinService: |
|
2314 case ECopyFromLocal: |
|
2315 case EMoveToLocal: |
|
2316 case EMoveWithinService: |
|
2317 case EMoveFromLocal: |
|
2318 case EPopulate: |
|
2319 case EDelete: |
|
2320 case EDeleteFolder: |
|
2321 case ECreate: |
|
2322 case ERename: |
|
2323 case EDisconnect: |
|
2324 case EUpdateFlag: |
|
2325 { |
|
2326 // Obtain progress from compound object if it exists |
|
2327 // Otherwise the last progress obtained on completion |
|
2328 // of the compound object is returned. |
|
2329 if (iImapCompound!=NULL) |
|
2330 { |
|
2331 iImapCompound->Progress(iProgress); |
|
2332 } |
|
2333 break; |
|
2334 } |
|
2335 case EIdle: |
|
2336 default: |
|
2337 break; |
|
2338 } |
|
2339 } |
|
2340 else if (iBackgroundSyncOp!=NULL) |
|
2341 { |
|
2342 // update sync progress if background sync is being performed. |
|
2343 iBackgroundSyncOp->Progress(iProgress); |
|
2344 } |
|
2345 |
|
2346 return iProgress; |
|
2347 } |
|
2348 |
|
2349 /** |
|
2350 changes local subscription flag on a folder immediately. |
|
2351 If unsubscribing, the folder is marked as invisible, and the invisible |
|
2352 flag is propagated to any parent folders that are not themselves subscribed |
|
2353 or contain subscribed folders. |
|
2354 |
|
2355 @param aFolder |
|
2356 @param aSubscribed |
|
2357 @return Error code |
|
2358 */ |
|
2359 EXPORT_C TInt CImapProtocolController::SetLocalSubscription(const TMsvId aFolder, |
|
2360 TBool aSubscribed) |
|
2361 { |
|
2362 __LOG_TEXT(KDefaultLog, "CImapProtocolController::SetLocalSubscription()"); |
|
2363 |
|
2364 TInt err; |
|
2365 |
|
2366 // Move to the entry |
|
2367 if ((err=iEntry.SetEntry(aFolder))!=KErrNone) |
|
2368 return(err); |
|
2369 |
|
2370 // Check it's a folder |
|
2371 if (iEntry.Entry().iType!=KUidMsvFolderEntry) |
|
2372 return(KErrNotSupported); |
|
2373 |
|
2374 // update subscription flag |
|
2375 TMsvEmailEntry entry=iEntry.Entry(); |
|
2376 entry.SetLocalSubscription(aSubscribed); |
|
2377 entry.SetVisible(aSubscribed); |
|
2378 |
|
2379 err = iEntry.ChangeEntry(entry); |
|
2380 |
|
2381 // Return if error or if setting subscribed |
|
2382 if (err!=KErrNone || !aSubscribed) |
|
2383 { |
|
2384 TRAP(err, PropagateUnsubscribeL(aFolder)); |
|
2385 return err; |
|
2386 } |
|
2387 else |
|
2388 { |
|
2389 return KErrNone; |
|
2390 } |
|
2391 } |
|
2392 |
|
2393 /** |
|
2394 Marks aFolder as invisible and propagates the invisible flag to parent folder. |
|
2395 |
|
2396 @param aFolder the unsubscribed folder. |
|
2397 */ |
|
2398 void CImapProtocolController::PropagateUnsubscribeL(const TMsvId aFolder) |
|
2399 { |
|
2400 // Settings may not yet be loaded. |
|
2401 if (iImapSettings->SettingsLoaded()==EFalse) |
|
2402 { |
|
2403 iImapSettings->LoadSettingsL(aFolder); |
|
2404 } |
|
2405 |
|
2406 // if synchronisation setting is not remote only then |
|
2407 // update the invisibility flags |
|
2408 if (iImapSettings->Synchronise() != EUseRemote) |
|
2409 { |
|
2410 PropagateInvisibleFlagL(aFolder); |
|
2411 ChangeVisibilityL(aFolder,ETrue,EFalse,KUidMsvMessageEntry); |
|
2412 } |
|
2413 } |
|
2414 |
|
2415 |
|
2416 // Mark service as on or offline |
|
2417 void CImapProtocolController::MarkOnOrOfflineL( const TBool aOnline ) |
|
2418 { |
|
2419 // Mark service entry as on/offline |
|
2420 User::LeaveIfError( iEntry.SetEntry( iServiceId ) ); |
|
2421 |
|
2422 TMsvEntry entry=iEntry.Entry(); |
|
2423 entry.SetConnected( aOnline ); |
|
2424 User::LeaveIfError( iEntry.ChangeEntry( entry ) ); |
|
2425 |
|
2426 // Release the service entry |
|
2427 User::LeaveIfError( iEntry.SetEntry( KMsvNullIndexEntryId ) ); |
|
2428 |
|
2429 // Going offline? |
|
2430 if ( !aOnline && iImapSettings->DisconnectedUserMode() ) |
|
2431 { |
|
2432 // We're an expert user going offline: don't touch anything |
|
2433 return; |
|
2434 } |
|
2435 |
|
2436 // Mark all immediate children of the service as invisible |
|
2437 if ( !aOnline ) |
|
2438 ChangeVisibilityL( iServiceId, !aOnline ); |
|
2439 } |
|
2440 |
|
2441 void CImapProtocolController::ChangeVisibilityL(TMsvId aParent, TBool aInvisible) |
|
2442 { |
|
2443 ChangeVisibilityL(aParent, aInvisible, ETrue, KUidMsvFolderEntry); |
|
2444 } |
|
2445 |
|
2446 |
|
2447 void CImapProtocolController::ChangeVisibilityL(TMsvId aParent, TBool aInvisible, TBool aRecurse, TUid aType) |
|
2448 { |
|
2449 // Get children at this level |
|
2450 CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection; |
|
2451 CleanupStack::PushL( selection ); |
|
2452 |
|
2453 CMsvEntrySelection* folders = new (ELeave) CMsvEntrySelection; |
|
2454 CleanupStack::PushL( folders ); |
|
2455 |
|
2456 User::LeaveIfError( iEntry.SetEntry( aParent ) ); |
|
2457 User::LeaveIfError( iEntry.GetChildren( *selection ) ); |
|
2458 |
|
2459 if ( selection->Count() ) |
|
2460 { |
|
2461 for( TInt child=0; child < selection->Count(); child++ ) |
|
2462 { |
|
2463 // Move to this child |
|
2464 User::LeaveIfError( iEntry.SetEntry( (*selection)[child] ) ); |
|
2465 |
|
2466 TMsvEntry message=iEntry.Entry(); |
|
2467 |
|
2468 // Is this the type we want to change? |
|
2469 if (message.iType==aType) |
|
2470 { |
|
2471 // Add to selection to do bulk change on, if necessary |
|
2472 if ((message.Visible() && aInvisible) || |
|
2473 (!message.Visible() && !aInvisible)) |
|
2474 { |
|
2475 folders->AppendL(message.Id()); |
|
2476 } |
|
2477 } |
|
2478 |
|
2479 // Recurse downwards |
|
2480 if (aRecurse && message.iType==KUidMsvFolderEntry) |
|
2481 ChangeVisibilityL(message.Id(),aInvisible,aRecurse,aType); |
|
2482 } |
|
2483 |
|
2484 // Change its visibility off all children if necessary |
|
2485 if (folders->Count()) |
|
2486 { |
|
2487 // Do the change to the invisible flag (actual constant for the |
|
2488 // flag we want is private:() |
|
2489 |
|
2490 User::LeaveIfError( iEntry.SetEntry( aParent ) ); |
|
2491 User::LeaveIfError( iEntry.ChangeAttributes(*folders, |
|
2492 aInvisible?0:KMsvVisibilityAttribute, |
|
2493 aInvisible?KMsvVisibilityAttribute:0)); |
|
2494 } |
|
2495 } |
|
2496 |
|
2497 // Release the service entry |
|
2498 User::LeaveIfError( iEntry.SetEntry( KMsvNullIndexEntryId ) ); |
|
2499 |
|
2500 // Get rid of selection |
|
2501 CleanupStack::PopAndDestroy(2); |
|
2502 } |
|
2503 |
|
2504 /** |
|
2505 Propagates invisible flag for unsubscribed folders. |
|
2506 aId has been unsubscribed. If it has no visible child folders then |
|
2507 it is made invisible and its parent checked with the same test |
|
2508 |
|
2509 @param aId the folder that has been unsubscribed |
|
2510 */ |
|
2511 void CImapProtocolController::PropagateInvisibleFlagL(TMsvId aId) |
|
2512 { |
|
2513 __LOG_FORMAT((KDefaultLog, "PropagateInvisibleFlagL: 0x%x", aId)); |
|
2514 |
|
2515 // finish if we've reached the top |
|
2516 if (aId == KMsvRootIndexEntryId) |
|
2517 { |
|
2518 return; |
|
2519 } |
|
2520 |
|
2521 User::LeaveIfError(iEntry.SetEntry(aId)); |
|
2522 |
|
2523 // finish if we've reached a service |
|
2524 if (iEntry.Entry().iType == KUidMsvServiceEntry) |
|
2525 { |
|
2526 return; |
|
2527 } |
|
2528 |
|
2529 // return if we've found a subscribed folder since we can't make |
|
2530 // it invisible |
|
2531 if (((TMsvEmailEntry)iEntry.Entry()).LocalSubscription()) |
|
2532 { |
|
2533 return; |
|
2534 } |
|
2535 |
|
2536 // check the children of this unsubscribed folder |
|
2537 CMsvEntrySelection* selection=new (ELeave) CMsvEntrySelection; |
|
2538 CleanupStack::PushL(selection); |
|
2539 |
|
2540 User::LeaveIfError(iEntry.GetChildren(*selection)); |
|
2541 |
|
2542 TBool visible=EFalse; |
|
2543 TInt count = selection->Count(); |
|
2544 for (TInt i=0; i < count; ++i) |
|
2545 { |
|
2546 User::LeaveIfError(iEntry.SetEntry((*selection)[i])); |
|
2547 |
|
2548 // look for a visible folder |
|
2549 TMsvEmailEntry entry = (TMsvEmailEntry)iEntry.Entry(); |
|
2550 if (entry.iType == KUidMsvFolderEntry && entry.Visible()) |
|
2551 { |
|
2552 visible=ETrue; |
|
2553 break; |
|
2554 } |
|
2555 } |
|
2556 |
|
2557 CleanupStack::PopAndDestroy(selection); |
|
2558 |
|
2559 // if no child folders were visible then make this folder |
|
2560 // invisible and continue up |
|
2561 if (!visible) |
|
2562 { |
|
2563 User::LeaveIfError(iEntry.SetEntry(aId)); |
|
2564 |
|
2565 // make this invisible |
|
2566 TMsvEntry entry = iEntry.Entry(); |
|
2567 entry.SetVisible(EFalse); |
|
2568 User::LeaveIfError(iEntry.ChangeEntry(entry)); |
|
2569 |
|
2570 // go up |
|
2571 PropagateInvisibleFlagL(entry.Parent()); |
|
2572 } |
|
2573 } |
|
2574 |
|
2575 |
|
2576 /** |
|
2577 Is this id in the local service? |
|
2578 @param aId the id of the entry to check |
|
2579 @return true, if the message id belongs to the local service. |
|
2580 */ |
|
2581 TBool CImapProtocolController::IdIsLocalL(TMsvId aId) |
|
2582 { |
|
2583 return ServiceOfL(aId) == KMsvLocalServiceIndexEntryIdValue; |
|
2584 } |
|
2585 |
|
2586 /** |
|
2587 Returns the id of the service containing this id |
|
2588 @param aId the id of the entry to check |
|
2589 @return the id of the containing service |
|
2590 */ |
|
2591 TMsvId CImapProtocolController::ServiceOfL(TMsvId aId) |
|
2592 { |
|
2593 TMsvId current=aId; |
|
2594 while(current!=KMsvRootIndexEntryIdValue) |
|
2595 { |
|
2596 // Visit this entry |
|
2597 User::LeaveIfError(iEntry.SetEntry(current)); |
|
2598 |
|
2599 TMsvEmailEntry entry = iEntry.Entry(); |
|
2600 |
|
2601 // if service then searched far enough |
|
2602 if (entry.iType==KUidMsvServiceEntry) |
|
2603 break; |
|
2604 |
|
2605 // Go upwards |
|
2606 current=entry.Parent(); |
|
2607 } |
|
2608 |
|
2609 return current; |
|
2610 } |
|
2611 |
|
2612 /** |
|
2613 Processes positive error codes returned by asynchronous service requests. |
|
2614 Specifically, these will be error codes returned by the CImapSession, |
|
2615 indicating error conditions in communication with the remote server. |
|
2616 |
|
2617 See cimapsessionconsts.h for full definition of error codes, summarised here: |
|
2618 |
|
2619 KErrImapNo IMAP server returned a tagged NO response |
|
2620 KErrImapBad IMAP server returned a tagged BAD response |
|
2621 KErrImapClosed indicates one of the streams has closed |
|
2622 KErrImapFlushTimeout an attempt to flush a cancelled command has timed out |
|
2623 KErrImapCorrupt corrupt data was enountered during parsing of IMAP server data |
|
2624 |
|
2625 @param aError - the positive error code received on completion |
|
2626 of an asynchronous service |
|
2627 |
|
2628 @return ETrue - if this function has called Complete() due to a fatal error. |
|
2629 EFalse - otherwise |
|
2630 */ |
|
2631 TBool CImapProtocolController::ProcessError(TInt aError) |
|
2632 { |
|
2633 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::ProcessError(iCurrentOp = %d, aError = %d)", iCurrentOp, aError)); |
|
2634 |
|
2635 // Bearer mobility support for initially connect failure |
|
2636 if (iMobilityManager && aError == KErrImapConnectError && iImapSessionManager->HasConnection()) |
|
2637 { |
|
2638 // Change migration state, so the connect error can be dealt with, |
|
2639 // using the migration state machine. |
|
2640 iMigrateState = EHandlingConnectError; |
|
2641 |
|
2642 SetActive(); |
|
2643 TRequestStatus* status = &iStatus; |
|
2644 User::RequestComplete(status, KErrNone); |
|
2645 |
|
2646 return ETrue; |
|
2647 } |
|
2648 |
|
2649 |
|
2650 // weed out non-fatal server errors |
|
2651 ThranslateSessionError(aError); |
|
2652 if (aError == KErrNone) |
|
2653 { |
|
2654 return EFalse; |
|
2655 } |
|
2656 |
|
2657 if (iForegroundSession>0) |
|
2658 { |
|
2659 // error has occurred on a secondary session. |
|
2660 // This is not fatal to the whole protocol controller's |
|
2661 // existance, but it is fatal to the requested operation |
|
2662 |
|
2663 // get final progress state... |
|
2664 if (iCurrentOp==EConnectSecondary) |
|
2665 { |
|
2666 iImapSessionManager->Progress(iProgress.iGenericProgress); |
|
2667 } |
|
2668 else |
|
2669 { |
|
2670 iImapCompound->Progress(iProgress); |
|
2671 } |
|
2672 |
|
2673 //... and update reported error code |
|
2674 iProgress.iGenericProgress.iErrorCode=aError; |
|
2675 |
|
2676 // delete the compound operation object |
|
2677 delete iImapCompound; |
|
2678 iImapCompound = NULL; |
|
2679 |
|
2680 // drop the secondary session |
|
2681 DropSession(iForegroundSession); |
|
2682 |
|
2683 // complete the user request with KErrNone.. |
|
2684 Complete(KErrNone); |
|
2685 } |
|
2686 else |
|
2687 { |
|
2688 // DoComplete normally handles the session tidyup, but |
|
2689 // is not called if the error has occurred during a background |
|
2690 // operation, for example ECancelRecoverPrimary |
|
2691 if (iCurrentOp==ECancelRecoverPrimary) |
|
2692 { |
|
2693 // Non-fatal errors should have been handled prior to this. |
|
2694 DisconnectAll(); |
|
2695 |
|
2696 // Save error code in progress and flag the disconnect |
|
2697 // this is defensive as the client should not be watching progress |
|
2698 iProgress.iGenericProgress.iState=TImap4GenericProgress::EDisconnected; |
|
2699 iProgress.iGenericProgress.iErrorCode=aError; |
|
2700 } |
|
2701 Complete(aError); |
|
2702 } |
|
2703 return ETrue; |
|
2704 } |
|
2705 |
|
2706 /** |
|
2707 Translates session error codes for reporting to the Server MTM. |
|
2708 KErrImapNo and KErrImapBad are non-fatal to the session, and |
|
2709 should have been fielded by the compound operation, sync manager |
|
2710 or session manager (during session connect), however they are |
|
2711 translated to KErrNone here. |
|
2712 |
|
2713 All other session errors are fatal to the connection. If an |
|
2714 error occurs on the primary session, all connected sessions |
|
2715 should be disconnected and the client completed. |
|
2716 */ |
|
2717 void CImapProtocolController::ThranslateSessionError(TInt& errCode) |
|
2718 { |
|
2719 if ( errCode == KErrNone |
|
2720 || errCode == KErrImapNo |
|
2721 || errCode == KErrImapBad ) |
|
2722 { |
|
2723 // No and bad should have been handled by the compound |
|
2724 // operation and are non-fatal to the connection. |
|
2725 errCode = KErrNone; |
|
2726 } |
|
2727 else |
|
2728 { |
|
2729 errCode = KErrImapServerFail; |
|
2730 } |
|
2731 } |
|
2732 |
|
2733 /** |
|
2734 Resets the progress object |
|
2735 */ |
|
2736 void CImapProtocolController::ResetProgress() |
|
2737 { |
|
2738 //initialise the TImap4SyncProgress part |
|
2739 iProgress.iSyncProgress.iFoldersToDo = 0; |
|
2740 iProgress.iSyncProgress.iFoldersDone = 0; |
|
2741 iProgress.iSyncProgress.iMsgsToDo = 0; |
|
2742 iProgress.iSyncProgress.iMsgsDone = 0; |
|
2743 iProgress.iSyncProgress.iHeadersFetched = 0; |
|
2744 iProgress.iSyncProgress.iOrphanedFolders = 0; |
|
2745 iProgress.iSyncProgress.iNewFolders = 0; |
|
2746 iProgress.iSyncProgress.iOrphanedMessages = 0; |
|
2747 iProgress.iSyncProgress.iRemoteMessagesDeleteTagged = 0; |
|
2748 iProgress.iSyncProgress.iMessagesFetchedOK = 0; |
|
2749 iProgress.iSyncProgress.iMessagePartsFetchedOK = 0; |
|
2750 iProgress.iSyncProgress.iMessagePartsNotFound = 0; |
|
2751 iProgress.iSyncProgress.iFoldersNotFound = 0; |
|
2752 iProgress.iSyncProgress.iErrorCode = KErrNone; |
|
2753 iProgress.iSyncProgress.iType = EImap4SyncProgressType; |
|
2754 |
|
2755 //initialise the TImap4GenericProgress part |
|
2756 iProgress.iGenericProgress.iMsgsToDo = 0; |
|
2757 iProgress.iGenericProgress.iMsgsDone = 0; |
|
2758 iProgress.iGenericProgress.iPartsToDo = 0; |
|
2759 iProgress.iGenericProgress.iPartsDone = 0; |
|
2760 iProgress.iGenericProgress.iBytesToDo = 0; |
|
2761 iProgress.iGenericProgress.iBytesDone = 0; |
|
2762 iProgress.iGenericProgress.iReturnedMsvId = 0; |
|
2763 iProgress.iGenericProgress.iTotalSize = 0; |
|
2764 iProgress.iGenericProgress.iErrorCode = KErrNone; |
|
2765 iProgress.iGenericProgress.iType = EImap4GenericProgressType; |
|
2766 |
|
2767 } |
|
2768 |
|
2769 /** |
|
2770 Notice that a preferred carrier has become available, and migration to that bearer has been accepted. |
|
2771 The protocol controller shall either pause or allow any current operation to complete |
|
2772 according to the action specified in parameter aAction. Once the current operation |
|
2773 is paused or complete, the protocol controller shall close any existing sockets |
|
2774 and finally notify the mobility framework that it is ready to migrate to the new |
|
2775 carrier. |
|
2776 |
|
2777 @param aAction - indicates the action that should be taken re: current operations |
|
2778 @param aIsSeamless - indicates if the |
|
2779 */ |
|
2780 void CImapProtocolController::PrepareForNewCarrier(TImMobilityAction aAction, TBool /*aIsSeamless*/) |
|
2781 { |
|
2782 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::PrepareForNewCarrier(iMigrateState=%d, aAction = %d)", iMigrateState, aAction)); |
|
2783 // Handle being called in an already-migrating state before handling usual case |
|
2784 if (iMigrateState!=ENotMigrating) |
|
2785 { |
|
2786 switch (iMigrateState) |
|
2787 { |
|
2788 case EDisconnectingForMigrate: |
|
2789 case EWaitingForOpToStop: |
|
2790 { |
|
2791 // Do not allow change from EWaitingForOpToStop to EWaitingForOpToComplete |
|
2792 // but do allow an operation to be stopped suddenly if necessary. |
|
2793 if (aAction==KAcceptImmediately) |
|
2794 { |
|
2795 CarrierLost(); |
|
2796 iMigrateState = EWaitingForNewCarrier; |
|
2797 iMobilityManager->MigrateToNewCarrier(); |
|
2798 |
|
2799 // do not set waiting if NewCarrierActive has been called synchronously. |
|
2800 if (iMigrateState == EWaitingForNewCarrier) |
|
2801 { |
|
2802 // Now in a waiting state, set self active |
|
2803 iStatus = KRequestPending; |
|
2804 SetActive(); |
|
2805 } |
|
2806 } |
|
2807 // else already preparing for new carrier, nothing to do. |
|
2808 return; |
|
2809 } |
|
2810 |
|
2811 case EWaitingForOpToComplete: // async wait on compound op/bground op/idle controller |
|
2812 { |
|
2813 // Allow change from EWaitingForOpToComplete to EWaitingForOpToStop |
|
2814 // also allow an operation to be stopped suddenly if necessary. |
|
2815 if (aAction==KAcceptImmediately) |
|
2816 { |
|
2817 CarrierLost(); |
|
2818 iMigrateState = EWaitingForNewCarrier; |
|
2819 iMobilityManager->MigrateToNewCarrier(); |
|
2820 |
|
2821 // do not set waiting if NewCarrierActive has been called synchronously. |
|
2822 if (iMigrateState == EWaitingForNewCarrier) |
|
2823 { |
|
2824 // Now in a waiting state, set self active |
|
2825 iStatus = KRequestPending; |
|
2826 SetActive(); |
|
2827 } |
|
2828 } |
|
2829 else if (aAction==KAcceptStopCurrent) |
|
2830 { |
|
2831 // change from EWaitingForOpToComplete to EWaitingForOpToStop |
|
2832 StopCurrentForMigrate(); |
|
2833 } |
|
2834 // else already preparing for new carrier, nothing to do. |
|
2835 return; |
|
2836 } |
|
2837 case EHandlingConnectError: |
|
2838 { |
|
2839 // We have a Connect Error, from previous connect attempt |
|
2840 // We are ready to (migrate) reconnect |
|
2841 iMigrateState = EWaitingForNewCarrier; |
|
2842 iMobilityManager->MigrateToNewCarrier(); |
|
2843 |
|
2844 // do not set waiting if NewCarrierActive has been called synchronously. |
|
2845 if (iMigrateState == EWaitingForNewCarrier) |
|
2846 { |
|
2847 // Now in a waiting state, set self active |
|
2848 iStatus = KRequestPending; |
|
2849 SetActive(); |
|
2850 } |
|
2851 break; |
|
2852 } |
|
2853 case EConnectingAfterMigrate: // async wait on session manager |
|
2854 { |
|
2855 // cancelling in this state tidies up the session array, so |
|
2856 // nothing extra to do here - now ready for migration. |
|
2857 Cancel(); |
|
2858 iMigrateState = EWaitingForNewCarrier; |
|
2859 iMobilityManager->MigrateToNewCarrier(); |
|
2860 |
|
2861 // do not set waiting if NewCarrierActive has been called synchronously. |
|
2862 if (iMigrateState == EWaitingForNewCarrier) |
|
2863 { |
|
2864 // Now in a waiting state, set self active |
|
2865 iStatus = KRequestPending; |
|
2866 SetActive(); |
|
2867 } |
|
2868 return; |
|
2869 } |
|
2870 |
|
2871 case EWaitingInitialCarrierRejected: // async wait state on mobility engine |
|
2872 case EWaitingForNewCarrier: // async wait state on mobility engine |
|
2873 case EStartingReconnect: // intermediate state |
|
2874 { |
|
2875 // already ready and waiting for a new carrier - Cancel dummy request |
|
2876 // and tell the Mobility framework we are ready |
|
2877 Cancel(); |
|
2878 iMigrateState = EWaitingForNewCarrier; |
|
2879 iMobilityManager->MigrateToNewCarrier(); |
|
2880 |
|
2881 // do not set waiting if NewCarrierActive has been called synchronously. |
|
2882 if (iMigrateState == EWaitingForNewCarrier) |
|
2883 { |
|
2884 // Now in a waiting state, set self active |
|
2885 iStatus = KRequestPending; |
|
2886 SetActive(); |
|
2887 } |
|
2888 return; |
|
2889 } |
|
2890 case ESuspendingForMigrate: // intermediate state |
|
2891 case ENotMigrating: // already checked this isn't true |
|
2892 default: |
|
2893 { |
|
2894 __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProConPreForNewCarBadMigrateState)); |
|
2895 } |
|
2896 } |
|
2897 } |
|
2898 |
|
2899 // Do the requested action... |
|
2900 switch (aAction) |
|
2901 { |
|
2902 case KAcceptCompleteCurrent: |
|
2903 { |
|
2904 // Any current operation shall be allowed to complete prior |
|
2905 // to indicating that the server MTM is ready to migrate to |
|
2906 // the new bearer. |
|
2907 CompleteCurrentForMigrate(); |
|
2908 break; |
|
2909 } |
|
2910 case KAcceptStopCurrent: |
|
2911 { |
|
2912 // Any current operation shall be allowed to continue until |
|
2913 // such a point that it may be resumed without re-sending or |
|
2914 // re-receiveing a significant amount to data prior to |
|
2915 // indicating that the server MTM is ready to migrate to the |
|
2916 // new bearer. |
|
2917 StopCurrentForMigrate(); |
|
2918 break; |
|
2919 } |
|
2920 case KAcceptImmediately: |
|
2921 default: |
|
2922 { |
|
2923 // accept immediately is an instruction to immediately suspend any |
|
2924 // current operation (cancel any outstanding server communication) |
|
2925 // and close any open sockets. This is the same behaviour as required |
|
2926 // for a downgrade situation. |
|
2927 CarrierLost(); |
|
2928 iMigrateState = EWaitingForNewCarrier; |
|
2929 iMobilityManager->MigrateToNewCarrier(); |
|
2930 |
|
2931 // do not set waiting if NewCarrierActive has been called synchronously. |
|
2932 if (iMigrateState == EWaitingForNewCarrier) |
|
2933 { |
|
2934 // Now in a waiting state, set self active |
|
2935 iStatus = KRequestPending; |
|
2936 SetActive(); |
|
2937 } |
|
2938 break; |
|
2939 } |
|
2940 } // end switch (aAction) |
|
2941 } |
|
2942 |
|
2943 /** |
|
2944 Configures the protocol controller (PC) to allow any current operation in progress |
|
2945 to complete prior to indicating to the mobility framework that it is ready to |
|
2946 migrate to the new carrier. |
|
2947 |
|
2948 Note the protocol controller may be in any of the following states |
|
2949 - IDLE (only one session exists) |
|
2950 - background sync in progress only (only one session exists) |
|
2951 - foreground op in progress only (only one session exists) |
|
2952 - background sync and foreground operation in progress (2 sessions exist) |
|
2953 - background sync in progress and connecting second session for foreground op |
|
2954 |
|
2955 */ |
|
2956 void CImapProtocolController::CompleteCurrentForMigrate() |
|
2957 { |
|
2958 __LOG_TEXT(KDefaultLog, "CImapProtocolController::CompleteCurrentForMigrate()"); |
|
2959 // set the migrating flag |
|
2960 iMigrateState = EWaitingForOpToComplete; |
|
2961 |
|
2962 if (BackgroundSyncInProgress()) |
|
2963 { |
|
2964 // 2-phase background sync is always delayed till after migration |
|
2965 iBackgroundSyncOp->StopForMigrate(); |
|
2966 } |
|
2967 |
|
2968 // If no operation in progress, stop the IDLE |
|
2969 if (iCurrentOp == EIdle && iImapIdleController->IsActive()) |
|
2970 { |
|
2971 iCurrentOp = EStopIdle; |
|
2972 iImapIdleController->StopIdle(iStatus); |
|
2973 SetActive(); |
|
2974 return; |
|
2975 } |
|
2976 |
|
2977 // cancel a secondary session connect |
|
2978 if (iCurrentOp == EConnectSecondary) |
|
2979 { |
|
2980 CancelForMigrate(); |
|
2981 iMigrateState = EWaitingForOpToComplete; |
|
2982 |
|
2983 // defensive: it is possible that the background sync has completed |
|
2984 // while the secondary connect is still in progress. In this case |
|
2985 // neither DoRunL() nor BackgroundSyncComplete() will not be called. |
|
2986 if (!BackgroundSyncInProgress()) |
|
2987 { |
|
2988 // fake a stop-idle op |
|
2989 iCurrentOp = EStopIdle; |
|
2990 SetActive(); |
|
2991 TRequestStatus* status = &iStatus; |
|
2992 User::RequestComplete(status, KErrNone); |
|
2993 } |
|
2994 } |
|
2995 } |
|
2996 |
|
2997 /** |
|
2998 CancelForMigrate() - cancels any outstanding service without deleting the |
|
2999 compound operation or completing the user request. |
|
3000 |
|
3001 This does not cancel a background sync. |
|
3002 |
|
3003 iMigrateState must be set to a new state immediately after calling this. |
|
3004 */ |
|
3005 void CImapProtocolController::CancelForMigrate() |
|
3006 { |
|
3007 iMigrateState = ESuspendingForMigrate; |
|
3008 Cancel(); |
|
3009 } |
|
3010 |
|
3011 /** |
|
3012 */ |
|
3013 void CImapProtocolController::DoCancelForMigrate() |
|
3014 { |
|
3015 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelForMigrate()"); |
|
3016 switch (iCurrentOp) |
|
3017 { |
|
3018 case EConnectSecondary: |
|
3019 { |
|
3020 // Cancel the connect request |
|
3021 iImapSessionManager->Cancel(); |
|
3022 // Remove the session pointer from the array |
|
3023 // The session has already been deleted - see note above. |
|
3024 TInt numSessions = iImapSessionArray.Count(); |
|
3025 iImapSessionArray.Remove(numSessions-1); |
|
3026 break; |
|
3027 } |
|
3028 |
|
3029 case EIdle: |
|
3030 case EStopIdle: |
|
3031 { |
|
3032 // Cancel the IDLE controller. |
|
3033 iImapIdleController->Cancel(); |
|
3034 break; |
|
3035 } |
|
3036 |
|
3037 case ESync: |
|
3038 case ESelect: |
|
3039 case ECopyToLocal: |
|
3040 case ECopyWithinService: |
|
3041 case ECopyFromLocal: |
|
3042 case EMoveToLocal: |
|
3043 case EMoveWithinService: |
|
3044 case EMoveFromLocal: |
|
3045 case EPopulate: |
|
3046 case EDelete: |
|
3047 case EDeleteFolder: |
|
3048 case ECreate: |
|
3049 case ERename: |
|
3050 { |
|
3051 // Cancel the compound operation |
|
3052 iImapCompound->CancelForMigrate(); |
|
3053 break; |
|
3054 } |
|
3055 |
|
3056 case ECancelRecoverPrimary: |
|
3057 { |
|
3058 // Cancel the session recovery. |
|
3059 (iImapSessionArray[0])->Cancel(); |
|
3060 } |
|
3061 |
|
3062 case EConnect: |
|
3063 // case EConnectAndSync: |
|
3064 case EDisconnect: |
|
3065 default: |
|
3066 { |
|
3067 // nothing to do.. |
|
3068 break; |
|
3069 } |
|
3070 |
|
3071 } // end of switch (iCurrentOp) |
|
3072 |
|
3073 // Do NOT call CMsgActive::DoCancel() |
|
3074 // - the client requested operation is not being cancelled |
|
3075 } |
|
3076 |
|
3077 |
|
3078 /** |
|
3079 Configures the protocol controller (PC) to stop any current operation in |
|
3080 progress at the next convenient point - the meaning of this depends on the |
|
3081 specific compound operations. For example, for simple operations such as |
|
3082 creating a folder, this will be when the operation has completed but for |
|
3083 operations for which multiple messages are processed in sequence (eg |
|
3084 fetching several messages), it shall be once the current message has been |
|
3085 processed (eg fetched). At this point the operation shall complete the |
|
3086 protocol controller's iStatus |
|
3087 |
|
3088 Note the protocol controller may be in any of the following states |
|
3089 - IDLE (only one session exists) |
|
3090 - background sync in progress only (only one session exists) |
|
3091 - foreground op in progress only (only one session exists) |
|
3092 - background sync and foreground operation in progress (2 sessions exist) |
|
3093 - background sync in progress and connecting second session for foreground op |
|
3094 |
|
3095 */ |
|
3096 void CImapProtocolController::StopCurrentForMigrate() |
|
3097 { |
|
3098 __LOG_TEXT(KDefaultLog, "CImapProtocolController::StopCurrentForMigrate()"); |
|
3099 // set the migrating flag |
|
3100 iMigrateState = EWaitingForOpToStop; |
|
3101 |
|
3102 if (BackgroundSyncInProgress()) |
|
3103 { |
|
3104 iBackgroundSyncOp->StopForMigrate(); |
|
3105 } |
|
3106 |
|
3107 if (iCurrentOp == EIdle && iImapIdleController->IsActive()) |
|
3108 { |
|
3109 // If no operation in progress, stop the IDLE |
|
3110 iCurrentOp = EStopIdle; |
|
3111 iImapIdleController->StopIdle(iStatus); |
|
3112 SetActive(); |
|
3113 return; |
|
3114 } |
|
3115 else if (iCurrentOp == EConnectSecondary) |
|
3116 { |
|
3117 // cancel a secondary session connect |
|
3118 Cancel(); |
|
3119 |
|
3120 // defensive: it is possible that the background sync has completed |
|
3121 // while the secondary connect is still in progress. In this case |
|
3122 // neither DoRunL() nor BackgroundSyncComplete() will not be called. |
|
3123 if (!BackgroundSyncInProgress()) |
|
3124 { |
|
3125 // fake a stop-idle op |
|
3126 iCurrentOp = EStopIdle; |
|
3127 SetActive(); |
|
3128 TRequestStatus* status = &iStatus; |
|
3129 User::RequestComplete(status, KErrNone); |
|
3130 } |
|
3131 } |
|
3132 else if (iCurrentOp != ECancelRecoverPrimary) |
|
3133 { |
|
3134 // nothing to do for ECancelRecoverPrimary - just wait for the |
|
3135 // session to flush. |
|
3136 // all other operations are told to stop: |
|
3137 iImapCompound->StopForMigrate(); |
|
3138 } |
|
3139 } |
|
3140 |
|
3141 /** |
|
3142 This API is called by the Bearer Mobility Manager. It is typically called in the |
|
3143 case that a downgrade is occuring, and the original sockets are no longer valid |
|
3144 for use. It may also be called if an immediate migration to an preferred bearer is |
|
3145 required, without graceful closing of the original sockets. |
|
3146 |
|
3147 Any operations are cancelled immediately using the CancelForMigrate() API. This |
|
3148 cancels the operations in such a way that they may be restarted following migration |
|
3149 to a new carrier. |
|
3150 */ |
|
3151 void CImapProtocolController::CarrierLost() |
|
3152 { |
|
3153 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::CarrierLost(iMigrateState=%d)", iMigrateState)); |
|
3154 |
|
3155 // Handle being called in an already-migrating state before handling usual case |
|
3156 if (iMigrateState!=ENotMigrating) |
|
3157 { |
|
3158 switch (iMigrateState) |
|
3159 { |
|
3160 case EWaitingForOpToStop: |
|
3161 case EWaitingForOpToComplete: |
|
3162 { |
|
3163 // break to default behaviour |
|
3164 break; |
|
3165 } |
|
3166 |
|
3167 case EStartingReconnect: // intermediate state |
|
3168 case EDisconnectingForMigrate: |
|
3169 case EConnectingAfterMigrate: |
|
3170 { |
|
3171 // cancel the disconnect/connect, then break to default behaviour |
|
3172 // (calling CancelForMigrate() shouldn't do anything as any compound |
|
3173 // operations will not themselves be active) |
|
3174 Cancel(); |
|
3175 break; |
|
3176 } |
|
3177 |
|
3178 case EHandlingConnectError: |
|
3179 { |
|
3180 // empty the session array |
|
3181 TInt numSessions = iImapSessionArray.Count(); |
|
3182 for (TInt i=0; i<numSessions; ++i) |
|
3183 { |
|
3184 if (iImapSessionArray[i]) |
|
3185 { |
|
3186 iImapSessionManager->Disconnect(*(iImapSessionArray[i])); |
|
3187 } |
|
3188 } |
|
3189 iImapSessionArray.ResetAndDestroy(); |
|
3190 |
|
3191 // Set the migration state: |
|
3192 iMigrateState = EWaitingForNewCarrier; |
|
3193 |
|
3194 // Now in an waiting state, set self active |
|
3195 iStatus = KRequestPending; |
|
3196 SetActive(); |
|
3197 return; |
|
3198 } |
|
3199 |
|
3200 case EWaitingInitialCarrierRejected: |
|
3201 case EWaitingForNewCarrier: |
|
3202 { |
|
3203 // already ready and waiting for a new carrier - nothing to do. |
|
3204 return; |
|
3205 } |
|
3206 |
|
3207 case ESuspendingForMigrate: // intermediate state |
|
3208 case ENotMigrating: // normal state |
|
3209 default: |
|
3210 { |
|
3211 __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProConKillCurrentBadMigrateState)); |
|
3212 break; |
|
3213 } |
|
3214 } |
|
3215 } |
|
3216 |
|
3217 |
|
3218 // stop any background operation |
|
3219 if (iBackgroundSyncOp) |
|
3220 { |
|
3221 iBackgroundSyncOp->CancelForMigrate(); |
|
3222 } |
|
3223 |
|
3224 // Cancel foreground operations |
|
3225 CancelForMigrate(); |
|
3226 |
|
3227 // delete the imap idle controller - this will be re-created on reconnect. |
|
3228 delete iImapIdleController; |
|
3229 iImapIdleController=NULL; |
|
3230 |
|
3231 // Drop connection on each of the imap sessions |
|
3232 TInt numSessions = iImapSessionArray.Count(); |
|
3233 for (TInt i=0; i<numSessions; ++i) |
|
3234 { |
|
3235 if (iImapSessionArray[i]) |
|
3236 { |
|
3237 iImapSessionManager->Disconnect(*(iImapSessionArray[i])); |
|
3238 } |
|
3239 } |
|
3240 |
|
3241 // empty the session array |
|
3242 iImapSessionArray.ResetAndDestroy(); |
|
3243 |
|
3244 // Set the migration state: |
|
3245 iMigrateState = EWaitingForNewCarrier; |
|
3246 |
|
3247 // Now in an waiting state, set self active |
|
3248 iStatus = KRequestPending; |
|
3249 SetActive(); |
|
3250 } |
|
3251 |
|
3252 /** |
|
3253 Called to indicate the migration has completed and the RConnection is ready to |
|
3254 provide new sockets via the new bearer. |
|
3255 |
|
3256 Initiates the creation of a new IMAP session, following which any suspended |
|
3257 operation shall be restarted. |
|
3258 */ |
|
3259 void CImapProtocolController::NewCarrierActive(TAccessPointInfo /*aNewAp*/, TBool /*aIsSeamless*/) |
|
3260 { |
|
3261 __LOG_TEXT(KDefaultLog, "CImapProtocolController::NewCarrierActive()"); |
|
3262 __ASSERT_DEBUG((iMigrateState == EWaitingForNewCarrier || iMigrateState == EWaitingInitialCarrierRejected), |
|
3263 TImapServerPanic::ImapPanic(TImapServerPanic::ENewCarrierActiveUnexpectedMigrateState)); |
|
3264 |
|
3265 // Cancel the dummy active state |
|
3266 Cancel(); |
|
3267 |
|
3268 // set the new migration state |
|
3269 iMigrateState = EStartingReconnect; |
|
3270 |
|
3271 // complete self - this requires some memory allocation, do it within the RunL. |
|
3272 TRequestStatus* status = &iStatus; |
|
3273 User::RequestComplete(status, KErrNone); |
|
3274 SetActive(); |
|
3275 } |
|
3276 |
|
3277 |
|
3278 void CImapProtocolController::NewPrimarySessionL() |
|
3279 { |
|
3280 // Create the primary session pointer |
|
3281 CImapSession* imapSession = NULL; |
|
3282 iImapSessionArray.AppendL(imapSession); |
|
3283 |
|
3284 // Request the session manager to connect the session |
|
3285 iImapSessionManager->GetSessionL(iStatus, iImapSessionArray[0]); |
|
3286 iMigrateState = EConnectingAfterMigrate; |
|
3287 |
|
3288 SetActive(); |
|
3289 } |
|
3290 |
|
3291 /** |
|
3292 Indicates that the RConnection is no longer valid. |
|
3293 Therefore disconnect and mark the service as offline. |
|
3294 */ |
|
3295 #ifdef __IMAP_LOGGING |
|
3296 void CImapProtocolController::MobilityError(TUint aError) |
|
3297 #else //__IMAP_LOGGING |
|
3298 void CImapProtocolController::MobilityError(TUint /*aError*/) |
|
3299 #endif //__IMAP_LOGGING |
|
3300 { |
|
3301 __LOG_FORMAT((KDefaultLog, "CImapProtocolController::MobilityError(iMigrateState=%d, aError=%d)", iMigrateState, aError)); |
|
3302 |
|
3303 // Cancel any async request |
|
3304 Cancel(); |
|
3305 |
|
3306 if (iRequestedOp != EIdle) |
|
3307 { |
|
3308 // Complete the user request - calls DisconnectAll() |
|
3309 Complete(KErrDisconnected); |
|
3310 } |
|
3311 else |
|
3312 { |
|
3313 // Disconnect all sessions and mark the service as offline |
|
3314 DisconnectAll(); |
|
3315 } |
|
3316 |
|
3317 // the RConnection is no longer valid - delete the session manager |
|
3318 // (will be recreated on ConnectL()) |
|
3319 delete iImapSessionManager; |
|
3320 iImapSessionManager = NULL; |
|
3321 |
|
3322 // no longer migrating... |
|
3323 iMigrateState = ENotMigrating; |
|
3324 |
|
3325 // Save error code in progress and flag the disconnect |
|
3326 // this is defensive as the client should not be watching progress |
|
3327 iProgress.iGenericProgress.iState=TImap4GenericProgress::EDisconnected; |
|
3328 iProgress.iGenericProgress.iErrorCode=KErrDisconnected; |
|
3329 } |
|
3330 |
|
3331 void CImapProtocolController::ProcessOpCompleteForMigrate() |
|
3332 { |
|
3333 // Any tidying up to do for the current user-requested operation |
|
3334 switch (iCurrentOp) |
|
3335 { |
|
3336 case ECancelRecoverPrimary: |
|
3337 case EIdle: |
|
3338 case EStopIdle: |
|
3339 { |
|
3340 // engine was IDLE or recovering from a cancel when the |
|
3341 // migrate notice arrived... nothing to do before disconnecting. |
|
3342 break; |
|
3343 } |
|
3344 |
|
3345 case ESync: |
|
3346 case ESelect: |
|
3347 case ECopyToLocal: |
|
3348 case ECopyWithinService: |
|
3349 case ECopyFromLocal: |
|
3350 case EMoveToLocal: |
|
3351 case EMoveWithinService: |
|
3352 case EMoveFromLocal: |
|
3353 case EPopulate: |
|
3354 case EDelete: |
|
3355 case EDeleteFolder: |
|
3356 case ECreate: |
|
3357 case ERename: |
|
3358 { |
|
3359 // update last operation progress state |
|
3360 iImapCompound->Progress(iProgress); |
|
3361 |
|
3362 // if the user requested operation has finished, |
|
3363 // tidyup and inform the client |
|
3364 if (iProgress.iGenericProgress.iState == TImap4GenericProgress::EIdle) |
|
3365 { |
|
3366 delete iImapCompound; |
|
3367 iImapCompound = NULL; |
|
3368 |
|
3369 // Complete the server mtm request. |
|
3370 Complete(iStatus.Int()); |
|
3371 } |
|
3372 break; |
|
3373 } |
|
3374 |
|
3375 case EConnect: |
|
3376 case EDisconnect: |
|
3377 case EConnectSecondary: |
|
3378 default: |
|
3379 { |
|
3380 __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProcessOpCompleteForMigrateUnexpectedState)); |
|
3381 } |
|
3382 } // end of switch (iCurrentOp) |
|
3383 } |
|
3384 |
|
3385 /** |
|
3386 Logs out and disconnects all connected sessions with the remote server. |
|
3387 */ |
|
3388 void CImapProtocolController::DisconnectForMigrateL() |
|
3389 { |
|
3390 __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectForMigrateL()"); |
|
3391 __ASSERT_DEBUG(iMigrateCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EMigrateCompoundIsNotNull)); |
|
3392 |
|
3393 // Background operations will have been taken care of already - just disconnect. |
|
3394 // Do not perform the late-delete offline operations. |
|
3395 delete iMigrateCompound; |
|
3396 iMigrateCompound = NULL; |
|
3397 |
|
3398 iMigrateCompound = CImapCompoundDisconnect::NewL( *iImapSyncManager, |
|
3399 iEntry, |
|
3400 *iImapSettings, |
|
3401 *iImapSessionManager, |
|
3402 *iImapMailStore, |
|
3403 iImapSessionArray, |
|
3404 iImapOfflineControl, |
|
3405 EFalse ); |
|
3406 |
|
3407 iMigrateState = EDisconnectingForMigrate; |
|
3408 iMigrateCompound->StartOperation(iStatus, *iImapSessionArray[0]); |
|
3409 SetActive(); |
|
3410 } |
|
3411 |
|
3412 |
|
3413 /** |
|
3414 Resumes operations that were stopped to allow migration to occur, |
|
3415 or operations that were requested while migration was in progress. |
|
3416 */ |
|
3417 void CImapProtocolController::RestartAfterMigrateL() |
|
3418 { |
|
3419 __LOG_TEXT(KDefaultLog, "CImapProtocolController::RestartAfterMigrateL()"); |
|
3420 |
|
3421 // The migration has completed. Restart anything that was going on |
|
3422 // before the migration started, or has been requested in the meantime. |
|
3423 iMigrateState = ENotMigrating; |
|
3424 |
|
3425 // was the initial carrier rejected during the connect operation? |
|
3426 // if so, mark as online and get the final connection progress info. |
|
3427 if (iCurrentOp == EConnect) |
|
3428 { |
|
3429 TRAP_IGNORE(MarkOnOrOfflineL(ETrue)); |
|
3430 |
|
3431 // Collect the final connect progress information |
|
3432 iImapSessionManager->Progress(iProgress.iGenericProgress); |
|
3433 |
|
3434 // Set last socket activity timeout to iMtmData1. This is used by Imcm. |
|
3435 User::LeaveIfError( iEntry.SetEntry( iServiceId ) ); |
|
3436 TMsvEntry entry=iEntry.Entry(); |
|
3437 entry.SetMtmData1(iImapSessionManager->LastSocketActivityTimeout()); |
|
3438 User::LeaveIfError( iEntry.ChangeEntry( entry ) ); |
|
3439 |
|
3440 // complete the connect request |
|
3441 Complete(iStatus.Int()); |
|
3442 } |
|
3443 |
|
3444 // Create a new IDLE controller - the old one was deleted. |
|
3445 delete iImapIdleController; |
|
3446 iImapIdleController=NULL; |
|
3447 iImapIdleController = CImapIdleController::NewL(*this, iImapSessionArray[0], *iImapSyncManager, iEntry, *iImapSettings, *iImapMailStore); |
|
3448 |
|
3449 // was there a background sync in progress prior to migration? |
|
3450 if (iBackgroundSyncOp) |
|
3451 { |
|
3452 // restart any background operation, using the new primary session. |
|
3453 iBackgroundSyncOp->ResumeOperationL(*iImapSessionArray[0]); |
|
3454 |
|
3455 // was there a forground operation paused as well? |
|
3456 if (iImapCompound) |
|
3457 { |
|
3458 // Create a second connected session. |
|
3459 iCurrentOp = EConnectSecondary; |
|
3460 // iRequestedOp should not have been changed... |
|
3461 CImapSession* imapSession = NULL; |
|
3462 iImapSessionArray.AppendL(imapSession); |
|
3463 TInt sessionCount = iImapSessionArray.Count(); |
|
3464 iImapSessionManager->GetSessionL(iStatus, iImapSessionArray[sessionCount-1]); |
|
3465 SetActive(); |
|
3466 } |
|
3467 else |
|
3468 { |
|
3469 iCurrentOp = EIdle; |
|
3470 } |
|
3471 return; |
|
3472 } |
|
3473 |
|
3474 if (iImapCompound) |
|
3475 { |
|
3476 // Idle has not been restarted after the migration, so the requested |
|
3477 // operation can be re-started without calling StopIdle() |
|
3478 // resume the suspended operation |
|
3479 iCurrentOp = iRequestedOp; |
|
3480 iImapCompound->ResumeOperationL(iStatus, *iImapSessionArray[0]); |
|
3481 SetActive(); |
|
3482 } |
|
3483 else |
|
3484 { |
|
3485 // otherwise just start Idle |
|
3486 iCurrentOp = EIdle; |
|
3487 iRequestedOp = EIdle; |
|
3488 StartIdle(); |
|
3489 } |
|
3490 } |
|
3491 |
|
3492 /** |
|
3493 Returns a packaged copy of the current progress for passing to the |
|
3494 mobility policy plugin when a preferred carrier available notice |
|
3495 is received. |
|
3496 */ |
|
3497 const TDesC8& CImapProtocolController::MobilityProgress() |
|
3498 { |
|
3499 Progress(); |
|
3500 iProgressBuffer = TImap4ProgressBuf(iProgress); |
|
3501 return iProgressBuffer; |
|
3502 } |
|
3503 /** |
|
3504 Updates the specified messages read/unread status from the remote server. |
|
3505 @param aStatus |
|
3506 */ |
|
3507 EXPORT_C void CImapProtocolController::UpdateFlagL( TRequestStatus& aStatus) |
|
3508 |
|
3509 { |
|
3510 __LOG_TEXT(KDefaultLog, "CImapProtocolController::UpdateFlagL()"); |
|
3511 __ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundIsNotNull)); |
|
3512 ResetProgress(); |
|
3513 if (!CompleteIfBackgroundOpInProgress(aStatus)) |
|
3514 { |
|
3515 iImapCompound = CImapUpdateFlagOperation::NewL(*iImapSyncManager, |
|
3516 iEntry, |
|
3517 *iImapSettings |
|
3518 ); |
|
3519 iRequestedOp = EUpdateFlag; |
|
3520 StartPrimaryOperation(); |
|
3521 Queue(aStatus); |
|
3522 SetActive(); |
|
3523 } |
|
3524 } |
|
3525 |
|
3526 |