|         |      1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). | 
|         |      2 // All rights reserved. | 
|         |      3 // This component and the accompanying materials are made available | 
|         |      4 // under the terms of "Eclipse Public License v1.0" | 
|         |      5 // which accompanies this distribution, and is available | 
|         |      6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". | 
|         |      7 // | 
|         |      8 // Initial Contributors: | 
|         |      9 // Nokia Corporation - initial contribution. | 
|         |     10 // | 
|         |     11 // Contributors: | 
|         |     12 // | 
|         |     13 // Description: | 
|         |     14 // | 
|         |     15  | 
|         |     16 #include "cimapcompoundcreate.h" | 
|         |     17 #include "cimapfolder.h" | 
|         |     18 #include "cimapsyncmanager.h" | 
|         |     19 #include "cimapsessionconsts.h" | 
|         |     20 #include "cimaplogger.h" | 
|         |     21 #include "imappaniccodes.h" | 
|         |     22  | 
|         |     23 #include "mobilitytestmtmapi.h" | 
|         |     24  | 
|         |     25 CImapCompoundCreate::CImapCompoundCreate(CImapSyncManager& aSyncManager, | 
|         |     26 						 				 CMsvServerEntry& aServerEntry, | 
|         |     27 						 				 CImapSettings& aImapSettings, | 
|         |     28 						 				 const TMsvId aParent, | 
|         |     29 						 				 const TBool aIsFolder) : | 
|         |     30 	CImapCompoundBase(aSyncManager, aServerEntry, aImapSettings), | 
|         |     31 	iParentId(aParent), iIsFolder(aIsFolder) | 
|         |     32 	 | 
|         |     33 	{ | 
|         |     34 	 | 
|         |     35 	} | 
|         |     36  | 
|         |     37 CImapCompoundCreate::~CImapCompoundCreate() | 
|         |     38 	{ | 
|         |     39 	delete iLeafName; | 
|         |     40 	iFolderList.ResetAndDestroy(); | 
|         |     41 	} | 
|         |     42 	 | 
|         |     43 CImapCompoundCreate* CImapCompoundCreate::NewL(CImapSyncManager& aSyncManager, | 
|         |     44 						 				  	   CMsvServerEntry& aServerEntry, | 
|         |     45 						 				  	   CImapSettings& aImapSettings, | 
|         |     46 											   const TMsvId aParent,  | 
|         |     47 						  					   const TDesC& aLeafName,  | 
|         |     48 						  					   const TBool aIsFolder) | 
|         |     49 	{ | 
|         |     50 	CImapCompoundCreate* self = new (ELeave) CImapCompoundCreate(aSyncManager, | 
|         |     51 																 aServerEntry, | 
|         |     52 																 aImapSettings, | 
|         |     53 																 aParent, | 
|         |     54 																 aIsFolder); | 
|         |     55 	CleanupStack::PushL(self); | 
|         |     56 	self->ConstructL(aLeafName); | 
|         |     57 	CleanupStack::Pop(self); | 
|         |     58 	return self; | 
|         |     59 	} | 
|         |     60  | 
|         |     61 void CImapCompoundCreate::ConstructL(const TDesC& aLeafName) | 
|         |     62 	{ | 
|         |     63 	iLeafName = aLeafName.AllocL(); | 
|         |     64 	 | 
|         |     65 	// Add to the active scheduler | 
|         |     66 	CActiveScheduler::Add(this); | 
|         |     67 	} | 
|         |     68  | 
|         |     69 	 | 
|         |     70 void CImapCompoundCreate::StartOperation(TRequestStatus& aStatus, CImapSession& aSession) | 
|         |     71 	{ | 
|         |     72 	iSession = &aSession; | 
|         |     73 	__LOG_TEXT(iSession->LogId(), "CImapCompoundCreate::StartOperation()"); | 
|         |     74 	iNextStep = ECreate; | 
|         |     75 	Queue(aStatus); | 
|         |     76 	CompleteSelf(); | 
|         |     77 	} | 
|         |     78  | 
|         |     79 /** | 
|         |     80 Handles the compound operation state machine | 
|         |     81  | 
|         |     82 @return ETrue if compound operation is completed,  | 
|         |     83 		EFalse otherwise. | 
|         |     84 */	 | 
|         |     85 TBool CImapCompoundCreate::DoRunLoopL() | 
|         |     86 	{ | 
|         |     87 	SetCurrentStep(); | 
|         |     88 	switch (iCurrentStep) | 
|         |     89 		{ | 
|         |     90 		case ECreate:		// asynchronous | 
|         |     91 			{ | 
|         |     92 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCreateFolder); | 
|         |     93 			// Make the folder/mailbox name to create | 
|         |     94 			HBufC* newFolderPath = MakeFolderNameL(iParentId, *iLeafName, iIsFolder); | 
|         |     95 			CleanupStack::PushL(newFolderPath); | 
|         |     96 			 | 
|         |     97 			iSession->CreateL(iStatus, *newFolderPath); | 
|         |     98  | 
|         |     99 			CleanupStack::PopAndDestroy(newFolderPath); | 
|         |    100  | 
|         |    101 			iProgressState = TImap4GenericProgress::EBusy; | 
|         |    102 			iNextStep = ECreateLocal; | 
|         |    103 			SetActive(); | 
|         |    104 			break; | 
|         |    105 			} | 
|         |    106 		 | 
|         |    107 		case ECheckFolderExists: | 
|         |    108 			{ | 
|         |    109 			// This state allows to check if a folder already exists remotely. | 
|         |    110 			// It is entered if a migration occurs during the create state, | 
|         |    111 			// and is used to determine if the CREATE succeeded, even though we | 
|         |    112 			// did not receive a response prior to the operation being cancelled | 
|         |    113 			// to allow the migration to occur. | 
|         |    114 			__LOG_TEXT(iSession->LogId(), "CImapSessionManager::ECheckFolderExists"); | 
|         |    115  | 
|         |    116 			// Make the folder/mailbox name to create | 
|         |    117 			HBufC* newFolderPath = MakeFolderNameL(iParentId, *iLeafName, iIsFolder); | 
|         |    118 			CleanupStack::PushL(newFolderPath); | 
|         |    119 			 | 
|         |    120 			iFolderList.ResetAndDestroy(); | 
|         |    121 			iSession->ListL(iStatus, KNullDesC(), *newFolderPath, iFolderList); | 
|         |    122 			 | 
|         |    123 			CleanupStack::PopAndDestroy(newFolderPath); | 
|         |    124  | 
|         |    125 			iNextStep = EProcessFolderCheck; | 
|         |    126 			SetActive(); | 
|         |    127 			break; | 
|         |    128 			} | 
|         |    129  | 
|         |    130 		case EProcessFolderCheck: | 
|         |    131 			{ | 
|         |    132 			if (iFolderList.Count()==0) | 
|         |    133 				{ | 
|         |    134 				// the folder does not exist remotely - (re)send the CREATE | 
|         |    135 				iNextStep = ECreate; | 
|         |    136 				} | 
|         |    137 			else | 
|         |    138 				{ | 
|         |    139 				// the folder exists on the remote server - create a local copy | 
|         |    140 				iNextStep = ECreateLocal; | 
|         |    141 				} | 
|         |    142 			return EFalse; | 
|         |    143 			} | 
|         |    144 		 | 
|         |    145 		case ECreateLocal: 	// synchronous | 
|         |    146 			{	 | 
|         |    147 			CreateLocalFolderL(); | 
|         |    148 			iNextStep = EFinished; | 
|         |    149 			// fall through | 
|         |    150 			} | 
|         |    151 			 | 
|         |    152 		case EFinished:		// finished | 
|         |    153 			{ | 
|         |    154 			__LOG_TEXT(iSession->LogId(), "CImapCompoundCreate::Completing OK"); | 
|         |    155 			iProgressState = TImap4GenericProgress::EIdle; | 
|         |    156 			Complete(KErrNone); | 
|         |    157 			return ETrue; | 
|         |    158 			} | 
|         |    159 			 | 
|         |    160 		default: | 
|         |    161 			{ | 
|         |    162 			__ASSERT_DEBUG(EFalse,  | 
|         |    163 			   TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundUnexpectedState)); | 
|         |    164 			// unexpected state - complete the request | 
|         |    165 			iProgressState = TImap4GenericProgress::EIdle; | 
|         |    166 			return ETrue; | 
|         |    167 			} | 
|         |    168 		} | 
|         |    169 	return EFalse; | 
|         |    170 	} | 
|         |    171  | 
|         |    172 /** | 
|         |    173 May be called in case of a genuine cancel or a cancel for migrate. | 
|         |    174 Following a genuine cancel, the compound operation will be deleted. | 
|         |    175 Following a cancel for migrate, the compound operation will be resumed, | 
|         |    176 so the iNextState is updated here to ensure the operation is | 
|         |    177 correctly restarted. | 
|         |    178  | 
|         |    179 In either case, CMsgActive::DoCancel() is called to complete the | 
|         |    180 user request with KErrCancel. | 
|         |    181  | 
|         |    182 Note that if the default CMsgActive::DoComplete() is overridden, | 
|         |    183 then that must also be modified to handle either case described above. | 
|         |    184 */ | 
|         |    185 void CImapCompoundCreate::DoCancel() | 
|         |    186 	{ | 
|         |    187 	switch (iCurrentStep) | 
|         |    188 		{ | 
|         |    189 		case ECreate: | 
|         |    190 		case ECheckFolderExists: | 
|         |    191 			{ | 
|         |    192 			// outstanding request is on session | 
|         |    193 			iSession->Cancel(); | 
|         |    194 			iNextStep = ECheckFolderExists; | 
|         |    195 			break; | 
|         |    196 			} | 
|         |    197 		case EProcessFolderCheck: | 
|         |    198 		case ECreateLocal: | 
|         |    199 		case EFinished: | 
|         |    200 			{ | 
|         |    201 			// self-completed or no outstanding request. | 
|         |    202 			break; | 
|         |    203 			} | 
|         |    204 		case ESuspendedForMigrate: | 
|         |    205 		default: | 
|         |    206 			{ | 
|         |    207 			__ASSERT_DEBUG(EFalse, | 
|         |    208 			   TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundCancelUnexpectedState)); | 
|         |    209 			break; | 
|         |    210 			} | 
|         |    211 		} // end switch (iCurrentStep) | 
|         |    212 	 | 
|         |    213 	if (!iCancelForMigrate) | 
|         |    214 		{ | 
|         |    215 		// genuine cancel - update progress | 
|         |    216 		iProgressErrorCode = KErrCancel; | 
|         |    217 		} | 
|         |    218 	CMsgActive::DoCancel(); | 
|         |    219 	} | 
|         |    220  | 
|         |    221 /** | 
|         |    222 Builds the full IMAP pathname for the folder to be created. | 
|         |    223  | 
|         |    224 @param aParent   id of the parent TMsvEntry | 
|         |    225 @param aLeafName name of the folder to be created | 
|         |    226 @param aIsFolder ETrue if the folder is to be a folder rather than a mailbox | 
|         |    227 @return a heap descriptor containing the full pathname.  Ownership is transferred to the caller. | 
|         |    228 */ | 
|         |    229 HBufC* CImapCompoundCreate::MakeFolderNameL(const TMsvId aParent,  | 
|         |    230 										  const TDesC& aLeafName, | 
|         |    231 										  const TBool aIsFolder) | 
|         |    232 	{ | 
|         |    233 	 | 
|         |    234 	// parent path is empty if creating a folder under the service entry. | 
|         |    235 	HBufC* parentpath = NULL; | 
|         |    236 	// Creates the ImapFolder without subscribe.. (EFalse is passed for not to subscribe folder) | 
|         |    237 	CImapFolder* folder = iSyncManager.GetFolderL(aParent, EFalse); | 
|         |    238 	if (aParent!=iImapSettings.ServiceId()) | 
|         |    239 		{ | 
|         |    240 		// Puts parentpath on the cleanupstack | 
|         |    241 		parentpath = folder->FullFolderPathL().AllocLC(); | 
|         |    242 		} | 
|         |    243 	else | 
|         |    244 		{ | 
|         |    245 		// otherwise parentpath is empty | 
|         |    246 		parentpath = KNullDesC().AllocLC(); | 
|         |    247 		} | 
|         |    248  | 
|         |    249 	const TDesC& pathSeparator = iImapSettings.PathSeparator();			 | 
|         |    250 	HBufC* newFolderPath = NULL; | 
|         |    251 			 | 
|         |    252 	if (*parentpath==KNullDesC) | 
|         |    253 		{ | 
|         |    254 		// creating a root entry folder | 
|         |    255 		if (aIsFolder) | 
|         |    256 			{ | 
|         |    257 			// +1 for trailing heirarchy path separator | 
|         |    258 			newFolderPath = HBufC16::NewLC(aLeafName.Length()+1); | 
|         |    259 			TPtr16 ptr(newFolderPath->Des()); | 
|         |    260 			ptr.Copy(aLeafName); | 
|         |    261 			ptr.Append(pathSeparator); | 
|         |    262 			} | 
|         |    263 		else | 
|         |    264 			{ | 
|         |    265 			// Root level mailbox | 
|         |    266 			newFolderPath = aLeafName.AllocLC(); | 
|         |    267 			} | 
|         |    268 		} | 
|         |    269 	else | 
|         |    270 		{ | 
|         |    271 		// creating a subfolder | 
|         |    272 		if (aIsFolder) | 
|         |    273 			{ | 
|         |    274 			// +1 for heirarchy separator, +1 for trailing heirarchy path separator | 
|         |    275 			newFolderPath = HBufC16::NewLC(parentpath->Length()+aLeafName.Length()+2); | 
|         |    276 			TPtr16 ptr(newFolderPath->Des()); | 
|         |    277 			ptr.Copy(*parentpath); | 
|         |    278 			ptr.Append(pathSeparator); | 
|         |    279 			ptr.Append(aLeafName); | 
|         |    280 			ptr.Append(pathSeparator); | 
|         |    281 			} | 
|         |    282 		else | 
|         |    283 			{ | 
|         |    284 			// +1 for heirarchy separator | 
|         |    285 			newFolderPath = HBufC16::NewLC(parentpath->Length()+aLeafName.Length()+1); | 
|         |    286 			TPtr16 ptr(newFolderPath->Des()); | 
|         |    287 			ptr.Copy(*parentpath); | 
|         |    288 			ptr.Append(pathSeparator); | 
|         |    289 			ptr.Append(aLeafName); | 
|         |    290 			} | 
|         |    291 		} | 
|         |    292 		 | 
|         |    293 	CleanupStack::Pop(newFolderPath); | 
|         |    294 	CleanupStack::PopAndDestroy(parentpath); | 
|         |    295 	 | 
|         |    296 	return newFolderPath; | 
|         |    297 	} | 
|         |    298  | 
|         |    299  | 
|         |    300 /** | 
|         |    301 Creates local mirror of the newly created folder. | 
|         |    302  | 
|         |    303 */ | 
|         |    304 void CImapCompoundCreate::CreateLocalFolderL() | 
|         |    305 	{ | 
|         |    306 	TMsvEmailEntry message; | 
|         |    307 	SetEntryL(iParentId); | 
|         |    308 	// No need to set iMtmData1-3 or iSize to 0 as this is done on construction. | 
|         |    309 	 | 
|         |    310 	message.iType=KUidMsvFolderEntry; | 
|         |    311 	message.iMtm=KUidMsgTypeIMAP4; | 
|         |    312 	message.iServiceId=iImapSettings.ServiceId(); | 
|         |    313 	message.SetValidUID(EFalse); | 
|         |    314 	message.SetMailbox(ETrue); // Default to creating a mailbox | 
|         |    315 	message.SetComplete(ETrue); | 
|         |    316 	message.iDetails.Set(*iLeafName); | 
|         |    317 	iServerEntry.CreateEntry(message); | 
|         |    318 	// Save the created id for the progress response | 
|         |    319 	iNewFolderId=message.Id(); | 
|         |    320 	} | 
|         |    321  | 
|         |    322  | 
|         |    323 void CImapCompoundCreate::Progress(TImap4CompoundProgress& aCompoundProgress) | 
|         |    324 	{ | 
|         |    325 	// Create does not set iOperation, it just sets iState to EBusy  | 
|         |    326 	// when doing the creation | 
|         |    327 	aCompoundProgress.iGenericProgress.iState = iProgressState; | 
|         |    328 	aCompoundProgress.iGenericProgress.iReturnedMsvId = iNewFolderId; | 
|         |    329 	 | 
|         |    330 	// Put error into progress buffer | 
|         |    331 	if( aCompoundProgress.iGenericProgress.iErrorCode == KErrNone ) | 
|         |    332 		{ | 
|         |    333 		aCompoundProgress.iGenericProgress.iErrorCode = iProgressErrorCode; | 
|         |    334 		} | 
|         |    335 	} | 
|         |    336  | 
|         |    337  | 
|         |    338 /** | 
|         |    339 Handles NO/BAD responses according to current step. | 
|         |    340 Negative server responses are not fatal - the error is reported in the  | 
|         |    341 progress report, and the operation completes. | 
|         |    342  | 
|         |    343 @return KErrNone if the error has been handled | 
|         |    344 		Completion error code otherwise. | 
|         |    345 */ | 
|         |    346 TInt CImapCompoundCreate::ProcessNegativeServerResponse() | 
|         |    347 	{ | 
|         |    348 	TInt err = iStatus.Int(); | 
|         |    349 	switch (iCurrentStep) | 
|         |    350 		{ | 
|         |    351 		case ECreate: | 
|         |    352 		case ECheckFolderExists: | 
|         |    353 			// Skip creation of local folder... | 
|         |    354 			iNextStep = EFinished; | 
|         |    355 			break; | 
|         |    356 		case EProcessFolderCheck: | 
|         |    357 		case ECreateLocal: | 
|         |    358 		case EFinished: | 
|         |    359 		case ESuspendedForMigrate: | 
|         |    360 		default: | 
|         |    361 			{ | 
|         |    362 			// positive error code not expected, | 
|         |    363 			// self-completed states or no outstanding request. | 
|         |    364 			TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundUnexpectedState); | 
|         |    365 			break; | 
|         |    366 			} | 
|         |    367 		 | 
|         |    368 		} // end switch (iCurrentStep) | 
|         |    369 	iProgressErrorCode = err; | 
|         |    370 	return KErrNone; | 
|         |    371 	} | 
|         |    372  | 
|         |    373 /** | 
|         |    374 Called to resume the compound operation following a bearer migration. | 
|         |    375 */ | 
|         |    376 void CImapCompoundCreate::ResumeOperationL(TRequestStatus& aStatus, CImapSession& aSession) | 
|         |    377 	{ | 
|         |    378 	iSession = &aSession; | 
|         |    379 	__LOG_TEXT(iSession->LogId(), "CImapCompoundCreate::Resuming"); | 
|         |    380 	__ASSERT_DEBUG(iCurrentStep==ESuspendedForMigrate, TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundUnexpectedState)); | 
|         |    381 	iStopForMigrate = EFalse; | 
|         |    382  | 
|         |    383 	// Switch on next step | 
|         |    384 	switch (iNextStep) | 
|         |    385 		{ | 
|         |    386 		case ECreate: | 
|         |    387 		case ECheckFolderExists: | 
|         |    388 			{ | 
|         |    389 			// Restart the operation | 
|         |    390 			CompleteSelf(); | 
|         |    391 			break; | 
|         |    392 			} | 
|         |    393 		 | 
|         |    394 		case ECreateLocal: | 
|         |    395 		case EFinished: | 
|         |    396 		default: | 
|         |    397 			{ | 
|         |    398 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundUnexpectedState)); | 
|         |    399 			// abandon the compound operation | 
|         |    400 			iNextStep=EFinished; | 
|         |    401 			CompleteSelf(); | 
|         |    402 			break; | 
|         |    403 			} | 
|         |    404 		} // end switch (iNextStep) | 
|         |    405 	Queue(aStatus); | 
|         |    406 	} |