Author: fejj
Date: 2007-05-31 21:46:13 -0400 (Thu, 31 May 2007)
New Revision: 78391

Modified:
   trunk/mcs/class/System/System.Net.Mail/ChangeLog
   trunk/mcs/class/System/System.Net.Mail/SmtpClient.cs
Log:
2007-05-31  Jeffrey Stedfast  <[EMAIL PROTECTED]>

        * SmtpClient.cs: Added an extensions parser to figure out if the
        ESMTP server supports things like STARTTLS and which AUTH
        mechanisms are supported. Don't try authenticating if no authmechs
        are supported.



Modified: trunk/mcs/class/System/System.Net.Mail/ChangeLog
===================================================================
--- trunk/mcs/class/System/System.Net.Mail/ChangeLog    2007-06-01 01:28:58 UTC 
(rev 78390)
+++ trunk/mcs/class/System/System.Net.Mail/ChangeLog    2007-06-01 01:46:13 UTC 
(rev 78391)
@@ -1,3 +1,10 @@
+2007-05-31  Jeffrey Stedfast  <[EMAIL PROTECTED]>
+
+       * SmtpClient.cs: Added an extensions parser to figure out if the
+       ESMTP server supports things like STARTTLS and which AUTH
+       mechanisms are supported. Don't try authenticating if no authmechs
+       are supported.
+
 2007-05-30  Jeffrey Stedfast  <[EMAIL PROTECTED]>
 
        * SmtpClient.cs: Fall back to HELO if EHLO fails. Also, do not

Modified: trunk/mcs/class/System/System.Net.Mail/SmtpClient.cs
===================================================================
--- trunk/mcs/class/System/System.Net.Mail/SmtpClient.cs        2007-06-01 
01:28:58 UTC (rev 78390)
+++ trunk/mcs/class/System/System.Net.Mail/SmtpClient.cs        2007-06-01 
01:46:13 UTC (rev 78391)
@@ -57,7 +57,7 @@
                string pickupDirectoryLocation;
                SmtpDeliveryMethod deliveryMethod;
                bool enableSsl;
-               X509CertificateCollection clientCertificates;
+               //X509CertificateCollection clientCertificates;
 
                TcpClient client;
                NetworkStream stream;
@@ -66,6 +66,20 @@
                int boundaryIndex;
                MailAddress defaultFrom;
 
+               // ESMTP state
+               enum AuthMechs {
+                       None        = 0,
+                       CramMD5     = 0x01,
+                       DigestMD5   = 0x02,
+                       GssAPI      = 0x04,
+                       Kerberos4   = 0x08,
+                       Login       = 0x10,
+                       Plain       = 0x20,
+               }
+               
+               AuthMechs authMechs = AuthMechs.None;
+               bool canStartTLS = false;
+
                Mutex mutex = new Mutex ();
 
                #endregion // Fields
@@ -118,7 +132,7 @@
                public X509CertificateCollection ClientCertificates {
                        get {
                                throw new NotImplementedException ("Client 
certificates are not supported");
-                               return clientCertificates;
+                               //return clientCertificates;
                        }
                }
 
@@ -133,6 +147,7 @@
                }
 
                public bool EnableSsl {
+                       // FIXME: So... is this supposed to enable SSL port 
functionality? or STARTTLS? Or both?
                        get { return enableSsl; }
                        set { enableSsl = value; }
                }
@@ -158,9 +173,9 @@
                        get { return port; }
                        // FIXME: Check to make sure an email is not being sent.
                        set { 
-                               if (value <= 0)
+                               if (value <= 0 || value > 65535)
                                        throw new ArgumentOutOfRangeException 
();
-                               port = value; 
+                               port = value;
                        }
                }
 
@@ -263,15 +278,67 @@
                                SmtpResponse response = SmtpResponse.Parse 
(line);
 
                                return response;
-                       }
-                       else {
+                       } else {
                                throw new System.IO.IOException ("Connection 
closed");
                        }
                }
 
-               public void Send (MailMessage message) {
-                       CheckHostAndPort ();
+               void ParseExtensions (string extens)
+               {
+                       char []delims = new char [1] { ' ' };
+                       int ln = 0;
+                       
+                       do {
+                               if (ln != 0)
+                                       ln++;
+                               
+                               if (ln > extens.Length)
+                                       break;
+                               
+                               if (extens.Substring (ln, 4) == "AUTH" &&
+                                   (extens[ln + 4] == ' ' || extens[ln + 4] == 
'=')) {
+                                       int eoln = extens.IndexOf ('\n', ln + 
4);
+                                       string mechlist = extens.Substring (ln, 
eoln);
+                                       string []mechs = mechlist.Split 
(delims);
+                                       
+                                       ln = eoln;
+                                       
+                                       for (int i = 0; i < mechs.Length; i++) {
+                                               switch (mechs[i]) {
+                                               case "CRAM-MD5":
+                                                       authMechs |= 
AuthMechs.CramMD5;
+                                                       break;
+                                               case "DIGEST-MD5":
+                                                       authMechs |= 
AuthMechs.DigestMD5;
+                                                       break;
+                                               case "GSSAPI":
+                                                       authMechs |= 
AuthMechs.GssAPI;
+                                                       break;
+                                               case "KERBEROS_V4":
+                                                       authMechs |= 
AuthMechs.Kerberos4;
+                                                       break;
+                                               case "LOGIN":
+                                                       authMechs |= 
AuthMechs.Login;
+                                                       break;
+                                               case "PLAIN":
+                                                       authMechs |= 
AuthMechs.Plain;
+                                                       break;
+                                               }
+                                       }
+                               } else if (extens.Substring (ln, 8) == 
"STARTTLS") {
+                                       canStartTLS = true;
+                               }
+                       } while ((ln = extens.IndexOf ('\n', ln)) != -1);
+               }
 
+               public void Send (MailMessage message)
+               {
+                       if (String.IsNullOrEmpty (Host))
+                               throw new InvalidOperationException ("The SMTP 
host was not specified");
+                       
+                       if (port == 0)
+                               port = 25;
+                       
                        // Block while sending
                        mutex.WaitOne ();
 
@@ -291,22 +358,37 @@
                        // FIXME: parse the list of extensions so we don't 
bother wasting
                        // our time trying commands if they aren't supported.
                        status = SendCommand ("EHLO " + Dns.GetHostName ());
-
+                       
                        if (IsError (status)) {
                                status = SendCommand ("HELO " + Dns.GetHostName 
());
                                
                                if (IsError (status))
                                        throw new SmtpException 
(status.StatusCode, status.Description);
+                       } else {
+                               // Parse ESMTP extensions
+                               string extens = status.Description;
+                               
+                               if (extens != null)
+                                       ParseExtensions (extens);
                        }
-
-                       if (EnableSsl) {
-                               // FIXME: only attempt this if STARTTLS is 
supported
+                       
+                       if (enableSsl) {
+                               // FIXME: I get the feeling from the docs that 
EnableSsl is meant
+                               // for using the SSL-port and not STARTTLS (or, 
if it includes
+                               // STARTTLS... only use STARTTLS if the 
SSL-type in the certificate
+                               // is TLS and not SSLv2 or SSLv3)
+                               
+                               // FIXME: even tho we have a canStartTLS 
flag... ignore it for now
+                               // so that the STARTTLS command can throw the 
appropriate
+                               // SmtpException if STARTTLS is unavailable
                                InitiateSecureConnection ();
+                               
+                               // FIXME: re-EHLO?
                        }
-
-                       // FIXME: only do this if AUTH is supported
-                       PerformAuthentication ();
-
+                       
+                       if (authMechs != AuthMechs.None)
+                               Authenticate ();
+                       
                        MailAddress from = message.From;
 
                        if (from == null)
@@ -370,8 +452,7 @@
 
                        if (hasAttachments || hasAlternateViews) {
                                SendMultipartBody (message);
-                       }
-                       else {
+                       } else {
                                SendSimpleBody (message);
                        }
 
@@ -383,10 +464,9 @@
 
                        try {
                                status = SendCommand ("QUIT");
+                       } catch (System.IO.IOException) {
+                               // We excuse server for the rude connection 
closing as a response to QUIT
                        }
-                       catch (System.IO.IOException) {
-                               //We excuse server for the rude connection 
closing as a response to QUIT
-                       }
 
                        writer.Close ();
                        reader.Close ();
@@ -598,8 +678,7 @@
                                if (i > 127) {
                                        writer.Write ("=");
                                        writer.Write (Convert.ToString (i, 
16).ToUpper ());
-                               }
-                               else
+                               } else
                                        writer.Write (Convert.ToChar (i));
                        }
 
@@ -638,29 +717,27 @@
                        throw new NotImplementedException ();
 #endif
                }
-
-               void CheckHostAndPort () {
-                       if (String.IsNullOrEmpty (Host))
-                               throw new InvalidOperationException ("The SMTP 
host was not specified");
-
-                       if (Port == 0)
-                               Port = 25;
-               }
                
-               void PerformAuthentication () {
+               void Authenticate ()
+               {
+                       string user = null, pass = null;
+                       
                        if (UseDefaultCredentials) {
-                               Authenticate (
-                                       
CredentialCache.DefaultCredentials.GetCredential (new System.Uri ("smtp://" + 
host), "basic").UserName,
-                                       
CredentialCache.DefaultCredentials.GetCredential (new System.Uri ("smtp://" + 
host), "basic").Password);
+                               user = 
CredentialCache.DefaultCredentials.GetCredential (new System.Uri ("smtp://" + 
host), "basic").UserName;
+                               pass =  
CredentialCache.DefaultCredentials.GetCredential (new System.Uri ("smtp://" + 
host), "basic").Password;
+                       } else if (Credentials != null) {
+                               user = Credentials.GetCredential (host, port, 
"smtp").UserName;
+                               pass = Credentials.GetCredential (host, port, 
"smtp").Password;
+                       } else {
+                               return;
                        }
-                       else if (Credentials != null) {
-                               Authenticate (
-                                       Credentials.GetCredential (host, port, 
"smtp").UserName,
-                                       Credentials.GetCredential (host, port, 
"smtp").Password);
-                       }
+                       
+                       Authenticate (user, pass);
                }
 
-               void Authenticate (string Username, string Password) {
+               void Authenticate (string Username, string Password)
+               {
+                       // FIXME: use the proper AuthMech
                        SmtpResponse status = SendCommand ("AUTH LOGIN");
                        if (((int) status.StatusCode) != 334) {
                                throw new SmtpException (status.StatusCode, 
status.Description);
@@ -676,13 +753,13 @@
                                throw new SmtpException (status.StatusCode, 
status.Description);
                        }
                }
-               /*
-                               [MonoTODO]
-                               private sealed ContextAwareResult 
IGetContextAwareResult.GetContextAwareResult ()
-                               {
-                                       throw new NotImplementedException ();
-                               }
-               */
+               
+               /*[MonoTODO]
+               private sealed ContextAwareResult 
IGetContextAwareResult.GetContextAwareResult ()
+               {
+                       throw new NotImplementedException ();
+               }*/
+               
                #endregion // Methods
                
                // The HeaderName struct is used to store constant string 
values representing mail headers.
@@ -711,7 +788,7 @@
 
                                if (line.Length < 4)
                                        throw new SmtpException ("Response is 
to short " +
-                                                                  line.Length 
+ ".");
+                                                                line.Length + 
".");
 
                                if ((line [3] != ' ') && (line [3] != '-'))
                                        throw new SmtpException ("Response 
format is wrong.(" +

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to