Exemple #1
0
        /// <summary>
        /// Is called if command is recieved.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="exception"></param>
        /// <param name="count"></param>
        /// <param name="tag"></param>
        private void EndRecieveCmd(SocketCallBackResult result, long count, Exception exception, object tag)
        {
            try
            {
                switch (result)
                {
                case SocketCallBackResult.Ok:
                    MemoryStream strm = (MemoryStream)tag;

                    string cmdLine = System.Text.Encoding.Default.GetString(strm.ToArray());

                    //	if(m_pServer.LogCommands)
                    //  {
                    //		m_pLogWriter.AddEntry(cmdLine + "<CRLF>",this.SessionID,this.RemoteEndPoint.Address.ToString(),"C");
                    //	}

                    // Exceute command
                    if (SwitchCommand(cmdLine))
                    {
                        // Session end, close session
                        EndSession();
                    }
                    break;

                case SocketCallBackResult.LengthExceeded:
                    this.Socket.WriteLine("500 Line too long.");

                    BeginRecieveCmd();
                    break;

                case SocketCallBackResult.SocketClosed:
                    EndSession();
                    break;

                case SocketCallBackResult.Exception:
                    OnError(exception);
                    break;
                }
            }
            catch (Exception x)
            {
                OnError(x);
            }
        }
Exemple #2
0
        /// <summary>
        /// Is called if command is recieved.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="exception"></param>
        /// <param name="count"></param>
        /// <param name="tag"></param>
        private void EndRecieveCmd(SocketCallBackResult result, long count, Exception exception, object tag)
        {
            try
            {
                switch (result)
                {
                case SocketCallBackResult.Ok:
                    MemoryStream strm = (MemoryStream)tag;

                    string cmdLine = System.Text.Encoding.Default.GetString(strm.ToArray());

                    // Exceute command
                    if (SwitchCommand(cmdLine))
                    {
                        // Session end, close session
                        EndSession();
                    }
                    break;

                case SocketCallBackResult.LengthExceeded:
                    this.Socket.WriteLine("-ERR Line too long.");

                    BeginRecieveCmd();
                    break;

                case SocketCallBackResult.SocketClosed:
                    EndSession();
                    break;

                case SocketCallBackResult.Exception:
                    OnError(exception);
                    break;
                }
            }
            catch (Exception x)
            {
                OnError(x);
            }
        }
        /// <summary>
        /// Is called if command is recieved.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void EndRecieveCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        MemoryStream strm = (MemoryStream)tag;

                        string cmdLine = System.Text.Encoding.Default.GetString(strm.ToArray());

                        // Exceute command
                        if(SwitchCommand(cmdLine)){
                            // Session end, close session
                            EndSession();
                        }
                        break;

                    case SocketCallBackResult.LengthExceeded:
                        this.Socket.WriteLine("500 Line too long.");

                        BeginRecieveCmd();
                        break;

                    case SocketCallBackResult.SocketClosed:
                        EndSession();
                        break;

                    case SocketCallBackResult.Exception:
                        OnError(exception);
                        break;
                }
            }
            catch(ReadException x){
                if(x.ReadReplyCode == ReadReplyCode.LengthExceeded){
                    this.Socket.WriteLine("500 Line too long.");

                    BeginRecieveCmd();
                }
                else if(x.ReadReplyCode == ReadReplyCode.SocketClosed){
                    EndSession();
                }
                else if(x.ReadReplyCode == ReadReplyCode.UnKnownError){
                    OnError(x);
                }
            }
            catch(Exception x){
                 OnError(x);
            }
        }
        private void EndBDatCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        m_BDAT_ReadedCount += count;

                        // BDAT command completed, got all data junks
                        if((bool)tag){
                            // Maximum allowed message size exceeded.
                            if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize){
                                m_pServer.OnMessageStoringCompleted(this,"Requested mail action aborted: exceeded storage allocation",m_pMsgStream);

                                this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
                            }
                            else{
                                // Notify Message stream owner that message storing completed ok.
                                MessageStoringCompleted_eArgs oArg = m_pServer.OnMessageStoringCompleted(this,null,m_pMsgStream);
                                if(oArg.ServerReply.ErrorReply){
                                    this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("500","Error storing message"),new SocketCallBack(this.EndSend));
                                }
                                else{
                                    this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("250","Message(" + m_BDAT_ReadedCount + " bytes) stored ok."),new SocketCallBack(this.EndSend));
                                }
                            }

                            /* RFC 2821 4.1.1.4 DATA
                            NOTE:
                                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.
                            */
                            ResetState();
                        }
                        // Got BDAT data block, BDAT must continue, that wasn't last data block.
                        else{
                            // Maximum allowed message size exceeded.
                            if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize){
                                this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
                            }
                            else{
                                this.Socket.BeginWriteLine("250 Data block of " + count + " bytes recieved OK.",new SocketCallBack(this.EndSend));
                            }
                        }
                        break;

                    case SocketCallBackResult.SocketClosed:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"SocketClosed",m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

                        EndSession();
                        return;

                    case SocketCallBackResult.Exception:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"Exception: " + exception.Message,m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

                        OnError(exception);
                        return;
                }
            }
            catch(Exception x){
                OnError(x);
            }
        }
        /// <summary>
        /// Is called when smtp client has finished reading MESSAGE send smtp server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnDataMessageSendReadServerResponseFinished(SocketCallBackResult result,
                                                                 long count,
                                                                 Exception exception,
                                                                 object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]);

            try
            {
                // TODO: some servers close connection after DATA command, hanndle Socket closed.

                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray());

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // DATA: completed susscessfully, call callback method.
                        callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }
        /// <summary>
        /// Is called when smtp client has finished reading DATA command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnDataReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[2])).ToArray());

                    // Response line must start with 334 or otherwise it's error response
                    if (!responseLine.StartsWith("354"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        Stream message = (Stream) (((object[]) tag)[0]);

                        // Start sending message to smtp server
                        m_pSocket.BeginWritePeriodTerminated(message, callback, OnDataMessageSendFinished);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }
        /// <summary>
        /// Is called when smtp client has finished BDAT command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnBdatSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // BDAT command successfully sent to SMTP server, start sending DATA.
                    m_pSocket.BeginWrite((Stream) (((object[]) tag)[0]), callback, OnBdatDataSendFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }
        /// <summary>
        /// Is called when smtp client has finished reading AUTH LOGIN password send server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnAuthLoginPwdReadServerResponseFinished(SocketCallBackResult result,
                                                              long count,
                                                              Exception exception,
                                                              object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray());

                    // Response line must start with 235 or otherwise it's error response
                    if (!responseLine.StartsWith("235"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        m_Authenticated = true;

                        if (m_Authenticated && m_pSocket.Logger != null)
                        {
                            m_pSocket.Logger.UserName = stateData.UserName;
                        }

                        // AUTH LOGIN completed susscessfully, call callback method.
                        stateData.Callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }
        /// <summary>
        /// Is called when smtp client has finished reading AUTH LOGIN user send server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnAuthLoginUserReadServerResponseFinished(SocketCallBackResult result,
                                                               long count,
                                                               Exception exception,
                                                               object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray());

                    // Response line must start with 334 or otherwise it's error response
                    if (!responseLine.StartsWith("334"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // Start sending password to server
                        m_pSocket.BeginWriteLine(
                            Convert.ToBase64String(Encoding.ASCII.GetBytes(stateData.Password)),
                            stateData,
                            OnAuthLoginPasswordSendFinished);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }
Exemple #10
0
        /// <summary>
        /// Is called if command is recieved.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="exception"></param>
        /// <param name="count"></param>
        /// <param name="tag"></param>
        private void EndRecieveCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        MemoryStream strm = (MemoryStream)tag;

                        string cmdLine = System.Text.Encoding.Default.GetString(strm.ToArray());

                        if(m_pServer.LogCommands){
                            m_pLogWriter.AddEntry(cmdLine + "<CRLF>",this.SessionID,this.RemoteEndPoint.Address.ToString(),"C");
                        }

                        // Exceute command
                        if(SwitchCommand(cmdLine)){
                            // Session end, close session
                            EndSession();
                        }
                        break;

                    case SocketCallBackResult.LengthExceeded:
                        SendData("-ERR Line too long.\r\n");

                        BeginRecieveCmd();
                        break;

                    case SocketCallBackResult.SocketClosed:
                        EndSession();
                        break;

                    case SocketCallBackResult.Exception:
                        OnError(exception);
                        break;
                }
            }
            catch(Exception x){
                 OnError(x);
            }
        }
Exemple #11
0
        /// <summary>
        /// Is called when DATA command is finnished.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void EndAppendCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                if(m_pServer.LogCommands){
                    m_pLogWriter.AddEntry("big binary " + count.ToString() + " bytes",this.SessionID,this.RemoteEndPoint.Address.ToString(),"S");
                }

                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        Hashtable         param   = (Hashtable)tag;
                        string            cmdTag  = (string)param["cmdTag"];
                        string            mailbox = (string)param["mailbox"];
                        IMAP_MessageFlags mFlags  = (IMAP_MessageFlags)param["mFlags"];
                        DateTime          date    = (DateTime)param["date"];
                        MemoryStream      strm    = (MemoryStream)param["strm"];

                        IMAP_Message msg = new IMAP_Message(null,"",0,mFlags,0,date);
                        string errotText = m_pServer.OnStoreMessage(this,mailbox,msg,strm.ToArray());
                        if(errotText == null){
                            SendData(cmdTag + " OK APPEND completed, recieved " + strm.Length + " bytes\r\n");
                        }
                        else{
                            SendData(cmdTag + " NO " + errotText + "\r\n");
                        }
                        break;

                    case SocketCallBackResult.LengthExceeded:
                    //	SendData("552 Requested mail action aborted: exceeded storage allocation\r\n");

                    //	BeginRecieveCmd();
                        break;

                    case SocketCallBackResult.SocketClosed:
                        EndSession();
                        return;

                    case SocketCallBackResult.Exception:
                        OnError(exception);
                        return;
                }

                // Command completed ok, get next command
                BeginRecieveCmd();
            }
            catch(Exception x){
                OnError(x);
            }
        }
        private void EndBDatCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        m_BDAT_ReadedCount += count;

                        // BDAT command completed, got all data junks
                        if((bool)tag)
                        {
                            // Maximum allowed message size exceeded.
                            if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize)
                            {
                                m_pServer.OnMessageStoringCompleted(this,"Requested mail action aborted: exceeded storage allocation",m_pMsgStream);

                                this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
                            }
                            else
                            {
                                // Notify Message stream owner that message storing completed ok

                                if (m_CERT_mode == true && m_CERT_valid == true) // miceli
                                {
                                    string masterkeyprivatefilename = "master.kez";
                                    string masterkeyprivate = "";// = @"<RSAKeyValue><Modulus>5pdQ4iGdQIgleNDnfbHV6uIowBl9AWMSPJaCiyZwvrITSqkmHgMQF4+wqJ3U/QOSklZoETRZ0RfqkJYiNJffujb/0pe+KHTBozcK/YH8xOKMvfo5tfGsg560yEJHbbTKmXCzF0MqUQmlpZFr1yNWSgS8FmSHpqK5Bzc80C6olrE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
                                    int bitStrength = 1024;
                                    if (File.Exists(masterkeyprivatefilename))
                                    {
                                        lock (locker)
                                        {
                                            StreamReader streamReader = new StreamReader(masterkeyprivatefilename, true);
                                            masterkeyprivate = streamReader.ReadToEnd();
                                            streamReader.Close();
                                        }
                                        string bitStrengthString = masterkeyprivate.Substring(0, masterkeyprivate.IndexOf("</BitStrength>") + 14);
                                        masterkeyprivate = masterkeyprivate.Replace(bitStrengthString, "");
                                        bitStrength = Convert.ToInt32(bitStrengthString.Replace("<BitStrength>", "").Replace("</BitStrength>", ""));
                                    }

                                    string lineRead;
                                    string[] lines;
                                    string headers;

                                    SaveStream(m_pMsgStream, @"c:\predecrypt.txt");

                                    RSACryptoPad.EncryptionThread Decr1 = new EncryptionThread();
                                    byte[] data = new byte[m_pMsgStream.Length];
                                    m_pMsgStream.Position = 0;
                                    m_pMsgStream.Read(data, 0, (int)m_pMsgStream.Length);
                                    lineRead = Encoding.ASCII.GetString(data);
                                    lines = lineRead.Split('\n');
                                    headers = lines[0] + '\n' + lines[1];
                                    string message = Decr1.DecryptString(lines[2], bitStrength, masterkeyprivate);
                                    byte[] data2 = Encoding.ASCII.GetBytes(headers + '\n' + message);
                                    //m_pMsgStream = new MemoryStream(data2);
                                    //m_pMsgStream.Flush();
                                    m_pMsgStream.Write(data2, 0, data2.Length);
                                    //m_pMsgStream.Position = 0;
                                }

                                SaveStream(m_pMsgStream, @"c:\postdecrypt.txt");

                                MessageStoringCompleted_eArgs oArg = m_pServer.OnMessageStoringCompleted(this,null,m_pMsgStream);
                                if(oArg.ServerReply.ErrorReply)
                                {
                                    this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("500","Error storing message"),new SocketCallBack(this.EndSend));
                                }
                                else{
                                    this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("250","Message(" + m_BDAT_ReadedCount + " bytes) stored ok."),new SocketCallBack(this.EndSend));
                                }
                            }

                            /* RFC 2821 4.1.1.4 DATA
                            NOTE:
                                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.
                            */
                            ResetState();
                        }
                        // Got BDAT data block, BDAT must continue, that wasn't last data block.
                        else{
                            // Maximum allowed message size exceeded.
                            if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize){
                                this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
                            }
                            else{
                                this.Socket.BeginWriteLine("250 Data block of " + count + " bytes recieved OK.",new SocketCallBack(this.EndSend));
                            }
                        }
                        break;

                    case SocketCallBackResult.SocketClosed:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"SocketClosed",m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

                        EndSession();
                        return;

                    case SocketCallBackResult.Exception:
                        if(m_pMsgStream != null)
                        {
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"Exception: " + exception.Message,m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

                        OnError(exception);
                        return;
                }
            }
            catch(Exception x)
            {
                OnError(x);
            }
        }
Exemple #13
0
        /// <summary>
        /// Is called when DATA command is finnished.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void EndDataCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
            //	if(m_pServer.LogCommands){
            //		m_pLogWriter.AddEntry("big binary " + count.ToString() + " bytes",this.SessionID,this.RemoteEndPoint.Address.ToString(),"S");
            //	}

                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        using(MemoryStream msgStream = Core.DoPeriodHandling(m_pMsgStream,false)){
                    //		if(Core.ScanInvalid_CR_or_LF(msgStream)){
                    //			m_pSocket.BeginSendLine("500 Message contains invalid CR or LF combination.",new SocketCallBack(this.EndSend));
                    //		}
                    //		else{
                                m_pMsgStream.SetLength(0);

                                // Store message
                                m_pMsgStream.Position = 0;
                                NewMail_EventArgs oArg = m_pServer.OnStoreMessage(this,msgStream);

                                // There is custom reply text, send it
                                if(oArg.ReplyText.Length > 0){
                                    m_pSocket.BeginSendLine("250 " + oArg.ReplyText,new SocketCallBack(this.EndSend));
                                }
                                else{
                                    m_pSocket.BeginSendLine("250 OK",new SocketCallBack(this.EndSend));
                                }
                    //		}
                        }
                        break;

                    case SocketCallBackResult.LengthExceeded:
                        m_pSocket.BeginSendLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
                        break;

                    case SocketCallBackResult.SocketClosed:
                        EndSession();
                        return;

                    case SocketCallBackResult.Exception:
                        OnError(exception);
                        return;
                }

                /* RFC 2821 4.1.1.4 DATA
                    NOTE:
                        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.
                */
                ResetState();

                // Command completed ok, get next command
            //	BeginRecieveCmd();
            }
            catch(Exception x){
                OnError(x);
            }
        }
Exemple #14
0
        /// <summary>
        /// Is called when DATA command is finnished.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void EndDataCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                if(m_pServer.LogCommands){
                    m_pLogWriter.AddEntry("big binary " + count.ToString() + " bytes",this.SessionID,this.RemoteEndPoint.Address.ToString(),"S");
                }

                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        using(MemoryStream msgStream = Core.DoPeriodHandling(m_pMsgStream,false)){
                            m_pMsgStream.SetLength(0);

                            // Store message
                            m_pServer.OnStoreMessage(this,msgStream);

                            SendData("250 OK\r\n");
                        }
                        break;

                    case SocketCallBackResult.LengthExceeded:
                        SendData("552 Requested mail action aborted: exceeded storage allocation\r\n");

                        BeginRecieveCmd();
                        break;

                    case SocketCallBackResult.SocketClosed:
                        EndSession();
                        return;

                    case SocketCallBackResult.Exception:
                        OnError(exception);
                        return;
                }

                /* RFC 2821 4.1.1.4 DATA
                    NOTE:
                        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.
                */
                ResetState();

                // Command completed ok, get next command
                BeginRecieveCmd();
            }
            catch(Exception x){
                OnError(x);
            }
        }
            private void ReadLineCompleted(SocketCallBackResult result,long count,Exception x,object tag)
            {
                // Accoridng RFC, we should get only "DONE" here.

                if(result == SocketCallBackResult.Ok){
                    if(Encoding.Default.GetString(((MemoryStream)tag).ToArray()).ToUpperInvariant() == "DONE"){
                        // Send "cmd-tag OK IDLE terminated" to connected client.
                        m_pSession.Socket.WriteLine(m_CmdTag + " OK IDLE terminated");

                        m_pSession.BeginRecieveCmd();

                        Dispose();
                    }
                    // Connected client send illegal stuff us, end session.
                    else{
                        m_pSession.EndSession();

                        Dispose();
                    }
                }
                // Receive errors, probably TCP connection broken.
                else{
                    m_pSession.EndSession();

                    Dispose();
                }
            }
        /// <summary>
        /// Is called if command is recieved.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void EndRecieveCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        MemoryStream strm = (MemoryStream)tag;

                        string cmdLine = this.Socket.Encoding.GetString(strm.ToArray());

                        // Exceute command
                        if(SwitchCommand(cmdLine)){
                            // Session end, close session
                            EndSession();
                        }
                        break;

                    case SocketCallBackResult.LengthExceeded:
                        this.Socket.WriteLine("-ERR Line too long.");

                        BeginRecieveCmd();
                        break;

                    case SocketCallBackResult.SocketClosed:
                        EndSession();
                        break;

                    case SocketCallBackResult.Exception:
                        OnError(exception);
                        break;
                }
            }
            catch(Exception x){
                 OnError(x);
            }
        }
        /// <summary>
        /// Is called when smtp client has finished reading AUTH CRAM-MD% server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnAuthCramMd5ReadServerResponseFinished(SocketCallBackResult result,
                                                             long count,
                                                             Exception exception,
                                                             object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray());

                    // Response line must start with 334 or otherwise it's error response
                    if (!responseLine.StartsWith("334"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        string md5HashKey =
                            Encoding.ASCII.GetString(Convert.FromBase64String(responseLine.Split(' ')[1]));

                        HMACMD5 kMd5 = new HMACMD5(Encoding.ASCII.GetBytes(stateData.Password));
                        byte[] md5HashByte = kMd5.ComputeHash(Encoding.ASCII.GetBytes(md5HashKey));
                        string hashedPwd = BitConverter.ToString(md5HashByte).ToLower().Replace("-", "");

                        // Start sending user name to server
                        m_pSocket.BeginWriteLine(
                            Convert.ToBase64String(
                                Encoding.ASCII.GetBytes(stateData.UserName + " " + hashedPwd)),
                            stateData,
                            OnAuthCramMd5UserPwdSendFinished);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }
		/// <summary>
		/// Is called when smtp client has finished reading DATA command server response line.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="count"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param>
		private void OnDataReadServerResponseFinished(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			CommadCompleted callback = (CommadCompleted)(((object[])tag)[1]);

			try{
				if(result == SocketCallBackResult.Ok){
					string responseLine = System.Text.Encoding.ASCII.GetString(((MemoryStream)(((object[])tag)[2])).ToArray());

					// Response line must start with 334 or otherwise it's error response
					if(!responseLine.StartsWith("354")){
						throw new Exception(responseLine);
					}
					else{
						Stream message = (Stream)(((object[])tag)[0]);
						message.Seek(0,SeekOrigin.End);

						// Terminate message <CRLF>.<CRLF>
						message.Write(new byte[]{(byte)'\r',(byte)'\n',(byte)'.',(byte)'\r',(byte)'\n'},0,5);

						message.Seek(0,SeekOrigin.Begin);
					
						// Start sending message to smtp server
						m_pSocket.BeginSendData(message,callback,new SocketCallBack(this.OnDataMessageSendFinished));	
					}				
				}
				else{
					HandleSocketError(result,exception);
				}
			}
			catch(Exception x){
				// Pass exception to callback method
				callback(SocketCallBackResult.Exception,x);
			}
		}
        /// <summary>
        /// Is called when smtp client has finished sending password to SMTP server.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnAuthLoginPasswordSendFinished(SocketCallBackResult result,
                                                     long count,
                                                     Exception exception,
                                                     object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    stateData.Tag = ms;
                    m_pSocket.BeginReadLine(ms, 1000, stateData, OnAuthLoginPwdReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }
		/// <summary>
		/// Handles socket errors.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="x"></param>
		private void HandleSocketError(SocketCallBackResult result,Exception x)
		{
			if(result == SocketCallBackResult.Exception){
				throw x;
			}
			else{
				throw new Exception(result.ToString());
			}
		}
        /// <summary>
        /// Is called when smtp client has finished RCPT TO: command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnRcptSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {callback, ms},
                                            OnRcptReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }
		/// <summary>
		/// Is called when smtp client has finished AUTH CRAM-MD5 command sending.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="count"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param>
		private void OnAuthCramMd5SendFinished(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			CommadCompleted callback = (CommadCompleted)(((object[])tag)[2]);

			try{
				if(result == SocketCallBackResult.Ok){
					MemoryStream ms = new MemoryStream();
					m_pSocket.BeginReadLine(ms,1000,new object[]{(((object[])tag)[0]),(((object[])tag)[1]),callback,ms},new SocketCallBack(this.OnAuthCramMd5ReadServerResponseFinished));
				}
				else{					
					HandleSocketError(result,exception);
				}
			}
			catch(Exception x){
				// Pass exception to callback method
				callback(SocketCallBackResult.Exception,x);
			}
		}
        /// <summary>
        /// Is called when smtp client has finished DATA command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnDataSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // DATA command has sent to SMTP server, start reading server response.
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {(((object[]) tag)[0]), callback, ms},
                                            OnDataReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }
		/// <summary>
		/// Is called when smtp client has finished reading AUTH CRAM-MD% server response line.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="count"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param> 
		private void OnAuthCramMd5ReadServerResponseFinished(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			CommadCompleted callback = (CommadCompleted)(((object[])tag)[2]);

			try{
				if(result == SocketCallBackResult.Ok){
					string responseLine = System.Text.Encoding.ASCII.GetString(((MemoryStream)(((object[])tag)[3])).ToArray());

					// Response line must start with 334 or otherwise it's error response
					if(!responseLine.StartsWith("334")){
						throw new Exception(responseLine);
					}
					else{
						string md5HashKey = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(responseLine.Split(' ')[1]));
					
						string userName = (string)(((object[])tag)[0]);
						string password = (string)(((object[])tag)[1]);

						HMACMD5 kMd5 = new HMACMD5(System.Text.Encoding.ASCII.GetBytes(password));
						byte[] md5HashByte = kMd5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(md5HashKey));
						string hashedPwd = BitConverter.ToString(md5HashByte).ToLower().Replace("-","");

						// Start sending user name to server
						m_pSocket.BeginSendLine(Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(userName + " " + hashedPwd)),callback,new SocketCallBack(this.OnAuthCramMd5UserPwdSendFinished));
					}
				}
				else{
					HandleSocketError(result,exception);
				}
			}
			catch(Exception x){
				// Pass exception to callback method
				callback(SocketCallBackResult.Exception,x);
			}
		}
        /// <summary>
        /// Is called when smtp client has sending MESSAGE to smtp server.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnDataMessageSendFinished(SocketCallBackResult result,
                                               long count,
                                               Exception exception,
                                               object tag)
        {
            CommadCompleted callback = (CommadCompleted) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // Message has successfully sent to smtp server, start reading server response
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {callback, ms},
                                            OnDataMessageSendReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }
		/// <summary>
		/// Is called when smtp client has finished reading user name and password send server response line.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="count"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param> 
		private void OnAuthCramMd5UserPwdReadServerResponseFinished(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			CommadCompleted callback = (CommadCompleted)(((object[])tag)[0]);

			try{
				if(result == SocketCallBackResult.Ok){
					string responseLine = System.Text.Encoding.ASCII.GetString(((MemoryStream)(((object[])tag)[1])).ToArray());

					// Response line must start with 235 or otherwise it's error response
					if(!responseLine.StartsWith("235")){
						throw new Exception(responseLine);
					}
					else{
						// AUTH CRAM-MD5 completed susscessfully, call callback method.
						callback(SocketCallBackResult.Ok,null);
					}
				}
				else{
					HandleSocketError(result,exception);
				}
			}
			catch(Exception x){
				// Pass exception to callback method
				callback(SocketCallBackResult.Exception,x);
			}
		}
        /// <summary>
        /// Handles socket errors.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="x"></param>
        private void HandleSocketError(SocketCallBackResult result, Exception x)
        {
            // Log socket errors to log
            if (m_pSocket.Logger != null)
            {
                if (result == SocketCallBackResult.SocketClosed)
                {
                    m_pSocket.Logger.AddTextEntry("Server closed socket !");
                }
                else if (x != null && x is SocketException)
                {
                    SocketException socketException = (SocketException) x;
                    // Server disconnected or aborted connection
                    if (socketException.ErrorCode == 10054 || socketException.ErrorCode == 10053)
                    {
                        m_pSocket.Logger.AddTextEntry("Server closed socket or aborted connection !");
                    }
                }
                else
                {
                    m_pSocket.Logger.AddTextEntry("Unknown error !");
                }
            }

            if (result == SocketCallBackResult.Exception)
            {
                throw x;
            }
            else
            {
                throw new Exception(result.ToString());
            }
        }
		/// <summary>
		/// Is called when smtp client has finished reading MAIL FROM: command server response line.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="count"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param> 
		private void OnAuthLoginReadServerResponseFinished(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			CommadCompleted callback = (CommadCompleted)(((object[])tag)[2]);

			try{
				if(result == SocketCallBackResult.Ok){
					string responseLine = System.Text.Encoding.ASCII.GetString(((MemoryStream)(((object[])tag)[3])).ToArray());

					// Response line must start with 334 or otherwise it's error response
					if(!responseLine.StartsWith("334")){
						throw new Exception(responseLine);
					}
					else{
						string userName = (string)(((object[])tag)[0]);

						// Start sending user name to server
						m_pSocket.BeginSendLine(Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(userName)),new object[]{(((object[])tag)[1]),callback},new SocketCallBack(this.OnAuthLoginUserSendFinished));
					}
				}
				else{
					HandleSocketError(result,exception);
				}
			}
			catch(Exception x){
				// Pass exception to callback method
				callback(SocketCallBackResult.Exception,x);
			}
		}
        /// <summary>
        /// Is called when DATA command is finnished.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void EndDataCmd(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        // Notify Message stream owner that message storing completed ok.
                        MessageStoringCompleted_eArgs oArg = m_pServer.OnMessageStoringCompleted(this,null,m_pMsgStream);
                        if(oArg.ServerReply.ErrorReply){
                            this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("500","Error storing message"),new SocketCallBack(this.EndSend));
                        }
                        else{
                            this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("250","OK"),new SocketCallBack(this.EndSend));
                        }
                        break;

                    case SocketCallBackResult.LengthExceeded:
                        // We must call that method to notify Message stream owner to close/dispose that stream.
                        m_pServer.OnMessageStoringCompleted(this,"Requested mail action aborted: exceeded storage allocation",m_pMsgStream);

                        this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
                        break;

                    case SocketCallBackResult.SocketClosed:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"SocketClosed",m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

                        EndSession();
                        break;

                    case SocketCallBackResult.Exception:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"Exception: " + exception.Message,m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

                        OnError(exception);
                        break;
                }

                /* RFC 2821 4.1.1.4 DATA
                    NOTE:
                        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.
                */
                ResetState();
            }
            catch(Exception x){
                OnError(x);
            }
        }
        /// <summary>
        /// Is called when smtp client has finished reading EHLO command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnEhloReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[2])).ToArray());

                    /* RFC 2821 4.1.1.1 EHLO
					*	Examples:
					*		250-domain<SP>free_text<CRLF>
					*       250-EHLO_keyword<CRLF>
					*		250<SP>EHLO_keyword<CRLF>
					* 
					* 250<SP> specifies that last EHLO response line.
					*/

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        // Server isn't required to support EHLO, try HELO
                        string hostName = (string) (((object[]) tag)[0]);
                        m_pSocket.BeginWriteLine("HELO " + hostName, callback, OnHeloSendFinished);
                    }
                    else
                    {
                        //---- Store supported ESMTP features --------------------//
                        if (responseLine.ToLower().IndexOf("size") > -1)
                        {
                            m_Supports_Size = true;
                        }
                        else if (responseLine.ToLower().IndexOf("chunking") > -1)
                        {
                            m_Supports_Bdat = true;
                        }
                        else if (responseLine.ToLower().IndexOf("cram-md5") > -1)
                        {
                            m_Supports_CramMd5 = true;
                        }
                        else if (responseLine.ToLower().IndexOf("login") > -1)
                        {
                            m_Supports_Login = true;
                        }
                        //--------------------------------------------------------//

                        // This isn't last EHLO response line
                        if (!responseLine.StartsWith("250 "))
                        {
                            MemoryStream ms = new MemoryStream();
                            m_pSocket.BeginReadLine(ms,
                                                    1000,
                                                    new[] {(((object[]) tag)[0]), callback, ms},
                                                    OnEhloReadServerResponseFinished);
                        }
                        else
                        {
                            // EHLO completed susscessfully, call callback method.
                            callback(SocketCallBackResult.Ok, null);
                        }
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }
        /// <summary>
        /// Is called when asynchronous send completes.
        /// </summary>
        /// <param name="result">If true, then send was successfull.</param>
        /// <param name="count">Count sended.</param>
        /// <param name="exception">Exception happend on send. NOTE: available only is result=false.</param>
        /// <param name="tag">User data.</param>
        private void EndSend(SocketCallBackResult result,long count,Exception exception,object tag)
        {
            try{
                switch(result)
                {
                    case SocketCallBackResult.Ok:
                        BeginRecieveCmd();
                        break;

                    case SocketCallBackResult.SocketClosed:
                        EndSession();
                        break;

                    case SocketCallBackResult.Exception:
                        OnError(exception);
                        break;
                }
            }
            catch(Exception x){
                OnError(x);
            }
        }
        /// <summary>
        /// Is called when smtp client has finished reading EHLO command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnHeloReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray());

                    /* RFC 2821 4.1.1.1 HELO
					*	Examples:
					*		250<SP>domain<SP>free_text<CRLF>
					* 
					*/

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // EHLO completed susscessfully, call callback method.
                        callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }