Skip to content

Commit

Permalink
send: preserve grouping when recalling and resending messages
Browse files Browse the repository at this point in the history
  • Loading branch information
dcpurton authored and flatcap committed Jan 14, 2022
1 parent 8f895e8 commit 9350145
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 156 deletions.
274 changes: 142 additions & 132 deletions postpone.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,144 @@ SecurityFlags mutt_parse_crypt_hdr(const char *p, bool set_empty_signas, Securit
return flags;
}

/**
* create_tmp_files_for_attachments - Create temporary files for all attachments
* @param fp_body file containing the template
* @param file Allocated buffer for temporary file name
* @param e_new The new email template header
* @param body First body in email or group
* @param protected_headers MIME headers for email template
* @retval 0 Success
* @retval -1 Error
*/
static int create_tmp_files_for_attachments(FILE *fp_body, struct Buffer *file,
struct Email *e_new, struct Body *body,
struct Envelope *protected_headers)
{
struct Body *b = NULL;
struct State s = { 0 };
SecurityFlags sec_type;

s.fp_in = fp_body;

for (b = body; b; b = b->next)
{
if (b->type == TYPE_MULTIPART)
{
if (create_tmp_files_for_attachments(fp_body, file, e_new, b->parts, protected_headers) < 0)
{
return -1;
}
}
else
{
mutt_buffer_reset(file);
if (b->filename)
{
mutt_buffer_strcpy(file, b->filename);
b->d_filename = mutt_str_dup(b->filename);
}
else
{
/* avoid Content-Disposition: header with temporary filename */
b->use_disp = false;
}

/* set up state flags */

s.flags = 0;

if (b->type == TYPE_TEXT)
{
if (mutt_istr_equal("yes",
mutt_param_get(&b->parameter, "x-mutt-noconv")))
{
b->noconv = true;
}
else
{
s.flags |= MUTT_CHARCONV;
b->noconv = false;
}

mutt_param_delete(&b->parameter, "x-mutt-noconv");
}

mutt_adv_mktemp(file);
s.fp_out = mutt_file_fopen(mutt_buffer_string(file), "w");
if (!s.fp_out)
return -1;

if (((WithCrypto & APPLICATION_PGP) != 0) &&
((sec_type = mutt_is_application_pgp(b)) & (SEC_ENCRYPT | SEC_SIGN)))
{
if (sec_type & SEC_ENCRYPT)
{
if (!crypt_valid_passphrase(APPLICATION_PGP))
return -1;
mutt_message(_("Decrypting message..."));
}

if (mutt_body_handler(b, &s) < 0)
{
mutt_error(_("Decryption failed"));
return -1;
}

if ((b == body) && !protected_headers)
{
protected_headers = b->mime_headers;
b->mime_headers = NULL;
}

e_new->security |= sec_type;
b->type = TYPE_TEXT;
mutt_str_replace(&b->subtype, "plain");
mutt_param_delete(&b->parameter, "x-action");
}
else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
((sec_type = mutt_is_application_smime(b)) & (SEC_ENCRYPT | SEC_SIGN)))
{
if (sec_type & SEC_ENCRYPT)
{
if (!crypt_valid_passphrase(APPLICATION_SMIME))
return -1;
crypt_smime_getkeys(e_new->env);
mutt_message(_("Decrypting message..."));
}

if (mutt_body_handler(b, &s) < 0)
{
mutt_error(_("Decryption failed"));
return -1;
}

e_new->security |= sec_type;
b->type = TYPE_TEXT;
mutt_str_replace(&b->subtype, "plain");
}
else
{
mutt_decode_attachment(b, &s);
}

if (mutt_file_fclose(&s.fp_out) != 0)
return -1;

mutt_str_replace(&b->filename, mutt_buffer_string(file));
b->unlink = true;

mutt_stamp_attachment(b);

mutt_body_free(&b->parts);
if (b->email)
b->email->body = NULL; /* avoid dangling pointer */
}
}

return 0;
}

/**
* mutt_prepare_template - Prepare a message template
* @param fp If not NULL, file containing the template
Expand All @@ -371,7 +509,6 @@ int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new,
struct Body *b = NULL;
FILE *fp_body = NULL;
int rc = -1;
struct State s = { 0 };
SecurityFlags sec_type;
struct Envelope *protected_headers = NULL;
struct Buffer *file = NULL;
Expand Down Expand Up @@ -459,143 +596,16 @@ int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new,
}
}

/* We don't need no primary multipart.
* Note: We _do_ preserve messages!
*
* XXX - we don't handle multipart/alternative in any
* smart way when sending messages. However, one may
* consider this a feature. */
if (e_new->body->type == TYPE_MULTIPART)
/* We don't need no primary multipart/mixed. */
if ((e_new->body->type == TYPE_MULTIPART) && mutt_istr_equal(e_new->body->subtype, "mixed"))
e_new->body = mutt_remove_multipart(e_new->body);

s.fp_in = fp_body;

file = mutt_buffer_pool_get();

struct Body *b_previous = NULL;

/* create temporary files for all attachments */
for (b = e_new->body; b; b = b->next)
if (create_tmp_files_for_attachments(fp_body, file, e_new, e_new->body, protected_headers) < 0)
{
/* what follows is roughly a receive-mode variant of
* mutt_get_tmp_attachment () from muttlib.c */

while (b->type == TYPE_MULTIPART)
{
struct Body *b_next = b->next;
b->next = NULL;
b = mutt_remove_multipart(b);
if (!b_previous)
e_new->body = b;
else
b_previous->next = b;
struct Body *b_part = b;
while (b_part->next)
b_part = b_part->next;
b_part->next = b_next;
}

b_previous = b;

mutt_buffer_reset(file);
if (b->filename)
{
mutt_buffer_strcpy(file, b->filename);
b->d_filename = mutt_str_dup(b->filename);
}
else
{
/* avoid Content-Disposition: header with temporary filename */
b->use_disp = false;
}

/* set up state flags */

s.flags = 0;

if (b->type == TYPE_TEXT)
{
if (mutt_istr_equal("yes",
mutt_param_get(&b->parameter, "x-mutt-noconv")))
{
b->noconv = true;
}
else
{
s.flags |= MUTT_CHARCONV;
b->noconv = false;
}

mutt_param_delete(&b->parameter, "x-mutt-noconv");
}

mutt_adv_mktemp(file);
s.fp_out = mutt_file_fopen(mutt_buffer_string(file), "w");
if (!s.fp_out)
goto bail;

if (((WithCrypto & APPLICATION_PGP) != 0) &&
((sec_type = mutt_is_application_pgp(b)) & (SEC_ENCRYPT | SEC_SIGN)))
{
if (sec_type & SEC_ENCRYPT)
{
if (!crypt_valid_passphrase(APPLICATION_PGP))
goto bail;
mutt_message(_("Decrypting message..."));
}

if (mutt_body_handler(b, &s) < 0)
{
mutt_error(_("Decryption failed"));
goto bail;
}

if ((b == e_new->body) && !protected_headers)
{
protected_headers = b->mime_headers;
b->mime_headers = NULL;
}

e_new->security |= sec_type;
b->type = TYPE_TEXT;
mutt_str_replace(&b->subtype, "plain");
mutt_param_delete(&b->parameter, "x-action");
}
else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
((sec_type = mutt_is_application_smime(b)) & (SEC_ENCRYPT | SEC_SIGN)))
{
if (sec_type & SEC_ENCRYPT)
{
if (!crypt_valid_passphrase(APPLICATION_SMIME))
goto bail;
crypt_smime_getkeys(e_new->env);
mutt_message(_("Decrypting message..."));
}

if (mutt_body_handler(b, &s) < 0)
{
mutt_error(_("Decryption failed"));
goto bail;
}

e_new->security |= sec_type;
b->type = TYPE_TEXT;
mutt_str_replace(&b->subtype, "plain");
}
else
mutt_decode_attachment(b, &s);

if (mutt_file_fclose(&s.fp_out) != 0)
goto bail;

mutt_str_replace(&b->filename, mutt_buffer_string(file));
b->unlink = true;

mutt_stamp_attachment(b);

mutt_body_free(&b->parts);
if (b->email)
b->email->body = NULL; /* avoid dangling pointer */
goto bail;
}

const bool c_crypt_protected_headers_read =
Expand Down

0 comments on commit 9350145

Please sign in to comment.