Example #1
0
        /// <summary>
        /// Reads SMTP server single or multiline response.
        /// </summary>
        /// <param name="op">Asynchronous operation.</param>
        /// <returns>Returns true if aynchronous operation is pending (The <see cref="ReadResponseAsyncOP.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 ReadResponseAsync(ReadResponseAsyncOP 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);
        }
Example #2
0
            /// <summary>
            /// Is called when SMTP server HELO command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void HeloReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    }
                    else{
                        m_pReplyLines = op.ReplyLines;

                        // HELO succeeded.
                        if(m_pReplyLines[0].ReplyCode == 250){
                            /* RFC 5321 4.1.1.1.
                                helo        = "HELO" SP Domain CRLF
                                helo-ok-rsp = "250" SP Domain [ SP helo-greet ] CRLF
                            */

                            m_pSmtpClient.m_RemoteHostName = m_pReplyLines[0].Text.Split(new char[]{' '},2)[0];
                            m_pSmtpClient.m_IsEsmtpSupported = true;
                            List<string> esmtpFeatures = new List<string>();
                            foreach(SMTP_t_ReplyLine line in m_pReplyLines){
                                esmtpFeatures.Add(line.Text);
                            }
                            m_pSmtpClient.m_pEsmtpFeatures = esmtpFeatures;
                        }
                        // HELO failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                            m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                }

                op.Dispose();

                SetState(AsyncOP_State.Completed);
            }
Example #3
0
        /// <summary>
        /// Is called when SMTP server greeting reading has completed.
        /// </summary>
        /// <param name="op">Asynchronous operation.</param>
        /// <param name="connectCallback">Callback to be called to complete connect operation.</param>
        private void ReadServerGreetingCompleted(ReadResponseAsyncOP op,CompleteConnectCallback connectCallback)
        {
            Exception error = null;

            try{
                // Greeting reading failed, we are done.
                if(op.Error != null){
                    error = op.Error;
                }
                // Greeting reading succeded.
                else{
                    /* RFC 5321 4.2.
                        Greeting = ( "220 " (Domain / address-literal) [ SP textstring ] CRLF ) /
                                   ( "220-" (Domain / address-literal) [ SP textstring ] CRLF
                                  *( "220-" [ textstring ] CRLF )
                                     "220" [ SP textstring ] CRLF )

                    */

                    // SMTP server accepted connection, get greeting text.
                    if(op.ReplyLines[0].ReplyCode == 220){
                        StringBuilder greetingText = new StringBuilder();
                        foreach(SMTP_t_ReplyLine line in op.ReplyLines){
                            greetingText.AppendLine(line.Text);
                        }

                        m_GreetingText = greetingText.ToString();
                        m_pEsmtpFeatures = new List<string>();
                        m_pRecipients = new List<string>();
                    }
                    // SMTP server rejected connection.
                    else{
                        error = new SMTP_ClientException(op.ReplyLines);
                    }
                }
            }
            catch(Exception x){
                error = x;
            }

            // Complete TCP_Client connect operation.
            connectCallback(error);
        }
Example #4
0
            /// <summary>
            /// Is called when SMTP server EHLO command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void EhloReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        SetState(AsyncOP_State.Completed);
                    }
                    else{
                        m_pReplyLines = op.ReplyLines;

                        // EHLO succeeded.
                        if(m_pReplyLines[0].ReplyCode == 250){
                            /* RFC 5321 4.1.1.1.
                                ehlo        = "EHLO" SP ( Domain / address-literal ) CRLF  
                     
                                ehlo-ok-rsp = ( "250" SP Domain [ SP ehlo-greet ] CRLF )
                                            / ( "250-" Domain [ SP ehlo-greet ] CRLF
                                             *( "250-" ehlo-line CRLF )
                                                "250" SP ehlo-line CRLF )
                            */

                            m_pSmtpClient.m_RemoteHostName = m_pReplyLines[0].Text.Split(new char[]{' '},2)[0];
                            m_pSmtpClient.m_IsEsmtpSupported = true;
                            List<string> esmtpFeatures = new List<string>();
                            foreach(SMTP_t_ReplyLine line in m_pReplyLines){
                                esmtpFeatures.Add(line.Text);
                            }
                            m_pSmtpClient.m_pEsmtpFeatures = esmtpFeatures;

                            SetState(AsyncOP_State.Completed);
                        }
                        // EHLO failed, try HELO(EHLO may be disabled or not supported)
                        else{
                            /* RFC 5321 4.1.1.1.
                                helo        = "HELO" SP Domain CRLF
                                helo-ok-rsp = "250" SP Domain [ SP helo-greet ] CRLF
                            */

                            // Log.
                            m_pSmtpClient.LogAddText("EHLO failed, will try HELO.");
                            
                            byte[] buffer = Encoding.UTF8.GetBytes("HELO " + m_HostName + "\r\n");

                            // Log
                            m_pSmtpClient.LogAddWrite(buffer.Length,"HELO " + m_HostName);

                            // Start command sending.
                            m_pSmtpClient.TcpStream.BeginWrite(buffer,0,buffer.Length,this.HeloCommandSendingCompleted,null);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    SetState(AsyncOP_State.Completed);
                }

                op.Dispose();
            }
Example #5
0
            /// <summary>
            /// Is called when NOOP command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void NoopReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    }
                    else{
                        // NOOP succeeded.
                        if(op.ReplyLines[0].ReplyCode == 250){
                            /* RFC 5321 4.1.1.9.
                                noop      = "NOOP" [ SP String ] CRLF
                                noop-resp = "250 OK" CRLF
                            */

                            // Do nothing.
                        }
                        // NOOP failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                            m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + x.Message,x);
                }

                op.Dispose();

                SetState(AsyncOP_State.Completed);
            }
Example #6
0
 /// <summary>
 /// This method is called when TCP client has sucessfully connected.
 /// </summary>
 /// <param name="callback">Callback to be called to complete connect operation.</param>
 protected override void OnConnected(CompleteConnectCallback callback)
 {            
     // Read SMTP server greeting response.
     ReadResponseAsyncOP readGreetingOP = new ReadResponseAsyncOP();
     readGreetingOP.CompletedAsync += delegate(object s,EventArgs<ReadResponseAsyncOP> e){
         ReadServerGreetingCompleted(readGreetingOP,callback);
     };
     if(!ReadResponseAsync(readGreetingOP)){
         ReadServerGreetingCompleted(readGreetingOP,callback);
     }
 }
Example #7
0
            /// <summary>
            /// Is called when SMTP server DATA command final response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void DataReadFinalResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        SetState(AsyncOP_State.Completed);
                    }
                    else{
                        // DATA command failed, only 2xx response is success.
                        if(op.ReplyLines[0].ReplyCode < 200 || op.ReplyLines[0].ReplyCode > 299){
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                        }

                        SetState(AsyncOP_State.Completed);
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    SetState(AsyncOP_State.Completed);
                }

                op.Dispose();
            }
Example #8
0
            /// <summary>
            /// Is called when SMTP server response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            private void AuthReadResponseCompleted(ReadResponseAsyncOP op)
            {
                try{
                    // Continue authenticating.
                    if(op.ReplyLines[0].ReplyCode == 334){
                        // 334 base64Data, we need to decode it.
                        byte[] serverResponse = Convert.FromBase64String(op.ReplyLines[0].Text);

                        byte[] clientResponse = m_pSASL.Continue(serverResponse);

                        // We need just send SASL returned auth-response as base64.
                        byte[] buffer = Encoding.UTF8.GetBytes(Convert.ToBase64String(clientResponse) + "\r\n");
                        
                        // Log
                        m_pSmtpClient.LogAddWrite(buffer.Length,Convert.ToBase64String(clientResponse));

                        // Start auth-data sending.
                        m_pSmtpClient.TcpStream.BeginWrite(buffer,0,buffer.Length,this.AuthCommandSendingCompleted,null);
                    }
                    // Authentication suceeded.
                    else if(op.ReplyLines[0].ReplyCode == 235){
                        m_pSmtpClient.m_pAuthdUserIdentity = new GenericIdentity(m_pSASL.UserName,m_pSASL.Name);

                        SetState(AsyncOP_State.Completed);
                    }
                    // Authentication rejected.
                    else{
                        m_pException = new SMTP_ClientException(op.ReplyLines);
                        SetState(AsyncOP_State.Completed);
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + x.Message,x);
                    SetState(AsyncOP_State.Completed);
                }
            }
Example #9
0
            /// <summary>
            /// Is called when SMTP server DATA command initial response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void DataReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        SetState(AsyncOP_State.Completed);
                    }
                    else{
                        // DATA command succeeded.
                        if(op.ReplyLines[0].ReplyCode == 354){ 
                            // Start sending message.
                            SmartStream.WritePeriodTerminatedAsyncOP sendMsgOP = new SmartStream.WritePeriodTerminatedAsyncOP(m_pStream);
                            sendMsgOP.CompletedAsync += delegate(object s,EventArgs<SmartStream.WritePeriodTerminatedAsyncOP> e){
                                DataMsgSendingCompleted(sendMsgOP);
                            };
                            if(!m_pSmtpClient.TcpStream.WritePeriodTerminatedAsync(sendMsgOP)){
                                DataMsgSendingCompleted(sendMsgOP);
                            }                            
                        }
                        // DATA command failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                            SetState(AsyncOP_State.Completed);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    SetState(AsyncOP_State.Completed);
                }

                op.Dispose();
            }
Example #10
0
            /// <summary>
            /// Is called when DATA command message sending has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void DataMsgSendingCompleted(SmartStream.WritePeriodTerminatedAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        SetState(AsyncOP_State.Completed);
                    }
                    else{
                        // Log
                        m_pSmtpClient.LogAddWrite(op.BytesWritten,"Sent message " + op.BytesWritten + " bytes.");
                                                                       
                        // Read DATA command final response.
                        ReadResponseAsyncOP readResponseOP = new ReadResponseAsyncOP();
                        readResponseOP.CompletedAsync += delegate(object s,EventArgs<ReadResponseAsyncOP> e){
                            DataReadFinalResponseCompleted(readResponseOP);
                        };
                        if(!m_pSmtpClient.ReadResponseAsync(readResponseOP)){
                            DataReadFinalResponseCompleted(readResponseOP);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    SetState(AsyncOP_State.Completed);
                }

                op.Dispose();
            }
Example #11
0
            /// <summary>
            /// Is called when SMTP server BDAT command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void BdatReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        SetState(AsyncOP_State.Completed);
                    }
                    else{
                        // BDAT succeeded.
                        if(op.ReplyLines[0].ReplyCode == 250){ 
                            // We have sent whole message, we are done.
                            if(m_BdatBytesInBuffer == 0){
                                SetState(AsyncOP_State.Completed);

                                return;
                            }
                            // Send next BDAT data-chunk.
                            else{
                                // Start reading next message data-block.
                                m_pStream.BeginRead(m_pBdatBuffer,0,m_pBdatBuffer.Length,this.BdatChunkReadingCompleted,null);
                            }
                        }
                        // BDAT failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);

                            SetState(AsyncOP_State.Completed);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    SetState(AsyncOP_State.Completed);
                }

                op.Dispose();
            }
Example #12
0
            /// <summary>
            /// Is called when SMTP server RCPT command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void RcptReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    }
                    else{
                        // RCPT succeeded.
                        if(op.ReplyLines[0].ReplyCode == 250){
                            if(!m_pSmtpClient.m_pRecipients.Contains(m_To)){
                                m_pSmtpClient.m_pRecipients.Add(m_To);
                            }
                        }
                        // RCPT failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                            m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    if(m_pSmtpClient != null){
                        m_pSmtpClient.LogAddException("Exception: " + x.Message,x);
                    }
                }

                op.Dispose();

                SetState(AsyncOP_State.Completed);
            }
Example #13
0
            /// <summary>
            /// Is called when SMTP server MAIL command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void MailReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    }
                    else{
                        // MAIL succeeded.
                        if(op.ReplyLines[0].ReplyCode == 250){
                            m_pSmtpClient.m_MailFrom = m_MailFrom;
                        }
                        // MAIL failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                            m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                }

                op.Dispose();

                SetState(AsyncOP_State.Completed);
            }
Example #14
0
            /// <summary>
            /// Is called when STARTTLS command sending has finished.
            /// </summary>
            /// <param name="ar">Asynchronous result.</param>
            private void StartTlsCommandSendingCompleted(IAsyncResult ar)
            {
                try{
                    m_pSmtpClient.TcpStream.EndWrite(ar);

                    // Read SMTP server response.
                    ReadResponseAsyncOP readResponseOP = new ReadResponseAsyncOP();
                    readResponseOP.CompletedAsync += delegate(object s,EventArgs<ReadResponseAsyncOP> e){
                        StartTlsReadResponseCompleted(readResponseOP);
                    };
                    if(!m_pSmtpClient.ReadResponseAsync(readResponseOP)){
                        StartTlsReadResponseCompleted(readResponseOP);
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + x.Message,x);
                    SetState(AsyncOP_State.Completed);
                }
            }
Example #15
0
            /// <summary>
            /// Is called when SMTP server RSET command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void RsetReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    }
                    else{
                        // RSET succeeded.
                        if(op.ReplyLines[0].ReplyCode == 250){
                            /* RFC 5321 4.1.1.9.
                                rset      = "RSET" CRLF
                                rset-resp = "250 OK" CRLF
                            */

                            // Do nothing.
                        }
                        // RSET failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                            m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    m_pSmtpClient.LogAddException("Exception: " + x.Message,x);
                }

                SetState(AsyncOP_State.Completed);
            }
Example #16
0
            /// <summary>
            /// Is called when STARTTLS command response reading has completed.
            /// </summary>
            /// <param name="op">Asynchronous operation.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
            private void StartTlsReadResponseCompleted(ReadResponseAsyncOP op)
            {
                if(op == null){
                    throw new ArgumentNullException("op");
                }

                try{
                    if(op.Error != null){
                        m_pException = op.Error;
                    }
                    else{
                        // STARTTLS accepted.
                        if(op.ReplyLines[0].ReplyCode == 220){
                            /* RFC 3207 4.
                                The format for the STARTTLS command is:

                                STARTTLS

                                with no parameters.

                                After the client gives the STARTTLS command, the server responds with
                                one of the following reply codes:

                                220 Ready to start TLS
                                501 Syntax error (no parameters allowed)
                                454 TLS not available due to temporary reason
                            */

                            // Log
                            m_pSmtpClient.LogAddText("Starting TLS handshake.");

                            SwitchToSecureAsyncOP switchSecureOP = new SwitchToSecureAsyncOP(m_pCertCallback);
                            switchSecureOP.CompletedAsync += delegate(object s,EventArgs<SwitchToSecureAsyncOP> e){
                                SwitchToSecureCompleted(switchSecureOP);
                            };
                            if(!m_pSmtpClient.SwitchToSecureAsync(switchSecureOP)){
                                SwitchToSecureCompleted(switchSecureOP);
                            }                       
                        }
                        // STARTTLS failed.
                        else{
                            m_pException = new SMTP_ClientException(op.ReplyLines);
                        }
                    }
                }
                catch(Exception x){
                    m_pException = x;                    
                }

                op.Dispose();

                if(m_pException != null){
                    m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    SetState(AsyncOP_State.Completed);
                }
            }
Example #17
0
            /// <summary>
            /// Is called when HELO command sending has finished.
            /// </summary>
            /// <param name="ar">Asynchronous result.</param>
            private void HeloCommandSendingCompleted(IAsyncResult ar)
            {
                try{
                    m_pSmtpClient.TcpStream.EndWrite(ar);

                    // Read HELO command response.
                    ReadResponseAsyncOP readResponseOP = new ReadResponseAsyncOP();
                    readResponseOP.CompletedAsync += delegate(object s,EventArgs<ReadResponseAsyncOP> e){
                        HeloReadResponseCompleted(readResponseOP);
                    };
                    if(!m_pSmtpClient.ReadResponseAsync(readResponseOP)){
                        HeloReadResponseCompleted(readResponseOP);
                    }
                }
                catch(Exception x){
                    m_pException = x;
                    if(m_pSmtpClient != null){
                        m_pSmtpClient.LogAddException("Exception: " + m_pException.Message,m_pException);
                    }
                    SetState(AsyncOP_State.Completed);
                }
            }