|         |      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 "cimapbodystructurebuilder.h" | 
|         |     17  | 
|         |     18 #include "cimapatom.h" | 
|         |     19 #include "cimapatomwalker.h" | 
|         |     20 #include "cimapatomparser.h" | 
|         |     21 #include "cimapbodystructure.h" | 
|         |     22 #include "cimapfetchresponse.h" | 
|         |     23 #include "cimapsessionconsts.h" | 
|         |     24 #include "cimapcommand.h" | 
|         |     25 #include "imappaniccodes.h" | 
|         |     26  | 
|         |     27  | 
|         |     28 CImapBodyStructureBuilder* CImapBodyStructureBuilder::NewL(CImapFetchResponse& aFetchResponse, TInt aLogId) | 
|         |     29 // static method | 
|         |     30 	{ | 
|         |     31 	CImapBodyStructureBuilder* self = new(ELeave)CImapBodyStructureBuilder(aFetchResponse, aLogId); | 
|         |     32 	CleanupStack::PushL(self); | 
|         |     33 	self->ConstructL(); | 
|         |     34 	CleanupStack::Pop(self); | 
|         |     35 	return self; | 
|         |     36 	} | 
|         |     37 CImapBodyStructureBuilder::CImapBodyStructureBuilder(CImapFetchResponse& aFetchResponse, TInt aLogId) | 
|         |     38 	: iFetchResponse(aFetchResponse) | 
|         |     39 	, iBodyStructureOwned(ETrue) | 
|         |     40 	, iProcessBlockState(EWaitLine) | 
|         |     41 	, iLogId(aLogId) | 
|         |     42 	{} | 
|         |     43 	 | 
|         |     44 void CImapBodyStructureBuilder::ConstructL() | 
|         |     45 	{ | 
|         |     46 	iAtomParser = CImapAtomParser::NewL(EFalse, iLogId); | 
|         |     47 	iAtomWalker = CImapAtomWalker::NewL(iLogId); | 
|         |     48 	} | 
|         |     49 	 | 
|         |     50 CImapBodyStructureBuilder::~CImapBodyStructureBuilder() | 
|         |     51 	{ | 
|         |     52 	delete iAtomWalker; | 
|         |     53 	delete iAtomParser; | 
|         |     54 	 | 
|         |     55 	// NOTE | 
|         |     56 	// | 
|         |     57 	// CImapBodyStructure is a tree data strucutre, where any CImapBodyStructure owns and  | 
|         |     58 	// is responssible for destroying its children. | 
|         |     59 	// | 
|         |     60 	// iBodyStructureStack[0] is the root bodystructure  | 
|         |     61 	// ownership of the which is usually passed to CImapFetchResponse object before we get here | 
|         |     62 	// So destroying iBodyStructureStack[0] will cause all its children to be destroyed too. | 
|         |     63 	// | 
|         |     64 	// With the exception of the root bodystructure, iBodyStructureStack does not own any  | 
|         |     65 	// of the objects it points to, and MUST NOT destroy them. | 
|         |     66 	 | 
|         |     67 	if (iBodyStructureOwned) | 
|         |     68 		{ | 
|         |     69 		if (iBodyStructureStack.Count() > 0) | 
|         |     70 			{ | 
|         |     71 			// delete the root bodystructure. | 
|         |     72 			delete iBodyStructureStack[0]; | 
|         |     73 			} | 
|         |     74 		} | 
|         |     75 	iBodyStructureStack.Close(); // And DO NOT destroy the data that is pointed to. | 
|         |     76 	} | 
|         |     77  | 
|         |     78 /** | 
|         |     79 Parses a block of incoming data from the session. | 
|         |     80 ProcessBlockL() should be called repeatedly with more data until it returns EFalse to  | 
|         |     81 indicate that enough data has been received. | 
|         |     82 This method parses the incoming data into an atom tree as the data is received. | 
|         |     83 When the last block of data is received, the method will then parse the complete atom tree, | 
|         |     84 populating iFetchResponse with a fully initialised CImapBodyStructure tree. | 
|         |     85 @param aData either a line or literal block of data. | 
|         |     86 @return Whether ProcessBlockL() expects to be called again with the next block of data from the session. | 
|         |     87 */ | 
|         |     88 TBool CImapBodyStructureBuilder::ProcessBlockL(const TDesC8& aData) | 
|         |     89 	{ | 
|         |     90 	TBool wantMore = ETrue; | 
|         |     91 	switch (iProcessBlockState) | 
|         |     92 		{ | 
|         |     93 		case EWaitLine: | 
|         |     94 			{ | 
|         |     95 			wantMore = iAtomParser->ProcessLineL(aData); | 
|         |     96 			 | 
|         |     97 			if (!wantMore) | 
|         |     98 				{				 | 
|         |     99 				iAtomWalker->SetRootL(iAtomParser->RootAtom()); | 
|         |    100 				 | 
|         |    101 				// Get to the first "(" | 
|         |    102 				__ASSERT_ALWAYS(iAtomWalker->CurrentDes(EFalse).Length()==0, CImapCommand::CorruptDataL(iLogId)); | 
|         |    103 				__ASSERT_ALWAYS(iAtomWalker->PeekAcross() == NULL, CImapCommand::CorruptDataL(iLogId)); | 
|         |    104 					 | 
|         |    105 				iAtomWalker->WalkDownL(); | 
|         |    106 				__ASSERT_ALWAYS(iAtomWalker->CurrentMatch(KImapTxtOpenBracket()), CImapCommand::CorruptDataL(iLogId)); | 
|         |    107 				 | 
|         |    108 				iProcessBlockState = EParsing; | 
|         |    109 				ParseLoopL(); | 
|         |    110 				 | 
|         |    111 				TransferBufferOwnershipToFetchResponseL(); | 
|         |    112 				} | 
|         |    113 			else | 
|         |    114 				{ | 
|         |    115 				iProcessBlockState = EWaitLiteral; | 
|         |    116 				} | 
|         |    117 			} | 
|         |    118 			break; | 
|         |    119 		case EWaitLiteral: | 
|         |    120 			{ | 
|         |    121 			iAtomParser->ProcessLiteralBlockL(aData); | 
|         |    122 			iProcessBlockState = EWaitLine; | 
|         |    123 			} | 
|         |    124 			break; | 
|         |    125 		default: | 
|         |    126 			{ | 
|         |    127 			// This is an internal programming error. | 
|         |    128 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderInvalidProcessBlockState)); | 
|         |    129 			wantMore = EFalse; | 
|         |    130 			} | 
|         |    131 			break; | 
|         |    132 		} | 
|         |    133 		 | 
|         |    134 	return wantMore; | 
|         |    135 	} | 
|         |    136  | 
|         |    137 /** | 
|         |    138 Assigns the root bodystructure object, and its associated data to iFetchResponse. | 
|         |    139 iFetchResponse takes ownership of the bodystructure and its data. | 
|         |    140 */ | 
|         |    141 void CImapBodyStructureBuilder::TransferBufferOwnershipToFetchResponseL() | 
|         |    142 	{ | 
|         |    143 	// Check for internal programming errors. | 
|         |    144 	__ASSERT_DEBUG(iBodyStructureOwned, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderRootNotOwned)); | 
|         |    145 	__ASSERT_DEBUG(iBodyStructureStack.Count() == 1, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderExpectedRootAtomOnlyOnStack)); | 
|         |    146 	__ASSERT_DEBUG(iBodyStructureStack[0] == iBodyStructure, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderCurrentAtomIsNotRoot)); | 
|         |    147 	 | 
|         |    148 	// Prepare to transfer ownership of bodyStructureData from iAtomParser to iFetchResponse | 
|         |    149 	// bodyStructureData will no longer be owned by iAtomParser | 
|         |    150 	HBufC8* bodyStructureData = iAtomParser->DetachBuffer(); | 
|         |    151 	 | 
|         |    152 	// Transfer ownership of iBodyStructure and bodyStructureData to iFetchResponse | 
|         |    153 	iFetchResponse.SetBodyStructure(iBodyStructure, bodyStructureData); | 
|         |    154 	 | 
|         |    155 	// iBodyStructure is no longer owned by "this" CImapBodyStructureBuilder object. | 
|         |    156 	iBodyStructureOwned = EFalse; | 
|         |    157 	} | 
|         |    158  | 
|         |    159 /** | 
|         |    160 Returns any data that was not parsed by ParseBlockL() | 
|         |    161  - i.e any data that follows the top level BODYSTRUCTURE. | 
|         |    162 This will be a null string until ParseBlockL() has returned EFalse | 
|         |    163 to indicate that it has finished parsing. | 
|         |    164 When non-null, the returned pointer descriptor points into a section of the  | 
|         |    165 aData descriptor that was passed into ParseBlockL().  Consequently, it is | 
|         |    166 only valid while the aData descriptor it points into is valid. | 
|         |    167 @return a descriptor pointing to unparsed data. | 
|         |    168 */ | 
|         |    169 TPtrC8 CImapBodyStructureBuilder::UnparsedData() | 
|         |    170 	{ | 
|         |    171 	return iAtomParser->UnparsedData(); | 
|         |    172 	}	 | 
|         |    173 	 | 
|         |    174 /** | 
|         |    175 The main loop for parsing the bodystructure. | 
|         |    176 The loop uses a state machine and bodystructure stack in order to handle | 
|         |    177 embedded bodystructures without needing to use recursion. | 
|         |    178 */ | 
|         |    179 void CImapBodyStructureBuilder::ParseLoopL() | 
|         |    180 	{ | 
|         |    181 	// Check for internal programming error | 
|         |    182 	__ASSERT_DEBUG(iBodyStructureStack.Count() == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderStackNotEmpty)); | 
|         |    183 	 | 
|         |    184 	TParseStep parseStep = EParseNewBodyStructure;	 | 
|         |    185 	 | 
|         |    186 	while (parseStep != EParseComplete) | 
|         |    187 		{ | 
|         |    188 		switch (parseStep) | 
|         |    189 			{ | 
|         |    190 			case EParseNewBodyStructure: | 
|         |    191 				{ | 
|         |    192 				// Either at the start of the root body structure, | 
|         |    193 				// Or at the start of an embedded body structure. | 
|         |    194 				PushNewBodyStructureL(); | 
|         |    195 				parseStep = ParseBodyStructureTypeL(); | 
|         |    196 				} | 
|         |    197 				break; | 
|         |    198 			case EParseBasic: | 
|         |    199 				{ | 
|         |    200 				// Found a "basic" bodystructure - i.e. not text, rfc822 or multipart. | 
|         |    201 				ParseBodyTypeBasicL(); | 
|         |    202 				ParseBodyExt1PartL(); | 
|         |    203 				parseStep = EParseSubStructureComplete; | 
|         |    204 				} | 
|         |    205 				break; | 
|         |    206 			case EParseText: | 
|         |    207 				{ | 
|         |    208 				// Found a "TEXT" body structure | 
|         |    209 				ParseBodyTypeTextL(); | 
|         |    210 				ParseBodyExt1PartL(); | 
|         |    211 				parseStep = EParseSubStructureComplete; | 
|         |    212 				} | 
|         |    213 				break; | 
|         |    214 			case EParseBodyTypeMessageRfc822: | 
|         |    215 				{ | 
|         |    216 				// Found a "MESSAGE/RFC822" body structure. | 
|         |    217 				// This contains an embedded bodystructure, so parse up to the structure, | 
|         |    218 				// and then allow the loop to parse the embedded structure. | 
|         |    219 				ParseBodyTypeMessageRfc822L(); | 
|         |    220 				parseStep = EParseNewBodyStructure; | 
|         |    221 				} | 
|         |    222 				break; | 
|         |    223 			case EParseRemainderMessageRfc822: | 
|         |    224 				{ | 
|         |    225 				// Just finished parsing the embedded bodystructure of a "MESSAGE/RFC822". | 
|         |    226 				// Complete parsing the parent MESSAGE/RFC822 structure here. | 
|         |    227 				ParseRemainderMessageRfc822L(); | 
|         |    228 				ParseBodyExt1PartL(); | 
|         |    229 				parseStep = EParseSubStructureComplete; | 
|         |    230 				} | 
|         |    231 				break; | 
|         |    232 			case EParseRemainderMultipart: | 
|         |    233 				{ | 
|         |    234 				// Just finished parsing the final embedded bodystructure of a MULTIPART structure. | 
|         |    235 				// Complete parsing the parent MULTIPART structure here | 
|         |    236 				ParseRemainderMultipartL(); | 
|         |    237 				parseStep = EParseSubStructureComplete; | 
|         |    238 				} | 
|         |    239 				break; | 
|         |    240 			case EParseSubStructureComplete: | 
|         |    241 				{ | 
|         |    242 				// Just finished parsing a bodystructure. | 
|         |    243 				// If it is the root bodystructure then we are complete. | 
|         |    244 				// Otherwise, let ParseSubStructureCompleteL() will find out whether it is | 
|         |    245 				// * embedded in a MESSAGE/RFC822 structure - requiring the remainder to be parsed next: EParseRemainderMessageRfc822 | 
|         |    246 				// * embedded in a MULTIPART structure in which case | 
|         |    247 				//   > either there is another embedded structure next: EParseNewBodyStructure | 
|         |    248 				//   > or this is the last embedded structure, so we need to parse the multipart remainder: EParseRemainderMultipart | 
|         |    249 					 | 
|         |    250 				if (PopBodyStructureL()) | 
|         |    251 					{ | 
|         |    252 					// we were actually in the root, so we are fully complete. | 
|         |    253 					parseStep = EParseComplete; | 
|         |    254 					} | 
|         |    255 				else | 
|         |    256 					{ | 
|         |    257 					// we were in a genuine substructure, so need to walk up and decide what to do. | 
|         |    258 					parseStep = ParseSubStructureCompleteL(); | 
|         |    259 					}				 | 
|         |    260 				} | 
|         |    261 				break; | 
|         |    262 			default: | 
|         |    263 				{ | 
|         |    264 				// This is an internal programming error. | 
|         |    265 				__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderInvalidParseStep)); | 
|         |    266 				User::Leave(KErrGeneral); // avoid an infinite loop. | 
|         |    267 				} | 
|         |    268 			} | 
|         |    269 		} | 
|         |    270 	} | 
|         |    271  | 
|         |    272 /** | 
|         |    273 When the parse loop comes across a new root or embedded bodystructure, it will use this method to... | 
|         |    274   > Create a new CImapBodyStructure object to represent the bodystructure | 
|         |    275   > Push the object onto the stack and make it "current" | 
|         |    276   > Associate an embedded bodystructure with its parent. | 
|         |    277  | 
|         |    278 */ | 
|         |    279 void CImapBodyStructureBuilder::PushNewBodyStructureL() | 
|         |    280 	{ | 
|         |    281 	// Going to create a new body structure. | 
|         |    282 	// Need to be sure that something (either the stack root or its tree) | 
|         |    283 	// is going to own and ultimatelty destroy it. | 
|         |    284 	__ASSERT_DEBUG(iBodyStructureOwned, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderRootNotOwned)); | 
|         |    285 	 | 
|         |    286 	CImapBodyStructure* bodyStructure = CImapBodyStructure::NewL(); | 
|         |    287 	CleanupStack::PushL(bodyStructure); | 
|         |    288 	 | 
|         |    289 	// root bodystructure is iBodyStructureStack[0] | 
|         |    290 	if (iBodyStructure == NULL) | 
|         |    291 		{ | 
|         |    292 		// Check for internal programming error | 
|         |    293 		__ASSERT_DEBUG(iBodyStructureStack.Count() == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderStackNotEmpty)); | 
|         |    294 		 | 
|         |    295 		iBodyStructureStack.AppendL(bodyStructure); | 
|         |    296 		 | 
|         |    297 		// ownership is now transferred to the root bodystructure tree | 
|         |    298 		CleanupStack::Pop(bodyStructure); | 
|         |    299 		} | 
|         |    300 	else | 
|         |    301 		{ | 
|         |    302 		// Check for internal programming error | 
|         |    303 		__ASSERT_DEBUG(iBodyStructureStack.Count() > 0, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderStackIsEmpty)); | 
|         |    304 		 | 
|         |    305 		iBodyStructure->AppendEmbeddedBodyStructureL(*bodyStructure); | 
|         |    306 										 | 
|         |    307 		// ownership is now transferred to the root bodystructure tree | 
|         |    308 		CleanupStack::Pop(bodyStructure); | 
|         |    309 		 | 
|         |    310 		iBodyStructureStack.AppendL(bodyStructure); | 
|         |    311 		} | 
|         |    312 	 | 
|         |    313 	// This is now the bodystructure that we are parsing. | 
|         |    314 	iBodyStructure = bodyStructure; | 
|         |    315 	} | 
|         |    316  | 
|         |    317 /** | 
|         |    318 Pops a bodystructure from the stack - except the root, which will not be popped. | 
|         |    319 @return whether we were in the root already. | 
|         |    320 */	 | 
|         |    321 TBool CImapBodyStructureBuilder::PopBodyStructureL() | 
|         |    322 	{ | 
|         |    323 	TBool bRootAlready = EFalse; | 
|         |    324 	TInt stackCount = iBodyStructureStack.Count(); | 
|         |    325  | 
|         |    326 	if (stackCount > 1) | 
|         |    327 		{ | 
|         |    328 		// Pop the bodystructure stack | 
|         |    329 		--stackCount; | 
|         |    330 		CImapBodyStructure* poppedBs = iBodyStructureStack[stackCount]; | 
|         |    331 		iBodyStructureStack.Remove(stackCount); // No need to destroy the bodystructure, as it is now owned by iBodyStructureStack[stackCount-1] | 
|         |    332 		 | 
|         |    333 		iBodyStructure = iBodyStructureStack[stackCount-1]; | 
|         |    334 		} | 
|         |    335 	else | 
|         |    336 		{ | 
|         |    337 		// Check for internal programming error: Not expecting a stack count of 0 or less | 
|         |    338 		__ASSERT_DEBUG(stackCount == 1, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderExpectedRootAtomOnlyOnStack)); | 
|         |    339 		bRootAlready = ETrue; | 
|         |    340 		} | 
|         |    341 		 | 
|         |    342 	return bRootAlready; | 
|         |    343 	} | 
|         |    344  | 
|         |    345 /** | 
|         |    346 Found the closing bracket of our substructure. | 
|         |    347 Pop the stack, walk up and decide what to do next. | 
|         |    348 If we've reached the root level, then parsing is complete. | 
|         |    349 If our parent is a multipart, then check to see if we have a sibling.   | 
|         |    350 	If not then we have come to the end of our parent's structure too - handle this in a separate loop. | 
|         |    351 If our parent is a Rfc822, then we need to parse the remainder of the Rfc822 structure. | 
|         |    352 	If not then we have come to the end of our parent's structure too - handle this in a separate loop. | 
|         |    353 @return  | 
|         |    354 */ | 
|         |    355 CImapBodyStructureBuilder::TParseStep CImapBodyStructureBuilder::ParseSubStructureCompleteL() | 
|         |    356 	{ | 
|         |    357 	TParseStep nextStep = EParseComplete; | 
|         |    358 	 | 
|         |    359 	iAtomWalker->WalkUpL(); | 
|         |    360 	 | 
|         |    361 	if (iBodyStructure->BodyStructureType() == CImapBodyStructure::ETypeMultipart) | 
|         |    362 		{ | 
|         |    363 		// Expecting either an open bracket for another bodystructure | 
|         |    364 		// or the subtype.  | 
|         |    365 		CImapAtom* peekAcross = iAtomWalker->PeekAcross(); // peekAcross does not need to be destroyed as no ownership is transferred. | 
|         |    366 		if (peekAcross == NULL) | 
|         |    367 			{ | 
|         |    368 			// But not expecting "nothing". | 
|         |    369 			CImapCommand::CorruptDataL(iLogId); | 
|         |    370 			} | 
|         |    371 		 | 
|         |    372 		if (peekAcross->Match(KImapTxtOpenBracket())) | 
|         |    373 			{ | 
|         |    374 			// position the atom walker on the open bracket, ready for ParseBodyStructureTypeL | 
|         |    375 			// to walk down into it. | 
|         |    376 			iAtomWalker->WalkAcrossL(ETrue); | 
|         |    377 			nextStep = EParseNewBodyStructure; | 
|         |    378 			} | 
|         |    379 		else | 
|         |    380 			{ | 
|         |    381 			// stay where we are, so that ParseRemainderMultipartL() | 
|         |    382 			// can walk accross to the subtype, as any other Parse method would do | 
|         |    383 			nextStep = EParseRemainderMultipart; | 
|         |    384 			} | 
|         |    385 		} | 
|         |    386 	else if (iBodyStructure->BodyStructureType() == CImapBodyStructure::ETypeMessageRfc822) | 
|         |    387 		{ | 
|         |    388 		// stay where we are, so that ParseRemainderMessageRfc822L() | 
|         |    389 		// can walk accross to the body-fld-lines, as any other Parse method would do | 
|         |    390 		nextStep = EParseRemainderMessageRfc822; | 
|         |    391 		} | 
|         |    392 	else | 
|         |    393 		{ | 
|         |    394 		// No other bodystruct type has substructures. | 
|         |    395 		// So getting here is an internal programming error. | 
|         |    396 		__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderInvalidBodyStructureType)); | 
|         |    397 		User::Leave(KErrGeneral); | 
|         |    398 		} | 
|         |    399 			 | 
|         |    400 	return nextStep; | 
|         |    401 	} | 
|         |    402  | 
|         |    403 /** | 
|         |    404 body = "(" (body-type-1part / body-type-mpart) ")" | 
|         |    405  | 
|         |    406 This method expects iAtomWalker to be positioned at the opening bracket of a body structure. | 
|         |    407 The method works out the type of the bodystructure, and returns the appropriate next parse  | 
|         |    408 step to the parse loop. | 
|         |    409 For multipart structures, iAtomWalker is left positioned at the opening bracket of the embedded structure. | 
|         |    410 Foa all other structures, iAtomWalker is left positioned at the subtype field. | 
|         |    411  | 
|         |    412 @return The next step for the parse loop to take.  This is one of | 
|         |    413   > EParseNewBodyStructure for MULTIPART structures | 
|         |    414   > EParseText for TEXT structures | 
|         |    415   > EParseBodyTypeMessageRfc822 for MESSAGE/RFC822 | 
|         |    416   > EParseBasic for all other structures. | 
|         |    417 */ | 
|         |    418 CImapBodyStructureBuilder::TParseStep CImapBodyStructureBuilder::ParseBodyStructureTypeL() | 
|         |    419 	{ | 
|         |    420 	// Start at the opening bracket | 
|         |    421 	__ASSERT_ALWAYS(iAtomWalker->CurrentMatch(KImapTxtOpenBracket()), CImapCommand::CorruptDataL(iLogId)); | 
|         |    422 	iAtomWalker->WalkDownL(); | 
|         |    423 		 | 
|         |    424 	// What kind of body type does this represent?	 | 
|         |    425 	// Assume Basic, unless we find otherwise. | 
|         |    426 	TParseStep nextStep = EParseBasic; | 
|         |    427 	 | 
|         |    428 	// Is it body-type-mpart? - check for opening bracket | 
|         |    429 	// body-type-mpart = 1*body SP media-subtype [SP body-ext-mpart] | 
|         |    430 	if (iAtomWalker->CurrentMatch(KImapTxtOpenBracket())) | 
|         |    431 		{ | 
|         |    432 		// According to section 6.4.5 of RFC3501, "MULTIPART" is the correct Type string for | 
|         |    433 		// multipart messages.  This is an implicit value not directly available from the | 
|         |    434 		// bodystructure input string.  So we point the bodystructure object at a constant string instead. | 
|         |    435 		iBodyStructure->SetType(KImapTxtMultipart()); | 
|         |    436 		 | 
|         |    437 		iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeMultipart); | 
|         |    438 		nextStep = EParseNewBodyStructure; | 
|         |    439 		} | 
|         |    440 	else | 
|         |    441 		{ | 
|         |    442 		// body-type-1part = (body-type-basic / body-type-msg / body-type-text) [SP body-ext-1part] | 
|         |    443 		iBodyStructure->SetType(iAtomWalker->CurrentDes(EFalse)); // media-basic and variants is a string, not an nstring | 
|         |    444 		__ASSERT_ALWAYS(iAtomWalker->PeekDown() == NULL, CImapCommand::CorruptDataL(iLogId)); | 
|         |    445 		 | 
|         |    446 		iAtomWalker->WalkAcrossL(ETrue); | 
|         |    447 		iBodyStructure->SetSubType(iAtomWalker->CurrentDes(EFalse)); // media-subtype and variants is a string, not an nstring | 
|         |    448 		 | 
|         |    449 		if (iBodyStructure->Type().CompareF(KImapTxtText())==0) | 
|         |    450 		// body-type-text = media-text SP body-fields SP body-fld-lines | 
|         |    451 		//  | 
|         |    452 		// media-text = DQUOTE "TEXT" DQUOTE SP media-subtype | 
|         |    453 		// media-subtype = string | 
|         |    454 			{ | 
|         |    455 			// we have media-text... | 
|         |    456 			// ... so this is body-type-text | 
|         |    457 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeText); | 
|         |    458 			nextStep = EParseText; | 
|         |    459 			} | 
|         |    460 		else if (iBodyStructure->Type().CompareF(KImapTxtMessage())==0 && iBodyStructure->SubType().CompareF(KImapTxtRfc822())==0) | 
|         |    461 		// body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines | 
|         |    462 		//  | 
|         |    463 		// media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE | 
|         |    464 			{ | 
|         |    465 			// we have media-message... | 
|         |    466 			// ... so this is body-type-msg | 
|         |    467 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeMessageRfc822); | 
|         |    468 			nextStep = EParseBodyTypeMessageRfc822; | 
|         |    469 			} | 
|         |    470 		else | 
|         |    471 			{ | 
|         |    472 			// Not multipart, text or rfc822, so must be basic. | 
|         |    473 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeBasic); | 
|         |    474 			} | 
|         |    475 		} | 
|         |    476 		 | 
|         |    477 	return nextStep;	 | 
|         |    478 	} | 
|         |    479 	 | 
|         |    480 /** | 
|         |    481 body-type-basic = media-basic SP body-fields | 
|         |    482  | 
|         |    483 This method expects media-basict to have been parsed already, as part of ParseBodyStructureTypeL() | 
|         |    484 It expects the atom walker to be positioned at the last atom of media-basic | 
|         |    485 */ | 
|         |    486 void CImapBodyStructureBuilder::ParseBodyTypeBasicL() | 
|         |    487 	{ | 
|         |    488 	// body-fields | 
|         |    489 	ParseBodyFieldsL(); | 
|         |    490 	} | 
|         |    491 	 | 
|         |    492 /** | 
|         |    493 body-type-text = media-text SP body-fields SP body-fld-lines | 
|         |    494  | 
|         |    495 This method expects media-text to have been parsed already, as part of ParseBodyStructureTypeL() | 
|         |    496 It expects the atom walker to be positioned at the last atom of media-text | 
|         |    497 */ | 
|         |    498 void CImapBodyStructureBuilder::ParseBodyTypeTextL() | 
|         |    499 	{ | 
|         |    500 	// body-fields | 
|         |    501 	ParseBodyFieldsL(); | 
|         |    502 	 | 
|         |    503 	// body-fld-lines = number | 
|         |    504 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    505 	iBodyStructure->SetBodyLines(iAtomWalker->CurrentDes(EFalse)); | 
|         |    506 	} | 
|         |    507 	 | 
|         |    508 /** | 
|         |    509 body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines | 
|         |    510  | 
|         |    511 This method parses up to and including envelope. | 
|         |    512 It then returns, allowing the parse loop to parse the nested "body" that is next. | 
|         |    513 Upon completion of the nested "body", ParseRemainderMessageRfc822L() will be called to finish parsing | 
|         |    514 the message body type | 
|         |    515  | 
|         |    516 This method expects media-message to have been parsed already, as part of ParseBodyStructureTypeL() | 
|         |    517 It expects the atom walker to be positioned at the last atom of media-text | 
|         |    518 */ | 
|         |    519 void CImapBodyStructureBuilder::ParseBodyTypeMessageRfc822L() | 
|         |    520 	{ | 
|         |    521 	// body-fields SP SP body SP body-fld-lines | 
|         |    522 	ParseBodyFieldsL(); | 
|         |    523 	 | 
|         |    524 	// envelope | 
|         |    525 	ParseEnvelopeL(); | 
|         |    526 	 | 
|         |    527 	// Expect a body substructure next. | 
|         |    528 	// Position iAtomWalker at the opening bracket, ready for ParseBodyStructureTypeL | 
|         |    529 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    530 	} | 
|         |    531  | 
|         |    532 /** | 
|         |    533 body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines | 
|         |    534  | 
|         |    535 ParseBodyTypeMessageRfc822L processes up to and including body-fields. | 
|         |    536 The ParseLoop processes the nested "body" | 
|         |    537 This method processes the remainder - i.e. body-fld-lines | 
|         |    538 It expects the atom walker to be positioned at the field just prior to body-fld-lines | 
|         |    539 */ | 
|         |    540 void CImapBodyStructureBuilder::ParseRemainderMessageRfc822L() | 
|         |    541 	{ | 
|         |    542 	// body-fld-lines = number | 
|         |    543 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    544 	iBodyStructure->SetBodyLines(iAtomWalker->CurrentDes(EFalse)); | 
|         |    545 	} | 
|         |    546  | 
|         |    547 /** | 
|         |    548 body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP body-fld-enc SP body-fld-octets	 | 
|         |    549  | 
|         |    550 This method expects iAtomWalker to be positioned just prior to body-fld-param | 
|         |    551 */ | 
|         |    552 void CImapBodyStructureBuilder::ParseBodyFieldsL() | 
|         |    553 	{ | 
|         |    554 	ParseBodyFieldParamsL(EFalse); | 
|         |    555 	 | 
|         |    556 	// body-fld-id = nstring | 
|         |    557 	iAtomWalker->WalkAcrossL(EFalse); | 
|         |    558 	iBodyStructure->SetBodyId(iAtomWalker->CurrentDes(ETrue));  | 
|         |    559 	 | 
|         |    560 	// body-fld-desc = nstring | 
|         |    561 	iAtomWalker->WalkAcrossL(EFalse); | 
|         |    562 	iBodyStructure->SetBodyDescription(iAtomWalker->CurrentDes(ETrue)); | 
|         |    563 	 | 
|         |    564 	// body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/ "QUOTED-PRINTABLE") DQUOTE) / string | 
|         |    565 	// i.e. it's a string that might be in quotes | 
|         |    566 	iAtomWalker->WalkAcrossL(EFalse); | 
|         |    567 	iBodyStructure->SetBodyEncoding(iAtomWalker->CurrentDes(EFalse)); | 
|         |    568 	 | 
|         |    569 	// body-fld-octets = number | 
|         |    570 	iAtomWalker->WalkAcrossL(EFalse); | 
|         |    571 	iBodyStructure->SetBodySizeOctets(iAtomWalker->CurrentDes(EFalse)); | 
|         |    572 	} | 
|         |    573 	 | 
|         |    574 /** | 
|         |    575 body-fld-param = "(" string SP string *(SP string SP string) ")" / nil | 
|         |    576  | 
|         |    577 This method expects iAtomWalker to be positioned just prior to the "(" or "NIL" atom. | 
|         |    578 */ | 
|         |    579 void CImapBodyStructureBuilder::ParseBodyFieldParamsL(TBool aStoreAsDisposition) | 
|         |    580  | 
|         |    581 	{ | 
|         |    582 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomNil) | 
|         |    583 		{ | 
|         |    584 		// there are no params | 
|         |    585 		return; | 
|         |    586 		} | 
|         |    587 	 | 
|         |    588 	// Consume the bracket | 
|         |    589 	iAtomWalker->WalkDownL(); | 
|         |    590 	 | 
|         |    591 	do  | 
|         |    592 		{ | 
|         |    593 		CImapBodyStructure::TAttributeValuePair pair; | 
|         |    594 		pair.iAttribute.Set(iAtomWalker->CurrentDes(EFalse)); | 
|         |    595 		 | 
|         |    596 		iAtomWalker->WalkAcrossL(ETrue); | 
|         |    597 		pair.iValue.Set(iAtomWalker->CurrentDes(EFalse)); | 
|         |    598 		 | 
|         |    599 		if (aStoreAsDisposition) | 
|         |    600 			{ | 
|         |    601 			iBodyStructure->AppendExtDispositionParameterListL(pair);	 | 
|         |    602 			} | 
|         |    603 		else | 
|         |    604 			{ | 
|         |    605 			iBodyStructure->AppendParameterListL(pair); | 
|         |    606 			}		 | 
|         |    607 		}  | 
|         |    608 		while (iAtomWalker->WalkAcrossL(EFalse)); | 
|         |    609 		 | 
|         |    610 	iAtomWalker->WalkUpL(); | 
|         |    611 	} | 
|         |    612  | 
|         |    613 /**  | 
|         |    614 body-fld-dsp = "(" string SP body-fld-param ")" / nil | 
|         |    615  | 
|         |    616 This method expects iAtomWalker to be positioned just prior to the "(" or "NIL" atom. | 
|         |    617 */ | 
|         |    618 void CImapBodyStructureBuilder::ParseBodyFieldDispL() | 
|         |    619 	{ | 
|         |    620 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomNil) | 
|         |    621 		{ | 
|         |    622 		// there are no params | 
|         |    623 		return; | 
|         |    624 		} | 
|         |    625 		 | 
|         |    626 	iAtomWalker->WalkDownL(); | 
|         |    627 	 | 
|         |    628 	// string | 
|         |    629 	iBodyStructure->SetExtDispositionName(iAtomWalker->CurrentDes(EFalse)); | 
|         |    630 	 | 
|         |    631 	// body-fld-param | 
|         |    632 	ParseBodyFieldParamsL(ETrue); | 
|         |    633 	 | 
|         |    634 	iAtomWalker->WalkUpL();	 | 
|         |    635 	} | 
|         |    636 	 | 
|         |    637 /** | 
|         |    638 body-fld-lang = nstring / "(" string *(SP string) ")" | 
|         |    639  | 
|         |    640 This method should only be called if body-fld-lang is expected. | 
|         |    641 The caller should check first, using iAtomWalker->PeekAcross() | 
|         |    642 */ | 
|         |    643 void CImapBodyStructureBuilder::ParseBodyFieldLangL() | 
|         |    644 	{ | 
|         |    645 	// Consume the bracket | 
|         |    646 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    647 	 | 
|         |    648 	if (iAtomWalker->CurrentMatch(KImapTxtOpenBracket())) | 
|         |    649 		{ | 
|         |    650 		// we have many strings | 
|         |    651 		// "(" string *(SP string) ")" | 
|         |    652 		 | 
|         |    653 		iAtomWalker->WalkDownL(); | 
|         |    654 				 | 
|         |    655 		do  | 
|         |    656 			{ | 
|         |    657 			iBodyStructure->AppendExtLanguageListL(iAtomWalker->CurrentDes(EFalse)); | 
|         |    658 			 | 
|         |    659 			} while (iAtomWalker->WalkAcrossL(EFalse)); | 
|         |    660 		 | 
|         |    661 		iAtomWalker->WalkUpL(); | 
|         |    662 		} | 
|         |    663 	else  | 
|         |    664 		{ | 
|         |    665 		// we have a single nstring - only add it if it is non-empty | 
|         |    666 		const TDesC8& language = iAtomWalker->CurrentDes(ETrue); | 
|         |    667 		if (language.Length() > 0) | 
|         |    668 			{ | 
|         |    669 			iBodyStructure->AppendExtLanguageListL(language);	 | 
|         |    670 			}		 | 
|         |    671 		} | 
|         |    672 	} | 
|         |    673  | 
|         |    674 /** | 
|         |    675 body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]] | 
|         |    676  | 
|         |    677 This only appears in | 
|         |    678 body-type-1part = (body-type-basic / body-type-msg / body-type-text) [SP body-ext-1part] | 
|         |    679 So, this method treats the body-fld-md5 field as optional | 
|         |    680 */ | 
|         |    681 void CImapBodyStructureBuilder::ParseBodyExt1PartL() | 
|         |    682 	{ | 
|         |    683 	// Return as soon as a field is not found. | 
|         |    684 	if (iAtomWalker->WalkAcrossL(EFalse)) | 
|         |    685 		{ | 
|         |    686 		// body-fld-md5 = nstring | 
|         |    687 		iBodyStructure->SetExtMD5(iAtomWalker->CurrentDes(ETrue)); | 
|         |    688 		 | 
|         |    689 		// [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]] | 
|         |    690 		ParseCommonOptionalExtensionsL(); | 
|         |    691 		} | 
|         |    692 	} | 
|         |    693  | 
|         |    694 /** | 
|         |    695 body-type-mpart = 1*body SP media-subtype [SP body-ext-mpart] | 
|         |    696 This method deals with media-subtype [SP body-ext-mpart] | 
|         |    697  | 
|         |    698 body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]] | 
|         |    699  | 
|         |    700 It expects iAtomWalker to be positioned just prior to media-subtype. | 
|         |    701 */ | 
|         |    702 void CImapBodyStructureBuilder::ParseRemainderMultipartL() | 
|         |    703 	{ | 
|         |    704 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    705 	 | 
|         |    706 	// media-subtype = string | 
|         |    707 	iBodyStructure->SetSubType(iAtomWalker->CurrentDes(EFalse)); | 
|         |    708 	 | 
|         |    709 	// The remainder of items are optional.  Return as soon as one is not found. | 
|         |    710 	 | 
|         |    711 	// body-fld-param | 
|         |    712 	if (iAtomWalker->PeekAcross()) | 
|         |    713 		{ | 
|         |    714 		ParseBodyFieldParamsL(EFalse); | 
|         |    715 		 | 
|         |    716 		// [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]] | 
|         |    717 		ParseCommonOptionalExtensionsL();		 | 
|         |    718 		} | 
|         |    719 	} | 
|         |    720 	 | 
|         |    721 /** | 
|         |    722 body-ext-1part = body-fld-md5   [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]] | 
|         |    723 body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]] | 
|         |    724 Apart from the first parameter, body extensions for 1 and multi part are the same. | 
|         |    725 So this method parses them in one place. | 
|         |    726 */ | 
|         |    727 void CImapBodyStructureBuilder::ParseCommonOptionalExtensionsL() | 
|         |    728 	{ | 
|         |    729 	// Return as soon as a field is not found. | 
|         |    730 	 | 
|         |    731 	// body-fld-dsp | 
|         |    732 	if (iAtomWalker->PeekAcross()) | 
|         |    733 		{ | 
|         |    734 		ParseBodyFieldDispL(); | 
|         |    735 		 | 
|         |    736 		// body-fld-lang | 
|         |    737 		if (iAtomWalker->PeekAcross()) | 
|         |    738 			{ | 
|         |    739 			ParseBodyFieldLangL(); | 
|         |    740 		 | 
|         |    741 			// body-fld-loc = nstring | 
|         |    742 			if (iAtomWalker->WalkAcrossL(EFalse)) | 
|         |    743 				{ | 
|         |    744 				iBodyStructure->SetExtLocation(iAtomWalker->CurrentDes(ETrue)); | 
|         |    745 				 | 
|         |    746 				// *(SP body-extension) | 
|         |    747 				if (iAtomWalker->PeekAcross()) | 
|         |    748 					{ | 
|         |    749 					ParseBodyExtensionL(); | 
|         |    750 					} | 
|         |    751 				} | 
|         |    752 			} | 
|         |    753 		} | 
|         |    754 	} | 
|         |    755 	 | 
|         |    756 /** | 
|         |    757 body-extension = nstring / number / "(" body-extension *(SP body-extension) ")" | 
|         |    758 RFC3501 says:  "Future expansion. Client implementations | 
|         |    759 				MUST accept body-extension fields. Server | 
|         |    760 				implementations MUST NOT generate | 
|         |    761 				body-extension fields except as defined by | 
|         |    762 				future standard or standards-track | 
|         |    763 				revisions of this specification. | 
|         |    764 As body-extension is always at the end of a (sub)bodystructure, it is safe to ignore. | 
|         |    765 This method provides a placeholder for extracting any body-extension data that we might  | 
|         |    766 be interested in, in the future. | 
|         |    767 */ | 
|         |    768 void CImapBodyStructureBuilder::ParseBodyExtensionL() | 
|         |    769 	{} | 
|         |    770  | 
|         |    771 /** | 
|         |    772 envelope = "(" env-date SP env-subject SP env-from SP env-sender SP env-reply-to SP env-to SP env-cc SP env-bcc SP env-in-reply-to SP env-message-id ")" | 
|         |    773  | 
|         |    774 This method expects iAtomWalker to be positioned at the opening bracket. | 
|         |    775 */ | 
|         |    776 void CImapBodyStructureBuilder::ParseEnvelopeL() | 
|         |    777 	{ | 
|         |    778 	// Always expect an open bracket here, so allow atom walker to leave if there is one | 
|         |    779 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    780 	iAtomWalker->WalkDownL(); | 
|         |    781 	 | 
|         |    782 	CImapEnvelope& envelope = iBodyStructure->GetRfc822EnvelopeStructureL(); | 
|         |    783 		 | 
|         |    784 	// env-date = nstring | 
|         |    785 	envelope.SetEnvDate(iAtomWalker->CurrentDes(ETrue)); | 
|         |    786 	 | 
|         |    787 	// env-subject = nstring | 
|         |    788 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    789 	envelope.SetEnvSubject(iAtomWalker->CurrentDes(ETrue)); | 
|         |    790 	 | 
|         |    791 	// This single address structure will be *copied* into various envelope address arrays | 
|         |    792 	CImapEnvelope::TAddress address; // this will copied into many en | 
|         |    793 	 | 
|         |    794 	// env-from = "(" 1*address ")" / nil | 
|         |    795 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen) | 
|         |    796 		{ | 
|         |    797 		iAtomWalker->WalkDownL(); | 
|         |    798 		do | 
|         |    799 			{ | 
|         |    800 			ParseAddressL(address); | 
|         |    801 			envelope.AppendEnvFromL(address); | 
|         |    802 			 | 
|         |    803 			} while(iAtomWalker->WalkAcrossL(EFalse)); | 
|         |    804 		 | 
|         |    805 		iAtomWalker->WalkUpL(); | 
|         |    806 		} | 
|         |    807 		 | 
|         |    808 	// env-sender = "(" 1*address ")" / nil | 
|         |    809 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen) | 
|         |    810 		{ | 
|         |    811 		iAtomWalker->WalkDownL(); | 
|         |    812 		do | 
|         |    813 			{ | 
|         |    814 			ParseAddressL(address); | 
|         |    815 			envelope.AppendEnvSenderL(address); | 
|         |    816 			 | 
|         |    817 			} while(iAtomWalker->WalkAcrossL(EFalse)); | 
|         |    818 		 | 
|         |    819 		iAtomWalker->WalkUpL(); | 
|         |    820 		} | 
|         |    821 	// env-reply-to = "(" 1*address ")" / nil | 
|         |    822 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen) | 
|         |    823 		{ | 
|         |    824 		iAtomWalker->WalkDownL(); | 
|         |    825 		do | 
|         |    826 			{ | 
|         |    827 			ParseAddressL(address); | 
|         |    828 			envelope.AppendEnvReplyToL(address); | 
|         |    829 			 | 
|         |    830 			} while(iAtomWalker->WalkAcrossL(EFalse)); | 
|         |    831 		 | 
|         |    832 		iAtomWalker->WalkUpL(); | 
|         |    833 		} | 
|         |    834 		 | 
|         |    835 	// env-to = "(" 1*address ")" / nil | 
|         |    836 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen) | 
|         |    837 		{ | 
|         |    838 		iAtomWalker->WalkDownL(); | 
|         |    839 		do | 
|         |    840 			{ | 
|         |    841 			ParseAddressL(address); | 
|         |    842 			envelope.AppendEnvToL(address); | 
|         |    843 			 | 
|         |    844 			} while(iAtomWalker->WalkAcrossL(EFalse)); | 
|         |    845 		 | 
|         |    846 		iAtomWalker->WalkUpL(); | 
|         |    847 		} | 
|         |    848 		 | 
|         |    849 	// env-cc = "(" 1*address ")" / nil | 
|         |    850 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen) | 
|         |    851 		{ | 
|         |    852 		iAtomWalker->WalkDownL(); | 
|         |    853 		do | 
|         |    854 			{ | 
|         |    855 			ParseAddressL(address); | 
|         |    856 			envelope.AppendEnvCcL(address); | 
|         |    857 			 | 
|         |    858 			} while(iAtomWalker->WalkAcrossL(EFalse)); | 
|         |    859 		 | 
|         |    860 		iAtomWalker->WalkUpL(); | 
|         |    861 		} | 
|         |    862 		 | 
|         |    863 	// env-bcc = "(" 1*address ")" / nil | 
|         |    864 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen) | 
|         |    865 		{ | 
|         |    866 		iAtomWalker->WalkDownL(); | 
|         |    867 		do | 
|         |    868 			{ | 
|         |    869 			ParseAddressL(address); | 
|         |    870 			envelope.AppendEnvBccL(address); | 
|         |    871 			 | 
|         |    872 			} while(iAtomWalker->WalkAcrossL(EFalse)); | 
|         |    873 		 | 
|         |    874 		iAtomWalker->WalkUpL(); | 
|         |    875 		} | 
|         |    876 	 | 
|         |    877 	// env-in-reply-to = nstring | 
|         |    878 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    879 	envelope.SetEnvInReplyTo(iAtomWalker->CurrentDes(ETrue)); | 
|         |    880 	 | 
|         |    881 	// env-message-id = nstring	 | 
|         |    882 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    883 	envelope.SetEnvMessageId(iAtomWalker->CurrentDes(ETrue)); | 
|         |    884 	 | 
|         |    885 	iAtomWalker->WalkUpL(); | 
|         |    886 	} | 
|         |    887  | 
|         |    888 /** | 
|         |    889 address = "(" addr-name SP addr-adl SP addr-mailbox SP addr-host ")" | 
|         |    890  | 
|         |    891 This method expects iAtomWalker to be positioned at the opening bracket. | 
|         |    892 */ | 
|         |    893 void CImapBodyStructureBuilder::ParseAddressL(CImapEnvelope::TAddress& aAddress) | 
|         |    894 	{ | 
|         |    895 	// Always expect an open bracket here, so allow atom walker to leave if there is one | 
|         |    896 	iAtomWalker->WalkDownL(); | 
|         |    897 	 | 
|         |    898 	// addr-name = nstring | 
|         |    899 	aAddress.SetName(iAtomWalker->CurrentDes(ETrue)); | 
|         |    900 	 | 
|         |    901 	// addr-adl = nstring | 
|         |    902 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    903 	aAddress.SetAdl(iAtomWalker->CurrentDes(ETrue)); | 
|         |    904 	 | 
|         |    905 	// addr-mailbox = nstring | 
|         |    906 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    907 	aAddress.SetMailbox(iAtomWalker->CurrentDes(ETrue)); | 
|         |    908 	 | 
|         |    909 	// addr-host = nstring | 
|         |    910 	iAtomWalker->WalkAcrossL(ETrue); | 
|         |    911 	aAddress.SetHost(iAtomWalker->CurrentDes(ETrue)); | 
|         |    912 	 | 
|         |    913 	iAtomWalker->WalkUpL(); | 
|         |    914 	} |