On Tuesday, 06 September 2005 at 20:08, Steve Kennedy wrote: > On Tue, Sep 06, 2005 at 11:39:33AM -0700, Brendan Cully wrote: > > > Attached is Michael Elkins' SMTP relay patch patch.me.smtp.3 ported to > > 1.5.10. I've replaced smtp_host with smtp_url so you can override the > > port, and because I intend to add AUTH and TLS support to it > > shortly. It's such a tiny patch that I have a hard time considering it > > to be bloat, and if it isn't very full-featured, nothing stops you > > from using the standard process-based interface. > > Apologies in advance if this starts a flamefest. > > As it's so small, couldn't it be included with the standard build (or a > compile time option). Now there's a flame-bait ;) I think it would be nice. Here's an updated version that supports TLS for SMTP connections. It's against CVS HEAD btw, not 1.5.10.
diff -r 31066b9fe2ab Makefile.am --- a/Makefile.am Tue Sep 6 23:47:38 2005 +++ b/Makefile.am Tue Sep 6 12:53:23 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 31066b9fe2ab account.h --- a/account.h Tue Sep 6 23:47:38 2005 +++ b/account.h Tue Sep 6 12:53:23 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 31066b9fe2ab configure.in --- a/configure.in Tue Sep 6 23:47:38 2005 +++ b/configure.in Tue Sep 6 12:53:23 2005 @@ -512,6 +512,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 31066b9fe2ab globals.h --- a/globals.h Tue Sep 6 23:47:38 2005 +++ b/globals.h Tue Sep 6 12:53:23 2005 @@ -108,6 +108,9 @@ WHERE char *Shell; WHERE char *Signature; WHERE char *SimpleSearch; +#if USE_SMTP +WHERE char *SmtpUrl; +#endif /* USE_SMTP */ WHERE char *Spoolfile; WHERE char *SpamSep; #if defined(USE_SSL) || defined(USE_GNUTLS) diff -r 31066b9fe2ab init.h --- a/init.h Tue Sep 6 23:47:38 2005 +++ b/init.h Tue Sep 6 12:53:23 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 @@ -2486,6 +2489,19 @@ ** 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, NULL }, + /* + ** .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://[user[:pass]@]host[:port]/ + ** .pp + ** Setting this variable overrides the value of the ``$$sendmail'' + ** variable. + */ +#endif /* USE_SMTP */ { "sort", DT_SORT, R_INDEX|R_RESORT, UL &Sort, SORT_DATE }, /* ** .pp diff -r 31066b9fe2ab mutt_socket.h --- a/mutt_socket.h Tue Sep 6 23:47:38 2005 +++ b/mutt_socket.h Tue Sep 6 12:53:23 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 31066b9fe2ab protos.h --- a/protos.h Tue Sep 6 23:47:38 2005 +++ b/protos.h Tue Sep 6 12:53:23 2005 @@ -342,6 +342,9 @@ 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 (ADDRESS *, ADDRESS *, ADDRESS *, ADDRESS *, const char *); +#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 31066b9fe2ab send.c --- a/send.c Tue Sep 6 23:47:38 2005 +++ b/send.c Tue Sep 6 12:53:23 2005 @@ -990,6 +990,12 @@ 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); +#endif /* USE_SMTP */ + i = mutt_invoke_sendmail (msg->env->from, msg->env->to, msg->env->cc, msg->env->bcc, tempfile, (msg->content->encoding == ENC8BIT)); return (i); diff -r 31066b9fe2ab sendlib.c --- a/sendlib.c Tue Sep 6 23:47:38 2005 +++ b/sendlib.c Tue Sep 6 12:53:23 2005 @@ -2169,6 +2169,11 @@ 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); + else +#endif /* USE_SMTP */ ret = mutt_invoke_sendmail (env_from, to, NULL, NULL, tempfile, h->content->encoding == ENC8BIT); } diff -r 31066b9fe2ab url.c --- a/url.c Tue Sep 6 23:47:38 2005 +++ b/url.c Tue Sep 6 12:53:23 2005 @@ -37,10 +37,11 @@ { "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 }, + { NULL, U_UNKNOWN } }; diff -r 31066b9fe2ab url.h --- a/url.h Tue Sep 6 23:47:38 2005 +++ b/url.h Tue Sep 6 12:53:23 2005 @@ -8,6 +8,7 @@ U_POPS, U_IMAP, U_IMAPS, + U_SMTP, U_MAILTO, U_UNKNOWN } diff -r 31066b9fe2ab smtp.c --- /dev/null Tue Sep 6 23:47:38 2005 +++ b/smtp.c Tue Sep 6 12:53:23 2005 @@ -0,0 +1,309 @@ +/* mutt - text oriented MIME mail user agent + * Copyright (C) 2002 Michael R. Elkins <me@xxxxxxxx> + * Copyright (C) 2005 Brendan Cully <brendan@xxxxxxxxxx> + * + * 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_socket.h" +#if defined(USE_SSL) || defined(USE_GNUTLS) +# include "mutt_ssl.h" +#endif + +#include <netdb.h> + +#define smtp_success(x) ((x)/100 == 2) +#define smtp_continue 354 + +#define smtp_err_read -2 +#define smtp_err_write -3 + +#define SMTP_PORT 25 + +enum { + STARTTLS, + + CAPMAX +}; + +static int smtp_fill_account (ACCOUNT* account); +static int smtp_open (CONNECTION* conn); + +static unsigned char Capabilites[(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 (buf[3] != '-') + break; + + if (!ascii_strncasecmp ("STARTTLS", buf + 4, 8)) + mutt_bit_set (Capabilites, STARTTLS); + } while (1); + + 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, ADDRESS * a) +{ + char buf[1024]; + int r; + + while (a) + { + 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) +{ + FILE *fp = 0; + char buf[1024]; + int r; + + fp = fopen (msgfile, "r"); + if (!fp) + { + mutt_error ("SMTP session failed: unable to open %s", msgfile); + return -1; + } + + 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), fp)) + { + if (buf[0] == '.') + if (mutt_socket_write (conn, ".") == -1) + { + fclose (fp); + return smtp_err_write; + } + if (mutt_socket_write (conn, buf) == -1) + { + fclose (fp); + return smtp_err_write; + } + } + 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 (ADDRESS * from, ADDRESS * to, ADDRESS * cc, ADDRESS * bcc, + const char *msgfile) +{ + 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; + + do + { + /* send our greeting */ + if (( ret = smtp_open (conn))) + break; + + /* send the sender's address */ + snprintf (buf, sizeof (buf), "MAIL FROM: <%s>\r\n", from->mailbox); + 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_free (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; + + 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->flags = 0; + account->port = SmtpPort; + account->type = M_ACCT_TYPE_SMTP; + + urlstr = safe_strdup (SmtpUrl); + url_parse_ciss (&url, SmtpUrl); + if (url.scheme != U_SMTP || mutt_account_fromurl (account, &url) < 0) + { + FREE (&urlstr); + mutt_error (_("Invalid SMTP URL: %s"), SmtpUrl); + mutt_sleep (1); + return -1; + } + + FREE (&urlstr); + return 0; +} + +static int smtp_open (CONNECTION* conn) +{ + char buf[LONG_STRING]; + int ehlo = 0; + int rc; + + memset (Capabilites, 0, sizeof (Capabilites)); + + /* if TLS or AUTH are requested, use EHLO */ + if (conn->account.flags & M_ACCT_USER) + ehlo = 1; +#if defined(USE_SSL) || defined(USE_GNUTLS) + if (option (OPTSSLFORCETLS) || quadoption (OPT_SSLSTARTTLS) != M_NO) + ehlo = 1; +#endif + + if (mutt_socket_open (conn)) + return -1; + + /* get greeting string */ + if ((rc = smtp_get_resp (conn))) + return rc; + + snprintf (buf, sizeof (buf), "%s %s\r\n", ehlo ? "EHLO" : "HELO", Hostname); + /* 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; + if ((rc = smtp_get_resp (conn))) + return rc; + +#if defined(USE_SSL) || defined(USE_GNUTLS) + if (option (OPTSSLFORCETLS)) + rc = M_YES; + else if (mutt_bit_isset (Capabilites, 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 (idata->conn)) +#endif + { + mutt_error (_("Could not negotiate TLS connection")); + mutt_sleep (1); + return -1; + } + } +#endif + + return 0; +}
Attachment:
pgp0H7pSIHzhz.pgp
Description: PGP signature