changeset: 7120:278b6efc6bba
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:18 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/278b6efc6bba

Create ATTACH_CONTEXT to hold attachment index. (see #3728)

Move the idx and idxlen into ATTACH_CONTEXT.  In subsequence patches,
this structure will hold more useful items, such as the virtual index.

The swap out is straightforward, except for:
  * update_idx() in compose.c, which post-increments the idxlen in the
    call and again in the function.
  * mutt_gen_attach_list() which doesn't need to returns the new values.

changeset: 7121:b8bbccd98632
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:19 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/b8bbccd98632

Change helpers functions to pass actx. (see #3728)

Change the pager, compose, recvattach and recvcmd to pass the actx
instead of the individual idx and idxlen parameters.

Separate out the compose menu exit logic to first free the BODY data
and then call the shared actx free function at the bottom.

changeset: 7122:ee1fd4a71a8a
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:20 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/ee1fd4a71a8a

Add helpers to add and remove actx entries. (see #3728)

Use the helper in compose update_idx(), to consolidate the resize
logic and simplify the code.

Separate out the actx "free" routine from a routine to empty out the
idx.  The index regeneration routines should flush and rebuild the
index without having to renerate the actx structure.

changeset: 7123:23ce88ed8961
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:21 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/23ce88ed8961

Change recvattach to allow nested encryption. (see #3728)

* Add a FP and BODY array to the actx.  These are used to allow proper
  cleanup.

* Add HEADER and root_fp entries, to allow for index regeneration.

* Separate out the compose and recvattach index generation functions.

* Change the recvattach index generator to decrypt as encrypted parts
  are found.

changeset: 7124:c7fe290bc3a3
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:22 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/c7fe290bc3a3

Add virtual index to actx. (see #3728)

The virtual index is modeled after the CONTEXT.  Add a CURATTACH
helper to reduce code verbosity.  Store the actx as menu->data.

Simplify and consolidate the recvattach and compose menu update code
inside a function.

Because compose and recvattach share so much code, change compose to
use the virtual index even though it has no collapse/expand
functionality.

changeset: 7125:26e06bd4f29d
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:24 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/26e06bd4f29d

Fix the expand/collapse code to use the virtual index. (see #3728)

Fix the init code to respect OPTDIGESTCOLLAPSE.

changeset: 7126:e6e8b2f1fae3
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:25 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/e6e8b2f1fae3

Fix shared attachment functions. (see #3728)

With nested decryption, the correct FP is associated with the
ATTACHPTR entry.  Also, the BODY entries are not continguous, so the
functions need to iterate over the actx index, not the BODY structure.

changeset: 7127:38855dc0a02a
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:26 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/38855dc0a02a

Fix attachment check_traditional and extract_keys operations. (see #3728)

Add helpers and iterate over the actx->idx instead of the BODY structure.

changeset: 7128:052ad4fcdd6b
user:      Kevin McCarthy <ke...@8t8.us>
date:      Thu Aug 10 18:18:28 2017 -0700
link:      http://dev.mutt.org/hg/mutt/rev/052ad4fcdd6b

Add edit-content-type helper and warning for decrypted attachments. (closes 
#3728)

Regenerating the actx index will overwrite any changes made to a
decrypted attachment.  Change the mutt_edit_content_type() function to
return 1 when a structural change is made.  Add a warning message when
that is the case and a decrypted message was edited, so the user is
not surprised.

Note: mutt_edit_content_type() appeared to regenerate multipart
subparts every time, leading to a memory leak.  I believe this was an
oversite, and it should have regenerated only when there were no
subparts, so have "fixed" this.

diffs (truncated from 3035 to 950 lines):

diff -r 5f034395e53d -r 052ad4fcdd6b attach.c
--- a/attach.c  Wed Aug 09 08:08:24 2017 -0700
+++ b/attach.c  Thu Aug 10 18:18:28 2017 -0700
@@ -330,7 +330,7 @@
 
 /* returns -1 on error, 0 or the return code from mutt_do_pager() on success */
 int mutt_view_attachment (FILE *fp, BODY *a, int flag, HEADER *hdr,
-                         ATTACHPTR **idx, short idxlen)
+                         ATTACH_CONTEXT *actx)
 {
   char tempfile[_POSIX_PATH_MAX] = "";
   char pagerfile[_POSIX_PATH_MAX] = "";
@@ -571,8 +571,7 @@
     info.fp = fp;
     info.bdy = a;
     info.ctx = Context;
-    info.idx = idx;
-    info.idxlen = idxlen;
+    info.actx = actx;
     info.hdr = hdr;
 
     rc = mutt_do_pager (descrip, pagerfile,
@@ -1042,3 +1041,88 @@
     return 0;
   }
 }
+
+void mutt_actx_add_attach (ATTACH_CONTEXT *actx, ATTACHPTR *attach)
+{
+  int i;
+
+  if (actx->idxlen == actx->idxmax)
+  {
+    actx->idxmax += 5;
+    safe_realloc (&actx->idx, sizeof (ATTACHPTR *) * actx->idxmax);
+    safe_realloc (&actx->v2r, sizeof (short) * actx->idxmax);
+    for (i = actx->idxlen; i < actx->idxmax; i++)
+      actx->idx[i] = NULL;
+  }
+
+  actx->idx[actx->idxlen++] = attach;
+}
+
+void mutt_actx_add_fp (ATTACH_CONTEXT *actx, FILE *new_fp)
+{
+  int i;
+
+  if (actx->fp_len == actx->fp_max)
+  {
+    actx->fp_max += 5;
+    safe_realloc (&actx->fp_idx, sizeof (FILE *) * actx->fp_max);
+    for (i = actx->fp_len; i < actx->fp_max; i++)
+      actx->fp_idx[i] = NULL;
+  }
+
+  actx->fp_idx[actx->fp_len++] = new_fp;
+}
+
+void mutt_actx_add_body (ATTACH_CONTEXT *actx, BODY *new_body)
+{
+  int i;
+
+  if (actx->body_len == actx->body_max)
+  {
+    actx->body_max += 5;
+    safe_realloc (&actx->body_idx, sizeof (BODY *) * actx->body_max);
+    for (i = actx->body_len; i < actx->body_max; i++)
+      actx->body_idx[i] = NULL;
+  }
+
+  actx->body_idx[actx->body_len++] = new_body;
+}
+
+void mutt_actx_free_entries (ATTACH_CONTEXT *actx)
+{
+  int i;
+
+  for (i = 0; i < actx->idxlen; i++)
+  {
+    if (actx->idx[i]->content)
+      actx->idx[i]->content->aptr = NULL;
+    FREE (&actx->idx[i]->tree);
+    FREE (&actx->idx[i]);
+  }
+  actx->idxlen = 0;
+  actx->vcount = 0;
+
+  for (i = 0; i < actx->fp_len; i++)
+    safe_fclose (&actx->fp_idx[i]);
+  actx->fp_len = 0;
+
+  for (i = 0; i < actx->body_len; i++)
+    mutt_free_body (&actx->body_idx[i]);
+  actx->body_len = 0;
+}
+
+void mutt_free_attach_context (ATTACH_CONTEXT **pactx)
+{
+  ATTACH_CONTEXT *actx;
+
+  if (!pactx || !*pactx)
+    return;
+
+  actx = *pactx;
+  mutt_actx_free_entries (actx);
+  FREE (&actx->idx);
+  FREE (&actx->v2r);
+  FREE (&actx->fp_idx);
+  FREE (&actx->body_idx);
+  FREE (pactx);  /* __FREE_CHECKED__ */
+}
diff -r 5f034395e53d -r 052ad4fcdd6b attach.h
--- a/attach.h  Wed Aug 09 08:08:24 2017 -0700
+++ b/attach.h  Thu Aug 10 18:18:28 2017 -0700
@@ -26,31 +26,58 @@
 typedef struct attachptr
 {
   BODY *content;
+  FILE *fp;                   /* used in the recvattach menu. */
   int parent_type;
   char *tree;
   int level;
   int num;
   unsigned int unowned : 1;   /* don't unlink on detach */
+  unsigned int decrypted : 1;   /* not part of message as stored in the 
hdr->content. */
 } ATTACHPTR;
 
-ATTACHPTR **mutt_gen_attach_list (BODY *, int, ATTACHPTR **, short *, short *,
-                                  int, int);
-void mutt_update_tree (ATTACHPTR **, short);
-int mutt_view_attachment (FILE*, BODY *, int, HEADER *, ATTACHPTR **, short);
+typedef struct attach_ctx
+{
+  HEADER *hdr;          /* used by recvattach for updating */
+  FILE *root_fp;        /* used by recvattach for updating */
+
+  ATTACHPTR **idx;
+  short idxlen;
+  short idxmax;
+
+  short *v2r;             /* mapping from virtual to real attachment */
+  short vcount;           /* the number of virtual attachments */
+
+  FILE **fp_idx;        /* Extra FILE* used for decryption */
+  short fp_len;
+  short fp_max;
+
+  BODY **body_idx;      /* Extra BODY* used for decryption */
+  short body_len;
+  short body_max;
+} ATTACH_CONTEXT;
+
+void mutt_attach_init (ATTACH_CONTEXT *);
+void mutt_update_tree (ATTACH_CONTEXT *);
+int mutt_view_attachment (FILE*, BODY *, int, HEADER *, ATTACH_CONTEXT *);
 
 int mutt_tag_attach (MUTTMENU *menu, int n, int m);
-int mutt_attach_display_loop (MUTTMENU *menu, int op, FILE *fp, HEADER *hdr,
-                             BODY *cur, ATTACHPTR ***idxp, short *idxlen, 
short *idxmax,
-                             int recv);
+int mutt_attach_display_loop (MUTTMENU *menu, int op, HEADER *hdr,
+                             ATTACH_CONTEXT *acvtx, int recv);
 
 
-void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr, 
MUTTMENU *menu);
-void mutt_pipe_attachment_list (FILE *fp, int tag, BODY *top, int filter);
-void mutt_print_attachment_list (FILE *fp, int tag, BODY *top);
+void mutt_save_attachment_list (ATTACH_CONTEXT *actx, FILE *fp, int tag, BODY 
*top, HEADER *hdr, MUTTMENU *menu);
+void mutt_pipe_attachment_list (ATTACH_CONTEXT *actx, FILE *fp, int tag, BODY 
*top, int filter);
+void mutt_print_attachment_list (ATTACH_CONTEXT *actx, FILE *fp, int tag, BODY 
*top);
 
-void mutt_attach_bounce (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
-void mutt_attach_resend (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
-void mutt_attach_forward (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
-void mutt_attach_reply (FILE *, HEADER *, ATTACHPTR **, short, BODY *, int);
+void mutt_attach_bounce (FILE *, HEADER *, ATTACH_CONTEXT *, BODY *);
+void mutt_attach_resend (FILE *, HEADER *, ATTACH_CONTEXT *, BODY *);
+void mutt_attach_forward (FILE *, HEADER *, ATTACH_CONTEXT *, BODY *);
+void mutt_attach_reply (FILE *, HEADER *, ATTACH_CONTEXT *, BODY *, int);
+
+void mutt_actx_add_attach (ATTACH_CONTEXT *actx, ATTACHPTR *attach);
+void mutt_actx_add_fp (ATTACH_CONTEXT *actx, FILE *new_fp);
+void mutt_actx_add_body (ATTACH_CONTEXT *actx, BODY *new_body);
+void mutt_actx_free_entries (ATTACH_CONTEXT *actx);
+void mutt_free_attach_context (ATTACH_CONTEXT **pactx);
 
 #endif /* _ATTACH_H_ */
diff -r 5f034395e53d -r 052ad4fcdd6b browser.c
--- a/browser.c Wed Aug 09 08:08:24 2017 -0700
+++ b/browser.c Thu Aug 10 18:18:28 2017 -0700
@@ -1275,7 +1275,7 @@
          b = mutt_make_file_attach (buf);
          if (b != NULL)
          {
-           mutt_view_attachment (NULL, b, MUTT_REGULAR, NULL, NULL, 0);
+           mutt_view_attachment (NULL, b, MUTT_REGULAR, NULL, NULL);
            mutt_free_body (&b);
            menu->redraw = REDRAW_FULL;
          }
diff -r 5f034395e53d -r 052ad4fcdd6b commands.c
--- a/commands.c        Wed Aug 09 08:08:24 2017 -0700
+++ b/commands.c        Thu Aug 10 18:18:28 2017 -0700
@@ -878,7 +878,13 @@
   mutt_message ("Mutt %s (%s)", MUTT_VERSION, ReleaseDate);
 }
 
-void mutt_edit_content_type (HEADER *h, BODY *b, FILE *fp)
+/*
+ * Returns:
+ *   1 when a structural change is made.
+ *     recvattach requires this to know when to regenerate the actx.
+ *   0 otherwise.
+ */
+int mutt_edit_content_type (HEADER *h, BODY *b, FILE *fp)
 {
   char buf[LONG_STRING];
   char obuf[LONG_STRING];
@@ -890,6 +896,7 @@
 
   short charset_changed = 0;
   short type_changed = 0;
+  short structure_changed = 0;
   
   cp = mutt_get_parameter ("charset", b->parameter);
   strfcpy (charset, NONULL (cp), sizeof (charset));
@@ -911,7 +918,7 @@
   
   if (mutt_get_field ("Content-Type: ", buf, sizeof (buf), 0) != 0 ||
       buf[0] == 0)
-    return;
+    return 0;
   
   /* clean up previous junk */
   mutt_free_parameter (&b->parameter);
@@ -952,15 +959,22 @@
   b->force_charset |= charset_changed ? 1 : 0;
 
   if (!is_multipart (b) && b->parts)
+  {
+    structure_changed = 1;
     mutt_free_body (&b->parts);
+  }
   if (!mutt_is_message_type (b->type, b->subtype) && b->hdr)
   {
+    structure_changed = 1;
     b->hdr->content = NULL;
     mutt_free_header (&b->hdr);
   }
 
-  if (fp && (is_multipart (b) || mutt_is_message_type (b->type, b->subtype)))
+  if (fp && !b->parts && (is_multipart (b) || mutt_is_message_type (b->type, 
b->subtype)))
+  {
+    structure_changed = 1;
     mutt_parse_part (fp, b);
+  }
   
   if (WithCrypto && h)
   {
@@ -969,6 +983,8 @@
 
     h->security |= crypt_query (b);
   }
+
+  return structure_changed;
 }
 
 
diff -r 5f034395e53d -r 052ad4fcdd6b compose.c
--- a/compose.c Wed Aug 09 08:08:24 2017 -0700
+++ b/compose.c Thu Aug 10 18:18:28 2017 -0700
@@ -46,8 +46,9 @@
 
 static const char* There_are_no_attachments = N_("There are no attachments.");
 
-#define CHECK_COUNT if (idxlen == 0) { mutt_error _(There_are_no_attachments); 
break; }
+#define CHECK_COUNT if (actx->idxlen == 0) { mutt_error 
_(There_are_no_attachments); break; }
 
+#define CURATTACH actx->idx[actx->v2r[menu->current]]
 
 
 enum
@@ -170,8 +171,10 @@
 
 static void snd_entry (char *b, size_t blen, MUTTMENU *menu, int num)
 {
+  ATTACH_CONTEXT *actx = (ATTACH_CONTEXT *)menu->data;
+
   mutt_FormatString (b, blen, 0, MuttIndexWindow->cols, NONULL (AttachFormat), 
mutt_attach_fmt,
-           (unsigned long)(((ATTACHPTR **) menu->data)[num]),
+           (unsigned long)(actx->idx[actx->v2r[num]]),
            MUTT_FORMAT_STAT_FILE | MUTT_FORMAT_ARROWCURSOR);
 }
 
@@ -305,16 +308,16 @@
 #endif /* MIXMASTER */
 
 static int
-check_attachments(ATTACHPTR **idx, short idxlen)
+check_attachments(ATTACH_CONTEXT *actx)
 {
   int i, r;
   struct stat st;
   char pretty[_POSIX_PATH_MAX], msg[_POSIX_PATH_MAX + SHORT_STRING];
 
-  for (i = 0; i < idxlen; i++)
+  for (i = 0; i < actx->idxlen; i++)
   {
-    strfcpy(pretty, idx[i]->content->filename, sizeof(pretty));
-    if(stat(idx[i]->content->filename, &st) != 0)
+    strfcpy(pretty, actx->idx[i]->content->filename, sizeof(pretty));
+    if(stat(actx->idx[i]->content->filename, &st) != 0)
     {
       mutt_pretty_mailbox(pretty, sizeof (pretty));
       mutt_error(_("%s [#%d] no longer exists!"),
@@ -322,14 +325,14 @@
       return -1;
     }
     
-    if(idx[i]->content->stamp < st.st_mtime)
+    if(actx->idx[i]->content->stamp < st.st_mtime)
     {
       mutt_pretty_mailbox(pretty, sizeof (pretty));
       snprintf(msg, sizeof(msg), _("%s [#%d] modified. Update encoding?"),
               pretty, i+1);
       
       if((r = mutt_yesorno(msg, MUTT_YES)) == MUTT_YES)
-       mutt_update_encoding(idx[i]->content);
+       mutt_update_encoding(actx->idx[i]->content);
       else if(r == -1)
        return -1;
     }
@@ -414,52 +417,102 @@
   mutt_paddstr (W, buf);
 }
 
-static int delete_attachment (MUTTMENU *menu, short *idxlen, int x)
+static int delete_attachment (ATTACH_CONTEXT *actx, int x)
 {
-  ATTACHPTR **idx = (ATTACHPTR **) menu->data;
+  ATTACHPTR **idx = actx->idx;
+  int rindex = actx->v2r[x];
   int y;
 
-  menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
-
-  if (x == 0 && menu->max == 1)
+  if (rindex == 0 && actx->idxlen == 1)
   {
     mutt_error _("You may not delete the only attachment.");
-    idx[x]->content->tagged = 0;
+    idx[rindex]->content->tagged = 0;
     return (-1);
   }
 
-  for (y = 0; y < *idxlen; y++)
+  for (y = 0; y < actx->idxlen; y++)
   {
-    if (idx[y]->content->next == idx[x]->content)
+    if (idx[y]->content->next == idx[rindex]->content)
     {
-      idx[y]->content->next = idx[x]->content->next;
+      idx[y]->content->next = idx[rindex]->content->next;
       break;
     }
   }
 
-  idx[x]->content->next = NULL;
-  idx[x]->content->parts = NULL;
-  mutt_free_body (&(idx[x]->content));
-  FREE (&idx[x]->tree);
-  FREE (&idx[x]);
-  for (; x < *idxlen - 1; x++)
-    idx[x] = idx[x+1];
-  idx[*idxlen - 1] = NULL;
-  menu->max = --(*idxlen);
-  
+  idx[rindex]->content->next = NULL;
+  idx[rindex]->content->parts = NULL;
+  mutt_free_body (&(idx[rindex]->content));
+  FREE (&idx[rindex]->tree);
+  FREE (&idx[rindex]);
+  for (; rindex < actx->idxlen - 1; rindex++)
+    idx[rindex] = idx[rindex+1];
+  idx[actx->idxlen - 1] = NULL;
+  actx->idxlen--;
+
   return (0);
 }
 
-static void update_idx (MUTTMENU *menu, ATTACHPTR **idx, short idxlen)
+static void mutt_gen_compose_attach_list (ATTACH_CONTEXT *actx,
+                                          BODY *m,
+                                          int parent_type,
+                                          int level)
 {
-  idx[idxlen]->level = (idxlen > 0) ? idx[idxlen-1]->level : 0;
-  if (idxlen)
-    idx[idxlen - 1]->content->next = idx[idxlen]->content;
-  idx[idxlen]->content->aptr = idx[idxlen];
-  menu->current = idxlen++;
-  mutt_update_tree (idx, idxlen);
-  menu->max = idxlen;
-  return;
+  ATTACHPTR *new;
+
+  for (; m; m = m->next)
+  {
+    if (m->type == TYPEMULTIPART && m->parts
+        && (!(WithCrypto & APPLICATION_PGP) || !mutt_is_multipart_encrypted(m))
+       )
+    {
+      mutt_gen_compose_attach_list (actx, m->parts, m->type, level);
+    }
+    else
+    {
+      new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
+      mutt_actx_add_attach (actx, new);
+      new->content = m;
+      m->aptr = new;
+      new->parent_type = parent_type;
+      new->level = level;
+
+      /* We don't support multipart messages in the compose menu yet */
+    }
+  }
+}
+
+static void mutt_update_compose_menu (ATTACH_CONTEXT *actx, MUTTMENU *menu, 
int init)
+{
+  if (init)
+  {
+    mutt_gen_compose_attach_list (actx, actx->hdr->content, -1, 0);
+    mutt_attach_init (actx);
+    menu->data = actx;
+  }
+
+  mutt_update_tree (actx);
+
+  menu->max = actx->vcount;
+  if (menu->max)
+  {
+    if (menu->current >= menu->max)
+      menu->current = menu->max - 1;
+  }
+  else
+    menu->current = 0;
+
+  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
+}
+
+static void update_idx (MUTTMENU *menu, ATTACH_CONTEXT *actx, ATTACHPTR *new)
+{
+  new->level = (actx->idxlen > 0) ? actx->idx[actx->idxlen-1]->level : 0;
+  if (actx->idxlen)
+    actx->idx[actx->idxlen - 1]->content->next = new->content;
+  new->content->aptr = new;
+  mutt_actx_add_attach (actx, new);
+  mutt_update_compose_menu (actx, menu, 0);
+  menu->current = actx->vcount - 1;
 }
 
 
@@ -476,11 +529,12 @@
 {
   size_t s;
   unsigned short i;
-  ATTACHPTR **idx = menu->data;
+  ATTACH_CONTEXT *actx = menu->data;
+  ATTACHPTR **idx = actx->idx;
   CONTENT *info;
   BODY *b;
   
-  for (i = 0, s = 0; i < menu->max; i++)
+  for (i = 0, s = 0; i < actx->idxlen; i++)
   {
     b = idx[i]->content;
 
@@ -646,9 +700,8 @@
   char buf[LONG_STRING];
   char fname[_POSIX_PATH_MAX];
   MUTTMENU *menu;
-  ATTACHPTR **idx = NULL;
-  short idxlen = 0;
-  short idxmax = 0;
+  ATTACH_CONTEXT *actx;
+  ATTACHPTR *new;
   int i, close = 0;
   int r = -1;          /* return value */
   int op = 0;
@@ -665,20 +718,19 @@
   rd.msg = msg;
   rd.fcc = fcc;
 
-  mutt_attach_init (msg->content);
-  idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
-
   menu = mutt_new_menu (MENU_COMPOSE);
   menu->offset = HDR_ATTACH;
-  menu->max = idxlen;
   menu->make_entry = snd_entry;
   menu->tag = mutt_tag_attach;
-  menu->data = idx;
   menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, 
ComposeHelp);
   menu->custom_menu_redraw = compose_menu_redraw;
   menu->redraw_data = &rd;
   mutt_push_current_menu (menu);
 
+  actx = safe_calloc (sizeof(ATTACH_CONTEXT), 1);
+  actx->hdr = msg;
+  mutt_update_compose_menu (actx, menu, 1);
+
   while (loop)
   {
     switch (op = mutt_menuLoop (menu))
@@ -784,17 +836,10 @@
        mutt_update_encoding (msg->content);
 
        /* attachments may have been added */
-       if (idxlen && idx[idxlen - 1]->content->next)
+       if (actx->idxlen && actx->idx[actx->idxlen - 1]->content->next)
        {
-         for (i = 0; i < idxlen; i++)
-          {
-            FREE (&idx[i]->tree);
-           FREE (&idx[i]);
-          }
-         idxlen = 0;
-         idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 
0, 1);
-         menu->data = idx;
-         menu->max = idxlen;
+          mutt_actx_free_entries (actx);
+          mutt_update_compose_menu (actx, menu, 1);
        }
 
         menu->redraw = REDRAW_FULL;
@@ -805,24 +850,19 @@
 
       case OP_COMPOSE_ATTACH_KEY:
         if (!(WithCrypto & APPLICATION_PGP))
-          break;       
-       if (idxlen == idxmax)
-        {
-         safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5));
-         menu->data = idx;
-       }
-       
-       idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
-       if ((idx[idxlen]->content = crypt_pgp_make_key_attachment(NULL)) != 
NULL)
+          break;
+
+       new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
+       if ((new->content = crypt_pgp_make_key_attachment(NULL)) != NULL)
        {
-         update_idx (menu, idx, idxlen++);
+         update_idx (menu, actx, new);
          menu->redraw |= REDRAW_INDEX;
        }
        else
-         FREE (&idx[idxlen]);
+         FREE (&new);
 
        menu->redraw |= REDRAW_STATUS;
-       
+
         mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
         break;
 
@@ -841,32 +881,26 @@
              *fname == '\0')
            break;
 
-         if (idxlen + numfiles >= idxmax)
-         {
-           safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + 
numfiles));
-           menu->data = idx;
-         }
-
          error = 0;
          if (numfiles > 1)
            mutt_message _("Attaching selected files...");
          for (i = 0; i < numfiles; i++)
          {
            char *att = files[i];
-           idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
-            idx[idxlen]->unowned = 1;
-           idx[idxlen]->content = mutt_make_file_attach (att);
-           if (idx[idxlen]->content != NULL)
-             update_idx (menu, idx, idxlen++);
+           new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
+            new->unowned = 1;
+           new->content = mutt_make_file_attach (att);
+           if (new->content != NULL)
+             update_idx (menu, actx, new);
            else
            {
              error = 1;
              mutt_error (_("Unable to attach %s!"), att);
-             FREE (&idx[idxlen]);
+             FREE (&new);
            }
             FREE (&files[i]);
          }
-         
+
          FREE (&files);
          if (!error) mutt_clear_error ();
 
@@ -925,7 +959,7 @@
 
          this = Context; /* remember current folder and sort methods*/
          oldSort = Sort; oldSortAux = SortAux;
-         
+
          Context = ctx;
          set_option(OPTATTACHMSG);
          mutt_message _("Tag the messages you want to attach!");
@@ -943,25 +977,19 @@
            break;
          }
 
-         if (idxlen + Context->tagged >= idxmax)
-         {
-           safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + 
Context->tagged));
-           menu->data = idx;
-         }
-
          for (i = 0; i < Context->msgcount; i++)
          {
            h = Context->hdrs[i];
            if (h->tagged)
            {
-             idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
-             idx[idxlen]->content = mutt_make_message_attach (Context, h, 1);
-             if (idx[idxlen]->content != NULL)
-               update_idx (menu, idx, idxlen++);
+             new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
+             new->content = mutt_make_message_attach (Context, h, 1);
+             if (new->content != NULL)
+               update_idx (menu, actx, new);
              else
              {
                mutt_error _("Unable to attach!");
-               FREE (&idx[idxlen]);
+               FREE (&new);
              }
            }
          }
@@ -984,38 +1012,27 @@
 
       case OP_DELETE:
        CHECK_COUNT;
-        if (idx[menu->current]->unowned)
-          idx[menu->current]->content->unlink = 0;
-       if (delete_attachment (menu, &idxlen, menu->current) == -1)
+        if (CURATTACH->unowned)
+          CURATTACH->content->unlink = 0;
+       if (delete_attachment (actx, menu->current) == -1)
          break;
-       mutt_update_tree (idx, idxlen);
-       if (idxlen)
-       {
-         if (menu->current > idxlen - 1)
-           menu->current = idxlen - 1;
-       }
-       else
-         menu->current = 0;
+       mutt_update_compose_menu (actx, menu, 0);
+       if (menu->current == 0)
+         msg->content = actx->idx[0]->content;
 
-       if (menu->current == 0)
-         msg->content = idx[0]->content;
-
-        menu->redraw |= REDRAW_STATUS;
         mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
         break;
 
-#define CURRENT idx[menu->current]->content
-      
       case OP_COMPOSE_TOGGLE_RECODE:
-      {      
+      {
         CHECK_COUNT;
-        if (!mutt_is_text_part (CURRENT))
+        if (!mutt_is_text_part (CURATTACH->content))
         {
          mutt_error (_("Recoding only affects text attachments."));
          break;
        }
-        CURRENT->noconv = !CURRENT->noconv;
-        if (CURRENT->noconv)
+        CURATTACH->content->noconv = !CURATTACH->content->noconv;
+        if (CURATTACH->content->noconv)
          mutt_message (_("The current attachment won't be converted."));
         else
          mutt_message (_("The current attachment will be converted."));
@@ -1023,18 +1040,17 @@
         mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
         break;
       }
-#undef CURRENT
 
       case OP_COMPOSE_EDIT_DESCRIPTION:
        CHECK_COUNT;
        strfcpy (buf,
-                idx[menu->current]->content->description ?
-                idx[menu->current]->content->description : "",
+                CURATTACH->content->description ?
+                CURATTACH->content->description : "",
                 sizeof (buf));
        /* header names should not be translated */
        if (mutt_get_field ("Description: ", buf, sizeof (buf), 0) == 0)
        {
-         mutt_str_replace (&idx[menu->current]->content->description, buf);
+         mutt_str_replace (&CURATTACH->content->description, buf);
          menu->redraw = REDRAW_CURRENT;
        }
         mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
@@ -1054,7 +1070,7 @@
        }
         else
         {
-          mutt_update_encoding(idx[menu->current]->content);
+          mutt_update_encoding(CURATTACH->content);
          menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
        }
         mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
@@ -1062,17 +1078,17 @@
       
       case OP_COMPOSE_TOGGLE_DISPOSITION:
        /* toggle the content-disposition between inline/attachment */
-       idx[menu->current]->content->disposition = 
(idx[menu->current]->content->disposition == DISPINLINE) ? DISPATTACH : 
DISPINLINE;
+       CURATTACH->content->disposition = (CURATTACH->content->disposition == 
DISPINLINE) ? DISPATTACH : DISPINLINE;
        menu->redraw = REDRAW_CURRENT;
        break;
 
       case OP_EDIT_TYPE:
        CHECK_COUNT;
         {
-         mutt_edit_content_type (NULL, idx[menu->current]->content, NULL);
+         mutt_edit_content_type (NULL, CURATTACH->content, NULL);
 
          /* this may have been a change to text/something */
-         mutt_update_encoding (idx[menu->current]->content);
+         mutt_update_encoding (CURATTACH->content);
 
          menu->redraw = REDRAW_CURRENT;
        }
@@ -1081,14 +1097,14 @@
 
       case OP_COMPOSE_EDIT_ENCODING:
        CHECK_COUNT;
-       strfcpy (buf, ENCODING (idx[menu->current]->content->encoding),
+       strfcpy (buf, ENCODING (CURATTACH->content->encoding),
                                                              sizeof (buf));
        if (mutt_get_field ("Content-Transfer-Encoding: ", buf,
                                            sizeof (buf), 0) == 0 && buf[0])
        {
          if ((i = mutt_check_encoding (buf)) != ENCOTHER && i != ENCUUENCODED)
          {
-           idx[menu->current]->content->encoding = i;
+           CURATTACH->content->encoding = i;
            menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
            mutt_clear_error();
          }
@@ -1104,7 +1120,7 @@
         * users an opportunity to change settings from the ":" prompt.
         */
       
-        if(check_attachments(idx, idxlen) != 0)
+        if(check_attachments(actx) != 0)
         {
          menu->redraw = REDRAW_FULL;
          break;
@@ -1131,15 +1147,15 @@
 
       case OP_COMPOSE_EDIT_FILE:
        CHECK_COUNT;
-       mutt_edit_file (NONULL(Editor), idx[menu->current]->content->filename);
-       mutt_update_encoding (idx[menu->current]->content);
+       mutt_edit_file (NONULL(Editor), CURATTACH->content->filename);
+       mutt_update_encoding (CURATTACH->content);
        menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
         mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
        break;
 
       case OP_COMPOSE_TOGGLE_UNLINK:
        CHECK_COUNT;
-       idx[menu->current]->content->unlink = 
!idx[menu->current]->content->unlink;
+       CURATTACH->content->unlink = !CURATTACH->content->unlink;
 
 #if 0
         /* OPTRESOLVE is otherwise ignored on this menu.
@@ -1165,7 +1181,7 @@
          }
          menu->redraw = REDRAW_FULL;
        }
-        else if (mutt_get_tmp_attachment(idx[menu->current]->content) == 0)
+        else if (mutt_get_tmp_attachment(CURATTACH->content) == 0)
          menu->redraw = REDRAW_CURRENT;
 
         /* No send2hook since this doesn't change the message. */
@@ -1177,10 +1193,10 @@
           int ret;
 
           CHECK_COUNT;
-          if (idx[menu->current]->content->d_filename)
-            src = idx[menu->current]->content->d_filename;
+          if (CURATTACH->content->d_filename)
+            src = CURATTACH->content->d_filename;
           else
-            src = idx[menu->current]->content->filename;
+            src = CURATTACH->content->filename;
           strfcpy (fname, mutt_basename (NONULL (src)), sizeof (fname));
           ret = mutt_get_field (_("Send attachment with name: "),
                                 fname, sizeof (fname), MUTT_FILE);
@@ -1190,7 +1206,7 @@
              * As opposed to RENAME_FILE, we don't check fname[0] because it's
              * valid to set an empty string here, to erase what was set
              */
-            mutt_str_replace (&idx[menu->current]->content->d_filename, fname);
+            mutt_str_replace (&CURATTACH->content->d_filename, fname);
             menu->redraw = REDRAW_CURRENT;
           }
         }
@@ -1198,12 +1214,12 @@
 
       case OP_COMPOSE_RENAME_FILE:
        CHECK_COUNT;
-       strfcpy (fname, idx[menu->current]->content->filename, sizeof (fname));
+       strfcpy (fname, CURATTACH->content->filename, sizeof (fname));
        mutt_pretty_mailbox (fname, sizeof (fname));
        if (mutt_get_field (_("Rename to: "), fname, sizeof (fname), MUTT_FILE)
                                                        == 0 && fname[0])
        {
-         if (stat(idx[menu->current]->content->filename, &st) == -1)
+         if (stat(CURATTACH->content->filename, &st) == -1)
          {
             /* L10N:
                "stat" is a system call. Do "man 2 stat" for more information. 
*/
@@ -1212,14 +1228,14 @@
          }
 
          mutt_expand_path (fname, sizeof (fname));
-         if(mutt_rename_file (idx[menu->current]->content->filename, fname))
+         if(mutt_rename_file (CURATTACH->content->filename, fname))
            break;
          
-         mutt_str_replace (&idx[menu->current]->content->filename, fname);
+         mutt_str_replace (&CURATTACH->content->filename, fname);
          menu->redraw = REDRAW_CURRENT;
 
-         if(idx[menu->current]->content->stamp >= st.st_mtime)
-           mutt_stamp_attachment(idx[menu->current]->content);
+         if(CURATTACH->content->stamp >= st.st_mtime)
+           mutt_stamp_attachment(CURATTACH->content);
          
        }
         mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
@@ -1256,37 +1272,33 @@
            mutt_error (_("Unknown Content-Type %s"), type);
            continue;
          }
-         if (idxlen == idxmax)
-         {
-           safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5));
-           menu->data = idx;
-         }
 
-         idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
+         new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
          /* Touch the file */
          if (!(fp = safe_fopen (fname, "w")))
          {
            mutt_error (_("Can't create file %s"), fname);
-           FREE (&idx[idxlen]);
+           FREE (&new);
            continue;
          }
          safe_fclose (&fp);
 
-         if ((idx[idxlen]->content = mutt_make_file_attach (fname)) == NULL)
+         if ((new->content = mutt_make_file_attach (fname)) == NULL)
          {
            mutt_error _("What we have here is a failure to make an 
attachment");
+            FREE (&new);
            continue;
          }
-         update_idx (menu, idx, idxlen++);
+         update_idx (menu, actx, new);
 
-         idx[menu->current]->content->type = itype;
-         mutt_str_replace (&idx[menu->current]->content->subtype, p);
-         idx[menu->current]->content->unlink = 1;
+         CURATTACH->content->type = itype;
+         mutt_str_replace (&CURATTACH->content->subtype, p);
+         CURATTACH->content->unlink = 1;
          menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
 
-         if (mutt_compose_attachment (idx[menu->current]->content))
+         if (mutt_compose_attachment (CURATTACH->content))
          {
-           mutt_update_encoding (idx[menu->current]->content);
+           mutt_update_encoding (CURATTACH->content);
            menu->redraw = REDRAW_FULL;
          }
        }
@@ -1295,9 +1307,9 @@
 
       case OP_COMPOSE_EDIT_MIME:
        CHECK_COUNT;
-       if (mutt_edit_attachment (idx[menu->current]->content))
+       if (mutt_edit_attachment (CURATTACH->content))
        {
-         mutt_update_encoding (idx[menu->current]->content);
+         mutt_update_encoding (CURATTACH->content);
          menu->redraw = REDRAW_FULL;
        }
         mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
@@ -1306,27 +1318,27 @@
       case OP_VIEW_ATTACH:
       case OP_DISPLAY_HEADERS:
        CHECK_COUNT;
-       mutt_attach_display_loop (menu, op, NULL, NULL, NULL, &idx, &idxlen, 
NULL, 0);
+       mutt_attach_display_loop (menu, op, NULL, actx, 0);
        menu->redraw = REDRAW_FULL;
         /* no send2hook, since this doesn't modify the message */
        break;
 
       case OP_SAVE:
        CHECK_COUNT;
-       mutt_save_attachment_list (NULL, menu->tagprefix, menu->tagprefix ?  
msg->content : idx[menu->current]->content, NULL, menu);
+       mutt_save_attachment_list (actx, NULL, menu->tagprefix, 
CURATTACH->content, NULL, menu);
         /* no send2hook, since this doesn't modify the message */
        break;
 
       case OP_PRINT:
        CHECK_COUNT;
-       mutt_print_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? 
msg->content : idx[menu->current]->content);
+       mutt_print_attachment_list (actx, NULL, menu->tagprefix, 
CURATTACH->content);
         /* no send2hook, since this doesn't modify the message */
        break;
 
       case OP_PIPE:
       case OP_FILTER:
         CHECK_COUNT;
-       mutt_pipe_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? 
msg->content : idx[menu->current]->content, op == OP_FILTER);
+       mutt_pipe_attachment_list (actx, NULL, menu->tagprefix, 
CURATTACH->content, op == OP_FILTER);
        if (op == OP_FILTER) /* cte might have changed */
          menu->redraw = menu->tagprefix ? REDRAW_FULL : REDRAW_CURRENT;

Reply via email to