From 6805ebb1c3c9beba474ebbe11b6cb8b15baa9e59 Mon Sep 17 00:00:00 2001 From: Charlie Allom Date: Thu, 6 Oct 2005 22:09:08 +0000 Subject: [PATCH] put this patch in the repository to work around a bug in DP (5269) Bug: Submitted by: Reviewed by: Approved by: Obtained from: git-svn-id: https://svn.macports.org/repository/macports/trunk/dports@14455 d073be05-634f-4543-b044-5fe20cf6d1d6 --- mail/mutt-devel/Portfile | 5 +- .../files/patch-cvs20051003.bc.smtp | 882 ++++++++++++++++++ 2 files changed, 883 insertions(+), 4 deletions(-) create mode 100644 mail/mutt-devel/files/patch-cvs20051003.bc.smtp diff --git a/mail/mutt-devel/Portfile b/mail/mutt-devel/Portfile index acf6144fb091a..3e4de792d52a2 100644 --- a/mail/mutt-devel/Portfile +++ b/mail/mutt-devel/Portfile @@ -1,4 +1,4 @@ -# $Id: Portfile,v 1.22 2005/10/06 05:40:15 yeled Exp $ +# $Id: Portfile,v 1.23 2005/10/06 22:09:08 yeled Exp $ PortSystem 1.0 name mutt-devel @@ -165,10 +165,7 @@ variant smtp { # Include internal SMTP relay support configure.args-append --enable-smtp if {[variant_isset cvs]} { - patch_sites-append http://mutt.kublai.com/patches/ patchfiles-append patch-cvs20051003.bc.smtp - checksums-append patch-cvs20051003.bc.smtp md5 \ - 69c8b148572db40100dab494488b8551 } else { patch_sites-append http://mutt.kublai.com/patches/ patchfiles-append patch-1.5.11.bc.smtp.11 diff --git a/mail/mutt-devel/files/patch-cvs20051003.bc.smtp b/mail/mutt-devel/files/patch-cvs20051003.bc.smtp new file mode 100644 index 0000000000000..6fdb65503ff72 --- /dev/null +++ b/mail/mutt-devel/files/patch-cvs20051003.bc.smtp @@ -0,0 +1,882 @@ +diff -r ad8150eee6fd Makefile.am +--- a/Makefile.am Mon Oct 3 07:52:36 2005 ++++ b/Makefile.am Mon Oct 3 20:18:16 2005 +@@ -61,7 +61,7 @@ + EXTRA_mutt_SOURCES = account.c md5c.c mutt_sasl.c mutt_socket.c mutt_ssl.c \ + mutt_tunnel.c pop.c pop_auth.c pop_lib.c smime.c pgp.c pgpinvoke.c pgpkey.c \ + pgplib.c sha1.c pgpmicalg.c gnupgparse.c resize.c dotlock.c remailer.c \ +- browser.h mbyte.h remailer.h url.h \ ++ smtp.c browser.h mbyte.h remailer.h url.h \ + crypt-mod-pgp-classic.c crypt-mod-smime-classic.c \ + pgppacket.c mutt_idna.h hcache.c mutt_ssl_gnutls.c \ + crypt-gpgme.c crypt-mod-pgp-gpgme.c crypt-mod-smime-gpgme.c +diff -r ad8150eee6fd account.c +--- a/account.c Mon Oct 3 07:52:36 2005 ++++ b/account.c Mon Oct 3 20:18:16 2005 +@@ -123,6 +123,16 @@ + } + #endif + ++#ifdef USE_SMTP ++ if (account->type == M_ACCT_TYPE_SMTP) ++ { ++ if (account->flags & M_ACCT_SSL) ++ url->scheme = U_SMTPS; ++ else ++ url->scheme = U_SMTP; ++ } ++#endif ++ + url->host = account->host; + if (account->flags & M_ACCT_PORT) + url->port = account->port; +diff -r ad8150eee6fd account.h +--- a/account.h Mon Oct 3 07:52:36 2005 ++++ b/account.h Mon Oct 3 20:18:16 2005 +@@ -28,7 +28,8 @@ + { + M_ACCT_TYPE_NONE = 0, + M_ACCT_TYPE_IMAP, +- M_ACCT_TYPE_POP ++ M_ACCT_TYPE_POP, ++ M_ACCT_TYPE_SMTP + }; + + /* account flags */ +diff -r ad8150eee6fd configure.in +--- a/configure.in Mon Oct 3 07:52:36 2005 ++++ b/configure.in Mon Oct 3 20:18:16 2005 +@@ -516,6 +516,13 @@ + fi + ]) + AM_CONDITIONAL(BUILD_IMAP, test x$need_imap = xyes) ++ ++AC_ARG_ENABLE(smtp, AC_HELP_STRING([--enable-smtp], [include internal SMTP relay support]), ++ [if test $enableval = yes; then ++ AC_DEFINE(USE_SMTP, 1, [Include internal SMTP relay support]) ++ MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS smtp.o" ++ need_socket="yes" ++ fi]) + + dnl -- end socket dependencies -- + +diff -r ad8150eee6fd globals.h +--- a/globals.h Mon Oct 3 07:52:36 2005 ++++ b/globals.h Mon Oct 3 20:18:16 2005 +@@ -112,6 +112,10 @@ + WHERE char *Shell; + WHERE char *Signature; + WHERE char *SimpleSearch; ++#if USE_SMTP ++WHERE char *SmtpUrl INITVAL (NULL); ++WHERE char *SmtpAuthenticators INITVAL (NULL); ++#endif /* USE_SMTP */ + WHERE char *Spoolfile; + WHERE char *SpamSep; + #if defined(USE_SSL) || defined(USE_GNUTLS) +diff -r ad8150eee6fd init.h +--- a/init.h Mon Oct 3 07:52:36 2005 ++++ b/init.h Mon Oct 3 20:18:16 2005 +@@ -91,6 +91,9 @@ + # endif + # ifndef USE_POP + # define USE_POP ++# endif ++# ifndef USE_SMTP ++# define USE_SMTP + # endif + # ifndef USE_SSL + # define USE_SSL +@@ -2504,6 +2507,34 @@ + ** messages from the current folder. The default is to pause one second, so + ** a value of zero for this option suppresses the pause. + */ ++#if USE_SMTP ++ { "smtp_url", DT_STR, R_NONE, UL &SmtpUrl, UL 0 }, ++ /* ++ ** .pp ++ ** Defines the SMTP ``smart'' host where sent messages should relayed for ++ ** delivery. This should take the form of an SMTP URL, eg: ++ ** .pp ++ ** smtp[s]://[user[:pass]@]host[:port]/ ++ ** .pp ++ ** Setting this variable overrides the value of the ``$$sendmail'' ++ ** variable. ++ */ ++# ifdef USE_SASL ++ { "smtp_authenticators", DT_STR, R_NONE, UL &SmtpAuthenticators, UL 0 }, ++ /* ++ ** .pp ++ ** This is a colon-delimited list of authentication methods mutt may ++ ** attempt to use to log in to an SMTP server, in the order mutt should ++ ** try them. Authentication methods are any SASL mechanism, eg ++ ** 'digest-md5', 'gssapi' or 'cram-md5'. ++ ** This parameter is case-insensitive. If this parameter is unset ++ ** (the default) mutt will try all available methods, in order from ++ ** most-secure to least-secure. ++ ** .pp ++ ** Example: set smtp_authenticators="digest-md5:cram-md5" ++ */ ++# endif /* USE_SASL */ ++#endif /* USE_SMTP */ + { "sort", DT_SORT, R_INDEX|R_RESORT, UL &Sort, SORT_DATE }, + /* + ** .pp +diff -r ad8150eee6fd main.c +--- a/main.c Mon Oct 3 07:52:36 2005 ++++ b/main.c Mon Oct 3 20:18:16 2005 +@@ -257,6 +257,12 @@ + "-USE_IMAP " + #endif + ++#ifdef USE_SMTP ++ "+USE_SMTP " ++#else ++ "-USE_SMTP " ++#endif ++ + #ifdef USE_GSS + "+USE_GSS " + #else +diff -r ad8150eee6fd mutt_sasl.c +--- a/mutt_sasl.c Mon Oct 3 07:52:36 2005 ++++ b/mutt_sasl.c Mon Oct 3 20:18:16 2005 +@@ -182,42 +182,44 @@ + case M_ACCT_TYPE_POP: + service = "pop"; + break; ++ case M_ACCT_TYPE_SMTP: ++ service = "smtp"; ++ break; + default: +- dprint (1, (debugfile, "mutt_sasl_client_new: account type unset\n")); ++ mutt_error (_("Unknown SASL profile")); + return -1; + } + + size = sizeof (local); +- if (getsockname (conn->fd, (struct sockaddr *)&local, &size)){ +- dprint (1, (debugfile, "mutt_sasl_client_new: getsockname for local failed\n")); ++ if (getsockname (conn->fd, (struct sockaddr *)&local, &size)) { ++ mutt_error (_("SASL failed to get local IP address")); + return -1; + } + else +- if (iptostring((struct sockaddr *)&local, size, iplocalport, IP_PORT_BUFLEN) != SASL_OK){ +- dprint (1, (debugfile, "mutt_sasl_client_new: iptostring for local failed\n")); ++ if (iptostring((struct sockaddr *)&local, size, iplocalport, IP_PORT_BUFLEN) != SASL_OK) { ++ mutt_error (_("SASL failed to parse local IP address")); + return -1; + } + + size = sizeof (remote); + if (getpeername (conn->fd, (struct sockaddr *)&remote, &size)){ +- dprint (1, (debugfile, "mutt_sasl_client_new: getsockname for remote failed\n")); ++ mutt_error (_("SASL failed to get remote IP address")); + return -1; + } + else + if (iptostring((struct sockaddr *)&remote, size, ipremoteport, IP_PORT_BUFLEN) != SASL_OK){ +- dprint (1, (debugfile, "mutt_sasl_client_new: iptostring for remote failed\n")); +- return -1; +- } +- +- dprint(1,(debugfile, "local ip: %s, remote ip:%s\n", iplocalport, ipremoteport)); ++ mutt_error (_("SASL failed to parse remote IP address")); ++ return -1; ++ } ++ ++ dprint(2, (debugfile, "local ip: %s, remote ip:%s\n", iplocalport, ipremoteport)); + + rc = sasl_client_new (service, conn->account.host, iplocalport, ipremoteport, + mutt_sasl_get_callbacks (&conn->account), 0, saslconn); + + if (rc != SASL_OK) + { +- dprint (1, (debugfile, +- "mutt_sasl_client_new: Error allocating SASL connection\n")); ++ mutt_error (_("Error allocating SASL connection")); + return -1; + } + +@@ -232,8 +234,7 @@ + secprops.security_flags |= SASL_SEC_NOPLAINTEXT; + if (sasl_setprop (*saslconn, SASL_SEC_PROPS, &secprops) != SASL_OK) + { +- dprint (1, (debugfile, +- "mutt_sasl_client_new: Error setting security properties\n")); ++ mutt_error (_("Error setting SASL security properties")); + return -1; + } + +@@ -243,13 +244,13 @@ + dprint (2, (debugfile, "External SSF: %d\n", conn->ssf)); + if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &(conn->ssf)) != SASL_OK) + { +- dprint (1, (debugfile, "mutt_sasl_client_new: Error setting external properties\n")); ++ mutt_error (_("Error setting SASL external security strength")); + return -1; + } + dprint (2, (debugfile, "External authentication name: %s\n", conn->account.user)); + if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) != SASL_OK) +- { +- dprint (1, (debugfile, "mutt_sasl_client_new: Error setting external properties\n")); ++ { ++ mutt_error (_("Error setting SASL external user name")); + return -1; + } + } +diff -r ad8150eee6fd mutt_socket.h +--- a/mutt_socket.h Mon Oct 3 07:52:36 2005 ++++ b/mutt_socket.h Mon Oct 3 20:18:16 2005 +@@ -56,7 +56,7 @@ + int mutt_socket_readchar (CONNECTION *conn, char *c); + #define mutt_socket_readln(A,B,C) mutt_socket_readln_d(A,B,C,M_SOCK_LOG_CMD) + int mutt_socket_readln_d (char *buf, size_t buflen, CONNECTION *conn, int dbg); +-#define mutt_socket_write(A,B) mutt_socket_write_d(A,B,M_SOCK_LOG_CMD); ++#define mutt_socket_write(A,B) mutt_socket_write_d(A,B,M_SOCK_LOG_CMD) + int mutt_socket_write_d (CONNECTION *conn, const char *buf, int dbg); + + /* stupid hack for imap_logout_all */ +diff -r ad8150eee6fd protos.h +--- a/protos.h Mon Oct 3 07:52:36 2005 ++++ b/protos.h Mon Oct 3 20:18:16 2005 +@@ -342,6 +342,10 @@ + int _mutt_save_message (HEADER *, CONTEXT *, int, int, int); + int mutt_save_message (HEADER *, int, int, int, int *); + int mutt_search_command (int, int); ++#ifdef USE_SMTP ++int mutt_smtp_send (const ADDRESS *, const ADDRESS *, const ADDRESS *, ++ const ADDRESS *, const char *, int); ++#endif + int mutt_strwidth (const char *); + int mutt_compose_menu (HEADER *, char *, size_t, HEADER *); + int mutt_thread_set_flag (HEADER *, int, int, int); +diff -r ad8150eee6fd send.c +--- a/send.c Mon Oct 3 07:52:36 2005 ++++ b/send.c Mon Oct 3 20:18:16 2005 +@@ -996,8 +996,16 @@ + return mix_send_message (msg->chain, tempfile); + #endif + ++#if USE_SMTP ++ if (SmtpUrl) ++ return mutt_smtp_send (msg->env->from, msg->env->to, msg->env->cc, ++ msg->env->bcc, tempfile, ++ (msg->content->encoding == ENC8BIT)); ++#endif /* USE_SMTP */ ++ + i = mutt_invoke_sendmail (msg->env->from, msg->env->to, msg->env->cc, +- msg->env->bcc, tempfile, (msg->content->encoding == ENC8BIT)); ++ msg->env->bcc, tempfile, ++ (msg->content->encoding == ENC8BIT)); + return (i); + } + +diff -r ad8150eee6fd sendlib.c +--- a/sendlib.c Mon Oct 3 07:52:36 2005 ++++ b/sendlib.c Mon Oct 3 20:18:16 2005 +@@ -2178,6 +2178,12 @@ + mutt_copy_bytes (fp, f, h->content->length); + fclose (f); + ++#if USE_SMTP ++ if (SmtpUrl) ++ ret = mutt_smtp_send (env_from, to, NULL, NULL, tempfile, ++ h->content->encoding == ENC8BIT); ++ else ++#endif /* USE_SMTP */ + ret = mutt_invoke_sendmail (env_from, to, NULL, NULL, tempfile, + h->content->encoding == ENC8BIT); + } +diff -r ad8150eee6fd url.c +--- a/url.c Mon Oct 3 07:52:36 2005 ++++ b/url.c Mon Oct 3 20:18:16 2005 +@@ -37,10 +37,12 @@ + { "file", U_FILE }, + { "imap", U_IMAP }, + { "imaps", U_IMAPS }, +- { "pop", U_POP }, +- { "pops", U_POPS }, ++ { "pop", U_POP }, ++ { "pops", U_POPS }, + { "mailto", U_MAILTO }, +- { NULL, U_UNKNOWN} ++ { "smtp", U_SMTP }, ++ { "smtps", U_SMTPS }, ++ { NULL, U_UNKNOWN } + }; + + +diff -r ad8150eee6fd url.h +--- a/url.h Mon Oct 3 07:52:36 2005 ++++ b/url.h Mon Oct 3 20:18:16 2005 +@@ -8,6 +8,8 @@ + U_POPS, + U_IMAP, + U_IMAPS, ++ U_SMTP, ++ U_SMTPS, + U_MAILTO, + U_UNKNOWN + } +diff -r ad8150eee6fd smtp.c +--- /dev/null Mon Oct 3 07:52:36 2005 ++++ b/smtp.c Mon Oct 3 20:18:16 2005 +@@ -0,0 +1,556 @@ ++/* mutt - text oriented MIME mail user agent ++ * Copyright (C) 2002 Michael R. Elkins ++ * Copyright (C) 2005 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 ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ++ */ ++ ++/* This file contains code for direct SMTP delivery of email messages. */ ++ ++#if HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "mutt.h" ++#include "mutt_curses.h" ++#include "mutt_socket.h" ++#if defined(USE_SSL) || defined(USE_GNUTLS) ++# include "mutt_ssl.h" ++#endif ++#ifdef USE_SASL ++#include "mutt_sasl.h" ++ ++#include ++#include ++#endif ++ ++#include ++#include ++#include ++ ++#define smtp_success(x) ((x)/100 == 2) ++#define smtp_ready 334 ++#define smtp_continue 354 ++ ++#define smtp_err_read -2 ++#define smtp_err_write -3 ++ ++#define SMTP_PORT 25 ++#define SMTPS_PORT 465 ++ ++#define SMTP_AUTH_SUCCESS 0 ++#define SMTP_AUTH_UNAVAIL 1 ++#define SMTP_AUTH_FAIL -1 ++ ++enum { ++ STARTTLS, ++ AUTH, ++ DSN, ++ EIGHTBITMIME, ++ ++ CAPMAX ++}; ++ ++#ifdef USE_SASL ++static int smtp_auth (CONNECTION* conn); ++static int smtp_auth_sasl (CONNECTION* conn, const char* mechanisms); ++#endif ++ ++static int smtp_fill_account (ACCOUNT* account); ++static int smtp_open (CONNECTION* conn); ++ ++static int Esmtp = 0; ++static char* AuthMechs = NULL; ++static unsigned char Capabilities[(CAPMAX + 7)/ 8]; ++ ++/* Reads a command response from the SMTP server. ++ * Returns: ++ * 0 on success (2xx code) or continue (354 code) ++ * -1 write error, or any other response code ++ */ ++static int ++smtp_get_resp (CONNECTION * conn) ++{ ++ int n; ++ char buf[1024]; ++ ++ do { ++ n = mutt_socket_readln (buf, sizeof (buf), conn); ++ if (n == -1) ++ 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)) ++ { ++ mutt_bit_set (Capabilities, AUTH); ++ FREE (&AuthMechs); ++ AuthMechs = safe_strdup (buf + 9); ++ } ++ else if (!ascii_strncasecmp ("DSN", buf + 4, 3)) ++ mutt_bit_set (Capabilities, DSN); ++ else if (!ascii_strncasecmp ("STARTTLS", buf + 4, 8)) ++ mutt_bit_set (Capabilities, STARTTLS); ++ } while (buf[3] == '-'); ++ ++ if (smtp_success (n) || n == smtp_continue) ++ return 0; ++ ++ mutt_error (_("SMTP session failed: %s"), buf); ++ return -1; ++} ++ ++static int ++smtp_rcpt_to (CONNECTION * conn, const ADDRESS * a) ++{ ++ char buf[1024]; ++ int r; ++ ++ while (a) ++ { ++ if (mutt_bit_isset (Capabilities, DSN) && DsnNotify) ++ snprintf (buf, sizeof (buf), "RCPT TO:<%s> NOTIFY=%s\r\n", ++ a->mailbox, DsnNotify); ++ else ++ snprintf (buf, sizeof (buf), "RCPT TO:<%s>\r\n", a->mailbox); ++ if (mutt_socket_write (conn, buf) == -1) ++ return smtp_err_write; ++ if ((r = smtp_get_resp (conn))) ++ return r; ++ a = a->next; ++ } ++ ++ return 0; ++} ++ ++static int ++smtp_data (CONNECTION * conn, const char *msgfile) ++{ ++ char buf[1024]; ++ FILE *fp = 0; ++ progress_t progress; ++ struct stat st; ++ int r; ++ size_t buflen; ++ ++ fp = fopen (msgfile, "r"); ++ if (!fp) ++ { ++ mutt_error ("SMTP session failed: unable to open %s", msgfile); ++ return -1; ++ } ++ stat (msgfile, &st); ++ progress.msg = _("Sending message..."); ++ progress.size = st.st_size; ++ mutt_progress_bar (&progress, 0); ++ ++ snprintf (buf, sizeof (buf), "DATA\r\n"); ++ if (mutt_socket_write (conn, buf) == -1) ++ { ++ fclose (fp); ++ return smtp_err_write; ++ } ++ if ((r = smtp_get_resp (conn))) ++ { ++ fclose (fp); ++ return r; ++ } ++ ++ while (fgets (buf, sizeof (buf) - 1, fp)) ++ { ++ buflen = mutt_strlen (buf); ++ if (buflen && buf[buflen-1] == '\n' ++ && (buflen == 1 || buf[buflen - 2] != '\r')) ++ snprintf (buf + buflen - 1, sizeof (buf) - buflen + 1, "\r\n"); ++ if (buf[0] == '.') ++ { ++ if (mutt_socket_write_d (conn, ".", 3) == -1) ++ { ++ fclose (fp); ++ return smtp_err_write; ++ } ++ } ++ if (mutt_socket_write_d (conn, buf, 3) == -1) ++ { ++ fclose (fp); ++ return smtp_err_write; ++ } ++ ++ mutt_progress_bar (&progress, ftell (fp)); ++ } ++ fclose (fp); ++ ++ /* terminate the message body */ ++ if (mutt_socket_write (conn, ".\r\n") == -1) ++ return smtp_err_write; ++ ++ if ((r = smtp_get_resp (conn))) ++ return r; ++ ++ return 0; ++} ++ ++int ++mutt_smtp_send (const ADDRESS* from, const ADDRESS* to, const ADDRESS* cc, ++ const ADDRESS* bcc, const char *msgfile, int eightbit) ++{ ++ CONNECTION *conn; ++ ACCOUNT account; ++ int ret = -1; ++ char buf[1024]; ++ ++ if (smtp_fill_account (&account) < 0) ++ return ret; ++ ++ if (!(conn = mutt_conn_find (NULL, &account))) ++ return -1; ++ ++ Esmtp = eightbit; ++ ++ do ++ { ++ /* send our greeting */ ++ if (( ret = smtp_open (conn))) ++ break; ++ FREE (&AuthMechs); ++ ++ /* send the sender's address */ ++ ret = snprintf (buf, sizeof (buf), "MAIL FROM:<%s>", ++ EnvFrom ? EnvFrom->mailbox : from->mailbox); ++ if (eightbit && mutt_bit_isset (Capabilities, EIGHTBITMIME)) ++ { ++ safe_strncat (buf, sizeof (buf), " BODY=8BITMIME", 15); ++ ret += 14; ++ } ++ if (DsnReturn && mutt_bit_isset (Capabilities, DSN)) ++ ret += snprintf (buf + ret, sizeof (buf) - ret, " RET=%s", DsnReturn); ++ safe_strncat (buf, sizeof (buf), "\r\n", 3); ++ if (mutt_socket_write (conn, buf) == -1) ++ { ++ ret = smtp_err_write; ++ break; ++ } ++ if ((ret = smtp_get_resp (conn))) ++ break; ++ ++ /* send the recipient list */ ++ if ((ret = smtp_rcpt_to (conn, to)) || (ret = smtp_rcpt_to (conn, cc)) ++ || (ret = smtp_rcpt_to (conn, bcc))) ++ break; ++ ++ /* send the message data */ ++ if ((ret = smtp_data (conn, msgfile))) ++ break; ++ ++ mutt_socket_write (conn, "QUIT\r\n"); ++ ++ ret = 0; ++ } ++ while (0); ++ ++ if (conn) ++ mutt_socket_close (conn); ++ ++ if (ret == smtp_err_read) ++ mutt_error (_("SMTP session failed: read error")); ++ else if (ret == smtp_err_write) ++ mutt_error (_("SMTP session failed: write error")); ++ ++ return ret; ++} ++ ++static int smtp_fill_account (ACCOUNT* account) ++{ ++ static unsigned short SmtpPort = 0; ++ ++ struct servent* service; ++ ciss_url_t url; ++ char* urlstr; ++ ++ account->flags = 0; ++ account->port = 0; ++ account->type = M_ACCT_TYPE_SMTP; ++ ++ urlstr = safe_strdup (SmtpUrl); ++ url_parse_ciss (&url, urlstr); ++ if ((url.scheme != U_SMTP && url.scheme != U_SMTPS) ++ || mutt_account_fromurl (account, &url) < 0) ++ { ++ FREE (&urlstr); ++ mutt_error (_("Invalid SMTP URL: %s"), SmtpUrl); ++ mutt_sleep (1); ++ return -1; ++ } ++ FREE (&urlstr); ++ ++ if (url.scheme == U_SMTPS) ++ account->flags |= M_ACCT_SSL; ++ ++ if (!account->port) ++ { ++ if (account->flags & M_ACCT_SSL) ++ account->port = SMTPS_PORT; ++ else ++ { ++ if (!SmtpPort) ++ { ++ service = getservbyname ("smtp", "tcp"); ++ if (service) ++ SmtpPort = ntohs (service->s_port); ++ else ++ SmtpPort = SMTP_PORT; ++ dprint (3, (debugfile, "Using default SMTP port %d\n", SmtpPort)); ++ } ++ account->port = SmtpPort; ++ } ++ } ++ ++ return 0; ++} ++ ++static int smtp_helo (CONNECTION* conn) ++{ ++ char buf[LONG_STRING]; ++ ++ memset (Capabilities, 0, sizeof (Capabilities)); ++ ++ if (!Esmtp) ++ { ++ /* if TLS or AUTH are requested, use EHLO */ ++ if (conn->account.flags & M_ACCT_USER) ++ Esmtp = 1; ++#if defined(USE_SSL) || defined(USE_GNUTLS) ++ if (option (OPTSSLFORCETLS) || quadoption (OPT_SSLSTARTTLS) != M_NO) ++ Esmtp = 1; ++#endif ++ } ++ ++ 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. ++ */ ++ if (mutt_socket_write (conn, buf) == -1) ++ return smtp_err_write; ++ return smtp_get_resp (conn); ++} ++ ++static int smtp_open (CONNECTION* conn) ++{ ++ int rc; ++ ++ if (mutt_socket_open (conn)) ++ return -1; ++ ++ /* get greeting string */ ++ if ((rc = smtp_get_resp (conn))) ++ return rc; ++ ++ if ((rc = smtp_helo (conn))) ++ return rc; ++ ++#if defined(USE_SSL) || defined(USE_GNUTLS) ++ if (conn->ssf) ++ rc = M_NO; ++ else if (option (OPTSSLFORCETLS)) ++ rc = M_YES; ++ else if (mutt_bit_isset (Capabilities, STARTTLS) && ++ (rc = query_quadoption (OPT_SSLSTARTTLS, ++ _("Secure connection with TLS?"))) == -1) ++ return rc; ++ ++ if (rc == M_YES) ++ { ++ if (mutt_socket_write (conn, "STARTTLS\r\n") < 0) ++ return smtp_err_write; ++ if ((rc = smtp_get_resp (conn))) ++ return rc; ++ ++#ifdef USE_SSL ++ if (mutt_ssl_starttls (conn)) ++#elif USE_GNUTLS ++ if (mutt_gnutls_starttls (conn)) ++#endif ++ { ++ mutt_error (_("Could not negotiate TLS connection")); ++ mutt_sleep (1); ++ return -1; ++ } ++ ++ /* re-EHLO to get authentication mechanisms */ ++ if ((rc = smtp_helo (conn))) ++ return rc; ++ } ++#endif ++ ++ if (conn->account.flags & M_ACCT_USER) ++ { ++ if (!mutt_bit_isset (Capabilities, AUTH)) ++ { ++ mutt_error (_("SMTP server does not support authentication")); ++ mutt_sleep (1); ++ return -1; ++ } ++ ++#ifdef USE_SASL ++ return smtp_auth (conn); ++#else ++ mutt_error (_("SMTP authentication requires SASL")); ++ mutt_sleep (1); ++ return -1; ++#endif /* USE_SASL */ ++ } ++ ++ return 0; ++} ++ ++#ifdef USE_SASL ++static int smtp_auth (CONNECTION* conn) ++{ ++ int r = SMTP_AUTH_UNAVAIL; ++ ++ if (SmtpAuthenticators && *SmtpAuthenticators) ++ { ++ char* methods = safe_strdup (SmtpAuthenticators); ++ char* method; ++ char* delim; ++ ++ for (method = methods; method; method = delim) ++ { ++ delim = strchr (method, ':'); ++ if (delim) ++ *delim++ = '\0'; ++ if (! method[0]) ++ continue; ++ ++ dprint (2, (debugfile, "smtp_authenticate: Trying method %s\n", method)); ++ ++ if ((r = smtp_auth_sasl (conn, method)) != SMTP_AUTH_UNAVAIL) ++ break; ++ } ++ ++ FREE (&methods); ++ } ++ else ++ r = smtp_auth_sasl (conn, AuthMechs); ++ ++ if (r == SMTP_AUTH_UNAVAIL) ++ { ++ mutt_error (_("No authenticators available")); ++ mutt_sleep (1); ++ } ++ ++ return r == SMTP_AUTH_SUCCESS ? 0 : -1; ++} ++ ++static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist) ++{ ++ sasl_conn_t* saslconn; ++ sasl_interact_t* interaction = NULL; ++ const char* mech; ++ const char* data = NULL; ++ unsigned int len; ++ char buf[HUGE_STRING]; ++ int rc, saslrc; ++ ++ if (mutt_sasl_client_new (conn, &saslconn) < 0) ++ return SMTP_AUTH_FAIL; ++ ++ do ++ { ++ rc = sasl_client_start (saslconn, mechlist, &interaction, &data, &len, &mech); ++ if (rc == SASL_INTERACT) ++ mutt_sasl_interact (interaction); ++ } ++ while (rc == SASL_INTERACT); ++ ++ if (rc != SASL_OK && rc != SASL_CONTINUE) ++ { ++ dprint (2, (debugfile, "smtp_auth_sasl: %s unavailable\n", mech)); ++ sasl_dispose (&saslconn); ++ return SMTP_AUTH_UNAVAIL; ++ } ++ ++ mutt_message (_("Authenticating (%s)..."), mech); ++ ++ snprintf (buf, sizeof (buf), "AUTH %s", mech); ++ if (len) ++ { ++ strncat (buf, " ", sizeof (buf)); ++ if (sasl_encode64 (data, len, buf + mutt_strlen (buf), ++ sizeof (buf) - mutt_strlen (buf), &len) != SASL_OK) ++ { ++ dprint (1, (debugfile, "smtp_auth_sasl: error base64-encoding client response.\n")); ++ goto fail; ++ } ++ } ++ strncat (buf, "\r\n", sizeof (buf)); ++ ++ do { ++ if (mutt_socket_write (conn, buf) < 0) ++ goto fail; ++ if (mutt_socket_readln (buf, sizeof (buf), conn) < 0) ++ goto fail; ++ rc = atoi(buf); ++ ++ if (rc != smtp_ready) ++ break; ++ ++ if (sasl_decode64 (buf+4, strlen (buf+4), buf, sizeof (buf), &len) != SASL_OK) ++ { ++ dprint (1, (debugfile, "smtp_auth_sasl: error base64-decoding server response.\n")); ++ goto fail; ++ } ++ ++ do ++ { ++ saslrc = sasl_client_step (saslconn, buf, len, &interaction, &data, &len); ++ if (saslrc == SASL_INTERACT) ++ mutt_sasl_interact (interaction); ++ } ++ while (saslrc == SASL_INTERACT); ++ ++ if (len) ++ { ++ if (sasl_encode64 (data, len, buf, sizeof (buf), &len) != SASL_OK) ++ { ++ dprint (1, (debugfile, "smtp_auth_sasl: error base64-encoding client response.\n")); ++ goto fail; ++ } ++ } ++ strfcpy (buf + len, "\r\n", sizeof (buf) - len); ++ } while (rc == smtp_ready); ++ ++ 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; ++} ++#endif /* USE_SASL */