From: Kevin McCarthy Date: Fri, 26 Apr 2019 02:41:04 +0000 (-0700) Subject: Add $forward_attachments quadoption for inline-forward mode X-Git-Tag: 2019-10-25~221^2~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4cccca17e35d654e7beb32e9bac86c4bbda58b77;p=neomutt Add $forward_attachments quadoption for inline-forward mode When set or answered yes, non text-decodable parts will be attached to the new message. The default value is "ask-yes", because I believe this is something people will want to use, and should be made aware of the new possible behavior. The option presents a nice middle ground between previous inline-forwarding behavior (where all the non-text parts were dropped), and $mime_forward where the entire email was included as an attachment. This was previously difficult to achieve, but after the recv-attachment refactoring: (a19e5266^..faabd621) it became possible to use the ATTACH_CONTEXT and the recvattach.c helper mutt_generate_recvattach_list() to properly deal with nesting and multiple file-handles. Co-authored-by: Richard Russon --- diff --git a/doc/manual.xml.head b/doc/manual.xml.head index 8257ffae7..db6d129e0 100644 --- a/doc/manual.xml.head +++ b/doc/manual.xml.head @@ -3177,6 +3177,14 @@ color sidebar_divider color8 default # Dark grey $mime_forward is a quadoption which, for example, can be set to ask-no. + + Mutt's default ($mime_forward=no and + $forward_decode=yes) is + to use standard inline forwarding. In that mode all text-decodable + parts are included in the new message body. Other attachments from + the original email can also attached to the new message, based on the + quadoption $forward_attachments. + The inclusion of headers is controlled by the current setting of the $weed variable, unless @@ -3193,7 +3201,8 @@ color sidebar_divider color8 default # Dark grey Editing the message to forward follows the same procedure as sending or - replying to a message does. + replying to a message does, but can be disabled via the quadoption + $forward_edit. diff --git a/globals.h b/globals.h index f9d6b78fa..64dbc1b8a 100644 --- a/globals.h +++ b/globals.h @@ -180,6 +180,7 @@ WHERE struct Regex *C_QuoteRegex; ///< Config: Regex to match quoted WHERE unsigned char C_Bounce; ///< Config: Confirm before bouncing a message WHERE unsigned char C_Copy; ///< Config: Save outgoing emails to $record WHERE unsigned char C_Delete; ///< Config: Really delete messages, when the mailbox is closed +WHERE unsigned char C_ForwardAttachments; ///< Config: Forward attachments when forwarding a message WHERE unsigned char C_MimeForward; ///< Config: Forward a message as a 'message/RFC822' MIME part WHERE unsigned char C_Print; ///< Config: Confirm before printing a message WHERE unsigned char C_Quit; ///< Config: Prompt before exiting NeoMutt diff --git a/init.h b/init.h index 801de6ae1..fa39dcb1c 100644 --- a/init.h +++ b/init.h @@ -1187,6 +1187,15 @@ struct ConfigDef MuttVars[] = { ** .pp ** Also see the $$record variable. */ + { "forward_attachments", DT_QUAD, R_NONE, &C_ForwardAttachments, MUTT_ASKYES }, + /* + ** .pp + ** When forwarding inline (i.e. $$mime_forward \fIunset\fP or + ** answered with ``no'' and $$forward_decode \fIset\fP), attachments + ** which cannot be decoded in a reasonable manner will be attached + ** to the newly composed message if this quadoption is \fIset\fP or + ** answered with ``yes''. + */ { "forward_attribution_intro", DT_STRING, R_NONE, &C_ForwardAttributionIntro, IP "----- Forwarded message from %f -----" }, /* ** .pp diff --git a/recvattach.c b/recvattach.c index cc34b97be..bf3535709 100644 --- a/recvattach.c +++ b/recvattach.c @@ -1137,9 +1137,9 @@ int mutt_attach_display_loop(struct Menu *menu, int op, struct Email *e, * @param level Attachment depth * @param decrypted True if attachment has been decrypted */ -static void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, - struct Body *parts, FILE *fp, - int parent_type, int level, bool decrypted) +void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, + struct Body *parts, FILE *fp, + int parent_type, int level, bool decrypted) { struct AttachPtr *new = NULL; struct Body *m = NULL; diff --git a/recvattach.h b/recvattach.h index 0964d6ca0..90a98d40a 100644 --- a/recvattach.h +++ b/recvattach.h @@ -44,4 +44,6 @@ void mutt_update_tree(struct AttachCtx *actx); const char *attach_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, unsigned long data, MuttFormatFlags flags); void mutt_view_attachments(struct Email *e); +void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted); + #endif /* MUTT_RECVATTACH_H */ diff --git a/send.c b/send.c index 52f84a176..9b8e21b1a 100644 --- a/send.c +++ b/send.c @@ -51,10 +51,12 @@ #include "edit.h" #include "filter.h" #include "globals.h" +#include "handler.h" #include "hdrline.h" #include "hook.h" #include "mailbox.h" #include "mutt_attach.h" +#include "mutt_body.h" #include "mutt_header.h" #include "mutt_logging.h" #include "mutt_parse.h" @@ -63,6 +65,7 @@ #include "options.h" #include "pattern.h" #include "protos.h" +#include "recvattach.h" #include "rfc3676.h" #include "sendlib.h" #include "smtp.h" @@ -533,6 +536,128 @@ static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out) return 0; } +/** + * inline_forward_attachments - Add attachments to an email, inline + * @param[in] m Mailbox + * @param[in] cur Current Email + * @param[out] plast Pointer to the last Attachment + * @param[out] forwardq Result of asking the user to forward the attachments, e.g. #MUTT_YES + * @retval 0 Success + * @retval -1 Error + */ +static int inline_forward_attachments(struct Mailbox *m, struct Email *cur, + struct Body ***plast, int *forwardq) +{ + struct Body **last = *plast, *body = NULL; + struct Message *msg = NULL; + struct AttachCtx *actx = NULL; + int rc = 0, i; + + mutt_parse_mime_message(m, cur); + mutt_message_hook(m, cur, MUTT_MESSAGE_HOOK); + + msg = mx_msg_open(m, cur->msgno); + if (!msg) + return -1; + + actx = mutt_mem_calloc(1, sizeof(*actx)); + actx->email = cur; + actx->fp_root = msg->fp; + + mutt_generate_recvattach_list(actx, actx->email, actx->email->content, + actx->fp_root, -1, 0, 0); + + for (i = 0; i < actx->idxlen; i++) + { + body = actx->idx[i]->content; + if ((body->type != TYPE_MULTIPART) && !mutt_can_decode(body) && + !((body->type == TYPE_APPLICATION) && + ((mutt_str_strcasecmp(body->subtype, "pgp-signature") == 0) || + (mutt_str_strcasecmp(body->subtype, "x-pkcs7-signature") == 0) || + (mutt_str_strcasecmp(body->subtype, "pkcs7-signature") == 0)))) + { + /* Ask the quadoption only once */ + if (*forwardq == -1) + { + *forwardq = query_quadoption(C_ForwardAttachments, + /* L10N: + This is the prompt for $forward_attachments. + When inline forwarding ($mime_forward answered "no"), this prompts + whether to add non-decodable attachments from the original email. + Text/plain parts and the like will be already be included in the + message contents, but other attachment, such as PDF files, will also + be added as attachments to the new mail, is this is answered yes. + */ + _("Forward attachments?")); + if (*forwardq != MUTT_YES) + { + if (*forwardq == -1) + rc = -1; + goto cleanup; + } + } + if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1) + { + rc = -1; + goto cleanup; + } + last = &((*last)->next); + } + } + +cleanup: + *plast = last; + mx_msg_close(m, &msg); + mutt_actx_free(&actx); + return rc; +} + +/** + * mutt_inline_forward - Forward attachments, inline + * @param m Mailbox + * @param msg Email to alter + * @param cur Current Email + * @param out File + * @retval 0 Success + * @retval -1 Error + */ +int mutt_inline_forward(struct Mailbox *m, struct Email *msg, struct Email *cur, FILE *out) +{ + int i, forwardq = -1; + struct Body **last; + + if (cur) + include_forward(m, cur, out); + else + for (i = 0; i < m->vcount; i++) + if (m->emails[m->v2r[i]]->tagged) + include_forward(m, m->emails[m->v2r[i]], out); + + if (C_ForwardDecode && (C_ForwardAttachments != MUTT_NO)) + { + last = &msg->content; + while (*last) + last = &((*last)->next); + + if (cur) + { + if (inline_forward_attachments(m, cur, &last, &forwardq) != 0) + return -1; + } + else + for (i = 0; i < m->vcount; i++) + if (m->emails[m->v2r[i]]->tagged) + { + if (inline_forward_attachments(m, m->emails[m->v2r[i]], &last, &forwardq) != 0) + return -1; + if (forwardq == MUTT_NO) + break; + } + } + + return 0; +} + /** * mutt_make_attribution - Add "on DATE, PERSON wrote" header * @param m Mailbox @@ -1056,15 +1181,8 @@ static int generate_body(FILE *fp_tmp, struct Email *msg, SendFlags flags, } else if (ans != MUTT_ABORT) { - if (single) - include_forward(m, en->email, fp_tmp); - else - { - STAILQ_FOREACH(en, el, entries) - { - include_forward(m, en->email, fp_tmp); - } - } + if (mutt_inline_forward(m, msg, en->email, fp_tmp) != 0) + return -1; } else return -1;