X-Git-Url: https://git.llucax.com/software/mutt-debian.git/blobdiff_plain/14c29200cb58d3c4a0830265f2433849781858d0..6c6f0d10745f764586b8689fecfbea955ba501dc:/smtp.c?ds=inline diff --git a/smtp.c b/smtp.c index 654f4aa..9d096a3 100644 --- a/smtp.c +++ b/smtp.c @@ -1,6 +1,6 @@ /* mutt - text oriented MIME mail user agent * Copyright (C) 2002 Michael R. Elkins - * Copyright (C) 2005-7 Brendan Cully + * Copyright (C) 2005-9 Brendan Cully * * 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_code -4 #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 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) @@ -89,13 +105,14 @@ smtp_get_resp (CONNECTION * 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; - 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); @@ -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); + + if (smtp_code (buf, n, &n) < 0) + return smtp_err_code; + } while (buf[3] == '-'); if (smtp_success (n) || n == smtp_continue) @@ -122,6 +143,12 @@ smtp_rcpt_to (CONNECTION * conn, const ADDRESS * 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); @@ -144,7 +171,7 @@ smtp_data (CONNECTION * conn, const char *msgfile) FILE *fp = 0; progress_t progress; struct stat st; - int r; + int r, term = 0; size_t buflen; fp = fopen (msgfile, "r"); @@ -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) { - 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"); @@ -180,19 +208,24 @@ smtp_data (CONNECTION * conn, const char *msgfile) { 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) @@ -210,8 +243,21 @@ mutt_smtp_send (const ADDRESS* from, const ADDRESS* to, const ADDRESS* cc, { 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; @@ -229,8 +275,7 @@ mutt_smtp_send (const ADDRESS* from, const ADDRESS* to, const ADDRESS* cc, 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); @@ -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")); + else if (ret == smtp_err_code) + mutt_error (_("Invalid server response")); return ret; } @@ -325,6 +372,7 @@ static int smtp_fill_account (ACCOUNT* account) static int smtp_helo (CONNECTION* conn) { char buf[LONG_STRING]; + const char* fqdn; memset (Capabilities, 0, sizeof (Capabilities)); @@ -339,7 +387,10 @@ static int smtp_helo (CONNECTION* conn) #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. @@ -403,6 +454,12 @@ static int smtp_open (CONNECTION* conn) } #ifdef USE_SASL + if (!(conn->account.flags & M_ACCT_PASS) && option (OPTNOCURSES)) + { + mutt_error (_("Interactive SMTP authentication not supported")); + mutt_sleep (1); + return -1; + } return smtp_auth (conn); #else mutt_error (_("SMTP authentication requires SASL")); @@ -435,7 +492,14 @@ static int smtp_auth (CONNECTION* conn) 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; } @@ -447,7 +511,12 @@ static int smtp_auth (CONNECTION* conn) 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); @@ -484,7 +553,8 @@ static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist) 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) @@ -502,9 +572,10 @@ static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist) 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; @@ -539,17 +610,8 @@ static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist) 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; }