3 * Send/reply with an attachment
6 * Copyright (C) 1999-2004 Thomas Roessler <roessler@does-not-exist.org>
7 * Copyright (C) 2019 Pietro Cerutti <gahr@gahr.ch>
10 * This program is free software: you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License as published by the Free Software
12 * Foundation, either version 2 of the License, or (at your option) any later
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License along with
21 * this program. If not, see <http://www.gnu.org/licenses/>.
25 * @page recvcmd Send/reply with an attachment
27 * Send/reply with an attachment
35 #include "mutt/mutt.h"
36 #include "address/lib.h"
37 #include "config/lib.h"
38 #include "email/lib.h"
47 #include "mutt_body.h"
48 #include "mutt_logging.h"
49 #include "mutt_window.h"
62 /* These Config Variables are only used in recvcmd.c */
63 unsigned char C_MimeForwardRest; ///< Config: Forward all attachments, even if they can't be decoded
66 * check_msg - Are we working with an RFC822 message
67 * @param b Body of email
68 * @param err If true, display a message if this isn't an RFC822 message
69 * @retval true This is an RFC822 message
71 * some helper functions to verify that we are exclusively operating on
72 * message/rfc822 attachments
74 static bool check_msg(struct Body *b, bool err)
76 if (!mutt_is_message_type(b->type, b->subtype))
79 mutt_error(_("You may only bounce message/rfc822 parts"));
86 * check_all_msg - Are all the Attachments RFC822 messages?
87 * @param actx Attachment context
88 * @param cur Current message
89 * @param err If true, report errors
90 * @retval true If all parts are RFC822 messages
92 static bool check_all_msg(struct AttachCtx *actx, struct Body *cur, bool err)
94 if (cur && !check_msg(cur, err))
98 for (short i = 0; i < actx->idxlen; i++)
100 if (actx->idx[i]->content->tagged)
102 if (!check_msg(actx->idx[i]->content, err))
111 * check_can_decode - Can we decode all tagged attachments?
112 * @param actx Attachment context
113 * @param cur Body of email
114 * @retval true All tagged attachments are decodable
116 static bool check_can_decode(struct AttachCtx *actx, struct Body *cur)
119 return mutt_can_decode(cur);
121 for (short i = 0; i < actx->idxlen; i++)
122 if (actx->idx[i]->content->tagged && !mutt_can_decode(actx->idx[i]->content))
129 * count_tagged - Count the number of tagged attachments
130 * @param actx Attachment context
131 * @retval num Number of tagged attachments
133 static short count_tagged(struct AttachCtx *actx)
136 for (short i = 0; i < actx->idxlen; i++)
137 if (actx->idx[i]->content->tagged)
144 * count_tagged_children - tagged children below a multipart/message attachment
145 * @param actx Attachment context
146 * @param i Index of first attachment
147 * @retval num Number of tagged attachments
149 static short count_tagged_children(struct AttachCtx *actx, short i)
151 short level = actx->idx[i]->level;
154 while ((++i < actx->idxlen) && (level < actx->idx[i]->level))
155 if (actx->idx[i]->content->tagged)
162 * mutt_attach_bounce - Bounce function, from the attachment menu
164 * @param fp Handle of message
165 * @param actx Attachment context
166 * @param cur Body of email
168 void mutt_attach_bounce(struct Mailbox *m, FILE *fp, struct AttachCtx *actx, struct Body *cur)
170 if (!m || !fp || !actx)
179 if (!check_all_msg(actx, cur, true))
182 /* one or more messages? */
183 p = cur ? 1 : count_tagged(actx);
185 /* RFC5322 mandates a From: header, so warn before bouncing
186 * messages without one */
189 if (TAILQ_EMPTY(&cur->email->env->from))
191 mutt_error(_("Warning: message contains no From: header"));
197 for (short i = 0; i < actx->idxlen; i++)
199 if (actx->idx[i]->content->tagged)
201 if (TAILQ_EMPTY(&actx->idx[i]->content->email->env->from))
203 mutt_error(_("Warning: message contains no From: header"));
212 mutt_str_strfcpy(prompt, _("Bounce message to: "), sizeof(prompt));
214 mutt_str_strfcpy(prompt, _("Bounce tagged messages to: "), sizeof(prompt));
217 if (mutt_get_field(prompt, buf, sizeof(buf), MUTT_ALIAS) || (buf[0] == '\0'))
220 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
221 mutt_addrlist_parse(&al, buf);
222 if (TAILQ_EMPTY(&al))
224 mutt_error(_("Error parsing address"));
228 mutt_expand_aliases(&al);
230 if (mutt_addrlist_to_intl(&al, &err) < 0)
232 mutt_error(_("Bad IDN: '%s'"), err);
238 mutt_addrlist_write(buf, sizeof(buf), &al, true);
240 #define EXTRA_SPACE (15 + 7 + 2)
241 /* See commands.c. */
242 snprintf(prompt, sizeof(prompt) - 4,
243 ngettext("Bounce message to %s?", "Bounce messages to %s?", p), buf);
245 if (mutt_strwidth(prompt) > MuttMessageWindow->cols - EXTRA_SPACE)
247 mutt_simple_format(prompt, sizeof(prompt) - 4, 0, MuttMessageWindow->cols - EXTRA_SPACE,
248 JUSTIFY_LEFT, 0, prompt, sizeof(prompt), false);
249 mutt_str_strcat(prompt, sizeof(prompt), "...?");
252 mutt_str_strcat(prompt, sizeof(prompt), "?");
254 if (query_quadoption(C_Bounce, prompt) != MUTT_YES)
256 mutt_window_clearline(MuttMessageWindow, 0);
257 mutt_message(ngettext("Message not bounced", "Messages not bounced", p));
261 mutt_window_clearline(MuttMessageWindow, 0);
264 ret = mutt_bounce_message(fp, cur->email, &al);
267 for (short i = 0; i < actx->idxlen; i++)
269 if (actx->idx[i]->content->tagged)
270 if (mutt_bounce_message(actx->idx[i]->fp, actx->idx[i]->content->email, &al))
276 mutt_message(ngettext("Message bounced", "Messages bounced", p));
278 mutt_error(ngettext("Error bouncing message", "Error bouncing messages", p));
281 mutt_addrlist_clear(&al);
285 * mutt_attach_resend - resend-message, from the attachment menu
286 * @param fp File containing email
287 * @param actx Attachment context
288 * @param cur Attachment
290 void mutt_attach_resend(FILE *fp, struct AttachCtx *actx, struct Body *cur)
292 if (!check_all_msg(actx, cur, true))
296 mutt_resend_message(fp, Context, cur->email);
299 for (short i = 0; i < actx->idxlen; i++)
300 if (actx->idx[i]->content->tagged)
301 mutt_resend_message(actx->idx[i]->fp, Context, actx->idx[i]->content->email);
306 * find_common_parent - find a common parent message for the tagged attachments
307 * @param actx Attachment context
308 * @param nattach Number of tagged attachments
309 * @retval ptr Parent attachment
310 * @retval NULL Failure, no common parent
312 static struct AttachPtr *find_common_parent(struct AttachCtx *actx, short nattach)
317 for (i = 0; i < actx->idxlen; i++)
318 if (actx->idx[i]->content->tagged)
323 if (mutt_is_message_type(actx->idx[i]->content->type, actx->idx[i]->content->subtype))
325 nchildren = count_tagged_children(actx, i);
326 if (nchildren == nattach)
335 * is_parent - Check whether one attachment is the parent of another
336 * @param i Index of parent Attachment
337 * @param actx Attachment context
338 * @param cur Potential child Attachemnt
339 * @retval true Attachment
341 * check whether attachment i is a parent of the attachment pointed to by cur
343 * Note: This and the calling procedure could be optimized quite a bit.
344 * For now, it's not worth the effort.
346 static int is_parent(short i, struct AttachCtx *actx, struct Body *cur)
348 short level = actx->idx[i]->level;
350 while ((++i < actx->idxlen) && (actx->idx[i]->level > level))
352 if (actx->idx[i]->content == cur)
360 * find_parent - Find the parent of an Attachment
361 * @param actx Attachment context
362 * @param cur Attachment (OPTIONAL)
363 * @param nattach Use the nth attachment
364 * @retval ptr Parent attachment
365 * @retval NULL No parent exists
367 static struct AttachPtr *find_parent(struct AttachCtx *actx, struct Body *cur, short nattach)
369 struct AttachPtr *parent = NULL;
373 for (short i = 0; i < actx->idxlen; i++)
375 if (mutt_is_message_type(actx->idx[i]->content->type,
376 actx->idx[i]->content->subtype) &&
377 is_parent(i, actx, cur))
379 parent = actx->idx[i];
381 if (actx->idx[i]->content == cur)
386 parent = find_common_parent(actx, nattach);
392 * include_header - Write an email header to a file, optionally quoting it
393 * @param quote If true, prefix the lines
394 * @param fp_in File to read from
396 * @param fp_out File to write to
397 * @param prefix Prefix for each line (OPTIONAL)
399 static void include_header(bool quote, FILE *fp_in, struct Email *e, FILE *fp_out, char *prefix)
401 CopyHeaderFlags chflags = CH_DECODE;
405 chflags |= CH_WEED | CH_REORDER;
410 mutt_str_strfcpy(prefix2, prefix, sizeof(prefix2));
411 else if (!C_TextFlowed)
413 mutt_make_string(prefix2, sizeof(prefix2), 0, NONULL(C_IndentString),
414 Context, Context->mailbox, e);
417 mutt_str_strfcpy(prefix2, ">", sizeof(prefix2));
419 chflags |= CH_PREFIX;
422 mutt_copy_header(fp_in, e, fp_out, chflags, quote ? prefix2 : NULL, 0);
426 * copy_problematic_attachments - Attach the body parts which can't be decoded
427 * @param[out] last Body pointer to update
428 * @param[in] actx Attachment context
429 * @param[in] force If true, attach parts that can't be decoded
430 * @retval ptr Pointer to last Body part
432 * This code is shared by forwarding and replying.
434 static struct Body **copy_problematic_attachments(struct Body **last,
435 struct AttachCtx *actx, bool force)
437 for (short i = 0; i < actx->idxlen; i++)
439 if (actx->idx[i]->content->tagged && (force || !mutt_can_decode(actx->idx[i]->content)))
441 if (mutt_body_copy(actx->idx[i]->fp, last, actx->idx[i]->content) == -1)
442 return NULL; /* XXXXX - may lead to crashes */
443 last = &((*last)->next);
450 * attach_forward_bodies - forward one or several MIME bodies
451 * @param fp File to read from
453 * @param actx Attachment Context
454 * @param cur Body of email
455 * @param nattach Number of tagged attachments
457 * (non-message types)
459 static void attach_forward_bodies(FILE *fp, struct Email *e, struct AttachCtx *actx,
460 struct Body *cur, short nattach)
462 bool mime_fwd_all = false;
463 bool mime_fwd_any = true;
464 struct Email *e_parent = NULL;
465 FILE *fp_parent = NULL;
467 enum QuadOption ans = MUTT_ABORT;
468 struct Buffer *tmpbody = NULL;
470 /* First, find the parent message.
471 * Note: This could be made an option by just
472 * putting the following lines into an if block. */
473 struct AttachPtr *parent = find_parent(actx, cur, nattach);
476 e_parent = parent->content->email;
477 fp_parent = parent->fp;
482 fp_parent = actx->fp_root;
485 struct Email *e_tmp = email_new();
486 e_tmp->env = mutt_env_new();
487 mutt_make_forward_subject(e_tmp->env, Context->mailbox, e_parent);
489 tmpbody = mutt_buffer_pool_get();
490 mutt_buffer_mktemp(tmpbody);
491 FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpbody), "w");
494 mutt_error(_("Can't open temporary file %s"), mutt_b2s(tmpbody));
499 mutt_forward_intro(Context->mailbox, e_parent, fp_tmp);
501 /* prepare the prefix here since we'll need it later. */
506 mutt_str_strfcpy(prefix, ">", sizeof(prefix));
509 mutt_make_string(prefix, sizeof(prefix), 0, NONULL(C_IndentString),
510 Context, Context->mailbox, e_parent);
514 include_header(C_ForwardQuote, fp_parent, e_parent, fp_tmp, prefix);
516 /* Now, we have prepared the first part of the message body: The
517 * original message's header.
519 * The next part is more interesting: either include the message bodies,
521 if ((!cur || mutt_can_decode(cur)) &&
522 ((ans = query_quadoption(C_MimeForward, _("Forward as attachments?"))) == MUTT_YES))
526 else if (ans == MUTT_ABORT)
531 /* shortcut MIMEFWDREST when there is only one attachment.
532 * Is this intuitive? */
533 if (!mime_fwd_all && !cur && (nattach > 1) && !check_can_decode(actx, cur))
535 ans = query_quadoption(
537 _("Can't decode all tagged attachments. MIME-forward the others?"));
538 if (ans == MUTT_ABORT)
540 else if (ans == MUTT_NO)
541 mime_fwd_any = false;
544 /* initialize a state structure */
546 struct State st = { 0 };
549 st.flags = MUTT_CHARCONV;
551 st.flags |= MUTT_WEED;
554 /* where do we append new MIME parts? */
555 struct Body **last = &e_tmp->content;
559 /* single body case */
561 if (!mime_fwd_all && mutt_can_decode(cur))
564 mutt_body_handler(cur, &st);
565 state_putc(&st, '\n');
569 if (mutt_body_copy(fp, last, cur) == -1)
575 /* multiple body case */
579 for (int i = 0; i < actx->idxlen; i++)
581 if (actx->idx[i]->content->tagged && mutt_can_decode(actx->idx[i]->content))
583 st.fp_in = actx->idx[i]->fp;
584 mutt_body_handler(actx->idx[i]->content, &st);
585 state_putc(&st, '\n');
590 if (mime_fwd_any && !copy_problematic_attachments(last, actx, mime_fwd_all))
594 mutt_forward_trailer(Context->mailbox, e_parent, fp_tmp);
596 mutt_file_fclose(&fp_tmp);
599 /* now that we have the template, send it. */
600 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
601 el_add_email(&el, e_parent);
602 ci_send_message(SEND_NO_FLAGS, e_tmp, mutt_b2s(tmpbody), NULL, &el);
603 emaillist_clear(&el);
604 mutt_buffer_pool_release(&tmpbody);
610 mutt_file_fclose(&fp_tmp);
611 mutt_file_unlink(mutt_b2s(tmpbody));
613 mutt_buffer_pool_release(&tmpbody);
619 * attach_forward_msgs - Forward one or several message-type attachments
620 * @param fp File handle to attachment
621 * @param actx Attachment Context
622 * @param cur Attachment to forward (OPTIONAL)
623 * @param flags Send mode, see #SendFlags
625 * This is different from the previous function since we want to mimic the
626 * index menu's behavior.
628 * Code reuse from ci_send_message() is not possible here - it relies on a
629 * context structure to find messages, while, on the attachment menu, messages
630 * are referenced through the attachment index.
632 static void attach_forward_msgs(FILE *fp, struct AttachCtx *actx,
633 struct Body *cur, SendFlags flags)
635 struct Email *e_cur = NULL;
636 struct Email *e_tmp = NULL;
638 struct Body **last = NULL;
639 struct Buffer *tmpbody = NULL;
642 CopyHeaderFlags chflags = CH_XMIT;
648 for (short i = 0; i < actx->idxlen; i++)
650 if (actx->idx[i]->content->tagged)
652 e_cur = actx->idx[i]->content->email;
659 e_tmp->env = mutt_env_new();
660 mutt_make_forward_subject(e_tmp->env, Context->mailbox, e_cur);
662 tmpbody = mutt_buffer_pool_get();
664 ans = query_quadoption(C_MimeForward, _("Forward MIME encapsulated?"));
667 /* no MIME encapsulation */
669 mutt_buffer_mktemp(tmpbody);
670 fp_tmp = mutt_file_fopen(mutt_b2s(tmpbody), "w");
673 mutt_error(_("Can't create %s"), mutt_b2s(tmpbody));
677 CopyMessageFlags cmflags = MUTT_CM_NO_FLAGS;
680 chflags |= CH_PREFIX;
681 cmflags |= MUTT_CM_PREFIX;
686 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
689 chflags |= CH_WEED | CH_REORDER;
690 cmflags |= MUTT_CM_WEED;
696 mutt_forward_intro(Context->mailbox, cur->email, fp_tmp);
697 mutt_copy_message_fp(fp_tmp, fp, cur->email, cmflags, chflags, 0);
698 mutt_forward_trailer(Context->mailbox, cur->email, fp_tmp);
702 for (short i = 0; i < actx->idxlen; i++)
704 if (actx->idx[i]->content->tagged)
706 mutt_forward_intro(Context->mailbox, actx->idx[i]->content->email, fp_tmp);
707 mutt_copy_message_fp(fp_tmp, actx->idx[i]->fp,
708 actx->idx[i]->content->email, cmflags, chflags, 0);
709 mutt_forward_trailer(Context->mailbox, actx->idx[i]->content->email, fp_tmp);
713 mutt_file_fclose(&fp_tmp);
715 else if (ans == MUTT_YES) /* do MIME encapsulation - we don't need to do much here */
717 last = &e_tmp->content;
719 mutt_body_copy(fp, last, cur);
722 for (short i = 0; i < actx->idxlen; i++)
724 if (actx->idx[i]->content->tagged)
726 mutt_body_copy(actx->idx[i]->fp, last, actx->idx[i]->content);
727 last = &((*last)->next);
735 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
736 el_add_email(&el, e_cur);
737 ci_send_message(flags, e_tmp,
738 mutt_buffer_is_empty(tmpbody) ? NULL : mutt_b2s(tmpbody), NULL, &el);
739 emaillist_clear(&el);
740 e_tmp = NULL; /* ci_send_message frees this */
744 mutt_buffer_pool_release(&tmpbody);
748 * mutt_attach_forward - Forward an Attachment
749 * @param fp Handle to the attachment
751 * @param actx Attachment Context
752 * @param cur Current message
753 * @param flags Send mode, see #SendFlags
755 void mutt_attach_forward(FILE *fp, struct Email *e, struct AttachCtx *actx,
756 struct Body *cur, SendFlags flags)
758 if (check_all_msg(actx, cur, false))
759 attach_forward_msgs(fp, actx, cur, flags);
762 const short nattach = count_tagged(actx);
763 attach_forward_bodies(fp, e, actx, cur, nattach);
768 * attach_reply_envelope_defaults - Create the envelope defaults for a reply
769 * @param env Envelope to fill in
770 * @param actx Attachment Context
771 * @param parent Parent Email
772 * @param flags Flags, see #SendFlags
776 * This function can be invoked in two ways.
778 * Either, parent is NULL. In this case, all tagged bodies are of a message type,
779 * and the header information is fetched from them.
781 * Or, parent is non-NULL. In this case, cur is the common parent of all the
782 * tagged attachments.
784 * Note that this code is horribly similar to envelope_defaults() from send.c.
786 static int attach_reply_envelope_defaults(struct Envelope *env, struct AttachCtx *actx,
787 struct Email *parent, SendFlags flags)
789 struct Envelope *curenv = NULL;
790 struct Email *e = NULL;
794 for (short i = 0; i < actx->idxlen; i++)
796 if (actx->idx[i]->content->tagged)
798 e = actx->idx[i]->content->email;
806 curenv = parent->env;
812 mutt_error(_("Can't find any tagged messages"));
817 if ((flags & SEND_NEWS))
819 /* in case followup set Newsgroups: with Followup-To: if it present */
820 if (!env->newsgroups && curenv &&
821 (mutt_str_strcasecmp(curenv->followup_to, "poster") != 0))
823 env->newsgroups = mutt_str_strdup(curenv->followup_to);
831 if (mutt_fetch_recips(env, curenv, flags) == -1)
836 for (short i = 0; i < actx->idxlen; i++)
838 if (actx->idx[i]->content->tagged &&
839 (mutt_fetch_recips(env, actx->idx[i]->content->email->env, flags) == -1))
846 if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
848 mutt_error(_("No mailing lists found"));
852 mutt_fix_reply_recipients(env);
854 mutt_make_misc_reply_headers(env, curenv);
857 mutt_add_to_reference_headers(env, curenv);
860 for (short i = 0; i < actx->idxlen; i++)
862 if (actx->idx[i]->content->tagged)
863 mutt_add_to_reference_headers(env, actx->idx[i]->content->email->env);
871 * attach_include_reply - This is _very_ similar to send.c's include_reply()
872 * @param fp File handle to attachment
873 * @param fp_tmp File handle to temporary file
876 static void attach_include_reply(FILE *fp, FILE *fp_tmp, struct Email *e)
878 CopyMessageFlags cmflags = MUTT_CM_PREFIX | MUTT_CM_DECODE | MUTT_CM_CHARCONV;
879 CopyHeaderFlags chflags = CH_DECODE;
881 mutt_make_attribution(Context->mailbox, e, fp_tmp);
884 cmflags |= MUTT_CM_NOHEADER;
888 cmflags |= MUTT_CM_WEED;
891 mutt_copy_message_fp(fp_tmp, fp, e, cmflags, chflags, 0);
892 mutt_make_post_indent(Context->mailbox, e, fp_tmp);
896 * mutt_attach_reply - Attach a reply
897 * @param fp File handle to reply
899 * @param actx Attachment Context
900 * @param e_cur Current message
901 * @param flags Send mode, see #SendFlags
903 void mutt_attach_reply(FILE *fp, struct Email *e, struct AttachCtx *actx,
904 struct Body *e_cur, SendFlags flags)
906 bool mime_reply_any = false;
909 struct AttachPtr *parent = NULL;
910 struct Email *e_parent = NULL;
911 FILE *fp_parent = NULL;
912 struct Email *e_tmp = NULL;
914 struct Buffer *tmpbody = NULL;
919 if (flags & SEND_NEWS)
925 if (!check_all_msg(actx, e_cur, false))
927 nattach = count_tagged(actx);
928 parent = find_parent(actx, e_cur, nattach);
931 e_parent = parent->content->email;
932 fp_parent = parent->fp;
937 fp_parent = actx->fp_root;
941 if ((nattach > 1) && !check_can_decode(actx, e_cur))
943 const enum QuadOption ans = query_quadoption(
944 C_MimeForwardRest, _("Can't decode all tagged attachments. "
945 "MIME-encapsulate the others?"));
946 if (ans == MUTT_ABORT)
949 mime_reply_any = true;
951 else if (nattach == 1)
952 mime_reply_any = true;
955 e_tmp->env = mutt_env_new();
957 if (attach_reply_envelope_defaults(
958 e_tmp->env, actx, e_parent ? e_parent : (e_cur ? e_cur->email : NULL), flags) == -1)
963 tmpbody = mutt_buffer_pool_get();
964 mutt_buffer_mktemp(tmpbody);
965 fp_tmp = mutt_file_fopen(mutt_b2s(tmpbody), "w");
968 mutt_error(_("Can't create %s"), mutt_b2s(tmpbody));
975 attach_include_reply(fp, fp_tmp, e_cur->email);
978 for (short i = 0; i < actx->idxlen; i++)
980 if (actx->idx[i]->content->tagged)
981 attach_include_reply(actx->idx[i]->fp, fp_tmp, actx->idx[i]->content->email);
987 mutt_make_attribution(Context->mailbox, e_parent, fp_tmp);
990 memset(&st, 0, sizeof(struct State));
995 mutt_str_strfcpy(prefix, ">", sizeof(prefix));
999 mutt_make_string(prefix, sizeof(prefix), 0, NONULL(C_IndentString),
1000 Context, Context->mailbox, e_parent);
1004 st.flags = MUTT_CHARCONV;
1007 st.flags |= MUTT_WEED;
1010 include_header(true, fp_parent, e_parent, fp_tmp, prefix);
1014 if (mutt_can_decode(e_cur))
1017 mutt_body_handler(e_cur, &st);
1018 state_putc(&st, '\n');
1021 mutt_body_copy(fp, &e_tmp->content, e_cur);
1025 for (short i = 0; i < actx->idxlen; i++)
1027 if (actx->idx[i]->content->tagged && mutt_can_decode(actx->idx[i]->content))
1029 st.fp_in = actx->idx[i]->fp;
1030 mutt_body_handler(actx->idx[i]->content, &st);
1031 state_putc(&st, '\n');
1036 mutt_make_post_indent(Context->mailbox, e_parent, fp_tmp);
1038 if (mime_reply_any && !e_cur &&
1039 !copy_problematic_attachments(&e_tmp->content, actx, false))
1045 mutt_file_fclose(&fp_tmp);
1047 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1048 el_add_email(&el, e_parent ? e_parent : (e_cur ? e_cur->email : NULL));
1049 if (ci_send_message(flags, e_tmp, mutt_b2s(tmpbody), NULL, &el) == 0)
1051 mutt_set_flag(Context->mailbox, e, MUTT_REPLIED, true);
1053 e_tmp = NULL; /* ci_send_message frees this */
1058 mutt_file_fclose(&fp_tmp);
1059 mutt_file_unlink(mutt_b2s(tmpbody));
1061 mutt_buffer_pool_release(&tmpbody);
1063 emaillist_clear(&el);
1067 * mutt_attach_mail_sender - Compose an email to the sender in the email attachment
1068 * @param fp File containing attachment (UNUSED)
1069 * @param e Email (UNUSED)
1070 * @param actx Attachment Context
1071 * @param cur Current attachment
1073 void mutt_attach_mail_sender(FILE *fp, struct Email *e, struct AttachCtx *actx,
1076 if (!check_all_msg(actx, cur, 0))
1078 /* L10N: You will see this error message if you invoke <compose-to-sender>
1079 when you are on a normal attachment. */
1080 mutt_error(_("You may only compose to sender with message/rfc822 parts"));
1084 struct Email *e_tmp = email_new();
1085 e_tmp->env = mutt_env_new();
1089 if (mutt_fetch_recips(e_tmp->env, cur->email->env, SEND_TO_SENDER) == -1)
1097 for (int i = 0; i < actx->idxlen; i++)
1099 if (actx->idx[i]->content->tagged &&
1100 (mutt_fetch_recips(e_tmp->env, actx->idx[i]->content->email->env,
1101 SEND_TO_SENDER) == -1))
1109 // This call will free e_tmp for us
1110 ci_send_message(SEND_NO_FLAGS, e_tmp, NULL, NULL, NULL);