3 * Prepare and send an email
6 * Copyright (C) 1996-2002,2004,2010,2012-2013 Michael R. Elkins <me@mutt.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 send Prepare and send an email
27 * Prepare and send an email
40 #include "mutt/mutt.h"
41 #include "address/lib.h"
42 #include "config/lib.h"
43 #include "email/lib.h"
58 #include "mutt_attach.h"
59 #include "mutt_body.h"
60 #include "mutt_header.h"
61 #include "mutt_logging.h"
62 #include "mutt_parse.h"
64 #include "ncrypt/ncrypt.h"
68 #include "recvattach.h"
75 #include "nntp/nntp.h"
81 #include "notmuch/mutt_notmuch.h"
84 #include "imap/imap.h"
87 #include "autocrypt/autocrypt.h"
90 /* These Config Variables are only used in send.c */
91 unsigned char C_AbortNoattach; ///< Config: Abort sending the email if attachments are missing
92 struct Regex *C_AbortNoattachRegex; ///< Config: Regex to match text indicating attachments are expected
93 unsigned char C_AbortNosubject; ///< Config: Abort creating the email if subject is missing
94 unsigned char C_AbortUnmodified; ///< Config: Abort the sending if the message hasn't been edited
95 bool C_AskFollowUp; ///< Config: (nntp) Ask the user for follow-up groups before editing
96 bool C_AskXCommentTo; ///< Config: (nntp) Ask the user for the 'X-Comment-To' field before editing
97 char *C_ContentType; ///< Config: Default "Content-Type" for newly composed messages
98 bool C_CryptAutoencrypt; ///< Config: Automatically PGP encrypt all outgoing mail
99 bool C_CryptAutopgp; ///< Config: Allow automatic PGP functions
100 bool C_CryptAutosign; ///< Config: Automatically PGP sign all outgoing mail
101 bool C_CryptAutosmime; ///< Config: Allow automatic SMIME functions
102 bool C_CryptReplyencrypt; ///< Config: Encrypt replies to encrypted messages
103 bool C_CryptReplysign; ///< Config: Sign replies to signed messages
104 bool C_CryptReplysignencrypted; ///< Config: Sign replies to encrypted messages
105 char *C_EmptySubject; ///< Config: Subject to use when replying to an email with none
106 bool C_FastReply; ///< Config: Don't prompt for the recipients and subject when replying/forwarding
107 unsigned char C_FccAttach; ///< Config: Save send message with all their attachments
108 bool C_FccBeforeSend; ///< Config: Save FCCs before sending the message
109 bool C_FccClear; ///< Config: Save sent messages unencrypted and unsigned
110 bool C_FollowupTo; ///< Config: Add the 'Mail-Followup-To' header is generated when sending mail
111 char *C_ForwardAttributionIntro; ///< Config: Prefix message for forwarded messages
112 char *C_ForwardAttributionTrailer; ///< Config: Suffix message for forwarded messages
113 unsigned char C_ForwardEdit; ///< Config: Automatically start the editor when forwarding a message
114 char *C_ForwardFormat; ///< Config: printf-like format string to control the subject when forwarding a message
115 bool C_ForwardReferences; ///< Config: Set the 'In-Reply-To' and 'References' headers when forwarding a message
116 bool C_Hdrs; ///< Config: Add custom headers to outgoing mail
117 unsigned char C_HonorFollowupTo; ///< Config: Honour the 'Mail-Followup-To' header when group replying
118 bool C_IgnoreListReplyTo; ///< Config: Ignore the 'Reply-To' header when using `<reply>` on a mailing list
119 unsigned char C_Include; ///< Config: Include a copy of the email that's being replied to
120 bool C_Metoo; ///< Config: Remove the user's address from the list of recipients
121 bool C_NmRecord; ///< Config: (notmuch) If the 'record' mailbox (sent mail) should be indexed
122 bool C_PgpReplyinline; ///< Config: Reply using old-style inline PGP messages (not recommended)
123 char *C_PostIndentString; ///< Config: Suffix message to add after reply text
124 bool C_PostponeEncrypt; ///< Config: Self-encrypt postponed messages
125 char *C_PostponeEncryptAs; ///< Config: Fallback encryption key for postponed messages
126 unsigned char C_Recall; ///< Config: Recall postponed mesaages when asked to compose a message
127 bool C_ReplySelf; ///< Config: Really reply to yourself, when replying to your own email
128 unsigned char C_ReplyTo; ///< Config: Address to use as a 'Reply-To' header
129 bool C_ReplyWithXorig; ///< Config: Create 'From' header from 'X-Original-To' header
130 bool C_ReverseName; ///< Config: Set the 'From' from the address the email was sent to
131 bool C_ReverseRealname; ///< Config: Set the 'From' from the full 'To' address the email was sent to
132 bool C_SigDashes; ///< Config: Insert '-- ' before the signature
133 char *C_Signature; ///< Config: File containing a signature to append to all mail
134 bool C_SigOnTop; ///< Config: Insert the signature before the quoted text
135 bool C_UseFrom; ///< Config: Set the 'From' header for outgoing mail
138 * append_signature - Append a signature to an email
139 * @param fp File to write to
141 static void append_signature(FILE *fp)
146 if (C_Signature && (fp_tmp = mutt_open_read(C_Signature, &pid)))
149 fputs("\n-- \n", fp);
150 mutt_file_copy_stream(fp_tmp, fp);
151 mutt_file_fclose(&fp_tmp);
153 mutt_wait_filter(pid);
158 * remove_user - Remove any address which matches the current user
159 * @param al List of addresses
160 * @param leave_only If set, don't remove the user's address if it it the only
163 static void remove_user(struct AddressList *al, bool leave_only)
165 struct Address *a = NULL, *tmp = NULL;
166 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
168 if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
170 TAILQ_REMOVE(al, a, entries);
177 * add_mailing_lists - Search Address lists for mailing lists
178 * @param out Address list where to append matching mailing lists
179 * @param t 'To' Address list
180 * @param c 'Cc' Address list
182 static void add_mailing_lists(struct AddressList *out, const struct AddressList *t,
183 const struct AddressList *c)
185 const struct AddressList *const als[] = { t, c };
187 for (size_t i = 0; i < mutt_array_size(als); ++i)
189 const struct AddressList *al = als[i];
190 struct Address *a = NULL;
191 TAILQ_FOREACH(a, al, entries)
193 if (!a->group && mutt_is_mail_list(a))
195 mutt_addrlist_append(out, mutt_addr_copy(a));
202 * mutt_edit_address - Edit an email address
203 * @param[in,out] al AddressList to edit
204 * @param[in] field Prompt for user
205 * @param[in] expand_aliases If true, expand Address aliases
209 int mutt_edit_address(struct AddressList *al, const char *field, bool expand_aliases)
218 mutt_addrlist_to_local(al);
219 mutt_addrlist_write(buf, sizeof(buf), al, false);
220 if (mutt_get_field(field, buf, sizeof(buf), MUTT_ALIAS) != 0)
222 mutt_addrlist_clear(al);
223 mutt_addrlist_parse2(al, buf);
225 mutt_expand_aliases(al);
226 idna_ok = mutt_addrlist_to_intl(al, &err);
229 mutt_error(_("Bad IDN: '%s'"), err);
232 } while (idna_ok != 0);
237 * edit_envelope - Edit Envelope fields
238 * @param en Envelope to edit
239 * @param flags Flags, see #SendFlags
243 static int edit_envelope(struct Envelope *en, SendFlags flags)
251 mutt_str_strfcpy(buf, en->newsgroups, sizeof(buf));
254 if (mutt_get_field("Newsgroups: ", buf, sizeof(buf), 0) != 0)
256 FREE(&en->newsgroups);
257 en->newsgroups = mutt_str_strdup(buf);
260 mutt_str_strfcpy(buf, en->followup_to, sizeof(buf));
263 if (C_AskFollowUp && (mutt_get_field("Followup-To: ", buf, sizeof(buf), 0) != 0))
267 FREE(&en->followup_to);
268 en->followup_to = mutt_str_strdup(buf);
270 if (en->x_comment_to)
271 mutt_str_strfcpy(buf, en->x_comment_to, sizeof(buf));
274 if (C_XCommentTo && C_AskXCommentTo &&
275 (mutt_get_field("X-Comment-To: ", buf, sizeof(buf), 0) != 0))
279 FREE(&en->x_comment_to);
280 en->x_comment_to = mutt_str_strdup(buf);
285 if ((mutt_edit_address(&en->to, _("To: "), true) == -1) || TAILQ_EMPTY(&en->to))
287 if (C_Askcc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
289 if (C_Askbcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
291 if (C_ReplyWithXorig && (flags & (SEND_REPLY | SEND_LIST_REPLY | SEND_GROUP_REPLY)) &&
292 (mutt_edit_address(&en->from, "From: ", true) == -1))
302 mutt_str_strfcpy(buf, en->subject, sizeof(buf));
306 const char *p = NULL;
309 struct ListNode *uh = NULL;
310 STAILQ_FOREACH(uh, &UserHeader, entries)
312 size_t plen = mutt_str_startswith(uh->data, "subject:", CASE_IGNORE);
315 p = mutt_str_skip_email_wsp(uh->data + plen);
316 mutt_str_strfcpy(buf, p, sizeof(buf));
321 if ((mutt_get_field(_("Subject: "), buf, sizeof(buf), 0) != 0) ||
323 (query_quadoption(C_AbortNosubject, _("No subject, abort?")) != MUTT_NO)))
325 mutt_message(_("No subject, aborting"));
328 mutt_str_replace(&en->subject, buf);
335 * nntp_get_header - Get the trimmed header
336 * @param s Header line with leading whitespace
337 * @retval ptr Copy of string
339 * @note The caller should free the returned string.
341 static char *nntp_get_header(const char *s)
344 return mutt_str_strdup(s);
349 * process_user_recips - Process the user headers
350 * @param env Envelope to populate
352 static void process_user_recips(struct Envelope *env)
354 struct ListNode *uh = NULL;
355 STAILQ_FOREACH(uh, &UserHeader, entries)
358 if ((plen = mutt_str_startswith(uh->data, "to:", CASE_IGNORE)))
359 mutt_addrlist_parse(&env->to, uh->data + plen);
360 else if ((plen = mutt_str_startswith(uh->data, "cc:", CASE_IGNORE)))
361 mutt_addrlist_parse(&env->cc, uh->data + plen);
362 else if ((plen = mutt_str_startswith(uh->data, "bcc:", CASE_IGNORE)))
363 mutt_addrlist_parse(&env->bcc, uh->data + plen);
365 else if ((plen = mutt_str_startswith(uh->data, "newsgroups:", CASE_IGNORE)))
366 env->newsgroups = nntp_get_header(uh->data + plen);
367 else if ((plen = mutt_str_startswith(uh->data, "followup-to:", CASE_IGNORE)))
368 env->followup_to = nntp_get_header(uh->data + plen);
369 else if ((plen = mutt_str_startswith(uh->data, "x-comment-to:", CASE_IGNORE)))
370 env->x_comment_to = nntp_get_header(uh->data + plen);
376 * process_user_header - Process the user headers
377 * @param env Envelope to populate
379 static void process_user_header(struct Envelope *env)
381 struct ListNode *uh = NULL;
382 STAILQ_FOREACH(uh, &UserHeader, entries)
385 if ((plen = mutt_str_startswith(uh->data, "from:", CASE_IGNORE)))
387 /* User has specified a default From: address. Remove default address */
388 mutt_addrlist_clear(&env->from);
389 mutt_addrlist_parse(&env->from, uh->data + plen);
391 else if ((plen = mutt_str_startswith(uh->data, "reply-to:", CASE_IGNORE)))
393 mutt_addrlist_clear(&env->reply_to);
394 mutt_addrlist_parse(&env->reply_to, uh->data + plen);
396 else if ((plen = mutt_str_startswith(uh->data, "message-id:", CASE_IGNORE)))
398 char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
399 if (mutt_addr_valid_msgid(tmp))
401 FREE(&env->message_id);
402 env->message_id = tmp;
407 else if (!mutt_str_startswith(uh->data, "to:", CASE_IGNORE) &&
408 !mutt_str_startswith(uh->data, "cc:", CASE_IGNORE) &&
409 !mutt_str_startswith(uh->data, "bcc:", CASE_IGNORE) &&
411 !mutt_str_startswith(uh->data, "newsgroups:", CASE_IGNORE) &&
412 !mutt_str_startswith(uh->data, "followup-to:", CASE_IGNORE) &&
413 !mutt_str_startswith(uh->data, "x-comment-to:", CASE_IGNORE) &&
415 !mutt_str_startswith(uh->data, "supersedes:", CASE_IGNORE) &&
416 !mutt_str_startswith(uh->data, "subject:", CASE_IGNORE) &&
417 !mutt_str_startswith(uh->data, "return-path:", CASE_IGNORE))
419 mutt_list_insert_tail(&env->userhdrs, mutt_str_strdup(uh->data));
425 * mutt_forward_intro - Add the "start of forwarded message" text
428 * @param fp File to write to
430 void mutt_forward_intro(struct Mailbox *m, struct Email *e, FILE *fp)
432 if (!C_ForwardAttributionIntro || !fp)
436 setlocale(LC_TIME, NONULL(C_AttributionLocale));
437 mutt_make_string(buf, sizeof(buf), 0, C_ForwardAttributionIntro, NULL, m, e);
438 setlocale(LC_TIME, "");
444 * mutt_forward_trailer - Add a "end of forwarded message" text
447 * @param fp File to write to
449 void mutt_forward_trailer(struct Mailbox *m, struct Email *e, FILE *fp)
451 if (!C_ForwardAttributionTrailer || !fp)
455 setlocale(LC_TIME, NONULL(C_AttributionLocale));
456 mutt_make_string(buf, sizeof(buf), 0, C_ForwardAttributionTrailer, NULL, m, e);
457 setlocale(LC_TIME, "");
464 * include_forward - Write out a forwarded message
467 * @param fp_out File to write to
471 static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out)
473 CopyHeaderFlags chflags = CH_DECODE;
474 CopyMessageFlags cmflags = MUTT_CM_NO_FLAGS;
476 mutt_parse_mime_message(m, e);
477 mutt_message_hook(m, e, MUTT_MESSAGE_HOOK);
479 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && C_ForwardDecode)
481 /* make sure we have the user's passphrase before proceeding... */
482 if (!crypt_valid_passphrase(e->security))
486 mutt_forward_intro(m, e, fp_out);
490 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
493 chflags |= CH_WEED | CH_REORDER;
494 cmflags |= MUTT_CM_WEED;
498 cmflags |= MUTT_CM_PREFIX;
500 mutt_copy_message(fp_out, m, e, cmflags, chflags, 0);
501 mutt_forward_trailer(m, e, fp_out);
506 * inline_forward_attachments - Add attachments to an email, inline
507 * @param[in] m Mailbox
508 * @param[in] e Current Email
509 * @param[out] plast Pointer to the last Attachment
510 * @param[out] forwardq Result of asking the user to forward the attachments, e.g. #MUTT_YES
514 static int inline_forward_attachments(struct Mailbox *m, struct Email *e,
515 struct Body ***plast, int *forwardq)
517 struct Body **last = *plast;
518 struct Body *body = NULL;
519 struct Message *msg = NULL;
520 struct AttachCtx *actx = NULL;
523 mutt_parse_mime_message(m, e);
524 mutt_message_hook(m, e, MUTT_MESSAGE_HOOK);
526 msg = mx_msg_open(m, e->msgno);
530 actx = mutt_mem_calloc(1, sizeof(*actx));
532 actx->fp_root = msg->fp;
534 mutt_generate_recvattach_list(actx, actx->email, actx->email->content,
535 actx->fp_root, -1, 0, 0);
537 for (i = 0; i < actx->idxlen; i++)
539 body = actx->idx[i]->content;
540 if ((body->type != TYPE_MULTIPART) && !mutt_can_decode(body) &&
541 !((body->type == TYPE_APPLICATION) &&
542 ((mutt_str_strcasecmp(body->subtype, "pgp-signature") == 0) ||
543 (mutt_str_strcasecmp(body->subtype, "x-pkcs7-signature") == 0) ||
544 (mutt_str_strcasecmp(body->subtype, "pkcs7-signature") == 0))))
546 /* Ask the quadoption only once */
549 *forwardq = query_quadoption(C_ForwardAttachments,
551 This is the prompt for $forward_attachments.
552 When inline forwarding ($mime_forward answered "no"), this prompts
553 whether to add non-decodable attachments from the original email.
554 Text/plain parts and the like will already be included in the
555 message contents, but other attachment, such as PDF files, will also
556 be added as attachments to the new mail, if this is answered yes.
558 _("Forward attachments?"));
559 if (*forwardq != MUTT_YES)
566 if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1)
571 last = &((*last)->next);
577 mx_msg_close(m, &msg);
578 mutt_actx_free(&actx);
583 * mutt_inline_forward - Forward attachments, inline
585 * @param e_edit Email to alter
586 * @param e_cur Current Email
591 int mutt_inline_forward(struct Mailbox *m, struct Email *e_edit,
592 struct Email *e_cur, FILE *out)
594 int i, forwardq = -1;
595 struct Body **last = NULL;
598 include_forward(m, e_cur, out);
600 for (i = 0; i < m->vcount; i++)
601 if (m->emails[m->v2r[i]]->tagged)
602 include_forward(m, m->emails[m->v2r[i]], out);
604 if (C_ForwardDecode && (C_ForwardAttachments != MUTT_NO))
606 last = &e_edit->content;
608 last = &((*last)->next);
612 if (inline_forward_attachments(m, e_cur, &last, &forwardq) != 0)
616 for (i = 0; i < m->vcount; i++)
617 if (m->emails[m->v2r[i]]->tagged)
619 if (inline_forward_attachments(m, m->emails[m->v2r[i]], &last, &forwardq) != 0)
621 if (forwardq == MUTT_NO)
630 * mutt_make_attribution - Add "on DATE, PERSON wrote" header
633 * @param fp_out File to write to
635 void mutt_make_attribution(struct Mailbox *m, struct Email *e, FILE *fp_out)
637 if (!C_Attribution || !fp_out)
641 setlocale(LC_TIME, NONULL(C_AttributionLocale));
642 mutt_make_string(buf, sizeof(buf), 0, C_Attribution, NULL, m, e);
643 setlocale(LC_TIME, "");
649 * mutt_make_post_indent - Add suffix to replied email text
652 * @param fp_out File to write to
654 void mutt_make_post_indent(struct Mailbox *m, struct Email *e, FILE *fp_out)
656 if (!C_PostIndentString || !fp_out)
660 mutt_make_string(buf, sizeof(buf), 0, C_PostIndentString, NULL, m, e);
666 * include_reply - Generate the reply text for an email
669 * @param fp_out File to write to
673 static int include_reply(struct Mailbox *m, struct Email *e, FILE *fp_out)
675 CopyMessageFlags cmflags =
676 MUTT_CM_PREFIX | MUTT_CM_DECODE | MUTT_CM_CHARCONV | MUTT_CM_REPLYING;
677 CopyHeaderFlags chflags = CH_DECODE;
679 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
681 /* make sure we have the user's passphrase before proceeding... */
682 if (!crypt_valid_passphrase(e->security))
686 mutt_parse_mime_message(m, e);
687 mutt_message_hook(m, e, MUTT_MESSAGE_HOOK);
689 mutt_make_attribution(m, e, fp_out);
692 cmflags |= MUTT_CM_NOHEADER;
695 chflags |= CH_WEED | CH_REORDER;
696 cmflags |= MUTT_CM_WEED;
699 mutt_copy_message(fp_out, m, e, cmflags, chflags, 0);
701 mutt_make_post_indent(m, e, fp_out);
707 * choose_default_to - Pick the best 'to:' value
708 * @param from From Address
709 * @param env Envelope
710 * @retval ptr Addresses to use
712 static const struct AddressList *choose_default_to(const struct Address *from,
713 const struct Envelope *env)
715 if (!C_ReplySelf && mutt_addr_is_user(from))
717 /* mail is from the user, assume replying to recipients */
727 * default_to - Generate default email addresses
728 * @param[in,out] to 'To' address
729 * @param[in] env Envelope to populate
730 * @param[in] flags Flags, see #SendFlags
731 * @param[in] hmfupto If true, add 'followup-to' address to 'to' address
735 static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto)
738 const struct Address *from = TAILQ_FIRST(&env->from);
739 const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
741 if (flags && !TAILQ_EMPTY(&env->mail_followup_to) && (hmfupto == MUTT_YES))
743 mutt_addrlist_copy(to, &env->mail_followup_to, true);
747 /* Exit now if we're setting up the default Cc list for list-reply
748 * (only set if Mail-Followup-To is present and honoured). */
749 if (flags & SEND_LIST_REPLY)
752 const struct AddressList *default_to = choose_default_to(from, env);
756 const bool from_is_reply_to = mutt_addr_cmp(from, reply_to);
757 const bool multiple_reply_to =
758 reply_to && TAILQ_NEXT(TAILQ_FIRST(&env->reply_to), entries);
759 if ((from_is_reply_to && !multiple_reply_to && !reply_to->personal) ||
760 (C_IgnoreListReplyTo && mutt_is_mail_list(reply_to) &&
761 (mutt_addrlist_search(reply_to, &env->to) ||
762 mutt_addrlist_search(reply_to, &env->cc))))
764 /* If the Reply-To: address is a mailing list, assume that it was
765 * put there by the mailing list, and use the From: address
767 * We also take the from header if our correspondent has a reply-to
768 * header which is identical to the electronic mail address given
769 * in his From header, and the reply-to has no display-name. */
770 mutt_addrlist_copy(to, &env->from, false);
772 else if (!(from_is_reply_to && !multiple_reply_to) && (C_ReplyTo != MUTT_YES))
774 /* There are quite a few mailing lists which set the Reply-To:
775 * header field to the list address, which makes it quite impossible
776 * to send a message to only the sender of the message. This
777 * provides a way to do that. */
778 /* L10N: Asks whether the user respects the reply-to header.
779 If she says no, neomutt will reply to the from header's address instead. */
780 snprintf(prompt, sizeof(prompt), _("Reply to %s%s?"), reply_to->mailbox,
781 multiple_reply_to ? ",..." : "");
782 switch (query_quadoption(C_ReplyTo, prompt))
785 mutt_addrlist_copy(to, &env->reply_to, false);
789 mutt_addrlist_copy(to, default_to, false);
793 return -1; /* abort */
798 mutt_addrlist_copy(to, &env->reply_to, false);
803 mutt_addrlist_copy(to, default_to, false);
810 * mutt_fetch_recips - Generate recpients for a reply email
811 * @param out Envelope to populate
812 * @param in Envelope of source email
813 * @param flags Flags, see #SendFlags
817 int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags)
819 enum QuadOption hmfupto = MUTT_ABORT;
820 const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
822 if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
825 snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"), followup_to->mailbox,
826 TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
828 hmfupto = query_quadoption(C_HonorFollowupTo, prompt);
829 if (hmfupto == MUTT_ABORT)
833 if (flags & SEND_LIST_REPLY)
835 add_mailing_lists(&out->to, &in->to, &in->cc);
837 if (followup_to && (hmfupto == MUTT_YES) &&
838 (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES)) == MUTT_ABORT))
840 return -1; /* abort */
843 else if (flags & SEND_TO_SENDER)
845 mutt_addrlist_copy(&out->to, &in->from, false);
849 if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
850 (hmfupto == MUTT_YES)) == -1)
851 return -1; /* abort */
853 if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
854 (!followup_to || (hmfupto != MUTT_YES)))
856 /* if(!mutt_addr_is_user(in->to)) */
857 if (flags & SEND_GROUP_REPLY)
858 mutt_addrlist_copy(&out->cc, &in->to, true);
860 mutt_addrlist_copy(&out->to, &in->cc, true);
861 mutt_addrlist_copy(&out->cc, &in->cc, true);
868 * add_references - Add the email's references to a list
869 * @param head List of references
870 * @param env Envelope of message
872 static void add_references(struct ListHead *head, struct Envelope *env)
874 struct ListNode *np = NULL;
876 struct ListHead *src = !STAILQ_EMPTY(&env->references) ? &env->references : &env->in_reply_to;
877 STAILQ_FOREACH(np, src, entries)
879 mutt_list_insert_tail(head, mutt_str_strdup(np->data));
884 * add_message_id - Add the email's message ID to a list
885 * @param head List of message IDs
886 * @param env Envelope of message
888 static void add_message_id(struct ListHead *head, struct Envelope *env)
892 mutt_list_insert_head(head, mutt_str_strdup(env->message_id));
897 * mutt_fix_reply_recipients - Remove duplicate recipients
898 * @param env Envelope to fix
900 void mutt_fix_reply_recipients(struct Envelope *env)
904 /* the order is important here. do the CC: first so that if the
905 * the user is the only recipient, it ends up on the TO: field */
906 remove_user(&env->cc, TAILQ_EMPTY(&env->to));
907 remove_user(&env->to, TAILQ_EMPTY(&env->cc) || C_ReplySelf);
910 /* the CC field can get cluttered, especially with lists */
911 mutt_addrlist_dedupe(&env->to);
912 mutt_addrlist_dedupe(&env->cc);
913 mutt_addrlist_remove_xrefs(&env->to, &env->cc);
915 if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
917 TAILQ_SWAP(&env->to, &env->cc, Address, entries);
922 * mutt_make_forward_subject - Create a subject for a forwarded email
923 * @param env Envelope for result
927 void mutt_make_forward_subject(struct Envelope *env, struct Mailbox *m, struct Email *e)
934 /* set the default subject for the message. */
935 mutt_make_string(buf, sizeof(buf), 0, NONULL(C_ForwardFormat), NULL, m, e);
936 mutt_str_replace(&env->subject, buf);
940 * mutt_make_misc_reply_headers - Set subject for a reply
941 * @param env Envelope for result
942 * @param curenv Envelope of source email
944 void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *curenv)
949 /* This takes precedence over a subject that might have
950 * been taken from a List-Post header. Is that correct? */
951 if (curenv->real_subj)
954 env->subject = mutt_mem_malloc(mutt_str_strlen(curenv->real_subj) + 5);
955 sprintf(env->subject, "Re: %s", curenv->real_subj);
957 else if (!env->subject)
958 env->subject = mutt_str_strdup(C_EmptySubject);
962 * mutt_add_to_reference_headers - Generate references for a reply email
963 * @param env Envelope for result
964 * @param curenv Envelope of source email
966 void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *curenv)
968 add_references(&env->references, curenv);
969 add_message_id(&env->references, curenv);
970 add_message_id(&env->in_reply_to, curenv);
973 if (OptNewsSend && C_XCommentTo && !TAILQ_EMPTY(&curenv->from))
974 env->x_comment_to = mutt_str_strdup(mutt_get_name(TAILQ_FIRST(&curenv->from)));
979 * make_reference_headers - Generate reference headers for an email
980 * @param el List of source Emails
981 * @param env Envelope for result
983 static void make_reference_headers(struct EmailList *el, struct Envelope *env)
985 if (!el || !env || STAILQ_EMPTY(el))
988 struct EmailNode *en = STAILQ_FIRST(el);
989 bool single = !STAILQ_NEXT(en, entries);
993 STAILQ_FOREACH(en, el, entries)
995 mutt_add_to_reference_headers(env, en->email->env);
999 mutt_add_to_reference_headers(env, en->email->env);
1001 /* if there's more than entry in In-Reply-To (i.e. message has multiple
1002 * parents), don't generate a References: header as it's discouraged by
1003 * RFC2822, sect. 3.6.4 */
1004 if (!single && !STAILQ_EMPTY(&env->in_reply_to) &&
1005 STAILQ_NEXT(STAILQ_FIRST(&env->in_reply_to), entries))
1007 mutt_list_free(&env->references);
1012 * envelope_defaults - Fill in some defaults for a new email
1013 * @param env Envelope for result
1015 * @param el List of Emails to use
1016 * @param flags Flags, see #SendFlags
1018 * @retval -1 Failure
1020 static int envelope_defaults(struct Envelope *env, struct Mailbox *m,
1021 struct EmailList *el, SendFlags flags)
1023 if (!el || STAILQ_EMPTY(el))
1026 struct EmailNode *en = STAILQ_FIRST(el);
1027 bool single = !STAILQ_NEXT(en, entries);
1029 struct Envelope *curenv = en->email->env;
1033 if (flags & (SEND_REPLY | SEND_TO_SENDER))
1036 if ((flags & SEND_NEWS))
1038 /* in case followup set Newsgroups: with Followup-To: if it present */
1039 if (!env->newsgroups &&
1040 (mutt_str_strcasecmp(curenv->followup_to, "poster") != 0))
1042 env->newsgroups = mutt_str_strdup(curenv->followup_to);
1049 STAILQ_FOREACH(en, el, entries)
1051 if (mutt_fetch_recips(env, en->email->env, flags) == -1)
1055 else if (mutt_fetch_recips(env, curenv, flags) == -1)
1058 if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1060 mutt_error(_("No mailing lists found"));
1064 if (flags & SEND_REPLY)
1066 mutt_make_misc_reply_headers(env, curenv);
1067 make_reference_headers(el, env);
1070 else if (flags & SEND_FORWARD)
1072 mutt_make_forward_subject(env, m, en->email);
1073 if (C_ForwardReferences)
1074 make_reference_headers(el, env);
1081 * generate_body - Create a new email body
1082 * @param fp_tmp Stream for outgoing message
1083 * @param e Email for outgoing message
1084 * @param flags Compose mode, see #SendFlags
1086 * @param el List of Emails to use
1090 static int generate_body(FILE *fp_tmp, struct Email *e, SendFlags flags,
1091 struct Mailbox *m, struct EmailList *el)
1093 struct Body *tmp = NULL;
1094 struct EmailNode *en = NULL;
1098 en = STAILQ_FIRST(el);
1100 single = !STAILQ_NEXT(en, entries);
1102 /* An EmailList is required for replying and forwarding */
1103 if (!el && (flags & (SEND_REPLY | SEND_FORWARD)))
1106 if (flags & SEND_REPLY)
1108 enum QuadOption ans =
1109 query_quadoption(C_Include, _("Include message in reply?"));
1110 if (ans == MUTT_ABORT)
1113 if (ans == MUTT_YES)
1115 mutt_message(_("Including quoted message..."));
1117 include_reply(m, en->email, fp_tmp);
1120 STAILQ_FOREACH(en, el, entries)
1122 if (include_reply(m, en->email, fp_tmp) == -1)
1124 mutt_error(_("Could not include all requested messages"));
1127 fputc('\n', fp_tmp);
1132 else if (flags & SEND_FORWARD)
1134 enum QuadOption ans =
1135 query_quadoption(C_MimeForward, _("Forward as attachment?"));
1136 if (ans == MUTT_YES)
1138 struct Body *last = e->content;
1140 mutt_message(_("Preparing forwarded message..."));
1142 while (last && last->next)
1147 tmp = mutt_make_message_attach(m, en->email, false);
1155 STAILQ_FOREACH(en, el, entries)
1157 tmp = mutt_make_message_attach(m, en->email, false);
1171 else if ((ans != MUTT_ABORT) && en)
1173 if (mutt_inline_forward(m, e, en->email, fp_tmp) != 0)
1179 /* if (WithCrypto && (flags & SEND_KEY)) */
1180 else if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY))
1182 struct Body *b = NULL;
1184 if (((WithCrypto & APPLICATION_PGP) != 0) && !(b = crypt_pgp_make_key_attachment()))
1189 b->next = e->content;
1199 * mutt_set_followup_to - Set followup-to field
1200 * @param env Envelope to modify
1202 void mutt_set_followup_to(struct Envelope *env)
1204 /* Only generate the Mail-Followup-To if the user has requested it, and
1205 * it hasn't already been set */
1212 if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1213 env->followup_to = mutt_str_strdup(env->newsgroups);
1218 if (TAILQ_EMPTY(&env->mail_followup_to))
1220 if (mutt_is_list_recipient(false, env))
1222 /* this message goes to known mailing lists, so create a proper
1223 * mail-followup-to header */
1225 mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1226 mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1229 /* remove ourselves from the mail-followup-to header */
1230 remove_user(&env->mail_followup_to, false);
1232 /* If we are not subscribed to any of the lists in question, re-add
1233 * ourselves to the mail-followup-to header. The mail-followup-to header
1234 * generated is a no-op with group-reply, but makes sure list-reply has the
1235 * desired effect. */
1237 if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1238 !mutt_is_subscribed_list_recipient(false, env))
1240 struct AddressList *al = NULL;
1241 if (!TAILQ_EMPTY(&env->reply_to))
1242 al = &env->reply_to;
1243 else if (!TAILQ_EMPTY(&env->from))
1248 struct Address *a = NULL;
1249 TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1251 mutt_addrlist_prepend(&env->mail_followup_to, mutt_addr_copy(a));
1256 mutt_addrlist_prepend(&env->mail_followup_to, mutt_default_from());
1260 mutt_addrlist_dedupe(&env->mail_followup_to);
1265 * set_reverse_name - Try to set the 'from' field from the recipients
1266 * @param al AddressList to prepend the found address
1267 * @param env Envelope to use
1269 * Look through the recipients of the message we are replying to, and if we
1270 * find an address that matches $alternates, we use that as the default from
1273 static void set_reverse_name(struct AddressList *al, struct Envelope *env)
1275 struct Address *a = NULL;
1276 if (TAILQ_EMPTY(al))
1278 TAILQ_FOREACH(a, &env->to, entries)
1280 if (mutt_addr_is_user(a))
1282 mutt_addrlist_append(al, mutt_addr_copy(a));
1288 if (TAILQ_EMPTY(al))
1290 TAILQ_FOREACH(a, &env->cc, entries)
1292 if (mutt_addr_is_user(a))
1294 mutt_addrlist_append(al, mutt_addr_copy(a));
1300 if (TAILQ_EMPTY(al))
1302 struct Address *from = TAILQ_FIRST(&env->from);
1303 if (from && mutt_addr_is_user(from))
1305 mutt_addrlist_append(al, mutt_addr_copy(from));
1309 if (!TAILQ_EMPTY(al))
1311 /* when $reverse_realname is not set, clear the personal name so that it
1312 * may be set via a reply- or send-hook. */
1313 if (!C_ReverseRealname)
1314 FREE(&TAILQ_FIRST(al)->personal);
1319 * mutt_default_from - Get a default 'from' Address
1320 * @retval ptr Newly allocated Address
1322 struct Address *mutt_default_from(void)
1324 /* Note: We let $from override $realname here.
1325 * Is this the right thing to do?
1330 return mutt_addr_copy(C_From);
1332 else if (C_UseDomain)
1334 struct Address *addr = mutt_addr_new();
1335 mutt_str_asprintf(&addr->mailbox, "%s@%s", NONULL(Username), NONULL(mutt_fqdn(true)));
1340 return mutt_addr_create(NULL, Username);
1345 * send_message - Send an email
1348 * @retval -1 Failure
1350 static int send_message(struct Email *e)
1352 struct Buffer *tempfile = NULL;
1355 short old_write_bcc;
1358 /* Write out the message in MIME form. */
1359 tempfile = mutt_buffer_pool_get();
1360 mutt_buffer_mktemp(tempfile);
1361 FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tempfile), "w");
1366 old_write_bcc = C_WriteBcc;
1371 mutt_rfc822_write_header(fp_tmp, e->env, e->content, MUTT_WRITE_HEADER_NORMAL,
1372 !STAILQ_EMPTY(&e->chain),
1373 mutt_should_hide_protected_subject(e));
1376 mutt_rfc822_write_header(fp_tmp, e->env, e->content, MUTT_WRITE_HEADER_NORMAL,
1377 false, mutt_should_hide_protected_subject(e));
1384 fputc('\n', fp_tmp); /* tie off the header. */
1386 if ((mutt_write_mime_body(e->content, fp_tmp) == -1))
1389 if (mutt_file_fclose(&fp_tmp) != 0)
1391 mutt_perror(mutt_b2s(tempfile));
1392 unlink(mutt_b2s(tempfile));
1397 if (!STAILQ_EMPTY(&e->chain))
1399 i = mix_send_message(&e->chain, mutt_b2s(tempfile));
1412 i = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1413 mutt_b2s(tempfile), (e->content->encoding == ENC_8BIT));
1419 i = mutt_invoke_sendmail(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1420 mutt_b2s(tempfile), (e->content->encoding == ENC_8BIT));
1424 mutt_file_fclose(&fp_tmp);
1425 unlink(mutt_b2s(tempfile));
1427 mutt_buffer_pool_release(&tempfile);
1432 * mutt_encode_descriptions - rfc2047 encode the content-descriptions
1433 * @param b Body of email
1434 * @param recurse If true, encode children parts
1436 void mutt_encode_descriptions(struct Body *b, bool recurse)
1438 for (struct Body *t = b; t; t = t->next)
1442 rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), C_SendCharset);
1444 if (recurse && t->parts)
1445 mutt_encode_descriptions(t->parts, recurse);
1450 * decode_descriptions - rfc2047 decode them in case of an error
1451 * @param b MIME parts to decode
1453 static void decode_descriptions(struct Body *b)
1455 for (struct Body *t = b; t; t = t->next)
1459 rfc2047_decode(&t->description);
1462 decode_descriptions(t->parts);
1467 * fix_end_of_file - Ensure a file ends with a linefeed
1468 * @param data Name of file to fix
1470 static void fix_end_of_file(const char *data)
1472 FILE *fp = mutt_file_fopen(data, "a+");
1475 if (fseek(fp, -1, SEEK_END) >= 0)
1481 mutt_file_fclose(&fp);
1485 * mutt_resend_message - Resend an email
1486 * @param fp File containing email
1487 * @param ctx Mailbox
1488 * @param e_cur Email to resend
1489 * @retval 0 Message was successfully sent
1490 * @retval -1 Message was aborted or an error occurred
1491 * @retval 1 Message was postponed
1493 int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur)
1495 struct Email *e_new = email_new();
1497 if (mutt_prepare_template(fp, ctx->mailbox, e_new, e_cur, true) < 0)
1505 /* mutt_prepare_template doesn't always flip on an application bit.
1506 * so fix that here */
1507 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1509 if (((WithCrypto & APPLICATION_SMIME) != 0) && C_SmimeIsDefault)
1510 e_new->security |= APPLICATION_SMIME;
1511 else if (WithCrypto & APPLICATION_PGP)
1512 e_new->security |= APPLICATION_PGP;
1514 e_new->security |= APPLICATION_SMIME;
1517 if (C_CryptOpportunisticEncrypt)
1519 e_new->security |= SEC_OPPENCRYPT;
1520 crypt_opportunistic_encrypt(e_new);
1524 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1525 el_add_email(&el, e_cur);
1526 int rc = ci_send_message(SEND_RESEND, e_new, NULL, ctx, &el);
1527 emaillist_clear(&el);
1533 * is_reply - Is one email a reply to another?
1534 * @param reply Email to test
1535 * @param orig Original email
1536 * @retval true It is a reply
1537 * @retval false It is not a reply
1539 static bool is_reply(struct Email *reply, struct Email *orig)
1541 if (!reply || !reply->env || !orig || !orig->env)
1543 return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1544 mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1548 * search_attach_keyword - Search an email for 'attachment' keywords
1549 * @param filename Filename
1550 * @retval true If the regex matches in the email
1552 * Search an email for the regex in $abort_noattach_regex.
1553 * A match might indicate that the user should have attached something.
1555 * @note Quoted lines (as defined by $quote_regex) are ignored
1557 static bool search_attach_keyword(char *filename)
1559 /* Search for the regex in C_AbortNoattachRegex within a file */
1560 if (!C_AbortNoattachRegex || !C_AbortNoattachRegex->regex || !C_QuoteRegex ||
1561 !C_QuoteRegex->regex)
1566 FILE *fp_att = mutt_file_fopen(filename, "r");
1570 char *inputline = mutt_mem_malloc(1024);
1572 while (!feof(fp_att))
1574 fgets(inputline, 1024, fp_att);
1575 if (!mutt_is_quote_line(inputline, NULL) &&
1576 mutt_regex_match(C_AbortNoattachRegex, inputline))
1583 mutt_file_fclose(&fp_att);
1588 * save_fcc - Save an Email to a 'sent mail' folder
1589 * @param[in] e Email to save
1590 * @param[in] fcc Folder to save to (can be comma-separated list)
1591 * @param[in] clear_content Cleartext content of Email
1592 * @param[in] pgpkeylist List of pgp keys
1593 * @param[in] flags Send mode, see #SendFlags
1594 * @param[out] finalpath Path of final folder
1598 static int save_fcc(struct Email *e, struct Buffer *fcc, struct Body *clear_content,
1599 char *pgpkeylist, SendFlags flags, char **finalpath)
1602 struct Body *save_content = NULL;
1604 mutt_buffer_expand_path(fcc);
1606 /* Don't save a copy when we are in batch-mode, and the FCC
1607 * folder is on an IMAP server: This would involve possibly lots
1608 * of user interaction, which is not available in batch mode.
1610 * Note: A patch to fix the problems with the use of IMAP servers
1611 * from non-curses mode is available from Brendan Cully. However,
1612 * I'd like to think a bit more about this before including it. */
1615 if ((flags & SEND_BATCH) && !mutt_buffer_is_empty(fcc) &&
1616 (imap_path_probe(mutt_b2s(fcc), NULL) == MUTT_IMAP))
1618 mutt_buffer_reset(fcc);
1619 mutt_error(_("Fcc to an IMAP mailbox is not supported in batch mode"));
1624 if (mutt_buffer_is_empty(fcc) || (mutt_str_strcmp("/dev/null", mutt_b2s(fcc)) == 0))
1627 struct Body *tmpbody = e->content;
1628 struct Body *save_sig = NULL;
1629 struct Body *save_parts = NULL;
1631 /* Before sending, we don't allow message manipulation because it
1632 * will break message signatures. This is especially complicated by
1633 * Protected Headers. */
1634 if (!C_FccBeforeSend)
1636 if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) && C_FccClear)
1638 e->content = clear_content;
1639 e->security &= ~(SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT);
1640 mutt_env_free(&e->content->mime_headers);
1643 /* check to see if the user wants copies of all attachments */
1644 if (e->content->type == TYPE_MULTIPART)
1646 if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) &&
1647 ((mutt_str_strcmp(e->content->subtype, "encrypted") == 0) ||
1648 (mutt_str_strcmp(e->content->subtype, "signed") == 0)))
1650 if ((clear_content->type == TYPE_MULTIPART) &&
1651 (query_quadoption(C_FccAttach, _("Save attachments in Fcc?")) == MUTT_NO))
1653 if (!(e->security & SEC_ENCRYPT) && (e->security & SEC_SIGN))
1655 /* save initial signature and attachments */
1656 save_sig = e->content->parts->next;
1657 save_parts = clear_content->parts->next;
1660 /* this means writing only the main part */
1661 e->content = clear_content->parts;
1663 if (mutt_protect(e, pgpkeylist, false) == -1)
1665 /* we can't do much about it at this point, so
1666 * fallback to saving the whole thing to fcc */
1667 e->content = tmpbody;
1672 save_content = e->content;
1677 if (query_quadoption(C_FccAttach, _("Save attachments in Fcc?")) == MUTT_NO)
1678 e->content = e->content->parts;
1686 /* update received time so that when storing to a mbox-style folder
1687 * the From_ line contains the current time instead of when the
1688 * message was first postponed. */
1689 e->received = mutt_date_epoch();
1690 rc = mutt_write_multiple_fcc(mutt_b2s(fcc), e, NULL, false, NULL, finalpath);
1691 while (rc && !(flags & SEND_BATCH))
1694 int choice = mutt_multi_choice(
1695 /* L10N: Called when saving to $record or Fcc failed after sending.
1696 (r)etry tries the same mailbox again.
1697 alternate (m)ailbox prompts for a different mailbox to try.
1698 (s)kip aborts saving. */
1699 _("Fcc failed. (r)etry, alternate (m)ailbox, or (s)kip?"),
1700 /* L10N: These correspond to the "Fcc failed" multi-choice prompt
1701 (r)etry, alternate (m)ailbox, or (s)kip.
1702 Any similarity to famous leaders of the FSF is coincidental. */
1706 case 2: /* alternate (m)ailbox */
1707 /* L10N: This is the prompt to enter an "alternate (m)ailbox" when the
1708 initial Fcc fails. */
1709 rc = mutt_buffer_enter_fname(_("Fcc mailbox"), fcc, true);
1710 if ((rc == -1) || mutt_buffer_is_empty(fcc))
1717 case 1: /* (r)etry */
1718 rc = mutt_write_multiple_fcc(mutt_b2s(fcc), e, NULL, false, NULL, finalpath);
1721 case -1: /* abort */
1722 case 3: /* (s)kip */
1729 if (!C_FccBeforeSend)
1731 e->content = tmpbody;
1733 if ((WithCrypto != 0) && save_sig)
1735 /* cleanup the second signature structures */
1736 if (save_content->parts)
1738 mutt_body_free(&save_content->parts->next);
1739 save_content->parts = NULL;
1741 mutt_body_free(&save_content);
1743 /* restore old signature and attachments */
1744 e->content->parts->next = save_sig;
1745 e->content->parts->parts->next = save_parts;
1747 else if ((WithCrypto != 0) && save_content)
1749 /* destroy the new encrypted body. */
1750 mutt_body_free(&save_content);
1758 * postpone_message - Save an Email for another day
1759 * @param e_post Email to postpone
1760 * @param e_cur Current Email in the index
1761 * @param fcc Folder for 'sent mail'
1762 * @param flags Send mode, see #SendFlags
1766 static int postpone_message(struct Email *e_post, struct Email *e_cur,
1767 const char *fcc, SendFlags flags)
1769 char *pgpkeylist = NULL;
1770 char *encrypt_as = NULL;
1771 struct Body *clear_content = NULL;
1775 mutt_error(_("Can't postpone. $postponed is unset"));
1779 if (e_post->content->next)
1780 e_post->content = mutt_make_multipart(e_post->content);
1782 mutt_encode_descriptions(e_post->content, true);
1784 if ((WithCrypto != 0) && C_PostponeEncrypt &&
1785 (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
1787 if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
1788 encrypt_as = C_PgpDefaultKey;
1789 else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e_post->security & APPLICATION_SMIME))
1790 encrypt_as = C_SmimeDefaultKey;
1792 encrypt_as = C_PostponeEncryptAs;
1794 #ifdef USE_AUTOCRYPT
1795 if (e_post->security & SEC_AUTOCRYPT)
1797 if (mutt_autocrypt_set_sign_as_default_key(e_post))
1799 e_post->content = mutt_remove_multipart(e_post->content);
1800 decode_descriptions(e_post->content);
1803 encrypt_as = AutocryptDefaultKey;
1809 pgpkeylist = mutt_str_strdup(encrypt_as);
1810 clear_content = e_post->content;
1811 if (mutt_protect(e_post, pgpkeylist, true) == -1)
1814 e_post->content = mutt_remove_multipart(e_post->content);
1815 decode_descriptions(e_post->content);
1821 mutt_encode_descriptions(e_post->content, false);
1825 /* make sure the message is written to the right part of a maildir
1826 * postponed folder. */
1827 e_post->read = false;
1828 e_post->old = false;
1830 mutt_prepare_envelope(e_post->env, false);
1831 mutt_env_to_intl(e_post->env, NULL, NULL); /* Handle bad IDNAs the next time. */
1833 if (mutt_write_fcc(NONULL(C_Postponed), e_post,
1834 (e_cur && (flags & SEND_REPLY)) ? e_cur->env->message_id : NULL,
1835 true, fcc, NULL) < 0)
1839 mutt_body_free(&e_post->content);
1840 e_post->content = clear_content;
1842 mutt_env_free(&e_post->content->mime_headers); /* protected headers */
1843 e_post->content = mutt_remove_multipart(e_post->content);
1844 decode_descriptions(e_post->content);
1845 mutt_unprepare_envelope(e_post->env);
1849 mutt_update_num_postponed();
1852 mutt_body_free(&clear_content);
1858 * ci_send_message - Send an email
1859 * @param flags Send mode, see #SendFlags
1860 * @param e_templ Template to use for new message
1861 * @param tempfile File specified by -i or -H
1862 * @param ctx Current mailbox
1863 * @param el List of Emails to send
1864 * @retval 0 Message was successfully sent
1865 * @retval -1 Message was aborted or an error occurred
1866 * @retval 1 Message was postponed
1868 int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile,
1869 struct Context *ctx, struct EmailList *el)
1872 struct Buffer fcc = mutt_buffer_make(0); /* where to copy this message */
1873 FILE *fp_tmp = NULL;
1874 struct Body *pbody = NULL;
1876 bool free_clear_content = false;
1878 struct Body *clear_content = NULL;
1879 char *pgpkeylist = NULL;
1880 /* save current value of "pgp_sign_as" and "smime_default_key" */
1881 char *pgp_signas = NULL;
1882 char *smime_signas = NULL;
1883 const char *tag = NULL;
1886 char *finalpath = NULL;
1887 struct EmailNode *en = NULL;
1888 struct Email *e_cur = NULL;
1891 en = STAILQ_FIRST(el);
1893 e_cur = STAILQ_NEXT(en, entries) ? NULL : en->email;
1898 if (flags & SEND_NEWS)
1901 OptNewsSend = false;
1904 if (!flags && !e_templ && (C_Recall != MUTT_NO) &&
1905 mutt_num_postponed(ctx ? ctx->mailbox : NULL, true))
1907 /* If the user is composing a new message, check to see if there
1908 * are any postponed messages first. */
1909 enum QuadOption ans =
1910 query_quadoption(C_Recall, _("Recall postponed message?"));
1911 if (ans == MUTT_ABORT)
1914 if (ans == MUTT_YES)
1915 flags |= SEND_POSTPONED;
1918 /* Allocate the buffer due to the long lifetime, but
1919 * pre-resize it to ensure there are no NULL data field issues */
1920 mutt_buffer_alloc(&fcc, 1024);
1922 if (flags & SEND_POSTPONED)
1924 if (WithCrypto & APPLICATION_PGP)
1925 pgp_signas = mutt_str_strdup(C_PgpSignAs);
1926 if (WithCrypto & APPLICATION_SMIME)
1927 smime_signas = mutt_str_strdup(C_SmimeSignAs);
1930 /* Delay expansion of aliases until absolutely necessary--shouldn't
1931 * be necessary unless we are prompting the user or about to execute a
1936 e_templ = email_new();
1938 if (flags == SEND_POSTPONED)
1940 rc = mutt_get_postponed(ctx, e_templ, &e_cur, &fcc);
1943 flags = SEND_POSTPONED;
1948 /* If postponed message is a news article, it have
1949 * a "Newsgroups:" header line, then set appropriate flag. */
1950 if (e_templ->env->newsgroups)
1957 flags &= ~SEND_NEWS;
1958 OptNewsSend = false;
1963 if (flags & (SEND_POSTPONED | SEND_RESEND))
1965 fp_tmp = mutt_file_fopen(e_templ->content->filename, "a+");
1968 mutt_perror(e_templ->content->filename);
1974 e_templ->env = mutt_env_new();
1977 /* Parse and use an eventual list-post header */
1978 if ((flags & SEND_LIST_REPLY) && e_cur && e_cur->env && e_cur->env->list_post)
1980 /* Use any list-post header as a template */
1981 mutt_parse_mailto(e_templ->env, NULL, e_cur->env->list_post);
1982 /* We don't let them set the sender's address. */
1983 mutt_addrlist_clear(&e_templ->env->from);
1986 if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND)))
1988 /* When SEND_DRAFT_FILE is set, the caller has already
1989 * created the "parent" body structure. */
1990 if (!(flags & SEND_DRAFT_FILE))
1992 pbody = mutt_body_new();
1993 pbody->next = e_templ->content; /* don't kill command-line attachments */
1994 e_templ->content = pbody;
1996 ctype = mutt_str_strdup(C_ContentType);
1998 ctype = mutt_str_strdup("text/plain");
1999 mutt_parse_content_type(ctype, e_templ->content);
2001 e_templ->content->unlink = true;
2002 e_templ->content->use_disp = false;
2003 e_templ->content->disposition = DISP_INLINE;
2007 fp_tmp = mutt_file_fopen(tempfile, "a+");
2008 e_templ->content->filename = mutt_str_strdup(tempfile);
2012 mutt_mktemp(buf, sizeof(buf));
2013 fp_tmp = mutt_file_fopen(buf, "w+");
2014 e_templ->content->filename = mutt_str_strdup(buf);
2018 fp_tmp = mutt_file_fopen(e_templ->content->filename, "a+");
2022 mutt_debug(LL_DEBUG1, "can't create tempfile %s (errno=%d)\n",
2023 e_templ->content->filename, errno);
2024 mutt_perror(e_templ->content->filename);
2029 /* this is handled here so that the user can match ~f in send-hook */
2030 if (e_cur && C_ReverseName && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2032 /* We shouldn't have to worry about alias expansion here since we are
2033 * either replying to a real or postponed message, therefore no aliases
2034 * should exist since the user has not had the opportunity to add
2035 * addresses to the list. We just have to ensure the postponed messages
2036 * have their aliases expanded. */
2038 if (!TAILQ_EMPTY(&e_templ->env->from))
2040 mutt_debug(LL_DEBUG5, "e_templ->env->from before set_reverse_name: %s\n",
2041 TAILQ_FIRST(&e_templ->env->from)->mailbox);
2042 mutt_addrlist_clear(&e_templ->env->from);
2044 set_reverse_name(&e_templ->env->from, e_cur->env);
2046 if (e_cur && C_ReplyWithXorig && !(flags & (SEND_POSTPONED | SEND_RESEND | SEND_FORWARD)))
2048 /* We shouldn't have to worry about freeing 'e_templ->env->from' before
2049 * setting it here since this code will only execute when doing some
2050 * sort of reply. The pointer will only be set when using the -H command
2053 * If there is already a from address recorded in 'e_templ->env->from',
2054 * then it theoretically comes from C_ReverseName handling, and we don't use
2055 * the 'X-Orig-To header'. */
2056 if (!TAILQ_EMPTY(&e_cur->env->x_original_to) && TAILQ_EMPTY(&e_templ->env->from))
2058 mutt_addrlist_copy(&e_templ->env->from, &e_cur->env->x_original_to, false);
2059 mutt_debug(LL_DEBUG5, "e_templ->env->from extracted from X-Original-To: header: %s\n",
2060 TAILQ_FIRST(&e_templ->env->from)->mailbox);
2064 if (!(flags & (SEND_POSTPONED | SEND_RESEND)) &&
2065 !((flags & SEND_DRAFT_FILE) && C_ResumeDraftFiles))
2067 if ((flags & (SEND_REPLY | SEND_FORWARD | SEND_TO_SENDER)) && ctx &&
2068 (envelope_defaults(e_templ->env, ctx->mailbox, el, flags) == -1))
2074 process_user_recips(e_templ->env);
2076 /* Expand aliases and remove duplicates/crossrefs */
2077 mutt_expand_aliases_env(e_templ->env);
2079 if (flags & SEND_REPLY)
2080 mutt_fix_reply_recipients(e_templ->env);
2083 if ((flags & SEND_NEWS) && ctx && (ctx->mailbox->magic == MUTT_NNTP) &&
2084 !e_templ->env->newsgroups)
2086 e_templ->env->newsgroups =
2087 mutt_str_strdup(((struct NntpMboxData *) ctx->mailbox->mdata)->group);
2091 if (!(flags & (SEND_MAILX | SEND_BATCH)) &&
2092 !(C_Autoedit && C_EditHeaders) && !((flags & SEND_REPLY) && C_FastReply))
2094 if (edit_envelope(e_templ->env, flags) == -1)
2098 /* the from address must be set here regardless of whether or not
2099 * $use_from is set so that the '~P' (from you) operator in send-hook
2100 * patterns will work. if $use_from is unset, the from address is killed
2101 * after send-hooks are evaluated */
2103 const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2106 mutt_addrlist_append(&e_templ->env->from, mutt_default_from());
2109 if ((flags & SEND_REPLY) && e_cur)
2111 /* change setting based upon message we are replying to */
2112 mutt_message_hook(ctx ? ctx->mailbox : NULL, e_cur, MUTT_REPLY_HOOK);
2114 /* set the replied flag for the message we are generating so that the
2115 * user can use ~Q in a send-hook to know when reply-hook's are also
2117 e_templ->replied = true;
2120 /* change settings based upon recipients */
2122 mutt_message_hook(NULL, e_templ, MUTT_SEND_HOOK);
2124 /* Unset the replied flag from the message we are composing since it is
2125 * no longer required. This is done here because the FCC'd copy of
2126 * this message was erroneously get the 'R'eplied flag when stored in
2127 * a maildir-style mailbox. */
2128 e_templ->replied = false;
2130 /* $use_from and/or $from might have changed in a send-hook */
2133 mutt_addrlist_clear(&e_templ->env->from);
2134 if (C_UseFrom && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2135 mutt_addrlist_append(&e_templ->env->from, mutt_default_from());
2139 process_user_header(e_templ->env);
2141 if (flags & SEND_BATCH)
2142 mutt_file_copy_stream(stdin, fp_tmp);
2144 if (C_SigOnTop && !(flags & (SEND_MAILX | SEND_KEY | SEND_BATCH)) &&
2145 C_Editor && (mutt_str_strcmp(C_Editor, "builtin") != 0))
2147 append_signature(fp_tmp);
2150 /* include replies/forwarded messages, unless we are given a template */
2151 if (!tempfile && (ctx || !(flags & (SEND_REPLY | SEND_FORWARD))) &&
2152 (generate_body(fp_tmp, e_templ, flags, ctx ? ctx->mailbox : NULL, el) == -1))
2157 if (!C_SigOnTop && !(flags & (SEND_MAILX | SEND_KEY | SEND_BATCH)) &&
2158 C_Editor && (mutt_str_strcmp(C_Editor, "builtin") != 0))
2160 append_signature(fp_tmp);
2164 /* Only set format=flowed for new messages. postponed/resent/draftfiles
2165 * should respect the original email.
2167 * This is set here so that send-hook can be used to turn the option on. */
2168 if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND | SEND_DRAFT_FILE)))
2170 if (C_TextFlowed && (e_templ->content->type == TYPE_TEXT) &&
2171 (mutt_str_strcasecmp(e_templ->content->subtype, "plain") == 0))
2173 mutt_param_set(&e_templ->content->parameter, "format", "flowed");
2177 /* This hook is even called for postponed messages, and can, e.g., be
2178 * used for setting the editor, the sendmail path, or the
2179 * envelope sender. */
2180 mutt_message_hook(NULL, e_templ, MUTT_SEND2_HOOK);
2182 /* wait until now to set the real name portion of our return address so
2183 * that $realname can be set in a send-hook */
2185 struct Address *from = TAILQ_FIRST(&e_templ->env->from);
2186 if (from && !from->personal && !(flags & (SEND_RESEND | SEND_POSTPONED)))
2187 from->personal = mutt_str_strdup(C_Realname);
2190 if (!(((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY)))
2191 mutt_file_fclose(&fp_tmp);
2193 if (flags & SEND_MAILX)
2195 if (mutt_builtin_editor(e_templ->content->filename, e_templ, e_cur) == -1)
2198 else if (!(flags & SEND_BATCH))
2201 time_t mtime = mutt_file_decrease_mtime(e_templ->content->filename, NULL);
2203 mutt_update_encoding(e_templ->content);
2205 /* Select whether or not the user's editor should be called now. We
2206 * don't want to do this when:
2207 * 1) we are sending a key/cert
2208 * 2) we are forwarding a message and the user doesn't want to edit it.
2209 * This is controlled by the quadoption $forward_edit. However, if
2210 * both $edit_headers and $autoedit are set, we want to ignore the
2211 * setting of $forward_edit because the user probably needs to add the
2213 if (!(flags & SEND_KEY) &&
2214 (((flags & SEND_FORWARD) == 0) || (C_EditHeaders && C_Autoedit) ||
2215 (query_quadoption(C_ForwardEdit, _("Edit forwarded message?")) == MUTT_YES)))
2217 /* If the this isn't a text message, look for a mailcap edit command */
2218 if (mutt_needs_mailcap(e_templ->content))
2220 if (!mutt_edit_attachment(e_templ->content))
2223 else if (!C_Editor || (mutt_str_strcmp("builtin", C_Editor) == 0))
2224 mutt_builtin_editor(e_templ->content->filename, e_templ, e_cur);
2225 else if (C_EditHeaders)
2227 mutt_env_to_local(e_templ->env);
2228 mutt_edit_headers(C_Editor, e_templ->content->filename, e_templ, &fcc);
2229 mutt_env_to_intl(e_templ->env, NULL, NULL);
2233 mutt_edit_file(C_Editor, e_templ->content->filename);
2234 if (stat(e_templ->content->filename, &st) == 0)
2236 if (mtime != st.st_mtime)
2237 fix_end_of_file(e_templ->content->filename);
2240 mutt_perror(e_templ->content->filename);
2243 mutt_message_hook(NULL, e_templ, MUTT_SEND2_HOOK);
2246 if (!(flags & (SEND_POSTPONED | SEND_FORWARD | SEND_KEY | SEND_RESEND | SEND_DRAFT_FILE)))
2248 if (stat(e_templ->content->filename, &st) == 0)
2250 /* if the file was not modified, bail out now */
2251 if ((mtime == st.st_mtime) && !e_templ->content->next &&
2252 (query_quadoption(C_AbortUnmodified,
2253 _("Abort unmodified message?")) == MUTT_YES))
2255 mutt_message(_("Aborted unmodified message"));
2260 mutt_perror(e_templ->content->filename);
2264 /* Set the message security unless:
2265 * 1) crypto support is not enabled (WithCrypto==0)
2266 * 2) pgp: header field was present during message editing with $edit_headers (e_templ->security != 0)
2267 * 3) we are resending a message
2268 * 4) we are recalling a postponed message (don't override the user's saved settings)
2269 * 5) we are in mailx mode
2270 * 6) we are in batch mode
2272 * This is done after allowing the user to edit the message so that security
2273 * settings can be configured with send2-hook and $edit_headers. */
2274 if ((WithCrypto != 0) && (e_templ->security == 0) &&
2275 !(flags & (SEND_BATCH | SEND_MAILX | SEND_POSTPONED | SEND_RESEND)))
2278 #ifdef USE_AUTOCRYPT
2279 C_Autocrypt && C_AutocryptReply
2283 && e_cur && (e_cur->security & SEC_AUTOCRYPT))
2285 e_templ->security |= (SEC_AUTOCRYPT | SEC_AUTOCRYPT_OVERRIDE);
2289 if (C_CryptAutosign)
2290 e_templ->security |= SEC_SIGN;
2291 if (C_CryptAutoencrypt)
2292 e_templ->security |= SEC_ENCRYPT;
2293 if (C_CryptReplyencrypt && e_cur && (e_cur->security & SEC_ENCRYPT))
2294 e_templ->security |= SEC_ENCRYPT;
2295 if (C_CryptReplysign && e_cur && (e_cur->security & SEC_SIGN))
2296 e_templ->security |= SEC_SIGN;
2297 if (C_CryptReplysignencrypted && e_cur && (e_cur->security & SEC_ENCRYPT))
2298 e_templ->security |= SEC_SIGN;
2299 if (((WithCrypto & APPLICATION_PGP) != 0) &&
2300 ((e_templ->security & (SEC_ENCRYPT | SEC_SIGN)) || C_CryptOpportunisticEncrypt))
2302 if (C_PgpAutoinline)
2303 e_templ->security |= SEC_INLINE;
2304 if (C_PgpReplyinline && e_cur && (e_cur->security & SEC_INLINE))
2305 e_templ->security |= SEC_INLINE;
2309 if (e_templ->security || C_CryptOpportunisticEncrypt)
2311 /* When replying / forwarding, use the original message's
2312 * crypto system. According to the documentation,
2313 * smime_is_default should be disregarded here.
2315 * Problem: At least with forwarding, this doesn't really
2316 * make much sense. Should we have an option to completely
2317 * disable individual mechanisms at run-time? */
2320 if (((WithCrypto & APPLICATION_PGP) != 0) && C_CryptAutopgp &&
2321 (e_cur->security & APPLICATION_PGP))
2323 e_templ->security |= APPLICATION_PGP;
2325 else if (((WithCrypto & APPLICATION_SMIME) != 0) && C_CryptAutosmime &&
2326 (e_cur->security & APPLICATION_SMIME))
2328 e_templ->security |= APPLICATION_SMIME;
2332 /* No crypto mechanism selected? Use availability + smime_is_default
2333 * for the decision. */
2334 if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2336 if (((WithCrypto & APPLICATION_SMIME) != 0) && C_CryptAutosmime && C_SmimeIsDefault)
2338 e_templ->security |= APPLICATION_SMIME;
2340 else if (((WithCrypto & APPLICATION_PGP) != 0) && C_CryptAutopgp)
2342 e_templ->security |= APPLICATION_PGP;
2344 else if (((WithCrypto & APPLICATION_SMIME) != 0) && C_CryptAutosmime)
2346 e_templ->security |= APPLICATION_SMIME;
2351 /* opportunistic encrypt relies on SMIME or PGP already being selected */
2352 if (C_CryptOpportunisticEncrypt)
2354 /* If something has already enabled encryption, e.g. C_CryptAutoencrypt
2355 * or C_CryptReplyencrypt, then don't enable opportunistic encrypt for
2357 if (!(e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
2359 e_templ->security |= SEC_OPPENCRYPT;
2360 crypt_opportunistic_encrypt(e_templ);
2364 /* No permissible mechanisms found. Don't sign or encrypt. */
2365 if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2366 e_templ->security = SEC_NO_FLAGS;
2369 /* Deal with the corner case where the crypto module backend is not available.
2370 * This can happen if configured without pgp/smime and with gpgme, but
2371 * $crypt_use_gpgme is unset. */
2372 if (e_templ->security && !crypt_has_module_backend(e_templ->security))
2375 "No crypto backend configured. Disabling message security setting."));
2376 e_templ->security = SEC_NO_FLAGS;
2379 /* specify a default fcc. if we are in batchmode, only save a copy of
2380 * the message if the value of $copy is yes or ask-yes */
2382 if (mutt_buffer_is_empty(&fcc) && !(flags & SEND_POSTPONED_FCC) &&
2383 (!(flags & SEND_BATCH) || (C_Copy & 0x1)))
2385 /* set the default FCC */
2386 const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2389 mutt_addrlist_append(&e_templ->env->from, mutt_default_from());
2391 mutt_select_fcc(&fcc, e_templ);
2394 mutt_addrlist_clear(&e_templ->env->from);
2398 mutt_rfc3676_space_stuff(e_templ);
2400 mutt_update_encoding(e_templ->content);
2402 if (!(flags & (SEND_MAILX | SEND_BATCH)))
2406 mutt_buffer_pretty_mailbox(&fcc);
2407 i = mutt_compose_menu(e_templ, &fcc, e_cur,
2408 ((flags & SEND_NO_FREE_HEADER) ? MUTT_COMPOSE_NOFREEHEADER : 0));
2413 if (flags & SEND_NEWS)
2414 mutt_message(_("Article not posted"));
2417 mutt_message(_("Mail not sent"));
2422 if (postpone_message(e_templ, e_cur, mutt_b2s(&fcc), flags) != 0)
2424 mutt_message(_("Message postponed"));
2431 if (!(flags & SEND_NEWS))
2433 if ((mutt_addrlist_count_recips(&e_templ->env->to) == 0) &&
2434 (mutt_addrlist_count_recips(&e_templ->env->cc) == 0) &&
2435 (mutt_addrlist_count_recips(&e_templ->env->bcc) == 0))
2437 if (flags & SEND_BATCH)
2439 puts(_("No recipients specified"));
2443 mutt_error(_("No recipients specified"));
2447 if (mutt_env_to_intl(e_templ->env, &tag, &err))
2449 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
2451 if (flags & SEND_BATCH)
2456 if (!e_templ->env->subject && !(flags & SEND_BATCH) &&
2457 (query_quadoption(C_AbortNosubject, _("No subject, abort sending?")) != MUTT_NO))
2459 /* if the abort is automatic, print an error message */
2460 if (C_AbortNosubject == MUTT_YES)
2461 mutt_error(_("No subject specified"));
2465 if ((flags & SEND_NEWS) && !e_templ->env->subject)
2467 mutt_error(_("No subject specified"));
2471 if ((flags & SEND_NEWS) && !e_templ->env->newsgroups)
2473 mutt_error(_("No newsgroup specified"));
2478 if (!(flags & SEND_BATCH) && (C_AbortNoattach != MUTT_NO) &&
2479 !e_templ->content->next && (e_templ->content->type == TYPE_TEXT) &&
2480 (mutt_str_strcasecmp(e_templ->content->subtype, "plain") == 0) &&
2481 search_attach_keyword(e_templ->content->filename) &&
2482 (query_quadoption(C_AbortNoattach,
2483 _("No attachments, cancel sending?")) != MUTT_NO))
2485 /* if the abort is automatic, print an error message */
2486 if (C_AbortNoattach == MUTT_YES)
2488 mutt_error(_("Message contains text matching "
2489 "\"$abort_noattach_regex\". Not sending."));
2494 if (e_templ->content->next)
2495 e_templ->content = mutt_make_multipart(e_templ->content);
2497 /* Ok, we need to do it this way instead of handling all fcc stuff in
2498 * one place in order to avoid going to main_loop with encoded "env"
2499 * in case of error. Ugh. */
2501 mutt_encode_descriptions(e_templ->content, true);
2503 /* Make sure that clear_content and free_clear_content are
2504 * properly initialized -- we may visit this particular place in
2505 * the code multiple times, including after a failed call to
2506 * mutt_protect(). */
2508 clear_content = NULL;
2509 free_clear_content = false;
2513 if (e_templ->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT))
2515 /* save the decrypted attachments */
2516 clear_content = e_templ->content;
2518 if ((crypt_get_keys(e_templ, &pgpkeylist, 0) == -1) ||
2519 (mutt_protect(e_templ, pgpkeylist, false) == -1))
2521 e_templ->content = mutt_remove_multipart(e_templ->content);
2525 decode_descriptions(e_templ->content);
2528 mutt_encode_descriptions(e_templ->content, false);
2531 /* at this point, e_templ->content is one of the following three things:
2532 * - multipart/signed. In this case, clear_content is a child
2533 * - multipart/encrypted. In this case, clear_content exists independently
2534 * - application/pgp. In this case, clear_content exists independently
2535 * - something else. In this case, it's the same as clear_content
2538 /* This is ugly -- lack of "reporting back" from mutt_protect(). */
2540 if (clear_content && (e_templ->content != clear_content) &&
2541 (e_templ->content->parts != clear_content))
2542 free_clear_content = true;
2545 if (!OptNoCurses && !(flags & SEND_MAILX))
2546 mutt_message(_("Sending message..."));
2548 mutt_prepare_envelope(e_templ->env, true);
2550 if (C_FccBeforeSend)
2551 save_fcc(e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath);
2553 i = send_message(e_templ);
2556 if (!(flags & SEND_BATCH))
2560 else if ((e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) ||
2561 ((e_templ->security & SEC_SIGN) && (e_templ->content->type == TYPE_APPLICATION)))
2563 if (e_templ->content != clear_content)
2565 mutt_body_free(&e_templ->content); /* destroy PGP data */
2566 e_templ->content = clear_content; /* restore clear text. */
2569 else if ((e_templ->security & SEC_SIGN) && (e_templ->content->type == TYPE_MULTIPART))
2571 mutt_body_free(&e_templ->content->parts->next); /* destroy sig */
2572 e_templ->content = mutt_remove_multipart(e_templ->content);
2576 mutt_env_free(&e_templ->content->mime_headers); /* protected headers */
2577 e_templ->content = mutt_remove_multipart(e_templ->content);
2578 decode_descriptions(e_templ->content);
2579 mutt_unprepare_envelope(e_templ->env);
2585 puts(_("Could not send the message"));
2590 if (!C_FccBeforeSend)
2591 save_fcc(e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath);
2593 if (!OptNoCurses && !(flags & SEND_MAILX))
2595 mutt_message((i != 0) ? _("Sending in background") :
2596 (flags & SEND_NEWS) ? _("Article posted") : /* USE_NNTP */
2600 nm_record_message(ctx ? ctx->mailbox : NULL, finalpath, e_cur);
2608 if ((WithCrypto != 0) && free_clear_content)
2609 mutt_body_free(&clear_content);
2611 /* set 'replied' flag only if the user didn't change/remove
2612 * In-Reply-To: and References: headers during edit */
2613 if (flags & SEND_REPLY)
2615 if (!(flags & SEND_POSTPONED) && ctx && ctx->mailbox)
2617 STAILQ_FOREACH(en, el, entries)
2619 mutt_set_flag(ctx->mailbox, en->email, MUTT_REPLIED, is_reply(en->email, e_templ));
2627 mutt_buffer_dealloc(&fcc);
2629 if (flags & SEND_POSTPONED)
2631 if (WithCrypto & APPLICATION_PGP)
2634 C_PgpSignAs = pgp_signas;
2636 if (WithCrypto & APPLICATION_SMIME)
2638 FREE(&C_SmimeSignAs);
2639 C_SmimeSignAs = smime_signas;
2643 mutt_file_fclose(&fp_tmp);
2644 if (!(flags & SEND_NO_FREE_HEADER))
2645 email_free(&e_templ);