Add "sendbox" and "use_sendbox" variables, intended to be used with Courier's Outbox feature. See http://www.inter7.com/courierimap/INSTALL.html#imapsend Usage: set sendbox=imap://imap.domain.com/INBOX/Outbox set use_sendbox=yes If use_sendbox is set, the sendmail variable is ignored and sendbox is used instead. Copyright 2006, Aron Griffis Released under the GNU GPL v2 --- a/PATCHES Sun Aug 06 19:38:36 2006 -0400 +++ b/PATCHES Mon Aug 07 15:08:19 2006 -0400 @@ -0,0 +1 @@ +mutt-1.5.12-sendbox.patch diff -r 3ef8eddb0c09 -r 63b2ad5b0ce7 compose.c --- a/compose.c Sun Aug 06 19:38:36 2006 -0400 +++ b/compose.c Mon Aug 07 15:08:19 2006 -0400 @@ -1207,7 +1207,7 @@ int mutt_compose_menu (HEADER *msg, /* if (msg->content->next) msg->content = mutt_make_multipart (msg->content); - if (mutt_write_fcc (NONULL (fname), msg, NULL, 1, NULL) < 0) + if (mutt_write_fcc (NONULL (fname), msg, NULL, 1, NULL, 0) < 0) msg->content = mutt_remove_multipart (msg->content); else mutt_message _("Message written."); diff -r 3ef8eddb0c09 -r 63b2ad5b0ce7 copy.c --- a/copy.c Sun Aug 06 19:38:36 2006 -0400 +++ b/copy.c Mon Aug 07 15:08:19 2006 -0400 @@ -62,7 +62,7 @@ mutt_copy_hdr (FILE *in, FILE *out, LOFF 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_TO)) == 0) { /* Without these flags to complicate things * we can do a more efficient line to line copying @@ -188,6 +188,9 @@ mutt_copy_hdr (FILE *in, FILE *out, LOFF continue; if ((flags & CH_WEED_DELIVERED) && ascii_strncasecmp ("Delivered-To:", buf, 13) == 0) + continue; + if ((flags & CH_WEED_RESENT_TO) && + ascii_strncasecmp ("Resent-To:", buf, 10) == 0) continue; if ((flags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) && (ascii_strncasecmp ("Status:", buf, 7) == 0 || diff -r 3ef8eddb0c09 -r 63b2ad5b0ce7 globals.h --- a/globals.h Sun Aug 06 19:38:36 2006 -0400 +++ b/globals.h Mon Aug 07 15:08:19 2006 -0400 @@ -110,6 +110,7 @@ WHERE char *PrintCmd; WHERE char *PrintCmd; WHERE char *QueryCmd; WHERE char *Realname; +WHERE char *Sendbox; WHERE char *SendCharset; WHERE char *Sendmail; WHERE char *Shell; diff -r 3ef8eddb0c09 -r 63b2ad5b0ce7 init.h --- a/init.h Sun Aug 06 19:38:36 2006 -0400 +++ b/init.h Mon Aug 07 15:08:19 2006 -0400 @@ -2450,12 +2450,23 @@ struct option_t MuttVars[] = { ** iso-8859-2, koi8-r or iso-2022-jp) either instead of or after ** "iso-8859-1". */ + { "sendbox", DT_PATH, R_NONE, UL &Sendbox, 0 }, + /* + ** .pp + ** Specifies a special mailbox that will + ** \fBsend\fP mail when written, honored when \fIuse_sendbox\fB 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 }, /* @@ -2877,6 +2888,12 @@ struct option_t MuttVars[] = { ** Normally, the default should work. */ #endif /* HAVE_GETADDRINFO */ + { "use_sendbox", DT_BOOL, R_NONE, OPTUSESENDBOX, 0 }, + /* + ** .pp + ** When \fIset\P, mutt sends mail using \fIsendbox\fB instead + ** of \fIsendmail\fP. + */ { "user_agent", DT_BOOL, R_NONE, OPTXMAILER, 1}, /* ** .pp diff -r 3ef8eddb0c09 -r 63b2ad5b0ce7 mutt.h --- a/mutt.h Sun Aug 06 19:38:36 2006 -0400 +++ b/mutt.h Mon Aug 07 15:08:19 2006 -0400 @@ -92,6 +92,7 @@ #define CH_NOQFROM (1<<15) /* give CH_FROM precedence over CH_WEED? */ #define CH_UPDATE_IRT (1<<16) /* update In-Reply-To: */ #define CH_UPDATE_REFS (1<<17) /* update References: */ +#define CH_WEED_RESENT_TO (1<<18) /* weed Resent-* headers */ /* flags for mutt_enter_string() */ #define M_ALIAS 1 /* do alias "completion" by calling up the alias-menu */ @@ -442,6 +443,7 @@ enum #ifdef HAVE_GETADDRINFO OPTUSEIPV6, #endif + OPTUSESENDBOX, OPTWAITKEY, OPTWEED, OPTWRAP, diff -r 3ef8eddb0c09 -r 63b2ad5b0ce7 mx.c --- a/mx.c Sun Aug 06 19:38:36 2006 -0400 +++ b/mx.c Mon Aug 07 15:08:19 2006 -0400 @@ -153,7 +153,7 @@ int mx_lock_file (const char *path, int #if defined (USE_FCNTL) || defined (USE_FLOCK) int count; int attempt; - struct stat prev_sb; + struct stat prev_sb = { 0 }; /* silence gcc warnings */ #endif int r = 0; @@ -166,7 +166,6 @@ int mx_lock_file (const char *path, int count = 0; attempt = 0; - prev_sb.st_size = 0; /* silence a GCC warning */ while (fcntl (fd, F_SETLK, &lck) == -1) { struct stat sb; diff -r 3ef8eddb0c09 -r 63b2ad5b0ce7 protos.h --- a/protos.h Sun Aug 06 19:38:36 2006 -0400 +++ b/protos.h Mon Aug 07 15:08:19 2006 -0400 @@ -353,7 +353,7 @@ void mutt_update_num_postponed (void); 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_rfc822_header (FILE *, ENVELOPE *, BODY *, int, int); diff -r 3ef8eddb0c09 -r 63b2ad5b0ce7 send.c --- a/send.c Sun Aug 06 19:38:36 2006 -0400 +++ b/send.c Mon Aug 07 15:08:19 2006 -0400 @@ -962,7 +962,13 @@ static int send_message (HEADER *msg) char tempfile[_POSIX_PATH_MAX]; FILE *tempfp; int i; - + + /* Some IMAP servers (e.g. Courier) allow sending mail by saving to a special + * folder, see http://www.inter7.com/courierimap/INSTALL.html#imapsend + */ + 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) @@ -1489,7 +1495,7 @@ main_loop: 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); @@ -1669,7 +1675,7 @@ full_fcc: * 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 3ef8eddb0c09 -r 63b2ad5b0ce7 sendlib.c --- a/sendlib.c Sun Aug 06 19:38:36 2006 -0400 +++ b/sendlib.c Mon Aug 07 15:08:19 2006 -0400 @@ -2136,52 +2136,102 @@ void mutt_unprepare_envelope (ENVELOPE * rfc2047_decode (&env->subject); } -static int _mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to, const char *resent_from, - ADDRESS *env_from) +static int _mutt_bounce_message (FILE *in, HEADER *hdr, ADDRESS *to, + const char *resent_from, ADDRESS *env_from) { int i, ret = 0; - FILE *f; - char date[SHORT_STRING], tempfile[_POSIX_PATH_MAX]; - MESSAGE *msg = NULL; - - if (!h) - { - /* Try to bounce each message out, aborting if we get any failures. */ + FILE *out; + char date[SHORT_STRING]; + char tempfile[_POSIX_PATH_MAX]; + MESSAGE *msg = NULL, *smsg = NULL; + CONTEXT sctx; + int ch_flags; + + if (!hdr) + { + /* Try to bounce each message out, aborting if we get any failures. */ for (i=0; imsgcount; i++) if (Context->hdrs[i]->tagged) - ret |= _mutt_bounce_message (fp, Context->hdrs[i], to, resent_from, env_from); + ret |= _mutt_bounce_message (in, Context->hdrs[i], to, resent_from, + env_from); return ret; } /* If we failed to open a message, return with error */ - if (!fp && (msg = mx_open_message (Context, h->msgno)) == NULL) - return -1; - - 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); - fclose (f); - + if (!in) { + if ((msg = mx_open_message (Context, hdr->msgno)) == NULL) + return -1; + in = msg->fp; + } + + ch_flags = CH_XMIT | CH_NONEWLINE | CH_NOQFROM; + if (!option (OPTBOUNCEDELIVERED)) + ch_flags |= CH_WEED_DELIVERED; + + if (option (OPTUSESENDBOX)) { + /* some imap servers (e.g. courier) can send mail by saving to a special + * folder, see http://www.inter7.com/courierimap/INSTALL.html#imapsend + */ + 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, hdr, 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; + } + out = 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_TO; + } else { + /* normal send path, create a temporary message which is the original + * message with Resent header fields prepended + */ + mutt_mktemp (tempfile); + if ((out = safe_fopen (tempfile, "w")) == NULL) { + mutt_perror (tempfile); + ret = -1; + goto close_msg; + } + } + + /* prepend the Resent header fields */ + fprintf (out, "Resent-From: %s", resent_from); + fprintf (out, "\nResent-%s", mutt_make_date (date, sizeof(date))); + fprintf (out, "Resent-Message-ID: %s\n", mutt_gen_msgid()); + fputs ("Resent-To: ", out); + mutt_write_address_list (to, out, 11, 0); + + /* copy original message */ + fseeko (in, hdr->offset, 0); + mutt_copy_header (in, hdr, out, ch_flags, NULL); + fputc ('\n', out); + mutt_copy_bytes (in, out, hdr->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 (out); ret = mutt_invoke_sendmail (env_from, to, NULL, NULL, tempfile, - h->content->encoding == ENC8BIT); - } - + hdr->content->encoding == ENC8BIT); + } + +close_msg: if (msg) mx_close_message (&msg); @@ -2277,7 +2327,7 @@ static void set_noconv_flags (BODY *b, s } } -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; @@ -2309,7 +2359,7 @@ int mutt_write_fcc (const char *path, HE } } - 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); @@ -2335,9 +2385,13 @@ int mutt_write_fcc (const char *path, HE */ if (post && fcc) fprintf (msg->fp, "X-Mutt-Fcc: %s\n", fcc); - fprintf (msg->fp, "Status: RO\n"); - - + + /* don't set RO flag if this is a send operation. + * FIXME: possibly could restrict to f.magic == M_MBOX too, I don't think any + * other formats use the Status header field + */ + if (!send) + fprintf (msg->fp, "Status: RO\n"); /* (postponment) if the mail is to be signed or encrypted, save this info */ if ((WithCrypto & APPLICATION_PGP)