NeoMutt  2018-07-16 +2481-68dcde
Teaching an old dog new tricks
DOXYGEN
recvattach.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <limits.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include "mutt/mutt.h"
38 #include "config/lib.h"
39 #include "email/lib.h"
40 #include "core/lib.h"
41 #include "mutt.h"
42 #include "recvattach.h"
43 #include "commands.h"
44 #include "context.h"
45 #include "curs_lib.h"
46 #include "filter.h"
47 #include "format_flags.h"
48 #include "globals.h"
49 #include "handler.h"
50 #include "hdrline.h"
51 #include "hook.h"
52 #include "keymap.h"
53 #include "mailcap.h"
54 #include "mutt_attach.h"
55 #include "mutt_logging.h"
56 #include "mutt_menu.h"
57 #include "mutt_parse.h"
58 #include "mutt_window.h"
59 #include "muttlib.h"
60 #include "mx.h"
61 #include "ncrypt/ncrypt.h"
62 #include "opcodes.h"
63 #include "options.h"
64 #include "recvcmd.h"
65 #include "send.h"
66 #include "sendlib.h"
67 #include "state.h"
68 #ifdef ENABLE_NLS
69 #include <libintl.h>
70 #endif
71 
72 /* These Config Variables are only used in recvattach.c */
75 char *C_AttachSep;
79 
80 static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init);
81 
82 static const char *Mailbox_is_read_only = N_("Mailbox is read-only");
83 
84 #define CHECK_READONLY \
85  if (!Context || !Context->mailbox || Context->mailbox->readonly) \
86  { \
87  mutt_flushinp(); \
88  mutt_error(_(Mailbox_is_read_only)); \
89  break; \
90  }
91 
92 #define CUR_ATTACH actx->idx[actx->v2r[menu->current]]
93 
94 static const struct Mapping AttachHelp[] = {
95  { N_("Exit"), OP_EXIT }, { N_("Save"), OP_SAVE }, { N_("Pipe"), OP_PIPE },
96  { N_("Print"), OP_PRINT }, { N_("Help"), OP_HELP }, { NULL, 0 },
97 };
98 
99 static const char *Function_not_permitted =
100  N_("Function not permitted in attach-message mode");
101 
102 #define CHECK_ATTACH \
103  if (OptAttachMsg) \
104  { \
105  mutt_flushinp(); \
106  mutt_error(_(Function_not_permitted)); \
107  break; \
108  }
109 
116 static void mutt_update_v2r(struct AttachCtx *actx)
117 {
118  int vindex, rindex, curlevel;
119 
120  vindex = 0;
121  rindex = 0;
122 
123  while (rindex < actx->idxlen)
124  {
125  actx->v2r[vindex++] = rindex;
126  if (actx->idx[rindex]->content->collapsed)
127  {
128  curlevel = actx->idx[rindex]->level;
129  do
130  rindex++;
131  while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
132  }
133  else
134  rindex++;
135  }
136 
137  actx->vcount = vindex;
138 }
139 
144 void mutt_update_tree(struct AttachCtx *actx)
145 {
146  char buf[256];
147  char *s = NULL;
148 
149  mutt_update_v2r(actx);
150 
151  for (int vindex = 0; vindex < actx->vcount; vindex++)
152  {
153  const int rindex = actx->v2r[vindex];
154  actx->idx[rindex]->num = vindex;
155  if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
156  {
157  if (actx->idx[rindex]->level)
158  {
159  s = buf + 2 * (actx->idx[rindex]->level - 1);
160  *s++ = (actx->idx[rindex]->content->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
161  *s++ = MUTT_TREE_HLINE;
162  *s++ = MUTT_TREE_RARROW;
163  }
164  else
165  s = buf;
166  *s = '\0';
167  }
168 
169  if (actx->idx[rindex]->tree)
170  {
171  if (mutt_str_strcmp(actx->idx[rindex]->tree, buf) != 0)
172  mutt_str_replace(&actx->idx[rindex]->tree, buf);
173  }
174  else
175  actx->idx[rindex]->tree = mutt_str_strdup(buf);
176 
177  if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
178  actx->idx[rindex]->level)
179  {
180  s = buf + 2 * (actx->idx[rindex]->level - 1);
181  *s++ = (actx->idx[rindex]->content->next) ? '\005' : '\006';
182  *s++ = '\006';
183  }
184  }
185 }
186 
210 const char *attach_format_str(char *buf, size_t buflen, size_t col, int cols,
211  char op, const char *src, const char *prec,
212  const char *if_str, const char *else_str,
213  unsigned long data, MuttFormatFlags flags)
214 {
215  char fmt[128];
216  char charset[128];
217  struct AttachPtr *aptr = (struct AttachPtr *) data;
218  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
219 
220  switch (op)
221  {
222  case 'C':
223  if (!optional)
224  {
225  if (mutt_is_text_part(aptr->content) &&
226  mutt_body_get_charset(aptr->content, charset, sizeof(charset)))
227  {
228  mutt_format_s(buf, buflen, prec, charset);
229  }
230  else
231  mutt_format_s(buf, buflen, prec, "");
232  }
233  else if (!mutt_is_text_part(aptr->content) ||
234  !mutt_body_get_charset(aptr->content, charset, sizeof(charset)))
235  {
236  optional = false;
237  }
238  break;
239  case 'c':
240  /* XXX */
241  if (!optional)
242  {
243  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
244  snprintf(buf, buflen, fmt,
245  ((aptr->content->type != TYPE_TEXT) || aptr->content->noconv) ? 'n' : 'c');
246  }
247  else if ((aptr->content->type != TYPE_TEXT) || aptr->content->noconv)
248  optional = false;
249  break;
250  case 'd':
251  if (!optional)
252  {
253  if (aptr->content->description)
254  {
255  mutt_format_s(buf, buflen, prec, aptr->content->description);
256  break;
257  }
258  if (mutt_is_message_type(aptr->content->type, aptr->content->subtype) &&
259  C_MessageFormat && aptr->content->email)
260  {
261  char s[128];
262  mutt_make_string_flags(s, sizeof(s), C_MessageFormat, NULL, NULL,
263  aptr->content->email,
265  if (*s)
266  {
267  mutt_format_s(buf, buflen, prec, s);
268  break;
269  }
270  }
271  if (!aptr->content->d_filename && !aptr->content->filename)
272  {
273  mutt_format_s(buf, buflen, prec, "<no description>");
274  break;
275  }
276  }
277  else if (aptr->content->description ||
278  (mutt_is_message_type(aptr->content->type, aptr->content->subtype) &&
279  C_MessageFormat && aptr->content->email))
280  {
281  break;
282  }
283  /* fallthrough */
284  case 'F':
285  if (!optional)
286  {
287  if (aptr->content->d_filename)
288  {
289  mutt_format_s(buf, buflen, prec, aptr->content->d_filename);
290  break;
291  }
292  }
293  else if (!aptr->content->d_filename && !aptr->content->filename)
294  {
295  optional = false;
296  break;
297  }
298  /* fallthrough */
299  case 'f':
300  if (!optional)
301  {
302  if (aptr->content->filename && (*aptr->content->filename == '/'))
303  {
304  char path[PATH_MAX];
305 
306  mutt_str_strfcpy(path, aptr->content->filename, sizeof(path));
307  mutt_pretty_mailbox(path, sizeof(path));
308  mutt_format_s(buf, buflen, prec, path);
309  }
310  else
311  mutt_format_s(buf, buflen, prec, NONULL(aptr->content->filename));
312  }
313  else if (!aptr->content->filename)
314  optional = false;
315  break;
316  case 'D':
317  if (!optional)
318  snprintf(buf, buflen, "%c", aptr->content->deleted ? 'D' : ' ');
319  else if (!aptr->content->deleted)
320  optional = false;
321  break;
322  case 'e':
323  if (!optional)
324  mutt_format_s(buf, buflen, prec, ENCODING(aptr->content->encoding));
325  break;
326  case 'I':
327  if (!optional)
328  {
329  const char dispchar[] = { 'I', 'A', 'F', '-' };
330  char ch;
331 
332  if (aptr->content->disposition < sizeof(dispchar))
333  ch = dispchar[aptr->content->disposition];
334  else
335  {
336  mutt_debug(LL_DEBUG1, "ERROR: invalid content-disposition %d\n",
337  aptr->content->disposition);
338  ch = '!';
339  }
340  snprintf(buf, buflen, "%c", ch);
341  }
342  break;
343  case 'm':
344  if (!optional)
345  mutt_format_s(buf, buflen, prec, TYPE(aptr->content));
346  break;
347  case 'M':
348  if (!optional)
349  mutt_format_s(buf, buflen, prec, aptr->content->subtype);
350  else if (!aptr->content->subtype)
351  optional = false;
352  break;
353  case 'n':
354  if (!optional)
355  {
356  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
357  snprintf(buf, buflen, fmt, aptr->num + 1);
358  }
359  break;
360  case 'Q':
361  if (optional)
362  optional = aptr->content->attach_qualifies;
363  else
364  {
365  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
366  mutt_format_s(buf, buflen, fmt, "Q");
367  }
368  break;
369  case 's':
370  {
371  size_t l;
372  if (flags & MUTT_FORMAT_STAT_FILE)
373  {
374  struct stat st;
375  stat(aptr->content->filename, &st);
376  l = st.st_size;
377  }
378  else
379  l = aptr->content->length;
380 
381  if (!optional)
382  {
383  char tmp[128];
384  mutt_str_pretty_size(tmp, sizeof(tmp), l);
385  mutt_format_s(buf, buflen, prec, tmp);
386  }
387  else if (l == 0)
388  optional = false;
389 
390  break;
391  }
392  case 't':
393  if (!optional)
394  snprintf(buf, buflen, "%c", aptr->content->tagged ? '*' : ' ');
395  else if (!aptr->content->tagged)
396  optional = false;
397  break;
398  case 'T':
399  if (!optional)
400  mutt_format_s_tree(buf, buflen, prec, NONULL(aptr->tree));
401  else if (!aptr->tree)
402  optional = false;
403  break;
404  case 'u':
405  if (!optional)
406  snprintf(buf, buflen, "%c", aptr->content->unlink ? '-' : ' ');
407  else if (!aptr->content->unlink)
408  optional = false;
409  break;
410  case 'X':
411  if (optional)
412  optional = ((aptr->content->attach_count + aptr->content->attach_qualifies) != 0);
413  else
414  {
415  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
416  snprintf(buf, buflen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
417  }
418  break;
419  default:
420  *buf = '\0';
421  }
422 
423  if (optional)
424  mutt_expando_format(buf, buflen, col, cols, if_str, attach_format_str, data,
426  else if (flags & MUTT_FORMAT_OPTIONAL)
427  mutt_expando_format(buf, buflen, col, cols, else_str, attach_format_str,
428  data, MUTT_FORMAT_NO_FLAGS);
429  return src;
430 }
431 
435 static void attach_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
436 {
437  struct AttachCtx *actx = menu->data;
438 
439  mutt_expando_format(buf, buflen, 0, menu->indexwin->cols, NONULL(C_AttachFormat),
440  attach_format_str, (unsigned long) (actx->idx[actx->v2r[line]]),
442 }
443 
447 int attach_tag(struct Menu *menu, int sel, int act)
448 {
449  struct AttachCtx *actx = menu->data;
450  struct Body *cur = actx->idx[actx->v2r[sel]]->content;
451  bool ot = cur->tagged;
452 
453  cur->tagged = ((act >= 0) ? act : !cur->tagged);
454  return cur->tagged - ot;
455 }
456 
461 static void prepend_savedir(struct Buffer *buf)
462 {
463  if (!buf || !buf->data || (buf->data[0] == '/'))
464  return;
465 
466  struct Buffer *tmp = mutt_buffer_pool_get();
467  if (C_AttachSaveDir)
468  {
470  if (tmp->dptr[-1] != '/')
471  mutt_buffer_addch(tmp, '/');
472  }
473  else
474  mutt_buffer_addstr(tmp, "./");
475 
476  mutt_buffer_addstr(tmp, mutt_b2s(buf));
477  mutt_buffer_strcpy(buf, mutt_b2s(tmp));
479 }
480 
486 static bool has_a_message(struct Body *body)
487 {
488  return (body->email && (body->encoding != ENC_BASE64) &&
489  (body->encoding != ENC_QUOTED_PRINTABLE) &&
490  mutt_is_message_type(body->type, body->subtype));
491 }
492 
502 static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
503 {
504  char *prompt = NULL;
505  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
506  int rc = -1;
507 
508  struct Buffer *buf = mutt_buffer_pool_get();
509  struct Buffer *tfile = mutt_buffer_pool_get();
510 
511  if (body->filename)
512  {
513  if (directory && *directory)
514  {
515  mutt_buffer_concat_path(buf, *directory, mutt_path_basename(body->filename));
516  }
517  else
518  mutt_buffer_strcpy(buf, body->filename);
519  }
520  else if (has_a_message(body))
521  {
522  mutt_default_save(buf->data, buf->dsize, body->email);
524  }
525 
526  prepend_savedir(buf);
527 
528  prompt = _("Save to file: ");
529  while (prompt)
530  {
531  if (mutt_get_field(prompt, buf->data, buf->dsize, MUTT_FILE | MUTT_CLEAR) != 0)
532  {
534  goto cleanup;
535  }
537  if (mutt_buffer_is_empty(buf))
538  goto cleanup;
539 
540  prompt = NULL;
542 
543  bool is_message = (fp && has_a_message(body));
544 
545  if (is_message)
546  {
547  struct stat st;
548 
549  /* check to make sure that this file is really the one the user wants */
550  rc = mutt_save_confirm(mutt_b2s(buf), &st);
551  if (rc == 1)
552  {
553  prompt = _("Save to file: ");
554  continue;
555  }
556  else if (rc == -1)
557  goto cleanup;
558  mutt_buffer_strcpy(tfile, mutt_b2s(buf));
559  }
560  else
561  {
562  rc = mutt_check_overwrite(body->filename, mutt_b2s(buf), tfile, &opt, directory);
563  if (rc == -1)
564  goto cleanup;
565  else if (rc == 1)
566  {
567  prompt = _("Save to file: ");
568  continue;
569  }
570  }
571 
572  mutt_message(_("Saving..."));
573  if (mutt_save_attachment(fp, body, mutt_b2s(tfile), opt,
574  (e || !is_message) ? e : body->email) == 0)
575  {
576  mutt_message(_("Attachment saved"));
577  rc = 0;
578  goto cleanup;
579  }
580  else
581  {
582  prompt = _("Save to file: ");
583  continue;
584  }
585  }
586 
587 cleanup:
589  mutt_buffer_pool_release(&tfile);
590  return rc;
591 }
592 
601 static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
602 {
603  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
604  int rc = -1;
605  struct Buffer *buf = mutt_buffer_pool_get();
606  struct Buffer *tfile = mutt_buffer_pool_get();
607 
608  if (body->filename)
609  {
610  mutt_buffer_strcpy(buf, body->filename);
611  }
612  else if (has_a_message(body))
613  {
614  mutt_default_save(buf->data, buf->dsize, body->email);
615  }
616 
617  prepend_savedir(buf);
619 
620  bool is_message = (fp && has_a_message(body));
621 
622  if (is_message)
623  {
624  mutt_buffer_strcpy(tfile, mutt_b2s(buf));
625  }
626  else
627  {
628  rc = mutt_check_overwrite(body->filename, mutt_b2s(buf), tfile, &opt, NULL);
629  if (rc == -1) // abort or cancel
630  goto cleanup;
631  }
632 
633  rc = mutt_save_attachment(fp, body, mutt_b2s(tfile), opt,
634  (e || !is_message) ? e : body->email);
635 
636 cleanup:
638  mutt_buffer_pool_release(&tfile);
639  return rc;
640 }
641 
651 void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
652  struct Body *top, struct Email *e, struct Menu *menu)
653 {
654  char *directory = NULL;
655  int rc = 1;
656  int last = menu ? menu->current : -1;
657  FILE *fp_out = NULL;
658  int saved_attachments = 0;
659 
660  struct Buffer *buf = mutt_buffer_pool_get();
661  struct Buffer *tfile = mutt_buffer_pool_get();
662 
663  for (int i = 0; !tag || (i < actx->idxlen); i++)
664  {
665  if (tag)
666  {
667  fp = actx->idx[i]->fp;
668  top = actx->idx[i]->content;
669  }
670  if (!tag || top->tagged)
671  {
672  if (!C_AttachSplit)
673  {
674  if (mutt_buffer_is_empty(buf))
675  {
676  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
677 
679  prepend_savedir(buf);
680 
681  if (mutt_get_field(_("Save to file: "), buf->data, buf->dsize,
682  MUTT_FILE | MUTT_CLEAR) != 0)
683  {
684  goto cleanup;
685  }
687  if (mutt_buffer_is_empty(buf))
688  goto cleanup;
690  if (mutt_check_overwrite(top->filename, mutt_b2s(buf), tfile, &opt, NULL))
691  goto cleanup;
692  rc = mutt_save_attachment(fp, top, mutt_b2s(tfile), opt, e);
693  if ((rc == 0) && C_AttachSep && (fp_out = fopen(mutt_b2s(tfile), "a")))
694  {
695  fprintf(fp_out, "%s", C_AttachSep);
696  mutt_file_fclose(&fp_out);
697  }
698  }
699  else
700  {
701  rc = mutt_save_attachment(fp, top, mutt_b2s(tfile), MUTT_SAVE_APPEND, e);
702  if ((rc == 0) && C_AttachSep && (fp_out = fopen(mutt_b2s(tfile), "a")))
703  {
704  fprintf(fp_out, "%s", C_AttachSep);
705  mutt_file_fclose(&fp_out);
706  }
707  }
708  }
709  else
710  {
711  if (tag && menu && top->aptr)
712  {
713  menu->oldcurrent = menu->current;
714  menu->current = top->aptr->num;
715  menu_check_recenter(menu);
716  menu->redraw |= REDRAW_MOTION;
717 
718  menu_redraw(menu);
719  }
721  {
722  // Save each file, with no prompting, using the configured 'AttachSaveDir'
723  rc = save_without_prompting(fp, top, e);
724  if (rc == 0)
725  saved_attachments++;
726  }
727  else
728  {
729  // Save each file, prompting the user for the location each time.
730  if (query_save_attachment(fp, top, e, &directory) == -1)
731  break;
732  }
733  }
734  }
735  if (!tag)
736  break;
737  }
738 
739  FREE(&directory);
740 
741  if (tag && menu)
742  {
743  menu->oldcurrent = menu->current;
744  menu->current = last;
745  menu_check_recenter(menu);
746  menu->redraw |= REDRAW_MOTION;
747  }
748 
749  if (!C_AttachSplit && (rc == 0))
750  mutt_message(_("Attachment saved"));
751 
752  if (C_AttachSaveWithoutPrompting && (rc == 0))
753  {
754  mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
755  saved_attachments);
756  }
757 
758 cleanup:
760  mutt_buffer_pool_release(&tfile);
761 }
762 
770 static void query_pipe_attachment(char *command, FILE *fp, struct Body *body, bool filter)
771 {
772  char tfile[PATH_MAX];
773 
774  if (filter)
775  {
776  char warning[PATH_MAX + 256];
777  snprintf(warning, sizeof(warning),
778  _("WARNING! You are about to overwrite %s, continue?"), body->filename);
779  if (mutt_yesorno(warning, MUTT_NO) != MUTT_YES)
780  {
782  return;
783  }
784  mutt_mktemp(tfile, sizeof(tfile));
785  }
786  else
787  tfile[0] = '\0';
788 
789  if (mutt_pipe_attachment(fp, body, command, tfile))
790  {
791  if (filter)
792  {
793  mutt_file_unlink(body->filename);
794  mutt_file_rename(tfile, body->filename);
795  mutt_update_encoding(body);
796  mutt_message(_("Attachment filtered"));
797  }
798  }
799  else
800  {
801  if (filter && tfile[0])
802  mutt_file_unlink(tfile);
803  }
804 }
805 
812 static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
813 {
814  if (!state || !state->fp_out)
815  return;
816 
817  if (fp)
818  {
819  state->fp_in = fp;
820  mutt_decode_attachment(b, state);
821  if (C_AttachSep)
822  state_puts(C_AttachSep, state);
823  }
824  else
825  {
826  FILE *fp_in = fopen(b->filename, "r");
827  if (!fp_in)
828  {
829  mutt_perror("fopen");
830  return;
831  }
832  mutt_file_copy_stream(fp_in, state->fp_out);
833  mutt_file_fclose(&fp_in);
834  if (C_AttachSep)
835  state_puts(C_AttachSep, state);
836  }
837 }
838 
849 static void pipe_attachment_list(char *command, struct AttachCtx *actx, FILE *fp, bool tag,
850  struct Body *top, bool filter, struct State *state)
851 {
852  for (int i = 0; !tag || (i < actx->idxlen); i++)
853  {
854  if (tag)
855  {
856  fp = actx->idx[i]->fp;
857  top = actx->idx[i]->content;
858  }
859  if (!tag || top->tagged)
860  {
861  if (!filter && !C_AttachSplit)
862  pipe_attachment(fp, top, state);
863  else
864  query_pipe_attachment(command, fp, top, filter);
865  }
866  if (!tag)
867  break;
868  }
869 }
870 
879 void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
880  struct Body *top, bool filter)
881 {
882  struct State state = { 0 };
883  char buf[PATH_MAX];
884 
885  if (fp)
886  filter = false; /* sanity check: we can't filter in the recv case yet */
887 
888  buf[0] = '\0';
889  /* perform charset conversion on text attachments when piping */
890  state.flags = MUTT_CHARCONV;
891 
892  if ((mutt_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
893  sizeof(buf), MUTT_CMD) != 0) ||
894  (buf[0] == '\0'))
895  {
896  return;
897  }
898 
899  mutt_expand_path(buf, sizeof(buf));
900 
901  if (!filter && !C_AttachSplit)
902  {
903  mutt_endwin();
904  pid_t pid = mutt_create_filter(buf, &state.fp_out, NULL, NULL);
905  pipe_attachment_list(buf, actx, fp, tag, top, filter, &state);
906  mutt_file_fclose(&state.fp_out);
907  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
909  }
910  else
911  pipe_attachment_list(buf, actx, fp, tag, top, filter, &state);
912 }
913 
921 static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
922 {
923  char type[256];
924 
925  for (int i = 0; !tag || (i < actx->idxlen); i++)
926  {
927  if (tag)
928  top = actx->idx[i]->content;
929  snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
930  if (!tag || top->tagged)
931  {
932  if (!mailcap_lookup(top, type, NULL, MUTT_MC_PRINT))
933  {
934  if ((mutt_str_strcasecmp("text/plain", top->subtype) != 0) &&
935  (mutt_str_strcasecmp("application/postscript", top->subtype) != 0))
936  {
937  if (!mutt_can_decode(top))
938  {
939  /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
940  application/octet-stream. */
941  mutt_error(_("I don't know how to print %s attachments"), type);
942  return false;
943  }
944  }
945  }
946  }
947  if (!tag)
948  break;
949  }
950  return true;
951 }
952 
961 static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
962  struct Body *top, struct State *state)
963 {
964  char type[256];
965 
966  for (int i = 0; !tag || (i < actx->idxlen); i++)
967  {
968  if (tag)
969  {
970  fp = actx->idx[i]->fp;
971  top = actx->idx[i]->content;
972  }
973  if (!tag || top->tagged)
974  {
975  snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
976  if (!C_AttachSplit && !mailcap_lookup(top, type, NULL, MUTT_MC_PRINT))
977  {
978  if ((mutt_str_strcasecmp("text/plain", top->subtype) == 0) ||
979  (mutt_str_strcasecmp("application/postscript", top->subtype) == 0))
980  {
981  pipe_attachment(fp, top, state);
982  }
983  else if (mutt_can_decode(top))
984  {
985  /* decode and print */
986 
987  FILE *fp_in = NULL;
988  struct Buffer *newfile = mutt_buffer_pool_get();
989 
990  mutt_buffer_mktemp(newfile);
991  if (mutt_decode_save_attachment(fp, top, mutt_b2s(newfile),
993  {
994  if (!state->fp_out)
995  {
996  mutt_error(
997  "BUG in print_attachment_list(). Please report this. ");
998  return;
999  }
1000 
1001  fp_in = fopen(mutt_b2s(newfile), "r");
1002  if (fp_in)
1003  {
1004  mutt_file_copy_stream(fp_in, state->fp_out);
1005  mutt_file_fclose(&fp_in);
1006  if (C_AttachSep)
1007  state_puts(C_AttachSep, state);
1008  }
1009  }
1010  mutt_file_unlink(mutt_b2s(newfile));
1011  mutt_buffer_pool_release(&newfile);
1012  }
1013  }
1014  else
1015  mutt_print_attachment(fp, top);
1016  }
1017  if (!tag)
1018  break;
1019  }
1020 }
1021 
1029 void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
1030 {
1031  char prompt[128];
1032  struct State state = { 0 };
1033  int tagmsgcount = 0;
1034 
1035  if (tag)
1036  for (int i = 0; i < actx->idxlen; i++)
1037  if (actx->idx[i]->content->tagged)
1038  tagmsgcount++;
1039 
1040  snprintf(prompt, sizeof(prompt),
1041  /* L10N: Although we now the precise number of tagged messages, we
1042  do not show it to the user. So feel free to use a "generic
1043  plural" as plural translation if your language has one. */
1044  tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
1045  _("Print attachment?"),
1046  tagmsgcount);
1047  if (query_quadoption(C_Print, prompt) != MUTT_YES)
1048  return;
1049 
1050  if (!C_AttachSplit)
1051  {
1052  if (!can_print(actx, top, tag))
1053  return;
1054  mutt_endwin();
1055  pid_t pid = mutt_create_filter(NONULL(C_PrintCommand), &state.fp_out, NULL, NULL);
1056  print_attachment_list(actx, fp, tag, top, &state);
1057  mutt_file_fclose(&state.fp_out);
1058  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
1060  }
1061  else
1062  print_attachment_list(actx, fp, tag, top, &state);
1063 }
1064 
1070 static void recvattach_extract_pgp_keys(struct AttachCtx *actx, struct Menu *menu)
1071 {
1072  if (!menu->tagprefix)
1074  else
1075  {
1076  for (int i = 0; i < actx->idxlen; i++)
1077  {
1078  if (actx->idx[i]->content->tagged)
1079  {
1080  crypt_pgp_extract_key_from_attachment(actx->idx[i]->fp, actx->idx[i]->content);
1081  }
1082  }
1083  }
1084 }
1085 
1094 static int recvattach_pgp_check_traditional(struct AttachCtx *actx, struct Menu *menu)
1095 {
1096  int rc = 0;
1097 
1098  if (!menu->tagprefix)
1099  rc = crypt_pgp_check_traditional(CUR_ATTACH->fp, CUR_ATTACH->content, true);
1100  else
1101  {
1102  for (int i = 0; i < actx->idxlen; i++)
1103  if (actx->idx[i]->content->tagged)
1104  rc = rc || crypt_pgp_check_traditional(actx->idx[i]->fp, actx->idx[i]->content, true);
1105  }
1106 
1107  return rc;
1108 }
1109 
1116 static void recvattach_edit_content_type(struct AttachCtx *actx,
1117  struct Menu *menu, struct Email *e)
1118 {
1119  if (!mutt_edit_content_type(e, CUR_ATTACH->content, CUR_ATTACH->fp))
1120  return;
1121 
1122  /* The mutt_update_recvattach_menu() will overwrite any changes
1123  * made to a decrypted CUR_ATTACH->content, so warn the user. */
1124  if (CUR_ATTACH->decrypted)
1125  {
1126  mutt_message(
1127  _("Structural changes to decrypted attachments are not supported"));
1128  mutt_sleep(1);
1129  }
1130  /* Editing the content type can rewrite the body structure. */
1131  for (int i = 0; i < actx->idxlen; i++)
1132  actx->idx[i]->content = NULL;
1133  mutt_actx_entries_free(actx);
1134  mutt_update_recvattach_menu(actx, menu, true);
1135 }
1136 
1146 int mutt_attach_display_loop(struct Menu *menu, int op, struct Email *e,
1147  struct AttachCtx *actx, bool recv)
1148 {
1149  do
1150  {
1151  switch (op)
1152  {
1153  case OP_DISPLAY_HEADERS:
1154  bool_str_toggle(Config, "weed", NULL);
1155  /* fallthrough */
1156 
1157  case OP_VIEW_ATTACH:
1158  op = mutt_view_attachment(CUR_ATTACH->fp, CUR_ATTACH->content,
1159  MUTT_VA_REGULAR, e, actx);
1160  break;
1161 
1162  case OP_NEXT_ENTRY:
1163  case OP_MAIN_NEXT_UNDELETED: /* hack */
1164  if (menu->current < menu->max - 1)
1165  {
1166  menu->current++;
1167  op = OP_VIEW_ATTACH;
1168  }
1169  else
1170  op = OP_NULL;
1171  break;
1172  case OP_PREV_ENTRY:
1173  case OP_MAIN_PREV_UNDELETED: /* hack */
1174  if (menu->current > 0)
1175  {
1176  menu->current--;
1177  op = OP_VIEW_ATTACH;
1178  }
1179  else
1180  op = OP_NULL;
1181  break;
1182  case OP_EDIT_TYPE:
1183  /* when we edit the content-type, we should redisplay the attachment
1184  * immediately */
1185  mutt_edit_content_type(e, CUR_ATTACH->content, CUR_ATTACH->fp);
1186  if (recv)
1187  recvattach_edit_content_type(actx, menu, e);
1188  else
1189  mutt_edit_content_type(e, CUR_ATTACH->content, CUR_ATTACH->fp);
1190 
1191  menu->redraw |= REDRAW_INDEX;
1192  op = OP_VIEW_ATTACH;
1193  break;
1194  /* functions which are passed through from the pager */
1195  case OP_CHECK_TRADITIONAL:
1197  {
1198  op = OP_NULL;
1199  break;
1200  }
1201  /* fallthrough */
1202  case OP_ATTACH_COLLAPSE:
1203  if (recv)
1204  return op;
1205  /* fallthrough */
1206  default:
1207  op = OP_NULL;
1208  }
1209  } while (op != OP_NULL);
1210 
1211  return op;
1212 }
1213 
1224 void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e,
1225  struct Body *parts, FILE *fp,
1226  int parent_type, int level, bool decrypted)
1227 {
1228  struct Body *m = NULL;
1229  struct Body *new_body = NULL;
1230  FILE *fp_new = NULL;
1232  int need_secured, secured;
1233 
1234  for (m = parts; m; m = m->next)
1235  {
1236  need_secured = 0;
1237  secured = 0;
1238 
1239  if (((WithCrypto & APPLICATION_SMIME) != 0) && (type = mutt_is_application_smime(m)))
1240  {
1241  need_secured = 1;
1242 
1243  if (type & SEC_ENCRYPT)
1244  {
1245  if (!crypt_valid_passphrase(APPLICATION_SMIME))
1246  goto decrypt_failed;
1247 
1248  if (e->env)
1250  }
1251 
1252  secured = !crypt_smime_decrypt_mime(fp, &fp_new, m, &new_body);
1253  /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1254  * text/plain type will still be returned by mutt_read_mime_header().
1255  * We can't distinguish an actual part from a failure, so only use a
1256  * text/plain that results from a single top-level part. */
1257  if (secured && (new_body->type == TYPE_TEXT) &&
1258  (mutt_str_strcasecmp("plain", new_body->subtype) == 0) &&
1259  ((parts != m) || m->next))
1260  {
1261  mutt_body_free(&new_body);
1262  mutt_file_fclose(&fp_new);
1263  goto decrypt_failed;
1264  }
1265 
1266  if (secured && (type & SEC_ENCRYPT))
1267  e->security |= SMIME_ENCRYPT;
1268  }
1269 
1270  if (((WithCrypto & APPLICATION_PGP) != 0) &&
1272  {
1273  need_secured = 1;
1274 
1275  if (!crypt_valid_passphrase(APPLICATION_PGP))
1276  goto decrypt_failed;
1277 
1278  secured = !crypt_pgp_decrypt_mime(fp, &fp_new, m, &new_body);
1279 
1280  if (secured)
1281  e->security |= PGP_ENCRYPT;
1282  }
1283 
1284  if (need_secured && secured)
1285  {
1286  mutt_actx_add_fp(actx, fp_new);
1287  mutt_actx_add_body(actx, new_body);
1288  mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1289  continue;
1290  }
1291 
1292  decrypt_failed:
1293  /* Fall through and show the original parts if decryption fails */
1294  if (need_secured && !secured)
1295  mutt_error(_("Can't decrypt encrypted message"));
1296 
1297  /* Strip out the top level multipart */
1298  if ((m->type == TYPE_MULTIPART) && m->parts && !need_secured &&
1299  ((parent_type == -1) && mutt_str_strcasecmp("alternative", m->subtype)))
1300  {
1301  mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level, decrypted);
1302  }
1303  else
1304  {
1305  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1306  mutt_actx_add_attach(actx, ap);
1307 
1308  ap->content = m;
1309  ap->fp = fp;
1310  m->aptr = ap;
1311  ap->parent_type = parent_type;
1312  ap->level = level;
1313  ap->decrypted = decrypted;
1314 
1315  if (m->type == TYPE_MULTIPART)
1316  mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level + 1, decrypted);
1317  else if (mutt_is_message_type(m->type, m->subtype))
1318  {
1319  mutt_generate_recvattach_list(actx, m->email, m->parts, fp, m->type,
1320  level + 1, decrypted);
1321  e->security |= m->email->security;
1322  }
1323  }
1324  }
1325 }
1326 
1331 void mutt_attach_init(struct AttachCtx *actx)
1332 {
1333  /* Collapse the attachments if '$digest_collapse' is set AND if...
1334  * the outer container is of type 'multipart/digest' */
1335  bool digest = (mutt_str_strcasecmp(actx->email->content->subtype, "digest") == 0);
1336 
1337  for (int i = 0; i < actx->idxlen; i++)
1338  {
1339  actx->idx[i]->content->tagged = false;
1340 
1341  /* OR an inner container is of type 'multipart/digest' */
1342  actx->idx[i]->content->collapsed =
1343  (C_DigestCollapse &&
1344  (digest ||
1345  ((actx->idx[i]->content->type == TYPE_MULTIPART) &&
1346  (mutt_str_strcasecmp(actx->idx[i]->content->subtype, "digest") == 0))));
1347  }
1348 }
1349 
1356 static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
1357 {
1358  if (init)
1359  {
1360  mutt_generate_recvattach_list(actx, actx->email, actx->email->content,
1361  actx->fp_root, -1, 0, 0);
1362  mutt_attach_init(actx);
1363  menu->data = actx;
1364  }
1365 
1366  mutt_update_tree(actx);
1367 
1368  menu->max = actx->vcount;
1369 
1370  if (menu->current >= menu->max)
1371  menu->current = menu->max - 1;
1372  menu_check_recenter(menu);
1373  menu->redraw |= REDRAW_INDEX;
1374 }
1375 
1381 static void attach_collapse(struct AttachCtx *actx, struct Menu *menu)
1382 {
1383  int rindex, curlevel;
1384 
1385  CUR_ATTACH->content->collapsed = !CUR_ATTACH->content->collapsed;
1386  /* When expanding, expand all the children too */
1387  if (CUR_ATTACH->content->collapsed)
1388  return;
1389 
1390  curlevel = CUR_ATTACH->level;
1391  rindex = actx->v2r[menu->current] + 1;
1392 
1393  while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel))
1394  {
1395  if (C_DigestCollapse && (actx->idx[rindex]->content->type == TYPE_MULTIPART) &&
1396  !mutt_str_strcasecmp(actx->idx[rindex]->content->subtype, "digest"))
1397  {
1398  actx->idx[rindex]->content->collapsed = true;
1399  }
1400  else
1401  {
1402  actx->idx[rindex]->content->collapsed = false;
1403  }
1404  rindex++;
1405  }
1406 }
1407 
1413 {
1414  char helpstr[1024];
1415  int op = OP_NULL;
1416 
1417  struct Mailbox *m = Context ? Context->mailbox : NULL;
1418 
1419  /* make sure we have parsed this message */
1421 
1423 
1424  struct Message *msg = mx_msg_open(m, e->msgno);
1425  if (!msg)
1426  return;
1427 
1428  struct Menu *menu = mutt_menu_new(MENU_ATTACH);
1429  menu->title = _("Attachments");
1431  menu->menu_tag = attach_tag;
1432  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_ATTACH, AttachHelp);
1433  mutt_menu_push_current(menu);
1434 
1435  struct AttachCtx *actx = mutt_actx_new();
1436  actx->email = e;
1437  actx->fp_root = msg->fp;
1438  mutt_update_recvattach_menu(actx, menu, true);
1439 
1440  while (true)
1441  {
1442  if (op == OP_NULL)
1443  op = mutt_menu_loop(menu);
1444  if (!Context)
1445  return;
1446  switch (op)
1447  {
1448  case OP_ATTACH_VIEW_MAILCAP:
1449  mutt_view_attachment(CUR_ATTACH->fp, CUR_ATTACH->content, MUTT_VA_MAILCAP, e, actx);
1450  menu->redraw = REDRAW_FULL;
1451  break;
1452 
1453  case OP_ATTACH_VIEW_TEXT:
1454  mutt_view_attachment(CUR_ATTACH->fp, CUR_ATTACH->content, MUTT_VA_AS_TEXT, e, actx);
1455  menu->redraw = REDRAW_FULL;
1456  break;
1457 
1458  case OP_DISPLAY_HEADERS:
1459  case OP_VIEW_ATTACH:
1460  op = mutt_attach_display_loop(menu, op, e, actx, true);
1461  menu->redraw = REDRAW_FULL;
1462  continue;
1463 
1464  case OP_ATTACH_COLLAPSE:
1465  if (!CUR_ATTACH->content->parts)
1466  {
1467  mutt_error(_("There are no subparts to show"));
1468  break;
1469  }
1470  attach_collapse(actx, menu);
1471  mutt_update_recvattach_menu(actx, menu, false);
1472  break;
1473 
1474  case OP_FORGET_PASSPHRASE:
1476  break;
1477 
1478  case OP_EXTRACT_KEYS:
1480  {
1481  recvattach_extract_pgp_keys(actx, menu);
1482  menu->redraw = REDRAW_FULL;
1483  }
1484  break;
1485 
1486  case OP_CHECK_TRADITIONAL:
1487  if (((WithCrypto & APPLICATION_PGP) != 0) &&
1489  {
1490  e->security = crypt_query(NULL);
1491  menu->redraw = REDRAW_FULL;
1492  }
1493  break;
1494 
1495  case OP_PRINT:
1497  CUR_ATTACH->content);
1498  break;
1499 
1500  case OP_PIPE:
1502  CUR_ATTACH->content, false);
1503  break;
1504 
1505  case OP_SAVE:
1507  CUR_ATTACH->content, e, menu);
1508 
1509  if (!menu->tagprefix && C_Resolve && (menu->current < menu->max - 1))
1510  menu->current++;
1511 
1513  break;
1514 
1515  case OP_DELETE:
1517 
1518 #ifdef USE_POP
1519  if (m->magic == MUTT_POP)
1520  {
1521  mutt_flushinp();
1522  mutt_error(_("Can't delete attachment from POP server"));
1523  break;
1524  }
1525 #endif
1526 
1527 #ifdef USE_NNTP
1528  if (m->magic == MUTT_NNTP)
1529  {
1530  mutt_flushinp();
1531  mutt_error(_("Can't delete attachment from news server"));
1532  break;
1533  }
1534 #endif
1535 
1536  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1537  {
1538  mutt_message(_("Deletion of attachments from encrypted messages is "
1539  "unsupported"));
1540  break;
1541  }
1542  if ((WithCrypto != 0) && (e->security & (SEC_SIGN | SEC_PARTSIGN)))
1543  {
1544  mutt_message(_("Deletion of attachments from signed messages may "
1545  "invalidate the signature"));
1546  }
1547  if (!menu->tagprefix)
1548  {
1549  if (CUR_ATTACH->parent_type == TYPE_MULTIPART)
1550  {
1551  CUR_ATTACH->content->deleted = true;
1552  if (C_Resolve && (menu->current < menu->max - 1))
1553  {
1554  menu->current++;
1555  menu->redraw = REDRAW_MOTION_RESYNC;
1556  }
1557  else
1558  menu->redraw = REDRAW_CURRENT;
1559  }
1560  else
1561  {
1562  mutt_message(
1563  _("Only deletion of multipart attachments is supported"));
1564  }
1565  }
1566  else
1567  {
1568  for (int i = 0; i < menu->max; i++)
1569  {
1570  if (actx->idx[i]->content->tagged)
1571  {
1572  if (actx->idx[i]->parent_type == TYPE_MULTIPART)
1573  {
1574  actx->idx[i]->content->deleted = true;
1575  menu->redraw = REDRAW_INDEX;
1576  }
1577  else
1578  {
1579  mutt_message(
1580  _("Only deletion of multipart attachments is supported"));
1581  }
1582  }
1583  }
1584  }
1585  break;
1586 
1587  case OP_UNDELETE:
1589  if (!menu->tagprefix)
1590  {
1591  CUR_ATTACH->content->deleted = false;
1592  if (C_Resolve && (menu->current < menu->max - 1))
1593  {
1594  menu->current++;
1595  menu->redraw = REDRAW_MOTION_RESYNC;
1596  }
1597  else
1598  menu->redraw = REDRAW_CURRENT;
1599  }
1600  else
1601  {
1602  for (int i = 0; i < menu->max; i++)
1603  {
1604  if (actx->idx[i]->content->tagged)
1605  {
1606  actx->idx[i]->content->deleted = false;
1607  menu->redraw = REDRAW_INDEX;
1608  }
1609  }
1610  }
1611  break;
1612 
1613  case OP_RESEND:
1614  CHECK_ATTACH;
1615  mutt_attach_resend(CUR_ATTACH->fp, actx,
1616  menu->tagprefix ? NULL : CUR_ATTACH->content);
1617  menu->redraw = REDRAW_FULL;
1618  break;
1619 
1620  case OP_BOUNCE_MESSAGE:
1621  CHECK_ATTACH;
1622  mutt_attach_bounce(m, CUR_ATTACH->fp, actx,
1623  menu->tagprefix ? NULL : CUR_ATTACH->content);
1624  menu->redraw = REDRAW_FULL;
1625  break;
1626 
1627  case OP_FORWARD_MESSAGE:
1628  CHECK_ATTACH;
1629  mutt_attach_forward(CUR_ATTACH->fp, e, actx,
1630  menu->tagprefix ? NULL : CUR_ATTACH->content, SEND_NO_FLAGS);
1631  menu->redraw = REDRAW_FULL;
1632  break;
1633 
1634 #ifdef USE_NNTP
1635  case OP_FORWARD_TO_GROUP:
1636  CHECK_ATTACH;
1637  mutt_attach_forward(CUR_ATTACH->fp, e, actx,
1638  menu->tagprefix ? NULL : CUR_ATTACH->content, SEND_NEWS);
1639  menu->redraw = REDRAW_FULL;
1640  break;
1641 
1642  case OP_FOLLOWUP:
1643  CHECK_ATTACH;
1644 
1645  if (!CUR_ATTACH->content->email->env->followup_to ||
1646  (mutt_str_strcasecmp(CUR_ATTACH->content->email->env->followup_to, "poster") != 0) ||
1648  _("Reply by mail as poster prefers?")) != MUTT_YES))
1649  {
1650  mutt_attach_reply(CUR_ATTACH->fp, e, actx,
1651  menu->tagprefix ? NULL : CUR_ATTACH->content,
1652  SEND_NEWS | SEND_REPLY);
1653  menu->redraw = REDRAW_FULL;
1654  break;
1655  }
1656 #endif
1657  /* fallthrough */
1658  case OP_REPLY:
1659  case OP_GROUP_REPLY:
1660  case OP_GROUP_CHAT_REPLY:
1661  case OP_LIST_REPLY:
1662  {
1663  CHECK_ATTACH;
1664 
1665  SendFlags flags = SEND_REPLY;
1666  if (op == OP_GROUP_REPLY)
1667  flags |= SEND_GROUP_REPLY;
1668  else if (op == OP_GROUP_CHAT_REPLY)
1669  flags |= SEND_GROUP_CHAT_REPLY;
1670  else if (op == OP_LIST_REPLY)
1671  flags |= SEND_LIST_REPLY;
1672 
1673  mutt_attach_reply(CUR_ATTACH->fp, e, actx,
1674  menu->tagprefix ? NULL : CUR_ATTACH->content, flags);
1675  menu->redraw = REDRAW_FULL;
1676  break;
1677  }
1678 
1679  case OP_COMPOSE_TO_SENDER:
1680  CHECK_ATTACH;
1681  mutt_attach_mail_sender(CUR_ATTACH->fp, e, actx,
1682  menu->tagprefix ? NULL : CUR_ATTACH->content);
1683  menu->redraw = REDRAW_FULL;
1684  break;
1685 
1686  case OP_EDIT_TYPE:
1687  recvattach_edit_content_type(actx, menu, e);
1688  menu->redraw |= REDRAW_INDEX;
1689  break;
1690 
1691  case OP_EXIT:
1692  mx_msg_close(m, &msg);
1693 
1694  e->attach_del = false;
1695  for (int i = 0; i < actx->idxlen; i++)
1696  {
1697  if (actx->idx[i]->content && actx->idx[i]->content->deleted)
1698  {
1699  e->attach_del = true;
1700  break;
1701  }
1702  }
1703  if (e->attach_del)
1704  e->changed = true;
1705 
1706  mutt_actx_free(&actx);
1707 
1708  mutt_menu_pop_current(menu);
1709  mutt_menu_free(&menu);
1710  return;
1711  }
1712 
1713  op = OP_NULL;
1714  }
1715 
1716  /* not reached */
1717 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:217
The "current" mailbox.
Definition: context.h:36
bool C_AttachSplit
Config: Save/print/pipe tagged messages individually.
Definition: recvattach.c:76
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1790
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 void pipe_attachment_list(char *command, struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter, struct State *state)
Pipe a list of attachments to a command.
Definition: recvattach.c:849
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
#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
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
Miscellaneous email parsing routines.
Lower left corner.
Definition: mutt_menu.h:61
char * C_MessageFormat
Config: printf-like format string for listing attached messages.
Definition: recvattach.c:78
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1383
static bool has_a_message(struct Body *body)
Determine if the Body has a message (to save)
Definition: recvattach.c:486
The envelope/body of an email.
Definition: email.h:39
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:70
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_actx_add_fp(struct AttachCtx *actx, FILE *fp_new)
Save a File handle to the Attachment Context.
Definition: attach.c:62
#define mutt_perror(...)
Definition: logging.h:85
GUI selectable list of items.
Definition: mutt_menu.h:82
Window management.
WHERE unsigned char C_Print
Config: Confirm before printing a message.
Definition: globals.h:190
WHERE char * C_AttachFormat
Config: printf-like format string for the attachment menu.
Definition: globals.h:104
GUI miscellaneous curses (window drawing) routines.
static void attach_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: recvattach.c:435
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:51
#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.
void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
Definition: recvattach.c:1224
The "currently-open" mailbox.
static const char * Mailbox_is_read_only
Definition: recvattach.c:82
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3331
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
#define mutt_message(...)
Definition: logging.h:83
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
int oldcurrent
For driver use only.
Definition: mutt_menu.h:109
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
char * C_AttachSaveWithoutPrompting
Config: If true, then don&#39;t prompt to save.
Definition: recvattach.c:74
No flags set.
Definition: mutt_attach.h:54
Pass files through external commands (filters)
WHERE unsigned char C_FollowupToPoster
Config: (nntp) Reply to the poster if &#39;poster&#39; is in the &#39;Followup-To&#39; header.
Definition: globals.h:197
void mutt_view_attachments(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1412
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:804
char * C_AttachSep
Config: Separator to add between saved/printed/piped attachments.
Definition: recvattach.c:75
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:51
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
#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
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
static void prepend_savedir(struct Buffer *buf)
Add C_AttachSaveDir to the beginning of a path.
Definition: recvattach.c:461
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:105
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:192
RFC1524 Mailcap routines.
static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct State *state)
Print a list of Attachments.
Definition: recvattach.c:961
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:52
String manipulation buffer.
Definition: buffer.h:33
bool C_DigestCollapse
Config: Hide the subparts of a multipart/digest.
Definition: recvattach.c:77
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:48
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: ncrypt.h:136
#define _(a)
Definition: message.h:28
WHERE struct ConfigSet * Config
Wrapper around the user&#39;s config settings.
Definition: globals.h:40
bool changed
Email has been edited.
Definition: email.h:50
struct Body * next
next attachment in the list
Definition: body.h:53
short idxlen
Number of attachmentes.
Definition: attach.h:55
FILE * fp_out
File to write to.
Definition: state.h:47
Force viewing as text.
Definition: mutt_attach.h:43
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:40
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:52
static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
Ask the user if we should save the attachment.
Definition: recvattach.c:502
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
int mutt_save_attachment(FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:789
View using default method.
Definition: mutt_attach.h:41
uint16_t SendFlags
Flags for ci_send_message(), e.g. SEND_REPLY.
Definition: send.h:85
#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
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:662
Flags to control mutt_expando_format()
All user-callable functions.
FILE * fp_in
File to read from.
Definition: state.h:46
#define SEC_PARTSIGN
Not all parts of the email is signed.
Definition: ncrypt.h:126
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
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1415
#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
unsigned int disposition
content-disposition
Definition: body.h:67
Convenience wrapper for the config headers.
#define CUR_ATTACH
Definition: recvattach.c:92
int attach_tag(struct Menu *menu, int sel, int act)
Tag an attachment - Implements Menu::menu_tag()
Definition: recvattach.c:447
Prepare and send an email.
Hundreds of global variables to back the user variables.
Right arrow.
Definition: mutt_menu.h:67
char * tree
Tree characters to display.
Definition: attach.h:39
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:86
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:897
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1087
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:147
size_t dsize
Length of data.
Definition: buffer.h:37
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
bool attach_qualifies
This attachment should be counted.
Definition: body.h:89
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1509
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
struct Mailbox * mailbox
Definition: context.h:50
Parse and execute user-defined hooks.
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:453
API for mailboxes.
Mailcap print field.
Definition: mailcap.h:60
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
void mutt_update_encoding(struct Body *a)
Update the encoding type.
Definition: sendlib.c:1455
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:95
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:150
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
void mutt_make_string_flags(char *buf, size_t buflen, const char *s, struct Context *ctx, struct Mailbox *m, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1497
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:307
signed short attach_count
Number of attachments.
Definition: body.h:59
struct AttachCtx * mutt_actx_new(void)
Create a new Attachment Context.
Definition: attach.c:131
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:89
bool tagged
This attachment is tagged.
Definition: body.h:70
static void query_pipe_attachment(char *command, FILE *fp, struct Body *body, bool filter)
Ask the user if we should pipe the attachment.
Definition: recvattach.c:770
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
void crypt_pgp_extract_key_from_attachment(FILE *fp, struct Body *top)
Wrapper for CryptModuleSpecs::pgp_extract_key_from_attachment()
Definition: cryptglue.c:384
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:43
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
bool collapsed
Used by recvattach.
Definition: body.h:88
char * subtype
content-type subtype
Definition: body.h:37
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:44
#define MUTT_CMD
Do completion on previous word.
Definition: mutt.h:68
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition: recvattach.c:116
#define mutt_b2s(buf)
Definition: buffer.h:41
bool decrypted
Not part of message as stored in the email->content.
Definition: attach.h:43
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
const char * line
Definition: common.c:36
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
#define SEC_SIGN
Email is signed.
Definition: ncrypt.h:123
static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:601
&#39;POP3&#39; Mailbox type
Definition: mailbox.h:54
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:271
A local copy of an email.
Definition: mx.h:81
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
Select an attachment.
Definition: keymap.h:63
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:92
static void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:1116
#define PATH_MAX
Definition: mutt.h:52
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
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
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
static void recvattach_extract_pgp_keys(struct AttachCtx *actx, struct Menu *menu)
Extract PGP keys from attachments.
Definition: recvattach.c:1070
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:920
Manage where the email is piped to external commands.
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:57
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * dptr
Current read/write position.
Definition: buffer.h:36
WHERE bool C_Resolve
Config: Move to the next email whenever a command modifies an email.
Definition: globals.h:253
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1727
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition: cryptglue.c:455
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1749
char * data
Pointer to data.
Definition: buffer.h:35
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1356
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
char * C_AttachSaveDir
Config: Default directory where attachments are saved.
Definition: recvattach.c:73
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
GUI present the user with a selectable list.
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:515
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:422
#define SEND_NEWS
Reply to a news article.
Definition: send.h:101
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: sendlib.c:1431
SecurityFlags mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:619
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition: recvattach.c:812
Handling of email attachments.
API for encryption/signing of emails.
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:612
char * description
content-description
Definition: body.h:40
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:433
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
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
static int recvattach_pgp_check_traditional(struct AttachCtx *actx, struct Menu *menu)
Is the Attachment inline PGP?
Definition: recvattach.c:1094
static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:921
Force viewing using mailcap entry.
Definition: mutt_attach.h:42
#define SEND_REPLY
Reply to sender.
Definition: send.h:87
#define CHECK_READONLY
Definition: recvattach.c:84
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
#define MUTT_FILE
Do file completion.
Definition: mutt.h:66
unsigned int type
content-type primary type
Definition: body.h:65
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
int(* menu_tag)(struct Menu *menu, int sel, int act)
Tag some menu items.
Definition: mutt_menu.h:137
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:134
int mutt_check_overwrite(const char *attname, const char *path, struct Buffer *fname, enum SaveAttach *opt, char **directory)
Ask the user if overwriting is necessary.
Definition: muttlib.c:710
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:1029
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
void mutt_attach_forward(FILE *fp, struct Email *e, struct AttachCtx *actx, struct Body *cur, SendFlags flags)
Forward an Attachment.
Definition: recvcmd.c:749
int crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional()
Definition: cryptglue.c:273
char * title
Title of this menu.
Definition: mutt_menu.h:84
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:532
Keep track when processing files.
bool deleted
Attachment marked for deletion.
Definition: body.h:71
static void attach_collapse(struct AttachCtx *actx, struct Menu *menu)
Close the tree of the current attachment.
Definition: recvattach.c:1381
#define TYPE(body)
Definition: mime.h:83
#define state_puts(str, state)
Definition: state.h:54
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition: attach.c:103
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:88
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:199
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:1151
Routines for managing attachments.
Log at debug level 1.
Definition: logging.h:56
Send/reply with an attachment.
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:42
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:268
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
short * v2r
Mapping from virtual to real attachment.
Definition: attach.h:58
struct Body * content
Attachment.
Definition: attach.h:36
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
#define SMIME_ENCRYPT
Definition: ncrypt.h:146
#define mutt_error(...)
Definition: logging.h:84
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:141
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
Quoted-printable text.
Definition: mime.h:51
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:144
FILE * fp
pointer to the message data
Definition: mx.h:83
Append to existing file.
Definition: mutt_attach.h:55
#define FREE(x)
Definition: memory.h:40
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 * data
Extra data for the current menu.
Definition: mutt_menu.h:86
Mapping between user-readable string and a constant.
Definition: mapping.h:29
Keep track when processing files.
Definition: state.h:44
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:1059
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:42
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Miscellaneous functions for sending an email.
int bool_str_toggle(struct ConfigSet *cs, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:240
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:579
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:100
static const char * Function_not_permitted
Definition: recvattach.c:99
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: ncrypt.h:120
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx)
View an attachment.
Definition: mutt_attach.c:384
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
bool mailcap_lookup(struct Body *a, char *type, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:465
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:228
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
#define CHECK_ATTACH
Definition: recvattach.c:102
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Decide how to display email content.
#define N_(a)
Definition: message.h:32
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define WithCrypto
Definition: ncrypt.h:160
A set of attachments.
Definition: attach.h:49
int level
Nesting depth of attachment.
Definition: attach.h:40
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
SecurityFlags crypt_query(struct Body *m)
Check out the type of encryption used.
Definition: crypt.c:696
Convenience wrapper for the library headers.
void mutt_attach_resend(FILE *fp, struct AttachCtx *actx, struct Body *cur)
resend-message, from the attachment menu
Definition: recvcmd.c:290
Left T-piece.
Definition: mutt_menu.h:63
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:672
char * help
Quickref for the current menu.
Definition: mutt_menu.h:85
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1039
#define PGP_ENCRYPT
Definition: ncrypt.h:140
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:45
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_actx_add_body(struct AttachCtx *actx, struct Body *new_body)
Add an email box to an Attachment Context.
Definition: attach.c:83
void mutt_format_s_tree(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string with tree characters.
Definition: curs_lib.c:1163
short vcount
The number of virtual attachments.
Definition: attach.h:59
int msgno
Number displayed to the user.
Definition: email.h:88
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:52
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: ncrypt.h:135
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1019
Horizontal line.
Definition: mutt_menu.h:64
void mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:352