]> granicus.if.org Git - mutt/commitdiff
Change recvattach to allow nested encryption. (see #3728)
authorKevin McCarthy <kevin@8t8.us>
Fri, 11 Aug 2017 01:18:21 +0000 (18:18 -0700)
committerKevin McCarthy <kevin@8t8.us>
Fri, 11 Aug 2017 01:18:21 +0000 (18:18 -0700)
* 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.

attach.c
attach.h
compose.c
protos.h
recvattach.c

index 9b4b649ed290046cf660ba6bf35b11ab01253374..6a12d82f2fefc076e4a1a9c3b3df71368fc738ef 100644 (file)
--- a/attach.c
+++ b/attach.c
@@ -1059,6 +1059,36 @@ void mutt_actx_add_attach (ATTACH_CONTEXT *actx, ATTACHPTR *attach, MUTTMENU *me
   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;
@@ -1070,8 +1100,15 @@ void mutt_actx_free_entries (ATTACH_CONTEXT *actx)
     FREE (&actx->idx[i]->tree);
     FREE (&actx->idx[i]);
   }
-
   actx->idxlen = 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)
@@ -1084,5 +1121,7 @@ void mutt_free_attach_context (ATTACH_CONTEXT **pactx)
   actx = *pactx;
   mutt_actx_free_entries (actx);
   FREE (&actx->idx);
+  FREE (&actx->fp_idx);
+  FREE (&actx->body_idx);
   FREE (pactx);  /* __FREE_CHECKED__ */
 }
index 41d780872c7f06f2db459f65f0165464729b7875..80eed5065b9de183cbc74f133e0434aaceb69fd3 100644 (file)
--- a/attach.h
+++ b/attach.h
 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;
 
 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;
+
+  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_gen_attach_list (ATTACH_CONTEXT *, BODY *, int, int, int);
+void mutt_attach_init (ATTACH_CONTEXT *);
 void mutt_update_tree (ATTACH_CONTEXT *);
 int mutt_view_attachment (FILE*, BODY *, int, HEADER *, ATTACH_CONTEXT *);
 
@@ -60,6 +73,8 @@ 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, MUTTMENU *menu);
+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);
 
index 4da1e5ffc626e327dd8703fe7e70e6de43431729..87bcb47a168dc06c22952921ee83f1ac1af2466d 100644 (file)
--- a/compose.c
+++ b/compose.c
@@ -450,6 +450,38 @@ static int delete_attachment (MUTTMENU *menu, short *idxlen, int x)
   return (0);
 }
 
+static void mutt_gen_compose_attach_list (ATTACH_CONTEXT *actx,
+                                          BODY *m,
+                                          int parent_type,
+                                          int level)
+{
+  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, NULL);
+      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 */
+    }
+  }
+
+  if (level == 0)
+    mutt_update_tree (actx);
+}
+
 static void update_idx (MUTTMENU *menu, ATTACH_CONTEXT *actx, ATTACHPTR *new)
 {
   new->level = (actx->idxlen > 0) ? actx->idx[actx->idxlen-1]->level : 0;
@@ -665,8 +697,8 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
   rd.fcc = fcc;
 
   actx = safe_calloc (sizeof(ATTACH_CONTEXT), 1);
-  mutt_attach_init (msg->content);
-  mutt_gen_attach_list (actx, msg->content, -1, 0, 1);
+  mutt_gen_compose_attach_list (actx, msg->content, -1, 0);
+  mutt_attach_init (actx);
 
   menu = mutt_new_menu (MENU_COMPOSE);
   menu->offset = HDR_ATTACH;
@@ -787,7 +819,7 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
        if (actx->idxlen && actx->idx[actx->idxlen - 1]->content->next)
        {
           mutt_actx_free_entries (actx);
-         mutt_gen_attach_list (actx, msg->content, -1, 0, 1);
+         mutt_gen_compose_attach_list (actx, msg->content, -1, 0);
          menu->data = actx->idx;
          menu->max = actx->idxlen;
        }
index 802cd902c658ff445b017314e2284ff8b61b563e..4f371684174f36fa4bd5d36256b250752c73d36c 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -163,7 +163,6 @@ void mutt_add_to_reference_headers (ENVELOPE *env, ENVELOPE *curenv, LIST ***pp,
 void mutt_adv_mktemp (char *, size_t);
 void mutt_alias_menu (char *, size_t, ALIAS *);
 void mutt_allow_interrupt (int);
-void mutt_attach_init (BODY *);
 void mutt_block_signals (void);
 void mutt_block_signals_system (void);
 int mutt_body_handler (BODY *, STATE *);
index 02e80e84bc648dc51d7e11cd3e3879c99aa589cd..a0d44e1592a7305d9c8660fbc039156bc7f0b279 100644 (file)
@@ -40,6 +40,8 @@
 #include <string.h>
 #include <errno.h>
 
+static void mutt_update_recvattach_menu (ATTACH_CONTEXT *actx, MUTTMENU *menu, int init);
+
 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
 
 #define CHECK_READONLY if (Context->readonly) \
@@ -98,49 +100,6 @@ void mutt_update_tree (ATTACH_CONTEXT *actx)
   }
 }
 
-void mutt_gen_attach_list (ATTACH_CONTEXT *actx,
-                           BODY *m,
-                          int parent_type,
-                          int level,
-                          int compose)
-{
-  ATTACHPTR *new;
-
-  for (; m; m = m->next)
-  {
-    if (m->type == TYPEMULTIPART && m->parts
-       && (compose || (parent_type == -1 && ascii_strcasecmp ("alternative", m->subtype)))
-        && (!(WithCrypto & APPLICATION_PGP) || !mutt_is_multipart_encrypted(m))
-       )
-    {
-      mutt_gen_attach_list (actx, m->parts, m->type, level, compose);
-    }
-    else
-    {
-      new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
-      mutt_actx_add_attach (actx, new, NULL);
-      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 */
-      if (!compose && !m->collapsed &&
-         ((m->type == TYPEMULTIPART
-            && (!(WithCrypto & APPLICATION_PGP)
-                || !mutt_is_multipart_encrypted (m))
-           )
-          || mutt_is_message_type(m->type, m->subtype)))
-      {
-       mutt_gen_attach_list (actx, m->parts, m->type, level + 1, compose);
-      }
-    }
-  }
-
-  if (level == 0)
-    mutt_update_tree (actx);
-}
-
 /* %c = character set: convert?
  * %C = character set
  * %D = deleted flag
@@ -796,26 +755,13 @@ void mutt_print_attachment_list (FILE *fp, int tag, BODY *top)
     print_attachment_list (fp, tag, top, &state);
 }
 
-static void
-mutt_update_attach_index (ATTACH_CONTEXT *actx, BODY *cur, MUTTMENU *menu)
-{
-  mutt_actx_free_entries (actx);
-  mutt_gen_attach_list (actx, cur, -1, 0, 0);
-
-  menu->max  = actx->idxlen;
-  menu->data = actx->idx;
-
-  if (menu->current >= menu->max)
-    menu->current = menu->max - 1;
-  menu_check_recenter (menu);
-  menu->redraw |= REDRAW_INDEX;
-}
-
 
 int
 mutt_attach_display_loop (MUTTMENU *menu, int op, FILE *fp, HEADER *hdr,
                          BODY *cur, ATTACH_CONTEXT *actx, int recv)
 {
+  int i;
+
   do
   {
     switch (op)
@@ -854,7 +800,13 @@ mutt_attach_display_loop (MUTTMENU *menu, int op, FILE *fp, HEADER *hdr,
           immediately */
        mutt_edit_content_type (hdr, actx->idx[menu->current]->content, fp);
         if (recv)
-         mutt_update_attach_index (actx, cur, menu);
+        {
+          /* Editing the content type can rewrite the body structure. */
+          for (i = 0; i < actx->idxlen; i++)
+            actx->idx[i]->content = NULL;
+          mutt_actx_free_entries (actx);
+          mutt_update_recvattach_menu (actx, menu, 1);
+        }
         op = OP_VIEW_ATTACH;
        break;
       /* functions which are passed through from the pager */
@@ -881,6 +833,143 @@ mutt_attach_display_loop (MUTTMENU *menu, int op, FILE *fp, HEADER *hdr,
   return op;
 }
 
+static void mutt_generate_recvattach_list (ATTACH_CONTEXT *actx,
+                                           HEADER *hdr,
+                                           BODY *m,
+                                           FILE *fp,
+                                           int parent_type,
+                                           int level,
+                                           int decrypted)
+{
+  ATTACHPTR *new;
+  BODY *new_body = NULL;
+  FILE *new_fp = NULL;
+  int need_secured, secured;
+
+  for (; m; m = m->next)
+  {
+    need_secured = secured = 0;
+
+    if ((WithCrypto & APPLICATION_SMIME) &&
+        mutt_is_application_smime (m))
+    {
+      need_secured = 1;
+
+      if (!crypt_valid_passphrase (APPLICATION_SMIME))
+        goto decrypt_failed;
+
+      if (hdr->env)
+        crypt_smime_getkeys (hdr->env);
+
+      secured = !crypt_smime_decrypt_mime (fp, &new_fp, m, &new_body);
+
+      /* S/MIME nesting */
+      if ((mutt_is_application_smime (new_body) & SMIMEOPAQUE))
+      {
+        BODY *outer_new_body = new_body;
+        FILE *outer_fp = new_fp;
+
+        new_body = NULL;
+        new_fp = NULL;
+
+        secured = !crypt_smime_decrypt_mime (outer_fp, &new_fp, outer_new_body,
+                                               &new_body);
+
+        mutt_free_body (&outer_new_body);
+        safe_fclose (&outer_fp);
+      }
+
+      if (secured)
+        hdr->security |= SMIMEENCRYPT;
+    }
+
+    if ((WithCrypto & APPLICATION_PGP) &&
+        (mutt_is_multipart_encrypted (m) ||
+         mutt_is_malformed_multipart_pgp_encrypted (m)))
+    {
+      need_secured = 1;
+
+      if (!crypt_valid_passphrase (APPLICATION_PGP))
+        goto decrypt_failed;
+
+      secured = !crypt_pgp_decrypt_mime (fp, &new_fp, m, &new_body);
+
+      if (secured)
+        hdr->security |= PGPENCRYPT;
+    }
+
+    if (need_secured && secured)
+    {
+      mutt_actx_add_fp (actx, new_fp);
+      mutt_actx_add_body (actx, new_body);
+      mutt_generate_recvattach_list (actx, hdr, new_body, new_fp, parent_type, level, 1);
+      continue;
+    }
+
+decrypt_failed:
+    /* Fall through and show the original parts if decryption fails */
+    if (need_secured && !secured)
+      mutt_error _("Can't decrypt encrypted message!");
+
+    /* Strip out the top level multipart */
+    if (m->type == TYPEMULTIPART &&
+        m->parts &&
+        !need_secured &&
+        (parent_type == -1 && ascii_strcasecmp ("alternative", m->subtype)))
+    {
+      mutt_generate_recvattach_list (actx, hdr, m->parts, fp, m->type, level, decrypted);
+    }
+    else
+    {
+      new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
+      mutt_actx_add_attach (actx, new, NULL);
+
+      new->content = m;
+      new->fp = fp;
+      m->aptr = new;
+      new->parent_type = parent_type;
+      new->level = level;
+      new->decrypted = decrypted;
+
+      if (m->type == TYPEMULTIPART ||
+          mutt_is_message_type(m->type, m->subtype))
+      {
+        mutt_generate_recvattach_list (actx, hdr, m->parts, fp, m->type, level + 1, decrypted);
+      }
+    }
+  }
+}
+
+void mutt_attach_init (ATTACH_CONTEXT *actx)
+{
+  int i;
+
+  for (i = 0; i < actx->idxlen; i++)
+  {
+    actx->idx[i]->content->tagged = 0;
+    actx->idx[i]->content->collapsed = 0;
+  }
+}
+
+static void mutt_update_recvattach_menu (ATTACH_CONTEXT *actx, MUTTMENU *menu, int init)
+{
+  if (init)
+    mutt_generate_recvattach_list (actx, actx->hdr, actx->hdr->content,
+                                   actx->root_fp, -1, 0, 0);
+
+  /* TODO: regenerate virtual index */
+  mutt_update_tree (actx);
+
+  menu->max  = actx->idxlen;
+  menu->data = actx->idx;
+
+  if (menu->current >= menu->max)
+    menu->current = menu->max - 1;
+  menu_check_recenter (menu);
+  menu->redraw |= REDRAW_INDEX;
+}
+
+/* TODO: fix this to use the index */
 static void attach_collapse (BODY *b, short collapse, short init, short just_one)
 {
   short i;
@@ -898,17 +987,6 @@ static void attach_collapse (BODY *b, short collapse, short init, short just_one
   }
 }
 
-void mutt_attach_init (BODY *b)
-{
-  for (; b; b = b->next)
-  {
-    b->tagged = 0;
-    b->collapsed = 0;
-    if (b->parts) 
-      mutt_attach_init (b->parts);
-  }
-}
-
 static const char *Function_not_permitted = N_("Function not permitted in attach-message mode.");
 
 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
@@ -923,9 +1001,6 @@ static const char *Function_not_permitted = N_("Function not permitted in attach
 
 void mutt_view_attachments (HEADER *hdr)
 {
-  int secured = 0;
-  int need_secured = 0;
-
   char helpstr[LONG_STRING];
   MUTTMENU *menu;
   BODY *cur = NULL;
@@ -944,66 +1019,6 @@ void mutt_view_attachments (HEADER *hdr)
   if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
     return;
 
-
-  if (WithCrypto && ((hdr->security & ENCRYPT) ||
-                     (mutt_is_application_smime(hdr->content) & SMIMEOPAQUE)))
-  {
-    need_secured  = 1;
-
-    if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase(hdr->security))
-    {
-      mx_close_message (Context, &msg);
-      return;
-    }
-    if ((WithCrypto & APPLICATION_SMIME) && (hdr->security & APPLICATION_SMIME))
-    {
-      if (hdr->env)
-         crypt_smime_getkeys (hdr->env);
-
-      if (mutt_is_application_smime(hdr->content))
-      {
-       secured = ! crypt_smime_decrypt_mime (msg->fp, &fp,
-                                              hdr->content, &cur);
-       
-       /* S/MIME nesting */
-       if ((mutt_is_application_smime (cur) & SMIMEOPAQUE))
-       {
-         BODY *_cur = cur;
-         FILE *_fp = fp;
-         
-         fp = NULL; cur = NULL;
-         secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
-         
-         mutt_free_body (&_cur);
-         safe_fclose (&_fp);
-       }
-      }
-      else
-       need_secured = 0;
-    }
-    if ((WithCrypto & APPLICATION_PGP) && (hdr->security & APPLICATION_PGP))
-    {
-      if (mutt_is_multipart_encrypted(hdr->content) ||
-          mutt_is_malformed_multipart_pgp_encrypted(hdr->content))
-       secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
-      else
-       need_secured = 0;
-    }
-
-    if (need_secured && !secured)
-    {
-      mx_close_message (Context, &msg);
-      mutt_error _("Can't decrypt encrypted message!");
-      return;
-    }
-  }
-  
-  if (!WithCrypto || !need_secured)
-  {
-    fp = msg->fp;
-    cur = hdr->content;
-  }
-
   menu = mutt_new_menu (MENU_ATTACH);
   menu->title = _("Attachments");
   menu->make_entry = attach_entry;
@@ -1012,9 +1027,10 @@ void mutt_view_attachments (HEADER *hdr)
   mutt_push_current_menu (menu);
 
   actx = safe_calloc (sizeof(ATTACH_CONTEXT), 1);
-  mutt_attach_init (cur);
-  attach_collapse (cur, 0, 1, 0);
-  mutt_update_attach_index (actx, cur, menu);
+  actx->hdr = hdr;
+  actx->root_fp = msg->fp;
+  mutt_update_recvattach_menu (actx, menu, 1);
+  mutt_attach_init (actx);
 
   FOREVER
   {
@@ -1050,7 +1066,7 @@ void mutt_view_attachments (HEADER *hdr)
          attach_collapse (actx->idx[menu->current]->content, 1, 0, 1);
         else
          attach_collapse (actx->idx[menu->current]->content, 0, 1, 1);
-        mutt_update_attach_index (actx, cur, menu);
+        mutt_update_recvattach_menu (actx, menu, 0);
         break;
       
       case OP_FORGET_PASSPHRASE:
@@ -1223,7 +1239,11 @@ void mutt_view_attachments (HEADER *hdr)
 
       case OP_EDIT_TYPE:
        mutt_edit_content_type (hdr, actx->idx[menu->current]->content, fp);
-        mutt_update_attach_index (actx, cur, menu);
+        /* Editing the content type can rewrite the body structure. */
+        for (i = 0; i < actx->idxlen; i++)
+          actx->idx[i]->content = NULL;
+        mutt_actx_free_entries (actx);
+        mutt_update_recvattach_menu (actx, menu, 1);
        break;
 
       case OP_EXIT:
@@ -1242,12 +1262,6 @@ void mutt_view_attachments (HEADER *hdr)
 
         mutt_free_attach_context (&actx);
 
-        if (WithCrypto && need_secured && secured)
-       {
-         safe_fclose (&fp);
-         mutt_free_body (&cur);
-       }
-
         mutt_pop_current_menu (menu);
        mutt_menuDestroy  (&menu);
        return;