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