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), 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);
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;
466 char tmpbody[PATH_MAX];
468 enum QuadOption ans = MUTT_ABORT;
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 mutt_mktemp(tmpbody, sizeof(tmpbody));
490 FILE *fp_tmp = mutt_file_fopen(tmpbody, "w");
493 mutt_error(_("Can't open temporary file %s"), tmpbody);
498 mutt_forward_intro(Context->mailbox, e_parent, fp_tmp);
500 /* prepare the prefix here since we'll need it later. */
505 mutt_str_strfcpy(prefix, ">", sizeof(prefix));
508 mutt_make_string(prefix, sizeof(prefix), NONULL(C_IndentString), Context,
509 Context->mailbox, e_parent);
513 include_header(C_ForwardQuote, fp_parent, e_parent, fp_tmp, prefix);
515 /* Now, we have prepared the first part of the message body: The
516 * original message's header.
518 * The next part is more interesting: either include the message bodies,
520 if ((!cur || mutt_can_decode(cur)) &&
521 ((ans = query_quadoption(C_MimeForward, _("Forward as attachments?"))) == MUTT_YES))
525 else if (ans == MUTT_ABORT)
530 /* shortcut MIMEFWDREST when there is only one attachment.
531 * Is this intuitive? */
532 if (!mime_fwd_all && !cur && (nattach > 1) && !check_can_decode(actx, cur))
534 ans = query_quadoption(
536 _("Can't decode all tagged attachments. MIME-forward the others?"));
537 if (ans == MUTT_ABORT)
539 else if (ans == MUTT_NO)
540 mime_fwd_any = false;
543 /* initialize a state structure */
545 struct State st = { 0 };
548 st.flags = MUTT_CHARCONV;
550 st.flags |= MUTT_WEED;
553 /* where do we append new MIME parts? */
554 struct Body **last = &e_tmp->content;
558 /* single body case */
560 if (!mime_fwd_all && mutt_can_decode(cur))
563 mutt_body_handler(cur, &st);
564 state_putc('\n', &st);
568 if (mutt_body_copy(fp, last, cur) == -1)
574 /* multiple body case */
578 for (int i = 0; i < actx->idxlen; i++)
580 if (actx->idx[i]->content->tagged && mutt_can_decode(actx->idx[i]->content))
582 st.fp_in = actx->idx[i]->fp;
583 mutt_body_handler(actx->idx[i]->content, &st);
584 state_putc('\n', &st);
589 if (mime_fwd_any && !copy_problematic_attachments(last, actx, mime_fwd_all))
593 mutt_forward_trailer(Context->mailbox, e_parent, fp_tmp);
595 mutt_file_fclose(&fp_tmp);
598 /* now that we have the template, send it. */
599 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
600 el_add_email(&el, e_parent);
601 ci_send_message(SEND_NO_FLAGS, e_tmp, tmpbody, NULL, &el);
602 emaillist_clear(&el);
609 mutt_file_fclose(&fp_tmp);
610 mutt_file_unlink(tmpbody);
617 * attach_forward_msgs - Forward one or several message-type attachments
618 * @param fp File handle to attachment
619 * @param actx Attachment Context
620 * @param cur Attachment to forward (OPTIONAL)
621 * @param flags Send mode, see #SendFlags
623 * This is different from the previous function since we want to mimic the
624 * index menu's behavior.
626 * Code reuse from ci_send_message() is not possible here - it relies on a
627 * context structure to find messages, while, on the attachment menu, messages
628 * are referenced through the attachment index.
630 static void attach_forward_msgs(FILE *fp, struct AttachCtx *actx,
631 struct Body *cur, SendFlags flags)
633 struct Email *e_cur = NULL;
634 struct Email *e_tmp = NULL;
637 struct Body **last = NULL;
638 char tmpbody[PATH_MAX];
641 CopyHeaderFlags chflags = CH_XMIT;
647 for (short i = 0; i < actx->idxlen; i++)
649 if (actx->idx[i]->content->tagged)
651 e_cur = actx->idx[i]->content->email;
658 e_tmp->env = mutt_env_new();
659 mutt_make_forward_subject(e_tmp->env, Context->mailbox, e_cur);
663 ans = query_quadoption(C_MimeForward, _("Forward MIME encapsulated?"));
666 /* no MIME encapsulation */
668 mutt_mktemp(tmpbody, sizeof(tmpbody));
669 fp_tmp = mutt_file_fopen(tmpbody, "w");
672 mutt_error(_("Can't create %s"), 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);
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);
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, (tmpbody[0] != '\0') ? tmpbody : NULL, NULL, &el);
738 emaillist_clear(&el);
742 * mutt_attach_forward - Forward an Attachment
743 * @param fp Handle to the attachment
745 * @param actx Attachment Context
746 * @param cur Current message
747 * @param flags Send mode, see #SendFlags
749 void mutt_attach_forward(FILE *fp, struct Email *e, struct AttachCtx *actx,
750 struct Body *cur, SendFlags flags)
752 if (check_all_msg(actx, cur, false))
753 attach_forward_msgs(fp, actx, cur, flags);
756 const short nattach = count_tagged(actx);
757 attach_forward_bodies(fp, e, actx, cur, nattach);
762 * attach_reply_envelope_defaults - Create the envelope defaults for a reply
763 * @param env Envelope to fill in
764 * @param actx Attachment Context
765 * @param parent Parent Email
766 * @param flags Flags, see #SendFlags
770 * This function can be invoked in two ways.
772 * Either, parent is NULL. In this case, all tagged bodies are of a message type,
773 * and the header information is fetched from them.
775 * Or, parent is non-NULL. In this case, cur is the common parent of all the
776 * tagged attachments.
778 * Note that this code is horribly similar to envelope_defaults() from send.c.
780 static int attach_reply_envelope_defaults(struct Envelope *env, struct AttachCtx *actx,
781 struct Email *parent, SendFlags flags)
783 struct Envelope *curenv = NULL;
784 struct Email *e = NULL;
788 for (short i = 0; i < actx->idxlen; i++)
790 if (actx->idx[i]->content->tagged)
792 e = actx->idx[i]->content->email;
800 curenv = parent->env;
806 mutt_error(_("Can't find any tagged messages"));
811 if ((flags & SEND_NEWS))
813 /* in case followup set Newsgroups: with Followup-To: if it present */
814 if (!env->newsgroups && curenv &&
815 (mutt_str_strcasecmp(curenv->followup_to, "poster") != 0))
817 env->newsgroups = mutt_str_strdup(curenv->followup_to);
825 if (mutt_fetch_recips(env, curenv, flags) == -1)
830 for (short i = 0; i < actx->idxlen; i++)
832 if (actx->idx[i]->content->tagged &&
833 (mutt_fetch_recips(env, actx->idx[i]->content->email->env, flags) == -1))
840 if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
842 mutt_error(_("No mailing lists found"));
846 mutt_fix_reply_recipients(env);
848 mutt_make_misc_reply_headers(env, curenv);
851 mutt_add_to_reference_headers(env, curenv);
854 for (short i = 0; i < actx->idxlen; i++)
856 if (actx->idx[i]->content->tagged)
857 mutt_add_to_reference_headers(env, actx->idx[i]->content->email->env);
865 * attach_include_reply - This is _very_ similar to send.c's include_reply()
866 * @param fp File handle to attachment
867 * @param fp_tmp File handle to temporary file
870 static void attach_include_reply(FILE *fp, FILE *fp_tmp, struct Email *e)
872 CopyMessageFlags cmflags = MUTT_CM_PREFIX | MUTT_CM_DECODE | MUTT_CM_CHARCONV;
873 CopyHeaderFlags chflags = CH_DECODE;
875 mutt_make_attribution(Context->mailbox, e, fp_tmp);
878 cmflags |= MUTT_CM_NOHEADER;
882 cmflags |= MUTT_CM_WEED;
885 mutt_copy_message_fp(fp_tmp, fp, e, cmflags, chflags);
886 mutt_make_post_indent(Context->mailbox, e, fp_tmp);
890 * mutt_attach_reply - Attach a reply
891 * @param fp File handle to reply
893 * @param actx Attachment Context
894 * @param e_cur Current message
895 * @param flags Send mode, see #SendFlags
897 void mutt_attach_reply(FILE *fp, struct Email *e, struct AttachCtx *actx,
898 struct Body *e_cur, SendFlags flags)
900 bool mime_reply_any = false;
903 struct AttachPtr *parent = NULL;
904 struct Email *e_parent = NULL;
905 FILE *fp_parent = NULL;
906 struct Email *e_tmp = NULL;
909 char tmpbody[PATH_MAX];
915 if (flags & SEND_NEWS)
921 if (!check_all_msg(actx, e_cur, false))
923 nattach = count_tagged(actx);
924 parent = find_parent(actx, e_cur, nattach);
927 e_parent = parent->content->email;
928 fp_parent = parent->fp;
933 fp_parent = actx->fp_root;
937 if ((nattach > 1) && !check_can_decode(actx, e_cur))
939 const enum QuadOption ans = query_quadoption(
940 C_MimeForwardRest, _("Can't decode all tagged attachments. "
941 "MIME-encapsulate the others?"));
942 if (ans == MUTT_ABORT)
944 else if (ans == MUTT_YES)
945 mime_reply_any = true;
947 else if (nattach == 1)
948 mime_reply_any = true;
951 e_tmp->env = mutt_env_new();
953 if (attach_reply_envelope_defaults(
954 e_tmp->env, actx, e_parent ? e_parent : (e_cur ? e_cur->email : NULL), flags) == -1)
960 mutt_mktemp(tmpbody, sizeof(tmpbody));
961 fp_tmp = mutt_file_fopen(tmpbody, "w");
964 mutt_error(_("Can't create %s"), tmpbody);
972 attach_include_reply(fp, fp_tmp, e_cur->email);
975 for (short i = 0; i < actx->idxlen; i++)
977 if (actx->idx[i]->content->tagged)
978 attach_include_reply(actx->idx[i]->fp, fp_tmp, actx->idx[i]->content->email);
984 mutt_make_attribution(Context->mailbox, e_parent, fp_tmp);
986 memset(&st, 0, sizeof(struct State));
991 mutt_make_string(prefix, sizeof(prefix), NONULL(C_IndentString), Context,
992 Context->mailbox, e_parent);
995 mutt_str_strfcpy(prefix, ">", sizeof(prefix));
998 st.flags = MUTT_CHARCONV;
1001 st.flags |= MUTT_WEED;
1004 include_header(true, fp_parent, e_parent, fp_tmp, prefix);
1008 if (mutt_can_decode(e_cur))
1011 mutt_body_handler(e_cur, &st);
1012 state_putc('\n', &st);
1015 mutt_body_copy(fp, &e_tmp->content, e_cur);
1019 for (short i = 0; i < actx->idxlen; i++)
1021 if (actx->idx[i]->content->tagged && mutt_can_decode(actx->idx[i]->content))
1023 st.fp_in = actx->idx[i]->fp;
1024 mutt_body_handler(actx->idx[i]->content, &st);
1025 state_putc('\n', &st);
1030 mutt_make_post_indent(Context->mailbox, e_parent, fp_tmp);
1032 if (mime_reply_any && !e_cur &&
1033 !copy_problematic_attachments(&e_tmp->content, actx, false))
1036 mutt_file_fclose(&fp_tmp);
1041 mutt_file_fclose(&fp_tmp);
1043 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1044 el_add_email(&el, e_parent ? e_parent : (e_cur ? e_cur->email : NULL));
1045 if (ci_send_message(flags, e_tmp, tmpbody, NULL, &el) == 0)
1047 mutt_set_flag(Context->mailbox, e, MUTT_REPLIED, true);
1049 emaillist_clear(&el);
1053 * mutt_attach_mail_sender - Compose an email to the sender in the email attachment
1054 * @param fp File containing attachment (UNUSED)
1055 * @param e Email (UNUSED)
1056 * @param actx Attachment Context
1057 * @param cur Current attachment
1059 void mutt_attach_mail_sender(FILE *fp, struct Email *e, struct AttachCtx *actx,
1062 if (!check_all_msg(actx, cur, 0))
1064 /* L10N: You will see this error message if you invoke <compose-to-sender>
1065 when you are on a normal attachment. */
1066 mutt_error(_("You may only compose to sender with message/rfc822 parts"));
1070 struct Email *e_tmp = email_new();
1071 e_tmp->env = mutt_env_new();
1075 if (mutt_fetch_recips(e_tmp->env, cur->email->env, SEND_TO_SENDER) == -1)
1083 for (int i = 0; i < actx->idxlen; i++)
1085 if (actx->idx[i]->content->tagged &&
1086 (mutt_fetch_recips(e_tmp->env, actx->idx[i]->content->email->env,
1087 SEND_TO_SENDER) == -1))
1095 // This call will free e_tmp for us
1096 ci_send_message(SEND_NO_FLAGS, e_tmp, NULL, NULL, NULL);