diff -Pur mutt/OPS mutt-patch/OPS --- mutt/OPS Mon Oct 10 11:21:18 2005 +++ mutt-patch/OPS Fri May 5 20:22:23 2006 @@ -32,7 +32,10 @@ OP_CREATE_MAILBOX "create a new mailbox (IMAP only)" OP_EDIT_TYPE "edit attachment content type" OP_COMPOSE_GET_ATTACHMENT "get a temporary copy of an attachment" +OP_COMPOSE_GROUP_ALTS "group tagged attachments as multipart/alternative" OP_COMPOSE_ISPELL "run ispell on the message" +OP_COMPOSE_MOVE_UP "move an attachment up in the attachment list" +OP_COMPOSE_MOVE_DOWN "move an attachment down in the attachment list" OP_COMPOSE_NEW_MIME "compose new attachment using mailcap entry" OP_COMPOSE_TOGGLE_RECODE "toggle recoding of this attachment" OP_COMPOSE_POSTPONE_MESSAGE "save this message to send later" diff -Pur mutt/PATCHES mutt-patch/PATCHES --- mutt/PATCHES Wed Dec 31 18:00:00 1969 +++ mutt-patch/PATCHES Fri May 5 20:22:22 2006 @@ -1,0 +1 @@ +patch-1.5.11.dgc.groupalts.2 diff -Pur mutt/compose.c mutt-patch/compose.c --- mutt/compose.c Sat Sep 17 15:46:10 2005 +++ mutt-patch/compose.c Fri May 5 20:22:23 2006 @@ -214,6 +214,8 @@ for (i = 0; i < idxlen; i++) { + if (idx[i]->content->type == TYPEMULTIPART) + continue; strfcpy(pretty, idx[i]->content->filename, sizeof(pretty)); if(stat(idx[i]->content->filename, &st) != 0) { @@ -361,6 +363,43 @@ } +/* + * compose_attach_swap: swap two adjacent entries in the attachment list. + */ +static void compose_attach_swap (BODY *msg, ATTACHPTR **idx, short first) +{ + int i; + void *saved; + BODY *part; + + /* Reorder BODY pointers. + * Must traverse msg from top since BODY * has no previous ptr. + */ + for (part = msg; part; part = part->next) + { + if (part->next == idx[first]->content) + { + idx[first]->content->next = idx[first+1]->content->next; + idx[first+1]->content->next = idx[first]->content; + part->next = idx[first+1]->content; + break; + } + } + + /* Reorder index */ + saved = idx[first]; + idx[first] = idx[first+1]; + idx[first+1] = saved; + + /* Swap ptr->num */ + i = idx[first]->num; + idx[first]->num = idx[first+1]->num; + idx[first+1]->num = i; + + return; +} + + /* * cum_attachs_size: Cumulative Attachments Size * @@ -658,6 +697,132 @@ mutt_message_hook (NULL, msg, M_SEND2HOOK); break; + + case OP_COMPOSE_MOVE_UP: + if (menu->current == 0) + { + mutt_error(_("Attachment is already at top.")); + break; + } + if (menu->current == 1) + { + mutt_error(_("The fundamental part cannot be moved.")); + break; + } + compose_attach_swap(msg->content, idx, menu->current - 1); + menu->redraw = 1; + menu->current--; + break; + + + case OP_COMPOSE_MOVE_DOWN: + if (menu->current == idxlen-1) + { + mutt_error(_("Attachment is already at bottom.")); + break; + } + if (menu->current == 0) + { + mutt_error(_("The fundamental part cannot be moved.")); + break; + } + compose_attach_swap(msg->content, idx, menu->current); + menu->redraw = 1; + menu->current++; + break; + + case OP_COMPOSE_GROUP_ALTS: + { + BODY *group, *bptr, *alts; + ATTACHPTR *gptr; + int i, j; + char *p; + + if (menu->tagged < 2) + { + mutt_error(_("Grouping alternatives requires at least 2 tagged messages.")); + break; + } + +/* need to redo using mutt_gen_attach_list() */ + + group = safe_calloc(1, sizeof(BODY)); + group->type = TYPEMULTIPART; + group->subtype = "alternative"; + + alts = NULL; + for (i = 0, bptr = msg->content; bptr && bptr->next;) + { + /* always look at bptr->next, not bptr itself */ + if (bptr->next->tagged) + { + /* untag */ + bptr->next->tagged = 0; + + /* for first match, set group desc according to match */ +# define ALTS_TAG "Alternatives for \"%s\"" + if (!group->description) + { + p = bptr->next->description; + if (!p) + p = bptr->next->filename; + if (p) + { + group->description = safe_calloc(1, + strlen(p) + strlen(ALTS_TAG) + 1); + sprintf(group->description, ALTS_TAG, p); + } + } + + /* append bptr->next to the alts list, + * and remove from the msg->content list */ + if (alts == NULL) + { + group->parts = alts = bptr->next; + bptr->next = bptr->next->next; + alts->next = NULL; + } + else + { + alts->next = bptr->next; + bptr->next = bptr->next->next; + alts = alts->next; + alts->next = NULL; + } + + /* now delink the idx entry */ + for (j = i+1; j < idxlen-1; ++j) + { + idx[j] = idx[j+1]; + } + --idxlen; + } + else + { + bptr = bptr->next; + ++i; + } + } + + /* add group to attachment list */ + for (bptr = msg->content; bptr->next; bptr = bptr->next); + bptr->next = group; + group->next = NULL; + + gptr = safe_calloc(1, sizeof(ATTACHPTR)); + gptr->content = group; + idx[idxlen] = gptr; + update_idx(menu, idx, idxlen++); + + /* add a boundary */ + mutt_generate_boundary(&group->parameter); + + /* if no group desc yet, make one up */ + if (!group->description) + group->description = strdup("unknown alternative group"); + } + menu->redraw = 1; + break; case OP_COMPOSE_ATTACH_FILE: { diff -Pur mutt/doc/manual.xml.head mutt-patch/doc/manual.xml.head --- mutt/doc/manual.xml.head Fri May 5 14:11:57 2006 +++ mutt-patch/doc/manual.xml.head Fri May 5 20:25:11 2006 @@ -5146,6 +5146,23 @@ unalternative_order command. + +Mutt includes some primitive ability to compose multipart/alternative +parts. In the Compose menu, attach the two (or more) alternatives as +usual. For example, attach "invitation.html" and then "invitation.txt". +(You can reorder them using the <move-up> (-) and <move-down> (+) +bindings.) Edit the descriptions, if you wish. Then tag the attachments +that are alternatives, and press the <group-alternatives> (&) binding +to group them together. The separate parts will be replaced by a single +new part with the multipart/alternative type. From this point on, the +alternatives must be manipulated or deleted as a group. + + + +Beware that such messages cannot be postponed. Once two attachments are +grouped as alternatives, they must be sent or lost. + + diff -Pur mutt/functions.h mutt-patch/functions.h --- mutt/functions.h Mon Oct 10 11:21:24 2005 +++ mutt-patch/functions.h Fri May 5 20:22:38 2006 @@ -293,6 +293,9 @@ { "edit-fcc", OP_COMPOSE_EDIT_FCC, "f" }, { "filter-entry", OP_FILTER, "F" }, { "get-attachment", OP_COMPOSE_GET_ATTACHMENT, "G" }, + { "group-alternatives", OP_COMPOSE_GROUP_ALTS, "&" }, + { "move-up", OP_COMPOSE_MOVE_UP, "-" }, + { "move-down", OP_COMPOSE_MOVE_DOWN, "+" }, { "display-toggle-weed", OP_DISPLAY_HEADERS, "h" }, { "ispell", OP_COMPOSE_ISPELL, "i" }, { "print-entry", OP_PRINT, "l" },