NeoMutt  2020-04-24
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 <sys/stat.h>
35 #include <unistd.h>
36 #include "mutt/lib.h"
37 #include "config/lib.h"
38 #include "email/lib.h"
39 #include "core/lib.h"
40 #include "gui/lib.h"
41 #include "mutt.h"
42 #include "recvattach.h"
43 #include "commands.h"
44 #include "context.h"
45 #include "format_flags.h"
46 #include "globals.h"
47 #include "handler.h"
48 #include "hdrline.h"
49 #include "hook.h"
50 #include "init.h"
51 #include "keymap.h"
52 #include "mailcap.h"
53 #include "mutt_attach.h"
54 #include "mutt_menu.h"
55 #include "mutt_parse.h"
56 #include "muttlib.h"
57 #include "mx.h"
58 #include "opcodes.h"
59 #include "options.h"
60 #include "recvcmd.h"
61 #include "send.h"
62 #include "sendlib.h"
63 #include "state.h"
64 #include "ncrypt/lib.h"
65 #ifdef ENABLE_NLS
66 #include <libintl.h>
67 #endif
68 
69 /* These Config Variables are only used in recvattach.c */
72 char *C_AttachSep;
76 
77 static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init);
78 
79 static const char *Mailbox_is_read_only = N_("Mailbox is read-only");
80 
81 #define CHECK_READONLY \
82  if (!Context || !Context->mailbox || Context->mailbox->readonly) \
83  { \
84  mutt_flushinp(); \
85  mutt_error(_(Mailbox_is_read_only)); \
86  break; \
87  }
88 
89 #define CUR_ATTACH actx->idx[actx->v2r[menu->current]]
90 
91 static const struct Mapping AttachHelp[] = {
92  { N_("Exit"), OP_EXIT }, { N_("Save"), OP_SAVE }, { N_("Pipe"), OP_PIPE },
93  { N_("Print"), OP_PRINT }, { N_("Help"), OP_HELP }, { NULL, 0 },
94 };
95 
96 static const char *Function_not_permitted =
97  N_("Function not permitted in attach-message mode");
98 
99 #define CHECK_ATTACH \
100  if (OptAttachMsg) \
101  { \
102  mutt_flushinp(); \
103  mutt_error(_(Function_not_permitted)); \
104  break; \
105  }
106 
113 static void mutt_update_v2r(struct AttachCtx *actx)
114 {
115  int vindex, rindex, curlevel;
116 
117  vindex = 0;
118  rindex = 0;
119 
120  while (rindex < actx->idxlen)
121  {
122  actx->v2r[vindex++] = rindex;
123  if (actx->idx[rindex]->content->collapsed)
124  {
125  curlevel = actx->idx[rindex]->level;
126  do
127  {
128  rindex++;
129  } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
130  }
131  else
132  rindex++;
133  }
134 
135  actx->vcount = vindex;
136 }
137 
142 void mutt_update_tree(struct AttachCtx *actx)
143 {
144  char buf[256];
145  char *s = NULL;
146 
147  mutt_update_v2r(actx);
148 
149  for (int vindex = 0; vindex < actx->vcount; vindex++)
150  {
151  const int rindex = actx->v2r[vindex];
152  actx->idx[rindex]->num = vindex;
153  if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
154  {
155  if (actx->idx[rindex]->level)
156  {
157  s = buf + 2 * (actx->idx[rindex]->level - 1);
158  *s++ = (actx->idx[rindex]->content->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
159  *s++ = MUTT_TREE_HLINE;
160  *s++ = MUTT_TREE_RARROW;
161  }
162  else
163  s = buf;
164  *s = '\0';
165  }
166 
167  if (actx->idx[rindex]->tree)
168  {
169  if (mutt_str_strcmp(actx->idx[rindex]->tree, buf) != 0)
170  mutt_str_replace(&actx->idx[rindex]->tree, buf);
171  }
172  else
173  actx->idx[rindex]->tree = mutt_str_strdup(buf);
174 
175  if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
176  actx->idx[rindex]->level)
177  {
178  s = buf + 2 * (actx->idx[rindex]->level - 1);
179  *s++ = (actx->idx[rindex]->content->next) ? '\005' : '\006';
180  *s++ = '\006';
181  }
182  }
183 }
184 
208 const char *attach_format_str(char *buf, size_t buflen, size_t col, int cols,
209  char op, const char *src, const char *prec,
210  const char *if_str, const char *else_str,
211  unsigned long data, MuttFormatFlags flags)
212 {
213  char fmt[128];
214  char charset[128];
215  struct AttachPtr *aptr = (struct AttachPtr *) data;
216  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
217 
218  switch (op)
219  {
220  case 'C':
221  if (!optional)
222  {
223  if (mutt_is_text_part(aptr->content) &&
224  mutt_body_get_charset(aptr->content, charset, sizeof(charset)))
225  {
226  mutt_format_s(buf, buflen, prec, charset);
227  }
228  else
229  mutt_format_s(buf, buflen, prec, "");
230  }
231  else if (!mutt_is_text_part(aptr->content) ||
232  !mutt_body_get_charset(aptr->content, charset, sizeof(charset)))
233  {
234  optional = false;
235  }
236  break;
237  case 'c':
238  /* XXX */
239  if (!optional)
240  {
241  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
242  snprintf(buf, buflen, fmt,
243  ((aptr->content->type != TYPE_TEXT) || aptr->content->noconv) ? 'n' : 'c');
244  }
245  else if ((aptr->content->type != TYPE_TEXT) || aptr->content->noconv)
246  optional = false;
247  break;
248  case 'd':
249  if (!optional)
250  {
251  if (aptr->content->description)
252  {
253  mutt_format_s(buf, buflen, prec, aptr->content->description);
254  break;
255  }
256  if (mutt_is_message_type(aptr->content->type, aptr->content->subtype) &&
257  C_MessageFormat && aptr->content->email)
258  {
259  char s[128];
260  mutt_make_string_flags(s, sizeof(s), cols, C_MessageFormat, NULL,
261  NULL, aptr->content->email,
263  if (*s)
264  {
265  mutt_format_s(buf, buflen, prec, s);
266  break;
267  }
268  }
269  if (!aptr->content->d_filename && !aptr->content->filename)
270  {
271  mutt_format_s(buf, buflen, prec, "<no description>");
272  break;
273  }
274  }
275  else if (aptr->content->description ||
276  (mutt_is_message_type(aptr->content->type, aptr->content->subtype) &&
277  C_MessageFormat && aptr->content->email))
278  {
279  break;
280  }
281  /* fallthrough */
282  case 'F':
283  if (!optional)
284  {
285  if (aptr->content->d_filename)
286  {
287  mutt_format_s(buf, buflen, prec, aptr->content->d_filename);
288  break;
289  }
290  }
291  else if (!aptr->content->d_filename && !aptr->content->filename)
292  {
293  optional = false;
294  break;
295  }
296  /* fallthrough */
297  case 'f':
298  if (!optional)
299  {
300  if (aptr->content->filename && (*aptr->content->filename == '/'))
301  {
302  struct Buffer *path = mutt_buffer_pool_get();
303 
304  mutt_buffer_strcpy(path, aptr->content->filename);
306  mutt_format_s(buf, buflen, prec, mutt_b2s(path));
308  }
309  else
310  mutt_format_s(buf, buflen, prec, NONULL(aptr->content->filename));
311  }
312  else if (!aptr->content->filename)
313  optional = false;
314  break;
315  case 'D':
316  if (!optional)
317  snprintf(buf, buflen, "%c", aptr->content->deleted ? 'D' : ' ');
318  else if (!aptr->content->deleted)
319  optional = false;
320  break;
321  case 'e':
322  if (!optional)
323  mutt_format_s(buf, buflen, prec, ENCODING(aptr->content->encoding));
324  break;
325  case 'I':
326  if (optional)
327  break;
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  break;
342  case 'm':
343  if (!optional)
344  mutt_format_s(buf, buflen, prec, TYPE(aptr->content));
345  break;
346  case 'M':
347  if (!optional)
348  mutt_format_s(buf, buflen, prec, aptr->content->subtype);
349  else if (!aptr->content->subtype)
350  optional = false;
351  break;
352  case 'n':
353  if (optional)
354  break;
355 
356  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
357  snprintf(buf, buflen, fmt, aptr->num + 1);
358  break;
359  case 'Q':
360  if (optional)
361  optional = aptr->content->attach_qualifies;
362  else
363  {
364  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
365  mutt_format_s(buf, buflen, fmt, "Q");
366  }
367  break;
368  case 's':
369  {
370  size_t l;
371  if (flags & MUTT_FORMAT_STAT_FILE)
372  {
373  struct stat st;
374  stat(aptr->content->filename, &st);
375  l = st.st_size;
376  }
377  else
378  l = aptr->content->length;
379 
380  if (!optional)
381  {
382  char tmp[128];
383  mutt_str_pretty_size(tmp, sizeof(tmp), l);
384  mutt_format_s(buf, buflen, prec, tmp);
385  }
386  else if (l == 0)
387  optional = false;
388 
389  break;
390  }
391  case 't':
392  if (!optional)
393  snprintf(buf, buflen, "%c", aptr->content->tagged ? '*' : ' ');
394  else if (!aptr->content->tagged)
395  optional = false;
396  break;
397  case 'T':
398  if (!optional)
399  mutt_format_s_tree(buf, buflen, prec, NONULL(aptr->tree));
400  else if (!aptr->tree)
401  optional = false;
402  break;
403  case 'u':
404  if (!optional)
405  snprintf(buf, buflen, "%c", aptr->content->unlink ? '-' : ' ');
406  else if (!aptr->content->unlink)
407  optional = false;
408  break;
409  case 'X':
410  if (optional)
411  optional = ((aptr->content->attach_count + aptr->content->attach_qualifies) != 0);
412  else
413  {
414  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
415  snprintf(buf, buflen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
416  }
417  break;
418  default:
419  *buf = '\0';
420  }
421 
422  if (optional)
423  {
424  mutt_expando_format(buf, buflen, col, cols, if_str, attach_format_str, data,
426  }
427  else if (flags & MUTT_FORMAT_OPTIONAL)
428  {
429  mutt_expando_format(buf, buflen, col, cols, else_str, attach_format_str,
430  data, MUTT_FORMAT_NO_FLAGS);
431  }
432  return src;
433 }
434 
438 static void attach_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
439 {
440  struct AttachCtx *actx = menu->data;
441 
442  mutt_expando_format(buf, buflen, 0, menu->win_index->state.cols,
444  (unsigned long) (actx->idx[actx->v2r[line]]), MUTT_FORMAT_ARROWCURSOR);
445 }
446 
450 int attach_tag(struct Menu *menu, int sel, int act)
451 {
452  struct AttachCtx *actx = menu->data;
453  struct Body *cur = actx->idx[actx->v2r[sel]]->content;
454  bool ot = cur->tagged;
455 
456  cur->tagged = ((act >= 0) ? act : !cur->tagged);
457  return cur->tagged - ot;
458 }
459 
464 static void prepend_savedir(struct Buffer *buf)
465 {
466  if (!buf || !buf->data || (buf->data[0] == '/'))
467  return;
468 
469  struct Buffer *tmp = mutt_buffer_pool_get();
470  if (C_AttachSaveDir)
471  {
473  if (tmp->dptr[-1] != '/')
474  mutt_buffer_addch(tmp, '/');
475  }
476  else
477  mutt_buffer_addstr(tmp, "./");
478 
479  mutt_buffer_addstr(tmp, mutt_b2s(buf));
480  mutt_buffer_copy(buf, tmp);
482 }
483 
489 static bool has_a_message(struct Body *body)
490 {
491  return (body->email && (body->encoding != ENC_BASE64) &&
492  (body->encoding != ENC_QUOTED_PRINTABLE) &&
493  mutt_is_message_type(body->type, body->subtype));
494 }
495 
505 static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
506 {
507  char *prompt = NULL;
508  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
509  int rc = -1;
510 
511  struct Buffer *buf = mutt_buffer_pool_get();
512  struct Buffer *tfile = mutt_buffer_pool_get();
513 
514  if (body->filename)
515  {
516  if (directory && *directory)
517  {
518  mutt_buffer_concat_path(buf, *directory, mutt_path_basename(body->filename));
519  }
520  else
521  mutt_buffer_strcpy(buf, body->filename);
522  }
523  else if (has_a_message(body))
524  {
525  mutt_default_save(buf->data, buf->dsize, body->email);
527  }
528 
529  prepend_savedir(buf);
530 
531  prompt = _("Save to file: ");
532  while (prompt)
533  {
534  if ((mutt_buffer_get_field(prompt, buf, MUTT_FILE | MUTT_CLEAR) != 0) ||
536  {
537  goto cleanup;
538  }
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_copy(tfile, 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_copy(tfile, 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_buffer_get_field(_("Save to file: "), buf, MUTT_FILE | MUTT_CLEAR) != 0) ||
683  {
684  goto cleanup;
685  }
687  if (mutt_check_overwrite(top->filename, mutt_b2s(buf), tfile, &opt, NULL))
688  goto cleanup;
689  rc = mutt_save_attachment(fp, top, mutt_b2s(tfile), opt, e);
690  if ((rc == 0) && C_AttachSep && (fp_out = fopen(mutt_b2s(tfile), "a")))
691  {
692  fprintf(fp_out, "%s", C_AttachSep);
693  mutt_file_fclose(&fp_out);
694  }
695  }
696  else
697  {
698  rc = mutt_save_attachment(fp, top, mutt_b2s(tfile), MUTT_SAVE_APPEND, e);
699  if ((rc == 0) && C_AttachSep && (fp_out = fopen(mutt_b2s(tfile), "a")))
700  {
701  fprintf(fp_out, "%s", C_AttachSep);
702  mutt_file_fclose(&fp_out);
703  }
704  }
705  }
706  else
707  {
708  if (tag && menu && top->aptr)
709  {
710  menu->oldcurrent = menu->current;
711  menu->current = top->aptr->num;
712  menu_check_recenter(menu);
713  menu->redraw |= REDRAW_MOTION;
714 
715  menu_redraw(menu);
716  }
718  {
719  // Save each file, with no prompting, using the configured 'AttachSaveDir'
720  rc = save_without_prompting(fp, top, e);
721  if (rc == 0)
722  saved_attachments++;
723  }
724  else
725  {
726  // Save each file, prompting the user for the location each time.
727  if (query_save_attachment(fp, top, e, &directory) == -1)
728  break;
729  }
730  }
731  }
732  if (!tag)
733  break;
734  }
735 
736  FREE(&directory);
737 
738  if (tag && menu)
739  {
740  menu->oldcurrent = menu->current;
741  menu->current = last;
742  menu_check_recenter(menu);
743  menu->redraw |= REDRAW_MOTION;
744  }
745 
746  if (!C_AttachSplit && (rc == 0))
747  mutt_message(_("Attachment saved"));
748 
749  if (C_AttachSaveWithoutPrompting && (rc == 0))
750  {
751  mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
752  saved_attachments);
753  }
754 
755 cleanup:
757  mutt_buffer_pool_release(&tfile);
758 }
759 
767 static void query_pipe_attachment(const char *command, FILE *fp, struct Body *body, bool filter)
768 {
769  char tfile[PATH_MAX];
770 
771  if (filter)
772  {
773  char warning[PATH_MAX + 256];
774  snprintf(warning, sizeof(warning),
775  _("WARNING! You are about to overwrite %s, continue?"), body->filename);
776  if (mutt_yesorno(warning, MUTT_NO) != MUTT_YES)
777  {
779  return;
780  }
781  mutt_mktemp(tfile, sizeof(tfile));
782  }
783  else
784  tfile[0] = '\0';
785 
786  if (mutt_pipe_attachment(fp, body, command, tfile))
787  {
788  if (filter)
789  {
790  mutt_file_unlink(body->filename);
791  mutt_file_rename(tfile, body->filename);
792  mutt_update_encoding(body);
793  mutt_message(_("Attachment filtered"));
794  }
795  }
796  else
797  {
798  if (filter && tfile[0])
799  mutt_file_unlink(tfile);
800  }
801 }
802 
809 static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
810 {
811  if (!state || !state->fp_out)
812  return;
813 
814  if (fp)
815  {
816  state->fp_in = fp;
817  mutt_decode_attachment(b, state);
818  if (C_AttachSep)
819  state_puts(state, C_AttachSep);
820  }
821  else
822  {
823  FILE *fp_in = fopen(b->filename, "r");
824  if (!fp_in)
825  {
826  mutt_perror("fopen");
827  return;
828  }
829  mutt_file_copy_stream(fp_in, state->fp_out);
830  mutt_file_fclose(&fp_in);
831  if (C_AttachSep)
832  state_puts(state, C_AttachSep);
833  }
834 }
835 
846 static void pipe_attachment_list(const char *command, struct AttachCtx *actx,
847  FILE *fp, bool tag, struct Body *top,
848  bool filter, struct State *state)
849 {
850  for (int i = 0; !tag || (i < actx->idxlen); i++)
851  {
852  if (tag)
853  {
854  fp = actx->idx[i]->fp;
855  top = actx->idx[i]->content;
856  }
857  if (!tag || top->tagged)
858  {
859  if (!filter && !C_AttachSplit)
860  pipe_attachment(fp, top, state);
861  else
862  query_pipe_attachment(command, fp, top, filter);
863  }
864  if (!tag)
865  break;
866  }
867 }
868 
877 void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
878  struct Body *top, bool filter)
879 {
880  struct State state = { 0 };
881  struct Buffer *buf = NULL;
882 
883  if (fp)
884  filter = false; /* sanity check: we can't filter in the recv case yet */
885 
886  buf = mutt_buffer_pool_get();
887  /* perform charset conversion on text attachments when piping */
888  state.flags = MUTT_CHARCONV;
889 
890  if (mutt_buffer_get_field((filter ? _("Filter through: ") : _("Pipe to: ")),
891  buf, MUTT_CMD) != 0)
892  {
893  goto cleanup;
894  }
895 
896  if (mutt_buffer_len(buf) == 0)
897  goto cleanup;
898 
900 
901  if (!filter && !C_AttachSplit)
902  {
903  mutt_endwin();
904  pid_t pid = filter_create(mutt_b2s(buf), &state.fp_out, NULL, NULL);
905  pipe_attachment_list(mutt_b2s(buf), actx, fp, tag, top, filter, &state);
906  mutt_file_fclose(&state.fp_out);
907  if ((filter_wait(pid) != 0) || C_WaitKey)
909  }
910  else
911  pipe_attachment_list(mutt_b2s(buf), actx, fp, tag, top, filter, &state);
912 
913 cleanup:
915 }
916 
924 static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
925 {
926  char type[256];
927 
928  for (int i = 0; !tag || (i < actx->idxlen); i++)
929  {
930  if (tag)
931  top = actx->idx[i]->content;
932  snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
933  if (!tag || top->tagged)
934  {
935  if (!mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
936  {
937  if ((mutt_str_strcasecmp("text/plain", top->subtype) != 0) &&
938  (mutt_str_strcasecmp("application/postscript", top->subtype) != 0))
939  {
940  if (!mutt_can_decode(top))
941  {
942  /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
943  application/octet-stream. */
944  mutt_error(_("I don't know how to print %s attachments"), type);
945  return false;
946  }
947  }
948  }
949  }
950  if (!tag)
951  break;
952  }
953  return true;
954 }
955 
964 static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
965  struct Body *top, struct State *state)
966 {
967  char type[256];
968 
969  for (int i = 0; !tag || (i < actx->idxlen); i++)
970  {
971  if (tag)
972  {
973  fp = actx->idx[i]->fp;
974  top = actx->idx[i]->content;
975  }
976  if (!tag || top->tagged)
977  {
978  snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
979  if (!C_AttachSplit && !mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
980  {
981  if ((mutt_str_strcasecmp("text/plain", top->subtype) == 0) ||
982  (mutt_str_strcasecmp("application/postscript", top->subtype) == 0))
983  {
984  pipe_attachment(fp, top, state);
985  }
986  else if (mutt_can_decode(top))
987  {
988  /* decode and print */
989 
990  FILE *fp_in = NULL;
991  struct Buffer *newfile = mutt_buffer_pool_get();
992 
993  mutt_buffer_mktemp(newfile);
994  if (mutt_decode_save_attachment(fp, top, mutt_b2s(newfile),
996  {
997  if (!state->fp_out)
998  {
999  mutt_error(
1000  "BUG in print_attachment_list(). Please report this. ");
1001  return;
1002  }
1003 
1004  fp_in = fopen(mutt_b2s(newfile), "r");
1005  if (fp_in)
1006  {
1007  mutt_file_copy_stream(fp_in, state->fp_out);
1008  mutt_file_fclose(&fp_in);
1009  if (C_AttachSep)
1010  state_puts(state, C_AttachSep);
1011  }
1012  }
1013  mutt_file_unlink(mutt_b2s(newfile));
1014  mutt_buffer_pool_release(&newfile);
1015  }
1016  }
1017  else
1018  mutt_print_attachment(fp, top);
1019  }
1020  if (!tag)
1021  break;
1022  }
1023 }
1024 
1032 void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
1033 {
1034  char prompt[128];
1035  struct State state = { 0 };
1036  int tagmsgcount = 0;
1037 
1038  if (tag)
1039  for (int i = 0; i < actx->idxlen; i++)
1040  if (actx->idx[i]->content->tagged)
1041  tagmsgcount++;
1042 
1043  snprintf(prompt, sizeof(prompt),
1044  /* L10N: Although we now the precise number of tagged messages, we
1045  do not show it to the user. So feel free to use a "generic
1046  plural" as plural translation if your language has one. */
1047  tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
1048  _("Print attachment?"),
1049  tagmsgcount);
1050  if (query_quadoption(C_Print, prompt) != MUTT_YES)
1051  return;
1052 
1053  if (C_AttachSplit)
1054  {
1055  print_attachment_list(actx, fp, tag, top, &state);
1056  }
1057  else
1058  {
1059  if (!can_print(actx, top, tag))
1060  return;
1061  mutt_endwin();
1062  pid_t pid = filter_create(NONULL(C_PrintCommand), &state.fp_out, NULL, NULL);
1063  print_attachment_list(actx, fp, tag, top, &state);
1064  mutt_file_fclose(&state.fp_out);
1065  if ((filter_wait(pid) != 0) || C_WaitKey)
1067  }
1068 }
1069 
1075 static void recvattach_extract_pgp_keys(struct AttachCtx *actx, struct Menu *menu)
1076 {
1077  if (!menu->tagprefix)
1079  else
1080  {
1081  for (int i = 0; i < actx->idxlen; i++)
1082  {
1083  if (actx->idx[i]->content->tagged)
1084  {
1085  crypt_pgp_extract_key_from_attachment(actx->idx[i]->fp, actx->idx[i]->content);
1086  }
1087  }
1088  }
1089 }
1090 
1099 static int recvattach_pgp_check_traditional(struct AttachCtx *actx, struct Menu *menu)
1100 {
1101  int rc = 0;
1102 
1103  if (!menu->tagprefix)
1104  rc = crypt_pgp_check_traditional(CUR_ATTACH->fp, CUR_ATTACH->content, true);
1105  else
1106  {
1107  for (int i = 0; i < actx->idxlen; i++)
1108  if (actx->idx[i]->content->tagged)
1109  rc = rc || crypt_pgp_check_traditional(actx->idx[i]->fp, actx->idx[i]->content, true);
1110  }
1111 
1112  return rc;
1113 }
1114 
1121 static void recvattach_edit_content_type(struct AttachCtx *actx,
1122  struct Menu *menu, struct Email *e)
1123 {
1124  if (!mutt_edit_content_type(e, CUR_ATTACH->content, CUR_ATTACH->fp))
1125  return;
1126 
1127  /* The mutt_update_recvattach_menu() will overwrite any changes
1128  * made to a decrypted CUR_ATTACH->content, so warn the user. */
1129  if (CUR_ATTACH->decrypted)
1130  {
1131  mutt_message(
1132  _("Structural changes to decrypted attachments are not supported"));
1133  mutt_sleep(1);
1134  }
1135  /* Editing the content type can rewrite the body structure. */
1136  for (int i = 0; i < actx->idxlen; i++)
1137  actx->idx[i]->content = NULL;
1138  mutt_actx_entries_free(actx);
1139  mutt_update_recvattach_menu(actx, menu, true);
1140 }
1141 
1151 int mutt_attach_display_loop(struct Menu *menu, int op, struct Email *e,
1152  struct AttachCtx *actx, bool recv)
1153 {
1154  do
1155  {
1156  switch (op)
1157  {
1158  case OP_DISPLAY_HEADERS:
1159  bool_str_toggle(NeoMutt->sub, "weed", NULL);
1160  /* fallthrough */
1161 
1162  case OP_VIEW_ATTACH:
1163  op = mutt_view_attachment(CUR_ATTACH->fp, CUR_ATTACH->content,
1164  MUTT_VA_REGULAR, e, actx, menu->win_index);
1165  break;
1166 
1167  case OP_NEXT_ENTRY:
1168  case OP_MAIN_NEXT_UNDELETED: /* hack */
1169  if (menu->current < menu->max - 1)
1170  {
1171  menu->current++;
1172  op = OP_VIEW_ATTACH;
1173  }
1174  else
1175  op = OP_NULL;
1176  break;
1177  case OP_PREV_ENTRY:
1178  case OP_MAIN_PREV_UNDELETED: /* hack */
1179  if (menu->current > 0)
1180  {
1181  menu->current--;
1182  op = OP_VIEW_ATTACH;
1183  }
1184  else
1185  op = OP_NULL;
1186  break;
1187  case OP_EDIT_TYPE:
1188  /* when we edit the content-type, we should redisplay the attachment
1189  * immediately */
1190  mutt_edit_content_type(e, CUR_ATTACH->content, CUR_ATTACH->fp);
1191  if (recv)
1192  recvattach_edit_content_type(actx, menu, e);
1193  else
1194  mutt_edit_content_type(e, CUR_ATTACH->content, CUR_ATTACH->fp);
1195 
1196  menu->redraw |= REDRAW_INDEX;
1197  op = OP_VIEW_ATTACH;
1198  break;
1199  /* functions which are passed through from the pager */
1200  case OP_CHECK_TRADITIONAL:
1202  {
1203  op = OP_NULL;
1204  break;
1205  }
1206  /* fallthrough */
1207  case OP_ATTACH_COLLAPSE:
1208  if (recv)
1209  return op;
1210  /* fallthrough */
1211  default:
1212  op = OP_NULL;
1213  }
1214  } while (op != OP_NULL);
1215 
1216  return op;
1217 }
1218 
1229 void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e,
1230  struct Body *parts, FILE *fp,
1231  int parent_type, int level, bool decrypted)
1232 {
1233  struct Body *m = NULL;
1234  struct Body *new_body = NULL;
1235  FILE *fp_new = NULL;
1237  int need_secured, secured;
1238 
1239  for (m = parts; m; m = m->next)
1240  {
1241  need_secured = 0;
1242  secured = 0;
1243 
1244  if (((WithCrypto & APPLICATION_SMIME) != 0) && (type = mutt_is_application_smime(m)))
1245  {
1246  need_secured = 1;
1247 
1248  if (type & SEC_ENCRYPT)
1249  {
1250  if (!crypt_valid_passphrase(APPLICATION_SMIME))
1251  goto decrypt_failed;
1252 
1253  if (e->env)
1255  }
1256 
1257  secured = !crypt_smime_decrypt_mime(fp, &fp_new, m, &new_body);
1258  /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1259  * text/plain type will still be returned by mutt_read_mime_header().
1260  * We can't distinguish an actual part from a failure, so only use a
1261  * text/plain that results from a single top-level part. */
1262  if (secured && (new_body->type == TYPE_TEXT) &&
1263  (mutt_str_strcasecmp("plain", new_body->subtype) == 0) &&
1264  ((parts != m) || m->next))
1265  {
1266  mutt_body_free(&new_body);
1267  mutt_file_fclose(&fp_new);
1268  goto decrypt_failed;
1269  }
1270 
1271  if (secured && (type & SEC_ENCRYPT))
1272  e->security |= SMIME_ENCRYPT;
1273  }
1274 
1275  if (((WithCrypto & APPLICATION_PGP) != 0) &&
1277  {
1278  need_secured = 1;
1279 
1280  if (!crypt_valid_passphrase(APPLICATION_PGP))
1281  goto decrypt_failed;
1282 
1283  secured = !crypt_pgp_decrypt_mime(fp, &fp_new, m, &new_body);
1284 
1285  if (secured)
1286  e->security |= PGP_ENCRYPT;
1287  }
1288 
1289  if (need_secured && secured)
1290  {
1291  mutt_actx_add_fp(actx, fp_new);
1292  mutt_actx_add_body(actx, new_body);
1293  mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1294  continue;
1295  }
1296 
1297  decrypt_failed:
1298  /* Fall through and show the original parts if decryption fails */
1299  if (need_secured && !secured)
1300  mutt_error(_("Can't decrypt encrypted message"));
1301 
1302  /* Strip out the top level multipart */
1303  if ((m->type == TYPE_MULTIPART) && m->parts && !need_secured &&
1304  ((parent_type == -1) && mutt_str_strcasecmp("alternative", m->subtype)))
1305  {
1306  mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level, decrypted);
1307  }
1308  else
1309  {
1310  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1311  mutt_actx_add_attach(actx, ap);
1312 
1313  ap->content = m;
1314  ap->fp = fp;
1315  m->aptr = ap;
1316  ap->parent_type = parent_type;
1317  ap->level = level;
1318  ap->decrypted = decrypted;
1319 
1320  if (m->type == TYPE_MULTIPART)
1321  mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level + 1, decrypted);
1322  else if (mutt_is_message_type(m->type, m->subtype))
1323  {
1324  mutt_generate_recvattach_list(actx, m->email, m->parts, fp, m->type,
1325  level + 1, decrypted);
1326  e->security |= m->email->security;
1327  }
1328  }
1329  }
1330 }
1331 
1336 void mutt_attach_init(struct AttachCtx *actx)
1337 {
1338  /* Collapse the attachments if '$digest_collapse' is set AND if...
1339  * the outer container is of type 'multipart/digest' */
1340  bool digest = (mutt_str_strcasecmp(actx->email->content->subtype, "digest") == 0);
1341 
1342  for (int i = 0; i < actx->idxlen; i++)
1343  {
1344  actx->idx[i]->content->tagged = false;
1345 
1346  /* OR an inner container is of type 'multipart/digest' */
1347  actx->idx[i]->content->collapsed =
1348  (C_DigestCollapse &&
1349  (digest ||
1350  ((actx->idx[i]->content->type == TYPE_MULTIPART) &&
1351  (mutt_str_strcasecmp(actx->idx[i]->content->subtype, "digest") == 0))));
1352  }
1353 }
1354 
1361 static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
1362 {
1363  if (init)
1364  {
1365  mutt_generate_recvattach_list(actx, actx->email, actx->email->content,
1366  actx->fp_root, -1, 0, 0);
1367  mutt_attach_init(actx);
1368  menu->data = actx;
1369  }
1370 
1371  mutt_update_tree(actx);
1372 
1373  menu->max = actx->vcount;
1374 
1375  if (menu->current >= menu->max)
1376  menu->current = menu->max - 1;
1377  menu_check_recenter(menu);
1378  menu->redraw |= REDRAW_INDEX;
1379 }
1380 
1386 static void attach_collapse(struct AttachCtx *actx, struct Menu *menu)
1387 {
1388  int rindex, curlevel;
1389 
1390  CUR_ATTACH->content->collapsed = !CUR_ATTACH->content->collapsed;
1391  /* When expanding, expand all the children too */
1392  if (CUR_ATTACH->content->collapsed)
1393  return;
1394 
1395  curlevel = CUR_ATTACH->level;
1396  rindex = actx->v2r[menu->current] + 1;
1397 
1398  while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel))
1399  {
1400  if (C_DigestCollapse && (actx->idx[rindex]->content->type == TYPE_MULTIPART) &&
1401  !mutt_str_strcasecmp(actx->idx[rindex]->content->subtype, "digest"))
1402  {
1403  actx->idx[rindex]->content->collapsed = true;
1404  }
1405  else
1406  {
1407  actx->idx[rindex]->content->collapsed = false;
1408  }
1409  rindex++;
1410  }
1411 }
1412 
1418 {
1419  char helpstr[1024];
1420  int op = OP_NULL;
1421 
1422  struct Mailbox *m = Context ? Context->mailbox : NULL;
1423 
1424  /* make sure we have parsed this message */
1426 
1428 
1429  struct Message *msg = mx_msg_open(m, e->msgno);
1430  if (!msg)
1431  return;
1432 
1433  struct MuttWindow *dlg =
1436 #ifdef USE_DEBUG_WINDOW
1437  dlg->name = "attach";
1438 #endif
1439  dlg->type = WT_DIALOG;
1440  struct MuttWindow *index =
1443  index->type = WT_INDEX;
1444  struct MuttWindow *ibar = mutt_window_new(
1446  ibar->type = WT_INDEX_BAR;
1447 
1448  if (C_StatusOnTop)
1449  {
1450  mutt_window_add_child(dlg, ibar);
1451  mutt_window_add_child(dlg, index);
1452  }
1453  else
1454  {
1455  mutt_window_add_child(dlg, index);
1456  mutt_window_add_child(dlg, ibar);
1457  }
1458 
1459  dialog_push(dlg);
1460 
1461  struct Menu *menu = mutt_menu_new(MENU_ATTACH);
1462 
1463  menu->pagelen = index->state.rows;
1464  menu->win_index = index;
1465  menu->win_ibar = ibar;
1466 
1467  menu->title = _("Attachments");
1468  menu->make_entry = attach_make_entry;
1469  menu->tag = attach_tag;
1470  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_ATTACH, AttachHelp);
1471  mutt_menu_push_current(menu);
1472 
1473  struct AttachCtx *actx = mutt_actx_new();
1474  actx->email = e;
1475  actx->fp_root = msg->fp;
1476  mutt_update_recvattach_menu(actx, menu, true);
1477 
1478  while (true)
1479  {
1480  if (op == OP_NULL)
1481  op = mutt_menu_loop(menu);
1482  if (!Context)
1483  return;
1484  switch (op)
1485  {
1486  case OP_ATTACH_VIEW_MAILCAP:
1488  MUTT_VA_MAILCAP, e, actx, menu->win_index);
1489  menu->redraw = REDRAW_FULL;
1490  break;
1491 
1492  case OP_ATTACH_VIEW_TEXT:
1494  MUTT_VA_AS_TEXT, e, actx, menu->win_index);
1495  menu->redraw = REDRAW_FULL;
1496  break;
1497 
1498  case OP_DISPLAY_HEADERS:
1499  case OP_VIEW_ATTACH:
1500  op = mutt_attach_display_loop(menu, op, e, actx, true);
1501  menu->redraw = REDRAW_FULL;
1502  continue;
1503 
1504  case OP_ATTACH_COLLAPSE:
1505  if (!CUR_ATTACH->content->parts)
1506  {
1507  mutt_error(_("There are no subparts to show"));
1508  break;
1509  }
1510  attach_collapse(actx, menu);
1511  mutt_update_recvattach_menu(actx, menu, false);
1512  break;
1513 
1514  case OP_FORGET_PASSPHRASE:
1516  break;
1517 
1518  case OP_EXTRACT_KEYS:
1520  {
1521  recvattach_extract_pgp_keys(actx, menu);
1522  menu->redraw = REDRAW_FULL;
1523  }
1524  break;
1525 
1526  case OP_CHECK_TRADITIONAL:
1527  if (((WithCrypto & APPLICATION_PGP) != 0) &&
1529  {
1530  e->security = crypt_query(NULL);
1531  menu->redraw = REDRAW_FULL;
1532  }
1533  break;
1534 
1535  case OP_PRINT:
1537  CUR_ATTACH->content);
1538  break;
1539 
1540  case OP_PIPE:
1542  CUR_ATTACH->content, false);
1543  break;
1544 
1545  case OP_SAVE:
1547  CUR_ATTACH->content, e, menu);
1548 
1549  if (!menu->tagprefix && C_Resolve && (menu->current < menu->max - 1))
1550  menu->current++;
1551 
1553  break;
1554 
1555  case OP_DELETE:
1557 
1558 #ifdef USE_POP
1559  if (m->type == MUTT_POP)
1560  {
1561  mutt_flushinp();
1562  mutt_error(_("Can't delete attachment from POP server"));
1563  break;
1564  }
1565 #endif
1566 
1567 #ifdef USE_NNTP
1568  if (m->type == MUTT_NNTP)
1569  {
1570  mutt_flushinp();
1571  mutt_error(_("Can't delete attachment from news server"));
1572  break;
1573  }
1574 #endif
1575 
1576  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1577  {
1578  mutt_message(_("Deletion of attachments from encrypted messages is "
1579  "unsupported"));
1580  break;
1581  }
1582  if ((WithCrypto != 0) && (e->security & (SEC_SIGN | SEC_PARTSIGN)))
1583  {
1584  mutt_message(_("Deletion of attachments from signed messages may "
1585  "invalidate the signature"));
1586  }
1587  if (!menu->tagprefix)
1588  {
1589  if (CUR_ATTACH->parent_type == TYPE_MULTIPART)
1590  {
1591  CUR_ATTACH->content->deleted = true;
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  mutt_message(
1603  _("Only deletion of multipart attachments is supported"));
1604  }
1605  }
1606  else
1607  {
1608  for (int i = 0; i < menu->max; i++)
1609  {
1610  if (actx->idx[i]->content->tagged)
1611  {
1612  if (actx->idx[i]->parent_type == TYPE_MULTIPART)
1613  {
1614  actx->idx[i]->content->deleted = true;
1615  menu->redraw = REDRAW_INDEX;
1616  }
1617  else
1618  {
1619  mutt_message(
1620  _("Only deletion of multipart attachments is supported"));
1621  }
1622  }
1623  }
1624  }
1625  break;
1626 
1627  case OP_UNDELETE:
1629  if (!menu->tagprefix)
1630  {
1631  CUR_ATTACH->content->deleted = false;
1632  if (C_Resolve && (menu->current < menu->max - 1))
1633  {
1634  menu->current++;
1635  menu->redraw = REDRAW_MOTION_RESYNC;
1636  }
1637  else
1638  menu->redraw = REDRAW_CURRENT;
1639  }
1640  else
1641  {
1642  for (int i = 0; i < menu->max; i++)
1643  {
1644  if (actx->idx[i]->content->tagged)
1645  {
1646  actx->idx[i]->content->deleted = false;
1647  menu->redraw = REDRAW_INDEX;
1648  }
1649  }
1650  }
1651  break;
1652 
1653  case OP_RESEND:
1654  CHECK_ATTACH;
1655  mutt_attach_resend(CUR_ATTACH->fp, actx,
1656  menu->tagprefix ? NULL : CUR_ATTACH->content);
1657  menu->redraw = REDRAW_FULL;
1658  break;
1659 
1660  case OP_BOUNCE_MESSAGE:
1661  CHECK_ATTACH;
1662  mutt_attach_bounce(m, CUR_ATTACH->fp, actx,
1663  menu->tagprefix ? NULL : CUR_ATTACH->content);
1664  menu->redraw = REDRAW_FULL;
1665  break;
1666 
1667  case OP_FORWARD_MESSAGE:
1668  CHECK_ATTACH;
1669  mutt_attach_forward(CUR_ATTACH->fp, e, actx,
1670  menu->tagprefix ? NULL : CUR_ATTACH->content, SEND_NO_FLAGS);
1671  menu->redraw = REDRAW_FULL;
1672  break;
1673 
1674 #ifdef USE_NNTP
1675  case OP_FORWARD_TO_GROUP:
1676  CHECK_ATTACH;
1677  mutt_attach_forward(CUR_ATTACH->fp, e, actx,
1678  menu->tagprefix ? NULL : CUR_ATTACH->content, SEND_NEWS);
1679  menu->redraw = REDRAW_FULL;
1680  break;
1681 
1682  case OP_FOLLOWUP:
1683  CHECK_ATTACH;
1684 
1685  if (!CUR_ATTACH->content->email->env->followup_to ||
1686  (mutt_str_strcasecmp(CUR_ATTACH->content->email->env->followup_to, "poster") != 0) ||
1688  _("Reply by mail as poster prefers?")) != MUTT_YES))
1689  {
1690  mutt_attach_reply(CUR_ATTACH->fp, e, actx,
1691  menu->tagprefix ? NULL : CUR_ATTACH->content,
1692  SEND_NEWS | SEND_REPLY);
1693  menu->redraw = REDRAW_FULL;
1694  break;
1695  }
1696 #endif
1697  /* fallthrough */
1698  case OP_REPLY:
1699  case OP_GROUP_REPLY:
1700  case OP_GROUP_CHAT_REPLY:
1701  case OP_LIST_REPLY:
1702  {
1703  CHECK_ATTACH;
1704 
1705  SendFlags flags = SEND_REPLY;
1706  if (op == OP_GROUP_REPLY)
1707  flags |= SEND_GROUP_REPLY;
1708  else if (op == OP_GROUP_CHAT_REPLY)
1709  flags |= SEND_GROUP_CHAT_REPLY;
1710  else if (op == OP_LIST_REPLY)
1711  flags |= SEND_LIST_REPLY;
1712 
1713  mutt_attach_reply(CUR_ATTACH->fp, e, actx,
1714  menu->tagprefix ? NULL : CUR_ATTACH->content, flags);
1715  menu->redraw = REDRAW_FULL;
1716  break;
1717  }
1718 
1719  case OP_COMPOSE_TO_SENDER:
1720  CHECK_ATTACH;
1721  mutt_attach_mail_sender(CUR_ATTACH->fp, e, actx,
1722  menu->tagprefix ? NULL : CUR_ATTACH->content);
1723  menu->redraw = REDRAW_FULL;
1724  break;
1725 
1726  case OP_EDIT_TYPE:
1727  recvattach_edit_content_type(actx, menu, e);
1728  menu->redraw |= REDRAW_INDEX;
1729  break;
1730 
1731  case OP_EXIT:
1732  mx_msg_close(m, &msg);
1733 
1734  e->attach_del = false;
1735  for (int i = 0; i < actx->idxlen; i++)
1736  {
1737  if (actx->idx[i]->content && actx->idx[i]->content->deleted)
1738  {
1739  e->attach_del = true;
1740  break;
1741  }
1742  }
1743  if (e->attach_del)
1744  e->changed = true;
1745 
1746  mutt_actx_free(&actx);
1747 
1748  mutt_menu_pop_current(menu);
1749  mutt_menu_free(&menu);
1750  dialog_pop();
1751  mutt_window_free(&dlg);
1752  return;
1753  }
1754 
1755  op = OP_NULL;
1756  }
1757 
1758  /* not reached */
1759 }
Convenience wrapper for the gui headers.
The "current" mailbox.
Definition: context.h:37
bool C_AttachSplit
Config: Save/print/pipe tagged messages individually.
Definition: recvattach.c:73
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1803
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:252
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:862
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:81
#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.
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
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:75
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define WithCrypto
Definition: lib.h:163
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1392
static bool has_a_message(struct Body *body)
Determine if the Body has a message (to save)
Definition: recvattach.c:489
The envelope/body of an email.
Definition: email.h:37
#define state_puts(STATE, STR)
Definition: state.h:55
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
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
Config/command parsing.
WHERE unsigned char C_Print
Config: Confirm before printing a message.
Definition: globals.h:184
WHERE char * C_AttachFormat
Config: printf-like format string for the attachment menu.
Definition: globals.h:101
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::make_entry()
Definition: recvattach.c:438
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
#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.
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer&#39;s contents to another Buffer.
Definition: buffer.c:445
void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
Definition: recvattach.c:1229
The "currently-open" mailbox.
static const char * Mailbox_is_read_only
Definition: recvattach.c:79
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:329
Dialog (nested Windows) displayed to the user.
Definition: mutt_window.h:70
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:1112
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
#define mutt_message(...)
Definition: logging.h:83
Window uses all available vertical space.
Definition: mutt_window.h:35
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
int oldcurrent
For driver use only.
Definition: mutt_menu.h:108
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1341
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void dialog_pop(void)
Hide a Window from the user.
Definition: mutt_window.c:628
char * C_AttachSaveWithoutPrompting
Config: If true, then don&#39;t prompt to save.
Definition: recvattach.c:71
#define SMIME_ENCRYPT
Definition: lib.h:149
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:125
No flags set.
Definition: mutt_attach.h:55
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:191
void mutt_view_attachments(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1417
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:896
char * C_AttachSep
Config: Separator to add between saved/printed/piped attachments.
Definition: recvattach.c:72
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
static int const char * fmt
Definition: acutest.h:488
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: mutt_window.c:605
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
struct Body * content
List of MIME parts.
Definition: email.h:90
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:464
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:104
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
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:964
#define PGP_ENCRYPT
Definition: lib.h:143
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:74
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:48
#define _(a)
Definition: message.h:28
bool changed
Email has been edited.
Definition: email.h:48
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:44
A division of the screen.
Definition: mutt_window.h:88
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:40
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:123
#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:505
#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:830
View using default method.
Definition: mutt_attach.h:42
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:86
#define MUTT_FORMAT_STAT_FILE
Used by attach_format_str.
Definition: format_flags.h:34
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:656
Flags to control mutt_expando_format()
All user-callable functions.
Container for Accounts, Notifications.
Definition: neomutt.h:35
FILE * fp_in
File to read from.
Definition: state.h:46
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:688
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1438
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
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:89
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:466
An Index Window containing a selection list.
Definition: mutt_window.h:74
int attach_tag(struct Menu *menu, int sel, int act)
Tag an attachment - Implements Menu::tag()
Definition: recvattach.c:450
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
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:74
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:87
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:904
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:1171
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:146
size_t dsize
Length of data.
Definition: buffer.h:37
bool attach_qualifies
This attachment should be counted.
Definition: body.h:83
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1535
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:377
struct Mailbox * mailbox
Definition: context.h:51
Parse and execute user-defined hooks.
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:459
Many unsorted constants and some structs.
API for mailboxes.
Mailcap print field.
Definition: mailcap.h:61
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Context *ctx, struct Mailbox *m, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1505
struct MuttWindow * win_ibar
Definition: mutt_menu.h:95
const char * title
Title of this menu.
Definition: mutt_menu.h:84
void mutt_update_encoding(struct Body *a)
Update the encoding type.
Definition: sendlib.c:1480
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:112
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:38
struct Envelope * env
Envelope information.
Definition: email.h:89
Convenience wrapper for the core headers.
#define ENCODING(x)
Definition: mime.h:85
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:90
bool tagged
This attachment is tagged.
Definition: body.h:70
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:398
#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:82
Window has a fixed size.
Definition: mutt_window.h:44
const char * help
Quickref for the current menu.
Definition: mutt_menu.h:85
char * subtype
content-type subtype
Definition: body.h:37
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:44
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
#define MUTT_CMD
Do completion on previous word.
Definition: mutt.h:60
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition: recvattach.c:113
#define mutt_b2s(buf)
Definition: buffer.h:41
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:138
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
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:78
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:93
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:137
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:55
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:257
A local copy of an email.
Definition: mx.h:83
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:546
Select an attachment.
Definition: keymap.h:72
struct MuttWindow * mutt_window_new(enum MuttWindowOrientation orient, enum MuttWindowSize size, int rows, int cols)
Create a new Window.
Definition: mutt_window.c:56
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
A mailbox.
Definition: mailbox.h:81
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:1121
#define PATH_MAX
Definition: mutt.h:44
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
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:1151
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:49
int num
Attachment index number.
Definition: attach.h:41
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1336
bool tagprefix
Definition: mutt_menu.h:92
static void recvattach_extract_pgp_keys(struct AttachCtx *actx, struct Menu *menu)
Extract PGP keys from attachments.
Definition: recvattach.c:1075
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:961
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:243
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1750
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition: cryptglue.c:460
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1762
char * data
Pointer to data.
Definition: buffer.h:35
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:239
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
static void query_pipe_attachment(const char *command, FILE *fp, struct Body *body, bool filter)
Ask the user if we should pipe the attachment.
Definition: recvattach.c:767
static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1361
char * C_AttachSaveDir
Config: Default directory where attachments are saved.
Definition: recvattach.c:70
static void pipe_attachment_list(const 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:846
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
GUI present the user with a selectable list.
API for encryption/signing of emails.
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:520
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:436
#define SEND_NEWS
Reply to a news article.
Definition: send.h:102
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: sendlib.c:1456
SecurityFlags mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:624
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition: recvattach.c:809
Handling of email attachments.
int(* tag)(struct Menu *menu, int sel, int act)
Tag some menu items.
Definition: mutt_menu.h:138
char * description
content-description
Definition: body.h:40
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:91
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:437
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/lib.h pgplib...
Definition: email.h:39
static int recvattach_pgp_check_traditional(struct AttachCtx *actx, struct Menu *menu)
Is the Attachment inline PGP?
Definition: recvattach.c:1099
static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:924
Force viewing using mailcap entry.
Definition: mutt_attach.h:43
#define SEND_REPLY
Reply to sender.
Definition: send.h:88
#define CHECK_READONLY
Definition: recvattach.c:81
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:455
#define MUTT_FILE
Do file completion.
Definition: mutt.h:58
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
unsigned int type
content-type primary type
Definition: body.h:65
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:473
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
#define mutt_buffer_get_field(field, buf, complete)
Definition: curs_lib.h:84
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:1032
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:756
#define SEC_SIGN
Email is signed.
Definition: lib.h:126
int crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional()
Definition: cryptglue.c:286
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:579
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:1386
#define TYPE(body)
Definition: mime.h:83
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:89
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:212
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:327
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:1221
Routines for managing attachments.
Log at debug level 1.
Definition: logging.h:40
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:271
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:208
#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:137
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:654
Quoted-printable text.
Definition: mime.h:51
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:142
FILE * fp
pointer to the message data
Definition: mx.h:85
Append to existing file.
Definition: mutt_attach.h:56
#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
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:374
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:1074
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:46
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:139
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Miscellaneous functions for sending an email.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:38
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:576
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:101
static const char * Function_not_permitted
Definition: recvattach.c:96
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1249
int const char int line
Definition: acutest.h:617
int current
Current entry.
Definition: mutt_menu.h:87
struct MuttWindow * win_index
Definition: mutt_menu.h:94
Convenience wrapper for the library headers.
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:116
Window wants as much space as possible.
Definition: mutt_window.h:45
#define CHECK_ATTACH
Definition: recvattach.c:99
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Decide how to display email content.
#define N_(a)
Definition: message.h:32
struct Email * email
header information for message/rfc822
Definition: body.h:55
Index Bar containing status info about the Index.
Definition: mutt_window.h:75
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:103
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:700
void(* make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:119
void mutt_attach_resend(FILE *fp, struct AttachCtx *actx, struct Body *cur)
resend-message, from the attachment menu
Definition: recvcmd.c:291
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:713
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:641
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1123
#define SEC_PARTSIGN
Not all parts of the email is signed.
Definition: lib.h:129
#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:877
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:1233
short vcount
The number of virtual attachments.
Definition: attach.h:59
int msgno
Number displayed to the user.
Definition: email.h:86
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:53
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:415
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1060
Horizontal line.
Definition: mutt_menu.h:64