NeoMutt  2018-07-16 +2481-68dcde
Teaching an old dog new tricks
DOXYGEN
compose.c
Go to the documentation of this file.
1 
31 #include "config.h"
32 #include <errno.h>
33 #include <limits.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 #include "mutt/mutt.h"
40 #include "address/lib.h"
41 #include "config/lib.h"
42 #include "email/lib.h"
43 #include "core/lib.h"
44 #include "conn/conn.h"
45 #include "mutt.h"
46 #include "compose.h"
47 #include "alias.h"
48 #include "browser.h"
49 #include "commands.h"
50 #include "context.h"
51 #include "curs_lib.h"
52 #include "edit.h"
53 #include "format_flags.h"
54 #include "globals.h"
55 #include "hook.h"
56 #include "index.h"
57 #include "keymap.h"
58 #include "mutt_attach.h"
59 #include "mutt_curses.h"
60 #include "mutt_header.h"
61 #include "mutt_logging.h"
62 #include "mutt_menu.h"
63 #include "mutt_window.h"
64 #include "muttlib.h"
65 #include "mx.h"
66 #include "ncrypt/ncrypt.h"
67 #include "opcodes.h"
68 #include "options.h"
69 #include "protos.h"
70 #include "recvattach.h"
71 #include "sendlib.h"
72 #include "sort.h"
73 #ifdef ENABLE_NLS
74 #include <libintl.h>
75 #endif
76 #ifdef MIXMASTER
77 #include "remailer.h"
78 #endif
79 #ifdef USE_NNTP
80 #include "nntp/nntp.h"
81 #endif
82 #ifdef USE_POP
83 #include "pop/pop.h"
84 #endif
85 #ifdef USE_IMAP
86 #include "imap/imap.h"
87 #endif
88 #ifdef USE_AUTOCRYPT
89 #include "autocrypt/autocrypt.h"
90 #endif
91 
92 /* These Config Variables are only used in compose.c */
94 char *C_Ispell;
95 unsigned char C_Postpone;
96 
97 static const char *There_are_no_attachments = N_("There are no attachments");
98 
99 static void compose_status_line(char *buf, size_t buflen, size_t col, int cols,
100  struct Menu *menu, const char *p);
101 
102 #define CHECK_COUNT \
103  if (actx->idxlen == 0) \
104  { \
105  mutt_error(_(There_are_no_attachments)); \
106  break; \
107  }
108 
109 #define CUR_ATTACH actx->idx[actx->v2r[menu->current]]
110 
117 {
118  HDR_FROM = 0,
125 #ifdef MIXMASTER
126  HDR_MIX,
127 #endif
130 #ifdef USE_AUTOCRYPT
132 #endif
133 #ifdef USE_NNTP
137 #endif
140 };
141 
144 
145 #define HDR_XOFFSET MaxHeaderWidth
146 #define W (rd->win->cols - MaxHeaderWidth)
147 
148 static const char *const Prompts[] = {
149  /* L10N: Compose menu field. May not want to translate. */
150  N_("From: "),
151  /* L10N: Compose menu field. May not want to translate. */
152  N_("To: "),
153  /* L10N: Compose menu field. May not want to translate. */
154  N_("Cc: "),
155  /* L10N: Compose menu field. May not want to translate. */
156  N_("Bcc: "),
157  /* L10N: Compose menu field. May not want to translate. */
158  N_("Subject: "),
159  /* L10N: Compose menu field. May not want to translate. */
160  N_("Reply-To: "),
161  /* L10N: Compose menu field. May not want to translate. */
162  N_("Fcc: "),
163 #ifdef MIXMASTER
164  /* L10N: "Mix" refers to the MixMaster chain for anonymous email */
165  N_("Mix: "),
166 #endif
167  /* L10N: Compose menu field. Holds "Encrypt", "Sign" related information */
168  N_("Security: "),
169  /* L10N:
170  This string is used by the compose menu.
171  Since it is hidden by default, it does not increase the
172  indentation of other compose menu fields. However, if possible,
173  it should not be longer than the other compose menu fields.
174  Since it shares the row with "Encrypt with:", it should not be longer
175  than 15-20 character cells. */
176  N_("Sign as: "),
177 #ifdef USE_AUTOCRYPT
178  // L10N: The compose menu autocrypt line
179  N_("Autocrypt: "),
180 #endif
181 #ifdef USE_NNTP
182  /* L10N: Compose menu field. May not want to translate. */
183  N_("Newsgroups: "),
184  /* L10N: Compose menu field. May not want to translate. */
185  N_("Followup-To: "),
186  /* L10N: Compose menu field. May not want to translate. */
187  N_("X-Comment-To: "),
188 #endif
189 };
190 
191 static const struct Mapping ComposeHelp[] = {
192  { N_("Send"), OP_COMPOSE_SEND_MESSAGE },
193  { N_("Abort"), OP_EXIT },
194  /* L10N: compose menu help line entry */
195  { N_("To"), OP_COMPOSE_EDIT_TO },
196  /* L10N: compose menu help line entry */
197  { N_("CC"), OP_COMPOSE_EDIT_CC },
198  /* L10N: compose menu help line entry */
199  { N_("Subj"), OP_COMPOSE_EDIT_SUBJECT },
200  { N_("Attach file"), OP_COMPOSE_ATTACH_FILE },
201  { N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION },
202  { N_("Help"), OP_HELP },
203  { NULL, 0 },
204 };
205 
206 #ifdef USE_NNTP
207 static struct Mapping ComposeNewsHelp[] = {
208  { N_("Send"), OP_COMPOSE_SEND_MESSAGE },
209  { N_("Abort"), OP_EXIT },
210  { N_("Newsgroups"), OP_COMPOSE_EDIT_NEWSGROUPS },
211  { N_("Subj"), OP_COMPOSE_EDIT_SUBJECT },
212  { N_("Attach file"), OP_COMPOSE_ATTACH_FILE },
213  { N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION },
214  { N_("Help"), OP_HELP },
215  { NULL, 0 },
216 };
217 #endif
218 
219 #ifdef USE_AUTOCRYPT
220 static const char *AutocryptRecUiFlags[] = {
221  /* L10N: Autocrypt recommendation flag: off.
222  * This is displayed when Autocrypt is turned off. */
223  N_("Off"),
224  /* L10N: Autocrypt recommendation flag: no.
225  * This is displayed when Autocrypt cannot encrypt to the recipients. */
226  N_("No"),
227  /* L10N: Autocrypt recommendation flag: discouraged.
228  * This is displayed when Autocrypt believes encryption should not be used.
229  * This might occur if one of the recipient Autocrypt Keys has not been
230  * used recently, or if the only key available is a Gossip Header key. */
231  N_("Discouraged"),
232  /* L10N: Autocrypt recommendation flag: available.
233  * This is displayed when Autocrypt believes encryption is possible, but
234  * leaves enabling it up to the sender. Probably because "prefer encrypt"
235  * is not set in both the sender and recipient keys. */
236  N_("Available"),
237  /* L10N: Autocrypt recommendation flag: yes.
238  * This is displayed when Autocrypt would normally enable encryption
239  * automatically. */
240  N_("Yes"),
241 };
242 #endif
243 
248 {
249  struct Email *email;
250  char *fcc;
251 #ifdef USE_AUTOCRYPT
254 #endif
255  struct MuttWindow *win;
256 };
257 
264 static void calc_header_width_padding(int idx, const char *header, bool calc_max)
265 {
266  int width;
267 
268  HeaderPadding[idx] = mutt_str_strlen(header);
269  width = mutt_strwidth(header);
270  if (calc_max && (MaxHeaderWidth < width))
271  MaxHeaderWidth = width;
272  HeaderPadding[idx] -= width;
273 }
274 
283 static void init_header_padding(void)
284 {
285  static bool done = false;
286 
287  if (done)
288  return;
289  done = true;
290 
291  for (int i = 0; i < HDR_ATTACH_TITLE; i++)
292  {
293  if (i == HDR_CRYPTINFO)
294  continue;
295  calc_header_width_padding(i, _(Prompts[i]), true);
296  }
297 
298  /* Don't include "Sign as: " in the MaxHeaderWidth calculation. It
299  * doesn't show up by default, and so can make the indentation of
300  * the other fields look funny. */
302 
303  for (int i = 0; i < HDR_ATTACH_TITLE; i++)
304  {
306  if (HeaderPadding[i] < 0)
307  HeaderPadding[i] = 0;
308  }
309 }
310 
314 static void snd_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
315 {
316  struct AttachCtx *actx = menu->data;
317 
318  mutt_expando_format(buf, buflen, 0, menu->indexwin->cols, NONULL(C_AttachFormat),
319  attach_format_str, (unsigned long) (actx->idx[actx->v2r[line]]),
321 }
322 
323 #ifdef USE_AUTOCRYPT
324 
328 static void autocrypt_compose_menu(struct Email *e)
329 {
330  /* L10N:
331  The compose menu autocrypt prompt.
332  (e)ncrypt enables encryption via autocrypt.
333  (c)lear sets cleartext.
334  (a)utomatic defers to the recommendation.
335  */
336  const char *prompt = _("Autocrypt: (e)ncrypt, (c)lear, (a)utomatic?");
337 
338  /* L10N:
339  The letter corresponding to the compose menu autocrypt prompt
340  (e)ncrypt, (c)lear, (a)utomatic
341  */
342  const char *letters = _("eca");
343 
344  int choice = mutt_multi_choice(prompt, letters);
345  switch (choice)
346  {
347  case 1:
350  break;
351  case 2:
352  e->security &= ~SEC_AUTOCRYPT;
354  break;
355  case 3:
358  e->security |= SEC_OPPENCRYPT;
359  break;
360  }
361 }
362 #endif
363 
368 static void redraw_crypt_lines(struct ComposeRedrawData *rd)
369 {
370  struct Email *e = rd->email;
371 
374  _(Prompts[HDR_CRYPT]));
375  NORMAL_COLOR;
376 
378  {
379  addstr(_("Not supported"));
380  return;
381  }
382 
383  if ((e->security & (SEC_ENCRYPT | SEC_SIGN)) == (SEC_ENCRYPT | SEC_SIGN))
384  {
386  addstr(_("Sign, Encrypt"));
387  }
388  else if (e->security & SEC_ENCRYPT)
389  {
391  addstr(_("Encrypt"));
392  }
393  else if (e->security & SEC_SIGN)
394  {
396  addstr(_("Sign"));
397  }
398  else
399  {
400  /* L10N: This refers to the encryption of the email, e.g. "Security: None" */
402  addstr(_("None"));
403  }
404  NORMAL_COLOR;
405 
406  if ((e->security & (SEC_ENCRYPT | SEC_SIGN)))
407  {
408  if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
409  {
410  if ((e->security & SEC_INLINE))
411  addstr(_(" (inline PGP)"));
412  else
413  addstr(_(" (PGP/MIME)"));
414  }
415  else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
416  addstr(_(" (S/MIME)"));
417  }
418 
420  addstr(_(" (OppEnc mode)"));
421 
425 
426  if (((WithCrypto & APPLICATION_PGP) != 0) &&
427  (e->security & APPLICATION_PGP) && (e->security & SEC_SIGN))
428  {
430  printw("%*s", HeaderPadding[HDR_CRYPTINFO], _(Prompts[HDR_CRYPTINFO]));
431  NORMAL_COLOR;
432  printw("%s", C_PgpSignAs ? C_PgpSignAs : _("<default>"));
433  }
434 
435  if (((WithCrypto & APPLICATION_SMIME) != 0) &&
436  (e->security & APPLICATION_SMIME) && (e->security & SEC_SIGN))
437  {
439  printw("%*s", HeaderPadding[HDR_CRYPTINFO], _(Prompts[HDR_CRYPTINFO]));
440  NORMAL_COLOR;
441  printw("%s", C_SmimeSignAs ? C_SmimeSignAs : _("<default>"));
442  }
443 
444  if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME) &&
446  {
448  mutt_window_mvprintw(rd->win, HDR_CRYPTINFO, 40, "%s", _("Encrypt with: "));
449  NORMAL_COLOR;
450  printw("%s", NONULL(C_SmimeEncryptWith));
451  }
452 
453 #ifdef USE_AUTOCRYPT
456  if (C_Autocrypt)
457  {
459  printw("%*s", HeaderPadding[HDR_AUTOCRYPT], _(Prompts[HDR_AUTOCRYPT]));
460  NORMAL_COLOR;
461  if (e->security & SEC_AUTOCRYPT)
462  {
464  addstr(_("Encrypt"));
465  }
466  else
467  {
469  addstr(_("Off"));
470  }
471 
473  mutt_window_mvprintw(rd->win, HDR_AUTOCRYPT, 40, "%s",
474  /* L10N:
475  The autocrypt compose menu Recommendation field.
476  Displays the output of the recommendation engine
477  (Off, No, Discouraged, Available, Yes)
478  */
479  _("Recommendation: "));
480  NORMAL_COLOR;
481  printw("%s", _(AutocryptRecUiFlags[rd->autocrypt_rec]));
482  }
483 #endif
484 }
485 
490 static void update_crypt_info(struct ComposeRedrawData *rd)
491 {
492  struct Email *e = rd->email;
493 
496 
497 #ifdef USE_AUTOCRYPT
498  if (C_Autocrypt)
499  {
501 
502  /* Anything that enables SEC_ENCRYPT or SEC_SIGN, or turns on SMIME
503  * overrides autocrypt, be it oppenc or the user having turned on
504  * those flags manually. */
507  else
508  {
509  if (!(e->security & SEC_AUTOCRYPT_OVERRIDE))
510  {
511  if (rd->autocrypt_rec == AUTOCRYPT_REC_YES)
512  {
513  e->security |= SEC_AUTOCRYPT;
514  e->security &= ~SEC_INLINE;
515  }
516  else
517  e->security &= ~SEC_AUTOCRYPT;
518  }
519  }
520  }
521 #endif
522 
523  redraw_crypt_lines(rd);
524 }
525 
526 #ifdef MIXMASTER
527 
532 static void redraw_mix_line(struct ListHead *chain, struct ComposeRedrawData *rd)
533 {
534  char *t = NULL;
535 
537  mutt_window_mvprintw(rd->win, HDR_MIX, 0, "%*s", HeaderPadding[HDR_MIX],
538  _(Prompts[HDR_MIX]));
539  NORMAL_COLOR;
540 
541  if (STAILQ_EMPTY(chain))
542  {
543  addstr(_("<no chain defined>"));
545  return;
546  }
547 
548  int c = 12;
549  struct ListNode *np = NULL;
550  STAILQ_FOREACH(np, chain, entries)
551  {
552  t = np->data;
553  if (t && (t[0] == '0') && (t[1] == '\0'))
554  t = "<random>";
555 
556  if (c + mutt_str_strlen(t) + 2 >= rd->win->cols)
557  break;
558 
559  addstr(NONULL(t));
560  if (STAILQ_NEXT(np, entries))
561  addstr(", ");
562 
563  c += mutt_str_strlen(t) + 2;
564  }
565 }
566 #endif /* MIXMASTER */
567 
574 static int check_attachments(struct AttachCtx *actx)
575 {
576  struct stat st;
577  char pretty[PATH_MAX], msg[PATH_MAX + 128];
578 
579  for (int i = 0; i < actx->idxlen; i++)
580  {
581  if (actx->idx[i]->content->type == TYPE_MULTIPART)
582  continue;
583  mutt_str_strfcpy(pretty, actx->idx[i]->content->filename, sizeof(pretty));
584  if (stat(actx->idx[i]->content->filename, &st) != 0)
585  {
586  mutt_pretty_mailbox(pretty, sizeof(pretty));
587  mutt_error(_("%s [#%d] no longer exists"), pretty, i + 1);
588  return -1;
589  }
590 
591  if (actx->idx[i]->content->stamp < st.st_mtime)
592  {
593  mutt_pretty_mailbox(pretty, sizeof(pretty));
594  snprintf(msg, sizeof(msg), _("%s [#%d] modified. Update encoding?"), pretty, i + 1);
595 
596  enum QuadOption ans = mutt_yesorno(msg, MUTT_YES);
597  if (ans == MUTT_YES)
598  mutt_update_encoding(actx->idx[i]->content);
599  else if (ans == MUTT_ABORT)
600  return -1;
601  }
602  }
603 
604  return 0;
605 }
606 
613 static void draw_envelope_addr(int line, struct AddressList *al, struct ComposeRedrawData *rd)
614 {
615  char buf[1024];
616 
617  buf[0] = '\0';
618  mutt_addrlist_write(buf, sizeof(buf), al, true);
620  mutt_window_mvprintw(rd->win, line, 0, "%*s", HeaderPadding[line], _(Prompts[line]));
621  NORMAL_COLOR;
622  mutt_paddstr(W, buf);
623 }
624 
629 static void draw_envelope(struct ComposeRedrawData *rd)
630 {
631  struct Email *e = rd->email;
632  char *fcc = rd->fcc;
633 
634  draw_envelope_addr(HDR_FROM, &e->env->from, rd);
635 #ifdef USE_NNTP
636  if (!OptNewsSend)
637  {
638 #endif
639  draw_envelope_addr(HDR_TO, &e->env->to, rd);
640  draw_envelope_addr(HDR_CC, &e->env->cc, rd);
641  draw_envelope_addr(HDR_BCC, &e->env->bcc, rd);
642 #ifdef USE_NNTP
643  }
644  else
645  {
646  mutt_window_mvprintw(rd->win, HDR_TO, 0, "%*s",
647  HeaderPadding[HDR_NEWSGROUPS], Prompts[HDR_NEWSGROUPS]);
649  mutt_window_mvprintw(rd->win, HDR_CC, 0, "%*s",
650  HeaderPadding[HDR_FOLLOWUPTO], Prompts[HDR_FOLLOWUPTO]);
652  if (C_XCommentTo)
653  {
654  mutt_window_mvprintw(rd->win, HDR_BCC, 0, "%*s",
655  HeaderPadding[HDR_XCOMMENTTO], Prompts[HDR_XCOMMENTTO]);
657  }
658  }
659 #endif
660 
662  mutt_window_mvprintw(rd->win, HDR_SUBJECT, 0, "%*s",
663  HeaderPadding[HDR_SUBJECT], _(Prompts[HDR_SUBJECT]));
664  NORMAL_COLOR;
666 
668 
671  _(Prompts[HDR_FCC]));
672  NORMAL_COLOR;
673  mutt_paddstr(W, fcc);
674 
675  if (WithCrypto)
676  redraw_crypt_lines(rd);
677 
678 #ifdef MIXMASTER
679  redraw_mix_line(&e->chain, rd);
680 #endif
681 
683  mutt_window_mvaddstr(rd->win, HDR_ATTACH_TITLE, 0, _("-- Attachments"));
685 
686  NORMAL_COLOR;
687 }
688 
695 static void edit_address_list(int line, struct AddressList *al, struct ComposeRedrawData *rd)
696 {
697  char buf[8192] = { 0 }; /* needs to be large for alias expansion */
698  char *err = NULL;
699 
701  mutt_addrlist_write(buf, sizeof(buf), al, false);
702  if (mutt_get_field(_(Prompts[line]), buf, sizeof(buf), MUTT_ALIAS) == 0)
703  {
705  mutt_addrlist_parse2(al, buf);
707  }
708 
709  if (mutt_addrlist_to_intl(al, &err) != 0)
710  {
711  mutt_error(_("Bad IDN: '%s'"), err);
712  mutt_refresh();
713  FREE(&err);
714  }
715 
716  /* redraw the expanded list so the user can see the result */
717  buf[0] = '\0';
718  mutt_addrlist_write(buf, sizeof(buf), al, true);
719  mutt_window_move(rd->win, line, HDR_XOFFSET);
720  mutt_paddstr(W, buf);
721 }
722 
730 static int delete_attachment(struct AttachCtx *actx, int x)
731 {
732  struct AttachPtr **idx = actx->idx;
733  int rindex = actx->v2r[x];
734 
735  if ((rindex == 0) && (actx->idxlen == 1))
736  {
737  mutt_error(_("You may not delete the only attachment"));
738  idx[rindex]->content->tagged = false;
739  return -1;
740  }
741 
742  for (int y = 0; y < actx->idxlen; y++)
743  {
744  if (idx[y]->content->next == idx[rindex]->content)
745  {
746  idx[y]->content->next = idx[rindex]->content->next;
747  break;
748  }
749  }
750 
751  idx[rindex]->content->next = NULL;
752  idx[rindex]->content->parts = NULL;
753  mutt_body_free(&(idx[rindex]->content));
754  FREE(&idx[rindex]->tree);
755  FREE(&idx[rindex]);
756  for (; rindex < actx->idxlen - 1; rindex++)
757  idx[rindex] = idx[rindex + 1];
758  idx[actx->idxlen - 1] = NULL;
759  actx->idxlen--;
760 
761  return 0;
762 }
763 
771 static void mutt_gen_compose_attach_list(struct AttachCtx *actx, struct Body *m,
772  int parent_type, int level)
773 {
774  for (; m; m = m->next)
775  {
776  if ((m->type == TYPE_MULTIPART) && m->parts &&
778  {
779  mutt_gen_compose_attach_list(actx, m->parts, m->type, level);
780  }
781  else
782  {
783  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
784  mutt_actx_add_attach(actx, ap);
785  ap->content = m;
786  m->aptr = ap;
787  ap->parent_type = parent_type;
788  ap->level = level;
789 
790  /* We don't support multipart messages in the compose menu yet */
791  }
792  }
793 }
794 
801 static void mutt_update_compose_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
802 {
803  if (init)
804  {
805  mutt_gen_compose_attach_list(actx, actx->email->content, -1, 0);
806  mutt_attach_init(actx);
807  menu->data = actx;
808  }
809 
810  mutt_update_tree(actx);
811 
812  menu->max = actx->vcount;
813  if (menu->max)
814  {
815  if (menu->current >= menu->max)
816  menu->current = menu->max - 1;
817  }
818  else
819  menu->current = 0;
820 
821  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
822 }
823 
830 static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
831 {
832  ap->level = (actx->idxlen > 0) ? actx->idx[actx->idxlen - 1]->level : 0;
833  if (actx->idxlen)
834  actx->idx[actx->idxlen - 1]->content->next = ap->content;
835  ap->content->aptr = ap;
836  mutt_actx_add_attach(actx, ap);
837  mutt_update_compose_menu(actx, menu, false);
838  menu->current = actx->vcount - 1;
839 }
840 
844 static void compose_custom_redraw(struct Menu *menu)
845 {
846  struct ComposeRedrawData *rd = menu->redraw_data;
847 
848  if (!rd)
849  return;
850 
851  if (menu->redraw & REDRAW_FULL)
852  {
853  menu_redraw_full(menu);
854 
855  draw_envelope(rd);
856  menu->offset = HDR_ATTACH;
857  menu->pagelen = menu->indexwin->rows - HDR_ATTACH;
858  }
859 
860  menu_check_recenter(menu);
861 
862  if (menu->redraw & REDRAW_STATUS)
863  {
864  char buf[1024];
865  compose_status_line(buf, sizeof(buf), 0, menu->statuswin->cols, menu,
867  mutt_window_move(menu->statuswin, 0, 0);
869  mutt_paddstr(menu->statuswin->cols, buf);
870  NORMAL_COLOR;
871  menu->redraw &= ~REDRAW_STATUS;
872  }
873 
874 #ifdef USE_SIDEBAR
875  if (menu->redraw & REDRAW_SIDEBAR)
876  menu_redraw_sidebar(menu);
877 #endif
878 
879  if (menu->redraw & REDRAW_INDEX)
880  menu_redraw_index(menu);
881  else if (menu->redraw & (REDRAW_MOTION | REDRAW_MOTION_RESYNC))
882  menu_redraw_motion(menu);
883  else if (menu->redraw == REDRAW_CURRENT)
884  menu_redraw_current(menu);
885 }
886 
893 static void compose_attach_swap(struct Body *msg, struct AttachPtr **idx, short first)
894 {
895  /* Reorder Body pointers.
896  * Must traverse msg from top since Body has no previous ptr. */
897  for (struct Body *part = msg; part; part = part->next)
898  {
899  if (part->next == idx[first]->content)
900  {
901  idx[first]->content->next = idx[first + 1]->content->next;
902  idx[first + 1]->content->next = idx[first]->content;
903  part->next = idx[first + 1]->content;
904  break;
905  }
906  }
907 
908  /* Reorder index */
909  struct AttachPtr *saved = idx[first];
910  idx[first] = idx[first + 1];
911  idx[first + 1] = saved;
912 
913  /* Swap ptr->num */
914  int i = idx[first]->num;
915  idx[first]->num = idx[first + 1]->num;
916  idx[first + 1]->num = i;
917 }
918 
927 static unsigned long cum_attachs_size(struct Menu *menu)
928 {
929  size_t s = 0;
930  struct AttachCtx *actx = menu->data;
931  struct AttachPtr **idx = actx->idx;
932  struct Content *info = NULL;
933  struct Body *b = NULL;
934 
935  for (unsigned short i = 0; i < actx->idxlen; i++)
936  {
937  b = idx[i]->content;
938 
939  if (!b->content)
941 
942  info = b->content;
943  if (info)
944  {
945  switch (b->encoding)
946  {
948  s += 3 * (info->lobin + info->hibin) + info->ascii + info->crlf;
949  break;
950  case ENC_BASE64:
951  s += (4 * (info->lobin + info->hibin + info->ascii + info->crlf)) / 3;
952  break;
953  default:
954  s += info->lobin + info->hibin + info->ascii + info->crlf;
955  break;
956  }
957  }
958  }
959 
960  return s;
961 }
962 
973 static const char *compose_format_str(char *buf, size_t buflen, size_t col, int cols,
974  char op, const char *src, const char *prec,
975  const char *if_str, const char *else_str,
976  unsigned long data, MuttFormatFlags flags)
977 {
978  char fmt[128], tmp[128];
979  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
980  struct Menu *menu = (struct Menu *) data;
981 
982  *buf = '\0';
983  switch (op)
984  {
985  case 'a': /* total number of attachments */
986  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
987  snprintf(buf, buflen, fmt, menu->max);
988  break;
989 
990  case 'h': /* hostname */
991  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
992  snprintf(buf, buflen, fmt, NONULL(ShortHostname));
993  break;
994 
995  case 'l': /* approx length of current message in bytes */
996  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
997  mutt_str_pretty_size(tmp, sizeof(tmp), menu ? cum_attachs_size(menu) : 0);
998  snprintf(buf, buflen, fmt, tmp);
999  break;
1000 
1001  case 'v':
1002  snprintf(buf, buflen, "%s", mutt_make_version());
1003  break;
1004 
1005  case 0:
1006  *buf = '\0';
1007  return src;
1008 
1009  default:
1010  snprintf(buf, buflen, "%%%s%c", prec, op);
1011  break;
1012  }
1013 
1014  if (optional)
1015  compose_status_line(buf, buflen, col, cols, menu, if_str);
1016  else if (flags & MUTT_FORMAT_OPTIONAL)
1017  compose_status_line(buf, buflen, col, cols, menu, else_str);
1018 
1019  return src;
1020 }
1021 
1031 static void compose_status_line(char *buf, size_t buflen, size_t col, int cols,
1032  struct Menu *menu, const char *src)
1033 {
1034  mutt_expando_format(buf, buflen, col, cols, src, compose_format_str,
1035  (unsigned long) menu, MUTT_FORMAT_NO_FLAGS);
1036 }
1037 
1049 int mutt_compose_menu(struct Email *e, char *fcc, size_t fcclen, struct Email *e_cur, int flags)
1050 {
1051  char helpstr[1024]; // This isn't copied by the help bar
1052  char buf[PATH_MAX];
1053  int op_close = OP_NULL;
1054  int rc = -1;
1055  bool loop = true;
1056  bool fcc_set = false; /* has the user edited the Fcc: field ? */
1057  struct ComposeRedrawData redraw = { 0 };
1058  struct ComposeRedrawData *rd = &redraw;
1059 #ifdef USE_NNTP
1060  bool news = OptNewsSend; /* is it a news article ? */
1061 #endif
1062 
1064 
1065  rd->email = e;
1066  rd->fcc = fcc;
1067  rd->win = MuttIndexWindow;
1068 
1069  struct Menu *menu = mutt_menu_new(MENU_COMPOSE);
1070  menu->offset = HDR_ATTACH;
1072  menu->menu_tag = attach_tag;
1073 #ifdef USE_NNTP
1074  if (news)
1075  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_COMPOSE, ComposeNewsHelp);
1076  else
1077 #endif
1078  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_COMPOSE, ComposeHelp);
1080  menu->redraw_data = rd;
1081  mutt_menu_push_current(menu);
1082 
1083  struct AttachCtx *actx = mutt_actx_new();
1084  actx->email = e;
1085  mutt_update_compose_menu(actx, menu, true);
1086 
1087  update_crypt_info(rd);
1088 
1089  while (loop)
1090  {
1091 #ifdef USE_NNTP
1092  OptNews = false; /* for any case */
1093 #endif
1094  const int op = mutt_menu_loop(menu);
1095  switch (op)
1096  {
1097  case OP_COMPOSE_EDIT_FROM:
1098  edit_address_list(HDR_FROM, &e->env->from, rd);
1099  update_crypt_info(rd);
1101  break;
1102 
1103  case OP_COMPOSE_EDIT_TO:
1104 #ifdef USE_NNTP
1105  if (news)
1106  break;
1107 #endif
1108  edit_address_list(HDR_TO, &e->env->to, rd);
1109  update_crypt_info(rd);
1111  break;
1112 
1113  case OP_COMPOSE_EDIT_BCC:
1114 #ifdef USE_NNTP
1115  if (news)
1116  break;
1117 #endif
1118  edit_address_list(HDR_BCC, &e->env->bcc, rd);
1119  update_crypt_info(rd);
1121  break;
1122 
1123  case OP_COMPOSE_EDIT_CC:
1124 #ifdef USE_NNTP
1125  if (news)
1126  break;
1127 #endif
1128  edit_address_list(HDR_CC, &e->env->cc, rd);
1129  update_crypt_info(rd);
1131  break;
1132 #ifdef USE_NNTP
1133  case OP_COMPOSE_EDIT_NEWSGROUPS:
1134  if (!news)
1135  break;
1136  if (e->env->newsgroups)
1137  mutt_str_strfcpy(buf, e->env->newsgroups, sizeof(buf));
1138  else
1139  buf[0] = '\0';
1140  if (mutt_get_field("Newsgroups: ", buf, sizeof(buf), 0) == 0)
1141  {
1142  mutt_str_replace(&e->env->newsgroups, buf);
1144  if (e->env->newsgroups)
1145  mutt_paddstr(W, e->env->newsgroups);
1146  else
1148  }
1149  break;
1150 
1151  case OP_COMPOSE_EDIT_FOLLOWUP_TO:
1152  if (!news)
1153  break;
1154  if (e->env->followup_to)
1155  mutt_str_strfcpy(buf, e->env->followup_to, sizeof(buf));
1156  else
1157  buf[0] = '\0';
1158  if (mutt_get_field("Followup-To: ", buf, sizeof(buf), 0) == 0)
1159  {
1160  mutt_str_replace(&e->env->followup_to, buf);
1162  if (e->env->followup_to)
1163  mutt_paddstr(W, e->env->followup_to);
1164  else
1166  }
1167  break;
1168 
1169  case OP_COMPOSE_EDIT_X_COMMENT_TO:
1170  if (!(news && C_XCommentTo))
1171  break;
1172  if (e->env->x_comment_to)
1173  mutt_str_strfcpy(buf, e->env->x_comment_to, sizeof(buf));
1174  else
1175  buf[0] = '\0';
1176  if (mutt_get_field("X-Comment-To: ", buf, sizeof(buf), 0) == 0)
1177  {
1178  mutt_str_replace(&e->env->x_comment_to, buf);
1180  if (e->env->x_comment_to)
1182  else
1184  }
1185  break;
1186 #endif
1187 
1188  case OP_COMPOSE_EDIT_SUBJECT:
1189  if (e->env->subject)
1190  mutt_str_strfcpy(buf, e->env->subject, sizeof(buf));
1191  else
1192  buf[0] = '\0';
1193  if (mutt_get_field(_("Subject: "), buf, sizeof(buf), 0) == 0)
1194  {
1195  mutt_str_replace(&e->env->subject, buf);
1197  if (e->env->subject)
1198  mutt_paddstr(W, e->env->subject);
1199  else
1201  }
1203  break;
1204 
1205  case OP_COMPOSE_EDIT_REPLY_TO:
1208  break;
1209 
1210  case OP_COMPOSE_EDIT_FCC:
1211  mutt_str_strfcpy(buf, fcc, sizeof(buf));
1212  if (mutt_get_field(_("Fcc: "), buf, sizeof(buf), MUTT_FILE | MUTT_CLEAR) == 0)
1213  {
1214  mutt_str_strfcpy(fcc, buf, fcclen);
1215  mutt_pretty_mailbox(fcc, fcclen);
1217  mutt_paddstr(W, fcc);
1218  fcc_set = true;
1219  }
1221  break;
1222 
1223  case OP_COMPOSE_EDIT_MESSAGE:
1224  if (C_Editor && (mutt_str_strcmp("builtin", C_Editor) != 0) && !C_EditHeaders)
1225  {
1228  menu->redraw = REDRAW_FULL;
1230  break;
1231  }
1232  /* fallthrough */
1233 
1234  case OP_COMPOSE_EDIT_HEADERS:
1235  if ((mutt_str_strcmp("builtin", C_Editor) != 0) &&
1236  ((op == OP_COMPOSE_EDIT_HEADERS) || ((op == OP_COMPOSE_EDIT_MESSAGE) && C_EditHeaders)))
1237  {
1238  const char *tag = NULL;
1239  char *err = NULL;
1240  mutt_env_to_local(e->env);
1241  mutt_edit_headers(NONULL(C_Editor), e->content->filename, e, fcc, fcclen);
1242  if (mutt_env_to_intl(e->env, &tag, &err))
1243  {
1244  mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
1245  FREE(&err);
1246  }
1247  update_crypt_info(rd);
1248  }
1249  else
1250  {
1251  /* this is grouped with OP_COMPOSE_EDIT_HEADERS because the
1252  * attachment list could change if the user invokes ~v to edit
1253  * the message with headers, in which we need to execute the
1254  * code below to regenerate the index array */
1255  mutt_builtin_editor(e->content->filename, e, e_cur);
1256  }
1258 
1259  /* attachments may have been added */
1260  if (actx->idxlen && actx->idx[actx->idxlen - 1]->content->next)
1261  {
1262  mutt_actx_entries_free(actx);
1263  mutt_update_compose_menu(actx, menu, true);
1264  }
1265 
1266  menu->redraw = REDRAW_FULL;
1268  break;
1269 
1270  case OP_COMPOSE_ATTACH_KEY:
1271  {
1272  if (!(WithCrypto & APPLICATION_PGP))
1273  break;
1274  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1276  if (ap->content)
1277  {
1278  update_idx(menu, actx, ap);
1279  menu->redraw |= REDRAW_INDEX;
1280  }
1281  else
1282  FREE(&ap);
1283 
1284  menu->redraw |= REDRAW_STATUS;
1285 
1287  break;
1288  }
1289 
1290  case OP_COMPOSE_MOVE_UP:
1291  if (menu->current == 0)
1292  {
1293  mutt_error(_("Attachment is already at top"));
1294  break;
1295  }
1296  if (menu->current == 1)
1297  {
1298  mutt_error(_("The fundamental part can't be moved"));
1299  break;
1300  }
1301  compose_attach_swap(e->content, actx->idx, menu->current - 1);
1302  menu->redraw = REDRAW_INDEX;
1303  menu->current--;
1304  break;
1305 
1306  case OP_COMPOSE_MOVE_DOWN:
1307  if (menu->current == (actx->idxlen - 1))
1308  {
1309  mutt_error(_("Attachment is already at bottom"));
1310  break;
1311  }
1312  if (menu->current == 0)
1313  {
1314  mutt_error(_("The fundamental part can't be moved"));
1315  break;
1316  }
1317  compose_attach_swap(e->content, actx->idx, menu->current);
1318  menu->redraw = REDRAW_INDEX;
1319  menu->current++;
1320  break;
1321 
1322  case OP_COMPOSE_GROUP_ALTS:
1323  {
1324  if (menu->tagged < 2)
1325  {
1326  mutt_error(
1327  _("Grouping 'alternatives' requires at least 2 tagged messages"));
1328  break;
1329  }
1330 
1331  struct Body *group = mutt_body_new();
1332  group->type = TYPE_MULTIPART;
1333  group->subtype = mutt_str_strdup("alternative");
1334  group->disposition = DISP_INLINE;
1335 
1336  struct Body *alts = NULL;
1337  /* group tagged message into a multipart/alternative */
1338  struct Body *bptr = e->content;
1339  for (int i = 0; bptr;)
1340  {
1341  if (bptr->tagged)
1342  {
1343  bptr->tagged = false;
1344  bptr->disposition = DISP_INLINE;
1345 
1346  /* for first match, set group desc according to match */
1347 #define ALTS_TAG "Alternatives for \"%s\""
1348  if (!group->description)
1349  {
1350  char *p = bptr->description ? bptr->description : bptr->filename;
1351  if (p)
1352  {
1353  group->description =
1354  mutt_mem_calloc(1, strlen(p) + strlen(ALTS_TAG) + 1);
1355  sprintf(group->description, ALTS_TAG, p);
1356  }
1357  }
1358 
1359  /* append bptr to the alts list,
1360  * and remove from the e->content list */
1361  if (!alts)
1362  {
1363  group->parts = bptr;
1364  alts = bptr;
1365  bptr = bptr->next;
1366  alts->next = NULL;
1367  }
1368  else
1369  {
1370  alts->next = bptr;
1371  bptr = bptr->next;
1372  alts = alts->next;
1373  alts->next = NULL;
1374  }
1375 
1376  for (int j = i; j < actx->idxlen - 1; j++)
1377  {
1378  actx->idx[j] = actx->idx[j + 1];
1379  actx->idx[j + 1] = NULL; /* for debug reason */
1380  }
1381  actx->idxlen--;
1382  }
1383  else
1384  {
1385  bptr = bptr->next;
1386  i++;
1387  }
1388  }
1389 
1390  group->next = NULL;
1392 
1393  /* if no group desc yet, make one up */
1394  if (!group->description)
1395  group->description = mutt_str_strdup("unknown alternative group");
1396 
1397  struct AttachPtr *gptr = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1398  gptr->content = group;
1399  update_idx(menu, actx, gptr);
1400  menu->redraw = REDRAW_INDEX;
1401  break;
1402  }
1403 
1404  case OP_COMPOSE_GROUP_LINGUAL:
1405  {
1406  if (menu->tagged < 2)
1407  {
1408  mutt_error(
1409  _("Grouping 'multilingual' requires at least 2 tagged messages"));
1410  break;
1411  }
1412 
1413  /* traverse to see whether all the parts have Content-Language: set */
1414  int tagged_with_lang_num = 0;
1415  for (struct Body *b = e->content; b; b = b->next)
1416  if (b->tagged && b->language && *b->language)
1417  tagged_with_lang_num++;
1418 
1419  if (menu->tagged != tagged_with_lang_num)
1420  {
1421  if (mutt_yesorno(
1422  _("Not all parts have 'Content-Language' set, continue?"), MUTT_YES) != MUTT_YES)
1423  {
1424  mutt_message(_("Not sending this message"));
1425  break;
1426  }
1427  }
1428 
1429  struct Body *group = mutt_body_new();
1430  group->type = TYPE_MULTIPART;
1431  group->subtype = mutt_str_strdup("multilingual");
1432  group->disposition = DISP_INLINE;
1433 
1434  struct Body *alts = NULL;
1435  /* group tagged message into a multipart/multilingual */
1436  struct Body *bptr = e->content;
1437  for (int i = 0; bptr;)
1438  {
1439  if (bptr->tagged)
1440  {
1441  bptr->tagged = false;
1442  bptr->disposition = DISP_INLINE;
1443 
1444  /* for first match, set group desc according to match */
1445 #define LINGUAL_TAG "Multilingual part for \"%s\""
1446  if (!group->description)
1447  {
1448  char *p = bptr->description ? bptr->description : bptr->filename;
1449  if (p)
1450  {
1451  group->description =
1452  mutt_mem_calloc(1, strlen(p) + strlen(LINGUAL_TAG) + 1);
1453  sprintf(group->description, LINGUAL_TAG, p);
1454  }
1455  }
1456 
1457  /* append bptr to the alts list,
1458  * and remove from the e->content list */
1459  if (!alts)
1460  {
1461  group->parts = bptr;
1462  alts = bptr;
1463  bptr = bptr->next;
1464  alts->next = NULL;
1465  }
1466  else
1467  {
1468  alts->next = bptr;
1469  bptr = bptr->next;
1470  alts = alts->next;
1471  alts->next = NULL;
1472  }
1473 
1474  for (int j = i; j < actx->idxlen - 1; j++)
1475  {
1476  actx->idx[j] = actx->idx[j + 1];
1477  actx->idx[j + 1] = NULL; /* for debug reason */
1478  }
1479  actx->idxlen--;
1480  }
1481  else
1482  {
1483  bptr = bptr->next;
1484  i++;
1485  }
1486  }
1487 
1488  group->next = NULL;
1490 
1491  /* if no group desc yet, make one up */
1492  if (!group->description)
1493  group->description = mutt_str_strdup("unknown multilingual group");
1494 
1495  struct AttachPtr *gptr = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1496  gptr->content = group;
1497  update_idx(menu, actx, gptr);
1498  menu->redraw = REDRAW_INDEX;
1499  break;
1500  }
1501 
1502  case OP_COMPOSE_ATTACH_FILE:
1503  {
1504  char *prompt = _("Attach file");
1505  int numfiles = 0;
1506  char **files = NULL;
1507  buf[0] = '\0';
1508 
1509  if ((mutt_enter_fname_full(prompt, buf, sizeof(buf), false, true,
1510  &files, &numfiles, MUTT_SEL_MULTI) == -1) ||
1511  (*buf == '\0'))
1512  {
1513  break;
1514  }
1515 
1516  bool error = false;
1517  if (numfiles > 1)
1518  {
1519  mutt_message(ngettext("Attaching selected file...",
1520  "Attaching selected files...", numfiles));
1521  }
1522  for (int i = 0; i < numfiles; i++)
1523  {
1524  char *att = files[i];
1525  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1526  ap->unowned = true;
1527  ap->content = mutt_make_file_attach(att);
1528  if (ap->content)
1529  update_idx(menu, actx, ap);
1530  else
1531  {
1532  error = true;
1533  mutt_error(_("Unable to attach %s"), att);
1534  FREE(&ap);
1535  }
1536  FREE(&files[i]);
1537  }
1538 
1539  FREE(&files);
1540  if (!error)
1541  mutt_clear_error();
1542 
1543  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1545  break;
1546  }
1547 
1548  case OP_COMPOSE_ATTACH_MESSAGE:
1549 #ifdef USE_NNTP
1550  case OP_COMPOSE_ATTACH_NEWS_MESSAGE:
1551 #endif
1552  {
1553  char *prompt = _("Open mailbox to attach message from");
1554  buf[0] = '\0';
1555 
1556 #ifdef USE_NNTP
1557  OptNews = false;
1558  if (Context && (op == OP_COMPOSE_ATTACH_NEWS_MESSAGE))
1559  {
1561  if (!CurrentNewsSrv)
1562  break;
1563 
1564  prompt = _("Open newsgroup to attach message from");
1565  OptNews = true;
1566  }
1567 #endif
1568 
1569  if (Context)
1570 #ifdef USE_NNTP
1571  if ((op == OP_COMPOSE_ATTACH_MESSAGE) ^ (Context->mailbox->magic == MUTT_NNTP))
1572 #endif
1573  {
1574  mutt_str_strfcpy(buf, mailbox_path(Context->mailbox), sizeof(buf));
1575  mutt_pretty_mailbox(buf, sizeof(buf));
1576  }
1577 
1578  if ((mutt_enter_fname(prompt, buf, sizeof(buf), true) == -1) || (buf[0] == '\0'))
1579  break;
1580 
1581 #ifdef USE_NNTP
1582  if (OptNews)
1583  nntp_expand_path(buf, sizeof(buf), &CurrentNewsSrv->conn->account);
1584  else
1585 #endif
1586  mutt_expand_path(buf, sizeof(buf));
1587 #ifdef USE_IMAP
1588  if (imap_path_probe(buf, NULL) != MUTT_IMAP)
1589 #endif
1590 #ifdef USE_POP
1591  if (pop_path_probe(buf, NULL) != MUTT_POP)
1592 #endif
1593 #ifdef USE_NNTP
1594  if (!OptNews && (nntp_path_probe(buf, NULL) != MUTT_NNTP))
1595 #endif
1596  /* check to make sure the file exists and is readable */
1597  if (access(buf, R_OK) == -1)
1598  {
1599  mutt_perror(buf);
1600  break;
1601  }
1602 
1603  menu->redraw = REDRAW_FULL;
1604 
1605  struct Mailbox *m = mx_path_resolve(buf);
1606  struct Context *ctx = mx_mbox_open(m, MUTT_READONLY);
1607  if (!ctx)
1608  {
1609  mutt_error(_("Unable to open mailbox %s"), buf);
1610  mailbox_free(&m);
1611  break;
1612  }
1613 
1614  if (ctx->mailbox->msg_count == 0)
1615  {
1616  mx_mbox_close(&ctx);
1617  mutt_error(_("No messages in that folder"));
1618  break;
1619  }
1620 
1621  struct Context *ctx_cur = Context; /* remember current folder and sort methods */
1622  int old_sort = C_Sort; /* C_Sort, SortAux could be changed in mutt_index_menu() */
1623  int old_sort_aux = C_SortAux;
1624 
1625  Context = ctx;
1626  OptAttachMsg = true;
1627  mutt_message(_("Tag the messages you want to attach"));
1628  op_close = mutt_index_menu();
1629  OptAttachMsg = false;
1630 
1631  if (!Context)
1632  {
1633  /* go back to the folder we started from */
1634  Context = ctx_cur;
1635  /* Restore old $sort and $sort_aux */
1636  C_Sort = old_sort;
1637  C_SortAux = old_sort_aux;
1638  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1639  break;
1640  }
1641 
1642  for (int i = 0; i < Context->mailbox->msg_count; i++)
1643  {
1644  if (!message_is_tagged(Context, i))
1645  continue;
1646 
1647  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1649  Context->mailbox->emails[i], true);
1650  if (ap->content)
1651  update_idx(menu, actx, ap);
1652  else
1653  {
1654  mutt_error(_("Unable to attach"));
1655  FREE(&ap);
1656  }
1657  }
1658  menu->redraw |= REDRAW_FULL;
1659 
1660  if (op_close == OP_QUIT)
1662  else
1663  {
1665  ctx_free(&Context);
1666  }
1667 
1668  /* go back to the folder we started from */
1669  Context = ctx_cur;
1670  /* Restore old $sort and $sort_aux */
1671  C_Sort = old_sort;
1672  C_SortAux = old_sort_aux;
1674  break;
1675  }
1676 
1677  case OP_DELETE:
1678  CHECK_COUNT;
1679  if (CUR_ATTACH->unowned)
1680  CUR_ATTACH->content->unlink = false;
1681  if (delete_attachment(actx, menu->current) == -1)
1682  break;
1683  mutt_update_compose_menu(actx, menu, false);
1684  if (menu->current == 0)
1685  e->content = actx->idx[0]->content;
1686 
1688  break;
1689 
1690  case OP_COMPOSE_TOGGLE_RECODE:
1691  {
1692  CHECK_COUNT;
1693  if (!mutt_is_text_part(CUR_ATTACH->content))
1694  {
1695  mutt_error(_("Recoding only affects text attachments"));
1696  break;
1697  }
1698  CUR_ATTACH->content->noconv = !CUR_ATTACH->content->noconv;
1699  if (CUR_ATTACH->content->noconv)
1700  mutt_message(_("The current attachment won't be converted"));
1701  else
1702  mutt_message(_("The current attachment will be converted"));
1703  menu->redraw = REDRAW_CURRENT;
1705  break;
1706  }
1707 
1708  case OP_COMPOSE_EDIT_DESCRIPTION:
1709  CHECK_COUNT;
1711  buf, CUR_ATTACH->content->description ? CUR_ATTACH->content->description : "",
1712  sizeof(buf));
1713  /* header names should not be translated */
1714  if (mutt_get_field("Description: ", buf, sizeof(buf), 0) == 0)
1715  {
1716  mutt_str_replace(&CUR_ATTACH->content->description, buf);
1717  menu->redraw = REDRAW_CURRENT;
1718  }
1720  break;
1721 
1722  case OP_COMPOSE_UPDATE_ENCODING:
1723  CHECK_COUNT;
1724  if (menu->tagprefix)
1725  {
1726  struct Body *top = NULL;
1727  for (top = e->content; top; top = top->next)
1728  {
1729  if (top->tagged)
1730  mutt_update_encoding(top);
1731  }
1732  menu->redraw = REDRAW_FULL;
1733  }
1734  else
1735  {
1736  mutt_update_encoding(CUR_ATTACH->content);
1738  }
1740  break;
1741 
1742  case OP_COMPOSE_TOGGLE_DISPOSITION:
1743  /* toggle the content-disposition between inline/attachment */
1744  CUR_ATTACH->content->disposition =
1745  (CUR_ATTACH->content->disposition == DISP_INLINE) ? DISP_ATTACH : DISP_INLINE;
1746  menu->redraw = REDRAW_CURRENT;
1747  break;
1748 
1749  case OP_EDIT_TYPE:
1750  CHECK_COUNT;
1751  {
1752  mutt_edit_content_type(NULL, CUR_ATTACH->content, NULL);
1753 
1754  /* this may have been a change to text/something */
1755  mutt_update_encoding(CUR_ATTACH->content);
1756 
1757  menu->redraw = REDRAW_CURRENT;
1758  }
1760  break;
1761 
1762  case OP_COMPOSE_EDIT_LANGUAGE:
1763  CHECK_COUNT;
1764  buf[0] = '\0'; /* clear buffer first */
1765  if (CUR_ATTACH->content->language)
1766  mutt_str_strfcpy(buf, CUR_ATTACH->content->language, sizeof(buf));
1767  if (mutt_get_field("Content-Language: ", buf, sizeof(buf), 0) == 0)
1768  {
1769  CUR_ATTACH->content->language = mutt_str_strdup(buf);
1771  mutt_clear_error();
1772  }
1773  else
1774  mutt_warning(_("Empty 'Content-Language'"));
1776  break;
1777 
1778  case OP_COMPOSE_EDIT_ENCODING:
1779  CHECK_COUNT;
1780  mutt_str_strfcpy(buf, ENCODING(CUR_ATTACH->content->encoding), sizeof(buf));
1781  if ((mutt_get_field("Content-Transfer-Encoding: ", buf, sizeof(buf), 0) == 0) &&
1782  (buf[0] != '\0'))
1783  {
1784  int enc = mutt_check_encoding(buf);
1785  if ((enc != ENC_OTHER) && (enc != ENC_UUENCODED))
1786  {
1787  CUR_ATTACH->content->encoding = enc;
1789  mutt_clear_error();
1790  }
1791  else
1792  mutt_error(_("Invalid encoding"));
1793  }
1795  break;
1796 
1797  case OP_COMPOSE_SEND_MESSAGE:
1798  /* Note: We don't invoke send2-hook here, since we want to leave
1799  * users an opportunity to change settings from the ":" prompt. */
1800  if (check_attachments(actx) != 0)
1801  {
1802  menu->redraw = REDRAW_FULL;
1803  break;
1804  }
1805 
1806 #ifdef MIXMASTER
1807  if (!STAILQ_EMPTY(&e->chain) && (mix_check_message(e) != 0))
1808  break;
1809 #endif
1810 
1811  if (!fcc_set && *fcc)
1812  {
1813  enum QuadOption ans =
1814  query_quadoption(C_Copy, _("Save a copy of this message?"));
1815  if (ans == MUTT_ABORT)
1816  break;
1817  else if (ans == MUTT_NO)
1818  *fcc = '\0';
1819  }
1820 
1821  loop = false;
1822  rc = 0;
1823  break;
1824 
1825  case OP_COMPOSE_EDIT_FILE:
1826  CHECK_COUNT;
1827  mutt_edit_file(NONULL(C_Editor), CUR_ATTACH->content->filename);
1828  mutt_update_encoding(CUR_ATTACH->content);
1831  break;
1832 
1833  case OP_COMPOSE_TOGGLE_UNLINK:
1834  CHECK_COUNT;
1835  CUR_ATTACH->content->unlink = !CUR_ATTACH->content->unlink;
1836 
1837  menu->redraw = REDRAW_INDEX;
1838  /* No send2hook since this doesn't change the message. */
1839  break;
1840 
1841  case OP_COMPOSE_GET_ATTACHMENT:
1842  CHECK_COUNT;
1843  if (menu->tagprefix)
1844  {
1845  for (struct Body *top = e->content; top; top = top->next)
1846  {
1847  if (top->tagged)
1849  }
1850  menu->redraw = REDRAW_FULL;
1851  }
1852  else if (mutt_get_tmp_attachment(CUR_ATTACH->content) == 0)
1853  menu->redraw = REDRAW_CURRENT;
1854 
1855  /* No send2hook since this doesn't change the message. */
1856  break;
1857 
1858  case OP_COMPOSE_RENAME_ATTACHMENT:
1859  {
1860  CHECK_COUNT;
1861  char *src = NULL;
1862  if (CUR_ATTACH->content->d_filename)
1863  src = CUR_ATTACH->content->d_filename;
1864  else
1865  src = CUR_ATTACH->content->filename;
1866  mutt_str_strfcpy(buf, mutt_path_basename(NONULL(src)), sizeof(buf));
1867  int ret = mutt_get_field(_("Send attachment with name: "), buf, sizeof(buf), MUTT_FILE);
1868  if (ret == 0)
1869  {
1870  /* As opposed to RENAME_FILE, we don't check buf[0] because it's
1871  * valid to set an empty string here, to erase what was set */
1872  mutt_str_replace(&CUR_ATTACH->content->d_filename, buf);
1873  menu->redraw = REDRAW_CURRENT;
1874  }
1875  break;
1876  }
1877 
1878  case OP_COMPOSE_RENAME_FILE:
1879  CHECK_COUNT;
1880  mutt_str_strfcpy(buf, CUR_ATTACH->content->filename, sizeof(buf));
1881  mutt_pretty_mailbox(buf, sizeof(buf));
1882  if ((mutt_get_field(_("Rename to: "), buf, sizeof(buf), MUTT_FILE) == 0) &&
1883  (buf[0] != '\0'))
1884  {
1885  struct stat st;
1886  if (stat(CUR_ATTACH->content->filename, &st) == -1)
1887  {
1888  /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */
1889  mutt_error(_("Can't stat %s: %s"), buf, strerror(errno));
1890  break;
1891  }
1892 
1893  mutt_expand_path(buf, sizeof(buf));
1894  if (mutt_file_rename(CUR_ATTACH->content->filename, buf))
1895  break;
1896 
1897  mutt_str_replace(&CUR_ATTACH->content->filename, buf);
1898  menu->redraw = REDRAW_CURRENT;
1899 
1900  if (CUR_ATTACH->content->stamp >= st.st_mtime)
1902  }
1904  break;
1905 
1906  case OP_COMPOSE_NEW_MIME:
1907  {
1908  buf[0] = '\0';
1909  if ((mutt_get_field(_("New file: "), buf, sizeof(buf), MUTT_FILE) != 0) ||
1910  (buf[0] == '\0'))
1911  {
1912  continue;
1913  }
1914  mutt_expand_path(buf, sizeof(buf));
1915 
1916  /* Call to lookup_mime_type () ? maybe later */
1917  char type[256] = { 0 };
1918  if ((mutt_get_field("Content-Type: ", type, sizeof(type), 0) != 0) ||
1919  (type[0] == '\0'))
1920  {
1921  continue;
1922  }
1923 
1924  char *p = strchr(type, '/');
1925  if (!p)
1926  {
1927  mutt_error(_("Content-Type is of the form base/sub"));
1928  continue;
1929  }
1930  *p++ = 0;
1931  enum ContentType itype = mutt_check_mime_type(type);
1932  if (itype == TYPE_OTHER)
1933  {
1934  mutt_error(_("Unknown Content-Type %s"), type);
1935  continue;
1936  }
1937  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1938  /* Touch the file */
1939  FILE *fp = mutt_file_fopen(buf, "w");
1940  if (!fp)
1941  {
1942  mutt_error(_("Can't create file %s"), buf);
1943  FREE(&ap);
1944  continue;
1945  }
1946  mutt_file_fclose(&fp);
1947 
1948  ap->content = mutt_make_file_attach(buf);
1949  if (!ap->content)
1950  {
1951  mutt_error(_("What we have here is a failure to make an attachment"));
1952  FREE(&ap);
1953  continue;
1954  }
1955  update_idx(menu, actx, ap);
1956 
1957  CUR_ATTACH->content->type = itype;
1958  mutt_str_replace(&CUR_ATTACH->content->subtype, p);
1959  CUR_ATTACH->content->unlink = true;
1960  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1961 
1962  if (mutt_compose_attachment(CUR_ATTACH->content))
1963  {
1964  mutt_update_encoding(CUR_ATTACH->content);
1965  menu->redraw = REDRAW_FULL;
1966  }
1968  break;
1969  }
1970 
1971  case OP_COMPOSE_EDIT_MIME:
1972  CHECK_COUNT;
1973  if (mutt_edit_attachment(CUR_ATTACH->content))
1974  {
1975  mutt_update_encoding(CUR_ATTACH->content);
1976  menu->redraw = REDRAW_FULL;
1977  }
1979  break;
1980 
1981  case OP_VIEW_ATTACH:
1982  case OP_DISPLAY_HEADERS:
1983  CHECK_COUNT;
1984  mutt_attach_display_loop(menu, op, NULL, actx, false);
1985  menu->redraw = REDRAW_FULL;
1986  /* no send2hook, since this doesn't modify the message */
1987  break;
1988 
1989  case OP_SAVE:
1990  CHECK_COUNT;
1991  mutt_save_attachment_list(actx, NULL, menu->tagprefix,
1992  CUR_ATTACH->content, NULL, menu);
1993  /* no send2hook, since this doesn't modify the message */
1994  break;
1995 
1996  case OP_PRINT:
1997  CHECK_COUNT;
1998  mutt_print_attachment_list(actx, NULL, menu->tagprefix, CUR_ATTACH->content);
1999  /* no send2hook, since this doesn't modify the message */
2000  break;
2001 
2002  case OP_PIPE:
2003  case OP_FILTER:
2004  CHECK_COUNT;
2005  mutt_pipe_attachment_list(actx, NULL, menu->tagprefix,
2006  CUR_ATTACH->content, (op == OP_FILTER));
2007  if (op == OP_FILTER) /* cte might have changed */
2008  menu->redraw = menu->tagprefix ? REDRAW_FULL : REDRAW_CURRENT;
2009  menu->redraw |= REDRAW_STATUS;
2011  break;
2012 
2013  case OP_EXIT:
2014  {
2015  enum QuadOption ans =
2016  query_quadoption(C_Postpone, _("Save (postpone) draft message?"));
2017  if (ans == MUTT_NO)
2018  {
2019  for (int i = 0; i < actx->idxlen; i++)
2020  if (actx->idx[i]->unowned)
2021  actx->idx[i]->content->unlink = false;
2022 
2023  if (!(flags & MUTT_COMPOSE_NOFREEHEADER))
2024  {
2025  for (int i = 0; i < actx->idxlen; i++)
2026  {
2027  /* avoid freeing other attachments */
2028  actx->idx[i]->content->next = NULL;
2029  actx->idx[i]->content->parts = NULL;
2030  mutt_body_free(&actx->idx[i]->content);
2031  }
2032  }
2033  rc = -1;
2034  loop = false;
2035  break;
2036  }
2037  else if (ans == MUTT_ABORT)
2038  break; /* abort */
2039  }
2040  /* fallthrough */
2041 
2042  case OP_COMPOSE_POSTPONE_MESSAGE:
2043  if (check_attachments(actx) != 0)
2044  {
2045  menu->redraw = REDRAW_FULL;
2046  break;
2047  }
2048 
2049  loop = false;
2050  rc = 1;
2051  break;
2052 
2053  case OP_COMPOSE_ISPELL:
2054  endwin();
2055  snprintf(buf, sizeof(buf), "%s -x %s", NONULL(C_Ispell), e->content->filename);
2056  if (mutt_system(buf) == -1)
2057  mutt_error(_("Error running \"%s\""), buf);
2058  else
2059  {
2061  menu->redraw |= REDRAW_STATUS;
2062  }
2063  break;
2064 
2065  case OP_COMPOSE_WRITE_MESSAGE:
2066  buf[0] = '\0';
2067  if (Context)
2068  {
2069  mutt_str_strfcpy(buf, mailbox_path(Context->mailbox), sizeof(buf));
2070  mutt_pretty_mailbox(buf, sizeof(buf));
2071  }
2072  if (actx->idxlen)
2073  e->content = actx->idx[0]->content;
2074  if ((mutt_enter_fname(_("Write message to mailbox"), buf, sizeof(buf), true) != -1) &&
2075  (buf[0] != '\0'))
2076  {
2077  mutt_message(_("Writing message to %s ..."), buf);
2078  mutt_expand_path(buf, sizeof(buf));
2079 
2080  if (e->content->next)
2082 
2083  if (mutt_write_fcc(buf, e, NULL, false, NULL, NULL) < 0)
2085  else
2086  mutt_message(_("Message written"));
2087  }
2088  break;
2089 
2090  case OP_COMPOSE_PGP_MENU:
2091  if (!(WithCrypto & APPLICATION_PGP))
2092  break;
2093  if (!crypt_has_module_backend(APPLICATION_PGP))
2094  {
2095  mutt_error(_("No PGP backend configured"));
2096  break;
2097  }
2098  if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
2099  {
2100  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
2101  {
2102  if (mutt_yesorno(_("S/MIME already selected. Clear and continue?"), MUTT_YES) != MUTT_YES)
2103  {
2104  mutt_clear_error();
2105  break;
2106  }
2107  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2108  }
2109  e->security &= ~APPLICATION_SMIME;
2110  e->security |= APPLICATION_PGP;
2111  update_crypt_info(rd);
2112  }
2113  e->security = crypt_pgp_send_menu(e);
2114  update_crypt_info(rd);
2116  break;
2117 
2118  case OP_FORGET_PASSPHRASE:
2120  break;
2121 
2122  case OP_COMPOSE_SMIME_MENU:
2123  if (!(WithCrypto & APPLICATION_SMIME))
2124  break;
2125  if (!crypt_has_module_backend(APPLICATION_SMIME))
2126  {
2127  mutt_error(_("No S/MIME backend configured"));
2128  break;
2129  }
2130 
2131  if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
2132  {
2133  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
2134  {
2135  if (mutt_yesorno(_("PGP already selected. Clear and continue?"), MUTT_YES) != MUTT_YES)
2136  {
2137  mutt_clear_error();
2138  break;
2139  }
2140  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2141  }
2142  e->security &= ~APPLICATION_PGP;
2144  update_crypt_info(rd);
2145  }
2147  update_crypt_info(rd);
2149  break;
2150 
2151 #ifdef MIXMASTER
2152  case OP_COMPOSE_MIX:
2153  mix_make_chain(&e->chain);
2155  break;
2156 #endif
2157 #ifdef USE_AUTOCRYPT
2158  case OP_COMPOSE_AUTOCRYPT_MENU:
2159  if (!C_Autocrypt)
2160  break;
2161 
2162  if ((WithCrypto & APPLICATION_SMIME) && (e->security & APPLICATION_SMIME))
2163  {
2164  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
2165  {
2166  if (mutt_yesorno(_("S/MIME already selected. Clear and continue?"), MUTT_YES) != MUTT_YES)
2167  {
2168  mutt_clear_error();
2169  break;
2170  }
2171  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2172  }
2173  e->security &= ~APPLICATION_SMIME;
2174  e->security |= APPLICATION_PGP;
2175  update_crypt_info(rd);
2176  }
2178  update_crypt_info(rd);
2180  break;
2181 #endif
2182  }
2183  }
2184 
2185 #ifdef USE_AUTOCRYPT
2186  /* This is a fail-safe to make sure the bit isn't somehow turned
2187  * on. The user could have disabled the option after setting SEC_AUTOCRYPT,
2188  * or perhaps resuming or replying to an autocrypt message. */
2189  if (!C_Autocrypt)
2190  e->security &= ~SEC_AUTOCRYPT;
2191 #endif
2192 
2193  mutt_menu_pop_current(menu);
2194  mutt_menu_free(&menu);
2195 
2196  if (actx->idxlen)
2197  e->content = actx->idx[0]->content;
2198  else
2199  e->content = NULL;
2200 
2201  mutt_actx_free(&actx);
2202 
2203  return rc;
2204 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
#define mutt_warning(...)
Definition: logging.h:82
The "current" mailbox.
Definition: context.h:36
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:194
struct NntpAccountData * nntp_select_server(struct Mailbox *m, char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:982
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg)
Create a message attachment.
Definition: sendlib.c:1486
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t *callback, unsigned long data, MuttFormatFlags flags)
Expand expandos (x) in a string.
Definition: muttlib.c:844
static int delete_attachment(struct AttachCtx *actx, int x)
Delete an attachment.
Definition: compose.c:730
Header labels, e.g. From:
Definition: mutt_curses.h:168
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:1418
Unknown Content-Type.
Definition: mime.h:31
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
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
Manage keymappings.
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
#define SEC_AUTOCRYPT
Message will be, or was Autocrypt encrypt+signed.
Definition: ncrypt.h:131
WHERE bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: globals.h:205
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
An email to which things will be attached.
Definition: attach.h:34
int mutt_attach_display_loop(struct Menu *menu, int op, struct Email *e, struct AttachCtx *actx, bool recv)
Event loop for the Attachment menu.
Definition: recvattach.c:1146
Define wrapper functions around Curses/Slang.
int msg_count
Total number of messages.
Definition: mailbox.h:102
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: sendlib.c:1742
Representation of the email&#39;s header.
static const char * compose_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, unsigned long data, MuttFormatFlags flags)
Create the status bar string for compose mode - Implements format_t.
Definition: compose.c:973
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:304
The envelope/body of an email.
Definition: email.h:39
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:70
#define mutt_perror(...)
Definition: logging.h:85
GUI editor for an email&#39;s headers.
#define MUTT_ALIAS
Do alias "completion" by calling up the alias-menu.
Definition: mutt.h:65
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:51
GUI selectable list of items.
Definition: mutt_menu.h:82
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2425
struct ConnAccount account
Definition: connection.h:36
Window management.
WHERE char * C_AttachFormat
Config: printf-like format string for the attachment menu.
Definition: globals.h:104
GUI miscellaneous curses (window drawing) routines.
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:51
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:558
Structs that make up an email.
The "currently-open" mailbox.
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
Mail will not be encrypted or signed.
Definition: mutt_curses.h:172
User aborted the question (with Ctrl-G)
Definition: quad.h:37
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3331
GUI manage the main index (list of emails)
#define mutt_message(...)
Definition: logging.h:83
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1332
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1298
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:1381
#define NORMAL_COLOR
Definition: mutt_curses.h:239
static void compose_custom_redraw(struct Menu *menu)
Redraw the compose menu - Implements Menu::menu_custom_redraw()
Definition: compose.c:844
#define SEC_AUTOCRYPT_OVERRIDE
Indicates manual set/unset of encryption.
Definition: ncrypt.h:132
Mail will be encrypted.
Definition: mutt_curses.h:169
static void edit_address_list(int line, struct AddressList *al, struct ComposeRedrawData *rd)
Let the user edit the address list.
Definition: compose.c:695
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:651
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:107
NeoMutt Logging.
"To:" field
Definition: compose.c:119
static const char * There_are_no_attachments
Definition: compose.c:97
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
struct Body * content
List of MIME parts.
Definition: email.h:92
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:105
"Cc:" field
Definition: compose.c:120
int mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:254
static void calc_header_width_padding(int idx, const char *header, bool calc_max)
Calculate the width needed for the compose labels.
Definition: compose.c:264
int MaxHeaderWidth
Definition: compose.c:143
#define _(a)
Definition: message.h:28
static void update_crypt_info(struct ComposeRedrawData *rd)
Update the crypto info.
Definition: compose.c:490
struct Body * next
next attachment in the list
Definition: body.h:53
short idxlen
Number of attachmentes.
Definition: attach.h:55
Compose an email.
Definition: keymap.h:64
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:254
WHERE unsigned char C_Copy
Config: Save outgoing emails to $record.
Definition: globals.h:186
#define SEC_INLINE
Email has an inline signature.
Definition: ncrypt.h:129
A division of the screen.
Definition: mutt_window.h:35
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:40
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
struct Email * email
Definition: compose.c:249
char * C_Ispell
Config: External command to perform spell-checking.
Definition: compose.c:94
long hibin
8-bit characters
Definition: content.h:35
size_t mutt_addrlist_write(char *buf, size_t buflen, const struct AddressList *al, bool display)
Write an Address to a buffer.
Definition: address.c:1137
AutocryptRec
Recommendation.
Definition: autocrypt.h:101
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:53
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:606
"Subject:" field
Definition: compose.c:122
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:312
#define MUTT_FORMAT_STAT_FILE
Used by attach_format_str.
Definition: format_flags.h:34
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:122
static int check_attachments(struct AttachCtx *actx)
Check if any attachments have changed or been deleted.
Definition: compose.c:574
"Sign as:" field (encryption/signing info)
Definition: compose.c:129
Flags to control mutt_expando_format()
"From:" field
Definition: compose.c:118
All user-callable functions.
static void mutt_gen_compose_attach_list(struct AttachCtx *actx, struct Body *m, int parent_type, int level)
Generate the attachment list for the compose screen.
Definition: compose.c:771
void(* menu_make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:120
Representation of a single alias to an email address.
The "-- Attachments" line.
Definition: compose.c:138
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:86
The body of an email.
Definition: body.h:34
#define REDRAW_SIDEBAR
Redraw the sidebar.
Definition: mutt_menu.h:51
Mail will be signed.
Definition: mutt_curses.h:170
unsigned int disposition
content-disposition
Definition: body.h:67
struct Content * mutt_get_content_info(const char *fname, struct Body *b)
Analyze file to determine MIME encoding to use.
Definition: sendlib.c:1013
Convenience wrapper for the config headers.
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1173
GUI component for displaying/selecting items from a list.
Hundreds of global variables to back the user variables.
Email Address Handling.
Mail will be encrypted and signed.
Definition: mutt_curses.h:171
static void snd_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the attachment list - Implements Menu::menu_make_entry()
Definition: compose.c:314
char * tree
Tree characters to display.
Definition: attach.h:39
Assorted sorting methods.
#define CUR_ATTACH
Definition: compose.c:109
Some miscellaneous functions.
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
void * redraw_data
Definition: mutt_menu.h:150
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:1029
int mutt_get_tmp_attachment(struct Body *a)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:65
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
WHERE bool C_EditHeaders
Config: Let the user edit the email headers whilst editing an email.
Definition: globals.h:217
struct Mailbox * mailbox
Definition: context.h:50
Parse and execute user-defined hooks.
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
int mutt_enter_fname_full(const char *prompt, char *buf, size_t buflen, bool mailbox, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file.
Definition: curs_lib.c:626
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:453
API for mailboxes.
enum AutocryptRec autocrypt_rec
Definition: compose.c:252
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: sendlib.c:604
struct Body * mutt_make_file_attach(const char *path)
Create a file attachment.
Definition: sendlib.c:1620
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:55
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:317
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
int crypt_smime_send_menu(struct Email *e)
Wrapper for CryptModuleSpecs::send_menu()
Definition: cryptglue.c:528
void mutt_update_encoding(struct Body *a)
Update the encoding type.
Definition: sendlib.c:1455
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:150
IMAP network mailbox.
static void draw_envelope(struct ComposeRedrawData *rd)
Write the email headers to the compose window.
Definition: compose.c:629
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:38
struct Envelope * env
Envelope information.
Definition: email.h:91
Convenience wrapper for the core headers.
#define ENCODING(x)
Definition: mime.h:85
POP network mailbox.
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:392
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
"X-Comment-To:" field
Definition: compose.c:136
Content is attached.
Definition: mime.h:63
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:307
static void compose_attach_swap(struct Body *msg, struct AttachPtr **idx, short first)
Swap two adjacent entries in the attachment list.
Definition: compose.c:893
void(* menu_custom_redraw)(struct Menu *menu)
Redraw the menu.
Definition: mutt_menu.h:149
struct AttachCtx * mutt_actx_new(void)
Create a new Attachment Context.
Definition: attach.c:131
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
bool tagged
This attachment is tagged.
Definition: body.h:70
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:109
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
static void compose_status_line(char *buf, size_t buflen, size_t col, int cols, struct Menu *menu, const char *p)
Compose the string for the status bar.
Definition: compose.c:1031
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:43
bool unowned
Don&#39;t unlink on detach.
Definition: attach.h:42
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: sendlib.c:1716
char * subtype
content-type subtype
Definition: body.h:37
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:44
Info about an attachment.
Definition: content.h:33
WHERE char * C_NewsServer
Config: (nntp) Url of the news server.
Definition: globals.h:134
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:843
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:94
Prototypes for many functions.
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
const char * line
Definition: common.c:36
WHERE short C_SortAux
Config: Secondary sort method for the index.
Definition: sort.h:59
#define HDR_XOFFSET
Definition: compose.c:145
#define SEC_SIGN
Email is signed.
Definition: ncrypt.h:123
struct MuttWindow * statuswin
Definition: mutt_menu.h:96
WHERE struct Context * Context
Definition: globals.h:42
int attach_tag(struct Menu *menu, int sel, int act)
Tag an attachment - Implements Menu::menu_tag()
Definition: recvattach.c:447
WHERE bool C_CryptOpportunisticEncrypt
Config: Enable encryption when the recipient&#39;s key is available.
Definition: globals.h:280
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
&#39;POP3&#39; Mailbox type
Definition: mailbox.h:54
#define REDRAW_STATUS
Redraw the status bar.
Definition: mutt_menu.h:46
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:426
#define ALTS_TAG
int mutt_compose_menu(struct Email *e, char *fcc, size_t fcclen, struct Email *e_cur, int flags)
Allow the user to edit the message envelope.
Definition: compose.c:1049
A mailbox.
Definition: mailbox.h:92
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1266
#define PATH_MAX
Definition: mutt.h:52
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:40
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
struct MuttWindow * indexwin
Definition: mutt_menu.h:95
int num
Attachment index number.
Definition: attach.h:41
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1331
bool tagprefix
Definition: mutt_menu.h:93
long ascii
Number of ascii chars.
Definition: content.h:39
Manage where the email is piped to external commands.
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:57
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1727
Autocrypt should be used.
Definition: autocrypt.h:107
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
WHERE char * C_SmimeEncryptWith
Config: Algorithm for encryption.
Definition: globals.h:173
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:750
int crypt_pgp_send_menu(struct Email *e)
Wrapper for CryptModuleSpecs::send_menu()
Definition: cryptglue.c:373
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
GUI present the user with a selectable list.
void mix_make_chain(struct ListHead *chainhead)
Create a Mixmaster chain.
Definition: remailer.c:563
static void mutt_update_compose_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Redraw the compose window.
Definition: compose.c:801
Handling of email attachments.
API for encryption/signing of emails.
static void draw_envelope_addr(int line, struct AddressList *al, struct ComposeRedrawData *rd)
Write addresses to the compose window.
Definition: compose.c:613
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:612
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * description
content-description
Definition: body.h:40
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:92
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:433
"Security:" field (encryption/signing info)
Definition: compose.c:128
static const char *const Prompts[]
Definition: compose.c:148
#define STAILQ_NEXT(elm, field)
Definition: queue.h:398
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/ncrypt.h pgplib.h, smime.h
Definition: email.h:41
#define W
Definition: compose.c:146
#define SET_COLOR(X)
Definition: mutt_curses.h:224
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: browser.h:46
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
int mutt_window_mvaddstr(struct MuttWindow *win, int row, int col, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:202
int tagged
Number of tagged entries.
Definition: mutt_menu.h:111
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:549
#define MUTT_FILE
Do file completion.
Definition: mutt.h:66
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:188
unsigned int type
content-type primary type
Definition: body.h:65
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: ncrypt.h:130
int autocrypt_rec_override
Definition: compose.c:253
int(* menu_tag)(struct Menu *menu, int sel, int act)
Tag some menu items.
Definition: mutt_menu.h:137
static void redraw_crypt_lines(struct ComposeRedrawData *rd)
Update the encryption info in the compose window.
Definition: compose.c:368
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:134
"Bcc:" field
Definition: compose.c:121
"Followup-To:" field
Definition: compose.c:135
#define LINGUAL_TAG
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
bool crypt_has_module_backend(SecurityFlags type)
Is there a crypto backend for a given type?
Definition: cryptglue.c:159
static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
Add a new attchment to the message.
Definition: compose.c:830
struct Connection * conn
Definition: nntp.h:102
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:879
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope&#39;s Address fields to local format.
Definition: envelope.c:274
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1030
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition: cryptglue.c:295
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition: attach.c:103
int offset
Row offset within the window to start the index.
Definition: mutt_menu.h:91
GUI basic built-in text editor.
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:36
char * data
String.
Definition: list.h:35
char * subject
Email&#39;s subject.
Definition: envelope.h:66
struct MuttWindow * win
Definition: compose.c:255
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
enum AutocryptRec mutt_autocrypt_ui_recommendation(struct Email *e, char **keylist)
Get the recommended action for an Email.
Definition: autocrypt.c:562
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1216
Routines for managing attachments.
static unsigned long cum_attachs_size(struct Menu *menu)
Cumulative Attachments Size.
Definition: compose.c:927
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
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
WHERE bool C_XCommentTo
Config: (nntp) Add &#39;X-Comment-To&#39; header that contains article author.
Definition: globals.h:294
short * v2r
Mapping from virtual to real attachment.
Definition: attach.h:58
struct Body * content
Attachment.
Definition: attach.h:36
Autocrypt end-to-end encryption.
const char * attach_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, unsigned long data, MuttFormatFlags flags)
Format a string for the attachment menu - Implements format_t.
Definition: recvattach.c:210
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
int HeaderPadding[HDR_ATTACH_TITLE]
Definition: compose.c:142
unsigned char C_Postpone
Config: Save messages to the C_Postponed folder.
Definition: compose.c:95
#define mutt_error(...)
Definition: logging.h:84
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:402
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe()
Definition: pop.c:1231
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
Quoted-printable text.
Definition: mime.h:51
Connection Library.
static void autocrypt_compose_menu(struct Email *e)
Autocrypt compose settings.
Definition: compose.c:328
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:144
WHERE char * C_Editor
Config: External command to use as an email editor.
Definition: globals.h:114
void mutt_edit_headers(const char *editor, const char *body, struct Email *e, char *fcc, size_t fcclen)
Let the user edit the message header and body.
Definition: mutt_header.c:168
HeaderField
Ordered list of headers for the compose screen.
Definition: compose.c:116
long crlf
\r and \n characters
Definition: content.h:38
#define mutt_enter_fname(prompt, buf, buflen, mailbox)
Definition: curs_lib.h:85
WHERE char * ShortHostname
Short version of the hostname.
Definition: globals.h:50
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1539
Status bar.
Definition: mutt_curses.h:129
void * data
Extra data for the current menu.
Definition: mutt_menu.h:86
#define MUTT_COMPOSE_NOFREEHEADER
Definition: compose.h:36
Mapping between user-readable string and a constant.
Definition: mapping.h:29
#define STAILQ_EMPTY(head)
Definition: queue.h:346
Where to start printing the attachments.
Definition: compose.c:139
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
int mutt_window_mvprintw(struct MuttWindow *win, int row, int col, const char *fmt,...)
Move the cursor and write a formatted string to a Window.
Definition: mutt_window.c:217
"Newsgroups:" field
Definition: compose.c:134
static void init_header_padding(void)
Calculate how much padding the compose table will need.
Definition: compose.c:283
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:48
Handling of global boolean variables.
Miscellaneous functions for sending an email.
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:579
char * C_ComposeFormat
Config: printf-like format string for the Compose panel&#39;s status bar.
Definition: compose.c:93
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe()
Definition: nntp.c:2825
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1216
int current
Current entry.
Definition: mutt_menu.h:87
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:44
"Fcc:" (save folder) field
Definition: compose.c:124
#define CHECK_COUNT
Definition: compose.c:102
WHERE char * C_PgpSignAs
Config: Use this alternative key for signing messages.
Definition: globals.h:168
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:583
int mutt_index_menu(void)
Display a list of emails.
Definition: index.c:1034
char * mutt_compile_help(char *buf, size_t buflen, enum MenuType menu, const struct Mapping *items)
Create the text for the help menu.
Definition: help.c:115
WHERE char * C_SmimeSignAs
Config: Use this alternative key for signing messages.
Definition: globals.h:172
A List node for strings.
Definition: list.h:33
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:52
#define N_(a)
Definition: message.h:32
static const char * AutocryptRecUiFlags[]
Definition: compose.c:220
#define WithCrypto
Definition: ncrypt.h:160
A set of attachments.
Definition: attach.h:49
int level
Nesting depth of attachment.
Definition: attach.h:40
Encoding unknown.
Definition: mime.h:48
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:308
Convenience wrapper for the library headers.
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:43
char * help
Quickref for the current menu.
Definition: mutt_menu.h:85
Keep track when the compose screen needs redrawing.
Definition: compose.c:247
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
UUEncoded text.
Definition: mime.h:54
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: context.c:343
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:45
Support of Mixmaster anonymous remailer.
int mutt_compose_attachment(struct Body *a)
Create an attachment.
Definition: mutt_attach.c:115
int mix_check_message(struct Email *e)
Safety-check the message before passing it to mixmaster.
Definition: remailer.c:780
Usenet network mailbox type; talk to an NNTP server.
short vcount
The number of virtual attachments.
Definition: attach.h:59
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:75
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1523
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: ncrypt.h:135
ContentType
Content-Type.
Definition: mime.h:29
"Reply-To:" field
Definition: compose.c:123
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath)
Write email to FCC mailbox.
Definition: sendlib.c:3246