NeoMutt  2021-02-05
Teaching an old dog new tricks
DOXYGEN
recvcmd.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include "mutt/lib.h"
35 #include "address/lib.h"
36 #include "config/lib.h"
37 #include "email/lib.h"
38 #include "core/lib.h"
39 #include "alias/lib.h"
40 #include "gui/lib.h"
41 #include "mutt.h"
42 #include "recvcmd.h"
43 #include "send/lib.h"
44 #include "context.h"
45 #include "copy.h"
46 #include "handler.h"
47 #include "hdrline.h"
48 #include "init.h"
49 #include "mutt_body.h"
50 #include "mutt_globals.h"
51 #include "mutt_logging.h"
52 #include "muttlib.h"
53 #include "options.h"
54 #include "protos.h"
55 #include "state.h"
56 #ifdef ENABLE_NLS
57 #include <libintl.h>
58 #endif
59 
60 struct Mailbox;
61 
62 /* These Config Variables are only used in recvcmd.c */
63 unsigned char C_MimeForwardRest;
64 
74 static bool check_msg(struct Body *b, bool err)
75 {
76  if (!mutt_is_message_type(b->type, b->subtype))
77  {
78  if (err)
79  mutt_error(_("You may only bounce message/rfc822 parts"));
80  return false;
81  }
82  return true;
83 }
84 
92 static bool check_all_msg(struct AttachCtx *actx, struct Body *cur, bool err)
93 {
94  if (cur && !check_msg(cur, err))
95  return false;
96  if (!cur)
97  {
98  for (short i = 0; i < actx->idxlen; i++)
99  {
100  if (actx->idx[i]->body->tagged)
101  {
102  if (!check_msg(actx->idx[i]->body, err))
103  return false;
104  }
105  }
106  }
107  return true;
108 }
109 
116 static bool check_can_decode(struct AttachCtx *actx, struct Body *cur)
117 {
118  if (cur)
119  return mutt_can_decode(cur);
120 
121  for (short i = 0; i < actx->idxlen; i++)
122  if (actx->idx[i]->body->tagged && !mutt_can_decode(actx->idx[i]->body))
123  return false;
124 
125  return true;
126 }
127 
133 static short count_tagged(struct AttachCtx *actx)
134 {
135  short count = 0;
136  for (short i = 0; i < actx->idxlen; i++)
137  if (actx->idx[i]->body->tagged)
138  count++;
139 
140  return count;
141 }
142 
149 static short count_tagged_children(struct AttachCtx *actx, short i)
150 {
151  short level = actx->idx[i]->level;
152  short count = 0;
153 
154  while ((++i < actx->idxlen) && (level < actx->idx[i]->level))
155  if (actx->idx[i]->body->tagged)
156  count++;
157 
158  return count;
159 }
160 
168 void mutt_attach_bounce(struct Mailbox *m, FILE *fp, struct AttachCtx *actx, struct Body *cur)
169 {
170  if (!m || !fp || !actx)
171  return;
172 
173  char prompt[256];
174  char buf[8192];
175  char *err = NULL;
176  int ret = 0;
177  int p = 0;
178 
179  if (!check_all_msg(actx, cur, true))
180  return;
181 
182  /* one or more messages? */
183  p = cur ? 1 : count_tagged(actx);
184 
185  /* RFC5322 mandates a From: header, so warn before bouncing
186  * messages without one */
187  if (cur)
188  {
189  if (TAILQ_EMPTY(&cur->email->env->from))
190  {
191  mutt_error(_("Warning: message contains no From: header"));
193  }
194  }
195  else
196  {
197  for (short i = 0; i < actx->idxlen; i++)
198  {
199  if (actx->idx[i]->body->tagged)
200  {
201  if (TAILQ_EMPTY(&actx->idx[i]->body->email->env->from))
202  {
203  mutt_error(_("Warning: message contains no From: header"));
205  break;
206  }
207  }
208  }
209  }
210 
211  if (p)
212  mutt_str_copy(prompt, _("Bounce message to: "), sizeof(prompt));
213  else
214  mutt_str_copy(prompt, _("Bounce tagged messages to: "), sizeof(prompt));
215 
216  buf[0] = '\0';
217  if (mutt_get_field(prompt, buf, sizeof(buf), MUTT_ALIAS) || (buf[0] == '\0'))
218  return;
219 
220  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
221  mutt_addrlist_parse(&al, buf);
222  if (TAILQ_EMPTY(&al))
223  {
224  mutt_error(_("Error parsing address"));
225  return;
226  }
227 
228  mutt_expand_aliases(&al);
229 
230  if (mutt_addrlist_to_intl(&al, &err) < 0)
231  {
232  mutt_error(_("Bad IDN: '%s'"), err);
233  FREE(&err);
234  goto end;
235  }
236 
237  buf[0] = '\0';
238  mutt_addrlist_write(&al, buf, sizeof(buf), true);
239 
240 #define EXTRA_SPACE (15 + 7 + 2)
241  /* See commands.c. */
242  snprintf(prompt, sizeof(prompt) - 4,
243  ngettext("Bounce message to %s?", "Bounce messages to %s?", p), buf);
244 
246  {
247  mutt_simple_format(prompt, sizeof(prompt) - 4, 0, MessageWindow->state.cols - EXTRA_SPACE,
248  JUSTIFY_LEFT, 0, prompt, sizeof(prompt), false);
249  mutt_str_cat(prompt, sizeof(prompt), "...?");
250  }
251  else
252  mutt_str_cat(prompt, sizeof(prompt), "?");
253 
254  if (query_quadoption(C_Bounce, prompt) != MUTT_YES)
255  {
257  mutt_message(ngettext("Message not bounced", "Messages not bounced", p));
258  goto end;
259  }
260 
262 
263  if (cur)
264  ret = mutt_bounce_message(fp, cur->email, &al, NeoMutt->sub);
265  else
266  {
267  for (short i = 0; i < actx->idxlen; i++)
268  {
269  if (actx->idx[i]->body->tagged)
270  {
271  if (mutt_bounce_message(actx->idx[i]->fp, actx->idx[i]->body->email,
272  &al, NeoMutt->sub))
273  {
274  ret = 1;
275  }
276  }
277  }
278  }
279 
280  if (ret == 0)
281  mutt_message(ngettext("Message bounced", "Messages bounced", p));
282  else
283  mutt_error(ngettext("Error bouncing message", "Error bouncing messages", p));
284 
285 end:
286  mutt_addrlist_clear(&al);
287 }
288 
295 void mutt_attach_resend(FILE *fp, struct AttachCtx *actx, struct Body *cur)
296 {
297  if (!check_all_msg(actx, cur, true))
298  return;
299 
300  if (cur)
302  else
303  {
304  for (short i = 0; i < actx->idxlen; i++)
305  {
306  if (actx->idx[i]->body->tagged)
307  {
308  mutt_resend_message(actx->idx[i]->fp, Context,
309  actx->idx[i]->body->email, NeoMutt->sub);
310  }
311  }
312  }
313 }
314 
322 static struct AttachPtr *find_common_parent(struct AttachCtx *actx, short nattach)
323 {
324  short i;
325  short nchildren;
326 
327  for (i = 0; i < actx->idxlen; i++)
328  if (actx->idx[i]->body->tagged)
329  break;
330 
331  while (--i >= 0)
332  {
333  if (mutt_is_message_type(actx->idx[i]->body->type, actx->idx[i]->body->subtype))
334  {
335  nchildren = count_tagged_children(actx, i);
336  if (nchildren == nattach)
337  return actx->idx[i];
338  }
339  }
340 
341  return NULL;
342 }
343 
356 static int is_parent(short i, struct AttachCtx *actx, struct Body *cur)
357 {
358  short level = actx->idx[i]->level;
359 
360  while ((++i < actx->idxlen) && (actx->idx[i]->level > level))
361  {
362  if (actx->idx[i]->body == cur)
363  return true;
364  }
365 
366  return false;
367 }
368 
377 static struct AttachPtr *find_parent(struct AttachCtx *actx, struct Body *cur, short nattach)
378 {
379  struct AttachPtr *parent = NULL;
380 
381  if (cur)
382  {
383  for (short i = 0; i < actx->idxlen; i++)
384  {
385  if (mutt_is_message_type(actx->idx[i]->body->type, actx->idx[i]->body->subtype) &&
386  is_parent(i, actx, cur))
387  {
388  parent = actx->idx[i];
389  }
390  if (actx->idx[i]->body == cur)
391  break;
392  }
393  }
394  else if (nattach)
395  parent = find_common_parent(actx, nattach);
396 
397  return parent;
398 }
399 
408 static void include_header(bool quote, FILE *fp_in, struct Email *e, FILE *fp_out, char *prefix)
409 {
410  CopyHeaderFlags chflags = CH_DECODE;
411  char prefix2[128];
412 
413  if (C_Weed)
414  chflags |= CH_WEED | CH_REORDER;
415 
416  if (quote)
417  {
418  if (prefix)
419  mutt_str_copy(prefix2, prefix, sizeof(prefix2));
420  else if (!C_TextFlowed)
421  {
422  mutt_make_string(prefix2, sizeof(prefix2), 0, NONULL(C_IndentString),
424  }
425  else
426  mutt_str_copy(prefix2, ">", sizeof(prefix2));
427 
428  chflags |= CH_PREFIX;
429  }
430 
431  mutt_copy_header(fp_in, e, fp_out, chflags, quote ? prefix2 : NULL, 0);
432 }
433 
443 static struct Body **copy_problematic_attachments(struct Body **last,
444  struct AttachCtx *actx, bool force)
445 {
446  for (short i = 0; i < actx->idxlen; i++)
447  {
448  if (actx->idx[i]->body->tagged && (force || !mutt_can_decode(actx->idx[i]->body)))
449  {
450  if (mutt_body_copy(actx->idx[i]->fp, last, actx->idx[i]->body) == -1)
451  return NULL; /* XXXXX - may lead to crashes */
452  last = &((*last)->next);
453  }
454  }
455  return last;
456 }
457 
468 static void attach_forward_bodies(FILE *fp, struct Email *e, struct AttachCtx *actx,
469  struct Body *cur, short nattach)
470 {
471  bool mime_fwd_all = false;
472  bool mime_fwd_any = true;
473  struct Email *e_parent = NULL;
474  FILE *fp_parent = NULL;
475  char prefix[256];
476  enum QuadOption ans = MUTT_NO;
477  struct Buffer *tmpbody = NULL;
478 
479  /* First, find the parent message.
480  * Note: This could be made an option by just
481  * putting the following lines into an if block. */
482  struct AttachPtr *parent = find_parent(actx, cur, nattach);
483  if (parent)
484  {
485  e_parent = parent->body->email;
486  fp_parent = parent->fp;
487  }
488  else
489  {
490  e_parent = e;
491  fp_parent = actx->fp_root;
492  }
493 
494  struct Email *e_tmp = email_new();
495  e_tmp->env = mutt_env_new();
496  mutt_make_forward_subject(e_tmp->env, Context->mailbox, e_parent, NeoMutt->sub);
497 
498  tmpbody = mutt_buffer_pool_get();
499  mutt_buffer_mktemp(tmpbody);
500  FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tmpbody), "w");
501  if (!fp_tmp)
502  {
503  mutt_error(_("Can't open temporary file %s"), mutt_buffer_string(tmpbody));
504  email_free(&e_tmp);
505  goto bail;
506  }
507 
508  mutt_forward_intro(Context->mailbox, e_parent, fp_tmp, NeoMutt->sub);
509 
510  /* prepare the prefix here since we'll need it later. */
511 
512  if (C_ForwardQuote)
513  {
514  if (C_TextFlowed)
515  mutt_str_copy(prefix, ">", sizeof(prefix));
516  else
517  {
518  mutt_make_string(prefix, sizeof(prefix), 0, NONULL(C_IndentString),
519  Context->mailbox, Context->msg_in_pager, e_parent);
520  }
521  }
522 
523  include_header(C_ForwardQuote, fp_parent, e_parent, fp_tmp, prefix);
524 
525  /* Now, we have prepared the first part of the message body: The
526  * original message's header.
527  *
528  * The next part is more interesting: either include the message bodies,
529  * or attach them. */
530  if ((!cur || mutt_can_decode(cur)) &&
531  ((ans = query_quadoption(C_MimeForward, _("Forward as attachments?"))) == MUTT_YES))
532  {
533  mime_fwd_all = true;
534  }
535  else if (ans == MUTT_ABORT)
536  {
537  goto bail;
538  }
539 
540  /* shortcut MIMEFWDREST when there is only one attachment.
541  * Is this intuitive? */
542  if (!mime_fwd_all && !cur && (nattach > 1) && !check_can_decode(actx, cur))
543  {
544  ans = query_quadoption(
546  _("Can't decode all tagged attachments. MIME-forward the others?"));
547  if (ans == MUTT_ABORT)
548  goto bail;
549  else if (ans == MUTT_NO)
550  mime_fwd_any = false;
551  }
552 
553  /* initialize a state structure */
554 
555  struct State st = { 0 };
556  if (C_ForwardQuote)
557  st.prefix = prefix;
558  st.flags = MUTT_CHARCONV;
559  if (C_Weed)
560  st.flags |= MUTT_WEED;
561  st.fp_out = fp_tmp;
562 
563  /* where do we append new MIME parts? */
564  struct Body **last = &e_tmp->body;
565 
566  if (cur)
567  {
568  /* single body case */
569 
570  if (!mime_fwd_all && mutt_can_decode(cur))
571  {
572  st.fp_in = fp;
573  mutt_body_handler(cur, &st);
574  state_putc(&st, '\n');
575  }
576  else
577  {
578  if (mutt_body_copy(fp, last, cur) == -1)
579  goto bail;
580  }
581  }
582  else
583  {
584  /* multiple body case */
585 
586  if (!mime_fwd_all)
587  {
588  for (int i = 0; i < actx->idxlen; i++)
589  {
590  if (actx->idx[i]->body->tagged && mutt_can_decode(actx->idx[i]->body))
591  {
592  st.fp_in = actx->idx[i]->fp;
593  mutt_body_handler(actx->idx[i]->body, &st);
594  state_putc(&st, '\n');
595  }
596  }
597  }
598 
599  if (mime_fwd_any && !copy_problematic_attachments(last, actx, mime_fwd_all))
600  goto bail;
601  }
602 
603  mutt_forward_trailer(Context->mailbox, e_parent, fp_tmp, NeoMutt->sub);
604 
605  mutt_file_fclose(&fp_tmp);
606  fp_tmp = NULL;
607 
608  /* now that we have the template, send it. */
609  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
610  emaillist_add_email(&el, e_parent);
611  mutt_send_message(SEND_NO_FLAGS, e_tmp, mutt_buffer_string(tmpbody), NULL,
612  &el, NeoMutt->sub);
613  emaillist_clear(&el);
614  mutt_buffer_pool_release(&tmpbody);
615  return;
616 
617 bail:
618  if (fp_tmp)
619  {
620  mutt_file_fclose(&fp_tmp);
622  }
623  mutt_buffer_pool_release(&tmpbody);
624 
625  email_free(&e_tmp);
626 }
627 
642 static void attach_forward_msgs(FILE *fp, struct AttachCtx *actx,
643  struct Body *cur, SendFlags flags)
644 {
645  struct Email *e_cur = NULL;
646  struct Email *e_tmp = NULL;
647  enum QuadOption ans;
648  struct Body **last = NULL;
649  struct Buffer *tmpbody = NULL;
650  FILE *fp_tmp = NULL;
651 
652  CopyHeaderFlags chflags = CH_XMIT;
653 
654  if (cur)
655  e_cur = cur->email;
656  else
657  {
658  for (short i = 0; i < actx->idxlen; i++)
659  {
660  if (actx->idx[i]->body->tagged)
661  {
662  e_cur = actx->idx[i]->body->email;
663  break;
664  }
665  }
666  }
667 
668  e_tmp = email_new();
669  e_tmp->env = mutt_env_new();
671 
672  tmpbody = mutt_buffer_pool_get();
673 
674  ans = query_quadoption(C_MimeForward, _("Forward MIME encapsulated?"));
675  if (ans == MUTT_NO)
676  {
677  /* no MIME encapsulation */
678 
679  mutt_buffer_mktemp(tmpbody);
680  fp_tmp = mutt_file_fopen(mutt_buffer_string(tmpbody), "w");
681  if (!fp_tmp)
682  {
683  mutt_error(_("Can't create %s"), mutt_buffer_string(tmpbody));
684  goto cleanup;
685  }
686 
688  if (C_ForwardQuote)
689  {
690  chflags |= CH_PREFIX;
691  cmflags |= MUTT_CM_PREFIX;
692  }
693 
694  if (C_ForwardDecode)
695  {
696  cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
697  if (C_Weed)
698  {
699  chflags |= CH_WEED | CH_REORDER;
700  cmflags |= MUTT_CM_WEED;
701  }
702  }
703 
704  if (cur)
705  {
707  mutt_copy_message_fp(fp_tmp, fp, cur->email, cmflags, chflags, 0);
709  }
710  else
711  {
712  for (short i = 0; i < actx->idxlen; i++)
713  {
714  if (actx->idx[i]->body->tagged)
715  {
717  fp_tmp, NeoMutt->sub);
718  mutt_copy_message_fp(fp_tmp, actx->idx[i]->fp,
719  actx->idx[i]->body->email, cmflags, chflags, 0);
721  fp_tmp, NeoMutt->sub);
722  }
723  }
724  }
725  mutt_file_fclose(&fp_tmp);
726  }
727  else if (ans == MUTT_YES) /* do MIME encapsulation - we don't need to do much here */
728  {
729  last = &e_tmp->body;
730  if (cur)
731  mutt_body_copy(fp, last, cur);
732  else
733  {
734  for (short i = 0; i < actx->idxlen; i++)
735  {
736  if (actx->idx[i]->body->tagged)
737  {
738  mutt_body_copy(actx->idx[i]->fp, last, actx->idx[i]->body);
739  last = &((*last)->next);
740  }
741  }
742  }
743  }
744  else
745  email_free(&e_tmp);
746 
747  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
748  emaillist_add_email(&el, e_cur);
749  mutt_send_message(flags, e_tmp,
750  mutt_buffer_is_empty(tmpbody) ? NULL : mutt_buffer_string(tmpbody),
751  NULL, &el, NeoMutt->sub);
752  emaillist_clear(&el);
753  e_tmp = NULL; /* mutt_send_message frees this */
754 
755 cleanup:
756  email_free(&e_tmp);
757  mutt_buffer_pool_release(&tmpbody);
758 }
759 
768 void mutt_attach_forward(FILE *fp, struct Email *e, struct AttachCtx *actx,
769  struct Body *cur, SendFlags flags)
770 {
771  if (check_all_msg(actx, cur, false))
772  attach_forward_msgs(fp, actx, cur, flags);
773  else
774  {
775  const short nattach = count_tagged(actx);
776  attach_forward_bodies(fp, e, actx, cur, nattach);
777  }
778 }
779 
799 static int attach_reply_envelope_defaults(struct Envelope *env, struct AttachCtx *actx,
800  struct Email *parent, SendFlags flags)
801 {
802  struct Envelope *curenv = NULL;
803  struct Email *e = NULL;
804 
805  if (!parent)
806  {
807  for (short i = 0; i < actx->idxlen; i++)
808  {
809  if (actx->idx[i]->body->tagged)
810  {
811  e = actx->idx[i]->body->email;
812  curenv = e->env;
813  break;
814  }
815  }
816  }
817  else
818  {
819  curenv = parent->env;
820  e = parent;
821  }
822 
823  if (!curenv || !e)
824  {
825  mutt_error(_("Can't find any tagged messages"));
826  return -1;
827  }
828 
829 #ifdef USE_NNTP
830  if ((flags & SEND_NEWS))
831  {
832  /* in case followup set Newsgroups: with Followup-To: if it present */
833  if (!env->newsgroups && curenv && !mutt_istr_equal(curenv->followup_to, "poster"))
834  {
835  env->newsgroups = mutt_str_dup(curenv->followup_to);
836  }
837  }
838  else
839 #endif
840  {
841  if (parent)
842  {
843  if (mutt_fetch_recips(env, curenv, flags, NeoMutt->sub) == -1)
844  return -1;
845  }
846  else
847  {
848  for (short i = 0; i < actx->idxlen; i++)
849  {
850  if (actx->idx[i]->body->tagged &&
851  (mutt_fetch_recips(env, actx->idx[i]->body->email->env, flags,
852  NeoMutt->sub) == -1))
853  {
854  return -1;
855  }
856  }
857  }
858 
859  if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
860  {
861  mutt_error(_("No mailing lists found"));
862  return -1;
863  }
864 
866  }
868 
869  if (parent)
871  else
872  {
873  for (short i = 0; i < actx->idxlen; i++)
874  {
875  if (actx->idx[i]->body->tagged)
876  {
878  NeoMutt->sub);
879  }
880  }
881  }
882 
883  return 0;
884 }
885 
892 static void attach_include_reply(FILE *fp, FILE *fp_tmp, struct Email *e)
893 {
895  CopyHeaderFlags chflags = CH_DECODE;
896 
898 
899  if (!C_Header)
900  cmflags |= MUTT_CM_NOHEADER;
901  if (C_Weed)
902  {
903  chflags |= CH_WEED;
904  cmflags |= MUTT_CM_WEED;
905  }
906 
907  mutt_copy_message_fp(fp_tmp, fp, e, cmflags, chflags, 0);
909 }
910 
919 void mutt_attach_reply(FILE *fp, struct Email *e, struct AttachCtx *actx,
920  struct Body *e_cur, SendFlags flags)
921 {
922  bool mime_reply_any = false;
923 
924  short nattach = 0;
925  struct AttachPtr *parent = NULL;
926  struct Email *e_parent = NULL;
927  FILE *fp_parent = NULL;
928  struct Email *e_tmp = NULL;
929  FILE *fp_tmp = NULL;
930  struct Buffer *tmpbody = NULL;
931  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
932 
933  char prefix[128];
934 
935 #ifdef USE_NNTP
936  if (flags & SEND_NEWS)
937  OptNewsSend = true;
938  else
939  OptNewsSend = false;
940 #endif
941 
942  if (!check_all_msg(actx, e_cur, false))
943  {
944  nattach = count_tagged(actx);
945  parent = find_parent(actx, e_cur, nattach);
946  if (parent)
947  {
948  e_parent = parent->body->email;
949  fp_parent = parent->fp;
950  }
951  else
952  {
953  e_parent = e;
954  fp_parent = actx->fp_root;
955  }
956  }
957 
958  if ((nattach > 1) && !check_can_decode(actx, e_cur))
959  {
960  const enum QuadOption ans = query_quadoption(
961  C_MimeForwardRest, _("Can't decode all tagged attachments. "
962  "MIME-encapsulate the others?"));
963  if (ans == MUTT_ABORT)
964  return;
965  if (ans == MUTT_YES)
966  mime_reply_any = true;
967  }
968  else if (nattach == 1)
969  mime_reply_any = true;
970 
971  e_tmp = email_new();
972  e_tmp->env = mutt_env_new();
973 
975  e_tmp->env, actx, e_parent ? e_parent : (e_cur ? e_cur->email : NULL), flags) == -1)
976  {
977  goto cleanup;
978  }
979 
980  tmpbody = mutt_buffer_pool_get();
981  mutt_buffer_mktemp(tmpbody);
982  fp_tmp = mutt_file_fopen(mutt_buffer_string(tmpbody), "w");
983  if (!fp_tmp)
984  {
985  mutt_error(_("Can't create %s"), mutt_buffer_string(tmpbody));
986  goto cleanup;
987  }
988 
989  if (!e_parent)
990  {
991  if (e_cur)
992  attach_include_reply(fp, fp_tmp, e_cur->email);
993  else
994  {
995  for (short i = 0; i < actx->idxlen; i++)
996  {
997  if (actx->idx[i]->body->tagged)
998  attach_include_reply(actx->idx[i]->fp, fp_tmp, actx->idx[i]->body->email);
999  }
1000  }
1001  }
1002  else
1003  {
1004  mutt_make_attribution(Context->mailbox, e_parent, fp_tmp, NeoMutt->sub);
1005 
1006  struct State st;
1007  memset(&st, 0, sizeof(struct State));
1008  st.fp_out = fp_tmp;
1009 
1010  if (C_TextFlowed)
1011  {
1012  mutt_str_copy(prefix, ">", sizeof(prefix));
1013  }
1014  else
1015  {
1016  mutt_make_string(prefix, sizeof(prefix), 0, NONULL(C_IndentString),
1017  Context->mailbox, Context->msg_in_pager, e_parent);
1018  }
1019 
1020  st.prefix = prefix;
1021  st.flags = MUTT_CHARCONV;
1022 
1023  if (C_Weed)
1024  st.flags |= MUTT_WEED;
1025 
1026  if (C_Header)
1027  include_header(true, fp_parent, e_parent, fp_tmp, prefix);
1028 
1029  if (e_cur)
1030  {
1031  if (mutt_can_decode(e_cur))
1032  {
1033  st.fp_in = fp;
1034  mutt_body_handler(e_cur, &st);
1035  state_putc(&st, '\n');
1036  }
1037  else
1038  mutt_body_copy(fp, &e_tmp->body, e_cur);
1039  }
1040  else
1041  {
1042  for (short i = 0; i < actx->idxlen; i++)
1043  {
1044  if (actx->idx[i]->body->tagged && mutt_can_decode(actx->idx[i]->body))
1045  {
1046  st.fp_in = actx->idx[i]->fp;
1047  mutt_body_handler(actx->idx[i]->body, &st);
1048  state_putc(&st, '\n');
1049  }
1050  }
1051  }
1052 
1053  mutt_make_post_indent(Context->mailbox, e_parent, fp_tmp, NeoMutt->sub);
1054 
1055  if (mime_reply_any && !e_cur && !copy_problematic_attachments(&e_tmp->body, actx, false))
1056  {
1057  goto cleanup;
1058  }
1059  }
1060 
1061  mutt_file_fclose(&fp_tmp);
1062 
1063  emaillist_add_email(&el, e_parent ? e_parent : (e_cur ? e_cur->email : NULL));
1064  if (mutt_send_message(flags, e_tmp, mutt_buffer_string(tmpbody), NULL, &el,
1065  NeoMutt->sub) == 0)
1066  {
1068  }
1069  e_tmp = NULL; /* mutt_send_message frees this */
1070 
1071 cleanup:
1072  if (fp_tmp)
1073  {
1074  mutt_file_fclose(&fp_tmp);
1076  }
1077  mutt_buffer_pool_release(&tmpbody);
1078  email_free(&e_tmp);
1079  emaillist_clear(&el);
1080 }
1081 
1089 void mutt_attach_mail_sender(FILE *fp, struct Email *e, struct AttachCtx *actx,
1090  struct Body *cur)
1091 {
1092  if (!check_all_msg(actx, cur, 0))
1093  {
1094  /* L10N: You will see this error message if you invoke <compose-to-sender>
1095  when you are on a normal attachment. */
1096  mutt_error(_("You may only compose to sender with message/rfc822 parts"));
1097  return;
1098  }
1099 
1100  struct Email *e_tmp = email_new();
1101  e_tmp->env = mutt_env_new();
1102 
1103  if (cur)
1104  {
1105  if (mutt_fetch_recips(e_tmp->env, cur->email->env, SEND_TO_SENDER, NeoMutt->sub) == -1)
1106  {
1107  email_free(&e_tmp);
1108  return;
1109  }
1110  }
1111  else
1112  {
1113  for (int i = 0; i < actx->idxlen; i++)
1114  {
1115  if (actx->idx[i]->body->tagged &&
1116  (mutt_fetch_recips(e_tmp->env, actx->idx[i]->body->email->env,
1117  SEND_TO_SENDER, NeoMutt->sub) == -1))
1118  {
1119  email_free(&e_tmp);
1120  return;
1121  }
1122  }
1123  }
1124 
1125  // This call will free e_tmp for us
1126  mutt_send_message(SEND_NO_FLAGS, e_tmp, NULL, NULL, NULL, NeoMutt->sub);
1127 }
void mutt_make_attribution(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add "on DATE, PERSON wrote" header.
Definition: send.c:585
Convenience wrapper for the gui headers.
int mutt_bounce_message(FILE *fp, struct Email *e, struct AddressList *to, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:1372
The "current" mailbox.
Definition: context.h:38
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
WHERE unsigned char C_MimeForward
Config: Forward a message as a &#39;message/RFC822&#39; MIME part.
Definition: mutt_globals.h:127
#define NONULL(x)
Definition: string2.h:37
An email to which things will be attached.
Definition: attach.h:34
static bool check_all_msg(struct AttachCtx *actx, struct Body *cur, bool err)
Are all the Attachments RFC822 messages?
Definition: recvcmd.c:92
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:67
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:294
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1366
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:52
int msg_in_pager
Message currently shown in the pager.
Definition: context.h:44
Left justify the text.
Definition: curs_lib.h:47
The envelope/body of an email.
Definition: email.h:37
static void include_header(bool quote, FILE *fp_in, struct Email *e, FILE *fp_out, char *prefix)
Write an email header to a file, optionally quoting it.
Definition: recvcmd.c:408
static bool check_can_decode(struct AttachCtx *actx, struct Body *cur)
Can we decode all tagged attachments?
Definition: recvcmd.c:116
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:43
#define MUTT_ALIAS
Do alias "completion" by calling up the alias-menu.
Definition: mutt.h:57
static void attach_include_reply(FILE *fp, FILE *fp_tmp, struct Email *e)
This is very similar to send.c&#39;s include_reply()
Definition: recvcmd.c:892
Config/command parsing.
struct Body * body
List of MIME parts.
Definition: email.h:91
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
Structs that make up an email.
String processing routines to generate the mail index.
The "currently-open" mailbox.
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
Convenience wrapper for the send headers.
#define mutt_message(...)
Definition: logging.h:83
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1468
static bool check_msg(struct Body *b, bool err)
Are we working with an RFC822 message.
Definition: recvcmd.c:74
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
WHERE bool C_Header
Config: Include the message headers in the reply email (Weed applies)
Definition: mutt_globals.h:149
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:52
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:40
String manipulation buffer.
Definition: buffer.h:33
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
short idxlen
Number of attachmentes.
Definition: attach.h:55
FILE * fp_out
File to write to.
Definition: state.h:47
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:130
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:31
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:37
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
Messages that have been replied to.
Definition: mutt.h:95
The body of an email.
Definition: body.h:34
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
Convenience wrapper for the config headers.
static void attach_forward_msgs(FILE *fp, struct AttachCtx *actx, struct Body *cur, SendFlags flags)
Forward one or several message-type attachments.
Definition: recvcmd.c:642
Email Address Handling.
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:40
Some miscellaneous functions.
void mutt_attach_reply(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *e_cur, SendFlags flags)
Attach a reply.
Definition: recvcmd.c:919
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
struct Mailbox * mailbox
Definition: context.h:50
Many unsorted constants and some structs.
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
WHERE bool C_ForwardQuote
Config: Automatically quote a forwarded message using $indent_string
Definition: mutt_globals.h:148
#define CH_WEED
Weed the headers?
Definition: copy.h:52
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:232
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:90
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
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
bool tagged
This attachment is tagged.
Definition: body.h:70
Email Aliases.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
User aborted the question (with Ctrl-G)
Definition: quad.h:38
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * subtype
content-type subtype
Definition: body.h:37
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
static int is_parent(short i, struct AttachCtx *actx, struct Body *cur)
Check whether one attachment is the parent of another.
Definition: recvcmd.c:356
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
WHERE bool C_ForwardDecode
Config: Decode the message when forwarding it.
Definition: mutt_globals.h:147
Prototypes for many functions.
void mutt_attach_bounce(struct Mailbox *m, FILE *fp, struct AttachCtx *actx, struct Body *cur)
Bounce function, from the attachment menu.
Definition: recvcmd.c:168
Representation of the body of an email.
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
struct MuttWindow * MessageWindow
Message Window, ":set", etc.
Definition: mutt_window.c:47
static struct AttachPtr * find_parent(struct AttachCtx *actx, struct Body *cur, short nattach)
Find the parent of an Attachment.
Definition: recvcmd.c:377
WHERE unsigned char C_Bounce
Config: Confirm before bouncing a message.
Definition: mutt_globals.h:124
A mailbox.
Definition: mailbox.h:81
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1359
void mutt_fix_reply_recipients(struct Envelope *env, struct ConfigSubset *sub)
Remove duplicate recipients.
Definition: send.c:877
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:37
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:58
#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:1805
static struct AttachPtr * find_common_parent(struct AttachCtx *actx, short nattach)
find a common parent message for the tagged attachments
Definition: recvcmd.c:322
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:53
void mutt_forward_intro(struct Mailbox *m, struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add the "start of forwarded message" text.
Definition: send.c:405
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:54
#define MUTT_WEED
Weed headers even when not in display mode.
Definition: state.h:35
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
static short count_tagged(struct AttachCtx *actx)
Count the number of tagged attachments.
Definition: recvcmd.c:133
#define SEND_NEWS
Reply to a news article.
Definition: send.h:54
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
Generate recpients for a reply email.
Definition: send.c:790
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:151
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
int mutt_resend_message(FILE *fp, struct Context *ctx, struct Email *e_cur, struct ConfigSubset *sub)
Resend an email.
Definition: send.c:1510
char * mutt_str_cat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:385
void mutt_attach_forward(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *cur, SendFlags flags)
Forward an Attachment.
Definition: recvcmd.c:768
static struct Body ** copy_problematic_attachments(struct Body **last, struct AttachCtx *actx, bool force)
Attach the body parts which can&#39;t be decoded.
Definition: recvcmd.c:443
Keep track when processing files.
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
Duplicate the structure of an entire email.
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1304
Send/reply with an attachment.
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition: copy.c:405
#define mutt_error(...)
Definition: logging.h:84
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
#define EXTRA_SPACE
#define FREE(x)
Definition: memory.h:40
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:1999
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: globals.c:40
Keep track when processing files.
Definition: state.h:44
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
void mutt_attach_mail_sender(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *cur)
Compose an email to the sender in the email attachment.
Definition: recvcmd.c:1089
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1595
void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Set subject for a reply.
Definition: send.c:928
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define state_putc(STATE, STR)
Definition: state.h:56
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
static int attach_reply_envelope_defaults(struct Envelope *env, struct AttachCtx *actx, struct Email *parent, SendFlags flags)
Create the envelope defaults for a reply.
Definition: recvcmd.c:799
#define TAILQ_EMPTY(head)
Definition: queue.h:714
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
make a copy of a message from a FILE pointer
Definition: copy.c:616
#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:46
void mutt_forward_trailer(struct Mailbox *m, struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add a "end of forwarded message" text.
Definition: send.c:430
unsigned char C_MimeForwardRest
Config: Forward all attachments, even if they can&#39;t be decoded.
Definition: recvcmd.c:60
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
Decide how to display email content.
struct Email * email
header information for message/rfc822
Definition: body.h:55
A set of attachments.
Definition: attach.h:49
void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Generate references for a reply email.
Definition: send.c:955
int level
Nesting depth of attachment.
Definition: attach.h:40
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:56
static short count_tagged_children(struct AttachCtx *actx, short i)
tagged children below a multipart/message attachment
Definition: recvcmd.c:149
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
void mutt_make_post_indent(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add suffix to replied email text.
Definition: send.c:610
void mutt_attach_resend(FILE *fp, struct AttachCtx *actx, struct Body *cur)
resend-message, from the attachment menu
Definition: recvcmd.c:295
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:1150
The header of an Email.
Definition: envelope.h:54
void mutt_make_forward_subject(struct Envelope *env, struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
Create a subject for a forwarded email.
Definition: send.c:908
#define mutt_make_string(BUF, BUFLEN, COLS, S, M, INPGR, E)
Definition: hdrline.h:58
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:1093
static void attach_forward_bodies(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *cur, short nattach)
forward one or several MIME bodies
Definition: recvcmd.c:468
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
WHERE char * C_IndentString
Config: String used to indent &#39;reply&#39; text.
Definition: mutt_globals.h:102
WHERE bool C_TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: mutt_globals.h:166
struct Body * body
Attachment.
Definition: attach.h:36