NeoMutt  2021-02-05-89-gabe350
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/lib.h"
38 #include "config/lib.h"
39 #include "email/lib.h"
40 #include "core/lib.h"
41 #include "gui/lib.h"
42 #include "mutt.h"
43 #include "recvattach.h"
44 #include "ncrypt/lib.h"
45 #include "nntp/lib.h"
46 #include "send/lib.h"
47 #include "commands.h"
48 #include "context.h"
49 #include "format_flags.h"
50 #include "handler.h"
51 #include "hdrline.h"
52 #include "hook.h"
53 #include "keymap.h"
54 #include "mailcap.h"
55 #include "mutt_attach.h"
56 #include "mutt_globals.h"
57 #include "mutt_menu.h"
58 #include "mutt_parse.h"
59 #include "mutt_thread.h"
60 #include "muttlib.h"
61 #include "mx.h"
62 #include "opcodes.h"
63 #include "options.h"
64 #include "recvcmd.h"
65 #include "rfc3676.h"
66 #include "state.h"
67 #ifdef ENABLE_NLS
68 #include <libintl.h>
69 #endif
70 
71 /* These Config Variables are only used in recvattach.c */
74 char *C_AttachSep;
78 
79 static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init);
80 
81 static const char *Mailbox_is_read_only = N_("Mailbox is read-only");
82 
83 #define CHECK_READONLY \
84  if (!Context || !Context->mailbox || Context->mailbox->readonly) \
85  { \
86  mutt_flushinp(); \
87  mutt_error(_(Mailbox_is_read_only)); \
88  break; \
89  }
90 
91 #define CUR_ATTACH actx->idx[actx->v2r[menu->current]]
92 
94 static const struct Mapping AttachHelp[] = {
95  // clang-format off
96  { N_("Exit"), OP_EXIT },
97  { N_("Save"), OP_SAVE },
98  { N_("Pipe"), OP_PIPE },
99  { N_("Print"), OP_PRINT },
100  { N_("Help"), OP_HELP },
101  { NULL, 0 },
102  // clang-format on
103 };
104 
105 static const char *Function_not_permitted =
106  N_("Function not permitted in attach-message mode");
107 
108 #define CHECK_ATTACH \
109  if (OptAttachMsg) \
110  { \
111  mutt_flushinp(); \
112  mutt_error(_(Function_not_permitted)); \
113  break; \
114  }
115 
122 static void mutt_update_v2r(struct AttachCtx *actx)
123 {
124  int vindex, rindex, curlevel;
125 
126  vindex = 0;
127  rindex = 0;
128 
129  while (rindex < actx->idxlen)
130  {
131  actx->v2r[vindex++] = rindex;
132  if (actx->idx[rindex]->body->collapsed)
133  {
134  curlevel = actx->idx[rindex]->level;
135  do
136  {
137  rindex++;
138  } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
139  }
140  else
141  rindex++;
142  }
143 
144  actx->vcount = vindex;
145 }
146 
151 void mutt_update_tree(struct AttachCtx *actx)
152 {
153  char buf[256];
154  char *s = NULL;
155 
156  mutt_update_v2r(actx);
157 
158  for (int vindex = 0; vindex < actx->vcount; vindex++)
159  {
160  const int rindex = actx->v2r[vindex];
161  actx->idx[rindex]->num = vindex;
162  if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
163  {
164  if (actx->idx[rindex]->level)
165  {
166  s = buf + 2 * (actx->idx[rindex]->level - 1);
167  *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
168  *s++ = MUTT_TREE_HLINE;
169  *s++ = MUTT_TREE_RARROW;
170  }
171  else
172  s = buf;
173  *s = '\0';
174  }
175 
176  if (actx->idx[rindex]->tree)
177  {
178  if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
179  mutt_str_replace(&actx->idx[rindex]->tree, buf);
180  }
181  else
182  actx->idx[rindex]->tree = mutt_str_dup(buf);
183 
184  if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
185  actx->idx[rindex]->level)
186  {
187  s = buf + 2 * (actx->idx[rindex]->level - 1);
188  *s++ = (actx->idx[rindex]->body->next) ? '\005' : '\006';
189  *s++ = '\006';
190  }
191  }
192 }
193 
217 const char *attach_format_str(char *buf, size_t buflen, size_t col, int cols, char op,
218  const char *src, const char *prec, const char *if_str,
219  const char *else_str, intptr_t data, MuttFormatFlags flags)
220 {
221  char fmt[128];
222  char charset[128];
223  struct AttachPtr *aptr = (struct AttachPtr *) data;
224  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
225 
226  switch (op)
227  {
228  case 'C':
229  if (!optional)
230  {
231  if (mutt_is_text_part(aptr->body) &&
232  mutt_body_get_charset(aptr->body, charset, sizeof(charset)))
233  {
234  mutt_format_s(buf, buflen, prec, charset);
235  }
236  else
237  mutt_format_s(buf, buflen, prec, "");
238  }
239  else if (!mutt_is_text_part(aptr->body) ||
240  !mutt_body_get_charset(aptr->body, charset, sizeof(charset)))
241  {
242  optional = false;
243  }
244  break;
245  case 'c':
246  /* XXX */
247  if (!optional)
248  {
249  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
250  snprintf(buf, buflen, fmt,
251  ((aptr->body->type != TYPE_TEXT) || aptr->body->noconv) ? 'n' : 'c');
252  }
253  else if ((aptr->body->type != TYPE_TEXT) || aptr->body->noconv)
254  optional = false;
255  break;
256  case 'd':
257  if (!optional)
258  {
259  if (aptr->body->description)
260  {
261  mutt_format_s(buf, buflen, prec, aptr->body->description);
262  break;
263  }
264  if (mutt_is_message_type(aptr->body->type, aptr->body->subtype) &&
265  C_MessageFormat && aptr->body->email)
266  {
267  char s[128];
268  mutt_make_string(s, sizeof(s), cols, C_MessageFormat, NULL, -1,
269  aptr->body->email,
271  if (*s)
272  {
273  mutt_format_s(buf, buflen, prec, s);
274  break;
275  }
276  }
277  if (!aptr->body->d_filename && !aptr->body->filename)
278  {
279  mutt_format_s(buf, buflen, prec, "<no description>");
280  break;
281  }
282  }
283  else if (aptr->body->description ||
284  (mutt_is_message_type(aptr->body->type, aptr->body->subtype) &&
285  C_MessageFormat && aptr->body->email))
286  {
287  break;
288  }
289  /* fallthrough */
290  case 'F':
291  if (!optional)
292  {
293  if (aptr->body->d_filename)
294  {
295  mutt_format_s(buf, buflen, prec, aptr->body->d_filename);
296  break;
297  }
298  }
299  else if (!aptr->body->d_filename && !aptr->body->filename)
300  {
301  optional = false;
302  break;
303  }
304  /* fallthrough */
305  case 'f':
306  if (!optional)
307  {
308  if (aptr->body->filename && (*aptr->body->filename == '/'))
309  {
310  struct Buffer *path = mutt_buffer_pool_get();
311 
312  mutt_buffer_strcpy(path, aptr->body->filename);
314  mutt_format_s(buf, buflen, prec, mutt_buffer_string(path));
316  }
317  else
318  mutt_format_s(buf, buflen, prec, NONULL(aptr->body->filename));
319  }
320  else if (!aptr->body->filename)
321  optional = false;
322  break;
323  case 'D':
324  if (!optional)
325  snprintf(buf, buflen, "%c", aptr->body->deleted ? 'D' : ' ');
326  else if (!aptr->body->deleted)
327  optional = false;
328  break;
329  case 'e':
330  if (!optional)
331  mutt_format_s(buf, buflen, prec, ENCODING(aptr->body->encoding));
332  break;
333  case 'I':
334  if (optional)
335  break;
336 
337  const char dispchar[] = { 'I', 'A', 'F', '-' };
338  char ch;
339 
340  if (aptr->body->disposition < sizeof(dispchar))
341  ch = dispchar[aptr->body->disposition];
342  else
343  {
344  mutt_debug(LL_DEBUG1, "ERROR: invalid content-disposition %d\n",
345  aptr->body->disposition);
346  ch = '!';
347  }
348  snprintf(buf, buflen, "%c", ch);
349  break;
350  case 'm':
351  if (!optional)
352  mutt_format_s(buf, buflen, prec, TYPE(aptr->body));
353  break;
354  case 'M':
355  if (!optional)
356  mutt_format_s(buf, buflen, prec, aptr->body->subtype);
357  else if (!aptr->body->subtype)
358  optional = false;
359  break;
360  case 'n':
361  if (optional)
362  break;
363 
364  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
365  snprintf(buf, buflen, fmt, aptr->num + 1);
366  break;
367  case 'Q':
368  if (optional)
369  optional = aptr->body->attach_qualifies;
370  else
371  {
372  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
373  mutt_format_s(buf, buflen, fmt, "Q");
374  }
375  break;
376  case 's':
377  {
378  size_t l;
379  if (aptr->body->filename && (flags & MUTT_FORMAT_STAT_FILE))
380  {
381  struct stat st;
382  stat(aptr->body->filename, &st);
383  l = st.st_size;
384  }
385  else
386  l = aptr->body->length;
387 
388  if (!optional)
389  {
390  char tmp[128];
391  mutt_str_pretty_size(tmp, sizeof(tmp), l);
392  mutt_format_s(buf, buflen, prec, tmp);
393  }
394  else if (l == 0)
395  optional = false;
396 
397  break;
398  }
399  case 't':
400  if (!optional)
401  snprintf(buf, buflen, "%c", aptr->body->tagged ? '*' : ' ');
402  else if (!aptr->body->tagged)
403  optional = false;
404  break;
405  case 'T':
406  if (!optional)
407  mutt_format_s_tree(buf, buflen, prec, NONULL(aptr->tree));
408  else if (!aptr->tree)
409  optional = false;
410  break;
411  case 'u':
412  if (!optional)
413  snprintf(buf, buflen, "%c", aptr->body->unlink ? '-' : ' ');
414  else if (!aptr->body->unlink)
415  optional = false;
416  break;
417  case 'X':
418  if (optional)
419  optional = ((aptr->body->attach_count + aptr->body->attach_qualifies) != 0);
420  else
421  {
422  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
423  snprintf(buf, buflen, fmt, aptr->body->attach_count + aptr->body->attach_qualifies);
424  }
425  break;
426  default:
427  *buf = '\0';
428  }
429 
430  if (optional)
431  {
432  mutt_expando_format(buf, buflen, col, cols, if_str, attach_format_str, data,
434  }
435  else if (flags & MUTT_FORMAT_OPTIONAL)
436  {
437  mutt_expando_format(buf, buflen, col, cols, else_str, attach_format_str,
438  data, MUTT_FORMAT_NO_FLAGS);
439  }
440  return src;
441 }
442 
446 static void attach_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
447 {
448  struct AttachCtx *actx = menu->mdata;
449 
450  mutt_expando_format(buf, buflen, 0, menu->win_index->state.cols,
452  (intptr_t)(actx->idx[actx->v2r[line]]), MUTT_FORMAT_ARROWCURSOR);
453 }
454 
458 int attach_tag(struct Menu *menu, int sel, int act)
459 {
460  struct AttachCtx *actx = menu->mdata;
461  struct Body *cur = actx->idx[actx->v2r[sel]]->body;
462  bool ot = cur->tagged;
463 
464  cur->tagged = ((act >= 0) ? act : !cur->tagged);
465  return cur->tagged - ot;
466 }
467 
472 static void prepend_savedir(struct Buffer *buf)
473 {
474  if (!buf || !buf->data || (buf->data[0] == '/'))
475  return;
476 
477  struct Buffer *tmp = mutt_buffer_pool_get();
478  if (C_AttachSaveDir)
479  {
481  if (tmp->dptr[-1] != '/')
482  mutt_buffer_addch(tmp, '/');
483  }
484  else
485  mutt_buffer_addstr(tmp, "./");
486 
488  mutt_buffer_copy(buf, tmp);
490 }
491 
497 static bool has_a_message(struct Body *body)
498 {
499  return (body->email && (body->encoding != ENC_BASE64) &&
500  (body->encoding != ENC_QUOTED_PRINTABLE) &&
501  mutt_is_message_type(body->type, body->subtype));
502 }
503 
529 static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path,
530  enum SaveAttach flags, struct Email *e)
531 {
532  int rc = -1;
533 
535  {
536  struct Body b_fake = { 0 };
537 
538  struct Buffer *tempfile = mutt_buffer_pool_get();
539  mutt_buffer_mktemp(tempfile);
540 
541  /* Pass MUTT_SAVE_NO_FLAGS to force mutt_file_fopen("w") */
543  if (rc != 0)
544  goto cleanup;
545 
547 
548  /* Now "really" save it. Send mode does this without touching anything,
549  * so force send-mode. */
550  memset(&b_fake, 0, sizeof(struct Body));
551  b_fake.filename = tempfile->data;
552  rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
553 
555 
556  cleanup:
557  mutt_buffer_pool_release(&tempfile);
558  }
559  else
560  {
561  rc = mutt_save_attachment(fp, b, path, flags, e);
562  }
563 
564  return rc;
565 }
566 
576 static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
577 {
578  char *prompt = NULL;
579  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
580  int rc = -1;
581 
582  struct Buffer *buf = mutt_buffer_pool_get();
583  struct Buffer *tfile = mutt_buffer_pool_get();
584 
585  if (body->filename)
586  {
587  if (directory && *directory)
588  {
589  mutt_buffer_concat_path(buf, *directory, mutt_path_basename(body->filename));
590  }
591  else
592  mutt_buffer_strcpy(buf, body->filename);
593  }
594  else if (has_a_message(body))
595  {
596  mutt_default_save(buf->data, buf->dsize, body->email);
598  }
599 
600  prepend_savedir(buf);
601 
602  prompt = _("Save to file: ");
603  while (prompt)
604  {
605  if ((mutt_buffer_get_field(prompt, buf, MUTT_FILE | MUTT_CLEAR, false, NULL,
606  NULL, NULL) != 0) ||
608  {
609  goto cleanup;
610  }
611 
612  prompt = NULL;
614 
615  bool is_message = (fp && has_a_message(body));
616 
617  if (is_message)
618  {
619  struct stat st;
620 
621  /* check to make sure that this file is really the one the user wants */
622  rc = mutt_save_confirm(mutt_buffer_string(buf), &st);
623  if (rc == 1)
624  {
625  prompt = _("Save to file: ");
626  continue;
627  }
628  else if (rc == -1)
629  goto cleanup;
630  mutt_buffer_copy(tfile, buf);
631  }
632  else
633  {
634  rc = mutt_check_overwrite(body->filename, mutt_buffer_string(buf), tfile,
635  &opt, directory);
636  if (rc == -1)
637  goto cleanup;
638  else if (rc == 1)
639  {
640  prompt = _("Save to file: ");
641  continue;
642  }
643  }
644 
645  mutt_message(_("Saving..."));
646  if (save_attachment_flowed_helper(fp, body, mutt_buffer_string(tfile), opt,
647  (e || !is_message) ? e : body->email) == 0)
648  {
649  mutt_message(_("Attachment saved"));
650  rc = 0;
651  goto cleanup;
652  }
653  else
654  {
655  prompt = _("Save to file: ");
656  continue;
657  }
658  }
659 
660 cleanup:
662  mutt_buffer_pool_release(&tfile);
663  return rc;
664 }
665 
674 static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
675 {
676  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
677  int rc = -1;
678  struct Buffer *buf = mutt_buffer_pool_get();
679  struct Buffer *tfile = mutt_buffer_pool_get();
680 
681  if (body->filename)
682  {
683  mutt_buffer_strcpy(buf, body->filename);
684  }
685  else if (has_a_message(body))
686  {
687  mutt_default_save(buf->data, buf->dsize, body->email);
688  }
689 
690  prepend_savedir(buf);
692 
693  bool is_message = (fp && has_a_message(body));
694 
695  if (is_message)
696  {
697  mutt_buffer_copy(tfile, buf);
698  }
699  else
700  {
701  rc = mutt_check_overwrite(body->filename, mutt_buffer_string(buf), tfile, &opt, NULL);
702  if (rc == -1) // abort or cancel
703  goto cleanup;
704  }
705 
706  rc = save_attachment_flowed_helper(fp, body, mutt_buffer_string(tfile), opt,
707  (e || !is_message) ? e : body->email);
708 
709 cleanup:
711  mutt_buffer_pool_release(&tfile);
712  return rc;
713 }
714 
724 void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
725  struct Body *top, struct Email *e, struct Menu *menu)
726 {
727  char *directory = NULL;
728  int rc = 1;
729  int last = menu ? menu->current : -1;
730  FILE *fp_out = NULL;
731  int saved_attachments = 0;
732 
733  struct Buffer *buf = mutt_buffer_pool_get();
734  struct Buffer *tfile = mutt_buffer_pool_get();
735 
736  for (int i = 0; !tag || (i < actx->idxlen); i++)
737  {
738  if (tag)
739  {
740  fp = actx->idx[i]->fp;
741  top = actx->idx[i]->body;
742  }
743  if (!tag || top->tagged)
744  {
745  if (!C_AttachSplit)
746  {
747  if (mutt_buffer_is_empty(buf))
748  {
749  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
750 
752  prepend_savedir(buf);
753 
754  if ((mutt_buffer_get_field(_("Save to file: "), buf, MUTT_FILE | MUTT_CLEAR,
755  false, NULL, NULL, NULL) != 0) ||
757  {
758  goto cleanup;
759  }
761  if (mutt_check_overwrite(top->filename, mutt_buffer_string(buf), tfile, &opt, NULL))
762  goto cleanup;
763  rc = save_attachment_flowed_helper(fp, top, mutt_buffer_string(tfile), opt, e);
764  if ((rc == 0) && C_AttachSep && (fp_out = fopen(mutt_buffer_string(tfile), "a")))
765  {
766  fprintf(fp_out, "%s", C_AttachSep);
767  mutt_file_fclose(&fp_out);
768  }
769  }
770  else
771  {
773  MUTT_SAVE_APPEND, e);
774  if ((rc == 0) && C_AttachSep && (fp_out = fopen(mutt_buffer_string(tfile), "a")))
775  {
776  fprintf(fp_out, "%s", C_AttachSep);
777  mutt_file_fclose(&fp_out);
778  }
779  }
780  }
781  else
782  {
783  if (tag && menu && top->aptr)
784  {
785  menu->oldcurrent = menu->current;
786  menu->current = top->aptr->num;
787  menu_check_recenter(menu);
788  menu->redraw |= REDRAW_MOTION;
789 
790  menu_redraw(menu);
791  }
793  {
794  // Save each file, with no prompting, using the configured 'AttachSaveDir'
795  rc = save_without_prompting(fp, top, e);
796  if (rc == 0)
797  saved_attachments++;
798  }
799  else
800  {
801  // Save each file, prompting the user for the location each time.
802  if (query_save_attachment(fp, top, e, &directory) == -1)
803  break;
804  }
805  }
806  }
807  if (!tag)
808  break;
809  }
810 
811  FREE(&directory);
812 
813  if (tag && menu)
814  {
815  menu->oldcurrent = menu->current;
816  menu->current = last;
817  menu_check_recenter(menu);
818  menu->redraw |= REDRAW_MOTION;
819  }
820 
821  if (!C_AttachSplit && (rc == 0))
822  mutt_message(_("Attachment saved"));
823 
824  if (C_AttachSaveWithoutPrompting && (rc == 0))
825  {
826  mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
827  saved_attachments);
828  }
829 
830 cleanup:
832  mutt_buffer_pool_release(&tfile);
833 }
834 
842 static void query_pipe_attachment(const char *command, FILE *fp, struct Body *body, bool filter)
843 {
844  char tfile[PATH_MAX];
845 
846  if (filter)
847  {
848  char warning[PATH_MAX + 256];
849  snprintf(warning, sizeof(warning),
850  _("WARNING! You are about to overwrite %s, continue?"), body->filename);
851  if (mutt_yesorno(warning, MUTT_NO) != MUTT_YES)
852  {
854  return;
855  }
856  mutt_mktemp(tfile, sizeof(tfile));
857  }
858  else
859  tfile[0] = '\0';
860 
861  if (mutt_pipe_attachment(fp, body, command, tfile))
862  {
863  if (filter)
864  {
865  mutt_file_unlink(body->filename);
866  mutt_file_rename(tfile, body->filename);
868  mutt_message(_("Attachment filtered"));
869  }
870  }
871  else
872  {
873  if (filter && tfile[0])
874  mutt_file_unlink(tfile);
875  }
876 }
877 
884 static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
885 {
886  if (!state || !state->fp_out)
887  return;
888 
889  FILE *fp_in = NULL;
890  FILE *fp_unstuff = NULL;
891  bool is_flowed = false, unlink_unstuff = false;
892  struct Buffer *unstuff_tempfile = NULL;
893 
895  {
896  is_flowed = true;
897  unstuff_tempfile = mutt_buffer_pool_get();
898  mutt_buffer_mktemp(unstuff_tempfile);
899  }
900 
901  if (fp)
902  {
903  state->fp_in = fp;
904 
905  if (is_flowed)
906  {
907  fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "w");
908  if (fp_unstuff == NULL)
909  {
910  mutt_perror("mutt_file_fopen");
911  goto bail;
912  }
913  unlink_unstuff = true;
914 
915  FILE *filter_fp = state->fp_out;
916  state->fp_out = fp_unstuff;
917  mutt_decode_attachment(b, state);
918  mutt_file_fclose(&fp_unstuff);
919  state->fp_out = filter_fp;
920 
921  fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "r");
922  if (fp_unstuff == NULL)
923  {
924  mutt_perror("mutt_file_fopen");
925  goto bail;
926  }
927  mutt_file_copy_stream(fp_unstuff, filter_fp);
928  mutt_file_fclose(&fp_unstuff);
929  }
930  else
931  mutt_decode_attachment(b, state);
932  }
933  else
934  {
935  const char *infile = NULL;
936 
937  if (is_flowed)
938  {
939  if (mutt_save_attachment(fp, b, mutt_buffer_string(unstuff_tempfile), 0, NULL) == -1)
940  goto bail;
941  unlink_unstuff = true;
943  infile = mutt_buffer_string(unstuff_tempfile);
944  }
945  else
946  infile = b->filename;
947 
948  fp_in = fopen(infile, "r");
949  if (!fp_in)
950  {
951  mutt_perror("fopen");
952  goto bail;
953  }
954  mutt_file_copy_stream(fp_in, state->fp_out);
955  mutt_file_fclose(&fp_in);
956  }
957 
958  if (C_AttachSep)
959  state_puts(state, C_AttachSep);
960 
961 bail:
962  mutt_file_fclose(&fp_unstuff);
963  mutt_file_fclose(&fp_in);
964 
965  if (unlink_unstuff)
966  mutt_file_unlink(mutt_buffer_string(unstuff_tempfile));
967  mutt_buffer_pool_release(&unstuff_tempfile);
968 }
969 
980 static void pipe_attachment_list(const char *command, struct AttachCtx *actx,
981  FILE *fp, bool tag, struct Body *top,
982  bool filter, struct State *state)
983 {
984  for (int i = 0; !tag || (i < actx->idxlen); i++)
985  {
986  if (tag)
987  {
988  fp = actx->idx[i]->fp;
989  top = actx->idx[i]->body;
990  }
991  if (!tag || top->tagged)
992  {
993  if (!filter && !C_AttachSplit)
994  pipe_attachment(fp, top, state);
995  else
996  query_pipe_attachment(command, fp, top, filter);
997  }
998  if (!tag)
999  break;
1000  }
1001 }
1002 
1011 void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
1012  struct Body *top, bool filter)
1013 {
1014  struct State state = { 0 };
1015  struct Buffer *buf = NULL;
1016 
1017  if (fp)
1018  filter = false; /* sanity check: we can't filter in the recv case yet */
1019 
1020  buf = mutt_buffer_pool_get();
1021  /* perform charset conversion on text attachments when piping */
1022  state.flags = MUTT_CHARCONV;
1023 
1024  if (mutt_buffer_get_field((filter ? _("Filter through: ") : _("Pipe to: ")),
1025  buf, MUTT_CMD, false, NULL, NULL, NULL) != 0)
1026  {
1027  goto cleanup;
1028  }
1029 
1030  if (mutt_buffer_len(buf) == 0)
1031  goto cleanup;
1032 
1034 
1035  if (!filter && !C_AttachSplit)
1036  {
1037  mutt_endwin();
1038  pid_t pid = filter_create(mutt_buffer_string(buf), &state.fp_out, NULL, NULL);
1039  pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
1040  mutt_file_fclose(&state.fp_out);
1041  if ((filter_wait(pid) != 0) || C_WaitKey)
1043  }
1044  else
1045  pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
1046 
1047 cleanup:
1049 }
1050 
1058 static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
1059 {
1060  char type[256];
1061 
1062  for (int i = 0; !tag || (i < actx->idxlen); i++)
1063  {
1064  if (tag)
1065  top = actx->idx[i]->body;
1066  snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
1067  if (!tag || top->tagged)
1068  {
1069  if (!mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
1070  {
1071  if (!mutt_istr_equal("text/plain", top->subtype) &&
1072  !mutt_istr_equal("application/postscript", top->subtype))
1073  {
1074  if (!mutt_can_decode(top))
1075  {
1076  /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
1077  application/octet-stream. */
1078  mutt_error(_("I don't know how to print %s attachments"), type);
1079  return false;
1080  }
1081  }
1082  }
1083  }
1084  if (!tag)
1085  break;
1086  }
1087  return true;
1088 }
1089 
1098 static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
1099  struct Body *top, struct State *state)
1100 {
1101  char type[256];
1102 
1103  for (int i = 0; !tag || (i < actx->idxlen); i++)
1104  {
1105  if (tag)
1106  {
1107  fp = actx->idx[i]->fp;
1108  top = actx->idx[i]->body;
1109  }
1110  if (!tag || top->tagged)
1111  {
1112  snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
1113  if (!C_AttachSplit && !mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
1114  {
1115  if (mutt_istr_equal("text/plain", top->subtype) ||
1116  mutt_istr_equal("application/postscript", top->subtype))
1117  {
1118  pipe_attachment(fp, top, state);
1119  }
1120  else if (mutt_can_decode(top))
1121  {
1122  /* decode and print */
1123 
1124  FILE *fp_in = NULL;
1125  struct Buffer *newfile = mutt_buffer_pool_get();
1126 
1127  mutt_buffer_mktemp(newfile);
1128  if (mutt_decode_save_attachment(fp, top, mutt_buffer_string(newfile),
1130  {
1131  if (!state->fp_out)
1132  {
1133  mutt_error(
1134  "BUG in print_attachment_list(). Please report this. ");
1135  return;
1136  }
1137 
1138  fp_in = fopen(mutt_buffer_string(newfile), "r");
1139  if (fp_in)
1140  {
1141  mutt_file_copy_stream(fp_in, state->fp_out);
1142  mutt_file_fclose(&fp_in);
1143  if (C_AttachSep)
1144  state_puts(state, C_AttachSep);
1145  }
1146  }
1148  mutt_buffer_pool_release(&newfile);
1149  }
1150  }
1151  else
1152  mutt_print_attachment(fp, top);
1153  }
1154  if (!tag)
1155  break;
1156  }
1157 }
1158 
1166 void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
1167 {
1168  char prompt[128];
1169  struct State state = { 0 };
1170  int tagmsgcount = 0;
1171 
1172  if (tag)
1173  for (int i = 0; i < actx->idxlen; i++)
1174  if (actx->idx[i]->body->tagged)
1175  tagmsgcount++;
1176 
1177  snprintf(prompt, sizeof(prompt),
1178  /* L10N: Although we now the precise number of tagged messages, we
1179  do not show it to the user. So feel free to use a "generic
1180  plural" as plural translation if your language has one. */
1181  tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
1182  _("Print attachment?"),
1183  tagmsgcount);
1184  if (query_quadoption(C_Print, prompt) != MUTT_YES)
1185  return;
1186 
1187  if (C_AttachSplit)
1188  {
1189  print_attachment_list(actx, fp, tag, top, &state);
1190  }
1191  else
1192  {
1193  if (!can_print(actx, top, tag))
1194  return;
1195  mutt_endwin();
1196  pid_t pid = filter_create(NONULL(C_PrintCommand), &state.fp_out, NULL, NULL);
1197  print_attachment_list(actx, fp, tag, top, &state);
1198  mutt_file_fclose(&state.fp_out);
1199  if ((filter_wait(pid) != 0) || C_WaitKey)
1201  }
1202 }
1203 
1209 static void recvattach_extract_pgp_keys(struct AttachCtx *actx, struct Menu *menu)
1210 {
1211  if (!menu->tagprefix)
1213  else
1214  {
1215  for (int i = 0; i < actx->idxlen; i++)
1216  {
1217  if (actx->idx[i]->body->tagged)
1218  {
1219  crypt_pgp_extract_key_from_attachment(actx->idx[i]->fp, actx->idx[i]->body);
1220  }
1221  }
1222  }
1223 }
1224 
1233 static int recvattach_pgp_check_traditional(struct AttachCtx *actx, struct Menu *menu)
1234 {
1235  int rc = 0;
1236 
1237  if (!menu->tagprefix)
1238  rc = crypt_pgp_check_traditional(CUR_ATTACH->fp, CUR_ATTACH->body, true);
1239  else
1240  {
1241  for (int i = 0; i < actx->idxlen; i++)
1242  if (actx->idx[i]->body->tagged)
1243  rc = rc || crypt_pgp_check_traditional(actx->idx[i]->fp, actx->idx[i]->body, true);
1244  }
1245 
1246  return rc;
1247 }
1248 
1255 static void recvattach_edit_content_type(struct AttachCtx *actx,
1256  struct Menu *menu, struct Email *e)
1257 {
1258  if (!mutt_edit_content_type(e, CUR_ATTACH->body, CUR_ATTACH->fp))
1259  return;
1260 
1261  /* The mutt_update_recvattach_menu() will overwrite any changes
1262  * made to a decrypted CUR_ATTACH->body, so warn the user. */
1263  if (CUR_ATTACH->decrypted)
1264  {
1265  mutt_message(
1266  _("Structural changes to decrypted attachments are not supported"));
1267  mutt_sleep(1);
1268  }
1269  /* Editing the content type can rewrite the body structure. */
1270  for (int i = 0; i < actx->idxlen; i++)
1271  actx->idx[i]->body = NULL;
1272  mutt_actx_entries_free(actx);
1273  mutt_update_recvattach_menu(actx, menu, true);
1274 }
1275 
1285 int mutt_attach_display_loop(struct Menu *menu, int op, struct Email *e,
1286  struct AttachCtx *actx, bool recv)
1287 {
1288  do
1289  {
1290  switch (op)
1291  {
1292  case OP_DISPLAY_HEADERS:
1293  bool_str_toggle(NeoMutt->sub, "weed", NULL);
1294  /* fallthrough */
1295 
1296  case OP_VIEW_ATTACH:
1297  op = mutt_view_attachment(CUR_ATTACH->fp, CUR_ATTACH->body,
1298  MUTT_VA_REGULAR, e, actx, menu->win_index);
1299  break;
1300 
1301  case OP_NEXT_ENTRY:
1302  case OP_MAIN_NEXT_UNDELETED: /* hack */
1303  if (menu->current < menu->max - 1)
1304  {
1305  menu->current++;
1306  op = OP_VIEW_ATTACH;
1307  }
1308  else
1309  op = OP_NULL;
1310  break;
1311  case OP_PREV_ENTRY:
1312  case OP_MAIN_PREV_UNDELETED: /* hack */
1313  if (menu->current > 0)
1314  {
1315  menu->current--;
1316  op = OP_VIEW_ATTACH;
1317  }
1318  else
1319  op = OP_NULL;
1320  break;
1321  case OP_EDIT_TYPE:
1322  /* when we edit the content-type, we should redisplay the attachment
1323  * immediately */
1325  if (recv)
1326  recvattach_edit_content_type(actx, menu, e);
1327  else
1329 
1330  menu->redraw |= REDRAW_INDEX;
1331  op = OP_VIEW_ATTACH;
1332  break;
1333  /* functions which are passed through from the pager */
1334  case OP_CHECK_TRADITIONAL:
1336  {
1337  op = OP_NULL;
1338  break;
1339  }
1340  /* fallthrough */
1341  case OP_ATTACH_COLLAPSE:
1342  if (recv)
1343  return op;
1344  /* fallthrough */
1345  default:
1346  op = OP_NULL;
1347  }
1348  } while (op != OP_NULL);
1349 
1350  return op;
1351 }
1352 
1363 void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e,
1364  struct Body *parts, FILE *fp,
1365  int parent_type, int level, bool decrypted)
1366 {
1367  struct Body *m = NULL;
1368  struct Body *new_body = NULL;
1369  FILE *fp_new = NULL;
1371  int need_secured, secured;
1372 
1373  for (m = parts; m; m = m->next)
1374  {
1375  need_secured = 0;
1376  secured = 0;
1377 
1379  {
1380  need_secured = 1;
1381 
1382  if (type & SEC_ENCRYPT)
1383  {
1385  goto decrypt_failed;
1386 
1387  if (e->env)
1389  }
1390 
1391  secured = !crypt_smime_decrypt_mime(fp, &fp_new, m, &new_body);
1392  /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1393  * text/plain type will still be returned by mutt_read_mime_header().
1394  * We can't distinguish an actual part from a failure, so only use a
1395  * text/plain that results from a single top-level part. */
1396  if (secured && (new_body->type == TYPE_TEXT) &&
1397  mutt_istr_equal("plain", new_body->subtype) && ((parts != m) || m->next))
1398  {
1399  mutt_body_free(&new_body);
1400  mutt_file_fclose(&fp_new);
1401  goto decrypt_failed;
1402  }
1403 
1404  if (secured && (type & SEC_ENCRYPT))
1405  e->security |= SMIME_ENCRYPT;
1406  }
1407 
1408  if (((WithCrypto & APPLICATION_PGP) != 0) &&
1410  {
1411  need_secured = 1;
1412 
1414  goto decrypt_failed;
1415 
1416  secured = !crypt_pgp_decrypt_mime(fp, &fp_new, m, &new_body);
1417 
1418  if (secured)
1419  e->security |= PGP_ENCRYPT;
1420  }
1421 
1422  if (need_secured && secured)
1423  {
1424  mutt_actx_add_fp(actx, fp_new);
1425  mutt_actx_add_body(actx, new_body);
1426  mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1427  continue;
1428  }
1429 
1430  decrypt_failed:
1431  /* Fall through and show the original parts if decryption fails */
1432  if (need_secured && !secured)
1433  mutt_error(_("Can't decrypt encrypted message"));
1434 
1435  /* Strip out the top level multipart */
1436  if ((m->type == TYPE_MULTIPART) && m->parts && !need_secured &&
1437  ((parent_type == -1) && !mutt_istr_equal("alternative", m->subtype)))
1438  {
1439  mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level, decrypted);
1440  }
1441  else
1442  {
1443  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1444  mutt_actx_add_attach(actx, ap);
1445 
1446  ap->body = m;
1447  ap->fp = fp;
1448  m->aptr = ap;
1449  ap->parent_type = parent_type;
1450  ap->level = level;
1451  ap->decrypted = decrypted;
1452 
1453  if (m->type == TYPE_MULTIPART)
1454  mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level + 1, decrypted);
1455  else if (mutt_is_message_type(m->type, m->subtype))
1456  {
1457  mutt_generate_recvattach_list(actx, m->email, m->parts, fp, m->type,
1458  level + 1, decrypted);
1459  e->security |= m->email->security;
1460  }
1461  }
1462  }
1463 }
1464 
1469 void mutt_attach_init(struct AttachCtx *actx)
1470 {
1471  /* Collapse the attachments if '$digest_collapse' is set AND if...
1472  * the outer container is of type 'multipart/digest' */
1473  bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1474 
1475  for (int i = 0; i < actx->idxlen; i++)
1476  {
1477  actx->idx[i]->body->tagged = false;
1478 
1479  /* OR an inner container is of type 'multipart/digest' */
1480  actx->idx[i]->body->collapsed =
1481  (C_DigestCollapse &&
1482  (digest || ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1483  mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1484  }
1485 }
1486 
1493 static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
1494 {
1495  if (init)
1496  {
1497  mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1498  actx->fp_root, -1, 0, 0);
1499  mutt_attach_init(actx);
1500  menu->mdata = actx;
1501  }
1502 
1503  mutt_update_tree(actx);
1504 
1505  menu->max = actx->vcount;
1506 
1507  if (menu->current >= menu->max)
1508  menu->current = menu->max - 1;
1509  menu_check_recenter(menu);
1510  menu->redraw |= REDRAW_INDEX;
1511 }
1512 
1518 static void attach_collapse(struct AttachCtx *actx, struct Menu *menu)
1519 {
1520  int rindex, curlevel;
1521 
1522  CUR_ATTACH->body->collapsed = !CUR_ATTACH->body->collapsed;
1523  /* When expanding, expand all the children too */
1524  if (CUR_ATTACH->body->collapsed)
1525  return;
1526 
1527  curlevel = CUR_ATTACH->level;
1528  rindex = actx->v2r[menu->current] + 1;
1529 
1530  while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel))
1531  {
1532  if (C_DigestCollapse && (actx->idx[rindex]->body->type == TYPE_MULTIPART) &&
1533  mutt_istr_equal(actx->idx[rindex]->body->subtype, "digest"))
1534  {
1535  actx->idx[rindex]->body->collapsed = true;
1536  }
1537  else
1538  {
1539  actx->idx[rindex]->body->collapsed = false;
1540  }
1541  rindex++;
1542  }
1543 }
1544 
1550 {
1551  int op = OP_NULL;
1552 
1553  struct Mailbox *m = Context ? Context->mailbox : NULL;
1554 
1555  /* make sure we have parsed this message */
1557 
1559 
1560  struct Message *msg = mx_msg_open(m, e->msgno);
1561  if (!msg)
1562  return;
1563 
1564  struct Menu *menu = mutt_menu_new(MENU_ATTACH);
1566  dlg->help_data = AttachHelp;
1567  dlg->help_menu = MENU_ATTACH;
1568 
1569  menu->title = _("Attachments");
1570  menu->make_entry = attach_make_entry;
1571  menu->tag = attach_tag;
1572  mutt_menu_push_current(menu);
1573 
1574  struct AttachCtx *actx = mutt_actx_new();
1575  actx->email = e;
1576  actx->fp_root = msg->fp;
1577  mutt_update_recvattach_menu(actx, menu, true);
1578 
1579  while (true)
1580  {
1581  if (op == OP_NULL)
1582  op = mutt_menu_loop(menu);
1583  window_redraw(dlg, true);
1584  if (!Context)
1585  return;
1586  switch (op)
1587  {
1588  case OP_ATTACH_VIEW_MAILCAP:
1590  e, actx, menu->win_index);
1591  menu->redraw = REDRAW_FULL;
1592  break;
1593 
1594  case OP_ATTACH_VIEW_TEXT:
1596  e, actx, menu->win_index);
1597  menu->redraw = REDRAW_FULL;
1598  break;
1599 
1600  case OP_ATTACH_VIEW_PAGER:
1602  actx, menu->win_index);
1603  menu->redraw = REDRAW_FULL;
1604  break;
1605 
1606  case OP_DISPLAY_HEADERS:
1607  case OP_VIEW_ATTACH:
1608  op = mutt_attach_display_loop(menu, op, e, actx, true);
1609  menu->redraw = REDRAW_FULL;
1610  continue;
1611 
1612  case OP_ATTACH_COLLAPSE:
1613  if (!CUR_ATTACH->body->parts)
1614  {
1615  mutt_error(_("There are no subparts to show"));
1616  break;
1617  }
1618  attach_collapse(actx, menu);
1619  mutt_update_recvattach_menu(actx, menu, false);
1620  break;
1621 
1622  case OP_FORGET_PASSPHRASE:
1624  break;
1625 
1626  case OP_EXTRACT_KEYS:
1628  {
1629  recvattach_extract_pgp_keys(actx, menu);
1630  menu->redraw = REDRAW_FULL;
1631  }
1632  break;
1633 
1634  case OP_CHECK_TRADITIONAL:
1635  if (((WithCrypto & APPLICATION_PGP) != 0) &&
1637  {
1638  e->security = crypt_query(NULL);
1639  menu->redraw = REDRAW_FULL;
1640  }
1641  break;
1642 
1643  case OP_PRINT:
1645  CUR_ATTACH->body);
1646  break;
1647 
1648  case OP_PIPE:
1650  CUR_ATTACH->body, false);
1651  break;
1652 
1653  case OP_SAVE:
1655  CUR_ATTACH->body, e, menu);
1656 
1657  if (!menu->tagprefix && C_Resolve && (menu->current < menu->max - 1))
1658  menu->current++;
1659 
1661  break;
1662 
1663  case OP_DELETE:
1665 
1666 #ifdef USE_POP
1667  if (m->type == MUTT_POP)
1668  {
1669  mutt_flushinp();
1670  mutt_error(_("Can't delete attachment from POP server"));
1671  break;
1672  }
1673 #endif
1674 
1675 #ifdef USE_NNTP
1676  if (m->type == MUTT_NNTP)
1677  {
1678  mutt_flushinp();
1679  mutt_error(_("Can't delete attachment from news server"));
1680  break;
1681  }
1682 #endif
1683 
1684  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1685  {
1686  mutt_message(_("Deletion of attachments from encrypted messages is "
1687  "unsupported"));
1688  break;
1689  }
1690  if ((WithCrypto != 0) && (e->security & (SEC_SIGN | SEC_PARTSIGN)))
1691  {
1692  mutt_message(_("Deletion of attachments from signed messages may "
1693  "invalidate the signature"));
1694  }
1695  if (!menu->tagprefix)
1696  {
1697  if (CUR_ATTACH->parent_type == TYPE_MULTIPART)
1698  {
1699  CUR_ATTACH->body->deleted = true;
1700  if (C_Resolve && (menu->current < menu->max - 1))
1701  {
1702  menu->current++;
1703  menu->redraw = REDRAW_MOTION_RESYNC;
1704  }
1705  else
1706  menu->redraw = REDRAW_CURRENT;
1707  }
1708  else
1709  {
1710  mutt_message(
1711  _("Only deletion of multipart attachments is supported"));
1712  }
1713  }
1714  else
1715  {
1716  for (int i = 0; i < menu->max; i++)
1717  {
1718  if (actx->idx[i]->body->tagged)
1719  {
1720  if (actx->idx[i]->parent_type == TYPE_MULTIPART)
1721  {
1722  actx->idx[i]->body->deleted = true;
1723  menu->redraw = REDRAW_INDEX;
1724  }
1725  else
1726  {
1727  mutt_message(
1728  _("Only deletion of multipart attachments is supported"));
1729  }
1730  }
1731  }
1732  }
1733  break;
1734 
1735  case OP_UNDELETE:
1737  if (!menu->tagprefix)
1738  {
1739  CUR_ATTACH->body->deleted = false;
1740  if (C_Resolve && (menu->current < menu->max - 1))
1741  {
1742  menu->current++;
1743  menu->redraw = REDRAW_MOTION_RESYNC;
1744  }
1745  else
1746  menu->redraw = REDRAW_CURRENT;
1747  }
1748  else
1749  {
1750  for (int i = 0; i < menu->max; i++)
1751  {
1752  if (actx->idx[i]->body->tagged)
1753  {
1754  actx->idx[i]->body->deleted = false;
1755  menu->redraw = REDRAW_INDEX;
1756  }
1757  }
1758  }
1759  break;
1760 
1761  case OP_RESEND:
1762  CHECK_ATTACH;
1764  menu->tagprefix ? NULL : CUR_ATTACH->body);
1765  menu->redraw = REDRAW_FULL;
1766  break;
1767 
1768  case OP_BOUNCE_MESSAGE:
1769  CHECK_ATTACH;
1770  mutt_attach_bounce(m, CUR_ATTACH->fp, actx,
1771  menu->tagprefix ? NULL : CUR_ATTACH->body);
1772  menu->redraw = REDRAW_FULL;
1773  break;
1774 
1775  case OP_FORWARD_MESSAGE:
1776  CHECK_ATTACH;
1777  mutt_attach_forward(CUR_ATTACH->fp, m, e, actx,
1778  menu->tagprefix ? NULL : CUR_ATTACH->body, SEND_NO_FLAGS);
1779  menu->redraw = REDRAW_FULL;
1780  break;
1781 
1782 #ifdef USE_NNTP
1783  case OP_FORWARD_TO_GROUP:
1784  CHECK_ATTACH;
1785  mutt_attach_forward(CUR_ATTACH->fp, m, e, actx,
1786  menu->tagprefix ? NULL : CUR_ATTACH->body, SEND_NEWS);
1787  menu->redraw = REDRAW_FULL;
1788  break;
1789 
1790  case OP_FOLLOWUP:
1791  CHECK_ATTACH;
1792 
1793  if (!CUR_ATTACH->body->email->env->followup_to ||
1794  !mutt_istr_equal(CUR_ATTACH->body->email->env->followup_to,
1795  "poster") ||
1797  _("Reply by mail as poster prefers?")) != MUTT_YES))
1798  {
1799  mutt_attach_reply(CUR_ATTACH->fp, m, e, actx,
1800  menu->tagprefix ? NULL : CUR_ATTACH->body,
1801  SEND_NEWS | SEND_REPLY);
1802  menu->redraw = REDRAW_FULL;
1803  break;
1804  }
1805 #endif
1806  /* fallthrough */
1807  case OP_REPLY:
1808  case OP_GROUP_REPLY:
1809  case OP_GROUP_CHAT_REPLY:
1810  case OP_LIST_REPLY:
1811  {
1812  CHECK_ATTACH;
1813 
1814  SendFlags flags = SEND_REPLY;
1815  if (op == OP_GROUP_REPLY)
1816  flags |= SEND_GROUP_REPLY;
1817  else if (op == OP_GROUP_CHAT_REPLY)
1818  flags |= SEND_GROUP_CHAT_REPLY;
1819  else if (op == OP_LIST_REPLY)
1820  flags |= SEND_LIST_REPLY;
1821 
1822  mutt_attach_reply(CUR_ATTACH->fp, m, e, actx,
1823  menu->tagprefix ? NULL : CUR_ATTACH->body, flags);
1824  menu->redraw = REDRAW_FULL;
1825  break;
1826  }
1827 
1828  case OP_COMPOSE_TO_SENDER:
1829  CHECK_ATTACH;
1830  mutt_attach_mail_sender(CUR_ATTACH->fp, e, actx,
1831  menu->tagprefix ? NULL : CUR_ATTACH->body);
1832  menu->redraw = REDRAW_FULL;
1833  break;
1834 
1835  case OP_EDIT_TYPE:
1836  recvattach_edit_content_type(actx, menu, e);
1837  menu->redraw |= REDRAW_INDEX;
1838  break;
1839 
1840  case OP_EXIT:
1841  mx_msg_close(m, &msg);
1842 
1843  e->attach_del = false;
1844  for (int i = 0; i < actx->idxlen; i++)
1845  {
1846  if (actx->idx[i]->body && actx->idx[i]->body->deleted)
1847  {
1848  e->attach_del = true;
1849  break;
1850  }
1851  }
1852  if (e->attach_del)
1853  e->changed = true;
1854 
1855  mutt_actx_free(&actx);
1856 
1857  mutt_menu_pop_current(menu);
1858  mutt_menu_free(&menu);
1860  return;
1861  }
1862 
1863  op = OP_NULL;
1864  }
1865 
1866  /* not reached */
1867 }
can_print
static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:1058
Menu::oldcurrent
int oldcurrent
For driver use only.
Definition: mutt_menu.h:76
rfc3676.h
recvattach_extract_pgp_keys
static void recvattach_extract_pgp_keys(struct AttachCtx *actx, struct Menu *menu)
Extract PGP keys from attachments.
Definition: recvattach.c:1209
mutt_endwin
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:572
SendFlags
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:37
Email::msgno
int msgno
Number displayed to the user.
Definition: email.h:87
mutt_rfc3676_is_format_flowed
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:387
AttachCtx
A set of attachments.
Definition: attach.h:49
SEND_GROUP_CHAT_REPLY
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:53
CHECK_ATTACH
#define CHECK_ATTACH
Definition: recvattach.c:108
ENC_QUOTED_PRINTABLE
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
lib.h
Body::noconv
bool noconv
Don't do character set conversion.
Definition: body.h:73
dialog_create_simple_index
struct MuttWindow * dialog_create_simple_index(struct Menu *menu, enum WindowType type)
Create a simple index Dialog.
Definition: dialog.c:165
AttachPtr::decrypted
bool decrypted
Not part of message as stored in the email->body.
Definition: attach.h:43
print_attachment_list
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:1098
mutt_message_hook
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:574
query_save_attachment
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:576
WT_DLG_ATTACH
@ WT_DLG_ATTACH
Attach Dialog, dlg_select_attachment()
Definition: mutt_window.h:75
SEND_REPLY
#define SEND_REPLY
Reply to sender.
Definition: send.h:41
AttachCtx::fp_root
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:52
State::fp_in
FILE * fp_in
File to read from.
Definition: state.h:46
mutt_actx_new
struct AttachCtx * mutt_actx_new(void)
Create a new Attachment Context.
Definition: attach.c:131
mutt_mem_calloc
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
crypt_smime_getkeys
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition: cryptglue.c:458
MessageWindow
struct MuttWindow * MessageWindow
Message Window, ":set", etc.
Definition: mutt_window.c:47
_
#define _(a)
Definition: message.h:28
NONULL
#define NONULL(x)
Definition: string2.h:37
Mailbox
A mailbox.
Definition: mailbox.h:81
AttachCtx::vcount
short vcount
The number of virtual attachments.
Definition: attach.h:59
mutt_actx_entries_free
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition: attach.c:103
mutt_make_string
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1427
APPLICATION_SMIME
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:98
AttachPtr::num
int num
Attachment index number.
Definition: attach.h:41
MUTT_FORMAT_FORCESUBJ
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
Buffer
String manipulation buffer.
Definition: buffer.h:33
mutt_update_encoding
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:905
mailcap_lookup
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:465
mutt_file_fclose
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
mutt_buffer_pretty_mailbox
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:599
mutt_is_malformed_multipart_pgp_encrypted
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:510
attach_make_entry
static void attach_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
Format a menu item for the attachment list - Implements Menu::make_entry()
Definition: recvattach.c:446
Body::next
struct Body * next
next attachment in the list
Definition: body.h:53
mutt_buffer_is_empty
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
format_flags.h
Body
The body of an email.
Definition: body.h:34
SMIME_ENCRYPT
#define SMIME_ENCRYPT
Definition: lib.h:109
SEC_ENCRYPT
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
AttachPtr::fp
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
MUTT_FORMAT_ARROWCURSOR
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
SEC_SIGN
#define SEC_SIGN
Email is signed.
Definition: lib.h:86
mutt_window_clearline
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:232
MUTT_POP
@ MUTT_POP
'POP3' Mailbox type
Definition: mailbox.h:55
mutt_buffer_mktemp
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
handler.h
AttachPtr
An email to which things will be attached.
Definition: attach.h:34
MuttWindow
A division of the screen.
Definition: mutt_window.h:115
MUTT_TREE_LLCORNER
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition: mutt_thread.h:56
C_AttachSplit
bool C_AttachSplit
Config: Save/print/pipe tagged messages individually.
Definition: recvattach.c:75
MENU_ATTACH
@ MENU_ATTACH
Select an attachment.
Definition: keymap.h:75
crypt_pgp_decrypt_mime
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:209
mailcap.h
mutt_parse.h
MUTT_YES
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:40
CUR_ATTACH
#define CUR_ATTACH
Definition: recvattach.c:91
Context
The "current" mailbox.
Definition: context.h:38
mutt_str_dup
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
Mailbox_is_read_only
static const char * Mailbox_is_read_only
Definition: recvattach.c:81
mutt_globals.h
mutt_file_fopen
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
mutt_file_unlink
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
LL_DEBUG1
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
FREE
#define FREE(x)
Definition: memory.h:40
options.h
C_AttachSep
char * C_AttachSep
Config: Separator to add between saved/printed/piped attachments.
Definition: recvattach.c:74
mutt_attach_display_loop
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:1285
Body::disposition
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
mutt_perror
#define mutt_perror(...)
Definition: logging.h:85
MUTT_MC_PRINT
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:61
Buffer::dptr
char * dptr
Current read/write position.
Definition: buffer.h:36
mutt_menu_new
struct Menu * mutt_menu_new(enum MenuType type)
Create a new Menu.
Definition: menu.c:956
Body::encoding
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Buffer::dsize
size_t dsize
Length of data.
Definition: buffer.h:37
MuttWindow::help_menu
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:134
mutt_pipe_attachment
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:707
SecurityFlags
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:83
REDRAW_MOTION_RESYNC
#define REDRAW_MOTION_RESYNC
Redraw any changing the menu selection.
Definition: mutt_menu.h:42
PATH_MAX
#define PATH_MAX
Definition: mutt.h:44
AttachHelp
static const struct Mapping AttachHelp[]
Help Bar for the Attachment selection dialog.
Definition: recvattach.c:94
Body::attach_qualifies
bool attach_qualifies
This attachment should be counted.
Definition: body.h:83
Menu::make_entry
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Format a item for a menu.
Definition: mutt_menu.h:88
mutt_sleep
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1448
mutt_buffer_pool_release
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
crypt_smime_decrypt_mime
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:434
MUTT_FORMAT_NO_FLAGS
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
Body::tagged
bool tagged
This attachment is tagged.
Definition: body.h:70
C_FollowupToPoster
unsigned char C_FollowupToPoster
Config: (nntp) Reply to the poster if 'poster' is in the 'Followup-To' header.
Definition: config.c:38
mutt_decode_save_attachment
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:1004
mutt_body_free
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
Body::subtype
char * subtype
content-type subtype
Definition: body.h:37
mutt_attach_mail_sender
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:1099
SaveAttach
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:54
State::fp_out
FILE * fp_out
File to write to.
Definition: state.h:47
mutt_parse_mime_message
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:49
mutt_istr_equal
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
Body::attach_count
signed short attach_count
Number of attachments.
Definition: body.h:59
attach_format_str
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, intptr_t data, MuttFormatFlags flags)
Format a string for the attachment menu - Implements format_t.
Definition: recvattach.c:217
mutt_str_equal
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
mutt_attach_forward
void mutt_attach_forward(FILE *fp, struct Mailbox *m, struct Email *e, struct AttachCtx *actx, struct Body *cur, SendFlags flags)
Forward an Attachment.
Definition: recvcmd.c:776
Mapping
Mapping between user-readable string and a constant.
Definition: mapping.h:31
lib.h
PGP_TRADITIONAL_CHECKED
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:99
SEND_NEWS
#define SEND_NEWS
Reply to a news article.
Definition: send.h:54
C_AttachSaveDir
char * C_AttachSaveDir
Config: Default directory where attachments are saved.
Definition: recvattach.c:72
MUTT_FILE
#define MUTT_FILE
Do file completion.
Definition: mutt.h:58
MUTT_FORMAT_STAT_FILE
#define MUTT_FORMAT_STAT_FILE
Used by attach_format_str.
Definition: format_flags.h:34
crypt_pgp_check_traditional
int crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional()
Definition: cryptglue.c:283
mutt_any_key_to_continue
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:605
filter_create
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
C_AttachSaveWithoutPrompting
char * C_AttachSaveWithoutPrompting
Config: If true, then don't prompt to save.
Definition: recvattach.c:73
mutt_str_pretty_size
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1663
query_quadoption
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:518
mutt_menu_push_current
void mutt_menu_push_current(struct Menu *menu)
Add a new Menu to the stack.
Definition: menu.c:1015
mutt_buffer_addch
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
Function_not_permitted
static const char * Function_not_permitted
Definition: recvattach.c:105
mutt_buffer_pool_get
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
mutt_path_basename
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:329
MUTT_NNTP
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:52
mutt_can_decode
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1805
MUTT_TREE_RARROW
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:62
MUTT_TREE_HLINE
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:59
crypt_query
SecurityFlags crypt_query(struct Body *m)
Check out the type of encryption used.
Definition: crypt.c:687
Mailbox::type
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
menu_check_recenter
void menu_check_recenter(struct Menu *menu)
Recentre the menu on screen.
Definition: menu.c:544
save_attachment_flowed_helper
static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path, enum SaveAttach flags, struct Email *e)
Helper for unstuffing attachments.
Definition: recvattach.c:529
mutt_edit_content_type
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1324
mutt_view_attachment
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:414
mutt_print_attachment
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1103
mutt_buffer_copy
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:445
MUTT_VA_PAGER
@ MUTT_VA_PAGER
View attachment in pager using copiousoutput mailcap.
Definition: mutt_attach.h:45
MUTT_VA_AS_TEXT
@ MUTT_VA_AS_TEXT
Force viewing as text.
Definition: mutt_attach.h:44
keymap.h
MUTT_CHARCONV
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
lib.h
C_DigestCollapse
bool C_DigestCollapse
Config: Hide the subparts of a multipart/digest.
Definition: recvattach.c:76
mutt_file_copy_stream
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
muttlib.h
TYPE
#define TYPE(body)
Definition: mime.h:89
mutt_is_multipart_encrypted
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:449
AttachPtr::level
int level
Nesting depth of attachment.
Definition: attach.h:40
Body::length
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
mutt_save_attachment_list
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:724
save_without_prompting
static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:674
mutt_rfc3676_space_unstuff_attachment
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:511
APPLICATION_PGP
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
mutt_menu.h
REDRAW_FULL
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:45
mutt_save_confirm
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1351
window_redraw
void window_redraw(struct MuttWindow *win, bool force)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:747
lib.h
pipe_attachment
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition: recvattach.c:884
mutt_body_get_charset
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition: body.c:131
Body::description
char * description
content-description
Definition: body.h:40
dlg_select_attachment
void dlg_select_attachment(struct Email *e)
Show the attachments in a Menu.
Definition: recvattach.c:1549
Menu::tagprefix
bool tagprefix
Definition: mutt_menu.h:61
mutt_is_message_type
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1368
mutt_default_save
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:655
Body::parts
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
mutt_pipe_attachment_list
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:1011
AttachPtr::body
struct Body * body
Attachment.
Definition: attach.h:36
Context::mailbox
struct Mailbox * mailbox
Definition: context.h:50
mutt_buffer_concat_path
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
Email::env
struct Envelope * env
Envelope information.
Definition: email.h:90
MUTT_SAVE_APPEND
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:57
mutt_debug
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
SEND_GROUP_REPLY
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:42
MUTT_NO
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:39
Menu::tag
int(* tag)(struct Menu *menu, int sel, int act)
Tag some menu items.
Definition: mutt_menu.h:107
attach_collapse
static void attach_collapse(struct AttachCtx *actx, struct Menu *menu)
Close the tree of the current attachment.
Definition: recvattach.c:1518
Menu::title
const char * title
Title of this menu.
Definition: mutt_menu.h:54
C_PrintCommand
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: mutt_globals.h:103
mutt_update_tree
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:151
bool_str_toggle
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:213
SEND_NO_FLAGS
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:40
REDRAW_INDEX
#define REDRAW_INDEX
Redraw the index.
Definition: mutt_menu.h:40
mutt_buffer_expand_path
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
Message::fp
FILE * fp
pointer to the message data
Definition: mx.h:96
mutt_buffer_get_field
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:260
mutt_buffer_string
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
mutt_print_attachment_list
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:1166
recvcmd.h
Email::security
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:39
MuttWindow::help_data
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:135
mutt_format_s
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:1248
mutt_str_replace
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
filter_wait
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
MUTT_FORMAT_OPTIONAL
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
WithCrypto
#define WithCrypto
Definition: lib.h:123
Body::collapsed
bool collapsed
Used by recvattach.
Definition: body.h:82
mutt_flushinp
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:923
mutt_menu_loop
int mutt_menu_loop(struct Menu *menu)
Menu event loop.
Definition: menu.c:1309
MuttWindow::state
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
lib.h
lib.h
mutt_menu_pop_current
void mutt_menu_pop_current(struct Menu *menu)
Remove a Menu from the stack.
Definition: menu.c:1027
mutt_check_overwrite
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:621
attach_tag
int attach_tag(struct Menu *menu, int sel, int act)
Tag an attachment - Implements Menu::tag()
Definition: recvattach.c:458
PGP_ENCRYPT
#define PGP_ENCRYPT
Definition: lib.h:103
crypt_forget_passphrase
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:93
ENCODING
#define ENCODING(x)
Definition: mime.h:92
mutt_format_s_tree
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:1260
recvattach_pgp_check_traditional
static int recvattach_pgp_check_traditional(struct AttachCtx *actx, struct Menu *menu)
Is the Attachment inline PGP?
Definition: recvattach.c:1233
mutt_mktemp
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:74
lib.h
State
Keep track when processing files.
Definition: state.h:44
mutt_attach_resend
void mutt_attach_resend(FILE *fp, struct Context *ctx, struct AttachCtx *actx, struct Body *cur)
resend-message, from the attachment menu
Definition: recvcmd.c:299
Body::d_filename
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
mutt_thread.h
MUTT_VA_REGULAR
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:42
query_pipe_attachment
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:842
Menu::mdata
void * mdata
Extra data for the current menu.
Definition: mutt_menu.h:55
Body::aptr
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:57
mutt_actx_add_fp
void mutt_actx_add_fp(struct AttachCtx *actx, FILE *fp_new)
Save a File handle to the Attachment Context.
Definition: attach.c:62
mutt_expando_format
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string.
Definition: muttlib.c:774
ENC_BASE64
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
mutt_actx_add_body
void mutt_actx_add_body(struct AttachCtx *actx, struct Body *new_body)
Add an email box to an Attachment Context.
Definition: attach.c:83
Menu::max
int max
Number of entries in the menu.
Definition: mutt_menu.h:57
TYPE_TEXT
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
menu_redraw
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: menu.c:1270
MUTT_SAVE_NO_FLAGS
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:56
MUTT_TREE_LTEE
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:58
MUTT_MESSAGE_HOOK
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:52
mutt_generate_recvattach_list
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:1363
mutt_buffer_fix_dptr
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
has_a_message
static bool has_a_message(struct Body *body)
Determine if the Body has a message (to save)
Definition: recvattach.c:497
NeoMutt
Container for Accounts, Notifications.
Definition: neomutt.h:36
mutt.h
AttachCtx::email
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
Body::type
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Body::deleted
bool deleted
Attachment marked for deletion.
Definition: body.h:71
crypt_pgp_extract_key_from_attachment
void crypt_pgp_extract_key_from_attachment(FILE *fp, struct Body *top)
Wrapper for CryptModuleSpecs::pgp_extract_key_from_attachment()
Definition: cryptglue.c:396
mutt_file_rename
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1347
recvattach.h
Menu::redraw
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:58
MUTT_CMD
#define MUTT_CMD
Do completion on previous word.
Definition: mutt.h:60
AttachPtr::tree
char * tree
Tree characters to display.
Definition: attach.h:39
mutt_actx_free
void mutt_actx_free(struct AttachCtx **ptr)
Free an Attachment Context.
Definition: attach.c:140
AttachCtx::v2r
short * v2r
Mapping from virtual to real attachment.
Definition: attach.h:58
mutt_buffer_len
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
REDRAW_CURRENT
#define REDRAW_CURRENT
Redraw the current line of the menu.
Definition: mutt_menu.h:43
recvattach_edit_content_type
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:1255
context.h
MUTT_CLEAR
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
AttachCtx::idx
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
CHECK_READONLY
#define CHECK_READONLY
Definition: recvattach.c:83
NeoMutt::sub
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
mutt_is_text_part
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:433
mutt_buffer_addstr
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
C_Resolve
WHERE bool C_Resolve
Config: Move to the next email whenever a command modifies an email.
Definition: mutt_globals.h:155
SEND_LIST_REPLY
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
mutt_update_recvattach_menu
static void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1493
Body::email
struct Email * email
header information for message/rfc822
Definition: body.h:55
prepend_savedir
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:472
WindowState::cols
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
Body::unlink
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
Email::attach_del
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
dialog_destroy_simple_index
void dialog_destroy_simple_index(struct MuttWindow **ptr)
Destroy a simple index Dialog.
Definition: dialog.c:209
AttachPtr::parent_type
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:38
Menu::current
int current
Current entry.
Definition: mutt_menu.h:56
mx.h
C_MessageFormat
char * C_MessageFormat
Config: printf-like format string for listing attached messages.
Definition: recvattach.c:77
mutt_attach_reply
void mutt_attach_reply(FILE *fp, struct Mailbox *m, struct Email *e, struct AttachCtx *actx, struct Body *e_cur, SendFlags flags)
Attach a reply.
Definition: recvcmd.c:929
commands.h
opcodes.h
mutt_decode_attachment
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1845
mx_msg_close
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1204
state.h
State::flags
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
mutt_attach_bounce
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
mutt_yesorno
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:380
Buffer::data
char * data
Pointer to data.
Definition: buffer.h:35
TYPE_MULTIPART
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
Email
The envelope/body of an email.
Definition: email.h:37
mutt_attach_init
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1469
C_AttachFormat
WHERE char * C_AttachFormat
Config: printf-like format string for the attachment menu.
Definition: mutt_globals.h:87
lib.h
mutt_actx_add_attach
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:40
REDRAW_MOTION
#define REDRAW_MOTION
Redraw after moving the menu list.
Definition: mutt_menu.h:41
mutt_message
#define mutt_message(...)
Definition: logging.h:83
mutt_attach.h
pipe_attachment_list
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:980
MUTT_VA_MAILCAP
@ MUTT_VA_MAILCAP
Force viewing using mailcap entry.
Definition: mutt_attach.h:43
Menu::win_index
struct MuttWindow * win_index
Definition: mutt_menu.h:63
MUTT_PRINTING
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
crypt_valid_passphrase
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
Menu
GUI selectable list of items.
Definition: mutt_menu.h:52
mutt_save_attachment
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:873
C_Print
WHERE unsigned char C_Print
Config: Confirm before printing a message.
Definition: mutt_globals.h:128
hook.h
N_
#define N_(a)
Definition: message.h:32
mutt_update_v2r
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition: recvattach.c:122
mutt_buffer_strcpy
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
C_WaitKey
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: mutt_globals.h:169
hdrline.h
AttachCtx::idxlen
short idxlen
Number of attachmentes.
Definition: attach.h:55
mutt_is_application_smime
SecurityFlags mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:612
Email::changed
bool changed
Email has been edited.
Definition: email.h:48
Message
A local copy of an email.
Definition: mx.h:94
state_puts
#define state_puts(STATE, STR)
Definition: state.h:55
MuttFormatFlags
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
SEC_PARTSIGN
#define SEC_PARTSIGN
Not all parts of the email is signed.
Definition: lib.h:89
Body::filename
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
Email::body
struct Body * body
List of MIME parts.
Definition: email.h:91
mutt_menu_free
void mutt_menu_free(struct Menu **ptr)
Destroy a menu.
Definition: menu.c:972
mx_msg_open
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1158
mutt_error
#define mutt_error(...)
Definition: logging.h:84