/// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="userName">User name.</param>
 /// <param name="password">Password.</param>
 /// <param name="callback">Callback what must be called when aynchrounous execution completes.</param>
 public Auth_state_data(string userName, string password, CommadCompleted callback)
 {
     m_UserName = userName;
     m_Password = password;
     m_pCallback = callback;
 }
 /// <summary>
 /// Start TLS(SSL) negotiation asynchronously.
 /// </summary>
 /// <param name="callback">The method to be called when the asynchronous StartTLS operation is completed.</param>
 public void BeginStartTLS(CommadCompleted callback)
 {
     ThreadPool.QueueUserWorkItem(BeginStartTLS_workerThread, callback);
 }
        /// <summary>
        /// Begins EHLO command.
        /// </summary>
        /// <param name="hostName">Host name which is reported to SMTP server.</param>
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginEhlo(string hostName, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* Rfc 2821 4.1.1.1 EHLO
			 * Syntax: "EHLO" SP Domain CRLF
			*/

            if (hostName.Length == 0)
            {
                hostName = Dns.GetHostName();
            }

            // Start sending EHLO command to server
            m_pSocket.BeginWriteLine("EHLO " + hostName, new object[] {hostName, callback}, OnEhloSendFinished);
        }
 /// <summary>
 /// Starts connection to specified host.
 /// </summary>
 /// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param>
 /// <param name="host">Host name or IP address.</param>
 /// <param name="port">Port where to connect.</param>
 /// <param name="callback">Callback to be called if connect ends.</param>
 public void BeginConnect(IPEndPoint localEndpoint, string host, int port, CommadCompleted callback)
 {
     BeginConnect(localEndpoint, host, port, false, callback);
 }
 /// <summary>
 /// Starts connection to specified host.
 /// </summary>
 /// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param>
 /// <param name="host">Host name or IP address.</param>
 /// <param name="port">Port where to connect.</param>
 /// <param name="ssl">Specifies if to connected via SSL.</param>
 /// <param name="callback">Callback to be called if connect ends.</param>
 public void BeginConnect(IPEndPoint localEndpoint,
                          string host,
                          int port,
                          bool ssl,
                          CommadCompleted callback)
 {
     ThreadPool.QueueUserWorkItem(BeginConnect_workerThread,
                                  new object[] {localEndpoint, host, port, ssl, callback});
 }
 /// <summary>
 /// Starts connection to specified host.
 /// </summary>
 /// <param name="host">Host name or IP address.</param>
 /// <param name="port">Port where to connect.</param>
 /// <param name="callback">Callback to be called if connect ends.</param>
 public void BeginConnect(string host, int port, CommadCompleted callback)
 {
     BeginConnect(null, host, port, false, callback);
 }
 /// <summary>
 /// Starts connection to specified host.
 /// </summary>
 /// <param name="host">Host name or IP address.</param>
 /// <param name="port">Port where to connect.</param>
 /// <param name="ssl">Specifies if to connected via SSL.</param>
 /// <param name="callback">Callback to be called if connect ends.</param>
 public void BeginConnect(string host, int port, bool ssl, CommadCompleted callback)
 {
     BeginConnect(null, host, port, ssl, callback);
 }
        /// <summary>
        /// Starts sending message.
        /// </summary>
        /// <param name="message">Message what will be sent to server. NOTE: Message sending starts from message stream current posision.</param>
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginSendMessage(Stream message, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.4 DATA
			 * Notes:
			 *		Message must be period handled for DATA command. This meas if message line starts with .,
			 *		additional .(period) must be added.
			 *		Message send is ended with <CRLF>.<CRLF>.
			 *	Examples:
			 *		C: DATA<CRLF>
			 *		S: 354 Start sending message, end with <crlf>.<crlf><CRLF>
			 *		C: send_message
			 *		C: <CRLF>.<CRLF>
			*/

            /* RFC 3030 BDAT
			 *	Syntax:BDAT<SP>message_size_in_bytes<SP>LAST<CRLF>
			 *	
			 *	Exapmle:
			 *		C: BDAT 1000 LAST<CRLF>
			 *		C: send_1000_byte_message
			 *		S: 250 OK<CRLF>
			 * 
			*/

            if (m_Supports_Bdat)
            {
                m_pSocket.BeginWriteLine("BDAT " + (message.Length - message.Position) + " LAST",
                                         new object[] {message, callback},
                                         OnBdatSendFinished);
            }
            else
            {
                m_pSocket.BeginWriteLine("DATA", new object[] {message, callback}, OnDataSendFinished);
            }
        }
        /// <summary>
        /// Begin adding recipient.
        /// </summary>
        /// <param name="recipientEmail">Recipient email address.</param>
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginAddRecipient(string recipientEmail, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.2 RCPT
			 *  Examples:
			 *		RCPT TO:<*****@*****.**>
			*/

            m_pSocket.BeginWriteLine("RCPT TO:<" + recipientEmail + ">", callback, OnRcptSendFinished);
        }
        /// <summary>
        /// Begin setting sender.
        /// </summary>
        /// <param name="senderEmail">Sender email address what is reported to smtp server.</param>
        /// <param name="messageSize">Message size in bytes or -1 if message size isn't known.</param>
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginSetSender(string senderEmail, long messageSize, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.2 MAIL
			 *  Examples:
			 *		MAIL FROM:<*****@*****.**>
			 * 
			 * RFC 1870 adds optional SIZE keyword support.
			 * SIZE keyword may only be used if it's reported in EHLO command response.
			 *	Examples:
			 *		MAIL FROM:<*****@*****.**> SIZE=1000
			*/

            if (m_Supports_Size && messageSize > -1)
            {
                m_pSocket.BeginWriteLine("MAIL FROM:<" + senderEmail + "> SIZE=" + messageSize,
                                         callback,
                                         OnMailSendFinished);
            }
            else
            {
                m_pSocket.BeginWriteLine("MAIL FROM:<" + senderEmail + ">", callback, OnMailSendFinished);
            }
        }
        /// <summary>
        /// Begins authenticate.
        /// </summary>
        /// <param name="userName">Uesr name.</param>
        /// <param name="password">Password.</param> 
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginAuthenticate(string userName, string password, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first !");
            }
            if (!(m_Supports_CramMd5 || m_Supports_Login))
            {
                throw new Exception("Authentication isn't supported.");
            }

            /* LOGIN
			 * Example:
			 *	C: AUTH<SP>LOGIN<CRLF>
			 *	S: 334<SP>base64(USERNAME)<CRLF>   // USERNAME is string constant
			 *	C: base64(username)<CRLF>
			 *  S: 334<SP>base64(PASSWORD)<CRLF>   // PASSWORD is string constant
			 *  C: base64(password)<CRLF>
			 *	S: 235 Ok<CRLF>
			*/

            /* Cram-M5
			   Example:
					C: AUTH<SP>CRAM-MD5<CRLF>
					S: 334<SP>base64(md5_calculation_hash)<CRLF>
					C: base64(username<SP>password_hash)<CRLF>
					S: 235 Ok<CRLF>
			*/

            if (m_Supports_CramMd5)
            {
                m_pSocket.BeginWriteLine("AUTH CRAM-MD5",
                                         new Auth_state_data(userName, password, callback),
                                         OnAuthCramMd5SendFinished);
            }
            else if (m_Supports_Login)
            {
                m_pSocket.BeginWriteLine("AUTH LOGIN",
                                         new Auth_state_data(userName, password, callback),
                                         OnAuthLoginSendFinished);
            }
        }
		/// <summary>
		/// Starts connection to specified host.
		/// </summary>
		/// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param>
		/// <param name="host">Host name or IP address.</param>
		/// <param name="port">Port where to connect.</param>
		/// <param name="callback">Callback to be called if connect ends.</param>
		public void BeginConnect(IPEndPoint localEndpoint,string host,int port,CommadCompleted callback)
		{
			ThreadPool.QueueUserWorkItem(new WaitCallback(this.BeginConnect_workerThread),new object[]{localEndpoint,host,port,callback});
		}