email/imap4mtm/imapsession/src/cimapfetchbody.cpp
changeset 0 72b543305e3a
child 34 84197e66a4bd
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 #include "cimapfetchbody.h"
       
    17 #include "moutputstream.h"
       
    18 #include "cimapsession.h"
       
    19 #include "cimapsessionconsts.h"
       
    20 #include "cimapsettings.h"
       
    21 #include "cimapmimeheaderfieldsparser.h"
       
    22 #include "cimapmimeheaderfields.h"
       
    23 #include "cfetchbodyinfo.h"
       
    24 #include "cimapfetchbodyresponse.h"
       
    25 #include "cimaplogger.h"
       
    26 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
    27 #include "cimapcapabilityinfo.h"
       
    28 #endif
       
    29 
       
    30 const TInt KMaxTagIdSize = 8;
       
    31 const TInt KDefaultMaxFetchSize = 20480;
       
    32 const TInt KOutstandingRequests = 2;
       
    33 const TInt KOutstandingBinaryFetchRequests = 1;
       
    34 
       
    35 _LIT8(KCommandFetch, "%S UID FETCH %d (BODY[%S]<%d.%d>)\r\n");
       
    36 _LIT8(KCommandFetchWithMime, "%S UID FETCH %d (BODY[%S]<%d.%d> BODY[%S.MIME])\r\n");
       
    37 _LIT8(KCommandFetchPeek, "%S UID FETCH %d (BODY.PEEK[%S]<%d.%d>)\r\n");
       
    38 _LIT8(KCommandFetchPeekWithMime, "%S UID FETCH %d (BODY.PEEK[%S]<%d.%d> BODY.PEEK[%S.MIME])\r\n");
       
    39 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
    40 _LIT8(KCommandFetchBinary, "%S UID FETCH %d (BINARY[%S]<%d.%d>)\r\n");
       
    41 _LIT8(KCommandFetchBinaryPeek, "%S UID FETCH %d (BINARY.PEEK[%S]<%d.%d>)\r\n");
       
    42 #endif
       
    43 _LIT8(KStartSection,"[");
       
    44 _LIT8(KEndSection,"]");
       
    45 _LIT8(KStartLiteral,"{");
       
    46 _LIT8(KEndLiteral,"}");
       
    47 _LIT8(KStartOrigin,"<");
       
    48 _LIT8(KEndOrigin,">");
       
    49  
       
    50 CImapFetchBody* CImapFetchBody::NewL(CImapFolderInfo* aSelectedFolderData, TInt aLogId, TUint aMessageUid,TBool aPeek, CFetchBodyInfo& aFetchBodyInfo, CImapFetchBodyResponse& aFetchBodyResponse, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, CImapSession& aParent)
       
    51 	{
       
    52 	CImapFetchBody* self = new (ELeave) CImapFetchBody(aSelectedFolderData, aLogId, aMessageUid, aPeek, aFetchBodyInfo, aFetchBodyResponse, aImapSettings, aImapMailStore, aParent);
       
    53 	CleanupStack::PushL(self);
       
    54 	self->ConstructL();
       
    55 	CleanupStack::Pop(self);
       
    56 	return self;
       
    57 	}
       
    58 	
       
    59 CImapFetchBody::CImapFetchBody(CImapFolderInfo* aSelectedFolderData, TInt aLogId, TUint aMessageUid, TBool aPeek, CFetchBodyInfo& aFetchBodyInfo, CImapFetchBodyResponse& aFetchBodyResponse, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, CImapSession& aParent)
       
    60 	: CImapCommand(aSelectedFolderData, aLogId),
       
    61 	iMessageUid(aMessageUid),
       
    62 	iPeek(aPeek),
       
    63 	iSizeToFetch(aFetchBodyInfo.SizeToFetch()),
       
    64 	iImapSettings(aImapSettings),
       
    65 	iFetchBodyInfo(aFetchBodyInfo),
       
    66 	iImapMailStore(aImapMailStore),
       
    67 	iParent(aParent),
       
    68 	iFetchBodyResponse(aFetchBodyResponse),
       
    69 	iSendFetch(ETrue)
       
    70 	{
       
    71 	}
       
    72 	
       
    73 CImapFetchBody::~CImapFetchBody()
       
    74 	{
       
    75 	// ensure that iImapMailStore will not call StoreOperationComplete() 
       
    76 	// on this object now that it is being destoyed.
       
    77 	
       
    78 	delete iHeaderFieldsParser;
       
    79 	delete iBuf;
       
    80 	iTagIds.Reset();
       
    81 	}
       
    82 
       
    83 /**
       
    84 Overrides CImapCommand::Cancel() by cancelling any outstanding mail store operation.
       
    85 */
       
    86 void CImapFetchBody::Cancel()
       
    87 	{
       
    88 	__LOG_TEXT(iLogId, "CImapFetchBody::Cancel()"); // Overrides CImapCommand::Cancel()
       
    89 	
       
    90 	iImapMailStore.CancelRequest(*this);
       
    91 	CImapCommand::Cancel();
       
    92 	}
       
    93 
       
    94 void CImapFetchBody::StoreOperationComplete(TMsvId /*aId*/,TInt aErrorCode)
       
    95 	{
       
    96 	__LOG_FORMAT((iLogId, "CImapFetchBody::StoreOperationComplete aErrorCode = %d",aErrorCode));
       
    97 	iStoreComplete = ETrue;
       
    98 	
       
    99 	// Complete early if there is an error
       
   100 	if (aErrorCode != KErrNone)
       
   101 		{
       
   102 		__LOG_TEXT(iLogId, "CImapFetchBody::StoreOperationComplete - ERROR: Completing Early");
       
   103 		iParent.FetchBodyOperationComplete(aErrorCode);
       
   104 		}
       
   105 	// Otherwise complete only if the last tagged OK has been received.
       
   106 	else if(ParseState() == ECommandComplete)
       
   107 		{
       
   108 		// Call the session to let it know we are done
       
   109 		__ASSERT_DEBUG(iRequestCount == iTotalRequests && iOutstandingRequests == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EStoreOperationCompleteWithPendingRequest) );
       
   110 		iParent.FetchBodyOperationComplete(aErrorCode);
       
   111 		}
       
   112 	}
       
   113 	
       
   114 TBool CImapFetchBody::IsStoreOperationComplete()
       
   115 	{
       
   116 	return iStoreComplete;
       
   117 	}
       
   118 	
       
   119 void CImapFetchBody::ConstructL()
       
   120 	{
       
   121 	// obtain
       
   122 	iImapSettings.GetTransportBufferSizesL(iMaxFetchSize, iMaxOutstandingRequests);
       
   123 
       
   124 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)		
       
   125 	// check for BINARY capability
       
   126 	const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   127 	TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap);		
       
   128 #endif
       
   129 	
       
   130 	// if either parameter is undefined, resort to using the defaults.
       
   131 	if(iMaxFetchSize==0)
       
   132 		{
       
   133 		iMaxFetchSize=KDefaultMaxFetchSize;	
       
   134 		}
       
   135 	
       
   136 	if(iMaxOutstandingRequests==0)
       
   137 		{
       
   138 		iMaxOutstandingRequests=KOutstandingRequests;	
       
   139 		}
       
   140 
       
   141 	//calculate the number of chunks that will be needed
       
   142 	iTotalRequests=TotalRequestsRequired(iSizeToFetch);
       
   143 		
       
   144 	__LOG_FORMAT((iLogId, "CImapFetchBody::CImapFetchBody iTotalRequests = %d",iTotalRequests));
       
   145 	
       
   146 	
       
   147 	if(iFetchBodyInfo.IsText())
       
   148 		{
       
   149 		// check if chunk storage mechanism is enabled.
       
   150 		if(iImapSettings.StorePlainText())
       
   151 			{
       
   152 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   153 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   154 				{
       
   155 				iImapMailStore.InitialiseStorePlainBodyTextL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,*this, ETrue);
       
   156 				}
       
   157 			else
       
   158 #endif
       
   159 				{
       
   160 				iImapMailStore.InitialiseStorePlainBodyTextL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,*this);
       
   161 				}			
       
   162 			}
       
   163 		else
       
   164 			{
       
   165 			if(iImapSettings.Store8BitData())
       
   166 				{
       
   167 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   168 				if(binaryCapExist && iFetchBodyInfo.IsText())
       
   169 					{
       
   170 					iImapMailStore.InitialiseStoreBody8L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,ETrue);
       
   171 					}
       
   172 				else
       
   173 #endif
       
   174 					{
       
   175 					iImapMailStore.InitialiseStoreBody8L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this);
       
   176 					}						
       
   177 				}
       
   178 			else
       
   179 				{
       
   180 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   181 				if(binaryCapExist && iFetchBodyInfo.IsText())
       
   182 					{
       
   183 					iImapMailStore.InitialiseStoreBody16L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this,ETrue);		
       
   184 					}
       
   185 				else			
       
   186 #endif
       
   187 					{	
       
   188 					iImapMailStore.InitialiseStoreBody16L(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this);		
       
   189 					}
       
   190 				}
       
   191 			}
       
   192 		}
       
   193 	else
       
   194 		{
       
   195 		iImapMailStore.InitialiseStoreAttachmentL(iTotalRequests,iImapSettings,iFetchBodyInfo,iLogId,*this);	
       
   196 		}
       
   197 	}
       
   198 
       
   199 TInt CImapFetchBody::TotalRequestsRequired(TInt aSize)
       
   200 	{
       
   201 	
       
   202 	TInt chunkNumber = aSize / iMaxFetchSize;
       
   203 	
       
   204 	if( (aSize % iMaxFetchSize)>0)
       
   205 		{
       
   206 		//add a chunk for the last bit of data
       
   207 		++chunkNumber;
       
   208 		}	
       
   209 
       
   210 	return chunkNumber;	
       
   211 	}
       
   212 
       
   213 
       
   214 TInt CImapFetchBody::CalculateChunk(TInt aPos)
       
   215 	{
       
   216 	return aPos / iMaxFetchSize;
       
   217 	}
       
   218 
       
   219 /** 
       
   220 Formats and sends the IMAP UID FETCH command.
       
   221 @param aTagId Command sequence id which will be send along with the IMAP command.
       
   222 @param aStream A wrapper for the outbound stream of a connected socket, using which 
       
   223 the command will be send to the server
       
   224 */
       
   225 void CImapFetchBody::SendMessageL(TInt aTagId, MOutputStream& aStream)
       
   226 	{	
       
   227 	iOutStream=&aStream;
       
   228 	
       
   229 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)		
       
   230 	// check for BINARY capability
       
   231 	const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   232 	TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap);		
       
   233 	if(binaryCapExist && iFetchBodyInfo.IsText())
       
   234 		{
       
   235 		// if message body part is downloaded using FETCH BINARY, then there should be only one
       
   236 		// Outstanding Request
       
   237 		iOutstandingRequests = KOutstandingBinaryFetchRequests;
       
   238 		}
       
   239 	else
       
   240 #endif
       
   241 		{
       
   242 		//iOutstandingRequests is the smaller of iMaxOutstandingRequests and the total chunk count
       
   243 		iOutstandingRequests = iTotalRequests>iMaxOutstandingRequests ? iMaxOutstandingRequests : iTotalRequests;
       
   244 		}
       
   245 	// SendMessageL will increment the tag ID as the first thing it does, so we
       
   246 	// should set it to 1 lower than the fist tag we want to send.
       
   247 	iTagId = aTagId - 1;
       
   248 
       
   249 	SendMessageL();	
       
   250 	}
       
   251 	
       
   252 void CImapFetchBody::SendMessageL()
       
   253 	{
       
   254 	// Set the tag ID to use in the next message
       
   255 	++iTagId;
       
   256 
       
   257 	_LIT8(KTagFormatId, "%d");
       
   258 	TBuf8<KMaxTagIdSize>tagIdBuffer;
       
   259 	tagIdBuffer.Format(KTagFormatId,iTagId);
       
   260 	
       
   261 	iTagIds.InsertInOrder(iTagId);
       
   262 	
       
   263 	
       
   264 	//create fetch command based on settings	
       
   265 	//the offset from which we want to fetch data
       
   266 	TInt offset = iRequestCount*iMaxFetchSize;
       
   267 	
       
   268 	// calclulate the size to fetch in this request,
       
   269 	// default to max fetch size.
       
   270 	TUint sizeToFetch = iMaxFetchSize;
       
   271 	
       
   272 	TInt bufLength = 0;
       
   273 	bufLength += iFetchBodyInfo.RelativePath()->Length();
       
   274 	bufLength += TagLength(offset);
       
   275 	bufLength += TagLength(sizeToFetch);
       
   276 	bufLength += tagIdBuffer.Length();
       
   277 
       
   278 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   279 	// check for BINARY capability
       
   280 	// Issue binary fetch for plain/text part only
       
   281 	const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   282 	TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap);	
       
   283 #endif
       
   284 	if (iRequestCount == 0)
       
   285 		{
       
   286 		bufLength += iFetchBodyInfo.RelativePath()->Length();
       
   287 		
       
   288 		if (iPeek)
       
   289 			{
       
   290 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   291 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   292 				{
       
   293 				bufLength += KCommandFetchBinaryPeek().Length();
       
   294 				}
       
   295 			else
       
   296 #endif
       
   297 				{
       
   298 				bufLength += KCommandFetchPeekWithMime().Length();	
       
   299 				}
       
   300 			}
       
   301 		else
       
   302 			{
       
   303 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   304 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   305 				{	
       
   306 				bufLength += KCommandFetchBinary().Length();
       
   307 				}
       
   308 			else
       
   309 #endif
       
   310 				{
       
   311 				bufLength += KCommandFetchWithMime().Length();
       
   312 				}			
       
   313 			}
       
   314 		}
       
   315 	else
       
   316 		{
       
   317 		if(iPeek)
       
   318 			{
       
   319 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   320 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   321 				{
       
   322 				bufLength += KCommandFetchBinaryPeek().Length();
       
   323 				}
       
   324 			else
       
   325 #endif
       
   326 				{
       
   327 				bufLength += KCommandFetchPeek().Length();	
       
   328 				}			
       
   329 			}
       
   330 		else
       
   331 			{
       
   332 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   333 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   334 				{
       
   335 				bufLength += KCommandFetchBinary().Length();							
       
   336 				}
       
   337 			else
       
   338 #endif
       
   339 				{
       
   340 				bufLength += KCommandFetch().Length();			
       
   341 				}			
       
   342 			}
       
   343 		}
       
   344 
       
   345 	//now create the command	
       
   346 	HBufC8* buffer = HBufC8::NewL(bufLength);				
       
   347 	delete iOutputBuffer;
       
   348 	iOutputBuffer=buffer;
       
   349 
       
   350 	if (iRequestCount == 0)
       
   351 		{
       
   352 		if(iPeek)
       
   353 			{
       
   354 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   355 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   356 				{
       
   357 				iOutputBuffer->Des().Format(KCommandFetchBinaryPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath());				
       
   358 				}
       
   359 			else
       
   360 #endif
       
   361 				{
       
   362 				iOutputBuffer->Des().Format(KCommandFetchPeekWithMime, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath());
       
   363 				}			
       
   364 			}
       
   365 		else
       
   366 			{
       
   367 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   368 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   369 				{
       
   370 				iOutputBuffer->Des().Format(KCommandFetchBinary, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath());	
       
   371 				}
       
   372 			else
       
   373 #endif
       
   374 				{
       
   375 				iOutputBuffer->Des().Format(KCommandFetchWithMime, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch, iFetchBodyInfo.RelativePath());	
       
   376 				}
       
   377 			}
       
   378 		}
       
   379 	else
       
   380 		{
       
   381 		if(iPeek)
       
   382 			{
       
   383 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   384 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   385 				{
       
   386 				iOutputBuffer->Des().Format(KCommandFetchBinaryPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch);	
       
   387 				}
       
   388 			else
       
   389 #endif
       
   390 				{
       
   391 				iOutputBuffer->Des().Format(KCommandFetchPeek, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, sizeToFetch);	
       
   392 				}			
       
   393 			}
       
   394 		else
       
   395 			{
       
   396 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)	
       
   397 			if(binaryCapExist && iFetchBodyInfo.IsText())
       
   398 				{
       
   399 				iOutputBuffer->Des().Format(KCommandFetchBinary, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, iMaxFetchSize);								
       
   400 				}
       
   401 			else
       
   402 #endif
       
   403 				{
       
   404 				iOutputBuffer->Des().Format(KCommandFetch, &tagIdBuffer, iMessageUid, iFetchBodyInfo.RelativePath(), offset, iMaxFetchSize);				
       
   405 				}			
       
   406 			}
       
   407 		}
       
   408 
       
   409 	delete iBuf;
       
   410 	iBuf = NULL;
       
   411 	iReceivedMimeHeaders = EFalse;
       
   412 
       
   413 	//send the command to the server
       
   414 	iOutStream->SendDataReq(*iOutputBuffer);
       
   415 	++iRequestCount;
       
   416 	}
       
   417 
       
   418 /**
       
   419 @param aData Will contain a single line of response from the server for LOGIN command without \r\n.
       
   420 @return will be any one of this
       
   421 	1) If the next expected chunk is a literal block, ParseMessageL() will return the size of the block it expects.
       
   422 	2) If the next expected chunk is a line, ParseMessageL() will return 0, and Result() will return EImapResponseNone.
       
   423 	3) If no further data is expected (e.g. the OK or error tag has been received) then ParseMessageL() will return 0, 
       
   424 	   and Result() will return one of EImapResponseOk, EImapResponseNo or EImapResponseBad.
       
   425 */
       
   426 CImapCommand::TParseBlockResult CImapFetchBody::DoParseBlockL(const TDesC8& aData)
       
   427 	{
       
   428 		
       
   429 	CImapCommand::TParseBlockResult resultCode(ECompleteUntagged);
       
   430 
       
   431 	switch (iState)
       
   432 		{
       
   433 		case EStateDataItemLine:
       
   434 			{
       
   435 			// We are the beginning of a new response, so we can't have found any UID data items yet.
       
   436 			// So we need to reset the flag here.
       
   437 			iUidDataItemFoundInResponse = EFalse;
       
   438 			resultCode = ProcessStartL();
       
   439 			
       
   440 			ASSERT(iState == EStateDataItemLine);
       
   441 			
       
   442 			// If we get EResponseIncomplete then allow the current EStateDataItemLine state to
       
   443 			// drop through to ProcessDataItems()
       
   444 			// otherwise, EStateComplete will take us straight to the return.
       
   445 			if (resultCode != EResponseIncomplete)
       
   446 				{
       
   447 				iState = EStateComplete;
       
   448 				}
       
   449 			}
       
   450 			break;
       
   451 		case EStateBodyLiteral:
       
   452 			{
       
   453 			// Bump progress: bytesdone is *encoded* length, so we just use the encoded length
       
   454 			iFetchBodyInfo.IncrementBytesFetched(aData.Length());
       
   455 			
       
   456 			__ASSERT_DEBUG(aData.Length() == iLiteralSize, TImapServerPanic::ImapPanic(TImapServerPanic::ETParseBlockResultInvalidLiteralSize) );
       
   457 
       
   458 			ProcessBodyLiteralL(aData);
       
   459 			resultCode = EResponseIncomplete; // always expect more data after a literal
       
   460 			}
       
   461 			break;
       
   462 		case EStateMime:
       
   463 			{
       
   464 			ProcessRestOfMimeL(iUnparsedData);
       
   465 			resultCode = EResponseIncomplete;
       
   466 			}
       
   467 			break;
       
   468 		case EStateFetchNextDataItemLine:
       
   469 			{
       
   470 			// Fetch is over.  Get ready to process next data item.
       
   471 			iUnparsedData.Set(aData);
       
   472 			GetAndStoreNextPart();
       
   473 			
       
   474 			iState = EStateDataItemLine;
       
   475 			}
       
   476 			break;
       
   477 		default:
       
   478 			{
       
   479 			// unexpected state
       
   480 			ASSERT(EFalse);
       
   481 			}
       
   482 		}
       
   483 
       
   484 	// The ProcessXxxL() methods above can change the state.
       
   485 	// Now we need to check if there are data items to process...
       
   486 	if (iState == EStateDataItemLine)
       
   487 		{
       
   488 		resultCode = ProcessDataItemsL();
       
   489 		}
       
   490 	else if (iState == EStateComplete)
       
   491 		{
       
   492 		//if we still have more requests to issue send the next one now
       
   493 		
       
   494 		if(resultCode == ECompleteTagged)
       
   495 			{
       
   496 			if (iResponseCode == EImapResponseOk)
       
   497 				{
       
   498 				++iResponseCount;
       
   499 				// If we received some MIME headers, we may need to store them
       
   500 				// with the CAF framework
       
   501 				if ((iReceivedMimeHeaders) && (iFetchBodyInfo.Caf() != NULL) && (iFetchBodyInfo.Caf()->Registered()))
       
   502 					{
       
   503 					WriteMimeHeadersToCafL();
       
   504 					}
       
   505 
       
   506 				// Store the body data if we received it
       
   507 				if (iBuf != NULL)
       
   508 					{
       
   509 					TInt extraFetchRequestCount = 0;
       
   510 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)					
       
   511 					// check for BINARY capability
       
   512 					const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   513 					TBool binaryCapExist = capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap);					
       
   514 					if(binaryCapExist && iFetchBodyInfo.IsText() && iPreviousLiteralBytesReceived < KDefaultMaxFetchSize)
       
   515 						{
       
   516 						extraFetchRequestCount = iTotalRequests - iRequestCount;
       
   517 						// iTotalRequests, iRequestCount and iResponseCount should be same at this stage
       
   518 						// iResponseCount will be same as iRequestCount
       
   519 						iTotalRequests=iRequestCount;
       
   520 						//reset iPreviousLiteralBytesReceived to zero
       
   521 						iPreviousLiteralBytesReceived=0;										
       
   522 						}
       
   523 #endif
       
   524 						
       
   525 					StoreBodyDataL(extraFetchRequestCount);										
       
   526 					
       
   527 					if (iRequestCount<iTotalRequests)
       
   528 						{
       
   529 						// if there are outstanding requests already then just add this request to the count
       
   530 						++iOutstandingRequests;
       
   531 						
       
   532 						// If iOutstandingRequests is greater than one, this means a write operation is in progress
       
   533 						// and the message will be sent when SendDataCnf() is called.
       
   534 						if (iSendFetch && (iOutstandingRequests == 1))
       
   535 							{
       
   536 							SendMessageL();
       
   537 							}
       
   538 
       
   539 						resultCode=ECompleteUntagged;
       
   540 						iResponseCode=EImapResponseNone;
       
   541 						}
       
   542 					// if there are remaining requests yet to be received then tell the session were not finished.
       
   543 					else if(iResponseCount<iTotalRequests)
       
   544 						{
       
   545 						resultCode = ECompleteUntagged;	
       
   546 						iResponseCode=EImapResponseNone;	
       
   547 						}
       
   548 					}
       
   549 				// if there is no body part to be stored but server sent a OK responsethen set 
       
   550 				// iStoreComplete to ETrue and Cancel the Request.If more than one FETCH was sent
       
   551 				// then Flush the state so that all incoming server data is discarded.
       
   552 				else
       
   553 					{
       
   554 					iStoreComplete = ETrue;
       
   555 					iImapMailStore.CancelRequest(*this);	
       
   556 					
       
   557 					// Check the tag id
       
   558 					if(iTagIds.Count())
       
   559 						{
       
   560 						EnterFlushingState();
       
   561 						resultCode = ECompleteUntagged;
       
   562 						iResponseCode = EImapResponseNone;
       
   563 						}		
       
   564 					}
       
   565 				}
       
   566 			else
       
   567 				{
       
   568 				iImapMailStore.CancelRequest(*this);
       
   569 				}
       
   570 			}
       
   571 			
       
   572 		// this response is complete, so the next data (if any) will be a data item line,
       
   573 		iState = EStateDataItemLine;
       
   574 		}
       
   575 
       
   576 	// For complete untagged responses, check whether the UID data item was received.
       
   577 	// If it was, then this was a genuine response to the UID FETCH command.
       
   578 	// If it was not received, then this was an unsolicited server event, and the data should be discarded.
       
   579 	if (resultCode == ECompleteUntagged)
       
   580 		{
       
   581 		if (iUidDataItemFoundInResponse)
       
   582 			{
       
   583 			// Genuine UID FETCH response - copy UID and FLAG info into the response object
       
   584 			iFetchBodyResponse.SetMessageFlagInfo(iMessageFlagInfo);
       
   585 			
       
   586 			// Note: iUidDataItemFoundInResponse is NOT reset here
       
   587 			// 		 Instead iUidDataItemFoundInResponse is set to EFalse just prior to calling ProcessStartL() - i.e. at the start of a new response.
       
   588 			}
       
   589 		else
       
   590 			{
       
   591 			// Record that an unsolicited FETCH was received - so that a sync will be triggered after this command.
       
   592 			__LOG_TEXT(iLogId, "CImapFetchBody::DoParseBlockL() - Found unsolicited FETCH FLAGS");
       
   593 			SetMessageFlagsChanged();
       
   594 			}
       
   595 		}
       
   596 
       
   597 	return resultCode;
       
   598 	}
       
   599 
       
   600 /**
       
   601 Returns the number of tagged responses that are currently expected.
       
   602 Because CImapFetchBody uses pipelining - with many simulataneous request running at once
       
   603 it will be expect a tagged response for each request that is still running on the server.
       
   604 @return the number of tagged responses that are currently expected.
       
   605 */
       
   606 TInt CImapFetchBody::NumberOfTaggedResponsesExpected() const
       
   607 	{
       
   608 	return iTagIds.Count();
       
   609 	}
       
   610 	
       
   611 CImapCommand::TParseBlockResult CImapFetchBody::ProcessStartL()
       
   612 	{
       
   613 	TParseBlockResult result = ENotRecognised;
       
   614 
       
   615 	TInt tagId = 0;	
       
   616 	TTagType tagged = GetTagTypeL(tagId);
       
   617 	switch(tagged)
       
   618 		{
       
   619 		case ETagged:
       
   620 			{
       
   621 			// Check the tag id
       
   622 			TInt tagPos=iTagIds.FindInOrder(tagId);
       
   623 			if(tagPos!=KErrNotFound)
       
   624 				{
       
   625 				iTagIds.Remove(tagPos);	
       
   626 				}
       
   627 			else
       
   628 				{
       
   629 				//Unexpected Tagid	
       
   630 	 			CorruptDataL();	
       
   631 				}
       
   632 	 		
       
   633  			// Fetch and check the response code
       
   634 			iResponseCode = GetResponseStateCode();
       
   635 			if (iResponseCode == EImapResponseNone)
       
   636 				{
       
   637 				// Was expecting one of OK/NO/BAD, but didn't get it.  This is a parse error.
       
   638 				CorruptDataL();
       
   639 				}
       
   640 				
       
   641 			result =ECompleteTagged;		
       
   642 			}
       
   643 			break;
       
   644 			
       
   645 		case EUntagged:
       
   646 			{
       
   647 			// Is this a FETCH response?
       
   648 			// Check for Sequence Number followed by "FETCH"
       
   649 			
       
   650 			TPtrC8 part1 = GetNextPart(); // returns KNullDesC8 if there is no part available
       
   651 			TPtrC8 part2 = GetNextPart(); // returns KNullDesC8 if there is no part available
       
   652 			
       
   653 			// Is part1 a Sequence Number?
       
   654 			TInt sequenceNumber = 0;
       
   655 			TLex8 lex(part1);
       
   656 			if (lex.Val(sequenceNumber) == KErrNone)
       
   657 				{
       
   658 				// part1 is a Sequence Number.  Now check part2 - is it "FETCH"?
       
   659 
       
   660 				if(part2.CompareF(KImapTxtFetch) == 0)
       
   661 					{
       
   662 										
       
   663 					if (GetAndStoreNextPart())
       
   664 						{
       
   665 						if (iCurrentPart[0] == '(')
       
   666 							{
       
   667 							iCurrentPart.Set(iCurrentPart.Mid(1));
       
   668 							}
       
   669 						else
       
   670 							{
       
   671 							// was expecting a bracket, got something else
       
   672 							CorruptDataL();
       
   673 							}
       
   674 						}
       
   675 					else
       
   676 						{
       
   677 						// was expecting a bracket, got nothing
       
   678 						CorruptDataL();
       
   679 						}
       
   680 
       
   681 					result = EResponseIncomplete;
       
   682 					}
       
   683 				}
       
   684 			}
       
   685 			break;
       
   686 		case EContinuation:
       
   687 		default:
       
   688 			{
       
   689 			CorruptDataL();
       
   690 			}
       
   691 			break;
       
   692 		}
       
   693 
       
   694 	// result will be ENotRecognised if tagged not found or untagged FETCH not found.
       
   695 	return result;
       
   696 	}
       
   697 
       
   698 CImapCommand::TParseBlockResult CImapFetchBody::ProcessDataItemsL()
       
   699 	{
       
   700 	CImapCommand::TParseBlockResult resultCode = EResponseIncomplete;
       
   701 	
       
   702 	TBool foundPart = ETrue;
       
   703 	while (iState == EStateDataItemLine && foundPart)
       
   704 		{
       
   705 		if (iCurrentPart.CompareF(KImapTxtUid) == 0)
       
   706 			{
       
   707 			ProcessUidL();
       
   708 			}
       
   709 		else if (iCurrentPart.CompareF(KImapTxtFlags) == 0)
       
   710 			{
       
   711 			ProcessFlagsL();
       
   712 			}
       
   713 	
       
   714 		// check if the part starts 'BODY['	
       
   715 		else if (iCurrentPart.Find(KImapTxtBody)==0)
       
   716 			{
       
   717 			//is it the body or the body.mime?
       
   718 			if(iCurrentPart.Find(KImapTxtMime) != KErrNotFound )
       
   719 				{
       
   720 				ProcessStartOfMimeL();
       
   721 				}
       
   722 			else
       
   723 				{
       
   724 				ProcessBodyL();	
       
   725 				}
       
   726 			}
       
   727 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   728 		// check if the part starts 'BINARY['	
       
   729 		else if (iCurrentPart.Find(KImapTxtBinary)==0)
       
   730 			{
       
   731 			// no mime to process for fetch binary
       
   732 			ProcessBodyL();	
       
   733 			}
       
   734 #endif
       
   735 	
       
   736 		// Only fetch the next part if we're still searching for data items.
       
   737 		if (iState == EStateDataItemLine)
       
   738 			{
       
   739 			foundPart = GetAndStoreNextPart();
       
   740 			}
       
   741 		}
       
   742 		
       
   743 	if (!foundPart && iState == EStateDataItemLine)
       
   744 		{
       
   745 		if(iBuf && iUnexpectedFormat)
       
   746 			{
       
   747 			iState = EStateFetchNextDataItemLine;
       
   748 			iUnexpectedFormat = EFalse;
       
   749 			}
       
   750 		resultCode = ECompleteUntagged;
       
   751 		}
       
   752 	iUnexpectedFormat = EFalse;	
       
   753 	return resultCode;
       
   754 	}
       
   755 
       
   756 
       
   757 void CImapFetchBody::ProcessStartOfMimeL()
       
   758 	{
       
   759 	//look for the body section that is being returned 
       
   760 	TInt secStart=iCurrentPart.Find(KStartSection);
       
   761 	TInt secEnd=iCurrentPart.Find(KImapTxtMime);
       
   762 
       
   763 	if(secStart==KErrNotFound || secEnd==KErrNotFound)
       
   764 		{
       
   765 		CorruptDataL();
       
   766 		}
       
   767 
       
   768 	TPtrC8 section = iCurrentPart.Mid(secStart + 1, secEnd - secStart - 1);
       
   769 
       
   770 	//check the section is what we asked for
       
   771 	if(section.CompareF(*iFetchBodyInfo.RelativePath())  != 0)
       
   772 		{
       
   773 		CorruptDataL();
       
   774 		}
       
   775 
       
   776 	// Peek the next part. We don't want to consume it as we may need
       
   777 	// to pass it to the header fields parser.
       
   778 	iCurrentPart.Set(PeekNextPart());
       
   779 	if (iCurrentPart.Length() == 0)
       
   780 		{
       
   781 		CorruptDataL();
       
   782 		}
       
   783 
       
   784 	iReceivedMimeHeaders = ETrue;
       
   785 	
       
   786 	// If the last character is ')' then we're at the last data item in the list.
       
   787 	// Consume the character so that the rest of the data item can be interpreted.
       
   788 	if (iCurrentPart.Right(1).CompareF(KImapTxtCloseBracket) == 0)
       
   789 		{
       
   790 		iCurrentPart.Set(iCurrentPart.Left(iCurrentPart.Length() - 1));
       
   791 		}
       
   792 	
       
   793 	// Check if data part is NIL or "" for empty string
       
   794 	if (iCurrentPart.CompareF(KImapTxtNil) == 0 || iCurrentPart.CompareF(KImapTxtEmptyStringAsDoubleQuotePair) == 0)
       
   795 		{
       
   796 		// Consume the NIL part
       
   797 		GetAndStoreNextPart();
       
   798 
       
   799 		// Create empty MIME header fields
       
   800 		CImapMimeHeaderFields* fields = CImapMimeHeaderFields::NewL();
       
   801 		iFetchBodyResponse.SetHeaderFields(fields);
       
   802 
       
   803 		// May be more data items coming up
       
   804 		iState = EStateDataItemLine;
       
   805 		}
       
   806 	else
       
   807 		{
       
   808 		// Pass the rest of the line to the header fields parser
       
   809 		iHeaderFieldsParser = CImapMimeHeaderFieldsParser::NewL(iFetchBodyResponse, iLogId);
       
   810 		iState = EStateMime;
       
   811 		ProcessRestOfMimeL(iUnparsedData);
       
   812 		}
       
   813 	}
       
   814 
       
   815 void CImapFetchBody::ProcessRestOfMimeL(const TDesC8& aData)
       
   816 	{
       
   817 	TBool wantsMore = iHeaderFieldsParser->ProcessBlockL(aData);
       
   818 
       
   819 	if (!wantsMore)
       
   820 		{
       
   821 		delete iHeaderFieldsParser;
       
   822 		iHeaderFieldsParser = NULL;
       
   823 		iState = EStateFetchNextDataItemLine;
       
   824 		}
       
   825 	}
       
   826 
       
   827 void CImapFetchBody::ProcessBodyL()
       
   828 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   829 	{//BODY[1]<0> or BINARY[1]<0>
       
   830 #else
       
   831 	{//BODY[1]<0>
       
   832 #endif	
       
   833 	//look for the body section that is being returned 
       
   834 	TInt secStart=iCurrentPart.Find(KStartSection);
       
   835 	TInt secEnd=iCurrentPart.Find(KEndSection);
       
   836 	
       
   837 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
   838 	const CImapCapabilityInfo& capabilityInfo = iParent.CapabilityInfo();
       
   839 	if(capabilityInfo.QueryFlag(CImapCapabilityInfo::EBinaryCap) && iFetchBodyInfo.IsText())
       
   840 		{
       
   841 		if(secStart!=KImapTxtBinary().Length() - 1  || secEnd <= secStart + 1)
       
   842 			{
       
   843 			CorruptDataL();
       
   844 			}
       
   845 		}
       
   846 	else
       
   847 #endif 
       
   848 		{
       
   849 		if(secStart!=KImapTxtBody().Length() - 1  || secEnd <= secStart + 1)
       
   850 			{
       
   851 			CorruptDataL();
       
   852 			}						
       
   853 		}
       
   854 			
       
   855 	TPtrC8 section=iCurrentPart.Mid(secStart+1,secEnd-secStart-1);
       
   856 	
       
   857 	//check the section is what we asked for
       
   858 	if(section.CompareF(*iFetchBodyInfo.RelativePath())  != 0)
       
   859 		{
       
   860 		CorruptDataL();
       
   861 		}
       
   862 	
       
   863 	//get the origin octet of the form <origin>, this may not exist, if its not
       
   864 		//then the origin is at the start of the data
       
   865 	TInt originStart=iCurrentPart.Find(KStartOrigin);
       
   866 	if(originStart==KErrNotFound)
       
   867 		{
       
   868 		//the origin octet will be 0, the data will  go in the first chunk
       
   869 		iCurrentChunk=0;		
       
   870 		}
       
   871 	else
       
   872 		{
       
   873 		if(originStart != secEnd + 1)
       
   874 			{
       
   875 			CorruptDataL();
       
   876 			}
       
   877 		TInt originEnd=iCurrentPart.Find(KEndOrigin);
       
   878 		if(originEnd==KErrNotFound || originEnd != iCurrentPart.Length() - 1 )
       
   879 			{
       
   880 			CorruptDataL();	
       
   881 			}
       
   882 		if(originEnd <= originStart + 1)
       
   883 			{
       
   884 			CorruptDataL();	
       
   885 			}
       
   886 			
       
   887 		TPtrC8 originPtr=iCurrentPart.Mid(originStart+1,originEnd-originStart-1);
       
   888 		TLex8 originToInt(originPtr);
       
   889 	
       
   890 		TInt origin=0;
       
   891 		TInt err = originToInt.Val(origin);
       
   892 		if (err != KErrNone)
       
   893 			{
       
   894 			// Was expecting originPtr to be a number
       
   895 			CorruptDataL();
       
   896 			}
       
   897 		
       
   898 		//set the chunk number
       
   899 		//if the origin was blank ie. <> then this is set to 0, the start of the data 
       
   900 		iCurrentChunk = CalculateChunk(origin);
       
   901 		}
       
   902 		
       
   903 	//now look for the size of the literal
       
   904 	TBool foundPart = GetAndStoreNextPart();
       
   905 	if(!foundPart)
       
   906 		{
       
   907 		CorruptDataL();	
       
   908 		}
       
   909 		
       
   910 	TInt litStart=iCurrentPart.Find(KStartLiteral);
       
   911 	TInt litEnd=iCurrentPart.Find(KEndLiteral);
       
   912 	
       
   913 	if(litStart==KErrNotFound && litEnd==KErrNotFound)
       
   914 		{
       
   915 		// This may be the data item
       
   916 		ProcessBodyLiteralL(iCurrentPart);
       
   917 		iState = EStateDataItemLine;
       
   918 		iUnexpectedFormat = ETrue;
       
   919 		}
       
   920 	else
       
   921 		{
       
   922 		if(litStart==KErrNotFound || litEnd==KErrNotFound)
       
   923 			{
       
   924 			CorruptDataL();	
       
   925 			}
       
   926 
       
   927 		if(litEnd <= litStart + 1)
       
   928 			{
       
   929 			CorruptDataL();	
       
   930 			}
       
   931 
       
   932 		TPtrC8 litPtr=iCurrentPart.Mid(litStart+1,litEnd-litStart-1);
       
   933 		TLex8 litSizeToInt(litPtr);
       
   934 		
       
   935 		TInt err = litSizeToInt.Val(iLiteralSize);
       
   936 		if (err != KErrNone)
       
   937 			{
       
   938 			// Was expecting litPtr to be a number
       
   939 			CorruptDataL();
       
   940 			}
       
   941 		
       
   942 		if(GetAndStoreNextPart())
       
   943 			{
       
   944 			ProcessBodyLiteralL(iCurrentPart);
       
   945 			iState = EStateDataItemLine;
       
   946 			iUnexpectedFormat = ETrue;
       
   947 			}
       
   948 		else
       
   949 			{
       
   950 			//now wait for the litereral
       
   951 			iState = EStateBodyLiteral;
       
   952 			}
       
   953 		}
       
   954 	}
       
   955 	
       
   956 void CImapFetchBody::ProcessBodyLiteralL(const TDesC8& aData)
       
   957 	{
       
   958 	delete iBuf;
       
   959 	iBuf = NULL;
       
   960 	iBuf = aData.AllocL();
       
   961 	
       
   962 	//now wait for the line that always follows a literal
       
   963 	iState = EStateFetchNextDataItemLine;
       
   964 	}
       
   965 
       
   966 /**
       
   967 Move to the next part
       
   968 @return whether a part was found
       
   969 */
       
   970 TBool CImapFetchBody::GetAndStoreNextPart()
       
   971 	{
       
   972 	iCurrentPart.Set(GetNextPart());
       
   973 	return (iCurrentPart.Length() > 0) ? ETrue : EFalse;
       
   974 	}
       
   975 
       
   976 void CImapFetchBody::ProcessFlagsL()
       
   977 	{
       
   978 	iUnparsedData.Set(iMessageFlagInfo.ParseFlagsL(iUnparsedData));
       
   979 	}
       
   980 
       
   981 void CImapFetchBody::ProcessUidL()
       
   982 	{
       
   983 	if (GetAndStoreNextPart())
       
   984 		{
       
   985 		TInt err = iMessageFlagInfo.SetMessageUid(iCurrentPart);
       
   986 		if (err == KErrNone)
       
   987 			{
       
   988 			iUidDataItemFoundInResponse = ETrue;
       
   989 			}
       
   990 		else
       
   991 			{
       
   992 			// expected iCurrentPart to be a number representing a UID.
       
   993 			// but we did not get a number.
       
   994 			CorruptDataL();
       
   995 			}
       
   996 		}
       
   997 	}
       
   998 
       
   999 void CImapFetchBody::WriteMimeHeadersToCafL()
       
  1000 	{
       
  1001 	CImapMimeHeaderFields* fields = iFetchBodyResponse.HeaderFields();
       
  1002 	if (fields != NULL)
       
  1003 		{
       
  1004 		TPtrC8 name;
       
  1005 		TPtrC8 value;
       
  1006 
       
  1007 		fields->RestartGetNextField();
       
  1008 		while (fields->GetNextField(name, value))
       
  1009 			{
       
  1010 			__LOG_FORMAT((iLogId, "Add CAF metadata: %S %S", &name, &value));
       
  1011 			iFetchBodyInfo.Caf()->AddToMetaDataL(name, value);
       
  1012 			}
       
  1013 		}
       
  1014 	}
       
  1015 
       
  1016 void CImapFetchBody::StoreBodyDataL(TBool aExtraFetchRequestCount)
       
  1017 	{
       
  1018 	// We are going to pass the buffer to the mail store, so set our
       
  1019 	// buffer to NULL so that we don't try to delete it if the store
       
  1020 	// routine leaves.
       
  1021 	HBufC8* buf(iBuf);
       
  1022 	iBuf = NULL;
       
  1023 
       
  1024 	if(iFetchBodyInfo.IsText())
       
  1025 		{
       
  1026 		if(iImapSettings.StorePlainText())
       
  1027 			{
       
  1028 			iSendFetch = iImapMailStore.StorePlainBodyTextL(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount);
       
  1029 			}
       
  1030 		else
       
  1031 			{
       
  1032 			if(iImapSettings.Store8BitData())
       
  1033 				{
       
  1034 				iImapMailStore.StoreBodyChunk8L(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount);
       
  1035 				}
       
  1036 			else
       
  1037 				{
       
  1038 				iImapMailStore.StoreBodyChunk16L(buf,iFetchBodyInfo.PartId(),iCurrentChunk,aExtraFetchRequestCount);	
       
  1039 				}
       
  1040 			}
       
  1041 		}
       
  1042 	else //attachments
       
  1043 		{
       
  1044 		iImapMailStore.StoreAttachmentChunkL(buf,iFetchBodyInfo.PartId(),iCurrentChunk);
       
  1045 		}
       
  1046 	}
       
  1047 
       
  1048 /**
       
  1049 If pipelining is enabled then this method will send the next fetch request to the server after confirmation of the last request having been sent.
       
  1050 @return void
       
  1051 */ 
       
  1052 
       
  1053 
       
  1054 void CImapFetchBody::SendDataCnfL()
       
  1055 	{
       
  1056 	ASSERT(iOutstandingRequests>0);
       
  1057 	--iOutstandingRequests;
       
  1058 	//if we want more requests outstanding then send the next one now
       
  1059 	if(iOutstandingRequests>0 && iSendFetch)
       
  1060 		{
       
  1061 		SendMessageL();	
       
  1062 		}
       
  1063 	}
       
  1064 /**
       
  1065 This method will enable the FETCH command to be send to the server if it was
       
  1066 disabled by CImapMailStore due to reciept of out-of-order chunks.
       
  1067 @return void
       
  1068 */	
       
  1069 void CImapFetchBody::EnableSendFetch()
       
  1070 	{
       
  1071 	iSendFetch = ETrue;
       
  1072 	}