--- mutt-1.5.8/PATCHES~ never +++ mutt-1.5.8/PATCHES Thu Mar 10 16:49:37 CST 2005 @@ -1,0 +1 @@ +patch-1.5.8.g10.mdn.3 diff -Pur mutt-1.5.8-base/OPS mutt-1.5.8/OPS --- mutt-1.5.8-base/OPS Fri Jul 4 12:07:11 2003 +++ mutt-1.5.8/OPS Thu Mar 10 16:44:36 2005 @@ -27,6 +27,7 @@ OP_COMPOSE_EDIT_MESSAGE "edit the message" OP_COMPOSE_EDIT_MIME "edit attachment using mailcap entry" OP_COMPOSE_EDIT_REPLY_TO "edit the Reply-To field" +OP_COMPOSE_EDIT_DNT "edit the Disposition-Notification-To field" OP_COMPOSE_EDIT_SUBJECT "edit the subject of this message" OP_COMPOSE_EDIT_TO "edit the TO list" OP_CREATE_MAILBOX "create a new mailbox (IMAP only)" @@ -42,6 +43,7 @@ OP_COMPOSE_TOGGLE_UNLINK "toggle whether to delete file after sending it" OP_COMPOSE_UPDATE_ENCODING "update an attachment's encoding info" OP_COMPOSE_WRITE_MESSAGE "write the message to a folder" +OP_COMPOSE_SWITCH_DNT "switch between Disposition-Notification-To defaults" OP_COPY_MESSAGE "copy a message to a file/mailbox" OP_CREATE_ALIAS "create an alias from a message sender" OP_CURRENT_BOTTOM "move entry to bottom of screen" diff -Pur mutt-1.5.8-base/alias.c mutt-1.5.8/alias.c --- mutt-1.5.8-base/alias.c Sat Feb 12 12:53:32 2005 +++ mutt-1.5.8/alias.c Thu Mar 10 16:44:36 2005 @@ -140,6 +140,7 @@ env->cc = mutt_expand_aliases (env->cc); env->bcc = mutt_expand_aliases (env->bcc); env->reply_to = mutt_expand_aliases (env->reply_to); + env->dnt = mutt_expand_aliases (env->dnt); env->mail_followup_to = mutt_expand_aliases (env->mail_followup_to); } diff -Pur mutt-1.5.8-base/commands.c mutt-1.5.8/commands.c --- mutt-1.5.8-base/commands.c Sat Feb 12 13:22:15 2005 +++ mutt-1.5.8/commands.c Thu Mar 10 16:44:36 2005 @@ -32,6 +32,7 @@ #include "pager.h" #include "mutt_crypt.h" #include "mutt_idna.h" +#include "rfc2047.h" #include #include #include @@ -58,6 +59,311 @@ /* The folder the user last saved to. Used by ci_save_message() */ static char LastSaveFolder[_POSIX_PATH_MAX] = ""; +static int is_in_mdn_list (ADDRESS *addr, LIST *p) +{ + if (addr->mailbox) + { + for (;p; p = p->next) + if (!mutt_strncasecmp (addr->mailbox, p->data, mutt_strlen (p->data))) + return 1; + } + return 0; +} + +/* Compare 2 addresses. Thisactually should do a case-insensitive + compare on the mailbox part (according to rfc-2298) but we ignore + that because case sensitive mailboxes are not common. + + FIXME: There is a similar but static function in send.c: mutt_addrcmp. + */ +static int address_compare (ADDRESS *a, ADDRESS *b) +{ + if (!a->mailbox || !b->mailbox) + return-1; + return ascii_strcasecmp (a->mailbox, b->mailbox); +} + +static void write_address (FILE *fp, const char *tag, const char *prefix, + ADDRESS *a, int qualify) +{ + const char *fqdn = mutt_fqdn (1); + char buffer[STRING]; + ADDRESS *aa; + + aa = rfc822_cpy_adr (a); + if (fqdn && qualify) + rfc822_qualify (aa, fqdn); + rfc2047_encode_adrlist (aa, tag); + *buffer = 0; + rfc822_write_address (buffer, sizeof (buffer), aa, 1); + rfc822_free_address (&aa); + + fprintf (fp, "%s: %s%s\n", tag, prefix, buffer); +} + + + + +/* Record that the MDN as already been sent. */ +static void mark_mdn_done (HEADER *cur) +{ + /* Hmmm: How should this be done. IMHO the New Message mark should + be sufficient but it is not exactly what we want: IF one select + "ignore for now" the message will be flaged as old but the MDN + was not sent and the next time it gets displayed, there won't be + an indication whether it should be sent or not. Also automatic + tools won't be able to detect that status. */ + mutt_set_flag (Context, cur, M_MDNSENT, 1); +} + +/* Construct a Message Disposition Notiifcation and send it out. */ +static void mutt_send_mdn (HEADER *cur, int confirmed, ADDRESS *dnt) +{ + char fnamebuf[LONG_STRING]; + FILE *fp; + HEADER *msg; + BODY *t; + char current_date_buf[SHORT_STRING], *current_date; + ADDRESS *addr; + + mutt_make_date (current_date_buf, sizeof (current_date_buf)); + current_date = current_date_buf; + current_date += strncmp (current_date_buf, "Date: ",6)? 0:6; + if (*current_date && current_date[strlen(current_date)-1] =='\n') + current_date[strlen(current_date)-1] = 0; + + msg = mutt_new_header (); + msg->env = mutt_new_envelope (); + msg->env->to = dnt; /* Note that this is not a copy! */ + msg->env->subject = safe_strdup ("Disposition notification"); + + t = mutt_new_body (); + msg->content = t; + t->type = TYPEMULTIPART; + t->subtype = safe_strdup ("report"); + t->encoding = ENC7BIT; + t->use_disp = 0; + t->disposition = DISPINLINE; + mutt_generate_boundary (&t->parameter); + mutt_set_parameter ("report-type", "disposition-notification", + &t->parameter); + + t->parts = mutt_new_body (); + t = t->parts; + t->type = TYPETEXT; + t->subtype = safe_strdup ("plain"); + t->use_disp = 0; + t->disposition = DISPINLINE; + t->encoding = ENC7BIT; + mutt_mktemp (fnamebuf); + t->filename = safe_strdup (fnamebuf); + t->unlink = 1; + if (!(fp = safe_fopen (t->filename, "w"))) + { + mutt_perror (t->filename); + /* fixme: cleanup */ + return; + } + fprintf (fp, "Original message info:\n\n"); + if (cur->env->date) + fprintf (fp, " Date: %s\n", cur->env->date); + if (cur->env->to) + write_address (fp, " To", "", cur->env->to, 0); + if (cur->env->subject) + fprintf (fp, " Subject: %s\n", cur->env->subject); + fprintf (fp, "\n" + "The message has been displayed at %s.\n" + "This is no guarantee that the message has been read or understood.\n\n", + current_date); + fclose (fp); + + + t->next = mutt_new_body (); + t = t->next; + t->type = TYPEMESSAGE; + t->subtype = safe_strdup ("disposition-notification"); + t->use_disp = 0; + t->disposition = DISPINLINE; + t->encoding = ENC7BIT; + mutt_mktemp (fnamebuf); + t->filename = safe_strdup (fnamebuf); + t->unlink = 1; + if (!(fp = safe_fopen (t->filename, "w"))) + { + mutt_perror (t->filename); + /* fixme: cleanup */ + return; + } + + fprintf (fp, "Reporting-UA: %s; Mutt/%s\n", Fqdn, MUTT_VERSION); + /*fprintf (fp, "Original-Recipient: rfc822;%s\n");*/ + + + addr = NULL; + { + LIST *uh = UserHeader; + + for (; uh; uh = uh->next) + { + if (!ascii_strncasecmp ("from:", uh->data, 5)) + { /* User has specified a default From: address. This has priority. */ + addr = rfc822_parse_adrlist (addr, uh->data + 5); + break; + } + } + } + if (!addr) + addr = mutt_default_from (); + + write_address (fp, "Final-Recipient", "rfc822;", addr, 1); + rfc822_free_address (&msg->env->from); + msg->env->from = addr; + + if (cur->env->message_id) + fprintf (fp, "Original-Message-ID: %s\n", cur->env->message_id); + + fprintf (fp, "Disposition: manual-action/MDN-sent-%s; displayed\n", + confirmed? "manually":"automatically"); + fclose (fp); + + if (!mutt_send_message_direct (msg, 1)) + mutt_message (_("Message Disposition Notification sent.")); + + msg->env->to = NULL; /* we didn't used a copy */ + mutt_free_envelope (&msg->env); msg->env = NULL; + + mark_mdn_done (cur); +} + + +/* Have a look at the current message and decide whether a MDN should + be sent. Return true if the user selected to ignore it for now. */ +int mutt_handle_mdn (HEADER *cur) +{ + int must_ask = 0; + int ask_this = 0; + int unknown_required = 0; + int confirmed = 0; + PARAMETER *parm; + ADDRESS *dnt_addr = NULL; + ADDRESS *a; + + if (!option (OPTMDNENABLE) ) + return 0; /* MDN support not enabled */ + + /* Do we have a notification header? */ + if (!cur->env || !cur->env->dnt) + return 0; /* Nothing to do. */ + if (cur->mdnsent) + return 0; /* Already sent. */ + + /* Check whether one of the notification addresses is in the deny + list. Add all non-denied addresses to a new list. */ + for (a = cur->env->dnt; a; a = a->next) + { + if (!is_in_mdn_list (a, MdnDeny)) + { + ADDRESS *aa = rfc822_cpy_adr_real (a); + rfc822_append (&dnt_addr, aa); + rfc822_free_address (&aa); + } + } + + if (!dnt_addr) + { + mark_mdn_done (cur); + return 0; /* All addresses are in the deny list. */ + } + + /* Check whether we can handle all required options. RFC2298 does + not define any yet, but we must be prepared for future extensions + and X-foo attributes. */ + for (parm=cur->env->dno; parm; parm = parm->next) + { + if (!ascii_strcasecmp (parm->value, "required")) + unknown_required = 1; + else if (ascii_strcasecmp (parm->value, "optional")) + must_ask = 1; /* invalid importance value */ + } + + if (unknown_required) + { + /* We don't sent a failed messages at all. */ + mark_mdn_done (cur); + mutt_message (_("Required Disposition Notification Option unknown " + "- DNT ignored")); + rfc822_free_address (&dnt_addr); + return 0; + } + + + /* Check that the Return-Path matches the DNT, a Return-Path exists + and that it does not comtain more than one address.*/ + if (dnt_addr->next) + must_ask = 1; /* More than one address. */ + else if (!cur->env->return_path) + must_ask = 1; + else if (cur->env->return_path->next) + must_ask = 1; + else if (address_compare (dnt_addr, cur->env->return_path)) + must_ask = 1; /* Addresses don't match. */ + else if ( option (OPTMDNCONFIRM) ) + ask_this = 1; + + /* Check the allow list, which overrides the above. */ + if (must_ask || ask_this) + { + for (a = dnt_addr; a; a = a->next) + if (!is_in_mdn_list (a, MdnAllow)) + break; + if (!a) /* All addresses are in the allow list. */ + must_ask = ask_this = 0; + } + + + /* Get confirmation if required. */ + if (must_ask) + { + switch (mutt_yesorno (_("Disposition-Notification request is questionable." + " Really send?"), M_NO)) + { + case M_YES: + break; + case M_NO: + mark_mdn_done (cur); + rfc822_free_address (&dnt_addr); + return 0; + default: + /* ^G */ + rfc822_free_address (&dnt_addr); + return 1; /* ignore/postponed */ + } + confirmed = 1; + } + else if (ask_this) + { + switch (mutt_yesorno (_("Disposition-Notification requested. " + "Send?"), M_YES)) + { + case M_YES: + break; + case M_NO: + mark_mdn_done (cur); + rfc822_free_address (&dnt_addr); + return 0; + default: + /* ^G */ + rfc822_free_address (&dnt_addr); + return 1; /* ignore/postponed */ + } + confirmed = 1; + } + + mutt_send_mdn (cur, confirmed, dnt_addr); + rfc822_free_address (&dnt_addr); + return 0; +} + int mutt_display_message (HEADER *cur) { char tempfile[_POSIX_PATH_MAX], buf[LONG_STRING]; @@ -156,6 +462,8 @@ mutt_unlink (tempfile); return 0; } + + mutt_handle_mdn (cur); if (fpfilterout != NULL && mutt_wait_filter (filterpid) != 0) mutt_any_key_to_continue (NULL); diff -Pur mutt-1.5.8-base/compose.c mutt-1.5.8/compose.c --- mutt-1.5.8-base/compose.c Thu Feb 3 12:47:52 2005 +++ mutt-1.5.8/compose.c Thu Mar 10 16:49:20 2005 @@ -59,6 +59,7 @@ HDR_SUBJECT, HDR_REPLYTO, HDR_FCC, + HDR_DNT, /* Disposition-Notification-To */ #ifdef MIXMASTER HDR_MIX, @@ -67,7 +68,7 @@ HDR_CRYPT, HDR_CRYPTINFO, - HDR_ATTACH = (HDR_FCC + 5) /* where to start printing the attachments */ + HDR_ATTACH = (HDR_DNT + 5) /* where to start printing the attachments */ }; #define HDR_XOFFSET 10 @@ -82,7 +83,8 @@ "Bcc: ", "Subject: ", "Reply-To: ", - "Fcc: " + "Fcc: ", + "Dnt: " }; static struct mapping_t ComposeHelp[] = { @@ -260,6 +262,8 @@ draw_envelope_addr (HDR_REPLYTO, msg->env->reply_to); mvprintw (HDR_FCC, 0, TITLE_FMT, Prompts[HDR_FCC - 1]); mutt_paddstr (W, fcc); + if (option(OPTMDNENABLE)) + draw_envelope_addr (HDR_DNT, msg->env->dnt); if (WithCrypto) redraw_crypt_lines (msg); @@ -313,6 +317,47 @@ return 0; } +static int switch_to_next_dnt (int line, ADDRESS **addr, int *current_dnt) +{ + char buf[HUGE_STRING] = ""; /* needs to be large for alias expansion */ + LIST *p; + int i, idx = *current_dnt + 1; + + if (!MdnDntDefaults) + return 0; + + rfc822_free_address (addr); + p = MdnDntDefaults; + for (i = 0; i < idx; i++) + { + p = p->next; + if (!p) + break; + } + if (!p) + idx = -1; + *current_dnt = idx; + + if (!p || !p->data || !strcmp (p->data, "none") ) + *addr = mutt_parse_adrlist (*addr, ""); + else + *addr = mutt_parse_adrlist (*addr, p->data); + + if (option (OPTNEEDREDRAW)) + { + unset_option (OPTNEEDREDRAW); + return (REDRAW_FULL); + } + + /* redraw the expanded list so the user can see the result */ + buf[0] = 0; + rfc822_write_address (buf, sizeof (buf), *addr, 1); + move (line, HDR_XOFFSET); + mutt_paddstr (W, buf); + + return 0; +} + static int delete_attachment (MUTTMENU *menu, short *idxlen, int x) { ATTACHPTR **idx = (ATTACHPTR **) menu->data; @@ -507,6 +552,7 @@ /* Sort, SortAux could be changed in mutt_index_menu() */ int oldSort, oldSortAux; struct stat st; + int current_dnt = -1; mutt_attach_init (msg->content); idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1); @@ -520,6 +566,20 @@ menu->data = idx; menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp); + if ( option(OPTMDNENABLE) && MdnDntDefaults && MdnDntDefaults->data + && !(msg->env->dnt && msg->env->dnt->mailbox + && *msg->env->dnt->mailbox)) + { + rfc822_free_address (&msg->env->dnt); + if (!MdnDntDefaults || !MdnDntDefaults->data + || !strcmp (MdnDntDefaults->data, "none") ) + msg->env->dnt = mutt_parse_adrlist (msg->env->dnt, ""); + else + msg->env->dnt = mutt_parse_adrlist (msg->env->dnt, + MdnDntDefaults->data); + current_dnt++; + } + while (loop) { switch (op = mutt_menuLoop (menu)) @@ -576,6 +636,15 @@ } MAYBE_REDRAW (menu->redraw); mutt_message_hook (NULL, msg, M_SEND2HOOK); + break; + case OP_COMPOSE_EDIT_DNT: + if (option (OPTMDNENABLE)) + menu->redraw = edit_address_list (HDR_DNT, &msg->env->dnt); + break; + case OP_COMPOSE_SWITCH_DNT: + if (option (OPTMDNENABLE)) + menu->redraw = switch_to_next_dnt (HDR_DNT, &msg->env->dnt, + ¤t_dnt); break; case OP_COMPOSE_EDIT_MESSAGE: if (Editor && (mutt_strcmp ("builtin", Editor) != 0) && !option (OPTEDITHDRS)) diff -Pur mutt-1.5.8-base/copy.c mutt-1.5.8/copy.c --- mutt-1.5.8-base/copy.c Thu Feb 3 12:47:52 2005 +++ mutt-1.5.8/copy.c Thu Mar 10 16:44:36 2005 @@ -383,7 +383,7 @@ return (-1); } - if (h->flagged || h->replied) + if (h->flagged || h->replied | h->mdnsent) { if (fputs ("X-Status: ", out) == EOF) return (-1); @@ -397,6 +397,12 @@ if (h->flagged) { if (fputc ('F', out) == EOF) + return (-1); + } + + if (h->mdnsent) + { + if (fputc ('N', out) == EOF) return (-1); } diff -Pur mutt-1.5.8-base/flags.c mutt-1.5.8/flags.c --- mutt-1.5.8-base/flags.c Thu Feb 3 12:47:52 2005 +++ mutt-1.5.8/flags.c Thu Mar 10 16:44:37 2005 @@ -221,6 +221,24 @@ } break; + case M_MDNSENT: + if (bf) + { + if (!h->mdnsent) + { + h->mdnsent = bf; + h->changed = 1; + if (upd_ctx) ctx->changed = 1; + } + } + else if (h->mdnsent) + { + h->mdnsent = 0; + h->changed = 1; + if (upd_ctx) ctx->changed = 1; + } + break; + case M_FLAG: #ifdef USE_IMAP diff -Pur mutt-1.5.8-base/functions.h mutt-1.5.8/functions.h --- mutt-1.5.8-base/functions.h Fri Jan 28 07:13:12 2005 +++ mutt-1.5.8/functions.h Thu Mar 10 16:44:37 2005 @@ -294,6 +294,8 @@ { "print-entry", OP_PRINT, "l" }, { "edit-mime", OP_COMPOSE_EDIT_MIME, "m" }, { "new-mime", OP_COMPOSE_NEW_MIME, "n" }, + { "edit-dnt", OP_COMPOSE_EDIT_DNT, "\033n" }, + { "switch-dnt", OP_COMPOSE_SWITCH_DNT, "\033N" }, { "postpone-message", OP_COMPOSE_POSTPONE_MESSAGE, "P" }, { "edit-reply-to", OP_COMPOSE_EDIT_REPLY_TO, "r" }, { "rename-file", OP_COMPOSE_RENAME_FILE, "R" }, diff -Pur mutt-1.5.8-base/globals.h mutt-1.5.8/globals.h --- mutt-1.5.8-base/globals.h Sat Feb 12 14:01:02 2005 +++ mutt-1.5.8/globals.h Thu Mar 10 16:44:37 2005 @@ -73,6 +73,7 @@ WHERE char *MhReplied; WHERE char *MhUnseen; WHERE char *MsgFmt; +WHERE char *MhMdnsent; #ifdef USE_SOCKET WHERE char *Preconnect INITVAL (NULL); @@ -137,6 +138,9 @@ WHERE LIST *Ignore INITVAL(0); WHERE LIST *MimeLookupList INITVAL(0); WHERE LIST *UnIgnore INITVAL(0); +WHERE LIST *MdnAllow INITVAL(0); +WHERE LIST *MdnDeny INITVAL(0); +WHERE LIST *MdnDntDefaults INITVAL(0); WHERE RX_LIST *Alternates INITVAL(0); WHERE RX_LIST *UnAlternates INITVAL(0); diff -Pur mutt-1.5.8-base/handler.c mutt-1.5.8/handler.c --- mutt-1.5.8-base/handler.c Thu Feb 3 12:47:52 2005 +++ mutt-1.5.8/handler.c Thu Mar 10 16:44:37 2005 @@ -1807,6 +1807,8 @@ plaintext = 1; else if (!ascii_strcasecmp ("external-body", b->subtype)) handler = external_body_handler; + else if (!ascii_strcasecmp ("disposition-notification", b->subtype)) + plaintext = 1; } else if (b->type == TYPEMULTIPART) { diff -Pur mutt-1.5.8-base/init.c mutt-1.5.8/init.c --- mutt-1.5.8-base/init.c Sat Feb 12 13:06:16 2005 +++ mutt-1.5.8/init.c Thu Mar 10 16:44:37 2005 @@ -1065,6 +1065,31 @@ return 0; } +/* FIXME? */ +static int parse_mdn_allow_deny (BUFFER *buf, BUFFER *s, + unsigned long data, BUFFER *err) +{ + do + { + mutt_extract_token (buf, s, 0); + add_to_list ((LIST **) data, buf->data); + } + while (MoreArgs (s)); + + return 0; +} + +static int parse_mdn_dnt_defaults (BUFFER *buf, BUFFER *s, + unsigned long data, BUFFER *err) +{ + + mutt_extract_token (buf, s, M_TOKEN_SPACE | M_TOKEN_QUOTE); + add_to_list ((LIST **) data, buf->data); + memset (buf, 0, sizeof (BUFFER)); + + return 0; +} + static void mutt_set_default (struct option_t *p) { switch (p->type & DT_MASK) diff -Pur mutt-1.5.8-base/init.h mutt-1.5.8/init.h --- mutt-1.5.8-base/init.h Sat Feb 12 14:01:10 2005 +++ mutt-1.5.8/init.h Thu Mar 10 16:48:22 2005 @@ -1115,6 +1115,21 @@ ** high bit from ``0xf4'' is ``0x74'', which is the ASCII character ** ``x''. */ + { "mdn_enable", DT_BOOL, R_NONE, OPTMDNENABLE, 0 }, + /* + ** .pp + ** When set, the message disposition notification support (RFC-2298) + ** is enabled. This shows an extra menu entry in the composer menu and + ** enables all the other MDN features. Keep it disabled to prevent any + ** disposition notifications to be send. + */ + { "mdn_confirm", DT_BOOL, R_NONE, OPTMDNCONFIRM, 0 }, + /* + ** .pp + ** When set, a confirmation to send a message disposition + ** notification is always requested. When unset, a confirmation is + ** only requested for suspect messages as demanded by RFC-2298. + */ { "mh_purge", DT_BOOL, R_NONE, OPTMHPURGE, 0 }, /* ** .pp @@ -1133,6 +1148,12 @@ ** .pp ** The name of the MH sequence used to tag replied messages. */ + { "mh_seq_mdnsent", DT_STR, R_NONE, UL &MhMdnsent, UL "mdnsent" }, + /* + ** .pp + ** The name of the MH sequence used to mark messages for whom a + ** message disposition notice has already been sent. + */ { "mh_seq_unseen", DT_STR, R_NONE, UL &MhUnseen, UL "unseen" }, /* ** .pp @@ -2895,6 +2916,8 @@ static int parse_unmy_hdr (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_subscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_unsubscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *); +static int parse_mdn_allow_deny (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err); +static int parse_mdn_dnt_defaults (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err); static int parse_alternates (BUFFER *, BUFFER *, unsigned long, BUFFER *); static int parse_unalternates (BUFFER *, BUFFER *, unsigned long, BUFFER *); @@ -2935,6 +2958,9 @@ { "macro", mutt_parse_macro, 0 }, { "mailboxes", mutt_parse_mailboxes, M_MAILBOXES }, { "unmailboxes", mutt_parse_mailboxes, M_UNMAILBOXES }, + { "mdn_allow", parse_mdn_allow_deny, UL &MdnAllow }, + { "mdn_deny", parse_mdn_allow_deny, UL &MdnDeny }, + { "mdn_dnt_defaults", parse_mdn_dnt_defaults, UL &MdnDntDefaults }, { "message-hook", mutt_parse_hook, M_MESSAGEHOOK }, { "mbox-hook", mutt_parse_hook, M_MBOXHOOK }, { "mime_lookup", parse_list, UL &MimeLookupList }, diff -Pur mutt-1.5.8-base/mbox.c mutt-1.5.8/mbox.c --- mutt-1.5.8-base/mbox.c Thu Feb 3 12:47:53 2005 +++ mutt-1.5.8/mbox.c Thu Mar 10 16:44:37 2005 @@ -1175,6 +1175,7 @@ mutt_set_flag (ctx, ctx->hdrs[i], M_REPLIED, old_hdrs[j]->replied); mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, old_hdrs[j]->old); mutt_set_flag (ctx, ctx->hdrs[i], M_READ, old_hdrs[j]->read); + mutt_set_flag (ctx, ctx->hdrs[i], M_MDNSENT, old_hdrs[j]->mdnsent); } mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, old_hdrs[j]->deleted); mutt_set_flag (ctx, ctx->hdrs[i], M_TAG, old_hdrs[j]->tagged); diff -Pur mutt-1.5.8-base/mh.c mutt-1.5.8/mh.c --- mutt-1.5.8-base/mh.c Thu Feb 3 12:47:53 2005 +++ mutt-1.5.8/mh.c Thu Mar 10 16:44:37 2005 @@ -69,6 +69,7 @@ #define MH_SEQ_UNSEEN (1 << 0) #define MH_SEQ_REPLIED (1 << 1) #define MH_SEQ_FLAGGED (1 << 2) +#define MH_SEQ_MDNSENT (1 << 3) static void mhs_alloc (struct mh_sequences *mhs, int i) { @@ -283,10 +284,12 @@ int unseen = 0; int flagged = 0; int replied = 0; + int mdnsent = 0; char seq_unseen[STRING]; char seq_replied[STRING]; char seq_flagged[STRING]; + char seq_mdnsent[STRING]; struct mh_sequences mhs; @@ -295,6 +298,7 @@ snprintf (seq_unseen, sizeof (seq_unseen), "%s:", NONULL (MhUnseen)); snprintf (seq_replied, sizeof (seq_replied), "%s:", NONULL (MhReplied)); snprintf (seq_flagged, sizeof (seq_flagged), "%s:", NONULL (MhFlagged)); + snprintf (seq_mdnsent, sizeof (seq_mdnsent), "%s:", NONULL (MhMdnsent)); if (mh_mkstemp (ctx, &nfp, &tmpfname) != 0) { @@ -316,13 +320,15 @@ continue; if (!mutt_strncmp (buff, seq_replied, mutt_strlen (seq_replied))) continue; + if (!mutt_strncmp (buff, seq_mdnsent, mutt_strlen (seq_mdnsent))) + continue; fprintf (nfp, "%s\n", buff); } } safe_fclose (&ofp); - /* now, update our unseen, flagged, and replied sequences */ + /* now, update our unseen, flagged, replied and mdnsent sequences */ for (l = 0; l < ctx->msgcount; l++) { if (ctx->hdrs[l]->deleted) @@ -350,6 +356,11 @@ mhs_set (&mhs, i, MH_SEQ_REPLIED); replied++; } + if (ctx->hdrs[l]->mdnsent) + { + mhs_set (&mhs, i, MH_SEQ_MDNSENT); + mdnsent++; + } } /* write out the new sequences */ @@ -359,6 +370,8 @@ mhs_write_one_sequence (nfp, &mhs, MH_SEQ_FLAGGED, NONULL (MhFlagged)); if (replied) mhs_write_one_sequence (nfp, &mhs, MH_SEQ_REPLIED, NONULL (MhReplied)); + if (mdnsent) + mhs_write_one_sequence (nfp, &mhs, MH_SEQ_MDNSENT, NONULL (MhMdnsent)); mhs_free_sequences (&mhs); @@ -467,6 +480,7 @@ md->h->read = (f & MH_SEQ_UNSEEN) ? 0 : 1; md->h->flagged = (f & MH_SEQ_FLAGGED) ? 1 : 0; md->h->replied = (f & MH_SEQ_REPLIED) ? 1 : 0; + md->h->mdnsent = (f & MH_SEQ_MDNSENT) ? 1 : 0; } } @@ -505,6 +519,7 @@ h->flagged = 0; h->read = 0; h->replied = 0; + h->mdnsent = 0; if ((p = strrchr (path, ':')) != NULL && mutt_strncmp (p + 1, "2,", 2) == 0) { @@ -537,6 +552,10 @@ h->deleted = 1; break; + case 'N': /* MDN has already been sent */ + h->mdnsent = 1; + break; + default: *q++ = *p; break; @@ -756,10 +775,11 @@ { dprint (2, (debugfile, - "%s:%d Adding header structure. Flags: %s%s%s%s%s\n", __FILE__, + "%s:%d Adding header structure. Flags: %s%s%s%s%s%s\n", __FILE__, __LINE__, md->h->flagged ? "f" : "", md->h->deleted ? "D" : "", md->h->replied ? "r" : "", md->h->old ? "O" : "", - md->h->read ? "R" : "")); + md->h->read ? "R" : "", + md->h->mdnsent ? "N" : "")); if (ctx->msgcount == ctx->hdrmax) mx_alloc_memory (ctx); @@ -993,10 +1013,12 @@ { char tmp[LONG_STRING]; snprintf (tmp, sizeof (tmp), - "%s%s%s%s%s", + "%s%s%s%s%s%s", hdr->flagged ? "F" : "", hdr->replied ? "R" : "", - hdr->read ? "S" : "", hdr->deleted ? "T" : "", + hdr->read ? "S" : "", + hdr->deleted ? "T" : "", + hdr->mdnsent ? "N" : "", NONULL(hdr->maildir_flags)); if (hdr->maildir_flags) qsort (tmp, strlen (tmp), 1, ch_compar); @@ -1531,6 +1553,7 @@ */ mutt_set_flag (ctx, o, M_FLAG, n->flagged); mutt_set_flag (ctx, o, M_REPLIED, n->replied); + mutt_set_flag (ctx, o, M_MDNSENT, n->mdnsent); mutt_set_flag (ctx, o, M_READ, n->read); mutt_set_flag (ctx, o, M_OLD, n->old); diff -Pur mutt-1.5.8-base/mutt.h mutt-1.5.8/mutt.h --- mutt-1.5.8-base/mutt.h Sat Feb 12 14:01:20 2005 +++ mutt-1.5.8/mutt.h Thu Mar 10 16:44:37 2005 @@ -206,6 +206,7 @@ M_LIMIT, M_EXPIRED, M_SUPERSEDED, + M_MDNSENT, /* actions for mutt_pattern_comp/mutt_pattern_exec */ M_AND, @@ -390,6 +391,8 @@ OPTMENUSCROLL, /* scroll menu instead of implicit next-page */ OPTMETAKEY, /* interpret ALT-x as ESC-x */ OPTMETOO, + OPTMDNENABLE, /* enable the MDN support */ + OPTMDNCONFIRM, /* always require confirmation before sending an MDN */ OPTMHPURGE, OPTMIMEFORWDECODE, OPTNARROWTREE, @@ -564,6 +567,13 @@ short num; } ALIAS; +typedef struct parameter +{ + char *attribute; + char *value; + struct parameter *next; +} PARAMETER; + typedef struct envelope { ADDRESS *return_path; @@ -574,6 +584,8 @@ ADDRESS *sender; ADDRESS *reply_to; ADDRESS *mail_followup_to; + ADDRESS *dnt; /* disposition-notification-to */ + PARAMETER *dno; /* disposition-notification-options */ char *list_post; /* this stores a mailto URL, or nothing */ char *subject; char *real_subj; /* offset of the real subject */ @@ -587,13 +599,6 @@ LIST *userhdrs; /* user defined headers */ } ENVELOPE; -typedef struct parameter -{ - char *attribute; - char *value; - struct parameter *next; -} PARAMETER; - /* Information that helps in determing the Content-* of an attachment */ typedef struct content { @@ -698,6 +703,7 @@ unsigned int expired : 1; /* already expired? */ unsigned int superseded : 1; /* got superseded? */ unsigned int replied : 1; + unsigned int mdnsent : 1; /* track whether an MDN has been sent*/ unsigned int subject_changed : 1; /* used for threading */ unsigned int threaded : 1; /* used for threading */ unsigned int display_subject : 1; /* used for threading */ diff -Pur mutt-1.5.8-base/muttlib.c mutt-1.5.8/muttlib.c --- mutt-1.5.8-base/muttlib.c Sat Feb 12 13:30:16 2005 +++ mutt-1.5.8/muttlib.c Thu Mar 10 16:44:37 2005 @@ -648,6 +648,9 @@ rfc822_free_address (&(*p)->bcc); rfc822_free_address (&(*p)->sender); rfc822_free_address (&(*p)->reply_to); + rfc822_free_address (&(*p)->dnt); + if ((*p)->dno) + mutt_free_parameter (&(*p)->dno); rfc822_free_address (&(*p)->mail_followup_to); FREE (&(*p)->list_post); diff -Pur mutt-1.5.8-base/parse.c mutt-1.5.8/parse.c --- mutt-1.5.8-base/parse.c Thu Feb 3 12:47:53 2005 +++ mutt-1.5.8/parse.c Thu Mar 10 16:44:37 2005 @@ -1029,6 +1029,25 @@ hdr->date_sent = mutt_parse_date (p, hdr); matched = 1; } + else if (!ascii_strcasecmp (line + 1, "isposition-notification-to")) + { + e->dnt = rfc822_parse_adrlist (e->dnt, p); + matched = 1; + } + else if (!ascii_strcasecmp (line + 1, "isposition-notification-options")) + { + if (!e->dno) + e->dno = parse_parameters (p); + else + { + PARAMETER *tmp; + + for (tmp=e->dno; tmp->next; tmp = tmp->next) + ; + tmp->next = parse_parameters (p); + } + matched = 1; + } break; case 'e': @@ -1222,6 +1241,9 @@ case 'F': hdr->flagged = 1; break; + case 'N': + hdr->mdnsent = 1; + break; default: break; } @@ -1406,6 +1428,7 @@ rfc2047_decode_adrlist (e->to); rfc2047_decode_adrlist (e->cc); rfc2047_decode_adrlist (e->reply_to); + rfc2047_decode_adrlist (e->dnt); rfc2047_decode_adrlist (e->mail_followup_to); rfc2047_decode_adrlist (e->return_path); rfc2047_decode_adrlist (e->sender); diff -Pur mutt-1.5.8-base/protos.h mutt-1.5.8/protos.h --- mutt-1.5.8-base/protos.h Tue Feb 1 02:59:02 2005 +++ mutt-1.5.8/protos.h Thu Mar 10 16:44:38 2005 @@ -297,7 +297,8 @@ int mutt_get_postponed (CONTEXT *, HEADER *, HEADER **, char *, size_t); int mutt_get_tmp_attachment (BODY *); int mutt_index_menu (void); -int mutt_invoke_sendmail (ADDRESS *, ADDRESS *, ADDRESS *, ADDRESS *, const char *, int); +int mutt_send_message_direct (HEADER *msg, int nullrp); +int mutt_invoke_sendmail (ADDRESS *, ADDRESS *, ADDRESS *, ADDRESS *, const char *, int, int); int mutt_is_autoview (BODY *, const char *); int mutt_is_mail_list (ADDRESS *); int mutt_is_message_type(int, const char *); diff -Pur mutt-1.5.8-base/send.c mutt-1.5.8/send.c --- mutt-1.5.8-base/send.c Thu Feb 3 12:47:53 2005 +++ mutt-1.5.8/send.c Thu Mar 10 16:44:38 2005 @@ -301,7 +301,9 @@ else if (ascii_strncasecmp ("to:", uh->data, 3) != 0 && ascii_strncasecmp ("cc:", uh->data, 3) != 0 && ascii_strncasecmp ("bcc:", uh->data, 4) != 0 && - ascii_strncasecmp ("subject:", uh->data, 8) != 0) + ascii_strncasecmp ("subject:", uh->data, 8) != 0 && + !(ascii_strncasecmp ("disposition-notification-to:", + uh->data, 28) == 0 && env->dnt)) { if (last) { @@ -951,7 +953,7 @@ return (adr); } -static int send_message (HEADER *msg) +static int send_message (HEADER *msg, int nullrp) { char tempfile[_POSIX_PATH_MAX]; FILE *tempfp; @@ -991,10 +993,17 @@ #endif 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), nullrp); return (i); } +/* Send a message as defined by MSG without any user interaction. If + NULLRP is set to true, a NULL return path (<>) will be used. */ +int mutt_send_message_direct (HEADER *msg, int nullrp) +{ + return send_message (msg, nullrp); +} + /* rfc2047 encode the content-descriptions */ static void encode_descriptions (BODY *b, short recurse) { @@ -1673,7 +1682,7 @@ * the send failed as well so we give the user a chance to fix the * error. */ - if (fcc_error || (i = send_message (msg)) == -1) + if (fcc_error || (i = send_message (msg, 0)) == -1) { if (!(flags & SENDBATCH)) { diff -Pur mutt-1.5.8-base/sendlib.c mutt-1.5.8/sendlib.c --- mutt-1.5.8-base/sendlib.c Thu Feb 3 12:47:53 2005 +++ mutt-1.5.8/sendlib.c Thu Mar 10 16:44:38 2005 @@ -1659,6 +1659,12 @@ mutt_write_address_list (env->mail_followup_to, fp, 18, 0); } + if (env->dnt && !privacy) + { + fputs ("Disposition-Notification-To: ", fp); + mutt_write_address_list (env->dnt, fp, 29, 0); + } + if (mode <= 0) { if (env->references) @@ -1989,7 +1995,8 @@ mutt_invoke_sendmail (ADDRESS *from, /* the sender */ ADDRESS *to, ADDRESS *cc, ADDRESS *bcc, /* recips */ const char *msg, /* file containing message */ - int eightbit) /* message contains 8bit chars */ + int eightbit, /* message contains 8bit chars */ + int nullrp) { char *ps = NULL, *path = NULL, *s = safe_strdup (Sendmail), *childout = NULL; char **args = NULL; @@ -2022,6 +2029,11 @@ if (eightbit && option (OPTUSE8BITMIME)) args = add_option (args, &argslen, &argsmax, "-B8BITMIME"); + if (nullrp) + { + args = add_option (args, &argslen, &argsmax, "-f"); + args = add_option (args, &argslen, &argsmax, "<>"); + } if (option (OPTENVFROM) && from && !from->next) { args = add_option (args, &argslen, &argsmax, "-f"); @@ -2170,6 +2182,7 @@ rfc2047_encode_adrlist (env->from, "From"); rfc2047_encode_adrlist (env->mail_followup_to, "Mail-Followup-To"); rfc2047_encode_adrlist (env->reply_to, "Reply-To"); + rfc2047_encode_adrlist (env->dnt, "Disposition-Notification-To"); if (env->subject) { @@ -2192,6 +2205,7 @@ rfc2047_decode_adrlist (env->cc); rfc2047_decode_adrlist (env->from); rfc2047_decode_adrlist (env->reply_to); + rfc2047_decode_adrlist (env->dnt); rfc2047_decode (&env->subject); } @@ -2238,7 +2252,7 @@ fclose (f); ret = mutt_invoke_sendmail (env_from, to, NULL, NULL, tempfile, - h->content->encoding == ENC8BIT); + (h->content->encoding == ENC8BIT), 0); } if (msg)