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" },