Ejemplo n.º 1
0
             /// <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;
                }
            }
Ejemplo n.º 2
0
 /// <summary>
 /// Sends specified final response to client.
 /// </summary>
 /// <param name="reply">SMTP reply.</param>
 private void SendFinalResponse(SMTP_t_ReplyLine reply)
 {
     try{
         if(reply == null){
             throw new ArgumentNullException("reply");
         }
        
         SMTP_Session.SendResponseAsyncOP sendResponseOP = new SendResponseAsyncOP(reply);
         sendResponseOP.CompletedAsync += delegate(object sender,EventArgs<SendResponseAsyncOP> e){
             SendFinalResponseCompleted(sendResponseOP);
         };
         if(!m_pSession.SendResponseAsync(sendResponseOP)){
             SendFinalResponseCompleted(sendResponseOP);
         }                    
     }
     catch(Exception x){
         m_pException = x;
         m_pSession.LogAddException("Exception: " + m_pException.Message,m_pException);
         SetState(AsyncOP_State.Completed);
     }
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Sends SMTP server response.
        /// </summary>
        /// <param name="op">Asynchronous operation.</param>
        /// <returns>Returns true if aynchronous operation is pending (The <see cref="SendResponseAsyncOP.CompletedAsync"/> event is raised upon completion of the operation).
        /// Returns false if operation completed synchronously.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
        private bool SendResponseAsync(SendResponseAsyncOP op)
        {
            if(this.IsDisposed){
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if(op == null){
                throw new ArgumentNullException("op");
            }
            if(op.State != AsyncOP_State.WaitingForStart){
                throw new ArgumentException("Invalid argument 'op' state, 'op' must be in 'AsyncOP_State.WaitingForStart' state.","op");
            }

            return op.Start(this);
        }