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

[PATCH] add sendbox feature



This is a repost of my sendbox patch against mercurial tip.  This
patch has been previously posted twice.  The first time was over
two years ago.

2006-08-09 http://marc.info/?l=mutt-dev&m=115513617113648&w=2
2007-12-04 http://marc.info/?l=mutt-dev&m=119681273920794&w=2

This relatively simple patch has seen only trivial changes since
the first posting, and has been in constant use by two people.
Here is the description and rationale, also mostly unchanged in
two years:

The purpose of this patch is to make it possible to send mail
using Courier IMAP's Outbox feature.  In mutt, I avoided calling
this "outbox" because that term is already used in the mutt
sources.  Besides, I think sendbox is more explicit.

The Outbox feature works like this: To send mail, it's possible
to nominate a mailbox that will send mails which are saved to it.
This mailbox acts like any other mailbox otherwise, including
storing the mails that are saved there.

This is desirable for numerous reasons, but here are the most
significant:

- on a slow connection, this allows the mail to be fcc'd and sent
  with the same transmission, rather than hitting the wire twice.

- sending mail from one's mailhost is nice because the mail
  originates from a good server, so your From address is valid
  and unquestioned

- single channel of mail transferral, easier network
  configuration and dealing with firewalls

- single point of authentication instead of two

- much easier to switch outgoing servers this way, instead of
  needing to reconfigure sendmail to use different outgoing
  servers

So this patch adds two settings: sendbox and use_sendbox.
Sendbox specifies a mailbox to which sent messages should be
saved, and use_sendbox instructs mutt to use sendbox instead of
sendmail.  For example:

    set sendbox=imaps://my.server.com/INBOX.Outbox
    set use_sendbox=yes

Thanks,
Aron

# HG changeset patch
# User Aron Griffis <agriffis@xxxxxxxxx>
# Date 1218630181 14400
# Branch HEAD
# Node ID 8b36e8473fd79a30b83e6753b251b2502b6faa31
# Parent  5a8839a5fa2bccdd34911bfc812fefd44a542e25
add sendbox feature

This patch lets mutt use Courier IMAP's Outbox feature.  It adds
two settings: sendbox and use_sendbox.  Sendbox specifies
a mailbox to which sent messages should be saved, and use_sendbox
instructs mutt to use sendbox instead of sendmail.

Signed-off-by: Aron Griffis <agriffis@xxxxxxxxx>

diff -r 5a8839a5fa2b -r 8b36e8473fd7 compose.c
--- a/compose.c Wed Aug 13 08:23:01 2008 -0400
+++ b/compose.c Wed Aug 13 08:23:01 2008 -0400
@@ -1207,7 +1207,7 @@
          if (msg->content->next)
            msg->content = mutt_make_multipart (msg->content);
 
-         if (mutt_write_fcc (fname, msg, NULL, 1, NULL) < 0)
+         if (mutt_write_fcc (fname, msg, NULL, 1, NULL, 0) < 0)
            msg->content = mutt_remove_multipart (msg->content);
          else
            mutt_message _("Message written.");
diff -r 5a8839a5fa2b -r 8b36e8473fd7 copy.c
--- a/copy.c    Wed Aug 13 08:23:01 2008 -0400
+++ b/copy.c    Wed Aug 13 08:23:01 2008 -0400
@@ -65,7 +65,8 @@
   buf[0] = '\n';
   buf[1] = 0;
 
-  if ((flags & (CH_REORDER | CH_WEED | CH_MIME | CH_DECODE | CH_PREFIX | 
CH_WEED_DELIVERED)) == 0)
+  if ((flags & (CH_REORDER | CH_WEED | CH_MIME | CH_DECODE | CH_PREFIX | 
+               CH_WEED_DELIVERED | CH_WEED_RESENT)) == 0)
   {
     /* Without these flags to complicate things
      * we can do a more efficient line to line copying
@@ -193,6 +194,10 @@
        continue;
       if ((flags & CH_WEED_DELIVERED) &&
          ascii_strncasecmp ("Delivered-To:", buf, 13) == 0)
+       continue;
+      if ((flags & CH_WEED_RESENT) &&
+         (ascii_strncasecmp ("Resent-To:", buf, 10) == 0 ||
+          ascii_strncasecmp ("Resent-From:", buf, 12) == 0))
        continue;
       if ((flags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
          (ascii_strncasecmp ("Status:", buf, 7) == 0 ||
diff -r 5a8839a5fa2b -r 8b36e8473fd7 copy.h
--- a/copy.h    Wed Aug 13 08:23:01 2008 -0400
+++ b/copy.h    Wed Aug 13 08:23:01 2008 -0400
@@ -52,6 +52,7 @@
 #define CH_NOQFROM        (1<<15) /* ignore ">From " line */
 #define CH_UPDATE_IRT     (1<<16) /* update In-Reply-To: */
 #define CH_UPDATE_REFS    (1<<17) /* update References: */
+#define CH_WEED_RESENT    (1<<18) /* weed Resent-To: header */
 
 
 int mutt_copy_hdr (FILE *, FILE *, LOFF_T, LOFF_T, int, const char *);
diff -r 5a8839a5fa2b -r 8b36e8473fd7 globals.h
--- a/globals.h Wed Aug 13 08:23:01 2008 -0400
+++ b/globals.h Wed Aug 13 08:23:01 2008 -0400
@@ -113,6 +113,7 @@
 WHERE char *QueryCmd;
 WHERE char *QueryFormat;
 WHERE char *Realname;
+WHERE char *Sendbox;
 WHERE char *SendCharset;
 WHERE char *Sendmail;
 WHERE char *Shell;
diff -r 5a8839a5fa2b -r 8b36e8473fd7 init.h
--- a/init.h    Wed Aug 13 08:23:01 2008 -0400
+++ b/init.h    Wed Aug 13 08:23:01 2008 -0400
@@ -2545,12 +2545,24 @@
   ** In case the text cannot be converted into one of these exactly,
   ** mutt uses ``$$charset'' as a fallback.
   */
+  { "sendbox",         DT_PATH,  R_NONE, UL &Sendbox, 0 },
+  /*
+  ** .pp
+  ** Specifies a special mailbox that will
+  ** \fBsend\fP mail when written, honored when \fIuse_sendbox\fP is \fIset\fP.
+  ** To make use of this, you probably want a Courier IMAP server configured 
for
+  ** sending, see 
+  ** http://www.inter7.com/courierimap/INSTALL.html#imapsend
+  */
   { "sendmail",                DT_PATH, R_NONE, UL &Sendmail, UL SENDMAIL " 
-oem -oi" },
   /*
   ** .pp
   ** Specifies the program and arguments used to deliver mail sent by Mutt.
   ** Mutt expects that the specified program interprets additional
   ** arguments as recipient addresses.
+  ** .pp
+  ** This variable is ignored in favor of \fIsendbox\fP if \fIuse_sendbox\fP
+  ** is \fIset\fP.
   */
   { "sendmail_wait",   DT_NUM,  R_NONE, UL &SendmailWait, 0 },
   /*
@@ -3033,6 +3045,12 @@
   ** Normally, the default should work.
   */
 #endif /* HAVE_GETADDRINFO */
+  { "use_sendbox",     DT_BOOL,  R_NONE, OPTUSESENDBOX, 0 },
+  /*
+  ** .pp
+  ** When \fIset\fP, mutt sends mail using \fIsendbox\fP instead
+  ** of \fIsendmail\fP.
+  */
   { "user_agent",      DT_BOOL, R_NONE, OPTXMAILER, 1},
   /*
   ** .pp
diff -r 5a8839a5fa2b -r 8b36e8473fd7 mutt.h
--- a/mutt.h    Wed Aug 13 08:23:01 2008 -0400
+++ b/mutt.h    Wed Aug 13 08:23:01 2008 -0400
@@ -436,6 +436,7 @@
 #ifdef HAVE_GETADDRINFO
   OPTUSEIPV6,
 #endif
+  OPTUSESENDBOX,
   OPTWAITKEY,
   OPTWEED,
   OPTWRAP,
diff -r 5a8839a5fa2b -r 8b36e8473fd7 protos.h
--- a/protos.h  Wed Aug 13 08:23:01 2008 -0400
+++ b/protos.h  Wed Aug 13 08:23:01 2008 -0400
@@ -366,7 +366,7 @@
 void mutt_update_num_postponed (void);
 int mutt_wait_filter (pid_t);
 int mutt_which_case (const char *);
-int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int, 
char *);
+int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int, 
char *, int);
 int mutt_write_mime_body (BODY *, FILE *);
 int mutt_write_mime_header (BODY *, FILE *);
 int mutt_write_one_header (FILE *fp, const char *tag, const char *value, const 
char *pfx, int wraplen);
diff -r 5a8839a5fa2b -r 8b36e8473fd7 send.c
--- a/send.c    Wed Aug 13 08:23:01 2008 -0400
+++ b/send.c    Wed Aug 13 08:23:01 2008 -0400
@@ -973,6 +973,10 @@
   short old_write_bcc;
 #endif
   
+  /* some imap servers can send mail by saving to a special folder */
+  if (option (OPTUSESENDBOX))
+    return mutt_write_fcc (NONULL (Sendbox), msg, NULL, 0, NULL, 1);
+
   /* Write out the message in MIME form. */
   mutt_mktemp (tempfile);
   if ((tempfp = safe_fopen (tempfile, "w")) == NULL)
@@ -1516,7 +1520,7 @@
       mutt_prepare_envelope (msg->env, 0);
       mutt_env_to_idna (msg->env, NULL, NULL); /* Handle bad IDNAs the next 
time. */
 
-      if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && 
(flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0)
+      if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && 
(flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc, 0) < 0)
       {
        msg->content = mutt_remove_multipart (msg->content);
        decode_descriptions (msg->content);
@@ -1696,7 +1700,7 @@
        * message was first postponed.
        */
       msg->received = time (NULL);
-      if (mutt_write_fcc (fcc, msg, NULL, 0, NULL) == -1)
+      if (mutt_write_fcc (fcc, msg, NULL, 0, NULL, 0) == -1)
       {
        /*
         * Error writing FCC, we should abort sending.
diff -r 5a8839a5fa2b -r 8b36e8473fd7 sendlib.c
--- a/sendlib.c Wed Aug 13 08:23:01 2008 -0400
+++ b/sendlib.c Wed Aug 13 08:23:01 2008 -0400
@@ -2374,7 +2374,9 @@
   int i, ret = 0;
   FILE *f;
   char date[SHORT_STRING], tempfile[_POSIX_PATH_MAX];
-  MESSAGE *msg = NULL;
+  MESSAGE *msg = NULL, *smsg = NULL;
+  CONTEXT sctx;
+  int ch_flags;
 
   if (!h)
   {
@@ -2391,25 +2393,67 @@
 
   if (!fp) fp = msg->fp;
 
-  mutt_mktemp (tempfile);
-  if ((f = safe_fopen (tempfile, "w")) != NULL)
-  {
-    int ch_flags = CH_XMIT | CH_NONEWLINE | CH_NOQFROM;
-    
-    if (!option (OPTBOUNCEDELIVERED))
-      ch_flags |= CH_WEED_DELIVERED;
-    
-    fseeko (fp, h->offset, 0);
-    fprintf (f, "Resent-From: %s", resent_from);
-    fprintf (f, "\nResent-%s", mutt_make_date (date, sizeof(date)));
-    fprintf (f, "Resent-Message-ID: %s\n", mutt_gen_msgid());
-    fputs ("Resent-To: ", f);
-    mutt_write_address_list (to, f, 11, 0);
-    mutt_copy_header (fp, h, f, ch_flags, NULL);
-    fputc ('\n', f);
-    mutt_copy_bytes (fp, f, h->content->length);
+  ch_flags = CH_XMIT | CH_NONEWLINE | CH_NOQFROM;
+  if (!option (OPTBOUNCEDELIVERED))
+    ch_flags |= CH_WEED_DELIVERED;
+
+  if (option (OPTUSESENDBOX)) {
+    /* some imap servers can send mail by saving to a special folder */
+    if (mx_open_mailbox (NONULL (Sendbox), M_APPEND | M_QUIET, &sctx) == NULL)
+    {
+      dprint (1, (debugfile, "_mutt_bounce_message(): unable to open mailbox 
%s"
+                 "in append-mode, aborting.\n", NONULL (Sendbox)));
+      ret = -1;
+      goto close_msg;
+    }
+    if ((smsg = mx_open_new_message (&sctx, h, M_ADD_FROM)) == NULL)
+    {
+      dprint (1, (debugfile, "_mutt_bounce_message(): mx_open_new_message "
+                 "failed in %s, aborting.\n", NONULL (Sendbox)));
+      mx_close_mailbox (&sctx, NULL);
+      ret = -1;
+      goto close_msg;
+    }
+    f = smsg->fp;
+
+    /* when using sendbox, Resent-To: headers will be unioned by the MTA to
+     * determine the recipient, so weed any old ones
+     */
+    ch_flags |= CH_WEED_RESENT;
+  } else {
+    /* create a temporary message which is the original message with Resent
+     * header fields prepended
+     */
+    mutt_mktemp (tempfile);
+    if ((f = safe_fopen (tempfile, "w")) == NULL) {
+      mutt_perror (tempfile);
+      ret = -1;
+      goto close_msg;
+    }
+  }
+
+  /* prepend the Resent header fields */
+  fprintf (f, "Resent-From: %s", resent_from);
+  fprintf (f, "\nResent-%s", mutt_make_date (date, sizeof(date)));
+  fprintf (f, "Resent-Message-ID: %s\n", mutt_gen_msgid());
+  fputs ("Resent-To: ", f);
+  mutt_write_address_list (to, f, 11, 0);
+
+  /* copy original message */
+  fseeko (fp, h->offset, 0);
+  mutt_copy_header (fp, h, f, ch_flags, NULL);
+  fputc ('\n', f);
+  mutt_copy_bytes (fp, f, h->content->length);
+
+  if (smsg) {
+    /* complete sending via Sendbox */
+    if (mx_commit_message (smsg, &sctx) != 0)
+       ret = -1;
+    mx_close_message (&smsg);
+    mx_close_mailbox (&sctx, NULL);
+  } else {
+    /* complete normal send */
     fclose (f);
-
 #if USE_SMTP
     if (SmtpUrl)
       ret = mutt_smtp_send (env_from, to, NULL, NULL, tempfile,
@@ -2420,6 +2464,7 @@
                                h->content->encoding == ENC8BIT);
   }
 
+close_msg:
   if (msg)
     mx_close_message (&msg);
 
@@ -2515,13 +2560,15 @@
   }
 }
 
-int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int 
post, char *fcc)
+int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int 
post, 
+                   char *fcc, int send)
 {
   CONTEXT f;
   MESSAGE *msg;
   char tempfile[_POSIX_PATH_MAX];
   FILE *tempfp = NULL;
   int r;
+  short old_write_bcc = 0;
 
   if (post)
     set_noconv_flags (hdr->content, 1);
@@ -2547,17 +2594,29 @@
     }
   }
 
-  hdr->read = !post; /* make sure to put it in the `cur' directory (maildir) */
+  hdr->read = !(post || send); /* make sure to put it in the `cur' directory 
(maildir) */
   if ((msg = mx_open_new_message (&f, hdr, M_ADD_FROM)) == NULL)
   {
     mx_close_mailbox (&f, NULL);
     return (-1);
   }
 
+  if (send) {
+    old_write_bcc = option (OPTWRITEBCC);
+    set_option (OPTWRITEBCC);
+  }
+
   /* post == 1 => postpone message. Set mode = -1 in mutt_write_rfc822_header()
    * post == 0 => Normal mode. Set mode = 0 in mutt_write_rfc822_header() 
-   * */
+   */
   mutt_write_rfc822_header (msg->fp, hdr->env, hdr->content, post ? -post : 0, 
0);
+
+  if (send && !old_write_bcc)
+    unset_option (OPTWRITEBCC);
+
+  /* set RO flag if this is not a send or post operation */
+  if (hdr->read)
+    fprintf (msg->fp, "Status: RO\n");
 
   /* (postponment) if this was a reply of some sort, <msgid> contians the
    * Message-ID: of message replied to.  Save it using a special X-Mutt-
@@ -2573,9 +2632,6 @@
    */
   if (post && fcc)
     fprintf (msg->fp, "X-Mutt-Fcc: %s\n", fcc);
-  fprintf (msg->fp, "Status: RO\n");
-
-
 
   /* (postponment) if the mail is to be signed or encrypted, save this info */
   if ((WithCrypto & APPLICATION_PGP)