<<< Date Index >>>     <<< Thread Index >>>

[PATCH] ME's SMTP relay patch ported to CVS



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.
diff -r 31066b9fe2ab Makefile.am
--- a/Makefile.am       Tue Sep  6 23:47:38 2005
+++ b/Makefile.am       Tue Sep  6 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 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 11:35:18 2005
@@ -0,0 +1,239 @@
+/* mutt - text oriented MIME mail user agent
+ * Copyright (C) 2002 Michael R. Elkins <me@xxxxxxxx>
+ * 
+ *     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"
+
+#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
+
+static int smtp_fill_account (ACCOUNT *account);
+
+/* 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];
+
+    n = mutt_socket_readln (buf, sizeof (buf), conn);
+    if (n == -1)
+       return smtp_err_read;
+    n = atoi (buf);
+    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
+    {
+       if (mutt_socket_open (conn))
+           break;
+
+       /* get greeting string */
+       if ((ret = smtp_get_resp (conn)))
+           break;
+
+       /* send our greeting */
+       snprintf (buf, sizeof (buf), "HELO %s\r\n", 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)
+       {
+           ret = smtp_err_write;
+           break;
+       }
+       if ((ret = smtp_get_resp (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;
+}

Attachment: pgpKQzTw0kxY8.pgp
Description: PGP signature