]> git.llucax.com Git - software/mutt-debian.git/blobdiff - smtp.c
Move Mutt with NNTP support to mutt-nntp package
[software/mutt-debian.git] / smtp.c
diff --git a/smtp.c b/smtp.c
index 654f4aa9834a38e7ec986237a8001a5ae2c779e9..a718006bd82f9fe5a268deb685ea0e6ed81c5397 100644 (file)
--- a/smtp.c
+++ b/smtp.c
@@ -1,6 +1,6 @@
 /* mutt - text oriented MIME mail user agent
  * Copyright (C) 2002 Michael R. Elkins <me@mutt.org>
 /* mutt - text oriented MIME mail user agent
  * Copyright (C) 2002 Michael R. Elkins <me@mutt.org>
- * Copyright (C) 2005-7 Brendan Cully <brendan@kublai.com>
+ * Copyright (C) 2005-9 Brendan Cully <brendan@kublai.com>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
@@ -47,6 +47,7 @@
 
 #define smtp_err_read -2
 #define smtp_err_write -3
 
 #define smtp_err_read -2
 #define smtp_err_write -3
+#define smtp_err_code -4
 
 #define SMTP_PORT 25
 #define SMTPS_PORT 465
 
 #define SMTP_PORT 25
 #define SMTPS_PORT 465
@@ -76,6 +77,21 @@ static int Esmtp = 0;
 static char* AuthMechs = NULL;
 static unsigned char Capabilities[(CAPMAX + 7)/ 8];
 
 static char* AuthMechs = NULL;
 static unsigned char Capabilities[(CAPMAX + 7)/ 8];
 
+static int smtp_code (char *buf, size_t len, int *n)
+{
+  char code[4];
+
+  if (len < 4)
+    return -1;
+  code[0] = buf[0];
+  code[1] = buf[1];
+  code[2] = buf[2];
+  code[3] = 0;
+  if (mutt_atoi (code, n) < 0)
+    return -1;
+  return 0;
+}
+
 /* Reads a command response from the SMTP server.
  * Returns:
  * 0   on success (2xx code) or continue (354 code)
 /* Reads a command response from the SMTP server.
  * Returns:
  * 0   on success (2xx code) or continue (354 code)
@@ -89,13 +105,14 @@ smtp_get_resp (CONNECTION * conn)
 
   do {
     n = mutt_socket_readln (buf, sizeof (buf), conn);
 
   do {
     n = mutt_socket_readln (buf, sizeof (buf), conn);
-    if (n == -1)
+    if (n < 4) {
+      /* read error, or no response code */
       return smtp_err_read;
       return smtp_err_read;
-    n = atoi (buf);
+    }
 
     if (!ascii_strncasecmp ("8BITMIME", buf + 4, 8))
       mutt_bit_set (Capabilities, EIGHTBITMIME);
 
     if (!ascii_strncasecmp ("8BITMIME", buf + 4, 8))
       mutt_bit_set (Capabilities, EIGHTBITMIME);
-    else if (!ascii_strncasecmp ("AUTH", buf + 4, 4))
+    else if (!ascii_strncasecmp ("AUTH ", buf + 4, 5))
     {
       mutt_bit_set (Capabilities, AUTH);
       FREE (&AuthMechs);
     {
       mutt_bit_set (Capabilities, AUTH);
       FREE (&AuthMechs);
@@ -105,6 +122,10 @@ smtp_get_resp (CONNECTION * conn)
       mutt_bit_set (Capabilities, DSN);
     else if (!ascii_strncasecmp ("STARTTLS", buf + 4, 8))
       mutt_bit_set (Capabilities, STARTTLS);
       mutt_bit_set (Capabilities, DSN);
     else if (!ascii_strncasecmp ("STARTTLS", buf + 4, 8))
       mutt_bit_set (Capabilities, STARTTLS);
+
+    if (smtp_code (buf, n, &n) < 0)
+      return smtp_err_code;
+
   } while (buf[3] == '-');
 
   if (smtp_success (n) || n == smtp_continue)
   } while (buf[3] == '-');
 
   if (smtp_success (n) || n == smtp_continue)
@@ -122,6 +143,12 @@ smtp_rcpt_to (CONNECTION * conn, const ADDRESS * a)
 
   while (a)
   {
 
   while (a)
   {
+    /* weed out group mailboxes, since those are for display only */
+    if (!a->mailbox || a->group)
+    {
+      a = a->next;
+      continue;
+    }
     if (mutt_bit_isset (Capabilities, DSN) && DsnNotify)
       snprintf (buf, sizeof (buf), "RCPT TO:<%s> NOTIFY=%s\r\n",
                 a->mailbox, DsnNotify);
     if (mutt_bit_isset (Capabilities, DSN) && DsnNotify)
       snprintf (buf, sizeof (buf), "RCPT TO:<%s> NOTIFY=%s\r\n",
                 a->mailbox, DsnNotify);
@@ -144,8 +171,8 @@ smtp_data (CONNECTION * conn, const char *msgfile)
   FILE *fp = 0;
   progress_t progress;
   struct stat st;
   FILE *fp = 0;
   progress_t progress;
   struct stat st;
-  int r;
-  size_t buflen;
+  int r, term = 0;
+  size_t buflen = 0;
 
   fp = fopen (msgfile, "r");
   if (!fp)
 
   fp = fopen (msgfile, "r");
   if (!fp)
@@ -161,18 +188,19 @@ smtp_data (CONNECTION * conn, const char *msgfile)
   snprintf (buf, sizeof (buf), "DATA\r\n");
   if (mutt_socket_write (conn, buf) == -1)
   {
   snprintf (buf, sizeof (buf), "DATA\r\n");
   if (mutt_socket_write (conn, buf) == -1)
   {
-    fclose (fp);
+    safe_fclose (&fp);
     return smtp_err_write;
   }
   if ((r = smtp_get_resp (conn)))
   {
     return smtp_err_write;
   }
   if ((r = smtp_get_resp (conn)))
   {
-    fclose (fp);
+    safe_fclose (&fp);
     return r;
   }
 
   while (fgets (buf, sizeof (buf) - 1, fp))
   {
     buflen = mutt_strlen (buf);
     return r;
   }
 
   while (fgets (buf, sizeof (buf) - 1, fp))
   {
     buflen = mutt_strlen (buf);
+    term = buf[buflen-1] == '\n';
     if (buflen && buf[buflen-1] == '\n'
        && (buflen == 1 || buf[buflen - 2] != '\r'))
       snprintf (buf + buflen - 1, sizeof (buf) - buflen + 1, "\r\n");
     if (buflen && buf[buflen-1] == '\n'
        && (buflen == 1 || buf[buflen - 2] != '\r'))
       snprintf (buf + buflen - 1, sizeof (buf) - buflen + 1, "\r\n");
@@ -180,19 +208,24 @@ smtp_data (CONNECTION * conn, const char *msgfile)
     {
       if (mutt_socket_write_d (conn, ".", -1, M_SOCK_LOG_FULL) == -1)
       {
     {
       if (mutt_socket_write_d (conn, ".", -1, M_SOCK_LOG_FULL) == -1)
       {
-        fclose (fp);
+        safe_fclose (&fp);
         return smtp_err_write;
       }
     }
     if (mutt_socket_write_d (conn, buf, -1, M_SOCK_LOG_FULL) == -1)
     {
         return smtp_err_write;
       }
     }
     if (mutt_socket_write_d (conn, buf, -1, M_SOCK_LOG_FULL) == -1)
     {
-      fclose (fp);
+      safe_fclose (&fp);
       return smtp_err_write;
     }
       return smtp_err_write;
     }
-
     mutt_progress_update (&progress, ftell (fp), -1);
   }
     mutt_progress_update (&progress, ftell (fp), -1);
   }
-  fclose (fp);
+  if (!term && buflen &&
+      mutt_socket_write_d (conn, "\r\n", -1, M_SOCK_LOG_FULL) == -1)
+  {
+    safe_fclose (&fp);
+    return smtp_err_write;
+  }
+  safe_fclose (&fp);
 
   /* terminate the message body */
   if (mutt_socket_write (conn, ".\r\n") == -1)
 
   /* terminate the message body */
   if (mutt_socket_write (conn, ".\r\n") == -1)
@@ -210,8 +243,21 @@ mutt_smtp_send (const ADDRESS* from, const ADDRESS* to, const ADDRESS* cc,
 {
   CONNECTION *conn;
   ACCOUNT account;
 {
   CONNECTION *conn;
   ACCOUNT account;
-  int ret = -1;
+  const char* envfrom;
   char buf[1024];
   char buf[1024];
+  int ret = -1;
+
+  /* it might be better to synthesize an envelope from from user and host
+   * but this condition is most likely arrived at accidentally */
+  if (EnvFrom)
+    envfrom = EnvFrom->mailbox;
+  else if (from)
+    envfrom = from->mailbox;
+  else
+  {
+    mutt_error (_("No from address given"));
+    return -1;
+  }
 
   if (smtp_fill_account (&account) < 0)
     return ret;
 
   if (smtp_fill_account (&account) < 0)
     return ret;
@@ -229,8 +275,7 @@ mutt_smtp_send (const ADDRESS* from, const ADDRESS* to, const ADDRESS* cc,
     FREE (&AuthMechs);
 
     /* send the sender's address */
     FREE (&AuthMechs);
 
     /* send the sender's address */
-    ret = snprintf (buf, sizeof (buf), "MAIL FROM:<%s>",
-                    EnvFrom ? EnvFrom->mailbox : from->mailbox);
+    ret = snprintf (buf, sizeof (buf), "MAIL FROM:<%s>", envfrom);
     if (eightbit && mutt_bit_isset (Capabilities, EIGHTBITMIME))
     {
       safe_strncat (buf, sizeof (buf), " BODY=8BITMIME", 15);
     if (eightbit && mutt_bit_isset (Capabilities, EIGHTBITMIME))
     {
       safe_strncat (buf, sizeof (buf), " BODY=8BITMIME", 15);
@@ -269,6 +314,8 @@ mutt_smtp_send (const ADDRESS* from, const ADDRESS* to, const ADDRESS* cc,
     mutt_error (_("SMTP session failed: read error"));
   else if (ret == smtp_err_write)
     mutt_error (_("SMTP session failed: write error"));
     mutt_error (_("SMTP session failed: read error"));
   else if (ret == smtp_err_write)
     mutt_error (_("SMTP session failed: write error"));
+  else if (ret == smtp_err_code)
+    mutt_error (_("Invalid server response"));
 
   return ret;
 }
 
   return ret;
 }
@@ -325,6 +372,7 @@ static int smtp_fill_account (ACCOUNT* account)
 static int smtp_helo (CONNECTION* conn)
 {
   char buf[LONG_STRING];
 static int smtp_helo (CONNECTION* conn)
 {
   char buf[LONG_STRING];
+  const char* fqdn;
 
   memset (Capabilities, 0, sizeof (Capabilities));
 
 
   memset (Capabilities, 0, sizeof (Capabilities));
 
@@ -339,7 +387,10 @@ static int smtp_helo (CONNECTION* conn)
 #endif
   }
 
 #endif
   }
 
-  snprintf (buf, sizeof (buf), "%s %s\r\n", Esmtp ? "EHLO" : "HELO", Fqdn);
+  if(!(fqdn = mutt_fqdn (0)))
+    fqdn = NONULL (Hostname);
+
+  snprintf (buf, sizeof (buf), "%s %s\r\n", Esmtp ? "EHLO" : "HELO", fqdn);
   /* XXX there should probably be a wrapper in mutt_socket.c that
     * repeatedly calls conn->write until all data is sent.  This
     * currently doesn't check for a short write.
   /* XXX there should probably be a wrapper in mutt_socket.c that
     * repeatedly calls conn->write until all data is sent.  This
     * currently doesn't check for a short write.
@@ -435,7 +486,14 @@ static int smtp_auth (CONNECTION* conn)
 
       dprint (2, (debugfile, "smtp_authenticate: Trying method %s\n", method));
 
 
       dprint (2, (debugfile, "smtp_authenticate: Trying method %s\n", method));
 
-      if ((r = smtp_auth_sasl (conn, method)) != SMTP_AUTH_UNAVAIL)
+      r = smtp_auth_sasl (conn, method);
+      
+      if (r == SMTP_AUTH_FAIL && delim)
+      {
+        mutt_error (_("%s authentication failed, trying next method"), method);
+        mutt_sleep (1);
+      }
+      else if (r != SMTP_AUTH_UNAVAIL)
         break;
     }
 
         break;
     }
 
@@ -447,7 +505,12 @@ static int smtp_auth (CONNECTION* conn)
   if (r != SMTP_AUTH_SUCCESS)
     mutt_account_unsetpass (&conn->account);
 
   if (r != SMTP_AUTH_SUCCESS)
     mutt_account_unsetpass (&conn->account);
 
-  if (r == SMTP_AUTH_UNAVAIL)
+  if (r == SMTP_AUTH_FAIL)
+  {
+    mutt_error (_("SASL authentication failed"));
+    mutt_sleep (1);
+  }
+  else if (r == SMTP_AUTH_UNAVAIL)
   {
     mutt_error (_("No authenticators available"));
     mutt_sleep (1);
   {
     mutt_error (_("No authenticators available"));
     mutt_sleep (1);
@@ -484,7 +547,8 @@ static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist)
     return SMTP_AUTH_UNAVAIL;
   }
 
     return SMTP_AUTH_UNAVAIL;
   }
 
-  mutt_message (_("Authenticating (%s)..."), mech);
+  if (!option(OPTNOCURSES))
+    mutt_message (_("Authenticating (%s)..."), mech);
 
   snprintf (buf, sizeof (buf), "AUTH %s", mech);
   if (len)
 
   snprintf (buf, sizeof (buf), "AUTH %s", mech);
   if (len)
@@ -502,9 +566,10 @@ static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist)
   do {
     if (mutt_socket_write (conn, buf) < 0)
       goto fail;
   do {
     if (mutt_socket_write (conn, buf) < 0)
       goto fail;
-    if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
+    if ((rc = mutt_socket_readln (buf, sizeof (buf), conn)) < 0)
+      goto fail;
+    if (smtp_code (buf, rc, &rc) < 0)
       goto fail;
       goto fail;
-    rc = atoi(buf);
 
     if (rc != smtp_ready)
       break;
 
     if (rc != smtp_ready)
       break;
@@ -532,24 +597,15 @@ static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist)
       }
     }
     strfcpy (buf + len, "\r\n", sizeof (buf) - len);
       }
     }
     strfcpy (buf + len, "\r\n", sizeof (buf) - len);
-  } while (rc == smtp_ready);
+  } while (rc == smtp_ready && saslrc != SASL_FAIL);
 
   if (smtp_success (rc))
   {
     mutt_sasl_setup_conn (conn, saslconn);
     return SMTP_AUTH_SUCCESS;
   }
 
   if (smtp_success (rc))
   {
     mutt_sasl_setup_conn (conn, saslconn);
     return SMTP_AUTH_SUCCESS;
   }
-  else if (SmtpAuthenticators && *SmtpAuthenticators)
-  {
-    /* if we're given a mech list to attempt, failure means try the next */
-    dprint (2, (debugfile, "smtp_auth_sasl: %s failed\n", mech));
-    sasl_dispose (&saslconn);
-    return SMTP_AUTH_UNAVAIL;
-  }
 
 fail:
 
 fail:
-  mutt_error (_("SASL authentication failed"));
-  mutt_sleep (1);
   sasl_dispose (&saslconn);
   return SMTP_AUTH_FAIL;
 }
   sasl_dispose (&saslconn);
   return SMTP_AUTH_FAIL;
 }