NeoMutt  2020-04-24
Teaching an old dog new tricks
DOXYGEN
send.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <errno.h>
32 #include <locale.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include "mutt/lib.h"
40 #include "address/lib.h"
41 #include "config/lib.h"
42 #include "email/lib.h"
43 #include "core/lib.h"
44 #include "gui/lib.h"
45 #include "mutt.h"
46 #include "send.h"
47 #include "alias.h"
48 #include "compose.h"
49 #include "context.h"
50 #include "copy.h"
51 #include "edit.h"
52 #include "globals.h"
53 #include "handler.h"
54 #include "hdrline.h"
55 #include "hook.h"
56 #include "init.h"
57 #include "mutt_attach.h"
58 #include "mutt_body.h"
59 #include "mutt_header.h"
60 #include "mutt_logging.h"
61 #include "mutt_parse.h"
62 #include "muttlib.h"
63 #include "options.h"
64 #include "pattern.h"
65 #include "protos.h"
66 #include "recvattach.h"
67 #include "rfc3676.h"
68 #include "sendlib.h"
69 #include "smtp.h"
70 #include "sort.h"
71 #include "ncrypt/lib.h"
72 #ifdef USE_NNTP
73 #include "mx.h"
74 #include "nntp/lib.h"
75 #endif
76 #ifdef MIXMASTER
77 #include "remailer.h"
78 #endif
79 #ifdef USE_NOTMUCH
80 #include "notmuch/lib.h"
81 #endif
82 #ifdef USE_IMAP
83 #include "imap/lib.h"
84 #endif
85 #ifdef USE_AUTOCRYPT
86 #include "autocrypt/lib.h"
87 #endif
88 
89 /* These Config Variables are only used in send.c */
90 unsigned char C_AbortNoattach;
92 unsigned char C_AbortNosubject;
93 unsigned char C_AbortUnmodified;
106 unsigned char C_FccAttach;
112 unsigned char C_ForwardEdit;
115 bool C_Hdrs;
116 unsigned char C_HonorFollowupTo;
118 unsigned char C_Include;
119 bool C_Metoo;
125 unsigned char C_Recall;
127 unsigned char C_ReplyTo;
132 char *C_Signature;
134 bool C_UseFrom;
135 
140 static void append_signature(FILE *fp)
141 {
142  FILE *fp_tmp = NULL;
143  pid_t pid;
144 
145  if (C_Signature && (fp_tmp = mutt_open_read(C_Signature, &pid)))
146  {
147  if (C_SigDashes)
148  fputs("\n-- \n", fp);
149  mutt_file_copy_stream(fp_tmp, fp);
150  mutt_file_fclose(&fp_tmp);
151  if (pid != -1)
152  filter_wait(pid);
153  }
154 }
155 
162 static void remove_user(struct AddressList *al, bool leave_only)
163 {
164  struct Address *a = NULL, *tmp = NULL;
165  TAILQ_FOREACH_SAFE(a, al, entries, tmp)
166  {
167  if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
168  {
169  TAILQ_REMOVE(al, a, entries);
170  mutt_addr_free(&a);
171  }
172  }
173 }
174 
181 static void add_mailing_lists(struct AddressList *out, const struct AddressList *t,
182  const struct AddressList *c)
183 {
184  const struct AddressList *const als[] = { t, c };
185 
186  for (size_t i = 0; i < mutt_array_size(als); ++i)
187  {
188  const struct AddressList *al = als[i];
189  struct Address *a = NULL;
190  TAILQ_FOREACH(a, al, entries)
191  {
192  if (!a->group && mutt_is_mail_list(a))
193  {
195  }
196  }
197  }
198 }
199 
208 int mutt_edit_address(struct AddressList *al, const char *field, bool expand_aliases)
209 {
210  char buf[8192];
211  char *err = NULL;
212  int idna_ok = 0;
213 
214  do
215  {
216  buf[0] = '\0';
218  mutt_addrlist_write(al, buf, sizeof(buf), false);
219  if (mutt_get_field(field, buf, sizeof(buf), MUTT_ALIAS) != 0)
220  return -1;
222  mutt_addrlist_parse2(al, buf);
223  if (expand_aliases)
225  idna_ok = mutt_addrlist_to_intl(al, &err);
226  if (idna_ok != 0)
227  {
228  mutt_error(_("Bad IDN: '%s'"), err);
229  FREE(&err);
230  }
231  } while (idna_ok != 0);
232  return 0;
233 }
234 
242 static int edit_envelope(struct Envelope *en, SendFlags flags)
243 {
244  char buf[8192];
245 
246 #ifdef USE_NNTP
247  if (OptNewsSend)
248  {
249  if (en->newsgroups)
250  mutt_str_strfcpy(buf, en->newsgroups, sizeof(buf));
251  else
252  buf[0] = '\0';
253  if (mutt_get_field("Newsgroups: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0)
254  return -1;
255  FREE(&en->newsgroups);
256  en->newsgroups = mutt_str_strdup(buf);
257 
258  if (en->followup_to)
259  mutt_str_strfcpy(buf, en->followup_to, sizeof(buf));
260  else
261  buf[0] = '\0';
262  if (C_AskFollowUp &&
263  (mutt_get_field("Followup-To: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0))
264  {
265  return -1;
266  }
267  FREE(&en->followup_to);
268  en->followup_to = mutt_str_strdup(buf);
269 
270  if (en->x_comment_to)
271  mutt_str_strfcpy(buf, en->x_comment_to, sizeof(buf));
272  else
273  buf[0] = '\0';
274  if (C_XCommentTo && C_AskXCommentTo &&
275  (mutt_get_field("X-Comment-To: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0))
276  {
277  return -1;
278  }
279  FREE(&en->x_comment_to);
280  en->x_comment_to = mutt_str_strdup(buf);
281  }
282  else
283 #endif
284  {
285  if ((mutt_edit_address(&en->to, _("To: "), true) == -1) || TAILQ_EMPTY(&en->to))
286  return -1;
287  if (C_Askcc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
288  return -1;
289  if (C_Askbcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
290  return -1;
292  (mutt_edit_address(&en->from, "From: ", true) == -1))
293  {
294  return -1;
295  }
296  }
297 
298  if (en->subject)
299  {
300  if (C_FastReply)
301  return 0;
302  mutt_str_strfcpy(buf, en->subject, sizeof(buf));
303  }
304  else
305  {
306  const char *p = NULL;
307 
308  buf[0] = '\0';
309  struct ListNode *uh = NULL;
310  STAILQ_FOREACH(uh, &UserHeader, entries)
311  {
312  size_t plen = mutt_str_startswith(uh->data, "subject:", CASE_IGNORE);
313  if (plen)
314  {
315  p = mutt_str_skip_email_wsp(uh->data + plen);
316  mutt_str_strfcpy(buf, p, sizeof(buf));
317  }
318  }
319  }
320 
321  if ((mutt_get_field(_("Subject: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0) ||
322  (!buf[0] &&
323  (query_quadoption(C_AbortNosubject, _("No subject, abort?")) != MUTT_NO)))
324  {
325  mutt_message(_("No subject, aborting"));
326  return -1;
327  }
328  mutt_str_replace(&en->subject, buf);
329 
330  return 0;
331 }
332 
333 #ifdef USE_NNTP
334 
341 static char *nntp_get_header(const char *s)
342 {
343  SKIPWS(s);
344  return mutt_str_strdup(s);
345 }
346 #endif
347 
352 static void process_user_recips(struct Envelope *env)
353 {
354  struct ListNode *uh = NULL;
355  STAILQ_FOREACH(uh, &UserHeader, entries)
356  {
357  size_t plen;
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);
364 #ifdef USE_NNTP
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);
371 #endif
372  }
373 }
374 
379 static void process_user_header(struct Envelope *env)
380 {
381  struct ListNode *uh = NULL;
382  STAILQ_FOREACH(uh, &UserHeader, entries)
383  {
384  size_t plen;
385  if ((plen = mutt_str_startswith(uh->data, "from:", CASE_IGNORE)))
386  {
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);
390  }
391  else if ((plen = mutt_str_startswith(uh->data, "reply-to:", CASE_IGNORE)))
392  {
394  mutt_addrlist_parse(&env->reply_to, uh->data + plen);
395  }
396  else if ((plen = mutt_str_startswith(uh->data, "message-id:", CASE_IGNORE)))
397  {
398  char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
399  if (mutt_addr_valid_msgid(tmp))
400  {
401  FREE(&env->message_id);
402  env->message_id = tmp;
403  }
404  else
405  FREE(&tmp);
406  }
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) &&
410 #ifdef USE_NNTP
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) &&
414 #endif
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))
418  {
420  }
421  }
422 }
423 
430 void mutt_forward_intro(struct Mailbox *m, struct Email *e, FILE *fp)
431 {
432  if (!C_ForwardAttributionIntro || !fp)
433  return;
434 
435  char buf[1024];
436  setlocale(LC_TIME, NONULL(C_AttributionLocale));
437  mutt_make_string(buf, sizeof(buf), 0, C_ForwardAttributionIntro, NULL, m, e);
438  setlocale(LC_TIME, "");
439  fputs(buf, fp);
440  fputs("\n\n", fp);
441 }
442 
449 void mutt_forward_trailer(struct Mailbox *m, struct Email *e, FILE *fp)
450 {
451  if (!C_ForwardAttributionTrailer || !fp)
452  return;
453 
454  char buf[1024];
455  setlocale(LC_TIME, NONULL(C_AttributionLocale));
456  mutt_make_string(buf, sizeof(buf), 0, C_ForwardAttributionTrailer, NULL, m, e);
457  setlocale(LC_TIME, "");
458  fputc('\n', fp);
459  fputs(buf, fp);
460  fputc('\n', fp);
461 }
462 
471 static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out)
472 {
473  CopyHeaderFlags chflags = CH_DECODE;
475 
478 
479  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && C_ForwardDecode)
480  {
481  /* make sure we have the user's passphrase before proceeding... */
483  return -1;
484  }
485 
486  mutt_forward_intro(m, e, fp_out);
487 
488  if (C_ForwardDecode)
489  {
490  cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
491  if (C_Weed)
492  {
493  chflags |= CH_WEED | CH_REORDER;
494  cmflags |= MUTT_CM_WEED;
495  }
496  }
497  if (C_ForwardQuote)
498  cmflags |= MUTT_CM_PREFIX;
499 
500  mutt_copy_message(fp_out, m, e, cmflags, chflags, 0);
501  mutt_forward_trailer(m, e, fp_out);
502  return 0;
503 }
504 
514 static int inline_forward_attachments(struct Mailbox *m, struct Email *e,
515  struct Body ***plast, int *forwardq)
516 {
517  struct Body **last = *plast;
518  struct Body *body = NULL;
519  struct Message *msg = NULL;
520  struct AttachCtx *actx = NULL;
521  int rc = 0, i;
522 
525 
526  msg = mx_msg_open(m, e->msgno);
527  if (!msg)
528  return -1;
529 
530  actx = mutt_mem_calloc(1, sizeof(*actx));
531  actx->email = e;
532  actx->fp_root = msg->fp;
533 
534  mutt_generate_recvattach_list(actx, actx->email, actx->email->content,
535  actx->fp_root, -1, 0, 0);
536 
537  for (i = 0; i < actx->idxlen; i++)
538  {
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))))
545  {
546  /* Ask the quadoption only once */
547  if (*forwardq == -1)
548  {
550  /* L10N: This is the prompt for $forward_attachments.
551  When inline forwarding ($mime_forward answered "no"), this prompts
552  whether to add non-decodable attachments from the original email.
553  Text/plain parts and the like will already be included in the
554  message contents, but other attachment, such as PDF files, will also
555  be added as attachments to the new mail, if this is answered yes. */
556  _("Forward attachments?"));
557  if (*forwardq != MUTT_YES)
558  {
559  if (*forwardq == -1)
560  rc = -1;
561  goto cleanup;
562  }
563  }
564  if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1)
565  {
566  rc = -1;
567  goto cleanup;
568  }
569  last = &((*last)->next);
570  }
571  }
572 
573 cleanup:
574  *plast = last;
575  mx_msg_close(m, &msg);
576  mutt_actx_free(&actx);
577  return rc;
578 }
579 
589 static int mutt_inline_forward(struct Mailbox *m, struct Email *e_edit,
590  struct Email *e_cur, FILE *out)
591 {
592  int forwardq = -1;
593  struct Body **last = NULL;
594 
595  if (e_cur)
596  include_forward(m, e_cur, out);
597  else
598  {
599  for (int i = 0; i < m->vcount; i++)
600  {
601  struct Email *e = mutt_get_virt_email(m, i);
602  if (!e)
603  continue;
604  if (e->tagged)
605  include_forward(m, e, out);
606  }
607  }
608 
610  {
611  last = &e_edit->content;
612  while (*last)
613  last = &((*last)->next);
614 
615  if (e_cur)
616  {
617  if (inline_forward_attachments(m, e_cur, &last, &forwardq) != 0)
618  return -1;
619  }
620  else
621  {
622  for (int i = 0; i < m->vcount; i++)
623  {
624  struct Email *e = mutt_get_virt_email(m, i);
625  if (!e)
626  continue;
627  if (e->tagged)
628  {
629  if (inline_forward_attachments(m, e, &last, &forwardq) != 0)
630  return -1;
631  if (forwardq == MUTT_NO)
632  break;
633  }
634  }
635  }
636  }
637 
638  return 0;
639 }
640 
647 void mutt_make_attribution(struct Mailbox *m, struct Email *e, FILE *fp_out)
648 {
649  if (!C_Attribution || !fp_out)
650  return;
651 
652  char buf[1024];
653  setlocale(LC_TIME, NONULL(C_AttributionLocale));
654  mutt_make_string(buf, sizeof(buf), 0, C_Attribution, NULL, m, e);
655  setlocale(LC_TIME, "");
656  fputs(buf, fp_out);
657  fputc('\n', fp_out);
658 }
659 
666 void mutt_make_post_indent(struct Mailbox *m, struct Email *e, FILE *fp_out)
667 {
668  if (!C_PostIndentString || !fp_out)
669  return;
670 
671  char buf[256];
672  mutt_make_string(buf, sizeof(buf), 0, C_PostIndentString, NULL, m, e);
673  fputs(buf, fp_out);
674  fputc('\n', fp_out);
675 }
676 
685 static int include_reply(struct Mailbox *m, struct Email *e, FILE *fp_out)
686 {
687  CopyMessageFlags cmflags =
689  CopyHeaderFlags chflags = CH_DECODE;
690 
691  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
692  {
693  /* make sure we have the user's passphrase before proceeding... */
695  return -1;
696  }
697 
700 
701  mutt_make_attribution(m, e, fp_out);
702 
703  if (!C_Header)
704  cmflags |= MUTT_CM_NOHEADER;
705  if (C_Weed)
706  {
707  chflags |= CH_WEED | CH_REORDER;
708  cmflags |= MUTT_CM_WEED;
709  }
710 
711  mutt_copy_message(fp_out, m, e, cmflags, chflags, 0);
712 
713  mutt_make_post_indent(m, e, fp_out);
714 
715  return 0;
716 }
717 
724 static const struct AddressList *choose_default_to(const struct Address *from,
725  const struct Envelope *env)
726 {
727  if (!C_ReplySelf && mutt_addr_is_user(from))
728  {
729  /* mail is from the user, assume replying to recipients */
730  return &env->to;
731  }
732  else
733  {
734  return &env->from;
735  }
736 }
737 
747 static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto)
748 {
749  char prompt[256];
750  const struct Address *from = TAILQ_FIRST(&env->from);
751  const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
752 
753  if (flags && !TAILQ_EMPTY(&env->mail_followup_to) && (hmfupto == MUTT_YES))
754  {
755  mutt_addrlist_copy(to, &env->mail_followup_to, true);
756  return 0;
757  }
758 
759  /* Exit now if we're setting up the default Cc list for list-reply
760  * (only set if Mail-Followup-To is present and honoured). */
761  if (flags & SEND_LIST_REPLY)
762  return 0;
763 
764  const struct AddressList *default_to = choose_default_to(from, env);
765 
766  if (reply_to)
767  {
768  const bool from_is_reply_to = mutt_addr_cmp(from, reply_to);
769  const bool multiple_reply_to =
770  reply_to && TAILQ_NEXT(TAILQ_FIRST(&env->reply_to), entries);
771  if ((from_is_reply_to && !multiple_reply_to && !reply_to->personal) ||
772  (C_IgnoreListReplyTo && mutt_is_mail_list(reply_to) &&
773  (mutt_addrlist_search(&env->to, reply_to) || mutt_addrlist_search(&env->cc, reply_to))))
774  {
775  /* If the Reply-To: address is a mailing list, assume that it was
776  * put there by the mailing list, and use the From: address
777  *
778  * We also take the from header if our correspondent has a reply-to
779  * header which is identical to the electronic mail address given
780  * in his From header, and the reply-to has no display-name. */
781  mutt_addrlist_copy(to, &env->from, false);
782  }
783  else if (!(from_is_reply_to && !multiple_reply_to) && (C_ReplyTo != MUTT_YES))
784  {
785  /* There are quite a few mailing lists which set the Reply-To:
786  * header field to the list address, which makes it quite impossible
787  * to send a message to only the sender of the message. This
788  * provides a way to do that. */
789  /* L10N: Asks whether the user respects the reply-to header.
790  If she says no, neomutt will reply to the from header's address instead. */
791  snprintf(prompt, sizeof(prompt), _("Reply to %s%s?"), reply_to->mailbox,
792  multiple_reply_to ? ",..." : "");
793  switch (query_quadoption(C_ReplyTo, prompt))
794  {
795  case MUTT_YES:
796  mutt_addrlist_copy(to, &env->reply_to, false);
797  break;
798 
799  case MUTT_NO:
800  mutt_addrlist_copy(to, default_to, false);
801  break;
802 
803  default:
804  return -1; /* abort */
805  }
806  }
807  else
808  {
809  mutt_addrlist_copy(to, &env->reply_to, false);
810  }
811  }
812  else
813  {
814  mutt_addrlist_copy(to, default_to, false);
815  }
816 
817  return 0;
818 }
819 
828 int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags)
829 {
830  enum QuadOption hmfupto = MUTT_ABORT;
831  const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
832 
833  if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
834  {
835  char prompt[256];
836  snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"), followup_to->mailbox,
837  TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
838 
839  hmfupto = query_quadoption(C_HonorFollowupTo, prompt);
840  if (hmfupto == MUTT_ABORT)
841  return -1;
842  }
843 
844  if (flags & SEND_LIST_REPLY)
845  {
846  add_mailing_lists(&out->to, &in->to, &in->cc);
847 
848  if (followup_to && (hmfupto == MUTT_YES) &&
849  (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES)) == MUTT_ABORT))
850  {
851  return -1; /* abort */
852  }
853  }
854  else if (flags & SEND_TO_SENDER)
855  {
856  mutt_addrlist_copy(&out->to, &in->from, false);
857  }
858  else
859  {
860  if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
861  (hmfupto == MUTT_YES)) == -1)
862  return -1; /* abort */
863 
864  if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
865  (!followup_to || (hmfupto != MUTT_YES)))
866  {
867  /* if(!mutt_addr_is_user(in->to)) */
868  if (flags & SEND_GROUP_REPLY)
869  mutt_addrlist_copy(&out->cc, &in->to, true);
870  else
871  mutt_addrlist_copy(&out->to, &in->cc, true);
872  mutt_addrlist_copy(&out->cc, &in->cc, true);
873  }
874  }
875  return 0;
876 }
877 
883 static void add_references(struct ListHead *head, struct Envelope *env)
884 {
885  struct ListNode *np = NULL;
886 
887  struct ListHead *src = !STAILQ_EMPTY(&env->references) ? &env->references : &env->in_reply_to;
888  STAILQ_FOREACH(np, src, entries)
889  {
891  }
892 }
893 
899 static void add_message_id(struct ListHead *head, struct Envelope *env)
900 {
901  if (env->message_id)
902  {
904  }
905 }
906 
912 {
913  if (!C_Metoo)
914  {
915  /* the order is important here. do the CC: first so that if the
916  * the user is the only recipient, it ends up on the TO: field */
917  remove_user(&env->cc, TAILQ_EMPTY(&env->to));
918  remove_user(&env->to, TAILQ_EMPTY(&env->cc) || C_ReplySelf);
919  }
920 
921  /* the CC field can get cluttered, especially with lists */
922  mutt_addrlist_dedupe(&env->to);
923  mutt_addrlist_dedupe(&env->cc);
924  mutt_addrlist_remove_xrefs(&env->to, &env->cc);
925 
926  if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
927  {
928  TAILQ_SWAP(&env->to, &env->cc, Address, entries);
929  }
930 }
931 
938 void mutt_make_forward_subject(struct Envelope *env, struct Mailbox *m, struct Email *e)
939 {
940  if (!env)
941  return;
942 
943  char buf[256];
944 
945  /* set the default subject for the message. */
946  mutt_make_string(buf, sizeof(buf), 0, NONULL(C_ForwardFormat), NULL, m, e);
947  mutt_str_replace(&env->subject, buf);
948 }
949 
955 void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *curenv)
956 {
957  if (!env || !curenv)
958  return;
959 
960  /* This takes precedence over a subject that might have
961  * been taken from a List-Post header. Is that correct? */
962  if (curenv->real_subj)
963  {
964  FREE(&env->subject);
965  env->subject = mutt_mem_malloc(mutt_str_strlen(curenv->real_subj) + 5);
966  sprintf(env->subject, "Re: %s", curenv->real_subj);
967  }
968  else if (!env->subject)
970 }
971 
977 void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *curenv)
978 {
979  add_references(&env->references, curenv);
980  add_message_id(&env->references, curenv);
981  add_message_id(&env->in_reply_to, curenv);
982 
983 #ifdef USE_NNTP
984  if (OptNewsSend && C_XCommentTo && !TAILQ_EMPTY(&curenv->from))
986 #endif
987 }
988 
994 static void make_reference_headers(struct EmailList *el, struct Envelope *env)
995 {
996  if (!el || !env || STAILQ_EMPTY(el))
997  return;
998 
999  struct EmailNode *en = STAILQ_FIRST(el);
1000  bool single = !STAILQ_NEXT(en, entries);
1001 
1002  if (!single)
1003  {
1004  STAILQ_FOREACH(en, el, entries)
1005  {
1007  }
1008  }
1009  else
1011 
1012  /* if there's more than entry in In-Reply-To (i.e. message has multiple
1013  * parents), don't generate a References: header as it's discouraged by
1014  * RFC2822, sect. 3.6.4 */
1015  if (!single && !STAILQ_EMPTY(&env->in_reply_to) &&
1016  STAILQ_NEXT(STAILQ_FIRST(&env->in_reply_to), entries))
1017  {
1018  mutt_list_free(&env->references);
1019  }
1020 }
1021 
1031 static int envelope_defaults(struct Envelope *env, struct Mailbox *m,
1032  struct EmailList *el, SendFlags flags)
1033 {
1034  if (!el || STAILQ_EMPTY(el))
1035  return -1;
1036 
1037  struct EmailNode *en = STAILQ_FIRST(el);
1038  bool single = !STAILQ_NEXT(en, entries);
1039 
1040  struct Envelope *curenv = en->email->env;
1041  if (!curenv)
1042  return -1;
1043 
1044  if (flags & (SEND_REPLY | SEND_TO_SENDER))
1045  {
1046 #ifdef USE_NNTP
1047  if ((flags & SEND_NEWS))
1048  {
1049  /* in case followup set Newsgroups: with Followup-To: if it present */
1050  if (!env->newsgroups &&
1051  (mutt_str_strcasecmp(curenv->followup_to, "poster") != 0))
1052  {
1053  env->newsgroups = mutt_str_strdup(curenv->followup_to);
1054  }
1055  }
1056  else
1057 #endif
1058  if (!single)
1059  {
1060  STAILQ_FOREACH(en, el, entries)
1061  {
1062  if (mutt_fetch_recips(env, en->email->env, flags) == -1)
1063  return -1;
1064  }
1065  }
1066  else if (mutt_fetch_recips(env, curenv, flags) == -1)
1067  return -1;
1068 
1069  if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1070  {
1071  mutt_error(_("No mailing lists found"));
1072  return -1;
1073  }
1074 
1075  if (flags & SEND_REPLY)
1076  {
1077  mutt_make_misc_reply_headers(env, curenv);
1078  make_reference_headers(el, env);
1079  }
1080  }
1081  else if (flags & SEND_FORWARD)
1082  {
1083  mutt_make_forward_subject(env, m, en->email);
1084  if (C_ForwardReferences)
1085  make_reference_headers(el, env);
1086  }
1087 
1088  return 0;
1089 }
1090 
1101 static int generate_body(FILE *fp_tmp, struct Email *e, SendFlags flags,
1102  struct Mailbox *m, struct EmailList *el)
1103 {
1104  struct Body *tmp = NULL;
1105  struct EmailNode *en = NULL;
1106  bool single = true;
1107 
1108  if (el)
1109  en = STAILQ_FIRST(el);
1110  if (en)
1111  single = !STAILQ_NEXT(en, entries);
1112 
1113  /* An EmailList is required for replying and forwarding */
1114  if (!el && (flags & (SEND_REPLY | SEND_FORWARD)))
1115  return -1;
1116 
1117  if (flags & SEND_REPLY)
1118  {
1119  enum QuadOption ans =
1120  query_quadoption(C_Include, _("Include message in reply?"));
1121  if (ans == MUTT_ABORT)
1122  return -1;
1123 
1124  if (ans == MUTT_YES)
1125  {
1126  mutt_message(_("Including quoted message..."));
1127  if (single && en)
1128  include_reply(m, en->email, fp_tmp);
1129  else
1130  {
1131  STAILQ_FOREACH(en, el, entries)
1132  {
1133  if (include_reply(m, en->email, fp_tmp) == -1)
1134  {
1135  mutt_error(_("Could not include all requested messages"));
1136  return -1;
1137  }
1138  fputc('\n', fp_tmp);
1139  }
1140  }
1141  }
1142  }
1143  else if (flags & SEND_FORWARD)
1144  {
1145  enum QuadOption ans =
1146  query_quadoption(C_MimeForward, _("Forward as attachment?"));
1147  if (ans == MUTT_YES)
1148  {
1149  struct Body *last = e->content;
1150 
1151  mutt_message(_("Preparing forwarded message..."));
1152 
1153  while (last && last->next)
1154  last = last->next;
1155 
1156  if (single && en)
1157  {
1158  tmp = mutt_make_message_attach(m, en->email, false);
1159  if (last)
1160  last->next = tmp;
1161  else
1162  e->content = tmp;
1163  }
1164  else
1165  {
1166  STAILQ_FOREACH(en, el, entries)
1167  {
1168  tmp = mutt_make_message_attach(m, en->email, false);
1169  if (last)
1170  {
1171  last->next = tmp;
1172  last = tmp;
1173  }
1174  else
1175  {
1176  last = tmp;
1177  e->content = tmp;
1178  }
1179  }
1180  }
1181  }
1182  else if ((ans != MUTT_ABORT) && en)
1183  {
1184  if (mutt_inline_forward(m, e, en->email, fp_tmp) != 0)
1185  return -1;
1186  }
1187  else
1188  return -1;
1189  }
1190  /* if (WithCrypto && (flags & SEND_KEY)) */
1191  else if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY))
1192  {
1193  struct Body *b = NULL;
1194 
1195  if (((WithCrypto & APPLICATION_PGP) != 0) && !(b = crypt_pgp_make_key_attachment()))
1196  {
1197  return -1;
1198  }
1199 
1200  b->next = e->content;
1201  e->content = b;
1202  }
1203 
1204  mutt_clear_error();
1205 
1206  return 0;
1207 }
1208 
1214 {
1215  /* Only generate the Mail-Followup-To if the user has requested it, and
1216  * it hasn't already been set */
1217 
1218  if (!C_FollowupTo)
1219  return;
1220 #ifdef USE_NNTP
1221  if (OptNewsSend)
1222  {
1223  if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1224  env->followup_to = mutt_str_strdup(env->newsgroups);
1225  return;
1226  }
1227 #endif
1228 
1229  if (TAILQ_EMPTY(&env->mail_followup_to))
1230  {
1231  if (mutt_is_list_recipient(false, env))
1232  {
1233  /* this message goes to known mailing lists, so create a proper
1234  * mail-followup-to header */
1235 
1236  mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1237  mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1238  }
1239 
1240  /* remove ourselves from the mail-followup-to header */
1241  remove_user(&env->mail_followup_to, false);
1242 
1243  /* If we are not subscribed to any of the lists in question, re-add
1244  * ourselves to the mail-followup-to header. The mail-followup-to header
1245  * generated is a no-op with group-reply, but makes sure list-reply has the
1246  * desired effect. */
1247 
1248  if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1249  !mutt_is_subscribed_list_recipient(false, env))
1250  {
1251  struct AddressList *al = NULL;
1252  if (!TAILQ_EMPTY(&env->reply_to))
1253  al = &env->reply_to;
1254  else if (!TAILQ_EMPTY(&env->from))
1255  al = &env->from;
1256 
1257  if (al)
1258  {
1259  struct Address *a = NULL;
1260  TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1261  {
1263  }
1264  }
1265  else
1266  {
1268  }
1269  }
1270 
1272  }
1273 }
1274 
1284 static void set_reverse_name(struct AddressList *al, struct Envelope *env)
1285 {
1286  struct Address *a = NULL;
1287  if (TAILQ_EMPTY(al))
1288  {
1289  TAILQ_FOREACH(a, &env->to, entries)
1290  {
1291  if (mutt_addr_is_user(a))
1292  {
1294  break;
1295  }
1296  }
1297  }
1298 
1299  if (TAILQ_EMPTY(al))
1300  {
1301  TAILQ_FOREACH(a, &env->cc, entries)
1302  {
1303  if (mutt_addr_is_user(a))
1304  {
1306  break;
1307  }
1308  }
1309  }
1310 
1311  if (TAILQ_EMPTY(al))
1312  {
1313  struct Address *from = TAILQ_FIRST(&env->from);
1314  if (from && mutt_addr_is_user(from))
1315  {
1317  }
1318  }
1319 
1320  if (!TAILQ_EMPTY(al))
1321  {
1322  /* when $reverse_realname is not set, clear the personal name so that it
1323  * may be set via a reply- or send-hook. */
1324  if (!C_ReverseRealname)
1325  FREE(&TAILQ_FIRST(al)->personal);
1326  }
1327 }
1328 
1334 {
1335  /* Note: We let $from override $realname here.
1336  * Is this the right thing to do?
1337  */
1338 
1339  if (C_From)
1340  {
1341  return mutt_addr_copy(C_From);
1342  }
1343  else if (C_UseDomain)
1344  {
1345  struct Address *addr = mutt_addr_new();
1346  mutt_str_asprintf(&addr->mailbox, "%s@%s", NONULL(Username), NONULL(mutt_fqdn(true)));
1347  return addr;
1348  }
1349  else
1350  {
1351  return mutt_addr_create(NULL, Username);
1352  }
1353 }
1354 
1361 static int invoke_mta(struct Email *e)
1362 {
1363  struct Buffer *tempfile = NULL;
1364  int rc = -1;
1365 #ifdef USE_SMTP
1366  short old_write_bcc;
1367 #endif
1368 
1369  /* Write out the message in MIME form. */
1370  tempfile = mutt_buffer_pool_get();
1371  mutt_buffer_mktemp(tempfile);
1372  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tempfile), "w");
1373  if (!fp_tmp)
1374  goto cleanup;
1375 
1376 #ifdef USE_SMTP
1377  old_write_bcc = C_WriteBcc;
1378  if (C_SmtpUrl)
1379  C_WriteBcc = false;
1380 #endif
1381 #ifdef MIXMASTER
1383  !STAILQ_EMPTY(&e->chain),
1385 #endif
1386 #ifndef MIXMASTER
1389 #endif
1390 #ifdef USE_SMTP
1391  if (old_write_bcc)
1392  C_WriteBcc = true;
1393 #endif
1394 
1395  fputc('\n', fp_tmp); /* tie off the header. */
1396 
1397  if ((mutt_write_mime_body(e->content, fp_tmp) == -1))
1398  goto cleanup;
1399 
1400  if (mutt_file_fclose(&fp_tmp) != 0)
1401  {
1402  mutt_perror(mutt_b2s(tempfile));
1403  unlink(mutt_b2s(tempfile));
1404  goto cleanup;
1405  }
1406 
1407 #ifdef MIXMASTER
1408  if (!STAILQ_EMPTY(&e->chain))
1409  {
1410  rc = mix_send_message(&e->chain, mutt_b2s(tempfile));
1411  goto cleanup;
1412  }
1413 #endif
1414 
1415 #ifdef USE_NNTP
1416  if (OptNewsSend)
1417  goto sendmail;
1418 #endif
1419 
1420 #ifdef USE_SMTP
1421  if (C_SmtpUrl)
1422  {
1423  rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1424  mutt_b2s(tempfile), (e->content->encoding == ENC_8BIT));
1425  goto cleanup;
1426  }
1427 #endif
1428 
1429 sendmail:
1430  rc = mutt_invoke_sendmail(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1431  mutt_b2s(tempfile), (e->content->encoding == ENC_8BIT));
1432 cleanup:
1433  if (fp_tmp)
1434  {
1435  mutt_file_fclose(&fp_tmp);
1436  unlink(mutt_b2s(tempfile));
1437  }
1438  mutt_buffer_pool_release(&tempfile);
1439  return rc;
1440 }
1441 
1447 void mutt_encode_descriptions(struct Body *b, bool recurse)
1448 {
1449  for (struct Body *t = b; t; t = t->next)
1450  {
1451  if (t->description)
1452  {
1453  rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), C_SendCharset);
1454  }
1455  if (recurse && t->parts)
1456  mutt_encode_descriptions(t->parts, recurse);
1457  }
1458 }
1459 
1464 static void decode_descriptions(struct Body *b)
1465 {
1466  for (struct Body *t = b; t; t = t->next)
1467  {
1468  if (t->description)
1469  {
1470  rfc2047_decode(&t->description);
1471  }
1472  if (t->parts)
1473  decode_descriptions(t->parts);
1474  }
1475 }
1476 
1481 static void fix_end_of_file(const char *data)
1482 {
1483  FILE *fp = mutt_file_fopen(data, "a+");
1484  if (!fp)
1485  return;
1486  if (fseek(fp, -1, SEEK_END) >= 0)
1487  {
1488  int c = fgetc(fp);
1489  if (c != '\n')
1490  fputc('\n', fp);
1491  }
1492  mutt_file_fclose(&fp);
1493 }
1494 
1504 int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur)
1505 {
1506  struct Email *e_new = email_new();
1507 
1508  if (mutt_prepare_template(fp, ctx->mailbox, e_new, e_cur, true) < 0)
1509  {
1510  email_free(&e_new);
1511  return -1;
1512  }
1513 
1514  if (WithCrypto)
1515  {
1516  /* mutt_prepare_template doesn't always flip on an application bit.
1517  * so fix that here */
1518  if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1519  {
1520  if (((WithCrypto & APPLICATION_SMIME) != 0) && C_SmimeIsDefault)
1521  e_new->security |= APPLICATION_SMIME;
1522  else if (WithCrypto & APPLICATION_PGP)
1523  e_new->security |= APPLICATION_PGP;
1524  else
1525  e_new->security |= APPLICATION_SMIME;
1526  }
1527 
1529  {
1530  e_new->security |= SEC_OPPENCRYPT;
1532  }
1533  }
1534 
1535  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1536  emaillist_add_email(&el, e_cur);
1537  int rc = mutt_send_message(SEND_RESEND, e_new, NULL, ctx, &el);
1538  emaillist_clear(&el);
1539 
1540  return rc;
1541 }
1542 
1550 static bool is_reply(struct Email *reply, struct Email *orig)
1551 {
1552  if (!reply || !reply->env || !orig || !orig->env)
1553  return false;
1554  return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1555  mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1556 }
1557 
1568 static bool search_attach_keyword(char *filename)
1569 {
1570  /* Search for the regex in C_AbortNoattachRegex within a file */
1571  if (!C_AbortNoattachRegex || !C_AbortNoattachRegex->regex || !C_QuoteRegex ||
1572  !C_QuoteRegex->regex)
1573  {
1574  return false;
1575  }
1576 
1577  FILE *fp_att = mutt_file_fopen(filename, "r");
1578  if (!fp_att)
1579  return false;
1580 
1581  char *inputline = mutt_mem_malloc(1024);
1582  bool found = false;
1583  while (!feof(fp_att))
1584  {
1585  fgets(inputline, 1024, fp_att);
1586  if (!mutt_is_quote_line(inputline, NULL) &&
1587  mutt_regex_match(C_AbortNoattachRegex, inputline))
1588  {
1589  found = true;
1590  break;
1591  }
1592  }
1593  FREE(&inputline);
1594  mutt_file_fclose(&fp_att);
1595  return found;
1596 }
1597 
1609 static int save_fcc(struct Email *e, struct Buffer *fcc, struct Body *clear_content,
1610  char *pgpkeylist, SendFlags flags, char **finalpath)
1611 {
1612  int rc = 0;
1613  struct Body *save_content = NULL;
1614 
1616 
1617  /* Don't save a copy when we are in batch-mode, and the FCC
1618  * folder is on an IMAP server: This would involve possibly lots
1619  * of user interaction, which is not available in batch mode.
1620  *
1621  * Note: A patch to fix the problems with the use of IMAP servers
1622  * from non-curses mode is available from Brendan Cully. However,
1623  * I'd like to think a bit more about this before including it. */
1624 
1625 #ifdef USE_IMAP
1626  if ((flags & SEND_BATCH) && !mutt_buffer_is_empty(fcc) &&
1627  (imap_path_probe(mutt_b2s(fcc), NULL) == MUTT_IMAP))
1628  {
1629  mutt_buffer_reset(fcc);
1630  mutt_error(_("Fcc to an IMAP mailbox is not supported in batch mode"));
1631  return rc;
1632  }
1633 #endif
1634 
1635  if (mutt_buffer_is_empty(fcc) || (mutt_str_strcmp("/dev/null", mutt_b2s(fcc)) == 0))
1636  return rc;
1637 
1638  struct Body *tmpbody = e->content;
1639  struct Body *save_sig = NULL;
1640  struct Body *save_parts = NULL;
1641 
1642  /* Before sending, we don't allow message manipulation because it
1643  * will break message signatures. This is especially complicated by
1644  * Protected Headers. */
1645  if (!C_FccBeforeSend)
1646  {
1647  if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) && C_FccClear)
1648  {
1649  e->content = clear_content;
1652  }
1653 
1654  /* check to see if the user wants copies of all attachments */
1655  bool save_atts = true;
1656  if (e->content->type == TYPE_MULTIPART)
1657  {
1658  /* In batch mode, save attachments if the quadoption is yes or ask-yes */
1659  if (flags & SEND_BATCH)
1660  {
1661  if ((C_FccAttach == MUTT_NO) || (C_FccAttach == MUTT_ASKNO))
1662  save_atts = false;
1663  }
1664  else if (query_quadoption(C_FccAttach, _("Save attachments in Fcc?")) != MUTT_YES)
1665  save_atts = false;
1666  }
1667  if (!save_atts)
1668  {
1669  if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) &&
1670  ((mutt_str_strcmp(e->content->subtype, "encrypted") == 0) ||
1671  (mutt_str_strcmp(e->content->subtype, "signed") == 0)))
1672  {
1673  if ((clear_content->type == TYPE_MULTIPART) &&
1674  (query_quadoption(C_FccAttach, _("Save attachments in Fcc?")) == MUTT_NO))
1675  {
1676  if (!(e->security & SEC_ENCRYPT) && (e->security & SEC_SIGN))
1677  {
1678  /* save initial signature and attachments */
1679  save_sig = e->content->parts->next;
1680  save_parts = clear_content->parts->next;
1681  }
1682 
1683  /* this means writing only the main part */
1684  e->content = clear_content->parts;
1685 
1686  if (mutt_protect(e, pgpkeylist, false) == -1)
1687  {
1688  /* we can't do much about it at this point, so
1689  * fallback to saving the whole thing to fcc */
1690  e->content = tmpbody;
1691  save_sig = NULL;
1692  goto full_fcc;
1693  }
1694 
1695  save_content = e->content;
1696  }
1697  }
1698  else
1699  {
1700  if (query_quadoption(C_FccAttach, _("Save attachments in Fcc?")) == MUTT_NO)
1701  e->content = e->content->parts;
1702  }
1703  }
1704  }
1705 
1706 full_fcc:
1707  if (e->content)
1708  {
1709  /* update received time so that when storing to a mbox-style folder
1710  * the From_ line contains the current time instead of when the
1711  * message was first postponed. */
1712  e->received = mutt_date_epoch();
1713  rc = mutt_write_multiple_fcc(mutt_b2s(fcc), e, NULL, false, NULL, finalpath);
1714  while (rc && !(flags & SEND_BATCH))
1715  {
1716  mutt_clear_error();
1717  int choice = mutt_multi_choice(
1718  /* L10N: Called when saving to $record or Fcc failed after sending.
1719  (r)etry tries the same mailbox again.
1720  alternate (m)ailbox prompts for a different mailbox to try.
1721  (s)kip aborts saving. */
1722  _("Fcc failed. (r)etry, alternate (m)ailbox, or (s)kip?"),
1723  /* L10N: These correspond to the "Fcc failed" multi-choice prompt
1724  (r)etry, alternate (m)ailbox, or (s)kip.
1725  Any similarity to famous leaders of the FSF is coincidental. */
1726  _("rms"));
1727  switch (choice)
1728  {
1729  case 2: /* alternate (m)ailbox */
1730  /* L10N: This is the prompt to enter an "alternate (m)ailbox" when the
1731  initial Fcc fails. */
1732  rc = mutt_buffer_enter_fname(_("Fcc mailbox"), fcc, true);
1733  if ((rc == -1) || mutt_buffer_is_empty(fcc))
1734  {
1735  rc = 0;
1736  break;
1737  }
1738  /* fall through */
1739 
1740  case 1: /* (r)etry */
1741  rc = mutt_write_multiple_fcc(mutt_b2s(fcc), e, NULL, false, NULL, finalpath);
1742  break;
1743 
1744  case -1: /* abort */
1745  case 3: /* (s)kip */
1746  rc = 0;
1747  break;
1748  }
1749  }
1750  }
1751 
1752  if (!C_FccBeforeSend)
1753  {
1754  e->content = tmpbody;
1755 
1756  if ((WithCrypto != 0) && save_sig)
1757  {
1758  /* cleanup the second signature structures */
1759  if (save_content->parts)
1760  {
1761  mutt_body_free(&save_content->parts->next);
1762  save_content->parts = NULL;
1763  }
1764  mutt_body_free(&save_content);
1765 
1766  /* restore old signature and attachments */
1767  e->content->parts->next = save_sig;
1768  e->content->parts->parts->next = save_parts;
1769  }
1770  else if ((WithCrypto != 0) && save_content)
1771  {
1772  /* destroy the new encrypted body. */
1773  mutt_body_free(&save_content);
1774  }
1775  }
1776 
1777  return 0;
1778 }
1779 
1789 static int postpone_message(struct Email *e_post, struct Email *e_cur,
1790  const char *fcc, SendFlags flags)
1791 {
1792  char *pgpkeylist = NULL;
1793  char *encrypt_as = NULL;
1794  struct Body *clear_content = NULL;
1795 
1796  if (!C_Postponed)
1797  {
1798  mutt_error(_("Can't postpone. $postponed is unset"));
1799  return -1;
1800  }
1801 
1802  if (e_post->content->next)
1803  e_post->content = mutt_make_multipart(e_post->content);
1804 
1805  mutt_encode_descriptions(e_post->content, true);
1806 
1807  if ((WithCrypto != 0) && C_PostponeEncrypt &&
1808  (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
1809  {
1810  if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
1811  encrypt_as = C_PgpDefaultKey;
1812  else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e_post->security & APPLICATION_SMIME))
1813  encrypt_as = C_SmimeDefaultKey;
1814  if (!encrypt_as)
1815  encrypt_as = C_PostponeEncryptAs;
1816 
1817 #ifdef USE_AUTOCRYPT
1818  if (e_post->security & SEC_AUTOCRYPT)
1819  {
1821  {
1822  e_post->content = mutt_remove_multipart(e_post->content);
1823  decode_descriptions(e_post->content);
1824  mutt_error(_("Error encrypting message. Check your crypt settings."));
1825  return -1;
1826  }
1827  encrypt_as = AutocryptDefaultKey;
1828  }
1829 #endif
1830 
1831  if (encrypt_as)
1832  {
1833  pgpkeylist = mutt_str_strdup(encrypt_as);
1834  clear_content = e_post->content;
1835  if (mutt_protect(e_post, pgpkeylist, true) == -1)
1836  {
1837  FREE(&pgpkeylist);
1838  e_post->content = mutt_remove_multipart(e_post->content);
1839  decode_descriptions(e_post->content);
1840  mutt_error(_("Error encrypting message. Check your crypt settings."));
1841  return -1;
1842  }
1843 
1844  FREE(&pgpkeylist);
1845 
1846  mutt_encode_descriptions(e_post->content, false);
1847  }
1848  }
1849 
1850  /* make sure the message is written to the right part of a maildir
1851  * postponed folder. */
1852  e_post->read = false;
1853  e_post->old = false;
1854 
1855  mutt_prepare_envelope(e_post->env, false);
1856  mutt_env_to_intl(e_post->env, NULL, NULL); /* Handle bad IDNAs the next time. */
1857 
1858  if (mutt_write_fcc(NONULL(C_Postponed), e_post,
1859  (e_cur && (flags & SEND_REPLY)) ? e_cur->env->message_id : NULL,
1860  true, fcc, NULL) < 0)
1861  {
1862  if (clear_content)
1863  {
1864  mutt_body_free(&e_post->content);
1865  e_post->content = clear_content;
1866  }
1867  mutt_env_free(&e_post->content->mime_headers); /* protected headers */
1868  e_post->content = mutt_remove_multipart(e_post->content);
1869  decode_descriptions(e_post->content);
1870  mutt_unprepare_envelope(e_post->env);
1871  return -1;
1872  }
1873 
1875 
1876  if (clear_content)
1877  mutt_body_free(&clear_content);
1878 
1879  return 0;
1880 }
1881 
1893 int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile,
1894  struct Context *ctx, struct EmailList *el)
1895 {
1896  char buf[1024];
1897  struct Buffer fcc = mutt_buffer_make(0); /* where to copy this message */
1898  FILE *fp_tmp = NULL;
1899  struct Body *pbody = NULL;
1900  int i;
1901  bool free_clear_content = false;
1902 
1903  struct Body *clear_content = NULL;
1904  char *pgpkeylist = NULL;
1905  /* save current value of "pgp_sign_as" and "smime_default_key" */
1906  char *pgp_signas = NULL;
1907  char *smime_signas = NULL;
1908  const char *tag = NULL;
1909  char *err = NULL;
1910  char *ctype = NULL;
1911  char *finalpath = NULL;
1912  struct EmailNode *en = NULL;
1913  struct Email *e_cur = NULL;
1914 
1915  if (el)
1916  en = STAILQ_FIRST(el);
1917  if (en)
1918  e_cur = STAILQ_NEXT(en, entries) ? NULL : en->email;
1919 
1920  int rc = -1;
1921 
1922 #ifdef USE_NNTP
1923  if (flags & SEND_NEWS)
1924  OptNewsSend = true;
1925  else
1926  OptNewsSend = false;
1927 #endif
1928 
1929  if (!flags && !e_templ && (C_Recall != MUTT_NO) &&
1930  mutt_num_postponed(ctx ? ctx->mailbox : NULL, true))
1931  {
1932  /* If the user is composing a new message, check to see if there
1933  * are any postponed messages first. */
1934  enum QuadOption ans =
1935  query_quadoption(C_Recall, _("Recall postponed message?"));
1936  if (ans == MUTT_ABORT)
1937  return rc;
1938 
1939  if (ans == MUTT_YES)
1940  flags |= SEND_POSTPONED;
1941  }
1942 
1943  /* Allocate the buffer due to the long lifetime, but
1944  * pre-resize it to ensure there are no NULL data field issues */
1945  mutt_buffer_alloc(&fcc, 1024);
1946 
1947  if (flags & SEND_POSTPONED)
1948  {
1950  pgp_signas = mutt_str_strdup(C_PgpSignAs);
1952  smime_signas = mutt_str_strdup(C_SmimeSignAs);
1953  }
1954 
1955  /* Delay expansion of aliases until absolutely necessary--shouldn't
1956  * be necessary unless we are prompting the user or about to execute a
1957  * send-hook. */
1958 
1959  if (!e_templ)
1960  {
1961  e_templ = email_new();
1962 
1963  if (flags == SEND_POSTPONED)
1964  {
1965  rc = mutt_get_postponed(ctx, e_templ, &e_cur, &fcc);
1966  if (rc < 0)
1967  {
1968  flags = SEND_POSTPONED;
1969  goto cleanup;
1970  }
1971  flags = rc;
1972 #ifdef USE_NNTP
1973  /* If postponed message is a news article, it have
1974  * a "Newsgroups:" header line, then set appropriate flag. */
1975  if (e_templ->env->newsgroups)
1976  {
1977  flags |= SEND_NEWS;
1978  OptNewsSend = true;
1979  }
1980  else
1981  {
1982  flags &= ~SEND_NEWS;
1983  OptNewsSend = false;
1984  }
1985 #endif
1986  }
1987 
1988  if (flags & (SEND_POSTPONED | SEND_RESEND))
1989  {
1990  fp_tmp = mutt_file_fopen(e_templ->content->filename, "a+");
1991  if (!fp_tmp)
1992  {
1993  mutt_perror(e_templ->content->filename);
1994  goto cleanup;
1995  }
1996  }
1997 
1998  if (!e_templ->env)
1999  e_templ->env = mutt_env_new();
2000  }
2001 
2002  /* Parse and use an eventual list-post header */
2003  if ((flags & SEND_LIST_REPLY) && e_cur && e_cur->env && e_cur->env->list_post)
2004  {
2005  /* Use any list-post header as a template */
2006  mutt_parse_mailto(e_templ->env, NULL, e_cur->env->list_post);
2007  /* We don't let them set the sender's address. */
2008  mutt_addrlist_clear(&e_templ->env->from);
2009  }
2010 
2011  if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND)))
2012  {
2013  /* When SEND_DRAFT_FILE is set, the caller has already
2014  * created the "parent" body structure. */
2015  if (!(flags & SEND_DRAFT_FILE))
2016  {
2017  pbody = mutt_body_new();
2018  pbody->next = e_templ->content; /* don't kill command-line attachments */
2019  e_templ->content = pbody;
2020 
2021  ctype = mutt_str_strdup(C_ContentType);
2022  if (!ctype)
2023  ctype = mutt_str_strdup("text/plain");
2024  mutt_parse_content_type(ctype, e_templ->content);
2025  FREE(&ctype);
2026  e_templ->content->unlink = true;
2027  e_templ->content->use_disp = false;
2028  e_templ->content->disposition = DISP_INLINE;
2029 
2030  if (tempfile)
2031  {
2032  fp_tmp = mutt_file_fopen(tempfile, "a+");
2033  e_templ->content->filename = mutt_str_strdup(tempfile);
2034  }
2035  else
2036  {
2037  mutt_mktemp(buf, sizeof(buf));
2038  fp_tmp = mutt_file_fopen(buf, "w+");
2039  e_templ->content->filename = mutt_str_strdup(buf);
2040  }
2041  }
2042  else
2043  fp_tmp = mutt_file_fopen(e_templ->content->filename, "a+");
2044 
2045  if (!fp_tmp)
2046  {
2047  mutt_debug(LL_DEBUG1, "can't create tempfile %s (errno=%d)\n",
2048  e_templ->content->filename, errno);
2049  mutt_perror(e_templ->content->filename);
2050  goto cleanup;
2051  }
2052  }
2053 
2054  /* this is handled here so that the user can match ~f in send-hook */
2055  if (e_cur && C_ReverseName && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2056  {
2057  /* We shouldn't have to worry about alias expansion here since we are
2058  * either replying to a real or postponed message, therefore no aliases
2059  * should exist since the user has not had the opportunity to add
2060  * addresses to the list. We just have to ensure the postponed messages
2061  * have their aliases expanded. */
2062 
2063  if (!TAILQ_EMPTY(&e_templ->env->from))
2064  {
2065  mutt_debug(LL_DEBUG5, "e_templ->env->from before set_reverse_name: %s\n",
2066  TAILQ_FIRST(&e_templ->env->from)->mailbox);
2067  mutt_addrlist_clear(&e_templ->env->from);
2068  }
2069  set_reverse_name(&e_templ->env->from, e_cur->env);
2070  }
2071  if (e_cur && C_ReplyWithXorig && !(flags & (SEND_POSTPONED | SEND_RESEND | SEND_FORWARD)))
2072  {
2073  /* We shouldn't have to worry about freeing 'e_templ->env->from' before
2074  * setting it here since this code will only execute when doing some
2075  * sort of reply. The pointer will only be set when using the -H command
2076  * line option.
2077  *
2078  * If there is already a from address recorded in 'e_templ->env->from',
2079  * then it theoretically comes from C_ReverseName handling, and we don't use
2080  * the 'X-Orig-To header'. */
2081  if (!TAILQ_EMPTY(&e_cur->env->x_original_to) && TAILQ_EMPTY(&e_templ->env->from))
2082  {
2083  mutt_addrlist_copy(&e_templ->env->from, &e_cur->env->x_original_to, false);
2084  mutt_debug(LL_DEBUG5, "e_templ->env->from extracted from X-Original-To: header: %s\n",
2085  TAILQ_FIRST(&e_templ->env->from)->mailbox);
2086  }
2087  }
2088 
2089  if (!(flags & (SEND_POSTPONED | SEND_RESEND)) &&
2090  !((flags & SEND_DRAFT_FILE) && C_ResumeDraftFiles))
2091  {
2092  if ((flags & (SEND_REPLY | SEND_FORWARD | SEND_TO_SENDER)) && ctx &&
2093  (envelope_defaults(e_templ->env, ctx->mailbox, el, flags) == -1))
2094  {
2095  goto cleanup;
2096  }
2097 
2098  if (C_Hdrs)
2099  process_user_recips(e_templ->env);
2100 
2101  /* Expand aliases and remove duplicates/crossrefs */
2102  mutt_expand_aliases_env(e_templ->env);
2103 
2104  if (flags & SEND_REPLY)
2105  mutt_fix_reply_recipients(e_templ->env);
2106 
2107 #ifdef USE_NNTP
2108  if ((flags & SEND_NEWS) && ctx && (ctx->mailbox->type == MUTT_NNTP) &&
2109  !e_templ->env->newsgroups)
2110  {
2111  e_templ->env->newsgroups =
2112  mutt_str_strdup(((struct NntpMboxData *) ctx->mailbox->mdata)->group);
2113  }
2114 #endif
2115 
2116  if (!(flags & (SEND_MAILX | SEND_BATCH)) &&
2117  !(C_Autoedit && C_EditHeaders) && !((flags & SEND_REPLY) && C_FastReply))
2118  {
2119  if (edit_envelope(e_templ->env, flags) == -1)
2120  goto cleanup;
2121  }
2122 
2123  /* the from address must be set here regardless of whether or not
2124  * $use_from is set so that the '~P' (from you) operator in send-hook
2125  * patterns will work. if $use_from is unset, the from address is killed
2126  * after send-hooks are evaluated */
2127 
2128  const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2129  if (killfrom)
2130  {
2132  }
2133 
2134  if ((flags & SEND_REPLY) && e_cur)
2135  {
2136  /* change setting based upon message we are replying to */
2137  mutt_message_hook(ctx ? ctx->mailbox : NULL, e_cur, MUTT_REPLY_HOOK);
2138 
2139  /* set the replied flag for the message we are generating so that the
2140  * user can use ~Q in a send-hook to know when reply-hook's are also
2141  * being used. */
2142  e_templ->replied = true;
2143  }
2144 
2145  /* change settings based upon recipients */
2146 
2147  mutt_message_hook(NULL, e_templ, MUTT_SEND_HOOK);
2148 
2149  /* Unset the replied flag from the message we are composing since it is
2150  * no longer required. This is done here because the FCC'd copy of
2151  * this message was erroneously get the 'R'eplied flag when stored in
2152  * a maildir-style mailbox. */
2153  e_templ->replied = false;
2154 
2155  /* $use_from and/or $from might have changed in a send-hook */
2156  if (killfrom)
2157  {
2158  mutt_addrlist_clear(&e_templ->env->from);
2159  if (C_UseFrom && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2161  }
2162 
2163  if (C_Hdrs)
2164  process_user_header(e_templ->env);
2165 
2166  if (flags & SEND_BATCH)
2167  {
2168  if (mutt_file_copy_stream(stdin, fp_tmp) < 1)
2169  {
2170  mutt_error(_("Refusing to send an empty email"));
2171  mutt_message(_("Try: echo | neomutt -s 'subject' user@example.com"));
2172  goto cleanup;
2173  }
2174  }
2175 
2176  if (C_SigOnTop && !(flags & (SEND_MAILX | SEND_KEY | SEND_BATCH)) &&
2177  C_Editor && (mutt_str_strcmp(C_Editor, "builtin") != 0))
2178  {
2179  append_signature(fp_tmp);
2180  }
2181 
2182  /* include replies/forwarded messages, unless we are given a template */
2183  if (!tempfile && (ctx || !(flags & (SEND_REPLY | SEND_FORWARD))) &&
2184  (generate_body(fp_tmp, e_templ, flags, ctx ? ctx->mailbox : NULL, el) == -1))
2185  {
2186  goto cleanup;
2187  }
2188 
2189  if (!C_SigOnTop && !(flags & (SEND_MAILX | SEND_KEY | SEND_BATCH)) &&
2190  C_Editor && (mutt_str_strcmp(C_Editor, "builtin") != 0))
2191  {
2192  append_signature(fp_tmp);
2193  }
2194  }
2195 
2196  /* Only set format=flowed for new messages. postponed/resent/draftfiles
2197  * should respect the original email.
2198  *
2199  * This is set here so that send-hook can be used to turn the option on. */
2200  if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND | SEND_DRAFT_FILE)))
2201  {
2202  if (C_TextFlowed && (e_templ->content->type == TYPE_TEXT) &&
2203  (mutt_str_strcasecmp(e_templ->content->subtype, "plain") == 0))
2204  {
2205  mutt_param_set(&e_templ->content->parameter, "format", "flowed");
2206  }
2207  }
2208 
2209  /* This hook is even called for postponed messages, and can, e.g., be
2210  * used for setting the editor, the sendmail path, or the
2211  * envelope sender. */
2212  mutt_message_hook(NULL, e_templ, MUTT_SEND2_HOOK);
2213 
2214  /* wait until now to set the real name portion of our return address so
2215  * that $realname can be set in a send-hook */
2216  {
2217  struct Address *from = TAILQ_FIRST(&e_templ->env->from);
2218  if (from && !from->personal && !(flags & (SEND_RESEND | SEND_POSTPONED)))
2220  }
2221 
2222  if (!(((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY)))
2223  mutt_file_fclose(&fp_tmp);
2224 
2225  if (flags & SEND_MAILX)
2226  {
2227  if (mutt_builtin_editor(e_templ->content->filename, e_templ, e_cur) == -1)
2228  goto cleanup;
2229  }
2230  else if (!(flags & SEND_BATCH))
2231  {
2232  struct stat st;
2233  time_t mtime = mutt_file_decrease_mtime(e_templ->content->filename, NULL);
2234 
2235  mutt_update_encoding(e_templ->content);
2236 
2237  /* Select whether or not the user's editor should be called now. We
2238  * don't want to do this when:
2239  * 1) we are sending a key/cert
2240  * 2) we are forwarding a message and the user doesn't want to edit it.
2241  * This is controlled by the quadoption $forward_edit. However, if
2242  * both $edit_headers and $autoedit are set, we want to ignore the
2243  * setting of $forward_edit because the user probably needs to add the
2244  * recipients. */
2245  if (!(flags & SEND_KEY) &&
2246  (((flags & SEND_FORWARD) == 0) || (C_EditHeaders && C_Autoedit) ||
2247  (query_quadoption(C_ForwardEdit, _("Edit forwarded message?")) == MUTT_YES)))
2248  {
2249  /* If the this isn't a text message, look for a mailcap edit command */
2250  if (mutt_needs_mailcap(e_templ->content))
2251  {
2252  if (!mutt_edit_attachment(e_templ->content))
2253  goto cleanup;
2254  }
2255  else if (!C_Editor || (mutt_str_strcmp("builtin", C_Editor) == 0))
2256  mutt_builtin_editor(e_templ->content->filename, e_templ, e_cur);
2257  else if (C_EditHeaders)
2258  {
2259  mutt_env_to_local(e_templ->env);
2260  mutt_edit_headers(C_Editor, e_templ->content->filename, e_templ, &fcc);
2261  mutt_env_to_intl(e_templ->env, NULL, NULL);
2262  }
2263  else
2264  {
2266  if (stat(e_templ->content->filename, &st) == 0)
2267  {
2268  if (mtime != st.st_mtime)
2269  fix_end_of_file(e_templ->content->filename);
2270  }
2271  else
2272  mutt_perror(e_templ->content->filename);
2273  }
2274 
2275  mutt_message_hook(NULL, e_templ, MUTT_SEND2_HOOK);
2276  }
2277 
2278  if (!(flags & (SEND_POSTPONED | SEND_FORWARD | SEND_KEY | SEND_RESEND | SEND_DRAFT_FILE)))
2279  {
2280  if (stat(e_templ->content->filename, &st) == 0)
2281  {
2282  /* if the file was not modified, bail out now */
2283  if ((mtime == st.st_mtime) && !e_templ->content->next &&
2285  _("Abort unmodified message?")) == MUTT_YES))
2286  {
2287  mutt_message(_("Aborted unmodified message"));
2288  goto cleanup;
2289  }
2290  }
2291  else
2292  mutt_perror(e_templ->content->filename);
2293  }
2294  }
2295 
2296  /* Set the message security unless:
2297  * 1) crypto support is not enabled (WithCrypto==0)
2298  * 2) pgp: header field was present during message editing with $edit_headers (e_templ->security != 0)
2299  * 3) we are resending a message
2300  * 4) we are recalling a postponed message (don't override the user's saved settings)
2301  * 5) we are in mailx mode
2302  * 6) we are in batch mode
2303  *
2304  * This is done after allowing the user to edit the message so that security
2305  * settings can be configured with send2-hook and $edit_headers. */
2306  if ((WithCrypto != 0) && (e_templ->security == 0) &&
2307  !(flags & (SEND_BATCH | SEND_MAILX | SEND_POSTPONED | SEND_RESEND)))
2308  {
2309  if (
2310 #ifdef USE_AUTOCRYPT
2312 #else
2313  0
2314 #endif
2315  && e_cur && (e_cur->security & SEC_AUTOCRYPT))
2316  {
2318  }
2319  else
2320  {
2321  if (C_CryptAutosign)
2322  e_templ->security |= SEC_SIGN;
2323  if (C_CryptAutoencrypt)
2324  e_templ->security |= SEC_ENCRYPT;
2325  if (C_CryptReplyencrypt && e_cur && (e_cur->security & SEC_ENCRYPT))
2326  e_templ->security |= SEC_ENCRYPT;
2327  if (C_CryptReplysign && e_cur && (e_cur->security & SEC_SIGN))
2328  e_templ->security |= SEC_SIGN;
2329  if (C_CryptReplysignencrypted && e_cur && (e_cur->security & SEC_ENCRYPT))
2330  e_templ->security |= SEC_SIGN;
2331  if (((WithCrypto & APPLICATION_PGP) != 0) &&
2333  {
2334  if (C_PgpAutoinline)
2335  e_templ->security |= SEC_INLINE;
2336  if (C_PgpReplyinline && e_cur && (e_cur->security & SEC_INLINE))
2337  e_templ->security |= SEC_INLINE;
2338  }
2339  }
2340 
2341  if (e_templ->security || C_CryptOpportunisticEncrypt)
2342  {
2343  /* When replying / forwarding, use the original message's
2344  * crypto system. According to the documentation,
2345  * smime_is_default should be disregarded here.
2346  *
2347  * Problem: At least with forwarding, this doesn't really
2348  * make much sense. Should we have an option to completely
2349  * disable individual mechanisms at run-time? */
2350  if (e_cur)
2351  {
2352  if (((WithCrypto & APPLICATION_PGP) != 0) && C_CryptAutopgp &&
2353  (e_cur->security & APPLICATION_PGP))
2354  {
2355  e_templ->security |= APPLICATION_PGP;
2356  }
2357  else if (((WithCrypto & APPLICATION_SMIME) != 0) && C_CryptAutosmime &&
2358  (e_cur->security & APPLICATION_SMIME))
2359  {
2360  e_templ->security |= APPLICATION_SMIME;
2361  }
2362  }
2363 
2364  /* No crypto mechanism selected? Use availability + smime_is_default
2365  * for the decision. */
2366  if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2367  {
2369  {
2370  e_templ->security |= APPLICATION_SMIME;
2371  }
2372  else if (((WithCrypto & APPLICATION_PGP) != 0) && C_CryptAutopgp)
2373  {
2374  e_templ->security |= APPLICATION_PGP;
2375  }
2376  else if (((WithCrypto & APPLICATION_SMIME) != 0) && C_CryptAutosmime)
2377  {
2378  e_templ->security |= APPLICATION_SMIME;
2379  }
2380  }
2381  }
2382 
2383  /* opportunistic encrypt relies on SMIME or PGP already being selected */
2385  {
2386  /* If something has already enabled encryption, e.g. C_CryptAutoencrypt
2387  * or C_CryptReplyencrypt, then don't enable opportunistic encrypt for
2388  * the message. */
2389  if (!(e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
2390  {
2391  e_templ->security |= SEC_OPPENCRYPT;
2392  crypt_opportunistic_encrypt(e_templ);
2393  }
2394  }
2395 
2396  /* No permissible mechanisms found. Don't sign or encrypt. */
2397  if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2398  e_templ->security = SEC_NO_FLAGS;
2399  }
2400 
2401  /* Deal with the corner case where the crypto module backend is not available.
2402  * This can happen if configured without PGP/SMIME and with GPGME, but
2403  * $crypt_use_gpgme is unset. */
2404  if (e_templ->security && !crypt_has_module_backend(e_templ->security))
2405  {
2406  mutt_error(_(
2407  "No crypto backend configured. Disabling message security setting."));
2408  e_templ->security = SEC_NO_FLAGS;
2409  }
2410 
2411  /* specify a default fcc. if we are in batchmode, only save a copy of
2412  * the message if the value of $copy is yes or ask-yes */
2413 
2414  if (mutt_buffer_is_empty(&fcc) && !(flags & SEND_POSTPONED_FCC) &&
2415  (!(flags & SEND_BATCH) || (C_Copy & 0x1)))
2416  {
2417  /* set the default FCC */
2418  const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2419  if (killfrom)
2420  {
2422  }
2423  mutt_select_fcc(&fcc, e_templ);
2424  if (killfrom)
2425  {
2426  mutt_addrlist_clear(&e_templ->env->from);
2427  }
2428  }
2429 
2430  mutt_rfc3676_space_stuff(e_templ);
2431 
2432  mutt_update_encoding(e_templ->content);
2433 
2434  if (!(flags & (SEND_MAILX | SEND_BATCH)))
2435  {
2436  main_loop:
2437 
2439  i = mutt_compose_menu(e_templ, &fcc, e_cur,
2441  if (i == -1)
2442  {
2443 /* abort */
2444 #ifdef USE_NNTP
2445  if (flags & SEND_NEWS)
2446  mutt_message(_("Article not posted"));
2447  else
2448 #endif
2449  mutt_message(_("Mail not sent"));
2450  goto cleanup;
2451  }
2452  else if (i == 1)
2453  {
2454  if (postpone_message(e_templ, e_cur, mutt_b2s(&fcc), flags) != 0)
2455  goto main_loop;
2456  mutt_message(_("Message postponed"));
2457  rc = 1;
2458  goto cleanup;
2459  }
2460  }
2461 
2462 #ifdef USE_NNTP
2463  if (!(flags & SEND_NEWS))
2464 #endif
2465  if ((mutt_addrlist_count_recips(&e_templ->env->to) == 0) &&
2466  (mutt_addrlist_count_recips(&e_templ->env->cc) == 0) &&
2467  (mutt_addrlist_count_recips(&e_templ->env->bcc) == 0))
2468  {
2469  if (flags & SEND_BATCH)
2470  {
2471  puts(_("No recipients specified"));
2472  goto cleanup;
2473  }
2474 
2475  mutt_error(_("No recipients specified"));
2476  goto main_loop;
2477  }
2478 
2479  if (mutt_env_to_intl(e_templ->env, &tag, &err))
2480  {
2481  mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
2482  FREE(&err);
2483  if (flags & SEND_BATCH)
2484  goto cleanup;
2485  goto main_loop;
2486  }
2487 
2488  if (!e_templ->env->subject && !(flags & SEND_BATCH) &&
2489  (query_quadoption(C_AbortNosubject, _("No subject, abort sending?")) != MUTT_NO))
2490  {
2491  /* if the abort is automatic, print an error message */
2492  if (C_AbortNosubject == MUTT_YES)
2493  mutt_error(_("No subject specified"));
2494  goto main_loop;
2495  }
2496 #ifdef USE_NNTP
2497  if ((flags & SEND_NEWS) && !e_templ->env->subject)
2498  {
2499  mutt_error(_("No subject specified"));
2500  goto main_loop;
2501  }
2502 
2503  if ((flags & SEND_NEWS) && !e_templ->env->newsgroups)
2504  {
2505  mutt_error(_("No newsgroup specified"));
2506  goto main_loop;
2507  }
2508 #endif
2509 
2510  if (!(flags & SEND_BATCH) && (C_AbortNoattach != MUTT_NO) &&
2511  !e_templ->content->next && (e_templ->content->type == TYPE_TEXT) &&
2512  (mutt_str_strcasecmp(e_templ->content->subtype, "plain") == 0) &&
2513  search_attach_keyword(e_templ->content->filename) &&
2515  _("No attachments, cancel sending?")) != MUTT_NO))
2516  {
2517  /* if the abort is automatic, print an error message */
2518  if (C_AbortNoattach == MUTT_YES)
2519  {
2520  mutt_error(_("Message contains text matching "
2521  "\"$abort_noattach_regex\". Not sending."));
2522  }
2523  goto main_loop;
2524  }
2525 
2526  if (e_templ->content->next)
2527  e_templ->content = mutt_make_multipart(e_templ->content);
2528 
2529  /* Ok, we need to do it this way instead of handling all fcc stuff in
2530  * one place in order to avoid going to main_loop with encoded "env"
2531  * in case of error. Ugh. */
2532 
2533  mutt_encode_descriptions(e_templ->content, true);
2534 
2535  /* Make sure that clear_content and free_clear_content are
2536  * properly initialized -- we may visit this particular place in
2537  * the code multiple times, including after a failed call to
2538  * mutt_protect(). */
2539 
2540  clear_content = NULL;
2541  free_clear_content = false;
2542 
2543  if (WithCrypto)
2544  {
2545  if (e_templ->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT))
2546  {
2547  /* save the decrypted attachments */
2548  clear_content = e_templ->content;
2549 
2550  if ((crypt_get_keys(e_templ, &pgpkeylist, 0) == -1) ||
2551  (mutt_protect(e_templ, pgpkeylist, false) == -1))
2552  {
2553  e_templ->content = mutt_remove_multipart(e_templ->content);
2554 
2555  FREE(&pgpkeylist);
2556 
2557  decode_descriptions(e_templ->content);
2558  goto main_loop;
2559  }
2560  mutt_encode_descriptions(e_templ->content, false);
2561  }
2562 
2563  /* at this point, e_templ->content is one of the following three things:
2564  * - multipart/signed. In this case, clear_content is a child
2565  * - multipart/encrypted. In this case, clear_content exists independently
2566  * - application/pgp. In this case, clear_content exists independently
2567  * - something else. In this case, it's the same as clear_content */
2568 
2569  /* This is ugly -- lack of "reporting back" from mutt_protect(). */
2570 
2571  if (clear_content && (e_templ->content != clear_content) &&
2572  (e_templ->content->parts != clear_content))
2573  free_clear_content = true;
2574  }
2575 
2576  if (!OptNoCurses && !(flags & SEND_MAILX))
2577  mutt_message(_("Sending message..."));
2578 
2579  mutt_prepare_envelope(e_templ->env, true);
2580 
2581  if (C_FccBeforeSend)
2582  save_fcc(e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath);
2583 
2584  i = invoke_mta(e_templ);
2585  if (i < 0)
2586  {
2587  if (!(flags & SEND_BATCH))
2588  {
2589  if (!WithCrypto)
2590  ;
2591  else if ((e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) ||
2592  ((e_templ->security & SEC_SIGN) && (e_templ->content->type == TYPE_APPLICATION)))
2593  {
2594  if (e_templ->content != clear_content)
2595  {
2596  mutt_body_free(&e_templ->content); /* destroy PGP data */
2597  e_templ->content = clear_content; /* restore clear text. */
2598  }
2599  }
2600  else if ((e_templ->security & SEC_SIGN) && (e_templ->content->type == TYPE_MULTIPART))
2601  {
2602  mutt_body_free(&e_templ->content->parts->next); /* destroy sig */
2603  e_templ->content = mutt_remove_multipart(e_templ->content);
2604  }
2605 
2606  FREE(&pgpkeylist);
2607  mutt_env_free(&e_templ->content->mime_headers); /* protected headers */
2608  e_templ->content = mutt_remove_multipart(e_templ->content);
2609  decode_descriptions(e_templ->content);
2610  mutt_unprepare_envelope(e_templ->env);
2611  FREE(&finalpath);
2612  goto main_loop;
2613  }
2614  else
2615  {
2616  puts(_("Could not send the message"));
2617  goto cleanup;
2618  }
2619  }
2620 
2621  if (!C_FccBeforeSend)
2622  save_fcc(e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath);
2623 
2624  if (!OptNoCurses && !(flags & SEND_MAILX))
2625  {
2626  mutt_message((i != 0) ? _("Sending in background") :
2627  (flags & SEND_NEWS) ? _("Article posted") : /* USE_NNTP */
2628  _("Mail sent"));
2629 #ifdef USE_NOTMUCH
2630  if (C_NmRecord)
2631  nm_record_message(ctx ? ctx->mailbox : NULL, finalpath, e_cur);
2632 #endif
2633  mutt_sleep(0);
2634  }
2635 
2636  if (WithCrypto)
2637  FREE(&pgpkeylist);
2638 
2639  if ((WithCrypto != 0) && free_clear_content)
2640  mutt_body_free(&clear_content);
2641 
2642  /* set 'replied' flag only if the user didn't change/remove
2643  * In-Reply-To: and References: headers during edit */
2644  if (flags & SEND_REPLY)
2645  {
2646  if (!(flags & SEND_POSTPONED) && ctx && ctx->mailbox)
2647  {
2648  STAILQ_FOREACH(en, el, entries)
2649  {
2650  mutt_set_flag(ctx->mailbox, en->email, MUTT_REPLIED, is_reply(en->email, e_templ));
2651  }
2652  }
2653  }
2654 
2655  rc = 0;
2656 
2657 cleanup:
2658  mutt_buffer_dealloc(&fcc);
2659 
2660  if (flags & SEND_POSTPONED)
2661  {
2662  if (WithCrypto & APPLICATION_PGP)
2663  {
2664  FREE(&C_PgpSignAs);
2665  C_PgpSignAs = pgp_signas;
2666  }
2668  {
2669  FREE(&C_SmimeSignAs);
2670  C_SmimeSignAs = smime_signas;
2671  }
2672  }
2673 
2674  mutt_file_fclose(&fp_tmp);
2675  if (!(flags & SEND_NO_FREE_HEADER))
2676  email_free(&e_templ);
2677 
2678  FREE(&finalpath);
2679  return rc;
2680 }
#define MUTT_SEND_HOOK
send-hook: when composing a new email
Definition: hook.h:47
int nm_record_message(struct Mailbox *m, char *path, struct Email *e)
Add a message to the Notmuch database.
Convenience wrapper for the gui headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:417
void mutt_fix_reply_recipients(struct Envelope *env)
Remove duplicate recipients.
Definition: send.c:911
WHERE char * Username
User&#39;s login name.
Definition: globals.h:52
The "current" mailbox.
Definition: context.h:37
struct Regex * C_AbortNoattachRegex
Config: Regex to match text indicating attachments are expected.
Definition: send.c:91
WHERE char * C_SmtpUrl
Config: (smtp) Url of the SMTP server.
Definition: globals.h:143
static void make_reference_headers(struct EmailList *el, struct Envelope *env)
Generate reference headers for an email.
Definition: send.c:994
bool C_Hdrs
Config: Add custom headers to outgoing mail.
Definition: send.c:115
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg)
Create a message attachment.
Definition: sendlib.c:1511
char * C_PostponeEncryptAs
Config: Fallback encryption key for postponed messages.
Definition: send.c:124
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:81
void mutt_actx_free(struct AttachCtx **ptr)
Free an Attachment Context.
Definition: attach.c:140
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
WHERE bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: globals.h:200
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
Miscellaneous email parsing routines.
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: sendlib.c:1772
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:70
Representation of the email&#39;s header.
#define WithCrypto
Definition: lib.h:163
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:303
#define SEND_POSTPONED_FCC
Used by mutt_get_postponed() to signal that the x-mutt-fcc header field was present.
Definition: send.h:97
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:100
IMAP network mailbox.
The envelope/body of an email.
Definition: email.h:37
WHERE bool C_WriteBcc
Config: Write out the &#39;Bcc&#39; field when preparing to send a mail.
Definition: globals.h:259
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:413
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define mutt_perror(...)
Definition: logging.h:85
char * C_ForwardAttributionIntro
Config: Prefix message for forwarded messages.
Definition: send.c:110
static int postpone_message(struct Email *e_post, struct Email *e_cur, const char *fcc, SendFlags flags)
Save an Email for another day.
Definition: send.c:1789
if(!test_colorize_)
Definition: acutest.h:499
GUI editor for an email&#39;s headers.
WHERE char * C_AttributionLocale
Config: Locale for dates in the attribution message.
Definition: globals.h:100
static void fix_end_of_file(const char *data)
Ensure a file ends with a linefeed.
Definition: send.c:1481
#define MUTT_ALIAS
Do alias "completion" by calling up the alias-menu.
Definition: mutt.h:57
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2524
Config/command parsing.
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
WHERE bool C_AutocryptReply
Config: Replying to an autocrypt email automatically enables autocrypt in the reply.
Definition: globals.h:201
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
bool C_ReplySelf
Config: Really reply to yourself, when replying to your own email.
Definition: send.c:126
Structs that make up an email.
String processing routines to generate the mail index.
void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
Definition: recvattach.c:1229
The "currently-open" mailbox.
unsigned char C_AbortNoattach
Config: Abort sending the email if attachments are missing.
Definition: send.c:90
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
Autocrypt end-to-end encryption.
static bool search_attach_keyword(char *filename)
Search an email for &#39;attachment&#39; keywords.
Definition: send.c:1568
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:124
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
WHERE bool C_ForwardDecode
Config: Decode the message when forwarding it.
Definition: globals.h:214
User aborted the question (with Ctrl-G)
Definition: quad.h:38
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:1112
#define mutt_message(...)
Definition: logging.h:83
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:144
WHERE char * C_SmimeDefaultKey
Config: Default key for SMIME operations.
Definition: globals.h:164
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email&#39;s references to a list.
Definition: send.c:883
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1329
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1412
char * C_ForwardFormat
Config: printf-like format string to control the subject when forwarding a message.
Definition: send.c:113
#define SEND_DRAFT_FILE
Used by the -H flag.
Definition: send.h:99
static char * nntp_get_header(const char *s)
Get the trimmed header.
Definition: send.c:341
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:125
#define mutt_make_string(BUF, BUFLEN, COLS, S, CTX, M, E)
Definition: hdrline.h:61
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:317
WHERE char * AutocryptDefaultKey
Autocrypt default key id (used for postponing messages)
Definition: globals.h:88
static int envelope_defaults(struct Envelope *env, struct Mailbox *m, struct EmailList *el, SendFlags flags)
Fill in some defaults for a new email.
Definition: send.c:1031
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
A normal Email, write full header + MIME headers.
Definition: sendlib.h:60
static void process_user_header(struct Envelope *env)
Process the user headers.
Definition: send.c:379
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1088
#define SEND_FORWARD
Forward email.
Definition: send.h:91
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags)
Generate recpients for a reply email.
Definition: send.c:828
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: hdrline.c:114
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:734
bool C_FccBeforeSend
Config: Save FCCs before sending the message.
Definition: send.c:107
regex_t * regex
compiled expression
Definition: regex3.h:91
struct Body * content
List of MIME parts.
Definition: email.h:90
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
int mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:257
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:52
void mutt_forward_intro(struct Mailbox *m, struct Email *e, FILE *fp)
Add the "start of forwarded message" text.
Definition: send.c:430
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:40
String manipulation buffer.
Definition: buffer.h:33
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:48
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:812
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
bool C_PostponeEncrypt
Config: Self-encrypt postponed messages.
Definition: send.c:123
#define _(a)
Definition: message.h:28
unsigned char C_AbortUnmodified
Config: Abort the sending if the message hasn&#39;t been edited.
Definition: send.c:93
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *curenv)
Set subject for a reply.
Definition: send.c:955
char * real_subj
Offset of the real subject.
Definition: envelope.h:67
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email&#39;s message ID to a list.
Definition: send.c:899
WHERE bool C_PgpAutoinline
Config: Use old-style inline PGP messages (not recommended)
Definition: globals.h:277
struct Body * next
next attachment in the list
Definition: body.h:53
short idxlen
Number of attachmentes.
Definition: attach.h:55
An email address.
Definition: address.h:34
8-bit text
Definition: mime.h:50
unsigned char C_Include
Config: Include a copy of the email that&#39;s being replied to.
Definition: send.c:118
WHERE unsigned char C_Copy
Config: Save outgoing emails to $record.
Definition: globals.h:180
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:49
char * mailbox
Mailbox and host address.
Definition: address.h:37
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:134
bool C_CryptAutosign
Config: Automatically PGP sign all outgoing mail.
Definition: send.c:99
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:692
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:52
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:31
static int inline_forward_attachments(struct Mailbox *m, struct Email *e, struct Body ***plast, int *forwardq)
Add attachments to an email, inline.
Definition: send.c:514
bool C_FollowupTo
Config: Add the &#39;Mail-Followup-To&#39; header is generated when sending mail.
Definition: send.c:109
bool C_SigDashes
Config: Insert &#39;– &#39; before the signature.
Definition: send.c:131
bool C_IgnoreListReplyTo
Config: Ignore the &#39;Reply-To&#39; header when using <reply> on a mailing list.
Definition: send.c:117
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto)
Generate default email addresses.
Definition: send.c:747
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:713
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
Definition: crypt.c:958
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:613
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:86
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope&#39;s Address fields to Punycode format.
Definition: envelope.c:309
void mutt_make_post_indent(struct Mailbox *m, struct Email *e, FILE *fp_out)
Add suffix to replied email text.
Definition: send.c:666
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
struct Address * mutt_addr_create(const char *personal, const char *mailbox)
Create and populate a new Address.
Definition: address.c:398
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:92
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:688
bool C_CryptReplysign
Config: Sign replies to signed messages.
Definition: send.c:102
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath)
Write email to FCC mailbox.
Definition: sendlib.c:3258
Representation of a single alias to an email address.
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:43
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:90
Messages that have been replied to.
Definition: mutt.h:93
int vcount
The number of virtual messages.
Definition: mailbox.h:102
The body of an email.
Definition: body.h:34
void mutt_prepare_envelope(struct Envelope *env, bool final)
Prepare an email header.
Definition: sendlib.c:3003
unsigned int disposition
content-disposition
Definition: body.h:67
Convenience wrapper for the config headers.
Prepare and send an email.
char * C_ForwardAttributionTrailer
Config: Suffix message for forwarded messages.
Definition: send.c:111
Hundreds of global variables to back the user variables.
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject)
Write out one RFC822 header line.
Definition: sendlib.c:2325
Email Address Handling.
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:132
unsigned char C_HonorFollowupTo
Config: Honour the &#39;Mail-Followup-To&#39; header when group replying.
Definition: send.c:116
Assorted sorting methods.
Some miscellaneous functions.
WHERE bool C_SmimeIsDefault
Config: Use SMIME rather than PGP by default.
Definition: globals.h:273
#define mutt_array_size(x)
Definition: memory.h:33
bool C_CryptAutosmime
Config: Allow automatic SMIME functions.
Definition: send.c:100
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1171
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:146
bool tagged
Email is tagged.
Definition: email.h:44
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1349
bool read
Email is read.
Definition: email.h:51
WHERE bool C_UseDomain
Config: Qualify local addresses using this domain.
Definition: globals.h:256
#define SEND_MAILX
Send email in Mailx compatibility mode.
Definition: send.h:94
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1535
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: email_globals.c:38
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
WHERE bool C_EditHeaders
Config: Let the user edit the email headers whilst editing an email.
Definition: globals.h:212
struct Mailbox * mailbox
Definition: context.h:51
unsigned char C_Recall
Config: Recall postponed mesaages when asked to compose a message.
Definition: send.c:125
Parse and execute user-defined hooks.
bool mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1606
int mutt_invoke_sendmail(struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, int eightbit)
Run sendmail.
Definition: sendlib.c:2823
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Many unsorted constants and some structs.
API for mailboxes.
unsigned char C_ReplyTo
Config: Address to use as a &#39;Reply-To&#39; header.
Definition: send.c:127
bool old
Email is seen, but unread.
Definition: email.h:50
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
Definition: queue.h:738
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:636
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
unsigned char C_AbortNosubject
Config: Abort creating the email if subject is missing.
Definition: send.c:92
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
WHERE unsigned char C_MimeForward
Config: Forward a message as a &#39;message/RFC822&#39; MIME part.
Definition: globals.h:183
void mutt_update_encoding(struct Body *a)
Update the encoding type.
Definition: sendlib.c:1480
static void process_user_recips(struct Envelope *env)
Process the user headers.
Definition: send.c:352
#define CH_WEED
Weed the headers?
Definition: copy.h:52
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
WHERE struct Address * C_From
Config: Default &#39;From&#39; address to use, if isn&#39;t otherwise set.
Definition: globals.h:94
struct Envelope * env
Envelope information.
Definition: email.h:89
Convenience wrapper for the core headers.
int mutt_body_copy(FILE *fp, struct Body **tgt, struct Body *src)
Create a send-mode duplicate from a receive-mode body.
Definition: mutt_body.c:48
static void decode_descriptions(struct Body *b)
rfc2047 decode them in case of an error
Definition: send.c:1464
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition: list.c:103
#define SKIPWS(ch)
Definition: string2.h:47
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
WHERE bool C_Autoedit
Config: Skip the initial compose menu and edit the email.
Definition: globals.h:203
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:90
static bool is_reply(struct Email *reply, struct Email *orig)
Is one email a reply to another?
Definition: send.c:1550
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
Usenet network mailbox type; talk to an NNTP server.
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el)
Send an email.
Definition: send.c:1893
int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath)
Handle FCC with multiple, comma separated entries.
Definition: sendlib.c:3211
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: sendlib.c:1746
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:95
int mutt_autocrypt_set_sign_as_default_key(struct Email *e)
Set the Autocrypt default key for signing.
Definition: autocrypt.c:663
char * subtype
content-type subtype
Definition: body.h:37
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
#define mutt_b2s(buf)
Definition: buffer.h:41
bool C_FastReply
Config: Don&#39;t prompt for the recipients and subject when replying/forwarding.
Definition: send.c:105
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:138
WHERE bool C_Header
Config: Include the message headers in the reply email (Weed applies)
Definition: globals.h:216
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:910
Prototypes for many functions.
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
#define SEND_RESEND
Reply using the current email as a template.
Definition: send.h:96
struct ListHead chain
Mixmaster chain.
Definition: email.h:99
Representation of the body of an email.
void mutt_set_followup_to(struct Envelope *env)
Set followup-to field.
Definition: send.c:1213
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:3042
Notmuch virtual mailbox type.
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:78
bool C_AskXCommentTo
Config: (nntp) Ask the user for the &#39;X-Comment-To&#39; field before editing.
Definition: send.c:95
struct Address * mutt_default_from(void)
Get a default &#39;from&#39; Address.
Definition: send.c:1333
unsigned char C_FccAttach
Config: Save send message with all their attachments.
Definition: send.c:106
WHERE bool C_CryptOpportunisticEncrypt
Config: Enable encryption when the recipient&#39;s key is available.
Definition: globals.h:268
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:137
A local copy of an email.
Definition: mx.h:83
static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out)
Write out a forwarded message.
Definition: send.c:471
bool C_ReverseName
Config: Set the &#39;From&#39; from the address the email was sent to.
Definition: send.c:129
A mailbox.
Definition: mailbox.h:81
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:37
void mutt_encode_descriptions(struct Body *b, bool recurse)
rfc2047 encode the content-descriptions
Definition: send.c:1447
void mutt_select_fcc(struct Buffer *path, struct Email *e)
Select the FCC path for an email.
Definition: hook.c:694
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:58
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:135
Type: &#39;text/*&#39;.
Definition: mime.h:38
static int generate_body(FILE *fp_tmp, struct Email *e, SendFlags flags, struct Mailbox *m, struct EmailList *el)
Create a new email body.
Definition: send.c:1101
int mutt_write_mime_body(struct Body *a, FILE *fp)
Write a MIME part.
Definition: sendlib.c:553
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:41
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1762
char * data
Pointer to data.
Definition: buffer.h:35
static int include_reply(struct Mailbox *m, struct Email *e, FILE *fp_out)
Generate the reply text for an email.
Definition: send.c:685
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:861
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:53
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition: crypt.c:171
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:776
WHERE struct Regex * C_QuoteRegex
Config: Regex to match quoted text in a reply.
Definition: globals.h:175
RFC3676 Format Flowed routines.
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition: address.c:1443
API for encryption/signing of emails.
bool C_ReverseRealname
Config: Set the &#39;From&#39; from the full &#39;To&#39; address the email was sent to.
Definition: send.c:130
Ignore case when comparing strings.
Definition: string2.h:68
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:802
#define SEND_NEWS
Reply to a news article.
Definition: send.h:102
Handling of email attachments.
bool C_FccClear
Config: Save sent messages unencrypted and unsigned.
Definition: send.c:108
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:46
int mix_send_message(struct ListHead *chain, const char *tempfile)
Send an email via Mixmaster.
Definition: remailer.c:906
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
bool mutt_addrlist_search(const struct AddressList *haystack, const struct Address *needle)
Search for an e-mail address in a list.
Definition: address.c:878
static void set_reverse_name(struct AddressList *al, struct Envelope *env)
Try to set the &#39;from&#39; field from the recipients.
Definition: send.c:1284
void mutt_update_num_postponed(void)
Force the update of the number of postponed messages.
Definition: postpone.c:199
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
bool C_PgpReplyinline
Config: Reply using old-style inline PGP messages (not recommended)
Definition: send.c:121
#define SEND_REPLY
Reply to sender.
Definition: send.h:88
NNTP-specific Mailbox data -.
Definition: lib.h:140
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:455
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:133
bool C_SigOnTop
Config: Insert the signature before the quoted text.
Definition: send.c:133
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2531
bool C_AskFollowUp
Config: (nntp) Ask the user for follow-up groups before editing.
Definition: send.c:94
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:98
static const struct AddressList * choose_default_to(const struct Address *from, const struct Envelope *env)
Pick the best &#39;to:&#39; value.
Definition: send.c:724
void mutt_forward_trailer(struct Mailbox *m, struct Email *e, FILE *fp)
Add a "end of forwarded message" text.
Definition: send.c:449
unsigned char C_ForwardEdit
Config: Automatically start the editor when forwarding a message.
Definition: send.c:112
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:612
unsigned int type
content-type primary type
Definition: body.h:65
char * list_post
This stores a mailto URL, or nothing.
Definition: envelope.h:65
bool C_CryptReplyencrypt
Config: Encrypt replies to encrypted messages.
Definition: send.c:101
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define SEC_SIGN
Email is signed.
Definition: lib.h:126
int mutt_addrlist_count_recips(const struct AddressList *al)
Count the number of Addresses with valid recipients.
Definition: address.c:841
bool crypt_has_module_backend(SecurityFlags type)
Is there a crypto backend for a given type?
Definition: cryptglue.c:172
char * personal
Real name of address.
Definition: address.h:36
int mutt_num_postponed(struct Mailbox *m, bool force)
Return the number of postponed messages.
Definition: postpone.c:86
WHERE bool C_TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: globals.h:254
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:455
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope&#39;s Address fields to local format.
Definition: envelope.c:271
void mutt_edit_headers(const char *editor, const char *body, struct Email *e, struct Buffer *fcc)
Let the user edit the message header and body.
Definition: mutt_header.c:168
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1036
WHERE bool C_ResumeDraftFiles
Config: Process draft files like postponed messages.
Definition: globals.h:244
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition: cryptglue.c:308
Send email to an SMTP server.
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:89
GUI basic built-in text editor.
char * data
String.
Definition: list.h:35
char * subject
Email&#39;s subject.
Definition: envelope.h:66
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Duplicate the structure of an entire email.
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:327
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1247
Routines for managing attachments.
Log at debug level 1.
Definition: logging.h:40
bool group
Group mailbox?
Definition: address.h:38
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
#define MUTT_SEND2_HOOK
send2-hook: when changing fields in the compose menu
Definition: hook.h:56
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:123
bool C_Metoo
Config: Remove the user&#39;s address from the list of recipients.
Definition: send.c:119
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
WHERE bool C_XCommentTo
Config: (nntp) Add &#39;X-Comment-To&#39; header that contains article author.
Definition: globals.h:283
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
Ask the user, defaulting to &#39;No&#39;.
Definition: quad.h:41
static void add_mailing_lists(struct AddressList *out, const struct AddressList *t, const struct AddressList *c)
Search Address lists for mailing lists.
Definition: send.c:181
struct Body * content
Attachment.
Definition: attach.h:36
struct Email * email
Email in the list.
Definition: email.h:116
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
Cached regular expression.
Definition: regex3.h:88
#define mutt_error(...)
Definition: logging.h:84
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:409
int mutt_builtin_editor(const char *path, struct Email *e_new, struct Email *e_cur)
Show the user the built-in editor.
Definition: edit.c:401
bool mutt_addr_valid_msgid(const char *msgid)
Is this a valid Message ID?
Definition: address.c:761
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
bool replied
Email has been replied to.
Definition: email.h:54
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition: rfc3676.c:463
static int edit_envelope(struct Envelope *en, SendFlags flags)
Edit Envelope fields.
Definition: send.c:242
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:654
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:609
WHERE char * C_Editor
Config: External command to use as an email editor.
Definition: globals.h:111
bool C_UseFrom
Config: Set the &#39;From&#39; header for outgoing mail.
Definition: send.c:134
FILE * fp
pointer to the message data
Definition: mx.h:85
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file&#39;s modification time by 1 second.
Definition: file.c:964
#define MUTT_REPLY_HOOK
reply-hook: when replying to an email
Definition: hook.h:55
WHERE bool C_ForwardQuote
Config: Automatically quote a forwarded message using C_IndentString.
Definition: globals.h:215
void mutt_make_forward_subject(struct Envelope *env, struct Mailbox *m, struct Email *e)
Create a subject for a forwarded email.
Definition: send.c:938
int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *e)
Matches subscribed mailing lists.
Definition: pattern.c:1813
void mutt_addrlist_remove_xrefs(const struct AddressList *a, struct AddressList *b)
Remove cross-references.
Definition: address.c:1385
static int invoke_mta(struct Email *e)
Send an email.
Definition: send.c:1361
WHERE char * C_PgpDefaultKey
Config: Default key to use for PGP operations.
Definition: globals.h:160
#define FREE(x)
Definition: memory.h:40
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:686
#define MUTT_COMPOSE_NOFREEHEADER
Definition: compose.h:35
static int mutt_inline_forward(struct Mailbox *m, struct Email *e_edit, struct Email *e_cur, FILE *out)
Forward attachments, inline.
Definition: send.c:589
#define STAILQ_EMPTY(head)
Definition: queue.h:345
static int save_fcc(struct Email *e, struct Buffer *fcc, struct Body *clear_content, char *pgpkeylist, SendFlags flags, char **finalpath)
Save an Email to a &#39;sent mail&#39; folder.
Definition: send.c:1609
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit)
Send a message using SMTP.
Definition: smtp.c:763
List of Emails.
Definition: email.h:114
struct Email * email_new(void)
Create a new Email.
Definition: email.c:68
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
WHERE char * C_Realname
Config: Real name of the user.
Definition: globals.h:139
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: pager.c:937
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Miscellaneous functions for sending an email.
bool C_ForwardReferences
Config: Set the &#39;In-Reply-To&#39; and &#39;References&#39; headers when forwarding a message. ...
Definition: send.c:114
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:576
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define TAILQ_EMPTY(head)
Definition: queue.h:714
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1220
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:101
#define MUTT_CM_NOHEADER
Don&#39;t copy the message header.
Definition: copy.h:35
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:47
WHERE char * C_Postponed
Config: Folder to store postponed messages.
Definition: globals.h:135
WHERE char * C_Attribution
Config: Message to start a reply, "On DATE, PERSON wrote:".
Definition: globals.h:99
Log at debug level 5.
Definition: logging.h:44
WHERE char * C_PgpSignAs
Config: Use this alternative key for signing messages.
Definition: globals.h:161
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition: send.c:162
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
WHERE char * C_SmimeSignAs
Config: Use this alternative key for signing messages.
Definition: globals.h:165
static void append_signature(FILE *fp)
Append a signature to an email.
Definition: send.c:140
A List node for strings.
Definition: list.h:33
#define TAILQ_SWAP(head1, head2, type, field)
Definition: queue.h:852
Match patterns to emails.
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:1393
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Decide how to display email content.
char * C_ContentType
Config: Default "Content-Type" for newly composed messages.
Definition: send.c:96
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
char * C_EmptySubject
Config: Subject to use when replying to an email with none.
Definition: send.c:104
int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur)
Resend an email.
Definition: send.c:1504
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
struct AddressList x_original_to
Email&#39;s &#39;X-Orig-to&#39;.
Definition: envelope.h:64
#define STAILQ_FIRST(head)
Definition: queue.h:347
int mutt_is_list_recipient(bool all_addr, struct Envelope *e)
Matches known mailing lists.
Definition: pattern.c:1825
A set of attachments.
Definition: attach.h:49
WHERE bool C_Askbcc
Config: Ask the user for the blind-carbon-copy recipients.
Definition: globals.h:197
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:353
char * mutt_extract_message_id(const char *s, const char **saveptr)
Find a message-id.
Definition: parse.c:358
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1144
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:641
#define mutt_buffer_enter_fname(prompt, fname, mailbox)
Definition: curs_lib.h:87
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1123
int mutt_get_postponed(struct Context *ctx, struct Email *hdr, struct Email **cur, struct Buffer *fcc)
Recall a postponed message.
Definition: postpone.c:331
Type: &#39;application/*&#39;.
Definition: mime.h:33
int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new, struct Email *e, bool resend)
Prepare a message template.
Definition: postpone.c:655
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
int mutt_edit_address(struct AddressList *al, const char *field, bool expand_aliases)
Edit an email address.
Definition: send.c:208
int mutt_compose_menu(struct Email *e, struct Buffer *fcc, struct Email *e_cur, int flags)
Allow the user to edit the message envelope.
Definition: compose.c:1317
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
Support of Mixmaster anonymous remailer.
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:82
char * C_Signature
Config: File containing a signature to append to all mail.
Definition: send.c:132
WHERE bool C_Askcc
Config: Ask the user for the carbon-copy recipients.
Definition: globals.h:198
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:93
The header of an Email.
Definition: envelope.h:54
void mutt_make_attribution(struct Mailbox *m, struct Email *e, FILE *fp_out)
Add "on DATE, PERSON wrote" header.
Definition: send.c:647
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:40
bool C_CryptReplysignencrypted
Config: Sign replies to encrypted messages.
Definition: send.c:103
bool C_NmRecord
Config: (notmuch) If the &#39;record&#39; mailbox (sent mail) should be indexed.
Definition: send.c:120
int msgno
Number displayed to the user.
Definition: email.h:86
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1432
void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *curenv)
Generate references for a reply email.
Definition: send.c:977
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
bool C_CryptAutopgp
Config: Allow automatic PGP functions.
Definition: send.c:98
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:157
WHERE unsigned char C_ForwardAttachments
Config: Forward attachments when forwarding a message.
Definition: globals.h:182
char * C_PostIndentString
Config: Suffix message to add after reply text.
Definition: send.c:122
bool C_CryptAutoencrypt
Config: Automatically PGP encrypt all outgoing mail.
Definition: send.c:97
bool C_ReplyWithXorig
Config: Create &#39;From&#39; header from &#39;X-Original-To&#39; header.
Definition: send.c:128