/// <summary> /// Starts operation processing. /// </summary> /// <param name="owner">Owner SMTP session.</param> /// <param name="cmdText">SMTP client command text.</param> /// <returns>Returns true if asynchronous operation in progress or false if operation completed synchronously.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null reference.</exception> public bool Start(SMTP_Session owner,string cmdText) { if(owner == null){ throw new ArgumentNullException("owner"); } m_pSession = owner; m_StartTime = DateTime.Now; SetState(AsyncOP_State.Active); try{ /* RFC 5321 4.1.1.4. The receiver normally sends a 354 response to DATA, and then treats the lines (strings ending in <CRLF> sequences, as described in Section 2.3.7) following the command as mail data from the sender. This command causes the mail data to be appended to the mail data buffer. The mail data may contain any of the 128 ASCII character codes, although experience has indicated that use of control characters other than SP, HT, CR, and LF may cause problems and SHOULD be avoided when possible. The custom of accepting lines ending only in <LF>, as a concession to non-conforming behavior on the part of some UNIX systems, has proven to cause more interoperability problems than it solves, and SMTP server systems MUST NOT do this, even in the name of improved robustness. In particular, the sequence "<LF>.<LF>" (bare line feeds, without carriage returns) MUST NOT be treated as equivalent to <CRLF>.<CRLF> as the end of mail data indication. Receipt of the end of mail data indication requires the server to process the stored mail transaction information. This processing consumes the information in the reverse-path buffer, the forward-path buffer, and the mail data buffer, and on the completion of this command these buffers are cleared. If the processing is successful, the receiver MUST send an OK reply. If the processing fails, the receiver MUST send a failure reply. The SMTP model does not allow for partial failures at this point: either the message is accepted by the server for delivery and a positive response is returned or it is not accepted and a failure reply is returned. In sending a positive "250 OK" completion reply to the end of data indication, the receiver takes full responsibility for the message (see Section 6.1). Errors that are diagnosed subsequently MUST be reported in a mail message, as discussed in Section 4.4. When the SMTP server accepts a message either for relaying or for final delivery, it inserts a trace record (also referred to interchangeably as a "time stamp line" or "Received" line) at the top of the mail data. This trace record indicates the identity of the host that sent the message, the identity of the host that received the message (and is inserting this time stamp), and the date and time the message was received. Relayed messages will have multiple time stamp lines. Details for formation of these lines, including their syntax, is specified in Section 4.4. */ // RFC 5321 3.1. if(m_pSession.m_SessionRejected){ SendFinalResponse(new SMTP_t_ReplyLine(503,"Bad sequence of commands: Session rejected.",true)); } // RFC 5321 4.1.4. else if(string.IsNullOrEmpty(m_pSession.m_EhloHost)){ SendFinalResponse(new SMTP_t_ReplyLine(503,"Bad sequence of commands: Send EHLO/HELO first.",true)); } // RFC 5321 4.1.4. else if(m_pSession.m_pFrom == null){ SendFinalResponse(new SMTP_t_ReplyLine(503,"Bad sequence of commands: Send 'MAIL FROM:' first.",true)); } // RFC 5321 4.1.4. else if(m_pSession.m_pTo.Count == 0){ SendFinalResponse(new SMTP_t_ReplyLine(503,"Bad sequence of commands: Send 'RCPT TO:' first.",true)); } else if(!string.IsNullOrEmpty(cmdText)){ SendFinalResponse(new SMTP_t_ReplyLine(500,"Command line syntax error.",true)); } else{ // Get message store stream. m_pSession.m_pMessageStream = m_pSession.OnGetMessageStream(); if(m_pSession.m_pMessageStream == null){ m_pSession.m_pMessageStream = new MemoryStreamEx(32000); } // Send "354 Start mail input; end with <CRLF>.<CRLF>". SMTP_Session.SendResponseAsyncOP sendResponseOP = new SendResponseAsyncOP(new SMTP_t_ReplyLine(354,"Start mail input; end with <CRLF>.<CRLF>",true)); sendResponseOP.CompletedAsync += delegate(object sender,EventArgs<SendResponseAsyncOP> e){ Send354ResponseCompleted(sendResponseOP); }; if(!m_pSession.SendResponseAsync(sendResponseOP)){ Send354ResponseCompleted(sendResponseOP); } } } catch(Exception x){ m_pException = x; m_pSession.LogAddException("Exception: " + m_pException.Message,m_pException); SetState(AsyncOP_State.Completed); } // Set flag rise CompletedAsync event flag. The event is raised when async op completes. // If already completed sync, that flag has no effect. lock(m_pLock){ m_RiseCompleted = true; return m_State == AsyncOP_State.Active; } }
/// <summary> /// Starts operation processing. /// </summary> /// <param name="owner">Owner SMTP session.</param> /// <returns>Returns true if asynchronous operation in progress or false if operation completed synchronously.</returns> /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null reference.</exception> public bool Start(SMTP_Session owner) { if(owner == null){ throw new ArgumentNullException("owner"); } m_pSession = owner; SetState(AsyncOP_State.Active); try{ // Build SMTP response. StringBuilder response = new StringBuilder(); foreach(SMTP_t_ReplyLine replyLine in m_pReplyLines){ response.Append(replyLine.ToString()); } byte[] buffer = Encoding.UTF8.GetBytes(response.ToString()); // Log m_pSession.LogAddWrite(buffer.Length,response.ToString()); // Start response sending. m_pSession.TcpStream.BeginWrite(buffer,0,buffer.Length,this.ResponseSendingCompleted,null); } catch(Exception x){ m_pException = x; m_pSession.LogAddException("Exception: " + m_pException.Message,m_pException); SetState(AsyncOP_State.Completed); } // Set flag rise CompletedAsync event flag. The event is raised when async op completes. // If already completed sync, that flag has no effect. lock(m_pLock){ m_RiseCompleted = true; return m_State == AsyncOP_State.Active; } }