/* 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
#define smtp_err_read -2
#define smtp_err_write -3
+#define smtp_err_code -4
#define SMTP_PORT 25
#define SMTPS_PORT 465
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)
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;
- n = atoi (buf);
+ }
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, 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 (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);
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)
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)))
{
- fclose (fp);
+ safe_fclose (&fp);
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 (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)
{
- fclose (fp);
+ safe_fclose (&fp);
return smtp_err_write;
}
-
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)
{
CONNECTION *conn;
ACCOUNT account;
- int ret = -1;
+ const char* envfrom;
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;
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);
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;
}
static int smtp_helo (CONNECTION* conn)
{
char buf[LONG_STRING];
+ const char* fqdn;
memset (Capabilities, 0, sizeof (Capabilities));
#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.
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;
}
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);
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)
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;
- rc = atoi(buf);
if (rc != smtp_ready)
break;
}
}
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;
}
- 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:
- mutt_error (_("SASL authentication failed"));
- mutt_sleep (1);
sasl_dispose (&saslconn);
return SMTP_AUTH_FAIL;
}