summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin McCarthy <kevin@8t8.us>2017-08-10 18:18:21 -0700
committerKevin McCarthy <kevin@8t8.us>2017-08-10 18:18:21 -0700
commit2fd6f99bea1337e1b490a9056033fe0151f22ddc (patch)
tree58ed4ac34b12270b6c495d8f20ef805b9d376481
parent7a002ec117886669ba9e1f19bed506847b730c9d (diff)
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.
-rw-r--r--attach.c41
-rw-r--r--attach.h17
-rw-r--r--compose.c38
-rw-r--r--protos.h1
-rw-r--r--recvattach.c302
5 files changed, 249 insertions, 150 deletions
diff --git a/attach.c b/attach.c
index 9b4b649e..6a12d82f 100644
--- 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__ */
}
diff --git a/attach.h b/attach.h
index 41d78087..80eed506 100644
--- a/attach.h
+++ b/attach.h
@@ -26,21 +26,34 @@
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);
diff --git a/compose.c b/compose.c
index 4da1e5ff..87bcb47a 100644
--- 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;
}
diff --git a/protos.h b/protos.h
index 802cd902..4f371684 100644
--- 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 *);
diff --git a/recvattach.c b/recvattach.c
index 02e80e84..a0d44e15 100644
--- a/recvattach.c
+++ b/recvattach.c
@@ -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;