Taddo - 2007-03-22

First i would like to thank everbody for the good job you are doing.

Here is my proposition :

As you know, the SMTP server responses messages to the Commandes sent by the client are format as 3 digits + a description of the response, and the SMTP protocol has this rule regarding those responses :

1- if the 3 digits are followed by a space char this mean that the server ends sending responses for the sent request commande Ex : 235 Authentication successful.

2- if those 3 digits are fellowed by a dash '-' char this mean that server is still sending other responses messages (it did not complete its response) Ex:

250-tsmtp4.mail.isp
250-PIPELINING
250-ETRN
250-DSN
250-SIZE 26214400
250-AUTH PLAIN LOGIN
250 AUTH=LOGIN

i noticed that with the current version of the ReadFromStream methods, some times we are getting this Error :

ERROR - Expecting 250. Recieved: 334 VXNlcm5hbWU6

After debugging and reading the trace log file, i noticed that After sending the
'EHLO pcexample' ReadFromStream returns only the first line of the server response Ex:

250-tsmtp4.mail.isp

(this line means that the server does not yet complete his responses as i explained). the problem is that we are not waiting for the server to complete what he wants to say. and we go directly to the 'AuthLogin(ref nwstream);' line code, and in this function after we send our 'AUTH LOGIN' commande to the server we try to read from the stream (ReadFromStream) and logicaly what we get is the rest of the incompleted server responses to the first commande we sent (wich is EHLO) wich is :

250-PIPELINING
250-ETRN
250-DSN
250-SIZE 26214400
250-AUTH PLAIN LOGIN
250 AUTH=LOGIN

this causes that our process is broken cause our 'AuthImplemented' will return 'FALSE'.

I think that we need an enhancement to the 'ReadFromStream' method so it will return the complete Server responses messages, i already did some work on that and i would like to share it with you so you can tell me what you think :

private string ReadFromStream(ref NetworkStream nw)
{
    try
    {
        byte[] readBuffer = new byte[4096];
                bool ContinueReading = true;
                string serverMsg = "";
                string returnValue = "";
                int TryTimes = 0;
                           
                while (ContinueReading)
                {
                    TryTimes++;

                    int length = nw.Read(readBuffer, 0, readBuffer.Length);
                    serverMsg = Encoding.ASCII.GetString(readBuffer, 0, length);
                    char[] arrReturnMsgChars;
                    ArrayList arrReturnMsgLines;

                    arrReturnMsgLines = parseResponseMsgInToLines(serverMsg);

                    if (arrReturnMsgLines.Count > 0)
                    {
                        returnValue = arrReturnMsgLines[arrReturnMsgLines.Count - 1].ToString();
                        arrReturnMsgChars = returnValue.ToCharArray();
                        //check if the responses we got is a final or we should wait other reponses
                        if (arrReturnMsgChars[3] == char.Parse("-"))
                        {
                            Thread.Sleep(500);
                        }
                        else
                        {
                            ContinueReading = false;
                        }
                    }

                    if (TryTimes == 4)
                    {
                        ContinueReading = false;
                    }
                }

                // return only the last message
                return returnValue;
            }
            catch(System.Exception e)
            {
                throw new SmtpException("Read from Stream threw an System.Exception: " + e.ToString());
            }
        }

private ArrayList parseResponseMsgInToLines(string returnMsg)
{
    ArrayList arrReturnMsgLines = new ArrayList(returnMsg.Split("\r\n".ToCharArray()));

           for (int i = 0; i < arrReturnMsgLines.Count; i++)
            {
                if (arrReturnMsgLines[i].ToString() == string.Empty)
                {
                    arrReturnMsgLines.RemoveAt(i);
                    i--;
                }
                else
                {
                    LogMessage(arrReturnMsgLines[i].ToString(), "[server]: ");
                }
            }

            return arrReturnMsgLines;
}

Regards,