NeoMutt  2021-10-29-33-g41675a
Teaching an old dog new tricks
DOXYGEN
mutt_attach.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38 #include <unistd.h>
39 #include "mutt/lib.h"
40 #include "config/lib.h"
41 #include "email/lib.h"
42 #include "core/lib.h"
43 #include "gui/lib.h"
44 #include "mutt_attach.h"
45 #include "ncrypt/lib.h"
46 #include "pager/lib.h"
47 #include "question/lib.h"
48 #include "send/lib.h"
49 #include "copy.h"
50 #include "handler.h"
51 #include "mailcap.h"
52 #include "mutt_globals.h"
53 #include "muttlib.h"
54 #include "mx.h"
55 #include "options.h"
56 #include "protos.h"
57 #include "rfc3676.h"
58 #ifdef USE_IMAP
59 #include "imap/lib.h"
60 #endif
61 
69 {
70  char type[256];
71  struct stat st = { 0 };
72 
73  if (a->unlink)
74  return 0;
75 
76  struct Buffer *tmpfile = mutt_buffer_pool_get();
77  struct MailcapEntry *entry = mailcap_entry_new();
78  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
79  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS);
80  mailcap_expand_filename(entry->nametemplate, a->filename, tmpfile);
81 
82  mailcap_entry_free(&entry);
83 
84  if (stat(a->filename, &st) == -1)
85  {
86  mutt_buffer_pool_release(&tmpfile);
87  return -1;
88  }
89 
90  FILE *fp_in = NULL, *fp_out = NULL;
91  if ((fp_in = fopen(a->filename, "r")) &&
92  (fp_out = mutt_file_fopen(mutt_buffer_string(tmpfile), "w")))
93  {
94  mutt_file_copy_stream(fp_in, fp_out);
96  a->unlink = true;
97 
98  if (a->stamp >= st.st_mtime)
100  }
101  else
102  mutt_perror(fp_in ? mutt_buffer_string(tmpfile) : a->filename);
103 
104  mutt_file_fclose(&fp_in);
105  mutt_file_fclose(&fp_out);
106 
107  mutt_buffer_pool_release(&tmpfile);
108 
109  return a->unlink ? 0 : -1;
110 }
111 
119 {
120  char type[256];
121  struct MailcapEntry *entry = mailcap_entry_new();
122  bool unlink_newfile = false;
123  int rc = 0;
124  struct Buffer *cmd = mutt_buffer_pool_get();
125  struct Buffer *newfile = mutt_buffer_pool_get();
126  struct Buffer *tmpfile = mutt_buffer_pool_get();
127 
128  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
129  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_COMPOSE))
130  {
131  if (entry->composecommand || entry->composetypecommand)
132  {
133  if (entry->composetypecommand)
135  else
136  mutt_buffer_strcpy(cmd, entry->composecommand);
137 
138  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
139  mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", a->filename,
140  mutt_buffer_string(newfile));
141  if (mutt_file_symlink(a->filename, mutt_buffer_string(newfile)) == -1)
142  {
143  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
144  goto bailout;
145  mutt_buffer_strcpy(newfile, a->filename);
146  }
147  else
148  unlink_newfile = true;
149 
150  if (mailcap_expand_command(a, mutt_buffer_string(newfile), type, cmd))
151  {
152  /* For now, editing requires a file, no piping */
153  mutt_error(_("Mailcap compose entry requires %%s"));
154  }
155  else
156  {
157  int r;
158 
159  mutt_endwin();
161  if (r == -1)
162  mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
163 
164  if ((r != -1) && entry->composetypecommand)
165  {
166  struct Body *b = NULL;
167 
168  FILE *fp = mutt_file_fopen(a->filename, "r");
169  if (!fp)
170  {
171  mutt_perror(_("Failure to open file to parse headers"));
172  goto bailout;
173  }
174 
175  b = mutt_read_mime_header(fp, 0);
176  if (b)
177  {
178  if (!TAILQ_EMPTY(&b->parameter))
179  {
181  a->parameter = b->parameter;
182  TAILQ_INIT(&b->parameter);
183  }
184  if (b->description)
185  {
186  FREE(&a->description);
187  a->description = b->description;
188  b->description = NULL;
189  }
190  if (b->form_name)
191  {
192  FREE(&a->form_name);
193  a->form_name = b->form_name;
194  b->form_name = NULL;
195  }
196 
197  /* Remove headers by copying out data to another file, then
198  * copying the file back */
199  const LOFF_T offset = b->offset;
200  mutt_body_free(&b);
201  if (!mutt_file_seek(fp, offset, SEEK_SET))
202  {
203  goto bailout;
204  }
205 
206  mutt_buffer_mktemp(tmpfile);
207  FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tmpfile), "w");
208  if (!fp_tmp)
209  {
210  mutt_perror(_("Failure to open file to strip headers"));
211  mutt_file_fclose(&fp);
212  goto bailout;
213  }
214  mutt_file_copy_stream(fp, fp_tmp);
215  mutt_file_fclose(&fp);
216  mutt_file_fclose(&fp_tmp);
218  if (mutt_file_rename(mutt_buffer_string(tmpfile), a->filename) != 0)
219  {
220  mutt_perror(_("Failure to rename file"));
221  goto bailout;
222  }
223  }
224  }
225  }
226  }
227  }
228  else
229  {
230  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
231  rc = 1;
232  goto bailout;
233  }
234 
235  rc = 1;
236 
237 bailout:
238 
239  if (unlink_newfile)
240  unlink(mutt_buffer_string(newfile));
241 
243  mutt_buffer_pool_release(&newfile);
244  mutt_buffer_pool_release(&tmpfile);
245 
246  mailcap_entry_free(&entry);
247  return rc;
248 }
249 
264 {
265  char type[256];
266  struct MailcapEntry *entry = mailcap_entry_new();
267  bool unlink_newfile = false;
268  int rc = 0;
269  struct Buffer *cmd = mutt_buffer_pool_get();
270  struct Buffer *newfile = mutt_buffer_pool_get();
271 
272  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
273  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_EDIT))
274  {
275  if (entry->editcommand)
276  {
277  mutt_buffer_strcpy(cmd, entry->editcommand);
278  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
279  mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", a->filename,
280  mutt_buffer_string(newfile));
281  if (mutt_file_symlink(a->filename, mutt_buffer_string(newfile)) == -1)
282  {
283  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
284  goto bailout;
285  mutt_buffer_strcpy(newfile, a->filename);
286  }
287  else
288  unlink_newfile = true;
289 
290  if (mailcap_expand_command(a, mutt_buffer_string(newfile), type, cmd))
291  {
292  /* For now, editing requires a file, no piping */
293  mutt_error(_("Mailcap Edit entry requires %%s"));
294  goto bailout;
295  }
296  else
297  {
298  mutt_endwin();
299  if (mutt_system(mutt_buffer_string(cmd)) == -1)
300  {
301  mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
302  goto bailout;
303  }
304  }
305  }
306  }
307  else if (a->type == TYPE_TEXT)
308  {
309  /* On text, default to editor */
310  const char *const c_editor = cs_subset_string(NeoMutt->sub, "editor");
311  mutt_edit_file(NONULL(c_editor), a->filename);
312  }
313  else
314  {
315  mutt_error(_("No mailcap edit entry for %s"), type);
316  rc = 0;
317  goto bailout;
318  }
319 
320  rc = 1;
321 
322 bailout:
323 
324  if (unlink_newfile)
325  unlink(mutt_buffer_string(newfile));
326 
328  mutt_buffer_pool_release(&newfile);
329 
330  mailcap_entry_free(&entry);
331  return rc;
332 }
333 
340 void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
341 {
342  struct ListNode *np = NULL;
343  STAILQ_FOREACH(np, &MimeLookupList, entries)
344  {
345  const int i = mutt_str_len(np->data) - 1;
346  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
347  mutt_istrn_equal(type, np->data, i)) ||
348  mutt_istr_equal(type, np->data))
349  {
350  struct Body tmp = { 0 };
351  enum ContentType n;
352  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
353  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
354  {
355  snprintf(type, len, "%s/%s",
356  (n == TYPE_AUDIO) ? "audio" :
357  (n == TYPE_APPLICATION) ? "application" :
358  (n == TYPE_IMAGE) ? "image" :
359  (n == TYPE_MESSAGE) ? "message" :
360  (n == TYPE_MODEL) ? "model" :
361  (n == TYPE_MULTIPART) ? "multipart" :
362  (n == TYPE_TEXT) ? "text" :
363  (n == TYPE_VIDEO) ? "video" :
364  "other",
365  tmp.subtype);
366  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
367  }
368  FREE(&tmp.subtype);
369  FREE(&tmp.xtype);
370  }
371  }
372 }
373 
387 static int wait_interactive_filter(pid_t pid)
388 {
389  int rc;
390 
391 #ifdef USE_IMAP
392  rc = imap_wait_keepalive(pid);
393 #else
394  waitpid(pid, &rc, 0);
395 #endif
397  rc = WIFEXITED(rc) ? WEXITSTATUS(rc) : -1;
398 
399  return rc;
400 }
401 
420 int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode,
421  struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
422 {
423  bool use_mailcap = false;
424  bool use_pipe = false;
425  bool use_pager = true;
426  char type[256];
427  char desc[256];
428  char *fname = NULL;
429  struct MailcapEntry *entry = NULL;
430  int rc = -1;
431  bool has_tempfile = false;
432  bool unlink_pagerfile = false;
433 
434  bool is_message = mutt_is_message_type(a->type, a->subtype);
435  if ((WithCrypto != 0) && is_message && a->email &&
437  {
438  return rc;
439  }
440 
441  struct Buffer *tmpfile = mutt_buffer_pool_get();
442  struct Buffer *pagerfile = mutt_buffer_pool_get();
443  struct Buffer *cmd = mutt_buffer_pool_get();
444 
445  use_mailcap = ((mode == MUTT_VA_MAILCAP) ||
446  ((mode == MUTT_VA_REGULAR) && mutt_needs_mailcap(a)) ||
447  (mode == MUTT_VA_PAGER));
448  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
449 
450  char columns[16];
451  snprintf(columns, sizeof(columns), "%d", win->state.cols);
452  mutt_envlist_set("COLUMNS", columns, true);
453 
454  if (use_mailcap)
455  {
456  entry = mailcap_entry_new();
457  enum MailcapLookup mailcap_opt =
459  if (!mailcap_lookup(a, type, sizeof(type), entry, mailcap_opt))
460  {
461  if ((mode == MUTT_VA_REGULAR) || (mode == MUTT_VA_PAGER))
462  {
463  /* fallback to view as text */
464  mailcap_entry_free(&entry);
465  mutt_error(_("No matching mailcap entry found. Viewing as text."));
466  mode = MUTT_VA_AS_TEXT;
467  use_mailcap = false;
468  }
469  else
470  goto return_error;
471  }
472  }
473 
474  if (use_mailcap)
475  {
476  if (!entry->command)
477  {
478  mutt_error(_("MIME type not defined. Can't view attachment."));
479  goto return_error;
480  }
481  mutt_buffer_strcpy(cmd, entry->command);
482 
483  fname = mutt_str_dup(a->filename);
484  /* In send mode(!fp), we allow slashes because those are part of
485  * the tmpfile. The path will be removed in expand_filename */
486  mutt_file_sanitize_filename(fname, fp ? true : false);
487  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
488  FREE(&fname);
489 
490  if (mutt_save_attachment(fp, a, mutt_buffer_string(tmpfile), 0, NULL) == -1)
491  goto return_error;
492  has_tempfile = true;
493 
495 
496  use_pipe = mailcap_expand_command(a, mutt_buffer_string(tmpfile), type, cmd);
497  use_pager = entry->copiousoutput;
498  }
499 
500  if (use_pager)
501  {
502  if (fp && !use_mailcap && a->filename)
503  {
504  /* recv case */
505  mutt_buffer_strcpy(pagerfile, a->filename);
506  mutt_adv_mktemp(pagerfile);
507  }
508  else
509  mutt_buffer_mktemp(pagerfile);
510  }
511 
512  if (use_mailcap)
513  {
514  pid_t pid = 0;
515  int fd_temp = -1, fd_pager = -1;
516 
517  if (!use_pager)
518  mutt_endwin();
519 
520  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
521  if (use_pager || use_pipe)
522  {
523  if (use_pager && ((fd_pager = mutt_file_open(mutt_buffer_string(pagerfile),
524  O_CREAT | O_EXCL | O_WRONLY)) == -1))
525  {
526  mutt_perror("open");
527  goto return_error;
528  }
529  unlink_pagerfile = true;
530 
531  if (use_pipe && ((fd_temp = open(mutt_buffer_string(tmpfile), 0)) == -1))
532  {
533  if (fd_pager != -1)
534  close(fd_pager);
535  mutt_perror("open");
536  goto return_error;
537  }
538  unlink_pagerfile = true;
539 
540  pid = filter_create_fd(mutt_buffer_string(cmd), NULL, NULL, NULL,
541  use_pipe ? fd_temp : -1, use_pager ? fd_pager : -1, -1);
542 
543  if (pid == -1)
544  {
545  if (fd_pager != -1)
546  close(fd_pager);
547 
548  if (fd_temp != -1)
549  close(fd_temp);
550 
551  mutt_error(_("Can't create filter"));
552  goto return_error;
553  }
554 
555  if (use_pager)
556  {
557  if (a->description)
558  {
559  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
561  }
562  else
563  {
564  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
565  mutt_buffer_string(cmd), type);
566  }
567  filter_wait(pid);
568  }
569  else
570  {
571  if (wait_interactive_filter(pid) || (entry->needsterminal && c_wait_key))
573  }
574 
575  if (fd_temp != -1)
576  close(fd_temp);
577  if (fd_pager != -1)
578  close(fd_pager);
579  }
580  else
581  {
582  /* interactive cmd */
583  int rv = mutt_system(mutt_buffer_string(cmd));
584  if (rv == -1)
585  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
586 
587  if ((rv != 0) || (entry->needsterminal && c_wait_key))
589  }
590  }
591  else
592  {
593  /* Don't use mailcap; the attachment is viewed in the pager */
594 
595  if (mode == MUTT_VA_AS_TEXT)
596  {
597  /* just let me see the raw data */
598  if (fp)
599  {
600  /* Viewing from a received message.
601  *
602  * Don't use mutt_save_attachment() because we want to perform charset
603  * conversion since this will be displayed by the internal pager. */
604  struct State decode_state = { 0 };
605 
606  decode_state.fp_out = mutt_file_fopen(mutt_buffer_string(pagerfile), "w");
607  if (!decode_state.fp_out)
608  {
609  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
610  mutt_buffer_string(pagerfile), errno, strerror(errno));
611  mutt_perror(mutt_buffer_string(pagerfile));
612  goto return_error;
613  }
614  decode_state.fp_in = fp;
615  decode_state.flags = MUTT_CHARCONV;
616  mutt_decode_attachment(a, &decode_state);
617  if (mutt_file_fclose(&decode_state.fp_out) == EOF)
618  {
619  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n",
620  mutt_buffer_string(pagerfile), errno, strerror(errno));
621  }
622  }
623  else
624  {
625  /* in compose mode, just copy the file. we can't use
626  * mutt_decode_attachment() since it assumes the content-encoding has
627  * already been applied */
628  if (mutt_save_attachment(fp, a, mutt_buffer_string(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
629  goto return_error;
630  unlink_pagerfile = true;
631  }
633  }
634  else
635  {
636  /* Use built-in handler */
637  OptViewAttach = true; /* disable the "use 'v' to view this part"
638  * message in case of error */
639  if (mutt_decode_save_attachment(fp, a, mutt_buffer_string(pagerfile),
641  {
642  OptViewAttach = false;
643  goto return_error;
644  }
645  unlink_pagerfile = true;
646  OptViewAttach = false;
647  }
648 
649  if (a->description)
650  mutt_str_copy(desc, a->description, sizeof(desc));
651  else if (a->filename)
652  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
653  else
654  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
655  }
656 
657  /* We only reach this point if there have been no errors */
658 
659  if (use_pager)
660  {
661  struct PagerData pdata = { 0 };
662  struct PagerView pview = { &pdata };
663 
664  pdata.actx = actx;
665  pdata.body = a;
666  pdata.fname = mutt_buffer_string(pagerfile);
667  pdata.fp = fp;
668 
669  pview.banner = desc;
670  pview.flags = MUTT_PAGER_ATTACHMENT |
671  (is_message ? MUTT_PAGER_MESSAGE : MUTT_PAGER_NO_FLAGS) |
672  ((use_mailcap && entry->xneomuttnowrap) ? MUTT_PAGER_NOWRAP :
674  pview.mode = PAGER_MODE_ATTACH;
675 
676  rc = mutt_do_pager(&pview, e);
677 
678  mutt_buffer_reset(pagerfile);
679  unlink_pagerfile = false;
680  }
681  else
682  rc = 0;
683 
684 return_error:
685 
686  if (!entry || !entry->xneomuttkeep)
687  {
688  if ((fp && !mutt_buffer_is_empty(tmpfile)) || has_tempfile)
689  {
690  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
692  }
693  }
694 
695  mailcap_entry_free(&entry);
696 
697  if (unlink_pagerfile)
699 
700  mutt_buffer_pool_release(&tmpfile);
701  mutt_buffer_pool_release(&pagerfile);
703  mutt_envlist_unset("COLUMNS");
704 
705  return rc;
706 }
707 
717 int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
718 {
719  pid_t pid = 0;
720  int out = -1, rc = 0;
721  bool is_flowed = false;
722  bool unlink_unstuff = false;
723  FILE *fp_filter = NULL, *fp_unstuff = NULL, *fp_in = NULL;
724  struct Buffer *unstuff_tempfile = NULL;
725 
726  if (outfile && *outfile)
727  {
728  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
729  if (out < 0)
730  {
731  mutt_perror("open");
732  return 0;
733  }
734  }
735 
737  {
738  is_flowed = true;
739  unstuff_tempfile = mutt_buffer_pool_get();
740  mutt_buffer_mktemp(unstuff_tempfile);
741  }
742 
743  mutt_endwin();
744 
745  if (outfile && *outfile)
746  pid = filter_create_fd(path, &fp_filter, NULL, NULL, -1, out, -1);
747  else
748  pid = filter_create(path, &fp_filter, NULL, NULL);
749  if (pid < 0)
750  {
751  mutt_perror(_("Can't create filter"));
752  goto bail;
753  }
754 
755  /* recv case */
756  if (fp)
757  {
758  struct State s = { 0 };
759 
760  /* perform charset conversion on text attachments when piping */
761  s.flags = MUTT_CHARCONV;
762 
763  if (is_flowed)
764  {
765  fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "w");
766  if (fp_unstuff == NULL)
767  {
768  mutt_perror("mutt_file_fopen");
769  goto bail;
770  }
771  unlink_unstuff = true;
772 
773  s.fp_in = fp;
774  s.fp_out = fp_unstuff;
775  mutt_decode_attachment(b, &s);
776  mutt_file_fclose(&fp_unstuff);
777 
779 
780  fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "r");
781  if (fp_unstuff == NULL)
782  {
783  mutt_perror("mutt_file_fopen");
784  goto bail;
785  }
786  mutt_file_copy_stream(fp_unstuff, fp_filter);
787  mutt_file_fclose(&fp_unstuff);
788  }
789  else
790  {
791  s.fp_in = fp;
792  s.fp_out = fp_filter;
793  mutt_decode_attachment(b, &s);
794  }
795  }
796 
797  /* send case */
798  else
799  {
800  const char *infile = NULL;
801 
802  if (is_flowed)
803  {
804  if (mutt_save_attachment(fp, b, mutt_buffer_string(unstuff_tempfile),
805  MUTT_SAVE_NO_FLAGS, NULL) == -1)
806  {
807  goto bail;
808  }
809  unlink_unstuff = true;
811  infile = mutt_buffer_string(unstuff_tempfile);
812  }
813  else
814  infile = b->filename;
815 
816  fp_in = fopen(infile, "r");
817  if (!fp_in)
818  {
819  mutt_perror("fopen");
820  goto bail;
821  }
822 
823  mutt_file_copy_stream(fp_in, fp_filter);
825  }
826 
827  mutt_file_fclose(&fp_filter);
828  rc = 1;
829 
830 bail:
831  if (outfile && *outfile)
832  {
833  close(out);
834  if (rc == 0)
835  unlink(outfile);
836  else if (is_flowed)
838  }
839 
840  mutt_file_fclose(&fp_unstuff);
841  mutt_file_fclose(&fp_filter);
843 
844  if (unlink_unstuff)
845  mutt_file_unlink(mutt_buffer_string(unstuff_tempfile));
846  mutt_buffer_pool_release(&unstuff_tempfile);
847 
848  /* check for error exit from child process */
849  if ((pid > 0) && (filter_wait(pid) != 0))
850  rc = 0;
851 
852  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
853  if ((rc == 0) || c_wait_key)
855  return rc;
856 }
857 
864 static FILE *save_attachment_open(const char *path, enum SaveAttach opt)
865 {
866  if (opt == MUTT_SAVE_APPEND)
867  return fopen(path, "a");
868  if (opt == MUTT_SAVE_OVERWRITE)
869  return fopen(path, "w");
870 
871  return mutt_file_fopen(path, "w");
872 }
873 
884 int mutt_save_attachment(FILE *fp, struct Body *m, const char *path,
885  enum SaveAttach opt, struct Email *e)
886 {
887  if (!m)
888  return -1;
889 
890  if (fp)
891  {
892  /* recv mode */
893 
894  if (e && m->email && (m->encoding != ENC_BASE64) &&
896  {
897  /* message type attachments are written to mail folders. */
898 
899  char buf[8192];
900  struct Message *msg = NULL;
901  CopyHeaderFlags chflags = CH_NO_FLAGS;
902  int rc = -1;
903 
904  struct Email *e_new = m->email;
905  e_new->msgno = e->msgno; /* required for MH/maildir */
906  e_new->read = true;
907 
908  if (!mutt_file_seek(fp, m->offset, SEEK_SET))
909  return -1;
910  if (!fgets(buf, sizeof(buf), fp))
911  return -1;
912  struct Mailbox *m_att = mx_path_resolve(path);
913  if (!mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET))
914  {
915  mailbox_free(&m_att);
916  return -1;
917  }
918  msg = mx_msg_open_new(m_att, e_new,
919  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
920  if (!msg)
921  {
922  mx_mbox_close(m_att);
923  return -1;
924  }
925  if ((m_att->type == MUTT_MBOX) || (m_att->type == MUTT_MMDF))
926  chflags = CH_FROM | CH_UPDATE_LEN;
927  chflags |= ((m_att->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
928  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
929  (mx_msg_commit(m_att, msg) == 0))
930  {
931  rc = 0;
932  }
933  else
934  {
935  rc = -1;
936  }
937 
938  mx_msg_close(m_att, &msg);
939  mx_mbox_close(m_att);
940  return rc;
941  }
942  else
943  {
944  /* In recv mode, extract from folder and decode */
945 
946  struct State s = { 0 };
947 
948  s.fp_out = save_attachment_open(path, opt);
949  if (!s.fp_out)
950  {
951  mutt_perror("fopen");
952  return -1;
953  }
954  if (!mutt_file_seek((s.fp_in = fp), m->offset, SEEK_SET))
955  {
957  return -1;
958  }
959  mutt_decode_attachment(m, &s);
960 
961  if (mutt_file_fsync_close(&s.fp_out) != 0)
962  {
963  mutt_perror("fclose");
964  return -1;
965  }
966  }
967  }
968  else
969  {
970  if (!m->filename)
971  return -1;
972 
973  /* In send mode, just copy file */
974 
975  FILE *fp_old = fopen(m->filename, "r");
976  if (!fp_old)
977  {
978  mutt_perror("fopen");
979  return -1;
980  }
981 
982  FILE *fp_new = save_attachment_open(path, opt);
983  if (!fp_new)
984  {
985  mutt_perror("fopen");
986  mutt_file_fclose(&fp_old);
987  return -1;
988  }
989 
990  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
991  {
992  mutt_error(_("Write fault"));
993  mutt_file_fclose(&fp_old);
994  mutt_file_fclose(&fp_new);
995  return -1;
996  }
997  mutt_file_fclose(&fp_old);
998  if (mutt_file_fsync_close(&fp_new) != 0)
999  {
1000  mutt_error(_("Write fault"));
1001  return -1;
1002  }
1003  }
1004 
1005  return 0;
1006 }
1007 
1018 int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path,
1019  int displaying, enum SaveAttach opt)
1020 {
1021  struct State s = { 0 };
1022  unsigned int saved_encoding = 0;
1023  struct Body *saved_parts = NULL;
1024  struct Email *e_saved = NULL;
1025  int rc = 0;
1026 
1027  s.flags = displaying;
1028 
1029  if (opt == MUTT_SAVE_APPEND)
1030  s.fp_out = fopen(path, "a");
1031  else if (opt == MUTT_SAVE_OVERWRITE)
1032  s.fp_out = fopen(path, "w");
1033  else
1034  s.fp_out = mutt_file_fopen(path, "w");
1035 
1036  if (!s.fp_out)
1037  {
1038  mutt_perror("fopen");
1039  return -1;
1040  }
1041 
1042  if (!fp)
1043  {
1044  /* When called from the compose menu, the attachment isn't parsed,
1045  * so we need to do it here. */
1046  struct stat st = { 0 };
1047 
1048  if (stat(m->filename, &st) == -1)
1049  {
1050  mutt_perror("stat");
1052  return -1;
1053  }
1054 
1055  s.fp_in = fopen(m->filename, "r");
1056  if (!s.fp_in)
1057  {
1058  mutt_perror("fopen");
1059  return -1;
1060  }
1061 
1062  saved_encoding = m->encoding;
1063  if (!is_multipart(m))
1064  m->encoding = ENC_8BIT;
1065 
1066  m->length = st.st_size;
1067  m->offset = 0;
1068  saved_parts = m->parts;
1069  e_saved = m->email;
1070  mutt_parse_part(s.fp_in, m);
1071 
1072  if (m->noconv || is_multipart(m))
1073  s.flags |= MUTT_CHARCONV;
1074  }
1075  else
1076  {
1077  s.fp_in = fp;
1078  s.flags |= MUTT_CHARCONV;
1079  }
1080 
1081  mutt_body_handler(m, &s);
1082 
1083  if (mutt_file_fsync_close(&s.fp_out) != 0)
1084  {
1085  mutt_perror("fclose");
1086  rc = -1;
1087  }
1088  if (!fp)
1089  {
1090  m->length = 0;
1091  m->encoding = saved_encoding;
1092  if (saved_parts)
1093  {
1094  email_free(&m->email);
1095  m->parts = saved_parts;
1096  m->email = e_saved;
1097  }
1098  mutt_file_fclose(&s.fp_in);
1099  }
1100 
1101  return rc;
1102 }
1103 
1117 int mutt_print_attachment(FILE *fp, struct Body *a)
1118 {
1119  char type[256];
1120  pid_t pid;
1121  FILE *fp_in = NULL, *fp_out = NULL;
1122  bool unlink_newfile = false;
1123  struct Buffer *newfile = mutt_buffer_pool_get();
1124  struct Buffer *cmd = mutt_buffer_pool_get();
1125 
1126  int rc = 0;
1127 
1128  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1129 
1130  if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1131  {
1132  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1133 
1134  struct MailcapEntry *entry = mailcap_entry_new();
1135  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1136 
1137  char *sanitized_fname = mutt_str_dup(a->filename);
1138  /* In send mode (!fp), we allow slashes because those are part of
1139  * the tempfile. The path will be removed in expand_filename */
1140  mutt_file_sanitize_filename(sanitized_fname, fp ? true : false);
1141  mailcap_expand_filename(entry->nametemplate, sanitized_fname, newfile);
1142  FREE(&sanitized_fname);
1143 
1144  if (mutt_save_attachment(fp, a, mutt_buffer_string(newfile),
1145  MUTT_SAVE_NO_FLAGS, NULL) == -1)
1146  {
1147  goto mailcap_cleanup;
1148  }
1149  unlink_newfile = 1;
1150 
1152 
1153  mutt_buffer_strcpy(cmd, entry->printcommand);
1154 
1155  bool piped = mailcap_expand_command(a, mutt_buffer_string(newfile), type, cmd);
1156 
1157  mutt_endwin();
1158 
1159  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1160  /* interactive program */
1161  if (piped)
1162  {
1163  fp_in = fopen(mutt_buffer_string(newfile), "r");
1164  if (!fp_in)
1165  {
1166  mutt_perror("fopen");
1167  mailcap_entry_free(&entry);
1168  goto mailcap_cleanup;
1169  }
1170 
1171  pid = filter_create(mutt_buffer_string(cmd), &fp_out, NULL, NULL);
1172  if (pid < 0)
1173  {
1174  mutt_perror(_("Can't create filter"));
1175  mailcap_entry_free(&entry);
1176  mutt_file_fclose(&fp_in);
1177  goto mailcap_cleanup;
1178  }
1179  mutt_file_copy_stream(fp_in, fp_out);
1180  mutt_file_fclose(&fp_out);
1181  mutt_file_fclose(&fp_in);
1182  if (filter_wait(pid) || c_wait_key)
1184  }
1185  else
1186  {
1187  int rc2 = mutt_system(mutt_buffer_string(cmd));
1188  if (rc2 == -1)
1189  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1190 
1191  if ((rc2 != 0) || c_wait_key)
1193  }
1194 
1195  rc = 1;
1196 
1197  mailcap_cleanup:
1198  if (unlink_newfile)
1200 
1201  mailcap_entry_free(&entry);
1202  goto out;
1203  }
1204 
1205  const char *const c_print_command =
1206  cs_subset_string(NeoMutt->sub, "print_command");
1207  if (mutt_istr_equal("text/plain", type) ||
1208  mutt_istr_equal("application/postscript", type))
1209  {
1210  rc = (mutt_pipe_attachment(fp, a, NONULL(c_print_command), NULL));
1211  goto out;
1212  }
1213  else if (mutt_can_decode(a))
1214  {
1215  /* decode and print */
1216 
1217  fp_in = NULL;
1218  fp_out = NULL;
1219 
1220  mutt_buffer_mktemp(newfile);
1221  if (mutt_decode_save_attachment(fp, a, mutt_buffer_string(newfile),
1223  {
1224  unlink_newfile = true;
1225  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1226  type, mutt_buffer_string(newfile));
1227 
1228  fp_in = fopen(mutt_buffer_string(newfile), "r");
1229  if (!fp_in)
1230  {
1231  mutt_perror("fopen");
1232  goto decode_cleanup;
1233  }
1234 
1235  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n",
1236  mutt_buffer_string(newfile));
1237 
1238  mutt_endwin();
1239  pid = filter_create(NONULL(c_print_command), &fp_out, NULL, NULL);
1240  if (pid < 0)
1241  {
1242  mutt_perror(_("Can't create filter"));
1243  goto decode_cleanup;
1244  }
1245 
1246  mutt_debug(LL_DEBUG2, "Filter created\n");
1247 
1248  mutt_file_copy_stream(fp_in, fp_out);
1249 
1250  mutt_file_fclose(&fp_out);
1251  mutt_file_fclose(&fp_in);
1252 
1253  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1254  if ((filter_wait(pid) != 0) || c_wait_key)
1256  rc = 1;
1257  }
1258  decode_cleanup:
1259  mutt_file_fclose(&fp_in);
1260  mutt_file_fclose(&fp_out);
1261  if (unlink_newfile)
1263  }
1264  else
1265  {
1266  mutt_error(_("I don't know how to print that"));
1267  rc = 0;
1268  }
1269 
1270 out:
1271  mutt_buffer_pool_release(&newfile);
1273 
1274  return rc;
1275 }
1276 
1281 void mutt_add_temp_attachment(const char *filename)
1282 {
1284 }
1285 
1290 {
1291  struct ListNode *np = NULL;
1292 
1293  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1294  {
1295  (void) mutt_file_chmod_add(np->data, S_IWUSR);
1296  mutt_file_unlink(np->data);
1297  }
1298 
1300 }
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Convenience wrapper for the config headers.
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Make a copy of a message from a FILE pointer.
Definition: copy.c:650
Duplicate the structure of an entire email.
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:58
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
Convenience wrapper for the core headers.
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:380
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:455
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:422
int mutt_do_pager(struct PagerView *pview, struct Email *e)
Display some page-able text to the user (help or attachment)
Definition: do_pager.c:120
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Structs that make up an email.
bool mutt_envlist_unset(const char *name)
Unset an environment variable.
Definition: envlist.c:132
bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:85
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
Definition: file.c:524
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:622
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:665
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1378
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:299
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1098
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
Convenience wrapper for the gui headers.
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1857
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1817
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1600
Decide how to display email content.
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
IMAP network mailbox.
int imap_wait_keepalive(pid_t pid)
Wait for a process to change state.
Definition: util.c:973
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:49
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:48
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:51
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:437
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:475
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:446
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:67
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:545
RFC1524 Mailcap routines.
MailcapLookup
Mailcap actions.
Definition: mailcap.h:55
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:59
@ MUTT_MC_EDIT
Mailcap edit field.
Definition: mailcap.h:57
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:60
@ MUTT_MC_NO_FLAGS
No flags set.
Definition: mailcap.h:56
@ MUTT_MC_COMPOSE
Mailcap compose field.
Definition: mailcap.h:58
#define FREE(x)
Definition: memory.h:40
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_8BIT
8-bit text
Definition: mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
ContentType
Content-Type.
Definition: mime.h:30
@ TYPE_AUDIO
Type: 'audio/*'.
Definition: mime.h:32
@ TYPE_IMAGE
Type: 'image/*'.
Definition: mime.h:34
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MODEL
Type: 'model/*'.
Definition: mime.h:36
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
@ TYPE_VIDEO
Type: 'video/*'.
Definition: mime.h:39
#define TYPE(body)
Definition: mime.h:89
#define is_multipart(body)
Definition: mime.h:82
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:727
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:181
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:475
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:560
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:257
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:432
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:717
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:340
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:1018
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1117
static int wait_interactive_filter(pid_t pid)
Wait after an interactive filter.
Definition: mutt_attach.c:387
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
Definition: mutt_attach.c:864
int mutt_get_tmp_attachment(struct Body *a)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:68
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1281
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:420
int mutt_compose_attachment(struct Body *a)
Create an attachment.
Definition: mutt_attach.c:118
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1289
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:884
int mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:263
Handling of email attachments.
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:56
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:58
@ MUTT_SAVE_OVERWRITE
Overwrite existing file.
Definition: mutt_attach.h:59
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:57
ViewAttachMode
Options for mutt_view_attachment()
Definition: mutt_attach.h:42
@ MUTT_VA_MAILCAP
Force viewing using mailcap entry.
Definition: mutt_attach.h:44
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:43
@ MUTT_VA_PAGER
View attachment in pager using copiousoutput mailcap.
Definition: mutt_attach.h:46
@ MUTT_VA_AS_TEXT
Force viewing as text.
Definition: mutt_attach.h:45
Hundreds of global variables to back the user variables.
struct ListHead TempAttachmentsList
List of temporary files for displaying attachments.
Definition: mutt_globals.h:69
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition: mutt_globals.h:67
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:406
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:83
Some miscellaneous functions.
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1191
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1673
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1170
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1059
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
API for mailboxes.
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:41
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:62
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:64
API for encryption/signing of emails.
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define WithCrypto
Definition: lib.h:113
Handling of global boolean variables.
bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:60
GUI display a file/email/help in a viewport with paging.
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: lib.h:59
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:72
@ PAGER_MODE_ATTACH
Pager is invoked via 2nd path. A user-selected attachment (mime part or a nested email) will be shown...
Definition: lib.h:137
#define MUTT_PAGER_MESSAGE
Definition: lib.h:75
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: lib.h:71
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1721
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1327
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1426
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:182
#define TAILQ_INIT(head)
Definition: queue.h:765
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void mutt_rfc3676_space_stuff_attachment(struct Body *b, const char *filename)
Stuff attachments.
Definition: rfc3676.c:536
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:515
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:391
RFC3676 Format Flowed routines.
Convenience wrapper for the send headers.
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:895
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:564
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:207
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
#define NONULL(x)
Definition: string2.h:37
A set of attachments.
Definition: attach.h:50
The body of an email.
Definition: body.h:35
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:71
LOFF_T offset
offset where the actual data begins
Definition: body.h:51
char * xtype
content-type if x-unknown
Definition: body.h:60
bool noconv
Don't do character set conversion.
Definition: body.h:45
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:66
time_t stamp
Time stamp of last encoding update.
Definition: body.h:75
LOFF_T length
length (in bytes) of attachment
Definition: body.h:52
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:61
struct Email * email
header information for message/rfc822
Definition: body.h:72
char * description
content-description
Definition: body.h:54
char * subtype
content-type subtype
Definition: body.h:59
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:40
char * form_name
Content-Disposition form-data name param.
Definition: body.h:58
unsigned int type
content-type primary type, ContentType
Definition: body.h:39
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:57
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
int msgno
Number displayed to the user.
Definition: email.h:111
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
A mailbox.
Definition: mailbox.h:82
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
A mailcap entry.
Definition: mailcap.h:36
char * composecommand
Definition: mailcap.h:39
bool needsterminal
endwin() and system
Definition: mailcap.h:45
char * nametemplate
Definition: mailcap.h:43
char * printcommand
Definition: mailcap.h:42
char * composetypecommand
Definition: mailcap.h:40
char * editcommand
Definition: mailcap.h:41
char * command
Definition: mailcap.h:37
bool copiousoutput
needs pager, basically
Definition: mailcap.h:46
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:47
bool xneomuttnowrap
do not wrap the output in the pager
Definition: mailcap.h:48
A local copy of an email.
Definition: mxapi.h:42
FILE * fp
pointer to the message data
Definition: mxapi.h:43
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Data to be displayed by PagerView.
Definition: lib.h:149
const char * fname
Name of the file to read.
Definition: lib.h:153
FILE * fp
Source stream.
Definition: lib.h:151
struct Body * body
Current attachment.
Definition: lib.h:150
struct AttachCtx * actx
Attachment information.
Definition: lib.h:152
Paged view into some data.
Definition: lib.h:160
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:161
enum PagerMode mode
Pager mode.
Definition: lib.h:162
PagerFlags flags
Additional settings to tweak pager's function.
Definition: lib.h:163
const char * banner
Title to display in status bar.
Definition: lib.h:164
Keep track when processing files.
Definition: state.h:45
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
FILE * fp_out
File to write to.
Definition: state.h:47
FILE * fp_in
File to read from.
Definition: state.h:46
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60