email/pop3andsmtpmtm/popservermtm/src/POPSMTM.CPP
changeset 0 72b543305e3a
child 26 ebe688cedc25
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #define _MSVAPI_DONT_INCLUDE_FLOGGER_
       
    17 
       
    18 #include <e32std.h>
       
    19 
       
    20 #include "POPSMTM.H"
       
    21 
       
    22 #include "POPSMBX.H"
       
    23 #include "POPS.H"
       
    24 #include "POPSOFFL.H"
       
    25 #include <iapprefs.h>
       
    26 // panics
       
    27 #include "POPS.PAN"
       
    28 
       
    29 #include <pop3set.h>
       
    30 #include <miutset.h>	// internet mail settings
       
    31 #include <miuthdr.h>
       
    32 #include <offop.h>
       
    33 #include <commdb.h>
       
    34 #include <pop3cmds.h>
       
    35 #include <imcvutil.h>
       
    36 #include <cemailaccounts.h>
       
    37 #include <tmsvsystemprogress.h>
       
    38 
       
    39 #include "msventry.h"	// CMsvServerEntry
       
    40 #include "POPSMTM.H"
       
    41 #include "POPS.H"
       
    42 #include "POPSOFFL.H"
       
    43 #include "iapprefs.h"
       
    44 #include "PopsDele.h"
       
    45 #include "POPSRFSH.h"
       
    46 #include "PopsCpMv.h"
       
    47 #include "PopsTopPop.h"
       
    48 #include "cpopsessionmanager.h"
       
    49 #include "imutcon.h"
       
    50 #include "cimmobilitymanager.h"
       
    51 #include "mobilitytestmtmapi.h"
       
    52 
       
    53 const TUid KUidPop3ServerMtm = {0x10003C77};
       
    54 
       
    55 #if (defined SYMBIAN_USER_PROMPT_SERVICE) 
       
    56 #include "cpopupsresponsewaiter.h"
       
    57 #endif
       
    58 
       
    59 //
       
    60 // factory function
       
    61 //
       
    62 EXPORT_C CImppServerMtm* CImppServerMtm::NewL(CRegisteredMtmDll& aPopServerMtmDll,
       
    63 											  CMsvServerEntry* aEntry) 
       
    64 	{
       
    65 	CImppServerMtm* popServerMtm=new CImppServerMtm(aPopServerMtmDll, aEntry);
       
    66 	if (popServerMtm==NULL)
       
    67 		{
       
    68 		aPopServerMtmDll.ReleaseLibrary();
       
    69 		User::Leave(KErrNoMemory);
       
    70 		}
       
    71 	CleanupStack::PushL(popServerMtm);
       
    72 	popServerMtm->ConstructL();
       
    73 	CleanupStack::Pop();
       
    74 	return popServerMtm;
       
    75 	}
       
    76 
       
    77 
       
    78 	//
       
    79 void CImppServerMtm::CopyFromLocalL(const CMsvEntrySelection& /*aSelection*/, TMsvId/* aDestination*/, TRequestStatus& /*aStatus*/)
       
    80 	{
       
    81 	User::Leave(KErrNotSupported);
       
    82 	}
       
    83 
       
    84 //
       
    85 // IMPPCPMV
       
    86 //
       
    87 void CImppServerMtm::CopyToLocalL(const CMsvEntrySelection& aSelection,
       
    88                                   TMsvId aDestination,
       
    89                                   TRequestStatus& aStatus)
       
    90 	{
       
    91 	if (AcceptingOfflineOperationsL(aSelection))
       
    92 		{
       
    93 		AddOfflineOperationL(aSelection, aDestination, CImOffLineOperation::EOffLineOpCopyToLocal, aStatus);
       
    94 		}
       
    95 	else if (iMigrationState!=ENotMigrating && !iState.iRunningOfflineOperations)
       
    96 		{
       
    97 		// do not accept new operations if currently migrating
       
    98 		User::Leave(KErrServerBusy);
       
    99 		}
       
   100 	else
       
   101 		{
       
   102 		DoCopyMoveL( aSelection, aDestination, aStatus, EImppCopy);
       
   103 		}
       
   104 	}
       
   105 
       
   106 void CImppServerMtm::MoveToLocalL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)
       
   107 	{
       
   108 	if (AcceptingOfflineOperationsL(aSelection))
       
   109 		{
       
   110 		AddOfflineOperationL(aSelection, aDestination, CImOffLineOperation::EOffLineOpMoveToLocal, aStatus);
       
   111 		}
       
   112 	else if (iMigrationState!=ENotMigrating && !iState.iRunningOfflineOperations)
       
   113 		{
       
   114 		// do not accept new operations if currently migrating
       
   115 		User::Leave(KErrServerBusy);
       
   116 		}
       
   117 	else
       
   118 		{
       
   119 		DoCopyMoveL( aSelection, aDestination, aStatus, EImppMove);
       
   120 		}
       
   121 	}
       
   122 
       
   123 //
       
   124 // IMPPDELE
       
   125 //
       
   126 void CImppServerMtm::DeleteAllL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
   127 	{
       
   128 	if (iMigrationState!=ENotMigrating && !iState.iRunningOfflineOperations)
       
   129 		{
       
   130 		// do not accept new operations if currently migrating
       
   131 		User::Leave(KErrServerBusy);
       
   132 		}
       
   133 		
       
   134 	if (PruneMessages(aSelection, aStatus))
       
   135 		{
       
   136 		// Was this call to DeleteAllL an instruction to delete local parts of a message ?
       
   137 		// If so then we don't need to continue.
       
   138 		return;
       
   139 		}
       
   140 	
       
   141 	if (iPopSettings == 0)
       
   142 		{
       
   143 		GetPopDetailsL(aSelection);
       
   144 		}
       
   145 
       
   146 
       
   147 	if ((iPopSettings->DisconnectedUserMode()) && (!iState.iQuitting))
       
   148 		// If we are in disconnected mode (although not necessarily disconnected)
       
   149 		// and we are not quitting then add the delete as an offline operation.
       
   150 		{
       
   151 		AddOfflineOperationL(aSelection, 0, CImOffLineOperation::EOffLineOpDelete, aStatus);
       
   152 		}
       
   153 	else
       
   154 		// If we are not in disconnected mode or we are quitting then do the delete now.
       
   155 		{
       
   156 		__ASSERT_DEBUG(iConnectedToPopMbox, Panic(EPopNotConnectedToMbox));
       
   157 		
       
   158 		if(iConnectedToPopMbox==EFalse)
       
   159 			{
       
   160 			TRAP_IGNORE( DoShowMessagesL( EFalse ) );
       
   161 			User::Leave(KErrDisconnected);
       
   162 			}
       
   163 		__ASSERT_DEBUG(iState.iCurrentOperation==EPopConnectedAndIdle,Panic(EImppAlreadyActive));
       
   164 		
       
   165 		if(iState.iCurrentOperation!=EPopConnectedAndIdle)
       
   166 			{
       
   167 			User::Leave(KErrInUse);
       
   168 			}
       
   169 
       
   170 		iReportStatus=&aStatus;
       
   171 		Cancel();
       
   172 		ResetProgress();
       
   173 
       
   174 		__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
   175 		// make sure iServerEntry is set to the service entry
       
   176 		User::LeaveIfError(iServerEntry->SetEntry(iServiceId));
       
   177 
       
   178 		CMsvEntrySelection* sel=StripInvalidEntriesLC(aSelection);
       
   179 		// set selected entries invisible (hopefully so they wont be selected twice)
       
   180 		TInt err=iServerEntry->ChangeAttributes( *sel, 0, KMsvVisibilityAttribute);
       
   181 		if (err)
       
   182 			{
       
   183 			iServerEntry->ChangeAttributes( *sel,KMsvVisibilityAttribute,0);
       
   184 			User::Leave(err);
       
   185 			}
       
   186 		delete iPopDelete;
       
   187 		iPopDelete=NULL;
       
   188 		iPopDelete=CImPop3Delete::NewL(*iServerEntry,*sel,iPopSession, iServiceId);
       
   189 		CleanupStack::PopAndDestroy(); //sel
       
   190 		iPopDelete->Start(iStatus);
       
   191 		SetActive();
       
   192 		aStatus = KRequestPending;
       
   193 		iOperationActive=ETrue;
       
   194 		iState.iCurrentOperation=EPopDeleting;
       
   195 		}
       
   196 	}
       
   197 
       
   198 void CImppServerMtm::CopyWithinServiceL(const CMsvEntrySelection& aSelection,TMsvId aDestination, TRequestStatus& aStatus)
       
   199 	{
       
   200 	if (aDestination == iServiceId)
       
   201 		// If the service id is given as the destination then the message selection is populated.
       
   202 		{
       
   203 		if (AcceptingOfflineOperationsL(aSelection))
       
   204 			{
       
   205 			AddOfflineOperationL(aSelection, aDestination, CImOffLineOperation::EOffLineOpCopyWithinService, aStatus);
       
   206 			}
       
   207 		else if (iMigrationState!=ENotMigrating && !iState.iRunningOfflineOperations)
       
   208 			{
       
   209 			// do not accept new operations if currently migrating
       
   210 			User::Leave(KErrServerBusy);
       
   211 			}
       
   212 		else
       
   213 			{
       
   214 			DoCopyMoveL( aSelection, 0 /*ignored when populating*/, aStatus, EImppPopulate);	
       
   215 			}
       
   216 		}
       
   217 	else
       
   218 		{
       
   219 		User::Leave(KErrNotSupported);	
       
   220 		}
       
   221 	}
       
   222 
       
   223 void CImppServerMtm::CreateL(TMsvEntry/* aNewEntry*/, TRequestStatus& /*aStatus*/)
       
   224 	{
       
   225 	User::Leave(KErrNotSupported);
       
   226 	}
       
   227 
       
   228 void CImppServerMtm::ChangeL(TMsvEntry aNewEntry, TRequestStatus& aStatus)
       
   229 	{
       
   230 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
   231 	User::LeaveIfError(iServerEntry->SetEntry( aNewEntry.Id() ));
       
   232 	User::LeaveIfError(iServerEntry->ChangeEntry( aNewEntry ));
       
   233 	
       
   234 	TRequestStatus* status = &aStatus;
       
   235 	User::RequestComplete(status, KErrNone);
       
   236 	}
       
   237 
       
   238 void CImppServerMtm::MoveFromLocalL(const CMsvEntrySelection& /*aSelection*/,TMsvId /*aDestination*/, TRequestStatus& /*aStatus*/)
       
   239 	{
       
   240 	User::Leave(KErrNotSupported);
       
   241 	}
       
   242 
       
   243 void CImppServerMtm::MoveWithinServiceL(const CMsvEntrySelection& /*aSelection*/,TMsvId /*aDestination*/, TRequestStatus& /*aStatus*/)
       
   244 	{
       
   245 	User::Leave(KErrNotSupported);
       
   246 	}
       
   247 
       
   248 //
       
   249 // Connect and refresh mailbox or quit 
       
   250 //
       
   251 void CImppServerMtm::StartCommandL(CMsvEntrySelection& aSelection, TInt aCommand, const TDesC8& aParameter, TRequestStatus& aStatus)
       
   252 	{
       
   253 
       
   254 	if (iMigrationState!=ENotMigrating && aCommand!=KPOP3MTMDisconnect && !iState.iRunningOfflineOperations)
       
   255 		{
       
   256 		// do not accept new operations (except disconnect) if currently migrating
       
   257 		User::Leave(KErrServerBusy);
       
   258 		}
       
   259 		
       
   260 	switch(aCommand)
       
   261 		{
       
   262 	case KPOP3MTMConnect: // KPop3MtmConnectUID
       
   263 		DoConnectL(aStatus, aSelection);
       
   264 		MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopConnecting);
       
   265 		break;
       
   266 	case KPOP3MTMDisconnect:
       
   267 		DoQuitL(aStatus);
       
   268 		break;
       
   269 	case KPOP3MTMCancelOfflineOperations:
       
   270 		if (iPopSettings == 0)
       
   271 			{
       
   272 			GetPopDetailsL(aSelection);
       
   273 			}
       
   274 		MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopCancellingOfflineOps);
       
   275 		CancelOfflineOperationsL(aSelection, aStatus);
       
   276 		break;
       
   277 	case KPOP3MTMPopulate:
       
   278 		{
       
   279 		GetPopDetailsL(aSelection);
       
   280 		// unpackage the destination from aParameter
       
   281 		TImPop3PopulateOptions info;
       
   282 		TImPop3PopulateOptions::UnpackL(aParameter,info);			
       
   283 		DoTopPopulateL(aSelection,info.PopulationLimit(),aStatus);
       
   284 		}
       
   285 		break;
       
   286 
       
   287 	case KPOP3MTMIsConnected:
       
   288 	default:
       
   289 		User::Leave(KErrNotSupported);
       
   290 		break;
       
   291 		}
       
   292 	}
       
   293 
       
   294 //
       
   295 //
       
   296 //
       
   297 void CImppServerMtm::DoConnectL(TRequestStatus& aStatus, CMsvEntrySelection& aSelection)
       
   298 	{
       
   299 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
   300 	if(IsActive())
       
   301 		{
       
   302 		User::Leave(KErrPop3ServerAlreadyConnected);
       
   303 		}
       
   304 	iNotConnectToPopMailBox = EFalse ;	
       
   305 	// set this here so progress can be set
       
   306 #if (defined SYMBIAN_USER_PROMPT_SERVICE) 	
       
   307 	iState.iCurrentOperation = EPopAuthoriseAndConnect;
       
   308 #else
       
   309 	iState.iCurrentOperation = EPopConnecting;
       
   310 #endif	
       
   311 	ResetProgress();
       
   312 	// POP3 settings
       
   313 	// attempt to open POP3 service settings leave if we cant
       
   314 	GetPopDetailsL(aSelection);
       
   315 
       
   316 	delete iMessagesToKeep;
       
   317 	iMessagesToKeep = NULL;
       
   318 	iMessagesToKeep = aSelection.CopyL();
       
   319 	
       
   320 	iReportStatus=&aStatus;
       
   321 
       
   322 	// Clear the new attribute on all entries if we are connecting
       
   323 	User::LeaveIfError(iServerEntry->SetEntry(iServiceId));
       
   324 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
   325 	CleanupStack::PushL(selection);
       
   326 	User::LeaveIfError(iServerEntry->GetChildren(*selection));  
       
   327 	User::LeaveIfError(iServerEntry->ChangeAttributes(*selection, 0, KMsvNewAttribute));
       
   328 	CleanupStack::PopAndDestroy(); // selection
       
   329 
       
   330 	// create session manager
       
   331 	if (!iSessionManager)
       
   332 		{
       
   333 		iSessionManager = CPopSessionManager::NewL();
       
   334 		}
       
   335 
       
   336 #if (defined SYMBIAN_USER_PROMPT_SERVICE) 	
       
   337 	// Connect to UPS server and check if connection to remote server is permitted.
       
   338 	iWaiter->AuthoriseAndConnectL(iPopSettings, iClientThreadId, iHasCapability, iStatus);
       
   339 #else
       
   340 	// obtain a connected pop session
       
   341 	iSessionManager->GetSessionL(*iPopSettings, *iIAPPreferences, iPopSession, iStatus);
       
   342 #endif
       
   343 	iOperationActive=ETrue;
       
   344 	SetActive();
       
   345 	aStatus = KRequestPending;
       
   346 	}
       
   347 
       
   348 
       
   349 void CImppServerMtm::ResetProgress()
       
   350 	{
       
   351 	iPopProgress.iTotalMsgs=0;
       
   352 	iPopProgress.iMsgsToProcess=0;
       
   353 	iPopProgress.iBytesDone=0;
       
   354 	iPopProgress.iTotalBytes=0;
       
   355 	iPopProgress.iErrorCode=KErrNone;
       
   356 
       
   357 	iPopProgressBuf.Zero();
       
   358 	}
       
   359 
       
   360 // utlity method - check state of mailbox and make sure it's raeady
       
   361 void CImppServerMtm::CheckMailboxStateL()
       
   362 	{
       
   363 	__ASSERT_DEBUG(iConnectedToPopMbox, Panic(EPopNotConnectedToMbox));
       
   364 	if(!iConnectedToPopMbox)
       
   365 		{
       
   366 		TRAP_IGNORE( DoShowMessagesL( EFalse ) );
       
   367 		User::Leave(KErrDisconnected);
       
   368 		}
       
   369 	__ASSERT_DEBUG(iState.iCurrentOperation==EPopConnectedAndIdle,Panic(EImppAlreadyActive));
       
   370 	if(iState.iCurrentOperation!=EPopConnectedAndIdle)
       
   371 		{
       
   372 		User::Leave(KErrInUse);
       
   373 		}
       
   374 	}
       
   375 
       
   376 
       
   377 //
       
   378 // Do the refresh
       
   379 //
       
   380 void CImppServerMtm::DoRefreshL()
       
   381 	{
       
   382 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
   383 	ResetProgress();
       
   384 	delete iMsvIdArray;
       
   385 	iMsvIdArray=NULL;
       
   386 	iMsvIdArray=new(ELeave)CArrayFixFlat<TMsvId>(8);
       
   387 	// context of entry should be set to service entry
       
   388 	User::LeaveIfError(iServerEntry->SetEntry(iServiceId));
       
   389 	delete iPopRefreshMailbox;
       
   390 	iPopRefreshMailbox=NULL;
       
   391 	iPopRefreshMailbox = CImPop3RefreshMailBox::NewL(*iServerEntry, *iPopSession, iServerEntry->FileSession());
       
   392 	iPopRefreshMailbox->SetMessagesToKeepL(iMessagesToKeep);
       
   393 	iPopRefreshMailbox->Start(iStatus,iMsvIdArray);
       
   394 	iOperationActive=ETrue;
       
   395 	SetActive();
       
   396 	iState.iCurrentOperation=EPopRefreshing;
       
   397 	MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopRefreshing);
       
   398 	}
       
   399 
       
   400 void CImppServerMtm::DoCopyMoveL(const CMsvEntrySelection& aSelection, TMsvId aDestination, TRequestStatus& aStatus, TImppCopyMethod aCopyMethod)
       
   401 	{
       
   402 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
   403 	CheckMailboxStateL();
       
   404 	
       
   405 	Cancel();
       
   406 	iReportStatus=&aStatus;
       
   407 	ResetProgress();
       
   408 
       
   409 	User::LeaveIfError(iServerEntry->SetEntry(iServiceId));
       
   410 	CMsvEntrySelection* sel=StripInvalidEntriesLC(aSelection);
       
   411 
       
   412 
       
   413 	if( aCopyMethod == EImppMove)
       
   414 		{
       
   415 		// set selected entries invisible (hopefully so they wont be selected twice)
       
   416 		TInt err=iServerEntry->ChangeAttributes(*sel, 0, KMsvVisibilityAttribute);
       
   417 		if (err)
       
   418 			{
       
   419 			iServerEntry->ChangeAttributes(*sel,KMsvVisibilityAttribute,0);
       
   420 			User::Leave(err);
       
   421 			}
       
   422 		}
       
   423 	delete iPopCopyMove;
       
   424 	iPopCopyMove=NULL;
       
   425 
       
   426 	if (aCopyMethod == EImppPopulate)
       
   427 		{
       
   428 		iPopCopyMove = CImPop3CopyMove::NewL(*sel,*iServerEntry,iPopSession,ETrue,iServerEntry->FileSession(), iLogMessage, iPopSettings->DisconnectedUserMode());
       
   429 		}
       
   430 	else
       
   431 		{
       
   432 		iPopCopyMove = CImPop3CopyMove::NewL(*sel,*iServerEntry,iPopSession,(aCopyMethod == EImppCopy),iServerEntry->FileSession(),aDestination, iLogMessage, iPopSettings->DisconnectedUserMode());
       
   433 		}
       
   434 
       
   435 	CleanupStack::PopAndDestroy(); //sel
       
   436 	
       
   437 	switch (aCopyMethod)
       
   438 		{
       
   439 		case EImppCopy:
       
   440 			iState.iCurrentOperation = EPopCopying;
       
   441 			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopCopying);
       
   442 			break;
       
   443 		case EImppMove:
       
   444 			iState.iCurrentOperation = EPopMoving;
       
   445 			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopMoving);
       
   446 			break;
       
   447 		case EImppPopulate:
       
   448 			iState.iCurrentOperation = EPopPopulating;
       
   449 			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopPopulating);
       
   450 			break;
       
   451 		default:
       
   452 			User::Leave(KErrNotSupported);
       
   453 			break;
       
   454 		};
       
   455 
       
   456 	iPopCopyMove->StartL(iStatus);
       
   457 
       
   458 	SetActive();
       
   459 	aStatus = KRequestPending;
       
   460 	iOperationActive = ETrue;
       
   461 	}
       
   462 
       
   463 void CImppServerMtm::DoTopPopulateL(const CMsvEntrySelection& aSelection, TInt aLimit, TRequestStatus& aStatus)
       
   464 	{
       
   465 	// Deletion of service entry from entrySelection which is added at client
       
   466 	CMsvEntrySelection* sel=StripInvalidEntriesLC(aSelection);
       
   467 	if(sel->At(0) == iServiceId)
       
   468 		{
       
   469 		sel->Delete(0);
       
   470 		}
       
   471 		
       
   472 	if ( aLimit==KErrNotFound )
       
   473 		{
       
   474 		// A full populate is required
       
   475 		DoCopyMoveL(*sel,sel->At(0),aStatus,EImppPopulate);
       
   476 		CleanupStack::PopAndDestroy(sel);
       
   477 		return;
       
   478 		}
       
   479 
       
   480 	CheckMailboxStateL();
       
   481 
       
   482 	Cancel();
       
   483 	iReportStatus=&aStatus;
       
   484 	ResetProgress();
       
   485 
       
   486 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
   487 	User::LeaveIfError(iServerEntry->SetEntry(iServiceId));
       
   488 
       
   489 	RArray<TUint> sizes;
       
   490 	CleanupClosePushL(sizes);
       
   491 
       
   492 	TInt count=sel->Count();
       
   493 	
       
   494 	for(TInt i=0;i<count;i++)
       
   495 		{
       
   496 		User::LeaveIfError(sizes.Append(iPopRefreshMailbox->RemoteMessageSizeL(sel->At(i))));
       
   497 		}
       
   498 
       
   499 	delete iPopTopPop;
       
   500 	iPopTopPop=NULL;
       
   501 
       
   502 	iPopTopPop = CImPop3TopPopulate::NewL(*sel,*iServerEntry,aLimit,iPopSession,iServerEntry->FileSession(), iLogMessage, iPopSettings->DisconnectedUserMode(),sizes);
       
   503 	CleanupStack::Pop(&sizes);
       
   504 
       
   505 	CleanupStack::PopAndDestroy(sel);
       
   506 	iState.iCurrentOperation = EPopTopPopulating;
       
   507 	MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopTopPopulating);
       
   508 	iPopTopPop->StartL(iStatus);
       
   509 	SetActive();
       
   510 	aStatus = KRequestPending;
       
   511 	iOperationActive = ETrue;
       
   512 	}
       
   513 
       
   514 //
       
   515 // quit
       
   516 //
       
   517 void CImppServerMtm::DoQuitL(TRequestStatus& aStatus)
       
   518 	{
       
   519 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
   520 	iReportStatus=&aStatus;
       
   521 	
       
   522 	// delete the mobility manager - we don't want to migrate during a disconnect
       
   523 	delete iMobilityManager;
       
   524 	iMobilityManager = NULL;
       
   525 	
       
   526 	if (!iConnectedToPopMbox)
       
   527 		{
       
   528 		aStatus=KRequestPending;
       
   529 	 	CommandComplete(KErrNone);
       
   530 		return;
       
   531 		}	
       
   532 	Cancel();
       
   533 	// set connected to false immed. on calling QUIT
       
   534 	User::LeaveIfError(iServerEntry->SetEntry(iServiceId));
       
   535 	TMsvEntry entry = iServerEntry->Entry();
       
   536 	entry.SetConnected( EFalse );
       
   537 	User::LeaveIfError(iServerEntry->ChangeEntry(entry));	
       
   538 	iState.iQuitting = ETrue;
       
   539 
       
   540   if (iMigrationState != ENotMigrating  &&
       
   541    		iMigrationState != EWaitingForOpToComplete &&
       
   542    		iMigrationState != EWaitingForOpToStop)
       
   543   	{
       
   544   	iMigrationState = ENotMigrating;
       
   545 		iState.iCurrentOperation=EPopQuitting;
       
   546 		ResetProgress();
       
   547 		TRequestStatus *pS = &iStatus;
       
   548 		User::RequestComplete(pS,KErrNone);
       
   549 		SetActive();
       
   550 		return;
       
   551   	}
       
   552 
       
   553 	if(iState.iCurrentOperation != EPopConnectedAndIdle)	// stopping in mid operation so just die
       
   554 		{
       
   555 		SetActive();
       
   556 		iState.iCurrentOperation=EPopDisconnected;
       
   557 		ResetProgress();
       
   558 		TRequestStatus *pS = &iStatus;
       
   559 		User::RequestComplete(pS,KErrNone);
       
   560 		}
       
   561 	else	// quit gracefully
       
   562 		{
       
   563 		// Run any pending delete operations.
       
   564 		// The quit operation will be started after this operation has completed.
       
   565 		FindFirstOfflineOperationL(ETrue);
       
   566 		}
       
   567 	aStatus = KRequestPending;
       
   568 	}
       
   569 
       
   570 //
       
   571 // Report some progess
       
   572 //
       
   573 const TDesC8& CImppServerMtm::Progress()
       
   574 	{
       
   575 	GetProgress();
       
   576 
       
   577 	iPopProgressBuf=TPop3ProgressBuf(iPopProgress);
       
   578 	return iPopProgressBuf;
       
   579 	}
       
   580 
       
   581 /** 
       
   582 Obtain the progress information for POPS MTM
       
   583 */
       
   584 void CImppServerMtm::GetProgress()
       
   585 	{
       
   586 	TBool progress = EFalse;
       
   587 	TInt progressError;	
       
   588 	if (iState.iRunningOfflineOperations)
       
   589 		{
       
   590 		const CImPop3OfflineOperationFinder::TOperationDetails operationDetails = iOfflineOpFinder->OperationDetails();
       
   591 
       
   592 		switch (operationDetails.iOpType)
       
   593 			{
       
   594 			case CImOffLineOperation::EOffLineOpCopyToLocal:
       
   595 			case CImOffLineOperation::EOffLineOpCopyWithinService:
       
   596 			case CImOffLineOperation::EOffLineOpMoveToLocal:
       
   597 				if (iPopCopyMove)
       
   598 					{
       
   599 					iPopProgress = iPopCopyMove->Progress();
       
   600 					}
       
   601 				break;
       
   602 			case CImOffLineOperation::EOffLineOpDelete:
       
   603 				iPopProgress.iPop3Progress = TPop3Progress::EPopDeleting;
       
   604 				break;
       
   605 			default:
       
   606 				break;
       
   607 			}
       
   608 
       
   609 		iPopProgress.iMsgsToProcess = operationDetails.iOperationsOfType - (operationDetails.iOperationNumber + 1);
       
   610 		iPopProgress.iTotalMsgs = operationDetails.iOperationsOfType;
       
   611 		}
       
   612 	else
       
   613 		{
       
   614 		TPopsMtmState state;
       
   615 		// If there has been an error which has cause disconnection then we are interested
       
   616 		// in the state that caused the failure rather than the Disconnected state. Therefore
       
   617 		// we need to report the iState.ILastCurrentOperation in this case.
       
   618 		if ((iPopProgress.iErrorCode != KErrNone) && (iState.iCurrentOperation == EPopDisconnected))
       
   619 			{
       
   620 			state = iState.iLastCurrentOperation;
       
   621 			}
       
   622 		else
       
   623 			{
       
   624 			state = iState.iCurrentOperation;
       
   625 			}
       
   626 
       
   627 		switch(state)
       
   628 			{
       
   629 		case EPopAuthoriseAndConnect:
       
   630 			{
       
   631 			iPopProgress.iPop3Progress = TPop3Progress::EPopConnecting;
       
   632 			iPopProgress.iTotalMsgs = KErrNotFound;
       
   633 			iPopProgress.iTotalBytes = KErrNotFound;
       
   634 			break;
       
   635 			}
       
   636 
       
   637 		case EPopConnecting:
       
   638 			{
       
   639 			iPopProgress.iPop3Progress = TPop3Progress::EPopConnecting;
       
   640 
       
   641 			// Check that session manager exists and get the progress information
       
   642 			// from it if it does.
       
   643 			// Under some circumstances the session manager might have been deleted
       
   644 			// such as when a the networking bearer mobility framework has indicated
       
   645 			// an error that means the RConnection is invalid.
       
   646 			if (iSessionManager)
       
   647 				{
       
   648 				iSessionManager->ConnectionProgress(iPopProgress);
       
   649 				}
       
   650 			else
       
   651 				{
       
   652 				iPopProgress.iTotalMsgs = KErrNotFound;
       
   653 				iPopProgress.iTotalBytes = KErrNotFound;			
       
   654 				}
       
   655 			break;
       
   656 			}
       
   657 
       
   658 		case EPopFindingFirstOfflineOp:
       
   659 			iPopProgress.iPop3Progress = TPop3Progress::EPopConnecting;
       
   660 			break;
       
   661 		case EPopRefreshing:
       
   662 			progressError = iPopProgress.iErrorCode;
       
   663 			if(progressError != KErrNone)
       
   664 				{
       
   665 				progress = ETrue;
       
   666 				}								
       
   667 			if(iPopRefreshMailbox!=NULL)
       
   668 				{
       
   669 				iPopProgress=iPopRefreshMailbox->Progress();
       
   670  				}
       
   671 			if(progress)
       
   672 				{	
       
   673 				iPopProgress.iErrorCode = progressError;
       
   674 				}		
       
   675 			iPopProgress.iPop3Progress = TPop3Progress::EPopRefreshing;
       
   676 			break;
       
   677 		case EPopTidying: 
       
   678 			if(iPopRefreshMailbox!=NULL)
       
   679 				{
       
   680 				iPopProgress=iPopRefreshMailbox->Progress();
       
   681 				}
       
   682 			iPopProgress.iPop3Progress = TPop3Progress::EPopRefreshing;
       
   683 			break;
       
   684 		case EPopConnectedAndIdle:
       
   685 			if (iState.iLastCurrentOperation==EPopAddingOfflineOp || iState.iLastCurrentOperation==EPopCancellingOfflineOps)
       
   686 				{
       
   687 				iOfflineOpSetter->Progress(iPopProgress);
       
   688 				}
       
   689 			if (iState.iLastCurrentOperation==EPopPopulating || iState.iLastCurrentOperation==EPopMoving || iState.iLastCurrentOperation==EPopCopying )
       
   690 				{
       
   691 				if(iPopCopyMove)
       
   692 					{
       
   693 					iPopProgress=iPopCopyMove->Progress();
       
   694 					}
       
   695 				else
       
   696 					{
       
   697 					iPopProgress.iMsgsToProcess = 0;
       
   698 					}
       
   699 				}
       
   700 			break;
       
   701 		case EPopCopying:
       
   702 			if(iPopCopyMove)
       
   703 				{
       
   704 				iPopProgress=iPopCopyMove->Progress();
       
   705 				}
       
   706 			iPopProgress.iPop3Progress = TPop3Progress::EPopCopying;
       
   707 			break;
       
   708 		case EPopPopulating:
       
   709 			if(iPopCopyMove)
       
   710 				{
       
   711 				iPopProgress=iPopCopyMove->Progress();
       
   712 				}
       
   713 			iPopProgress.iPop3Progress = TPop3Progress::EPopPopulating;
       
   714 			break;
       
   715 		case EPopTopPopulating:
       
   716 			if(iPopTopPop)
       
   717 				{
       
   718 				iPopProgress=iPopTopPop->Progress();
       
   719 				}
       
   720 			iPopProgress.iPop3Progress = TPop3Progress::EPopTopPopulating;
       
   721 			break;
       
   722 		case EPopMoving:
       
   723 			if(iPopCopyMove)
       
   724 				{
       
   725 				iPopProgress=iPopCopyMove->Progress();
       
   726 				}
       
   727 			iPopProgress.iPop3Progress = TPop3Progress::EPopMoving;
       
   728 			break;
       
   729 		case EPopDeleting:
       
   730 			if(iPopDelete)
       
   731 				{
       
   732 				iPopProgress=iPopDelete->Progress();
       
   733 				}
       
   734 			iPopProgress.iPop3Progress = TPop3Progress::EPopDeleting;
       
   735 			break;
       
   736 		case EPopQuitting:
       
   737 			iPopProgress.iPop3Progress = TPop3Progress::EPopDisconnecting;
       
   738 			break;
       
   739 		case EPopDisconnected:
       
   740 			iPopProgress.iPop3Progress = TPop3Progress::EPopDisconnected;
       
   741 			break;
       
   742 		case EPopAddingOfflineOp:
       
   743 		case EPopCancellingOfflineOps:
       
   744 			iOfflineOpSetter->Progress(iPopProgress);
       
   745 			break;
       
   746 		default:
       
   747 			break;
       
   748 			}
       
   749 
       
   750 		if ((state != EPopConnecting || state != EPopAuthoriseAndConnect) && iPopProgress.iMsgsToProcess > iPopProgress.iTotalMsgs)
       
   751 			{
       
   752 			iPopProgress.iMsgsToProcess = iPopProgress.iTotalMsgs;
       
   753 			}
       
   754 
       
   755 		if (iPopProgress.iMsgsToProcess<0)
       
   756 			{
       
   757 			iPopProgress.iMsgsToProcess = 0;
       
   758 			}
       
   759 		}
       
   760 		iPopProgress.iServiceId = iServiceId;
       
   761 }
       
   762 
       
   763 /** 
       
   764 This call leads to calling GetProgress() to populate the TPop3Progress structure.
       
   765 @param aOutSysProg The TMsvSystemProgress structure to be populated
       
   766 */
       
   767 void CImppServerMtm::GetSystemProgress(TMsvSystemProgress& aOutSysProg)
       
   768 	{
       
   769 	GetProgress();
       
   770 	aOutSysProg.iErrorCode = iPopProgress.iErrorCode;
       
   771 	}
       
   772 
       
   773 /** 
       
   774 The extension method provides a polymorphic behaviour to call the correct
       
   775 MTM.
       
   776 @param aExtensionId The Uid passed in as KUIDMsgMsvSystemProgress to obtain the
       
   777 System Progress.
       
   778 @return KErrNone if GetSystemProgress is called successfully.
       
   779 */
       
   780 TInt CImppServerMtm::Extension_(TUint aExtensionId, TAny *&a0, TAny *a1)	
       
   781 	{
       
   782 	switch(aExtensionId)
       
   783 		{
       
   784 		case KUIDMsgMsvSystemProgress:
       
   785 			{
       
   786 			TMsvSystemProgress* systemProgress = reinterpret_cast<TMsvSystemProgress*>(a1);
       
   787 			GetSystemProgress(*systemProgress);
       
   788 			return KErrNone;
       
   789 			}
       
   790 
       
   791 #if (defined SYMBIAN_USER_PROMPT_SERVICE)
       
   792 		case KUIDMsgClientThreadInfo:
       
   793 			{
       
   794 			iClientThreadId = *(TThreadId*) (a1);
       
   795 	    	iHasCapability = (TBool)*(TInt*)(a0);
       
   796 	    	return KErrNone;
       
   797 			}
       
   798 #endif
       
   799 
       
   800 		case KUidMsgNonOperationMtmData:
       
   801 			{
       
   802 			TNonOperationMtmDataType* mtmDataType = reinterpret_cast<TNonOperationMtmDataType*>(a0);
       
   803 			TPtrC8* mtmDataBuffer = reinterpret_cast<TPtrC8*>(a1);
       
   804 			return GetNonOperationMtmData(*mtmDataType, *mtmDataBuffer);
       
   805 			}
       
   806 
       
   807 		default:
       
   808 			{
       
   809 			// Chain to base class
       
   810 			return CBaseServerMtm::Extension_(aExtensionId, a0, a1);
       
   811 			}
       
   812 		}
       
   813 	}
       
   814 
       
   815 //
       
   816 // return current state of connection?
       
   817 //
       
   818  TBool CImppServerMtm::CommandExpected()
       
   819 	{
       
   820 	return iConnectedToPopMbox;
       
   821 	}
       
   822 
       
   823 //
       
   824 // Special cancel for migration purposes. 
       
   825 // Stops the current operation without completing the user/client request.
       
   826 // The cancelled operation may then be restarted once migration to a new 
       
   827 // bearer has completed.
       
   828 //
       
   829 void CImppServerMtm::CancelToMigrate()
       
   830 	{
       
   831 	iCancelForBMMigration = ETrue;
       
   832 	Cancel();
       
   833 	iCancelForBMMigration = EFalse;
       
   834 	}
       
   835 
       
   836 //
       
   837 // Implements the Cancel(). Unless called via the special method for handling 
       
   838 // cancelling for migration (above), calling DoCancel will cancel the user
       
   839 // requested operation, delete the pop session, mark the server offline and 
       
   840 // complete the user request if outstanding.
       
   841 //
       
   842 // If called via the special method, the server is not marked offline, and 
       
   843 // user requests are not completed.
       
   844 //
       
   845 void CImppServerMtm::DoCancel()
       
   846 	{
       
   847 	// Cancel current outstanding request according to current state...
       
   848 	switch (iMigrationState)
       
   849 		{
       
   850 		case ENotMigrating:
       
   851 		case EWaitingForOpToStop:
       
   852 		case EWaitingForOpToComplete:
       
   853 			{
       
   854 			// Cancels the current operation according to iState.iCurrentOperation
       
   855 			// If cancelling for bearer migration, operations are able to be resumed.
       
   856 			DoCancelCurrentOp();
       
   857 			break;
       
   858 			}
       
   859 		case EDisconnectingForMigrate:
       
   860 		case EConnectingAfterMigrate:
       
   861 			{
       
   862 			// Cancel the connect/disconnect on the session manager
       
   863 			iSessionManager->Cancel();
       
   864 			break;
       
   865 			}
       
   866 		case EWaitingForNewCarrier:
       
   867 		case EWaitingCarrierRejected:
       
   868 			{
       
   869 			// self-induced dummy wait state on the mobility manager
       
   870 			// Cancel it:
       
   871 			TRequestStatus* status = &iStatus;
       
   872 			User::RequestComplete(status, KErrCancel);
       
   873 			break;
       
   874 			}
       
   875 		default:
       
   876 			{
       
   877 			break;
       
   878 			}
       
   879 		}
       
   880 
       
   881 	// Final tidying for non-migration caused cancels
       
   882 	if (!iCancelForBMMigration)
       
   883 		{
       
   884 		if(iState.iCurrentOperation != EPopConnectedAndIdle)
       
   885 			{
       
   886 			iState.iCurrentOperation = EPopDisconnected;
       
   887 			TRAP_IGNORE(DoShowMessagesL( EFalse ) );
       
   888 			
       
   889 			// delete the mobility manager	
       
   890 			delete iMobilityManager;
       
   891 			iMobilityManager = NULL;
       
   892 
       
   893 			TInt err = iServerEntry->SetEntry(iServiceId);
       
   894 			if (err == KErrNone)
       
   895 				{
       
   896 				TMsvEntry entry = iServerEntry->Entry();
       
   897 				entry.SetConnected( EFalse );
       
   898 				iServerEntry->ChangeEntry( entry );	// ignore any error
       
   899 				}
       
   900 			}
       
   901 		
       
   902 		if(iOperationActive)
       
   903 			{
       
   904 			// Complete the client request now
       
   905 			CommandComplete(KErrCancel);
       
   906 			}
       
   907 		}
       
   908 	}
       
   909 
       
   910 
       
   911 /**
       
   912 Cancel according to iState.iCurrentOperation
       
   913 
       
   914 If the cancel is to allow a migration, the operation object in use
       
   915 is cancelled, but not deleted. This means it is possible to restart it
       
   916 later.
       
   917 */
       
   918 void CImppServerMtm::DoCancelCurrentOp()
       
   919 	{	
       
   920 	switch(iState.iCurrentOperation)
       
   921 		{
       
   922 		case EPopAuthoriseAndConnect:
       
   923 			{
       
   924 #if (defined SYMBIAN_USER_PROMPT_SERVICE)
       
   925 			iWaiter->Cancel();
       
   926 #endif
       
   927 			break;
       
   928 			}
       
   929 
       
   930 		case EPopDisconnected:
       
   931 		case EPopTidying: 		// self completed state
       
   932 			{
       
   933 			break;
       
   934 			}
       
   935 		case EPopConnecting:
       
   936 		case EPopQuitting:
       
   937 			{
       
   938 			__ASSERT_ALWAYS(iSessionManager, Panic(EPopNullPointer));
       
   939 			iSessionManager->Cancel();
       
   940 			break;
       
   941 			}
       
   942 		case EPopConnectedAndIdle:
       
   943 			{
       
   944 			__ASSERT_ALWAYS(iPopSession, Panic(EPopNullPointer));
       
   945 			iPopSession->Cancel();
       
   946 			break;
       
   947 			}
       
   948 		case EPopRefreshing:
       
   949 			{
       
   950 			if (iCancelForBMMigration)
       
   951 				{
       
   952 				iPopRefreshMailbox->CancelAllowResume();
       
   953 				}
       
   954 			else
       
   955 				{
       
   956 				iPopRefreshMailbox->Cancel();
       
   957 				}
       
   958 			delete iPopSession;
       
   959 			iPopSession = NULL;
       
   960 			break;
       
   961 			}
       
   962 		case EPopCopying:
       
   963 		case EPopMoving:
       
   964 		case EPopPopulating:
       
   965 			{
       
   966 			if (iCancelForBMMigration)
       
   967 				{
       
   968 				iPopCopyMove->CancelAllowResume();
       
   969 				}
       
   970 			else
       
   971 				{
       
   972 				delete iPopCopyMove;
       
   973 				iPopCopyMove=NULL;
       
   974 				}
       
   975 			delete iPopSession;
       
   976 			iPopSession = NULL;
       
   977 			break;
       
   978 			}
       
   979 		case EPopTopPopulating:
       
   980 			{
       
   981 			if (iCancelForBMMigration)
       
   982 				{
       
   983 				iPopTopPop->CancelAllowResume();
       
   984 				}
       
   985 			else
       
   986 				{
       
   987 				delete iPopTopPop;
       
   988 				iPopTopPop=NULL;
       
   989 				}
       
   990 			delete iPopSession;
       
   991 			iPopSession = NULL;
       
   992 			break;
       
   993 			}
       
   994 		case EPopDeleting:
       
   995 			{
       
   996 			if (iCancelForBMMigration)
       
   997 				{
       
   998 				iPopDelete->CancelAllowResume();
       
   999 				}
       
  1000 			else
       
  1001 				{
       
  1002 				delete iPopDelete;
       
  1003 				iPopDelete=NULL;
       
  1004 				}
       
  1005 			delete iPopSession;
       
  1006 			iPopSession = NULL;
       
  1007 			break;
       
  1008 			}
       
  1009 		case EPopAddingOfflineOp:
       
  1010 			{
       
  1011 			iOfflineOpSetter->Cancel();
       
  1012 			break;
       
  1013 			}
       
  1014 		case EPopFindingFirstOfflineOp:
       
  1015 			{
       
  1016 			iOfflineOpFinder->Cancel();
       
  1017 			break;
       
  1018 			}
       
  1019 		case EPopCancellingOfflineOps:
       
  1020 			{
       
  1021 			if (iCancelForBMMigration)
       
  1022 				{
       
  1023 				// RJS: update this Cancel() to enable resume
       
  1024 				iOfflineOpSetter->Cancel();
       
  1025 				}
       
  1026 			else
       
  1027 				{
       
  1028 				iOfflineOpSetter->Cancel();
       
  1029 				}
       
  1030 			break;
       
  1031 			}
       
  1032 		}
       
  1033 	}
       
  1034 
       
  1035 //
       
  1036 // 
       
  1037 //
       
  1038 void CImppServerMtm::DoRunL()
       
  1039 	{
       
  1040 	TInt err = KErrNone;
       
  1041 	TInt eCode=iStatus.Int();
       
  1042 	iState.iLastCurrentOperation = iState.iCurrentOperation;
       
  1043 	TBool quitSuccessfully = EFalse;
       
  1044 	TPop3Progress progress;
       
  1045 	
       
  1046    	if (iMigrationState != ENotMigrating  &&
       
  1047    		iMigrationState != EWaitingForOpToComplete &&
       
  1048    		iMigrationState != EWaitingForOpToStop)
       
  1049 		{
       
  1050 		if (DoMigrationRunL()) 
       
  1051 			{
       
  1052 			return;
       
  1053 			}
       
  1054 		}
       
  1055 
       
  1056 	switch(iState.iCurrentOperation)
       
  1057 		{
       
  1058 	case EPopAuthoriseAndConnect:
       
  1059 		{
       
  1060 		if (eCode == KErrNone)
       
  1061 			{
       
  1062 			iState.iCurrentOperation = EPopConnecting;
       
  1063 			// obtain a connected pop session
       
  1064 			iSessionManager->GetSessionL(*iPopSettings, *iIAPPreferences, iPopSession, iStatus);
       
  1065 			SetActive();
       
  1066 			return;
       
  1067 			}
       
  1068 		break;
       
  1069 		}
       
  1070 
       
  1071 	case EPopConnecting:
       
  1072 		{
       
  1073 		// Register for bearer mobility,
       
  1074 		if (StartBearerMobilityL(eCode))
       
  1075 			{
       
  1076 			// Return now if the initial carrier has been rejected.
       
  1077 			return;
       
  1078 			}
       
  1079 
       
  1080 		if (eCode == KErrNone)
       
  1081 			{
       
  1082 			__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1083 			// The POP session is now connected - update the connected flag.
       
  1084 			User::LeaveIfError( iServerEntry->SetEntry(iServiceId) );
       
  1085 			TMsvEntry entry;
       
  1086 			entry = iServerEntry->Entry();
       
  1087 			entry.SetConnected( ETrue );
       
  1088 			User::LeaveIfError( iServerEntry->ChangeEntry(entry) );
       
  1089 
       
  1090 			// if we've connected OK start the refresh
       
  1091 			if (iPopSession->MaxHeaders()==0)
       
  1092 				{
       
  1093 				iState.iCurrentOperation=EPopQuitting;
       
  1094 				CommandComplete(KErrNone);
       
  1095 				}
       
  1096 			else
       
  1097 				{
       
  1098 				TRAP_IGNORE( DoRefreshL() );
       
  1099 				}
       
  1100 			}
       
  1101 		break;
       
  1102 		}
       
  1103 	case EPopRefreshing:
       
  1104 		{
       
  1105 		// Check if stopping for migrate
       
  1106 		if(iMigrationState == EWaitingForOpToStop && eCode == KErrNone)
       
  1107 			{
       
  1108 			StoreConfigurationToMigrateL();
       
  1109 			// We were waiting on this op to stop before we migrate.
       
  1110 			// so start disconnecting for migration now
       
  1111 			DisconnectForMigrate();
       
  1112 			return;
       
  1113 			}
       
  1114 		
       
  1115 		// tidy up any dead messages
       
  1116 		// should only be necessary if the refresh has failed
       
  1117 		if(iMsvIdArray->Count())
       
  1118 			{
       
  1119 			iArrayCtr=iMsvIdArray->Count();
       
  1120 			iState.iCurrentOperation=EPopTidying;
       
  1121 			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopTidying);
       
  1122 			QueueRemoteCleanup();
       
  1123 			}
       
  1124 		else
       
  1125 			{
       
  1126 			if(eCode==KErrNone)
       
  1127 				{
       
  1128 				TRAP(eCode,DoShowMessagesL(ETrue));
       
  1129 				}
       
  1130 			iState.iQuitting = EFalse;
       
  1131 			if (eCode == KErrNone)
       
  1132 				{
       
  1133 				FindFirstOfflineOperationL(EFalse);
       
  1134 				}
       
  1135 			}
       
  1136 		break;
       
  1137 		}
       
  1138 	case EPopTidying:
       
  1139 		{
       
  1140 		if(--iArrayCtr>=0)
       
  1141 			{		
       
  1142 			__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1143 			//  No appropriate error handling here...
       
  1144 			//  Refresh has failed: need to remove all of the partially
       
  1145 			//  loaded headers etc..
       
  1146 			err = iServerEntry->DeleteEntry((*iMsvIdArray)[iArrayCtr]);
       
  1147 			__ASSERT_DEBUG(err == KErrNone, Panic(EPopFailedDebugAssert));
       
  1148 			QueueRemoteCleanup();
       
  1149 			}
       
  1150 		else
       
  1151 			{
       
  1152 			if(iMigrationState == EWaitingForOpToStop && eCode == KErrNone)
       
  1153 				{
       
  1154 				// Stopping for migrate. RestartAfterMigrateL() calls
       
  1155 				// FindFirstOfflineOperationL(EFalse) if restarting in
       
  1156 				// state EPopFindingFirstOfflineOp, so set it up and go.
       
  1157 				iState.iCurrentOperation = EPopFindingFirstOfflineOp;
       
  1158 				StoreConfigurationToMigrateL();
       
  1159 				DisconnectForMigrate();
       
  1160 				return;
       
  1161 				}
       
  1162 			else
       
  1163 				{
       
  1164 				FindFirstOfflineOperationL(EFalse);
       
  1165 				}
       
  1166 			}
       
  1167 		break;
       
  1168 		}
       
  1169 	case EPopFindingFirstOfflineOp:
       
  1170 		{
       
  1171 		if(iMigrationState == EWaitingForOpToStop && eCode == KErrNone)
       
  1172 			{
       
  1173 			// Stopping for migrate. RestartAfterMigrateL() calls
       
  1174 			// FindFirstOfflineOperationL(EFalse) if restarting in
       
  1175 			// state EPopFindingFirstOfflineOp. This is a little
       
  1176 			// inefficient, but avoids adding an extra state.
       
  1177 			iState.iCurrentOperation = EPopFindingFirstOfflineOp;
       
  1178 			StoreConfigurationToMigrateL();
       
  1179 			DisconnectForMigrate();
       
  1180 			return;
       
  1181 			}
       
  1182 				
       
  1183 		if (iOfflineOpFinder->OperationFound())
       
  1184 			{
       
  1185 			// A pending offline operation has been found, so run it.
       
  1186 			RunOfflineOperationL();
       
  1187 			}
       
  1188 		else
       
  1189 			// There are no more pending operations.
       
  1190 			{
       
  1191 			iState.iRunningOfflineOperations = EFalse;
       
  1192 			if (iState.iQuitting)
       
  1193 				{
       
  1194 				// The offline operations are being run as part of the quitting process.
       
  1195 				// As these operations have now been run the quitting process should be resumed.
       
  1196 				iState.iCurrentOperation=EPopQuitting;
       
  1197 				ResetProgress();
       
  1198 				if (iSessionManager && iPopSession)
       
  1199 					{
       
  1200 					iSessionManager->DeleteSession(*iPopSession, iStatus);
       
  1201 					MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopQuitting);
       
  1202 					iPopSession=NULL;
       
  1203 					}
       
  1204 				iOperationActive=ETrue;
       
  1205 				SetActive();
       
  1206 				}
       
  1207 			else
       
  1208 				{
       
  1209 				// The offline operations are being run as part of the connection process.
       
  1210 				// As these operations have now been run we are now connected.
       
  1211 				iState.iCurrentOperation=EPopConnectedAndIdle;
       
  1212 				iOperationActive=EFalse;
       
  1213 				}
       
  1214 			}
       
  1215 		break;
       
  1216 		}
       
  1217 	case EPopCopying:
       
  1218 	case EPopPopulating:
       
  1219 	case EPopMoving:
       
  1220 		{
       
  1221 		// Check if we are migrating
       
  1222 		if(iMigrationState == EWaitingForOpToStop && eCode == KErrNone)
       
  1223 			{
       
  1224 			// if the operation is incomplete, start migration here. Otherwise
       
  1225 			// allow the user request to be completed, and handle migration
       
  1226 			// as if the request was to complete op for migrate. 
       
  1227 			progress = iPopCopyMove->Progress();
       
  1228 			if (progress.iMsgsToProcess)
       
  1229 				{
       
  1230 				StoreConfigurationToMigrateL();
       
  1231 				DisconnectForMigrate();
       
  1232 				return;
       
  1233 				}
       
  1234 			}
       
  1235 
       
  1236 		if (iState.iRunningOfflineOperations && iState.iCurrentOperation != EPopMoving)
       
  1237 			// The operation was a pending offline operation and should be deleted.
       
  1238 			{
       
  1239 			__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1240 			CImPop3OfflineUtilities::DeleteL(iOfflineOpFinder->OfflineOperation(), *iServerEntry);
       
  1241 			}
       
  1242 
       
  1243 		__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1244 		delete iPopCopyMove;
       
  1245 		iPopCopyMove=NULL;
       
  1246 		iState.iCurrentOperation=EPopConnectedAndIdle;
       
  1247 		iOperationActive=EFalse;
       
  1248 
       
  1249 		// reset server entry context
       
  1250 		err = iServerEntry->SetEntry( iServiceId );
       
  1251 		if(err != KErrNone)
       
  1252 			{
       
  1253 			CommandComplete( err );
       
  1254 			return;
       
  1255 			}	// should disconnect
       
  1256 
       
  1257 		if ((iState.iRunningOfflineOperations) && (eCode == KErrNone))
       
  1258 			{
       
  1259 			iOfflineOpFinder->FindNext();
       
  1260 			// if we are stopping for migrate and there is another operation to perform,
       
  1261 			// allow the migration to happen now. Otherwise, allow the operation to finish.
       
  1262 			if (iMigrationState == EWaitingForOpToStop && iOfflineOpFinder->OperationFound())
       
  1263 				{
       
  1264 				StoreConfigurationToMigrateL();
       
  1265 				DisconnectForMigrate();
       
  1266 				return;			
       
  1267 				}
       
  1268 			RunOfflineOperationL();
       
  1269 			}			
       
  1270 		break;
       
  1271 		}
       
  1272 	case EPopTopPopulating:
       
  1273 		{
       
  1274 		__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1275 		// Check if we are migrating		
       
  1276 		if(iMigrationState == EWaitingForOpToStop && eCode == KErrNone)
       
  1277 			{
       
  1278 			// if the operation is incomplete, start migration here. Otherwise
       
  1279 			// allow the user request to be completed, and handle migration
       
  1280 			// as if the request was to complete op for migrate. 
       
  1281 			progress = iPopTopPop->Progress();
       
  1282 			if (progress.iMsgsToProcess)
       
  1283 				{
       
  1284 				StoreConfigurationToMigrateL();
       
  1285 				DisconnectForMigrate();
       
  1286 				return;
       
  1287 				}
       
  1288 			}
       
  1289 
       
  1290 		if (iState.iRunningOfflineOperations)
       
  1291 			// The operation was a pending offline operation and should be deleted.
       
  1292 			{
       
  1293 			CImPop3OfflineUtilities::DeleteL(iOfflineOpFinder->OfflineOperation(), *iServerEntry);
       
  1294 			}
       
  1295 
       
  1296 		delete iPopTopPop;
       
  1297 		iPopTopPop=NULL;
       
  1298 		iState.iCurrentOperation=EPopConnectedAndIdle;
       
  1299 		iOperationActive=EFalse;
       
  1300 
       
  1301 		// reset server entry context
       
  1302 		err = iServerEntry->SetEntry( iServiceId );
       
  1303 		if(err != KErrNone)
       
  1304 			{
       
  1305 			CommandComplete( err );
       
  1306 			return;
       
  1307 			}	// should disconnect
       
  1308 
       
  1309 		if ((iState.iRunningOfflineOperations) && (eCode == KErrNone))
       
  1310 			{
       
  1311 			iOfflineOpFinder->FindNext();
       
  1312 			// if we are stopping for migrate and there is another operation to perform,
       
  1313 			// allow the migration to happen now. Otherwise, allow the operation to finish.
       
  1314 			if (iMigrationState == EWaitingForOpToStop && iOfflineOpFinder->OperationFound())
       
  1315 				{
       
  1316 				StoreConfigurationToMigrateL();
       
  1317 				DisconnectForMigrate();
       
  1318 				return;			
       
  1319 				}
       
  1320 			RunOfflineOperationL();
       
  1321 			}
       
  1322 		break;
       
  1323 		}
       
  1324 	case EPopDeleting:
       
  1325 		{
       
  1326 		// Check if we are migrating
       
  1327 		if(iMigrationState == EWaitingForOpToStop && eCode == KErrNone)
       
  1328 			{
       
  1329 			// if the operation is incomplete, start migration here. Otherwise
       
  1330 			// allow the user request to be completed, and handle migration
       
  1331 			// as if the request was to complete op for migrate. 
       
  1332 			progress = iPopDelete->Progress();
       
  1333 			if (progress.iMsgsToProcess)
       
  1334 				{
       
  1335 				StoreConfigurationToMigrateL();
       
  1336 				DisconnectForMigrate();
       
  1337 				return;
       
  1338 				}
       
  1339 			}
       
  1340 
       
  1341 		delete iPopDelete;
       
  1342 		iPopDelete=NULL;
       
  1343 
       
  1344 		iState.iCurrentOperation=EPopConnectedAndIdle;
       
  1345 		iOperationActive=EFalse;
       
  1346 		if ((iState.iRunningOfflineOperations) && (eCode == KErrNone))
       
  1347 			{
       
  1348 			iOfflineOpFinder->FindNext();
       
  1349 			// if we are stopping for migrate and there is another operation to perform,
       
  1350 			// allow the migration to happen now. Otherwise, allow the operation to finish.
       
  1351 			if (iMigrationState == EWaitingForOpToStop && iOfflineOpFinder->OperationFound())
       
  1352 				{
       
  1353 				StoreConfigurationToMigrateL();
       
  1354 				DisconnectForMigrate();
       
  1355 				return;			
       
  1356 				}
       
  1357 			RunOfflineOperationL();
       
  1358 			}
       
  1359 		break;
       
  1360 		}
       
  1361 	case EPopQuitting:
       
  1362 		{
       
  1363 		quitSuccessfully = ETrue;
       
  1364 		break;
       
  1365 		}
       
  1366 	case EPopDisconnected:
       
  1367 		{
       
  1368 		// no change of state
       
  1369 		break;
       
  1370 		}
       
  1371 	case EPopAddingOfflineOp:
       
  1372 	case EPopCancellingOfflineOps:
       
  1373 		{
       
  1374 		iOperationActive = EFalse;
       
  1375 		if (!iConnectedToPopMbox)
       
  1376 			{
       
  1377 			iState.iCurrentOperation=EPopDisconnected;
       
  1378 			if(iNotConnectToPopMailBox)
       
  1379 				{
       
  1380 				CommandComplete(KErrDisconnected);
       
  1381 				iNotConnectToPopMailBox = EFalse ;
       
  1382 				}
       
  1383 			else
       
  1384 				{
       
  1385 				CommandComplete(KErrNone);
       
  1386 				}
       
  1387 			}
       
  1388 		else
       
  1389 			{
       
  1390 			if (eCode == KErrNotFound)
       
  1391 				{
       
  1392 				eCode = KErrNone;
       
  1393 				}
       
  1394 			iState.iCurrentOperation = EPopConnectedAndIdle;
       
  1395 			}
       
  1396 		break;
       
  1397 		}
       
  1398 	default:
       
  1399 		{
       
  1400 		iState.iCurrentOperation=(eCode==KErrNone) ? EPopConnectedAndIdle : EPopDisconnected;
       
  1401 		break;
       
  1402 		}
       
  1403 		} // end of switch (iState.iCurrentOperation)
       
  1404 
       
  1405 	// signal completion unless we're doing the refresh or tidying
       
  1406 	if( quitSuccessfully || eCode!=KErrNone )
       
  1407 		{
       
  1408 		__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1409 		if (iPopSession)
       
  1410 			{			
       
  1411 			delete iPopSession;
       
  1412 			iPopSession=NULL;
       
  1413 			}
       
  1414 		iState.iQuitting = EFalse;
       
  1415 		
       
  1416 		// delete the mobility manager	
       
  1417 		delete iMobilityManager;
       
  1418 		iMobilityManager = NULL;
       
  1419 		
       
  1420 		TRAP_IGNORE( DoShowMessagesL(EFalse) );
       
  1421 		if( iState.iCurrentOperation != EPopQuitting)
       
  1422 			{
       
  1423 			TInt err = iServerEntry->SetEntry( iServiceId );
       
  1424 			if(err == KErrNone)
       
  1425 				{
       
  1426 				TMsvEntry entry = iServerEntry->Entry();
       
  1427 				entry.SetConnected( EFalse );
       
  1428 				iServerEntry->ChangeEntry( entry );	// ignore any error
       
  1429 				}
       
  1430 			}
       
  1431 		if(!(iState.iLastCurrentOperation == EPopConnectedAndIdle && iState.iCurrentOperation == EPopDisconnected) ) 
       
  1432 			{	
       
  1433 			CommandComplete( eCode );
       
  1434 			}
       
  1435 		else
       
  1436 			{
       
  1437 			iPopProgress.iErrorCode = eCode;
       
  1438 			}
       
  1439 		iServerEntry->SetEntry(KMsvNullIndexEntryId); // when it times out the server MTM doesn't get deleted and henc the iServerEntry is locked and cannot do anythig withit.  If you set it to NULL it will solve the problem
       
  1440 		iState.iCurrentOperation = EPopDisconnected;
       
  1441 		return;
       
  1442 		}
       
  1443 		
       
  1444 	if(iReportStatus == NULL && IsActive())
       
  1445 		{
       
  1446 		// we are in an inconsistent state and should leave.
       
  1447 		// since we want to complete the request and return to the client,
       
  1448 		// we LEAVE with KErrUnknown. The completion of the request is done in the TRAP
       
  1449 		// of the ServiceL method, where DoComplete is called.
       
  1450 		User::Leave(KErrUnknown);
       
  1451 		}	
       
  1452 	
       
  1453 	
       
  1454 	// set pop session idle waiting
       
  1455 	if( iState.iCurrentOperation == EPopConnectedAndIdle && iConnectedToPopMbox
       
  1456 		&& iState.iCurrentOperation != iState.iLastCurrentOperation)
       
  1457 		{
       
  1458 		// Complete the waiting iStatus. Note this object stays active so that 
       
  1459 		// it can react to any connection failure, e.g. time-out
       
  1460 		CommandComplete( eCode );
       
  1461 		if(	(iMigrationState == EWaitingForOpToComplete) ||
       
  1462 			(iMigrationState == EWaitingForOpToStop) )
       
  1463 			{
       
  1464 			// We were waiting on this op to complete before we migrate.
       
  1465 			// so start disconnecting for migration now
       
  1466 			DisconnectForMigrate();
       
  1467 			}
       
  1468 		else
       
  1469 			{
       
  1470 			iPopSession->Waiting(iStatus);
       
  1471 			SetActive();
       
  1472 			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopConnectedAndIdle);
       
  1473 			}
       
  1474 		}
       
  1475 	}
       
  1476 	
       
  1477 /**
       
  1478 Stores configuration to be re-used post Migration.
       
  1479 */ 
       
  1480 void CImppServerMtm::StoreConfigurationToMigrateL()
       
  1481 	{
       
  1482 	iSavedValuesForMigration.iMessageArray 	= iPopSession->MessageArray();
       
  1483 	iSavedValuesForMigration.iNumMessages 	= iPopSession->GetNumMessages();
       
  1484 
       
  1485 	TInt32* IdTab = new(ELeave) TInt32[iSavedValuesForMigration.iNumMessages];
       
  1486 	// The copying of Array here is very crude and in-efficient
       
  1487 	// Need to use an arraytype that has a copy constructor
       
  1488 	for (TInt count=0; count < iSavedValuesForMigration.iNumMessages; count++)
       
  1489 		{
       
  1490 		IdTab[count] = iSavedValuesForMigration.iMessageArray[count];
       
  1491 		}	
       
  1492 	iSavedValuesForMigration.iMessageArray = IdTab;
       
  1493 	iSavedValuesForMigration.iValuesSaved = ETrue;
       
  1494 	}
       
  1495 
       
  1496 /**
       
  1497 Handles the migration state machine states.  
       
  1498 This is called the Pop ServerMTM doRunL() routine.
       
  1499 
       
  1500 @return ETrue if the state has been handled and DoRunL can return
       
  1501 */
       
  1502 TBool CImppServerMtm::DoMigrationRunL()
       
  1503 	{
       
  1504 	TBool migrationHandled = ETrue;
       
  1505 
       
  1506 	// We are migrating so handle the migration states here
       
  1507 	switch (iMigrationState)
       
  1508 		{
       
  1509 		case EDisconnectingForMigrate:
       
  1510 			{
       
  1511 			// Old session disconnected, tell the MM we are ready to migrate.
       
  1512 			iMigrationState = EWaitingForNewCarrier;
       
  1513 			iMobilityManager->MigrateToNewCarrier();
       
  1514 			// Set dummy request pending, unless state has been changed by MigrateToNewCarrier()
       
  1515 			if (iMigrationState == EWaitingForNewCarrier)
       
  1516 				{
       
  1517 				iStatus = KRequestPending;
       
  1518 				SetActive();
       
  1519 				}
       
  1520 			break;
       
  1521 			}
       
  1522 		case EWaitingForNewCarrier:
       
  1523 		case EWaitingCarrierRejected:
       
  1524 			{
       
  1525 			// Migration has completed, obtain a new connected POP session
       
  1526 			iMigrationState = EConnectingAfterMigrate;
       
  1527 			iSessionManager->GetSessionL(*iPopSettings, *iIAPPreferences, iPopSession, iStatus);
       
  1528 			SetActive();
       
  1529 			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopConnecting);
       
  1530 			break;
       
  1531 			}
       
  1532 		case EConnectingAfterMigrate:
       
  1533 			{
       
  1534 			if (iStatus.Int()!=KErrNone)
       
  1535 				{
       
  1536 				// An error has occurred while attempting to re-connect
       
  1537 				// - reject this new carrier, wait to see if a new one turns up.
       
  1538 				iMigrationState = EWaitingCarrierRejected;
       
  1539 				iMobilityManager->NewCarrierRejected();
       
  1540 
       
  1541 				// Now in a waiting state, set self active
       
  1542 				iStatus = KRequestPending;
       
  1543 				SetActive();
       
  1544 				}
       
  1545 			else
       
  1546 				{
       
  1547 				// We have a new pop session, set the state and tell the mobility manager
       
  1548 				iMigrationState = ENotMigrating;
       
  1549 				iMobilityManager->NewCarrierAccepted();
       
  1550 				// restart the pop server 
       
  1551 				RestartAfterMigrateL();
       
  1552 				}
       
  1553 			break;
       
  1554 			}
       
  1555 		default:
       
  1556 			{
       
  1557 			__ASSERT_DEBUG(EFalse, Panic(EPopUnexpectedMigrateState));
       
  1558 			migrationHandled = EFalse;
       
  1559 			break;
       
  1560 			}
       
  1561 		}
       
  1562 	return migrationHandled;
       
  1563 	}
       
  1564 
       
  1565 /**
       
  1566 Utility function to delete the Pop Session
       
  1567 note the Session Manager DeleteSession() request is asynchronous.
       
  1568 */
       
  1569 void CImppServerMtm::DisconnectForMigrate()
       
  1570 	{
       
  1571 	// Call the session manager to delete the session
       
  1572 	iMigrationState = EDisconnectingForMigrate;
       
  1573 	iSessionManager->DeleteSession(*iPopSession, iStatus);
       
  1574 	MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopQuitting);
       
  1575 	iPopSession = NULL;
       
  1576 	SetActive();
       
  1577 	}
       
  1578 	
       
  1579 /**
       
  1580 Restarts any pre-migration outstanding operations, or set the state machine into the same
       
  1581 state it was pre-migration along with any necessary connections and set ups.
       
  1582 
       
  1583 Note that iCurrentOperation will have returned to EPopConnectedAndIdle if the migration type
       
  1584 was "allow complete" or "stop for migrate" and the operation came to a natural finish.
       
  1585 
       
  1586 If iCurrentOperation is not EPopConnectedAndIdle, it indicates that the operation had not
       
  1587 completed prior to the migration. This is caused with by an "accept immediately" migration,
       
  1588 a CarrierLost() migration, or a "stop operation" migration for which the operation did not
       
  1589 come to a natural completion. In these cases, the operation in progress needs to be resumed.
       
  1590 */
       
  1591 void CImppServerMtm::RestartAfterMigrateL()
       
  1592 	{
       
  1593 	if (iSavedValuesForMigration.iValuesSaved)
       
  1594 		{
       
  1595 		// Ownership of MessageArray is passed to the PopSession here
       
  1596 		iPopSession->SetMessageArray(iSavedValuesForMigration.iMessageArray, iSavedValuesForMigration.iNumMessages);
       
  1597 		iSavedValuesForMigration.iValuesSaved = EFalse;
       
  1598 		}
       
  1599 
       
  1600 	// switch on pre-migrate state
       
  1601 	switch(iState.iCurrentOperation)
       
  1602 		{
       
  1603 		case EPopConnecting: // in this state if initial carrier rejected...
       
  1604 		case EPopTidying:
       
  1605 			{
       
  1606 			// Self complete to return to the State Machine
       
  1607 			iStatus = KRequestPending;
       
  1608 			SetActive();
       
  1609 			TRequestStatus *status = &iStatus;
       
  1610 			User::RequestComplete(status,KErrNone);
       
  1611 			break;
       
  1612 			}
       
  1613 		case EPopConnectedAndIdle:
       
  1614 			{
       
  1615 			if (iState.iRunningOfflineOperations)
       
  1616 				{
       
  1617 				// can be in this state if the offline operations were stopped before all
       
  1618 				// were finished.
       
  1619 				RunOfflineOperationL();
       
  1620 				}
       
  1621 			else
       
  1622 				{
       
  1623 				// No operation in progress at time of migration, re-enter idle waiting state
       
  1624 				iPopSession->Waiting(iStatus);
       
  1625 				SetActive();
       
  1626 				MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopConnectedAndIdle);
       
  1627 				}
       
  1628 			break;
       
  1629 			}
       
  1630 		// Refresh, Copy, Move, Delete, Populate - these operations need to be 
       
  1631 		// resumed if they were cancelled or stopped before completing.
       
  1632 		// Note that if the operation had actually completed, 
       
  1633 		// iCurrentOperation would now be EPopConnectedAndIdle.
       
  1634 		case EPopRefreshing:
       
  1635 			{
       
  1636 			// Resume the refresh operation:
       
  1637 			iPopRefreshMailbox->ResumeL(iPopSession, iStatus);
       
  1638 			SetActive();
       
  1639 			break;
       
  1640 			}
       
  1641 		case EPopCopying:
       
  1642 		case EPopMoving:
       
  1643 		case EPopPopulating:
       
  1644 			{
       
  1645 			// Resume the copy/move operation
       
  1646 			iPopCopyMove->ResumeL(iPopSession, iStatus);
       
  1647 			iStatus = KRequestPending;
       
  1648 			SetActive();
       
  1649 			break;
       
  1650 			}
       
  1651 		case EPopDeleting:
       
  1652 			{
       
  1653 			// Resume the delete operation
       
  1654 			iPopDelete->ResumeL(iPopSession, iStatus);
       
  1655 			SetActive();
       
  1656 			break;
       
  1657 			}
       
  1658 		case EPopTopPopulating:
       
  1659 			{
       
  1660 			iPopTopPop->ResumeL(iPopSession, iStatus);
       
  1661 			SetActive();
       
  1662 			break;
       
  1663 			}
       
  1664 		case EPopFindingFirstOfflineOp:
       
  1665 			{
       
  1666 			// This can be the current operation either during connect or
       
  1667 			// disconnect. However, we will not migrate during a disconnect,
       
  1668 			// so we can safely assume this is during connect.
       
  1669 			// This is an asynchronous operation that builds an array of 
       
  1670 			// offline requested operations that need to be performed once
       
  1671 			// connection has been established. Probably best to rebuild
       
  1672 			// the list now.
       
  1673 			User::LeaveIfError(iServerEntry->SetEntry(iServiceId));
       
  1674 			FindFirstOfflineOperationL(EFalse); // calls SetActive()
       
  1675 			break;
       
  1676 			}
       
  1677 		case EPopCancellingOfflineOps:
       
  1678 			{
       
  1679 			// nothing to stop this action when connected, therefore must be able
       
  1680 			// to handle it having been cancelled.
       
  1681 			iOfflineOpSetter->ResumeCancelOfflineOperationsL(iStatus);
       
  1682 			break;
       
  1683 			}
       
  1684 		case EPopAuthoriseAndConnect:
       
  1685 		case EPopQuitting:			// we shouldn't ever get a migration when quitting
       
  1686 		case EPopAddingOfflineOp:	// disconnected operation
       
  1687 		case EPopDisconnected:		// disconnected operation
       
  1688 		default:
       
  1689 			{
       
  1690 			__ASSERT_ALWAYS(EFalse, Panic(EPopRestartUnexpectedOp));
       
  1691 			break;
       
  1692 			}
       
  1693 		}
       
  1694 	
       
  1695 	}
       
  1696 
       
  1697 //
       
  1698 //
       
  1699 //
       
  1700 void CImppServerMtm::DoComplete(TInt aError)
       
  1701 	{
       
  1702 	CommandComplete( aError );	
       
  1703 	}
       
  1704 
       
  1705 //
       
  1706 // Open up POP3 settings store
       
  1707 //
       
  1708 void CImppServerMtm::GetPopDetailsL(const CMsvEntrySelection& aSel)
       
  1709 	{
       
  1710 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1711 	delete iPopSettings;
       
  1712 	iPopSettings=NULL;
       
  1713 	iPopSettings=new(ELeave)CImPop3Settings;
       
  1714 	delete iIAPPreferences;
       
  1715 	iIAPPreferences = NULL;
       
  1716 	iIAPPreferences = CImIAPPreferences::NewLC();
       
  1717 	CleanupStack::Pop(); // doesn't need to be on the stack!
       
  1718 	// check our entry is the service entry else use IT'S service id
       
  1719 	TInt err = iServerEntry->SetEntry(aSel[0]);
       
  1720 
       
  1721 	if (iServerEntry->Entry().iType != KUidMsvServiceEntry)
       
  1722 		{
       
  1723 		User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().iServiceId));
       
  1724 		iServiceId = iServerEntry->Entry().Id();
       
  1725 		}
       
  1726 
       
  1727 	__ASSERT_DEBUG(iServerEntry->Entry().iType==KUidMsvServiceEntry, Panic(EPopCurrentContextIsNotService));
       
  1728 	if(err == KErrNone && iServerEntry->Entry().iType != KUidMsvServiceEntry)
       
  1729 		{
       
  1730 		User::Leave(KErrNotSupported);
       
  1731 		}
       
  1732 
       
  1733 	CEmailAccounts* account = CEmailAccounts::NewLC();
       
  1734 	TPopAccount id;
       
  1735 	id.iPopAccountId = iServerEntry->Entry().MtmData2();	// iMtmData2 of the service entry contains TPopAccountId
       
  1736 	id.iPopAccountName = iServerEntry->Entry().iDetails;
       
  1737 	id.iPopService = iServerEntry->Entry().iServiceId;
       
  1738 	id.iSmtpService = iServerEntry->Entry().iRelatedId;
       
  1739 
       
  1740 	account->LoadPopSettingsL(id, *iPopSettings);
       
  1741 	account->LoadPopIapSettingsL(id, *iIAPPreferences);
       
  1742    	CleanupStack::PopAndDestroy(account);    
       
  1743 	__ASSERT_DEBUG(iServiceId==iServerEntry->Entry().Id(), Panic(EPopCurrentContextIsNotService));
       
  1744 	iServiceId = iServerEntry->Entry().Id();
       
  1745 	}
       
  1746 
       
  1747 //
       
  1748 // Async stage for cleaning up 
       
  1749 //
       
  1750 void CImppServerMtm::QueueRemoteCleanup()
       
  1751 	{
       
  1752 	TRequestStatus *pS = &iStatus;
       
  1753 	SetActive();
       
  1754 	User::RequestComplete(pS,KErrNone);
       
  1755 	}
       
  1756 
       
  1757 //
       
  1758 //  DoShowMessagesL().
       
  1759 //
       
  1760 //  Gets all the chld entries for iServiceId..   
       
  1761 //
       
  1762 //
       
  1763 void CImppServerMtm::DoShowMessagesL(TBool aShow)
       
  1764 	{
       
  1765 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1766 	if ((!iConnectedToPopMbox) && (!aShow))
       
  1767 		{
       
  1768 		return;
       
  1769 		}
       
  1770 	
       
  1771 	iConnectedToPopMbox=aShow;
       
  1772 
       
  1773 	// Leave messages displayed under the service if we are in disconnected mode.
       
  1774 	if (iPopSettings)
       
  1775 		{
       
  1776 		if ((iPopSettings->DisconnectedUserMode()))
       
  1777 			{
       
  1778 			aShow = ETrue;
       
  1779 			}
       
  1780 		}
       
  1781 
       
  1782 	if (iDoCallShowMessages==(TInt)aShow)
       
  1783 		{
       
  1784 		return;
       
  1785 		}
       
  1786 	User::LeaveIfError(iServerEntry->SetEntry( iServiceId ));
       
  1787 	__ASSERT_DEBUG(iServerEntry->Entry().Id()!=KMsvNullIndexEntryId, Panic(EPopCurrentContextIsNullEntry));
       
  1788 	if (iServerEntry->Entry().iType!=KUidMsvServiceEntry || iServerEntry->Entry().Id()==KMsvNullIndexEntryId)
       
  1789 		{
       
  1790 		return;
       
  1791 		}
       
  1792 	//  Make a new CMsvEntrySelection
       
  1793 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1794 	CleanupStack::PushL(selection);
       
  1795 	TMsvSelectionOrdering order;
       
  1796 	order.SetShowInvisibleEntries( ETrue );
       
  1797 	iServerEntry->SetSort( order );
       
  1798 	User::LeaveIfError(iServerEntry->GetChildren(*selection));
       
  1799   
       
  1800     //  Change the visible flag for each TMsvEntry in the child 
       
  1801     //  collection..
       
  1802 	if (aShow)
       
  1803 		{
       
  1804 		User::LeaveIfError(iServerEntry->ChangeAttributes(*selection, KMsvVisibilityAttribute,0));
       
  1805 		}
       
  1806 	else
       
  1807 		{
       
  1808 		User::LeaveIfError(iServerEntry->ChangeAttributes(*selection,0,KMsvVisibilityAttribute | KMsvUnreadAttribute));
       
  1809 		}
       
  1810 	CleanupStack::PopAndDestroy();  // selection
       
  1811 	iDoCallShowMessages=(TInt)aShow;
       
  1812 	}
       
  1813 
       
  1814 //
       
  1815 // Abort an MTM command if necessary
       
  1816 //
       
  1817 
       
  1818 void CImppServerMtm::CommandComplete( TInt aErrorCode )
       
  1819 	{
       
  1820 	// error code returned in the progress
       
  1821 	iPopProgress.iErrorCode = aErrorCode;
       
  1822 
       
  1823 	//check iReportStatus for cases where we have already completed the caller
       
  1824 	if(iReportStatus)
       
  1825 		{
       
  1826 		User::RequestComplete(iReportStatus, KErrNone);
       
  1827 		iReportStatus = NULL;	
       
  1828 		}
       
  1829 	}
       
  1830 
       
  1831 CMsvEntrySelection* CImppServerMtm::StripInvalidEntriesLC(const CMsvEntrySelection& aSelection, TBool aExcludePartial) const
       
  1832 	{
       
  1833 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1834 	CMsvEntrySelection* entries=aSelection.CopyLC();
       
  1835 	TMsvEntry* entry;
       
  1836 	TInt count=entries->Count();
       
  1837 	while (count--)
       
  1838 		{
       
  1839 		iServerEntry->GetEntryFromId((*entries)[count], entry);
       
  1840 		const TMsvEmailEntry &emailEntry=(*entry);
       
  1841 		if(entry->iServiceId != iServiceId || (emailEntry.PartialDownloaded() && aExcludePartial))
       
  1842 			{
       
  1843 			entries->Delete(count);
       
  1844 			}
       
  1845 		}
       
  1846 	return entries;
       
  1847 	}
       
  1848 
       
  1849 void CImppServerMtm::FindFirstOfflineOperationL(TBool aQuitting)
       
  1850 	{
       
  1851 	iState.iCurrentOperation=EPopFindingFirstOfflineOp;
       
  1852 	iOperationActive=ETrue;
       
  1853 	iOfflineOpFinder->FindFirstL(iServiceId, aQuitting, iStatus);	
       
  1854 	iState.iRunningOfflineOperations = ETrue;
       
  1855 	SetActive();
       
  1856 	MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopFindingFirstOfflineOp);
       
  1857 	}
       
  1858 
       
  1859 void CImppServerMtm::RunOfflineOperationL()
       
  1860 	{
       
  1861 	if (iOfflineOpFinder->OperationFound())
       
  1862 		{	
       
  1863 		const CImOffLineOperation& offlineOperation = iOfflineOpFinder->OfflineOperation();
       
  1864 		CMsvEntrySelection* messageSelection;
       
  1865 		iState.iCurrentOperation=EPopConnectedAndIdle;
       
  1866 		iOperationActive=EFalse;
       
  1867 
       
  1868 		switch (offlineOperation.OpType())
       
  1869 			{
       
  1870 			case CImOffLineOperation::EOffLineOpNone:
       
  1871 			case CImOffLineOperation::EOffLineOpCopyFromLocal:
       
  1872 			case CImOffLineOperation::EOffLineOpMoveFromLocal:
       
  1873 			case CImOffLineOperation::EOffLineOpMoveWithinService:
       
  1874 			case CImOffLineOperation::EOffLineOpChange:
       
  1875 			case CImOffLineOperation::EOffLineOpCreate:
       
  1876 			case CImOffLineOperation::EOffLineOpMtmSpecific:
       
  1877 				User::Leave(KErrNotSupported);
       
  1878 
       
  1879 			case CImOffLineOperation::EOffLineOpCopyToLocal:
       
  1880 				messageSelection = new (ELeave) CMsvEntrySelection;
       
  1881 				CleanupStack::PushL(messageSelection);
       
  1882 				messageSelection->AppendL(offlineOperation.MessageId());
       
  1883 				CopyToLocalL(*messageSelection, offlineOperation.TargetMessageId(),*iReportStatus);
       
  1884 				CleanupStack::PopAndDestroy(); // messageSelection
       
  1885 				break;
       
  1886 
       
  1887 			case CImOffLineOperation::EOffLineOpDelete:
       
  1888 				messageSelection = new (ELeave) CMsvEntrySelection;
       
  1889 				CleanupStack::PushL(messageSelection);
       
  1890 				messageSelection->AppendL(offlineOperation.MessageId());
       
  1891 				DeleteAllL(*messageSelection, *iReportStatus);
       
  1892 				CleanupStack::PopAndDestroy(); // messageSelection
       
  1893 				break;
       
  1894 
       
  1895 			case CImOffLineOperation::EOffLineOpCopyWithinService:
       
  1896 				messageSelection = new (ELeave) CMsvEntrySelection;
       
  1897 				CleanupStack::PushL(messageSelection);
       
  1898 				messageSelection->AppendL(offlineOperation.MessageId());
       
  1899 				CopyWithinServiceL(*messageSelection, offlineOperation.TargetMessageId(),*iReportStatus);
       
  1900 				CleanupStack::PopAndDestroy(); // messageSelection
       
  1901 				break;
       
  1902 
       
  1903 			case CImOffLineOperation::EOffLineOpMoveToLocal:
       
  1904 				messageSelection = new (ELeave) CMsvEntrySelection;
       
  1905 				CleanupStack::PushL(messageSelection);
       
  1906 				messageSelection->AppendL(offlineOperation.MessageId());
       
  1907 				MoveToLocalL(*messageSelection, offlineOperation.TargetMessageId(),*iReportStatus);
       
  1908 				CleanupStack::PopAndDestroy(); // messageSelection
       
  1909 				break;
       
  1910 			default:
       
  1911 				User::Leave(KErrNotSupported);
       
  1912 				break;
       
  1913 			}
       
  1914 		}
       
  1915 	else
       
  1916 		{
       
  1917 		iState.iRunningOfflineOperations = EFalse;
       
  1918 		if (iState.iQuitting)
       
  1919 			{
       
  1920 			// Run the actual quit operation now.
       
  1921 			iState.iCurrentOperation=EPopQuitting;
       
  1922 			ResetProgress();
       
  1923 			//iPopSession->Quit(iStatus);
       
  1924 			iSessionManager->DeleteSession(*iPopSession, iStatus);
       
  1925 			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopQuitting);
       
  1926 			iPopSession=NULL;
       
  1927 			iOperationActive=ETrue;
       
  1928 			SetActive();
       
  1929 			}
       
  1930 		else
       
  1931 			{
       
  1932 			iState.iCurrentOperation=EPopConnectedAndIdle;
       
  1933 			iOperationActive=EFalse;
       
  1934 			}
       
  1935 		}
       
  1936 	}
       
  1937 
       
  1938 
       
  1939 TBool CImppServerMtm::AcceptingOfflineOperationsL(const CMsvEntrySelection& aSelection)
       
  1940 // Returns true if the POPS MTM can accept an offline operation.
       
  1941 	{
       
  1942 	if (iPopSettings == 0)
       
  1943 		{
       
  1944 		GetPopDetailsL(aSelection);
       
  1945 		}
       
  1946 
       
  1947 	return ((iState.iCurrentOperation == EPopDisconnected) && (iPopSettings->DisconnectedUserMode()));
       
  1948 	}
       
  1949 
       
  1950 
       
  1951 void CImppServerMtm::AddOfflineOperationL(const CMsvEntrySelection& aSelection, TMsvId aDestination, CImOffLineOperation::TOffLineOpType aOperationType, TRequestStatus& aStatus)
       
  1952 // Asynchronously applies the given operation type to the given selection of
       
  1953 // messages. The destination parameter is ignored for some operations, eg. delete.
       
  1954 	{
       
  1955 	if (iState.iCurrentOperation == EPopConnectedAndIdle)
       
  1956 		{
       
  1957 		Cancel();
       
  1958 		}
       
  1959 
       
  1960 	iOfflineOpSetter->AddOfflineOperationL(&aSelection, aOperationType, aDestination, iStatus);
       
  1961 	iState.iCurrentOperation = EPopAddingOfflineOp;
       
  1962 	iReportStatus=&aStatus;
       
  1963 	ResetProgress();		
       
  1964 	SetActive();
       
  1965 	aStatus = KRequestPending;
       
  1966 	iOperationActive = ETrue;
       
  1967 	}
       
  1968 
       
  1969 void CImppServerMtm::CancelOfflineOperationsL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
  1970 	{
       
  1971 	Cancel();
       
  1972 	iOfflineOpSetter->CancelOfflineOperationsL(aSelection, iStatus);
       
  1973 	iState.iCurrentOperation = EPopCancellingOfflineOps;
       
  1974 	iReportStatus=&aStatus;
       
  1975 	ResetProgress();		
       
  1976 	SetActive();
       
  1977 	aStatus = KRequestPending;
       
  1978 	iOperationActive = ETrue;
       
  1979 	}
       
  1980 
       
  1981 //
       
  1982 // constructor
       
  1983 //
       
  1984 CImppServerMtm::CImppServerMtm(CRegisteredMtmDll& aPopServerMtmDll, CMsvServerEntry* aEntry)
       
  1985 :CBaseServerMtm(aPopServerMtmDll, aEntry)
       
  1986 	{
       
  1987 	}
       
  1988 
       
  1989 void CImppServerMtm::ConstructL()
       
  1990 	{
       
  1991 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  1992 	CActiveScheduler::Add(this);
       
  1993 	iConnectedToPopMbox=EFalse;
       
  1994 	iOperationActive=EFalse;
       
  1995 	iDoCallShowMessages=-1;
       
  1996 	ResetProgress();
       
  1997 	iServiceId=iServerEntry->Entry().Id();
       
  1998 
       
  1999 #if (defined SYMBIAN_USER_PROMPT_SERVICE)	
       
  2000 	iWaiter = CPopUpsResponseWaiter::NewL();
       
  2001 	iHasCapability = ETrue;
       
  2002 #endif
       
  2003 	
       
  2004 	iOfflineOpFinder = CImPop3OfflineOperationFinder::NewL(*iServerEntry);
       
  2005 	iOfflineOpSetter = CImPop3SetOfflineOps::NewL(*iServerEntry);
       
  2006 	iState.iCurrentOperation = EPopDisconnected;
       
  2007 	iCancelForBMMigration = EFalse;
       
  2008 	iMigrationState = ENotMigrating;
       
  2009 	iNotConnectToPopMailBox = ETrue ;
       
  2010 	TRAP_IGNORE( iLogMessage=CImLogMessage::NewL( iServerEntry->FileSession() ) );
       
  2011 	}
       
  2012 
       
  2013 CImppServerMtm::~CImppServerMtm()
       
  2014 	{
       
  2015 	Cancel();
       
  2016 
       
  2017 	if (iServerEntry->Entry().Id()!=KMsvNullIndexEntryId)
       
  2018 		{
       
  2019 		TRAP_IGNORE( DoShowMessagesL(EFalse) );
       
  2020 		TInt err = iServerEntry->SetEntry(iServiceId);
       
  2021 
       
  2022 		if (err == KErrNone)
       
  2023 			{
       
  2024 			TMsvEntry entry = iServerEntry->Entry();
       
  2025 			if (entry.Connected())
       
  2026 				{
       
  2027 				entry.SetConnected( EFalse );
       
  2028 				iServerEntry->ChangeEntry( entry );	// ignore any error
       
  2029 				}
       
  2030 			}
       
  2031 		}
       
  2032 
       
  2033 	delete iPopSession;
       
  2034 	delete iPopRefreshMailbox;
       
  2035 	delete iPopCopyMove;
       
  2036 	delete iPopDelete;
       
  2037 	delete iPopSettings;
       
  2038 	delete iIAPPreferences;
       
  2039 	delete iMsvIdArray;
       
  2040 	delete iOfflineOpFinder;
       
  2041 	delete iOfflineOpSetter;
       
  2042 	delete iLogMessage;
       
  2043 	delete iMessagesToKeep;
       
  2044 	delete iPopTopPop;
       
  2045 #if (defined SYMBIAN_USER_PROMPT_SERVICE)	
       
  2046  	delete iWaiter;
       
  2047 #endif
       
  2048 
       
  2049 	delete iMobilityManager;
       
  2050 	delete iSessionManager;	
       
  2051 	if(iSavedValuesForMigration.iValuesSaved)
       
  2052 		{
       
  2053 		// We are leaving before ownership of Message Array was passed to PopSession
       
  2054 		delete iSavedValuesForMigration.iMessageArray;
       
  2055 		}
       
  2056  	}
       
  2057 
       
  2058 
       
  2059 TBool CImppServerMtm::PruneMessages(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
  2060 	{
       
  2061 	TInt index = aSelection.Count();
       
  2062 	
       
  2063 	// See if the parent of the first entry is a message.
       
  2064 	// If it is then we need to prune the entries, ie. delete them locally.
       
  2065 	if (index == 0)
       
  2066 		{
       
  2067 		return EFalse;
       
  2068 		}
       
  2069 
       
  2070 	TInt err = iServerEntry->SetEntry(aSelection[0]);
       
  2071 
       
  2072 	if (err == KErrNone)
       
  2073 		{
       
  2074 		err = iServerEntry->SetEntry(iServerEntry->Entry().Parent());
       
  2075 		if (KUidMsvMessageEntry != iServerEntry->Entry().iType)
       
  2076 			{
       
  2077 			// The parent of the given entry was not a message, so we don't prune it.
       
  2078 			return EFalse;
       
  2079 			}
       
  2080 		}
       
  2081 
       
  2082 	while ((index--) && (err==KErrNone))
       
  2083 		{
       
  2084 		// Go to the required entry
       
  2085 		err = iServerEntry->SetEntry(aSelection[index]);
       
  2086 
       
  2087 		if (KErrNone == err)
       
  2088 			{
       
  2089 			// Go to the parent entry to see if it is a message entry
       
  2090 			iServerEntry->SetEntry(iServerEntry->Entry().Parent());
       
  2091 			TMsvEmailEntry entry = iServerEntry->Entry();
       
  2092 
       
  2093 			// Clear the complete flag because we are about to delete the child parts.
       
  2094 			entry.SetComplete(EFalse);
       
  2095 			entry.SetBodyTextComplete(EFalse);
       
  2096 			err = iServerEntry->ChangeEntry(entry);
       
  2097 
       
  2098 			if (KErrNone == err)
       
  2099 				{
       
  2100 				// Delete the body of the message.
       
  2101 				iServerEntry->DeleteEntry(aSelection[index]);
       
  2102 				}
       
  2103 			}
       
  2104 		}
       
  2105 	if (err == KErrNone)
       
  2106 		{
       
  2107   		err = iServerEntry->SetEntry(KMsvNullIndexEntryId);
       
  2108 		}
       
  2109 
       
  2110 	TRequestStatus* status = &aStatus;
       
  2111 	User::RequestComplete(status, err);
       
  2112 
       
  2113 	return ETrue;
       
  2114 	}
       
  2115 
       
  2116 /**
       
  2117 Notice that a preferred carrier has become available, and migration to that bearer has been 
       
  2118 accepted.  The Pop Server MTM shall either pause or allow any current operation to complete
       
  2119 according to the action specified in parameter aAction. Once the current operation is paused 
       
  2120 or complete, the Pop Server MTM shall close any existing sockets and finally notify the 
       
  2121 mobility framework that it is ready to migrate to the new carrier.
       
  2122 
       
  2123 @param aAction      - indicates the action that should be taken re: current operations
       
  2124 @param aIsSeamless  - indicates if the Bearer is seamless.
       
  2125 */
       
  2126 void CImppServerMtm::PrepareForNewCarrier(TImMobilityAction aAction, TBool /*aIsSeamless*/)
       
  2127 	{
       
  2128 	// if the action is to accept immediately, CancelToMigrate can handle any current state...
       
  2129 	if (aAction == KAcceptImmediately)
       
  2130 		{
       
  2131 		if (iPopSession)
       
  2132 			{
       
  2133 			TRAP_IGNORE(StoreConfigurationToMigrateL());
       
  2134 			}
       
  2135 
       
  2136 		// Accept the migration immediately, and delete any current activity
       
  2137 		CancelToMigrate();
       
  2138 		iMigrationState = EWaitingForNewCarrier;
       
  2139 		iMobilityManager->MigrateToNewCarrier();
       
  2140 
       
  2141 		// do not set waiting if NewCarrierActive has been called synchronously.
       
  2142 		if (iMigrationState == EWaitingForNewCarrier)
       
  2143 			{
       
  2144 			// Now in a waiting state, set self active
       
  2145 			iStatus = KRequestPending;
       
  2146 			SetActive();
       
  2147 			}		
       
  2148 		}
       
  2149 	else	// ...otherwise, we need to handle being called in different migration states
       
  2150 		{
       
  2151 		switch (iMigrationState)
       
  2152 			{
       
  2153 			case ENotMigrating:
       
  2154 				{
       
  2155 				// allow any op in progress to complete, or stop when convenient,
       
  2156 				// according to the specified action
       
  2157 				if (aAction == KAcceptCompleteCurrent)
       
  2158 					{
       
  2159 					CompleteCurrentOpForMigration();
       
  2160 					}
       
  2161 				else // aAction == KAcceptStopCurrent
       
  2162 					{
       
  2163 					StopCurrentOpForMigration();
       
  2164 					}
       
  2165 				break;
       
  2166 				}
       
  2167 			case EWaitingForOpToComplete:
       
  2168 				{
       
  2169 				// override a previous complete action with a stop...
       
  2170 				if (aAction == KAcceptStopCurrent)
       
  2171 					{
       
  2172 					StopCurrentOpForMigration();
       
  2173 					}
       
  2174 				break;
       
  2175 				}
       
  2176 			case EWaitingForOpToStop:
       
  2177 			case EDisconnectingForMigrate:
       
  2178 				{
       
  2179 				// already stopping, do NOT override a stop action with a complete action
       
  2180 				break;
       
  2181 				}
       
  2182 			case EWaitingForNewCarrier:
       
  2183 			case EWaitingCarrierRejected:
       
  2184 				{
       
  2185 				// aleady ready and waiting for a new carrier. Tell the mobility manager,
       
  2186 				// but no further action necessary
       
  2187 				iMobilityManager->MigrateToNewCarrier();
       
  2188 				break;
       
  2189 				}
       
  2190 			case EConnectingAfterMigrate:
       
  2191 				{
       
  2192 				// Cancel the (re)connect operation, and inform the mobility manager
       
  2193 				CancelToMigrate();
       
  2194 				iMigrationState = EWaitingForNewCarrier;
       
  2195 				iMobilityManager->MigrateToNewCarrier();
       
  2196 
       
  2197 				// do not set waiting if NewCarrierActive has been called synchronously.
       
  2198 				if (iMigrationState == EWaitingForNewCarrier)
       
  2199 					{
       
  2200 					// Now in a waiting state, set self active
       
  2201 					iStatus = KRequestPending;
       
  2202 					SetActive();
       
  2203 					}
       
  2204 				break;
       
  2205 				}
       
  2206 			default:
       
  2207 				{			
       
  2208 				__ASSERT_ALWAYS(EFalse, Panic(EPopNewCarrierUnknownState));
       
  2209 				break;	
       
  2210 				}			
       
  2211 			} // end of switch (iMigrationState)
       
  2212 		} // end of else...
       
  2213 	}
       
  2214 
       
  2215 /**
       
  2216 Handles the completion of operations in order to migrate.  This is called by the 
       
  2217 PrepareForNewCarrier() function, when it is called by the mobility manager with 
       
  2218 the mobility action CompleteCurrentOpForMigration.
       
  2219 */
       
  2220 void CImppServerMtm::CompleteCurrentOpForMigration()
       
  2221 	{
       
  2222 	iMigrationState = EWaitingForOpToComplete;
       
  2223 	switch(iState.iCurrentOperation)
       
  2224 		{
       
  2225 		case EPopRefreshing:
       
  2226 		case EPopTidying:
       
  2227 		case EPopCopying:
       
  2228 		case EPopMoving:
       
  2229 		case EPopPopulating:
       
  2230 		case EPopTopPopulating:
       
  2231 		case EPopDeleting:
       
  2232 		case EPopFindingFirstOfflineOp:
       
  2233 		case EPopCancellingOfflineOps:
       
  2234 			{
       
  2235 			// Just allow these operations to complete, handle in DoRunL
       
  2236 			break;
       
  2237 			}
       
  2238 		case EPopConnectedAndIdle:
       
  2239 			{
       
  2240 			// The POP Server MTM sets itself into a dummy active state when it enters
       
  2241 			// the EPopConnectedAndIdle state so we must cancel this active state
       
  2242 			CancelToMigrate();
       
  2243 			// Kick off the disconnect immediately. DoRunL is complex enough as it is.
       
  2244 			DisconnectForMigrate();
       
  2245 			break;
       
  2246 			}
       
  2247 		case EPopAuthoriseAndConnect:
       
  2248 		case EPopAddingOfflineOp:	// offline only
       
  2249 		case EPopDisconnected:		// offline
       
  2250 		case EPopConnecting: 		// haven't registered for bearer events in this state
       
  2251 		case EPopQuitting:			// deregistered
       
  2252 		default:
       
  2253 			{			
       
  2254 			__ASSERT_ALWAYS(EFalse, Panic(EPopCompleteOpUnexpectedOp));
       
  2255 			break;	
       
  2256 			}
       
  2257 		}
       
  2258 	}
       
  2259 
       
  2260 /**
       
  2261 Handles the halting of operations in order to migrate.  This is called by the 
       
  2262 PrepareForNewCarrier() function, when it is called by the mobility manager with 
       
  2263 the mobility action StopCurrentOpForMigration.
       
  2264 */
       
  2265 void CImppServerMtm::StopCurrentOpForMigration()
       
  2266 	{
       
  2267 	iMigrationState = EWaitingForOpToStop;
       
  2268 	// Signal the current operation handler to stop when convenient...
       
  2269 	switch (iState.iCurrentOperation)
       
  2270 		{
       
  2271 		case EPopTidying: 				// self completed state - handle in DoMigrateRunL
       
  2272 		case EPopFindingFirstOfflineOp: // self completed state - handle in DoMigrateRunL
       
  2273 		case EPopCancellingOfflineOps:	// allow to finish.
       
  2274 			{
       
  2275 			break;
       
  2276 			}
       
  2277 		case EPopCopying:
       
  2278 		case EPopMoving:
       
  2279 		case EPopPopulating:
       
  2280 			{
       
  2281 			iPopCopyMove->Pause();
       
  2282 			break;
       
  2283 			}
       
  2284 		case EPopTopPopulating:
       
  2285 			{
       
  2286 			iPopTopPop->Pause();
       
  2287 			break;
       
  2288 			}
       
  2289 		case EPopDeleting:
       
  2290 			{
       
  2291 			iPopDelete->Pause();
       
  2292 			break;
       
  2293 			}
       
  2294 		case EPopRefreshing:
       
  2295 			{	
       
  2296 			iPopRefreshMailbox->Pause();
       
  2297 			break;
       
  2298 			}
       
  2299 		case EPopConnectedAndIdle:
       
  2300 			{
       
  2301 			// The POP Server MTM sets itself into a dummy active state when it enters
       
  2302 			// the EPopConnectedAndIdle state so we must cancel this active state
       
  2303 			CancelToMigrate();
       
  2304 			// Kick off the disconnect immediately. DoRunL is complex enough as it is.
       
  2305 			DisconnectForMigrate();
       
  2306 			break;
       
  2307 			}
       
  2308 		case EPopAuthoriseAndConnect:  // not yet registered
       
  2309 		case EPopConnecting: 			// not yet registered
       
  2310 		case EPopQuitting:				// deregistered...
       
  2311 		case EPopDisconnected:			// offline
       
  2312 		case EPopAddingOfflineOp:		// offline
       
  2313 		default:
       
  2314 			{			
       
  2315 			__ASSERT_ALWAYS(EFalse, Panic(EPopStopOpUnexpectedOp));
       
  2316 			break;
       
  2317 			}
       
  2318 		}
       
  2319 	}
       
  2320 
       
  2321 /**
       
  2322 This function may be called directly by the Mobility Manager in the case
       
  2323 that a downgrade notification has been received from the networking layer.
       
  2324 On return from this function, the server MTM must have cancelled any operations
       
  2325 on the existing pop session with resume enabled.
       
  2326 
       
  2327 It may be called at any time, including when a migration is already in progress.
       
  2328 */
       
  2329 void CImppServerMtm::CarrierLost()
       
  2330 	{
       
  2331 	if (iPopSession)
       
  2332 		{
       
  2333 		TRAP_IGNORE(StoreConfigurationToMigrateL());
       
  2334 		}
       
  2335 
       
  2336 	// DoCancel() handles all migration states.
       
  2337 	CancelToMigrate();
       
  2338 	
       
  2339 	// Calling Cancel() doesnt *always* cause the iPopSession to be deleted,
       
  2340 	// for example, if in EPopConnectedAndIdle state. Just make sure:
       
  2341 	delete iPopSession;
       
  2342 	iPopSession = NULL;
       
  2343 	
       
  2344 	// Now that the current activity has been stopped, just need to wait for
       
  2345 	// a new carrier to come available. Set state and dummy request pending
       
  2346 	iMigrationState = EWaitingForNewCarrier;
       
  2347 	iStatus = KRequestPending;
       
  2348 	SetActive();
       
  2349 	}
       
  2350 	
       
  2351 /**
       
  2352 Notice that the New Carrier is now active and the server MTM can make connections on it.
       
  2353 Once this notice is received from the Mobility Manager, the Server MTM can create a new 
       
  2354 session on it and restart any awaiting operations on the New Carrier.  These could be 
       
  2355 operations that were stopped mid-way and need resuming from there or operations(requests)
       
  2356 that were cancelled and need starting from beginning.
       
  2357 @param aNewApp 		- acces point information.
       
  2358 @param aIsSeamless 	- Flag to indicate whether the migration is seamless.
       
  2359 */
       
  2360 void CImppServerMtm::NewCarrierActive(TAccessPointInfo /*aNewAp*/, TBool /*aIsSeamless*/)
       
  2361 	{
       
  2362 	__ASSERT_DEBUG((iMigrationState == EWaitingForNewCarrier ||
       
  2363 	                iMigrationState == EWaitingCarrierRejected),
       
  2364 	               Panic(EPopUnexpectedNewCarrierActive));
       
  2365 
       
  2366 	// Complete the request as the New carrier we were waiting on is now active
       
  2367 	// This will enable us to get back into the Server MTM state machine, 
       
  2368 	// initially dealing with the migration states and later with the MTM states if needed.
       
  2369 	TRequestStatus* status = &iStatus;
       
  2370 	User::RequestComplete(status, KErrNone);
       
  2371 	}
       
  2372 
       
  2373 /**
       
  2374 Handles Migration Errors
       
  2375 
       
  2376 Simply deletes everything, marks the server offline and completes any 
       
  2377 outstanding user requests.
       
  2378 
       
  2379 @param aError - An error code indicating the type of migration error.
       
  2380 */
       
  2381 void CImppServerMtm::MobilityError(TUint /*aError*/)
       
  2382 	{
       
  2383 	__ASSERT_ALWAYS(iServerEntry, Panic(EPopNullPointer));
       
  2384 	
       
  2385 	// use special form of Cancel() to make sure we complete while
       
  2386 	// reporting the correct error code. Using this means owned operation
       
  2387 	// classes must be explicitly deleted here.
       
  2388 	CancelToMigrate();
       
  2389 	
       
  2390 	// delete the mobility manager	
       
  2391 	delete iMobilityManager;
       
  2392 	iMobilityManager = NULL;
       
  2393 	
       
  2394 	// delete operation classes
       
  2395 	delete iPopRefreshMailbox;
       
  2396 	iPopRefreshMailbox = NULL;
       
  2397 	delete iPopCopyMove;
       
  2398 	iPopCopyMove = NULL;
       
  2399 	delete iPopDelete;
       
  2400 	iPopDelete = NULL;
       
  2401 	delete iPopTopPop;
       
  2402 	iPopTopPop = NULL;
       
  2403 
       
  2404 	// and the session
       
  2405 	delete iPopSession;
       
  2406 	iPopSession = NULL;
       
  2407 
       
  2408 	// and the session manager - error might be a result of the RConnection
       
  2409 	delete iSessionManager;	
       
  2410 	iSessionManager = NULL;
       
  2411 	
       
  2412 	// tidyup
       
  2413 	iState.iQuitting = EFalse;
       
  2414 	TRAP_IGNORE( DoShowMessagesL(EFalse) );
       
  2415 	
       
  2416 	TInt err = iServerEntry->SetEntry( iServiceId );
       
  2417 	if(err == KErrNone)
       
  2418 		{
       
  2419 		TMsvEntry entry = iServerEntry->Entry();
       
  2420 		entry.SetConnected( EFalse );
       
  2421 		iServerEntry->ChangeEntry( entry );	// ignore any error
       
  2422 		}
       
  2423 
       
  2424 	// If their is an outstanding command, then complete it with the error
       
  2425 	CommandComplete( KErrDisconnected );
       
  2426 
       
  2427 	// final tidyup
       
  2428 	iServerEntry->SetEntry(KMsvNullIndexEntryId);
       
  2429 	iState.iCurrentOperation = EPopDisconnected;
       
  2430 	}
       
  2431 
       
  2432 /**
       
  2433 Returns Progress info for Migration purposes
       
  2434 */
       
  2435 const TDesC8& CImppServerMtm::MobilityProgress()
       
  2436 	{
       
  2437 	return Progress();
       
  2438 	}
       
  2439 
       
  2440 /**
       
  2441 Gets MTM information that is not related to the current operation
       
  2442 
       
  2443 @param aMtmDataType Type of data to fetch
       
  2444 @param aMtmDataBuffer On return this points to a descriptor holding the data
       
  2445 
       
  2446 @return KErrNone if successful, or a system wide error code
       
  2447 */
       
  2448 TInt CImppServerMtm::GetNonOperationMtmData(TNonOperationMtmDataType aMtmDataType, TPtrC8& aMtmDataBuffer)
       
  2449 	{
       
  2450 	if (aMtmDataType == EMtmDataAccessPointId)
       
  2451 		{
       
  2452 		if (iSessionManager)
       
  2453 			{
       
  2454 			TNonOperationMtmDataAccessPointId mtmDataAccessPointId;
       
  2455 
       
  2456 			TInt err = iSessionManager->GetAccessPointIdForConnection(mtmDataAccessPointId.iAccessPointId);
       
  2457 
       
  2458 			if (err == KErrNone)
       
  2459 				{
       
  2460 				iMtmDataAccessPointIdBuffer = TNonOperationMtmDataAccessPointIdBuffer(mtmDataAccessPointId);
       
  2461 				aMtmDataBuffer.Set(iMtmDataAccessPointIdBuffer);
       
  2462 				return KErrNone;
       
  2463 				}
       
  2464 			}
       
  2465 
       
  2466 		return KErrNotFound;
       
  2467 		}
       
  2468 	return KErrNotSupported;
       
  2469 	}
       
  2470 
       
  2471 /**
       
  2472 Creates the mobility manager and registers the RConnection for notification of
       
  2473 bearer migration events, if the necessary conditions are met.
       
  2474 
       
  2475 Returns ETrue if mobility enabled and the initial carrier has been rejected.
       
  2476 
       
  2477 @param  aError completion code of the session connect async operation
       
  2478 @return ETrue  if the initial carrier has been rejected (DoRunL should return)
       
  2479 		EFalse otherwise, DoRunL processing should continue
       
  2480 */
       
  2481 TBool CImppServerMtm::StartBearerMobilityL(TInt aError)
       
  2482 	{
       
  2483 	// Connection operation complete. If the account supports bearer mobility
       
  2484 	// register now for bearer event notifications. 
       
  2485 	if (iPopSettings->BearerMobility() && iIAPPreferences->SNAPDefined())
       
  2486 		{
       
  2487 		// only create iMobilityManager once per connection request - we can be at this
       
  2488 		// point due an initial carrier rejected followed by successful migration...
       
  2489 		// also, check that the session manager has an RConnection. If not, bomb out.
       
  2490 		if (!iMobilityManager && iSessionManager->HasConnection())
       
  2491 			{
       
  2492 			iMobilityManager = CImMobilityManager::NewL(KUidPop3ServerMtm, iServiceId, *this);
       
  2493 			iMobilityManager->SetConnection(iSessionManager->GetConnection());
       
  2494 
       
  2495 			// if there has been a problem connecting the session, reject the current carrier
       
  2496 			// via the migration manager, and wait for a new bearer available notification.
       
  2497 			if (aError != KErrNone)
       
  2498 				{
       
  2499 				iMigrationState = EWaitingCarrierRejected;
       
  2500 				iMobilityManager->NewCarrierRejected();
       
  2501 				
       
  2502 				// do not set waiting if NewCarrierActive has been called synchronously.
       
  2503 				if (iMigrationState == EWaitingCarrierRejected)
       
  2504 					{
       
  2505 					// Now in a waiting state, set self active
       
  2506 					iStatus = KRequestPending;
       
  2507 					SetActive();
       
  2508 					}
       
  2509 				return ETrue;
       
  2510 				} // end if (eCode != KErrNone)
       
  2511 			} // end if (!iMobilityManager && iSessionManager->HasConnection())
       
  2512 		} // end if (iPopSettings->BearerMobility() && iIAPPreferences->SNAPDefined())
       
  2513 	return EFalse;
       
  2514 	}