email/pop3andsmtpmtm/smtpservermtm/src/IMSMFILE.CPP
changeset 0 72b543305e3a
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 1998-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 // File Mailer for Internet SMTP Transport Driver
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <mentact.h>		// CMsgActive
       
    19 #include <msvstd.h>			// TMsvEntry, CMsvEntrySelection
       
    20 #include <msventry.h>		// CMsvServerEntry
       
    21 #include <msvstore.h>		// CMsvStore
       
    22 #include <miutpars.h>		// TImMessageField
       
    23 #include <miuthdr.h>		// CImHeader
       
    24 #include <imcvsend.h>		// CImSendMessage
       
    25 
       
    26 #include "SMTS.H"
       
    27 #include "IMSM.H"			// KSmtpFilePriority
       
    28 #include "IMSMSEND.H"		// CImSmtpFile
       
    29 #include "SMTSUTIL.H"		// forward declarations for utility fns
       
    30 
       
    31 const TInt KMsvSuspendCheckGranuality=15;
       
    32 
       
    33 //As per RFC-2821(Section: 4.5.3.2 Timeouts) Maximum time out for Data termination is 10 minutes. 
       
    34 const TInt KSmtpDataTerminationTimeout=600;
       
    35 
       
    36 CImSmtpFile* CImSmtpFile::NewL(CImTextServerSession& aSocket,  
       
    37 							   CMsvServerEntry& aServerEntry,
       
    38 							   TTime& aTime,
       
    39 							   TBuf8<KImMailMaxBufferSize>& aSmtpBuffer,
       
    40 							   CSmtpSettings& aSettings,TBool aIsBccRcpt)
       
    41 	{
       
    42 	CImSmtpFile* self= new (ELeave) CImSmtpFile(aSocket,aSmtpBuffer,aServerEntry);
       
    43 	CleanupStack::PushL(self);
       
    44 	self->ConstructL(aTime,aSettings,aIsBccRcpt);
       
    45 	CleanupStack::Pop();	                                
       
    46 	return self;
       
    47 	}
       
    48 
       
    49 
       
    50 CImSmtpFile::CImSmtpFile(CImTextServerSession& aSocket,TBuf8<KImMailMaxBufferSize>& aSmtpBuffer,CMsvServerEntry &aServerEntry) 
       
    51 			: CMsgActive(KImSmtpFilePriority),
       
    52 			  iSocket(aSocket),
       
    53 			  iServerEntry(aServerEntry),
       
    54 			  iSmtpBuffer(aSmtpBuffer)															 
       
    55 
       
    56 	{
       
    57 	__DECLARE_NAME(_S("CImSmtpFile"));
       
    58 	}
       
    59 
       
    60 void CImSmtpFile::ConstructL(TTime& aTimeNow,CSmtpSettings& aSettings,TBool aIsBccRcpt) 
       
    61 
       
    62 	{
       
    63 	iSendCopyToSelf=aSettings.SendCopyToSelf();
       
    64 
       
    65 	iRecipientType = aIsBccRcpt? ERcptBcc : ERcptTo;
       
    66 
       
    67 	// Create and Initialise the CImSendMessage object..
       
    68 	iSendMessage = CImSendMessage::NewL(iServerEntry);
       
    69 
       
    70 	// Create objects to store header and body form the message file
       
    71 	// Read contents of message file into containers
       
    72 	iHeader = CImHeader::NewLC();		//  PushL(iHeader)
       
    73 	CleanupStack::Pop();			    //  iHeader
       
    74 
       
    75 	iEntryId=iServerEntry.Entry().Id();
       
    76 
       
    77 	CMsvStore* store = iServerEntry.EditStoreL();
       
    78 	CleanupStack::PushL(store);
       
    79 
       
    80 	// The message store entry always uses UTC, so set it now because the call to
       
    81 	// GetHeaderFromStoreL updates the time on that entry.
       
    82 	aTimeNow.UniversalTime();
       
    83 	GetHeaderFromStoreL(*store,iServerEntry, aTimeNow);	// Read ImHeader object from message file
       
    84 	CleanupStack::PopAndDestroy();//store
       
    85 
       
    86 	//  Sets iBodyType (TImBodyConvAlgorithm).
       
    87 	SelectBodyEncodingTypeL(aSettings.BodyEncoding(), iHeader->BodyEncoding());  
       
    88 
       
    89 	// Create the message to send.
       
    90 	// Note that when sending the message, we use the HomeTime as opposed to UniversalTime.
       
    91 	// This is because RFC822 mandates that the time in emails should be local time.
       
    92 	TTime homeTime;
       
    93 	homeTime.HomeTime();
       
    94 	iSendMessage->InitialiseL(iEntryId,iBodyType, homeTime, aSettings.ServerAddress(),
       
    95 									  aSettings.DefaultMsgCharSet().iUid, aSettings.SendCopyToSelf());
       
    96 
       
    97 	CActiveScheduler::Add(this);	// Add SmtpFile to scheduler's queue
       
    98 	}
       
    99 
       
   100 
       
   101 void CImSmtpFile::SetBytesToSend(TInt aNumBytes)
       
   102 	{
       
   103 	// Set the number of Bytes to send
       
   104 	iBytesToSend = aNumBytes;
       
   105 	}
       
   106 
       
   107 TInt CImSmtpFile::BytesToSend() const
       
   108 	{
       
   109 	return iBytesToSend;
       
   110 	}
       
   111 
       
   112 TInt CImSmtpFile::TotalMsgSizeL()
       
   113 // Return the Size of this Message
       
   114 	{
       
   115 	TInt msgSize = 0;
       
   116 	if (iSendMessage)
       
   117 		{
       
   118 		// factor of 4/3 is here to attempt to take account of the increase in size that will happen
       
   119 		// when the message is encoded
       
   120 		msgSize = TInt((4.0/3)*(iSendMessage->HeaderSize() + iSendMessage->BodySizeL()));
       
   121 		}
       
   122 
       
   123 	return msgSize;
       
   124 	}
       
   125 
       
   126 
       
   127 void CImSmtpFile::GetHeaderFromStoreL(CMsvStore& aStore, CMsvServerEntry& aServerEntry, TTime& aTimeNow)
       
   128 	{
       
   129 	// Retrieve the CImHeader object 
       
   130 	iHeader->RestoreL(aStore);
       
   131 
       
   132 	TMsvEntry entry = aServerEntry.Entry();
       
   133 	entry.iDate=aTimeNow;
       
   134 	entry.SetSendingState(KMsvSendStateSending);
       
   135 	entry.SetFailed(EFalse);
       
   136 	aServerEntry.ChangeEntry(entry);
       
   137 	} 
       
   138 
       
   139 
       
   140 void CImSmtpFile::StartL(TRequestStatus& aSessionStatus)
       
   141 	{
       
   142 	// Start sending the message file, by initialising the state machine
       
   143 	iCompleted=KErrNone;
       
   144 	iRecipientArray=NULL;
       
   145 	iState=EResettingSmtp;
       
   146 
       
   147 	ChangeStateL();			// Start the state machine
       
   148 	Queue(aSessionStatus);
       
   149 	}
       
   150 
       
   151 
       
   152 void CImSmtpFile::GetProgress(TImImailFileProgress& aFileProgress)
       
   153     {
       
   154 	// Return info about how much of message has been sent so far
       
   155 	aFileProgress.iBytesToSend = iBytesToSend;
       
   156 	aFileProgress.iBytesSent = iBytesSent;
       
   157 	aFileProgress.iSessionState = (TSmtpSessionState)iState;
       
   158 	}
       
   159 
       
   160 
       
   161 void CImSmtpFile::DoCancel()
       
   162     {
       
   163 	// Cancel any pending socket call
       
   164 	iSocket.Cancel();
       
   165 	CMsgActive::DoCancel();		// MUST be the last statement in DoCancel();
       
   166     }
       
   167 
       
   168 
       
   169 TInt CImSmtpFile::State()
       
   170 	{
       
   171 	// return current state of state machine
       
   172 	return iState;
       
   173 	}
       
   174 
       
   175 
       
   176 TBool CImSmtpFile::NextRecipientL()
       
   177 	{
       
   178 	// Return True if there is another recipient identified in imheader;
       
   179 	//	...if True, then "iRecipient" is set to point to next email address descriptor.
       
   180 	//
       
   181 	// This function scans through empty "To" and "Cc" fields
       
   182 	// if necessary to locate another recipient email address.
       
   183 
       
   184 	//Precondition: 'Bcc' recipients are dealt with in CImSmtpSession 
       
   185 	if(iRecipientType==ERcptBcc)
       
   186 		return EFalse;
       
   187 
       
   188 	if (!iRecipientArray)
       
   189 		{
       
   190 		// Nextrecipient has been called for the 1st time, so get "To:" list from CImHeader
       
   191 		iRecipientArray = &iHeader->ToRecipients();
       
   192 		if (iSendCopyToSelf==ESendCopyAsToRecipient)
       
   193 			{
       
   194 			if ( iHeader->ReceiptAddress().Length() )
       
   195 				iRecipientArray->AppendL(iHeader->ReceiptAddress());
       
   196 			else if ( iHeader->ReplyTo().Length() )
       
   197 				iRecipientArray->AppendL(iHeader->ReplyTo());
       
   198 			}
       
   199 		iRecipientIndex = 0;
       
   200 		iRecipientType = ERcptTo;
       
   201 		}
       
   202 
       
   203 	while ((iRecipientIndex >= iRecipientArray->Count()) && (iRecipientType <= ERcptCc))
       
   204 		{
       
   205 		// Find the next Email address (if it exists)
       
   206 		iRecipientArray = &iHeader->CcRecipients();
       
   207 		if (iSendCopyToSelf==ESendCopyAsCcRecipient)
       
   208 			{
       
   209 			if ( iHeader->ReceiptAddress().Length() )
       
   210 				iRecipientArray->AppendL(iHeader->ReceiptAddress());
       
   211 			else if ( iHeader->ReplyTo().Length() )
       
   212 				iRecipientArray->AppendL(iHeader->ReplyTo());
       
   213 			}
       
   214 		iRecipientIndex=0;
       
   215 		iRecipientType++;
       
   216 		}
       
   217 
       
   218 	if (iRecipientType <= ERcptCc)
       
   219 		{
       
   220 		iRecipient.Set((*iRecipientArray)[iRecipientIndex++]);
       
   221 		return ETrue;	// Found an email address; iRecipient points to it now.
       
   222 		}
       
   223 	return EFalse;	// iRecipientType>ERcptCc, so tell caller there are no more Email addresses left
       
   224 	}
       
   225 
       
   226 
       
   227 void CImSmtpFile::DoRunL()
       
   228     {
       
   229 	iCompleted=iStatus.Int();	// remember completion code - which is >= KErrNone
       
   230 
       
   231 	if (iState!=ESendData && iCompleted==KErrNone)
       
   232 		{
       
   233 		TInt SmtpCode = ESmtpNoReturnCode;
       
   234 		TBool CommandAccepted = GetCurrentTextLine();
       
   235 		if (CommandAccepted)
       
   236 			{
       
   237 			SmtpCode = SmtpResponseCode(iSmtpBuffer,iSmtpMultiLineResponse,iSmtpLastMultiLineResponse);			// parse out SMTP code from text response
       
   238 			CommandAccepted = LastSmtpCommandAccepted(SmtpCode,SmtpFilePositiveResponse(iState));	// was response accepted by remote server?
       
   239 			}
       
   240 
       
   241 		// "RSET", "DATA" and "." SMTP commands should never return a multi line response		
       
   242 		__ASSERT_DEBUG(iState!=ESendData,gPanic(EImsmBodyTextNotHandledHere));
       
   243 
       
   244 		if ((!CommandAccepted) && (iCompleted==KErrNone))
       
   245 			{
       
   246 			// Record an SMTP error only if no other error has been signalled.
       
   247 			iCompleted = SmtpFileError(SmtpCode);
       
   248 			}
       
   249 		}
       
   250 
       
   251 	if ((iState==EEndData) || (iCompleted!=KErrNone))
       
   252 		{
       
   253 		//  I have completed last state, or an error has occurred... 
       
   254 		//  so don't requeue state machine
       
   255 		return;
       
   256 		}
       
   257 
       
   258 	// Normal situation... choose the next state...
       
   259 	iState=SelectNextStateL();
       
   260 	ChangeStateL();	
       
   261     }
       
   262 
       
   263 
       
   264 TInt CImSmtpFile::SmtpFilePositiveResponse(TInt aState)
       
   265 	{
       
   266 	// Utility function returns 1st digit of 3 digit response code which
       
   267 	// I expect the remote SMTP server to return if last command succeeded.
       
   268 	TInt ExpectedFirstDigit;
       
   269 
       
   270 	if (aState==EBeginData)
       
   271 		{
       
   272 		ExpectedFirstDigit = 3;		// SMTP server should repond to "DATA" command with code "324"
       
   273 		}
       
   274 	else
       
   275 		{
       
   276 		ExpectedFirstDigit = 2;		// SMTP server should normally respond with code "250"
       
   277 		}
       
   278 	return ExpectedFirstDigit;
       
   279 	}
       
   280 
       
   281 
       
   282 TInt CImSmtpFile::SelectNextStateL()
       
   283 	{
       
   284 	// Choose the next state for the state machine
       
   285 	TInt NextState;
       
   286 
       
   287 	switch (iState)
       
   288 		{
       
   289 	case ERcptToSmtp:	// is there another recipient address?
       
   290 		NextState = (NextRecipientL()) ? ERcptToSmtp : EBeginData;
       
   291 		break;
       
   292 	case ESendData:		// is there any more data to send?
       
   293 		NextState = iMoreRfc822Data ? ESendData : EEndData;
       
   294 		break;
       
   295 	default:
       
   296 		NextState = iState+1;	
       
   297 		break;
       
   298 		}
       
   299 
       
   300 	return NextState;
       
   301 	}
       
   302 
       
   303 
       
   304 void CImSmtpFile::ChangeStateL()
       
   305     {
       
   306     //
       
   307     // State machine of the whole SMTP File mailer.
       
   308 	//	
       
   309 	TImMessageField emailField;
       
   310 
       
   311     switch (iState)
       
   312         {
       
   313     case EResettingSmtp:
       
   314 		SendAndQueueRead(KSmtpResetCommand);
       
   315         break;
       
   316 
       
   317     case EMailFromSmtp:
       
   318 		__ASSERT_DEBUG(iSmtpBuffer.Length(),gPanic(EImsmNoFromAddress));
       
   319 		if (emailField.ValidInternetEmailAddress(iHeader->From()))
       
   320 			{
       
   321     		iSmtpBuffer = KSmtpMailFromCommand;
       
   322 	    	iSmtpBuffer.Append(emailField.GetValidInternetEmailAddressFromString(iHeader->From()));
       
   323 		    iSmtpBuffer.Append(KSmtpCloseAngleBracket);
       
   324 			SendAndQueueRead(iSmtpBuffer);
       
   325 			}
       
   326 		else
       
   327 			{
       
   328 			// no Email address for return path, so refuse to send this message
       
   329 			RequestComplete(iStatus,0-KSmtpNoMailFromErr);
       
   330 			}
       
   331         break;
       
   332 
       
   333     case ERcptToSmtp: 
       
   334 		if(iRecipientType==ERcptBcc) 
       
   335 			{
       
   336 			iRecipientArray = &iHeader->BccRecipients();
       
   337 			iRecipient.Set((*iRecipientArray)[0]); // The should be only one Bcc recipient
       
   338 			}
       
   339 		else //'To' and 'Cc' recipients
       
   340 			{
       
   341 		    if(!iRecipientArray)
       
   342 				NextRecipientL();//	state was EMailFromSmtp, so initialise iRecipient
       
   343 			}
       
   344 				
       
   345 
       
   346         //  BUG_FIX SW1-659.. check with new build..
       
   347         //  Prepend the recipient address... into iSmtpBuffer and insert the command seq.
       
   348         iSmtpBuffer.Copy(emailField.GetValidInternetEmailAddressFromString(iRecipient));
       
   349         iSmtpBuffer.Insert(0, KSmtpRcptToCommand);
       
   350 		iSmtpBuffer.Append(KSmtpCloseAngleBracket);
       
   351 
       
   352         SendAndQueueRead(iSmtpBuffer);
       
   353         break;
       
   354 
       
   355     case EBeginData:
       
   356         SendAndQueueRead(KSmtpDataCommand);
       
   357         break;
       
   358 
       
   359     case ESendData:  // send RFC822 message now
       
   360         SendOneLineOfData();
       
   361         break;
       
   362 
       
   363     case EEndData:
       
   364 		// The bytes sent count is NOT accurate, so make sure this value
       
   365 		// doesn't exceed the number to send
       
   366 		iBytesSent = iBytesToSend;
       
   367 		// If smtp server did not respond within 10 mins after sending ".", the socket is timed out
       
   368 		iSocket.SendQueueReceiveWithTimeout(iStatus, KSmtpDataTerminationTimeout, KSmtpEndOfDataCommand);
       
   369 		break;
       
   370 
       
   371     default:    // Unknown state
       
   372         gPanic(EImsmBadFileState);
       
   373         break;
       
   374         }
       
   375 	SetActive();
       
   376     }
       
   377 
       
   378 
       
   379 void CImSmtpFile::SendOneLineOfData()
       
   380 	{
       
   381 	TInt paddedBytes=0;
       
   382 
       
   383 	if((iSuspendCheck++ % KMsvSuspendCheckGranuality) == 0)
       
   384 		{
       
   385 		// save the id, reset to top entry, check suspended state, fail if suspended
       
   386 		TMsvId savedId=iServerEntry.Entry().Id();
       
   387 		// if we can't get to the parent entry, just keep sending
       
   388 		TInt error=iServerEntry.SetEntry(iEntryId);
       
   389 		__ASSERT_DEBUG(error==KErrNone,gPanic(EImsmUnableToSetServerEntryToMessage));
       
   390 		if(error==KErrNone)
       
   391 			{
       
   392 			const TUint sendState=iServerEntry.Entry().SendingState();
       
   393 			// we would be in a bad way if we can't get back to the entry.
       
   394 			// but there isn't anything we can do about it
       
   395 			error=iServerEntry.SetEntry(savedId);
       
   396 			__ASSERT_ALWAYS(error==KErrNone,gPanic(EImsmUnableToSetServerEntryBack));
       
   397 
       
   398 			if(sendState==KMsvSendStateSuspended)
       
   399 				{
       
   400 				RequestComplete(iStatus,KErrCancel);
       
   401 				return;
       
   402 				}			
       
   403 			}
       
   404 		}
       
   405 
       
   406 	//->>Bug- SMTS was expecting a KImCvFinished (=-1) when IMCM finishes with the msg header and boby
       
   407 	// instead IMCM returns a KImCvAdvance (=1) to indicate the end of msg.
       
   408 	// this is fixed temporarily by using KImCvAdvance instead of KImCvFinished.
       
   409 	TRAPD(error,iMoreRfc822Data=(KImCvFinished!= iSendMessage->NextLineL(iSmtpBuffer,paddedBytes)));	// "iMoreRfc822Data" flag signals if this is last line of RFC822 body
       
   410 	if (!error)
       
   411 		{
       
   412 		__ASSERT_DEBUG(iSmtpBuffer.Length(),gPanic(EImsmBadSmtpBuffer));
       
   413 
       
   414 		// Checking for end of data = <CRLF>.
       
   415 
       
   416 		if (iSmtpBuffer[0]=='.')
       
   417 			{
       
   418 			paddedBytes++;
       
   419 			iSmtpBuffer.Insert(0,KStuffDot);
       
   420 			}
       
   421 
       
   422 		__ASSERT_DEBUG(iSmtpBuffer.Match(KSmtpMatchCrLf)==iSmtpBuffer.Length()-2,gPanic(EImsmNoCrLfTerminator));
       
   423 		iSocket.Send(iStatus,iSmtpBuffer);	// send line of text to TCP/IP socket
       
   424 
       
   425 		// update progress information
       
   426 		iBytesSent+=iSmtpBuffer.Length();	// NB counting terminating "\r\n" at end of each line
       
   427 		
       
   428 		// The bytes sent count is NOT accurate, so make sure the progress 
       
   429 		// does NOT exceed the amount to Send
       
   430 		if(iBytesSent > iBytesToSend)
       
   431 			iBytesSent = iBytesToSend;
       
   432 		}
       
   433 	else
       
   434 		{
       
   435 		RequestComplete(iStatus,error);
       
   436 		}
       
   437 	}
       
   438 
       
   439 
       
   440 TInt CImSmtpFile::SmtpFileError(TInt aSmtpErrorCode)
       
   441 	{
       
   442 	// Try to identify specific error condition from state and error code
       
   443 	// if unable to do so, return SMTP code.
       
   444 
       
   445 	switch (iState)
       
   446         {
       
   447 	case EMailFromSmtp:
       
   448 		if (aSmtpErrorCode==ESmtpSyntaxError ||aSmtpErrorCode==ESmtpUserNotLocal)
       
   449 			return(0-KSmtpBadMailFromAddress);
       
   450 
       
   451 		// If we receive one of the authentication error codes in response to our mail
       
   452 		// from command, then this indicates that the initial login was refused, but
       
   453 		// we decided to go on and try to do the send anyway.
       
   454 		// Return the KSmtpLoginRefused error code to indicate this.
       
   455 		// Note that the ESmtpTempAuthenticationFailure failure code should not be
       
   456 		// received in response to a mail from command, but some servers seem to use it.
       
   457 		if (aSmtpErrorCode == ESmtpTempAuthenticationFailure ||
       
   458 		    aSmtpErrorCode == ESmtpAuthenticationRequired)
       
   459 			{
       
   460 			return (0 - KSmtpLoginRefused);
       
   461 			}
       
   462 		break;
       
   463 
       
   464 	case ERcptToSmtp:
       
   465 		if (aSmtpErrorCode==ESmtpSyntaxError || aSmtpErrorCode==ESmtpMailboxNoAccess
       
   466 			||aSmtpErrorCode==ESmtpMailboxName)
       
   467 			return (0-KSmtpBadRcptToAddress);
       
   468 		break;
       
   469 
       
   470 	case EResettingSmtp:
       
   471 	case EBeginData:
       
   472 	case ESendData:
       
   473 	case EEndData:
       
   474 		break;
       
   475 
       
   476     default:     // Unknown state
       
   477         gPanic(EImsmBadFileState);
       
   478         break;
       
   479 		}
       
   480 
       
   481 	TInt error=IdentifySmtpError(aSmtpErrorCode);
       
   482 	return (error ? error : 0-KSmtpUnknownErr);	// return SMTP error code, if recognised
       
   483 	}	
       
   484 
       
   485 
       
   486 void CImSmtpFile::DoComplete(TInt& aStatus)
       
   487 	{
       
   488 	if (iCompleted)
       
   489 		{
       
   490 		// override completion code with my own (positive) error value
       
   491 		aStatus=iCompleted;
       
   492 		}
       
   493 	}
       
   494 	
       
   495 
       
   496 void CImSmtpFile::SelectBodyEncodingTypeL(TMsgOutboxBodyEncoding anSettingsValue, 
       
   497 										  TMsgOutboxBodyEncoding anHeaderValue)
       
   498 	{
       
   499 	if (anHeaderValue!=EMsgOutboxDefault)
       
   500 		iBodyType= anHeaderValue==EMsgOutboxNoAlgorithm ? ESendAsSimpleEmail:ESendAsMimeEmail;
       
   501 	else if (anSettingsValue!=EMsgOutboxDefault)
       
   502 		iBodyType= anSettingsValue==EMsgOutboxNoAlgorithm ? ESendAsSimpleEmail:ESendAsMimeEmail;
       
   503 	else
       
   504 		iBodyType=ESendAsMimeEmail; // Default setting.
       
   505 	}
       
   506 
       
   507 //   Creating library \EPOC32\RELEASE\WINS\UDEB\IMUT.LIB and object \EPOC32\RELEASE\WINS\UDEB\IMUT.exp
       
   508 
       
   509 
       
   510 void CImSmtpFile::SendAndQueueRead(const TDesC8& aDesc)
       
   511 	{
       
   512 	// Send SMTP command string to remote SMTP server -
       
   513 	// and then queues asynch read request for a response from the remote SMTP server.
       
   514 	iSocket.SendQueueReceive(iStatus,aDesc);
       
   515 	}
       
   516 
       
   517 
       
   518 TBool CImSmtpFile::GetCurrentTextLine()
       
   519 	{
       
   520 	TInt result=iSocket.GetCurrentTextLine(iSmtpBuffer);
       
   521 	__ASSERT_DEBUG(result==ECRLFTerminated,gPanic(EImsmBadSmtpBuffer));
       
   522 	return (result==ECRLFTerminated);
       
   523 	}
       
   524 
       
   525 
       
   526 CImSmtpFile::~CImSmtpFile()
       
   527 	{
       
   528 	// Destructor. Must NOT destroy iSocket as it is owned by iSmtpSession, not by iSmtpFile.
       
   529 	Cancel();
       
   530 
       
   531 	delete iHeader;
       
   532 	delete iSendMessage;
       
   533 	}