NeoMutt  2020-08-07-1-gab41a1
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 "send/lib.h"
47 #include "context.h"
48 #include "copy.h"
49 #include "handler.h"
50 #include "mailcap.h"
51 #include "mutt_globals.h"
52 #include "muttlib.h"
53 #include "mx.h"
54 #include "options.h"
55 #include "pager.h"
56 #include "protos.h"
57 #include "rfc3676.h"
58 #include "state.h"
59 #ifdef USE_IMAP
60 #include "imap/lib.h"
61 #endif
62 
70 {
71  char type[256];
72  struct stat st;
73 
74  if (a->unlink)
75  return 0;
76 
77  struct Buffer *tmpfile = mutt_buffer_pool_get();
78  struct MailcapEntry *entry = mailcap_entry_new();
79  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
80  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS);
81  mailcap_expand_filename(entry->nametemplate, a->filename, tmpfile);
82 
83  mailcap_entry_free(&entry);
84 
85  if (stat(a->filename, &st) == -1)
86  {
87  mutt_buffer_pool_release(&tmpfile);
88  return -1;
89  }
90 
91  FILE *fp_in = NULL, *fp_out = NULL;
92  if ((fp_in = fopen(a->filename, "r")) &&
93  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
94  {
95  mutt_file_copy_stream(fp_in, fp_out);
96  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
97  a->unlink = true;
98 
99  if (a->stamp >= st.st_mtime)
101  }
102  else
103  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
104 
105  mutt_file_fclose(&fp_in);
106  mutt_file_fclose(&fp_out);
107 
108  mutt_buffer_pool_release(&tmpfile);
109 
110  return a->unlink ? 0 : -1;
111 }
112 
120 {
121  char type[256];
122  struct MailcapEntry *entry = mailcap_entry_new();
123  bool unlink_newfile = false;
124  int rc = 0;
125  struct Buffer *cmd = mutt_buffer_pool_get();
126  struct Buffer *newfile = mutt_buffer_pool_get();
127  struct Buffer *tmpfile = mutt_buffer_pool_get();
128 
129  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
130  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_COMPOSE))
131  {
132  if (entry->composecommand || entry->composetypecommand)
133  {
134  if (entry->composetypecommand)
136  else
137  mutt_buffer_strcpy(cmd, entry->composecommand);
138 
139  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
140  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
141  if (mutt_file_symlink(a->filename, mutt_b2s(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_b2s(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();
160  r = mutt_system(mutt_b2s(cmd));
161  if (r == -1)
162  mutt_error(_("Error running \"%s\""), mutt_b2s(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_b2s(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_b2s(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_b2s(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\t newfile: %s\n", a->filename, mutt_b2s(newfile));
275  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
276  {
277  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
278  goto bailout;
279  mutt_buffer_strcpy(newfile, a->filename);
280  }
281  else
282  unlink_newfile = true;
283 
284  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
285  {
286  /* For now, editing requires a file, no piping */
287  mutt_error(_("Mailcap Edit entry requires %%s"));
288  goto bailout;
289  }
290  else
291  {
292  mutt_endwin();
293  if (mutt_system(mutt_b2s(cmd)) == -1)
294  {
295  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
296  goto bailout;
297  }
298  }
299  }
300  }
301  else if (a->type == TYPE_TEXT)
302  {
303  /* On text, default to editor */
305  }
306  else
307  {
308  mutt_error(_("No mailcap edit entry for %s"), type);
309  rc = 0;
310  goto bailout;
311  }
312 
313  rc = 1;
314 
315 bailout:
316 
317  if (unlink_newfile)
318  unlink(mutt_b2s(newfile));
319 
321  mutt_buffer_pool_release(&newfile);
322 
323  mailcap_entry_free(&entry);
324  return rc;
325 }
326 
333 void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
334 {
335  struct ListNode *np = NULL;
336  STAILQ_FOREACH(np, &MimeLookupList, entries)
337  {
338  const int i = mutt_str_len(np->data) - 1;
339  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
340  mutt_istrn_equal(type, np->data, i)) ||
341  mutt_istr_equal(type, np->data))
342  {
343  struct Body tmp = { 0 };
344  enum ContentType n;
345  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
346  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
347  {
348  snprintf(type, len, "%s/%s",
349  (n == TYPE_AUDIO) ?
350  "audio" :
351  (n == TYPE_APPLICATION) ?
352  "application" :
353  (n == TYPE_IMAGE) ?
354  "image" :
355  (n == TYPE_MESSAGE) ?
356  "message" :
357  (n == TYPE_MODEL) ?
358  "model" :
359  (n == TYPE_MULTIPART) ?
360  "multipart" :
361  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
362  tmp.subtype);
363  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
364  }
365  FREE(&tmp.subtype);
366  FREE(&tmp.xtype);
367  }
368  }
369 }
370 
384 static int wait_interactive_filter(pid_t pid)
385 {
386  int rc;
387 
388 #ifdef USE_IMAP
389  rc = imap_wait_keepalive(pid);
390 #else
391  waitpid(pid, &rc, 0);
392 #endif
394  rc = WIFEXITED(rc) ? WEXITSTATUS(rc) : -1;
395 
396  return rc;
397 }
416 int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode,
417  struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
418 {
419  bool use_mailcap = false;
420  bool use_pipe = false;
421  bool use_pager = true;
422  char type[256];
423  char desc[256];
424  char *fname = NULL;
425  struct MailcapEntry *entry = NULL;
426  int rc = -1;
427  bool unlink_tempfile = false;
428  bool unlink_pagerfile = false;
429 
430  bool is_message = mutt_is_message_type(a->type, a->subtype);
431  if ((WithCrypto != 0) && is_message && a->email &&
433  {
434  return rc;
435  }
436 
437  struct Buffer *tmpfile = mutt_buffer_pool_get();
438  struct Buffer *pagerfile = mutt_buffer_pool_get();
439  struct Buffer *cmd = mutt_buffer_pool_get();
440 
441  use_mailcap =
442  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
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  if (!mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS))
453  {
454  if (mode == MUTT_VA_REGULAR)
455  {
456  /* fallback to view as text */
457  mailcap_entry_free(&entry);
458  mutt_error(_("No matching mailcap entry found. Viewing as text."));
459  mode = MUTT_VA_AS_TEXT;
460  use_mailcap = false;
461  }
462  else
463  goto return_error;
464  }
465  }
466 
467  if (use_mailcap)
468  {
469  if (!entry->command)
470  {
471  mutt_error(_("MIME type not defined. Can't view attachment."));
472  goto return_error;
473  }
474  mutt_buffer_strcpy(cmd, entry->command);
475 
476  fname = mutt_str_dup(a->filename);
477  /* In send mode(!fp), we allow slashes because those are part of
478  * the tmpfile. The path will be removed in expand_filename */
479  mutt_file_sanitize_filename(fname, fp ? true : false);
480  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
481  FREE(&fname);
482 
483  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), 0, NULL) == -1)
484  goto return_error;
485  unlink_tempfile = true;
486 
488 
489  use_pipe = mailcap_expand_command(a, mutt_b2s(tmpfile), type, cmd);
490  use_pager = entry->copiousoutput;
491  }
492 
493  if (use_pager)
494  {
495  if (fp && !use_mailcap && a->filename)
496  {
497  /* recv case */
498  mutt_buffer_strcpy(pagerfile, a->filename);
499  mutt_adv_mktemp(pagerfile);
500  }
501  else
502  mutt_buffer_mktemp(pagerfile);
503  }
504 
505  if (use_mailcap)
506  {
507  pid_t pid = 0;
508  int fd_temp = -1, fd_pager = -1;
509 
510  if (!use_pager)
511  mutt_endwin();
512 
513  if (use_pager || use_pipe)
514  {
515  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
516  O_CREAT | O_EXCL | O_WRONLY)) == -1))
517  {
518  mutt_perror("open");
519  goto return_error;
520  }
521  unlink_pagerfile = true;
522 
523  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
524  {
525  if (fd_pager != -1)
526  close(fd_pager);
527  mutt_perror("open");
528  goto return_error;
529  }
530  unlink_pagerfile = true;
531 
532  pid = filter_create_fd(mutt_b2s(cmd), NULL, NULL, NULL,
533  use_pipe ? fd_temp : -1, use_pager ? fd_pager : -1, -1);
534 
535  if (pid == -1)
536  {
537  if (fd_pager != -1)
538  close(fd_pager);
539 
540  if (fd_temp != -1)
541  close(fd_temp);
542 
543  mutt_error(_("Can't create filter"));
544  goto return_error;
545  }
546 
547  if (use_pager)
548  {
549  if (a->description)
550  {
551  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
552  mutt_b2s(cmd), a->description);
553  }
554  else
555  {
556  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
557  mutt_b2s(cmd), type);
558  }
559  filter_wait(pid);
560  }
561  else
562  {
563  if (wait_interactive_filter(pid) || (entry->needsterminal && C_WaitKey))
565  }
566 
567  if (fd_temp != -1)
568  close(fd_temp);
569  if (fd_pager != -1)
570  close(fd_pager);
571  }
572  else
573  {
574  /* interactive cmd */
575  int rv = mutt_system(mutt_b2s(cmd));
576  if (rv == -1)
577  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
578 
579  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
581  }
582  }
583  else
584  {
585  /* Don't use mailcap; the attachment is viewed in the pager */
586 
587  if (mode == MUTT_VA_AS_TEXT)
588  {
589  /* just let me see the raw data */
590  if (fp)
591  {
592  /* Viewing from a received message.
593  *
594  * Don't use mutt_save_attachment() because we want to perform charset
595  * conversion since this will be displayed by the internal pager. */
596  struct State decode_state = { 0 };
597 
598  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
599  if (!decode_state.fp_out)
600  {
601  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
602  mutt_b2s(pagerfile), errno, strerror(errno));
603  mutt_perror(mutt_b2s(pagerfile));
604  goto return_error;
605  }
606  decode_state.fp_in = fp;
607  decode_state.flags = MUTT_CHARCONV;
608  mutt_decode_attachment(a, &decode_state);
609  if (mutt_file_fclose(&decode_state.fp_out) == EOF)
610  {
611  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
612  errno, strerror(errno));
613  }
614  }
615  else
616  {
617  /* in compose mode, just copy the file. we can't use
618  * mutt_decode_attachment() since it assumes the content-encoding has
619  * already been applied */
620  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
621  goto return_error;
622  unlink_pagerfile = true;
623  }
625  }
626  else
627  {
628  /* Use built-in handler */
629  OptViewAttach = true; /* disable the "use 'v' to view this part"
630  * message in case of error */
632  {
633  OptViewAttach = false;
634  goto return_error;
635  }
636  unlink_pagerfile = true;
637  OptViewAttach = false;
638  }
639 
640  if (a->description)
641  mutt_str_copy(desc, a->description, sizeof(desc));
642  else if (a->filename)
643  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
644  else
645  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
646  }
647 
648  /* We only reach this point if there have been no errors */
649 
650  if (use_pager)
651  {
652  struct Pager info = { 0 };
653  info.fp = fp;
654  info.body = a;
655  info.ctx = Context;
656  info.actx = actx;
657  info.email = e;
658 
659  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
661  &info);
662  mutt_buffer_reset(pagerfile);
663  unlink_pagerfile = false;
664  }
665  else
666  rc = 0;
667 
668 return_error:
669 
670  if (!entry || !entry->xneomuttkeep)
671  {
672  if (fp && !mutt_buffer_is_empty(tmpfile))
673  {
674  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
676  }
677  else if (unlink_tempfile)
678  {
679  unlink(mutt_b2s(tmpfile));
680  }
681  }
682 
683  mailcap_entry_free(&entry);
684 
685  if (unlink_pagerfile)
686  mutt_file_unlink(mutt_b2s(pagerfile));
687 
688  mutt_buffer_pool_release(&tmpfile);
689  mutt_buffer_pool_release(&pagerfile);
691  mutt_envlist_unset("COLUMNS");
692 
693  return rc;
694 }
695 
705 int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
706 {
707  pid_t pid = 0;
708  int out = -1, rc = 0;
709  bool is_flowed = false;
710  bool unlink_unstuff = false;
711  FILE *fp_filter = NULL, *fp_unstuff = NULL, *fp_in = NULL;
712  struct Buffer *unstuff_tempfile = NULL;
713 
714  if (outfile && *outfile)
715  {
716  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
717  if (out < 0)
718  {
719  mutt_perror("open");
720  return 0;
721  }
722  }
723 
725  {
726  is_flowed = true;
727  unstuff_tempfile = mutt_buffer_pool_get();
728  mutt_buffer_mktemp(unstuff_tempfile);
729  }
730 
731  mutt_endwin();
732 
733  if (outfile && *outfile)
734  pid = filter_create_fd(path, &fp_filter, NULL, NULL, -1, out, -1);
735  else
736  pid = filter_create(path, &fp_filter, NULL, NULL);
737  if (pid < 0)
738  {
739  mutt_perror(_("Can't create filter"));
740  goto bail;
741  }
742 
743  /* recv case */
744  if (fp)
745  {
746  struct State s = { 0 };
747 
748  /* perform charset conversion on text attachments when piping */
749  s.flags = MUTT_CHARCONV;
750 
751  if (is_flowed)
752  {
753  fp_unstuff = mutt_file_fopen(mutt_b2s(unstuff_tempfile), "w");
754  if (fp_unstuff == NULL)
755  {
756  mutt_perror("mutt_file_fopen");
757  goto bail;
758  }
759  unlink_unstuff = true;
760 
761  s.fp_in = fp;
762  s.fp_out = fp_unstuff;
763  mutt_decode_attachment(b, &s);
764  mutt_file_fclose(&fp_unstuff);
765 
766  mutt_rfc3676_space_unstuff_attachment(b, mutt_b2s(unstuff_tempfile));
767 
768  fp_unstuff = mutt_file_fopen(mutt_b2s(unstuff_tempfile), "r");
769  if (fp_unstuff == NULL)
770  {
771  mutt_perror("mutt_file_fopen");
772  goto bail;
773  }
774  mutt_file_copy_stream(fp_unstuff, fp_filter);
775  mutt_file_fclose(&fp_unstuff);
776  }
777  else
778  {
779  s.fp_in = fp;
780  s.fp_out = fp_filter;
781  mutt_decode_attachment(b, &s);
782  }
783  }
784 
785  /* send case */
786  else
787  {
788  const char *infile = NULL;
789 
790  if (is_flowed)
791  {
792  if (mutt_save_attachment(fp, b, mutt_b2s(unstuff_tempfile),
793  MUTT_SAVE_NO_FLAGS, NULL) == -1)
794  goto bail;
795  unlink_unstuff = true;
796  mutt_rfc3676_space_unstuff_attachment(b, mutt_b2s(unstuff_tempfile));
797  infile = mutt_b2s(unstuff_tempfile);
798  }
799  else
800  infile = b->filename;
801 
802  fp_in = fopen(infile, "r");
803  if (!fp_in)
804  {
805  mutt_perror("fopen");
806  goto bail;
807  }
808 
809  mutt_file_copy_stream(fp_in, fp_filter);
810  mutt_file_fclose(&fp_in);
811  }
812 
813  mutt_file_fclose(&fp_filter);
814  rc = 1;
815 
816 bail:
817  if (outfile && *outfile)
818  {
819  close(out);
820  if (rc == 0)
821  unlink(outfile);
822  else if (is_flowed)
824  }
825 
826  mutt_file_fclose(&fp_unstuff);
827  mutt_file_fclose(&fp_filter);
828  mutt_file_fclose(&fp_in);
829 
830  if (unlink_unstuff)
831  mutt_file_unlink(mutt_b2s(unstuff_tempfile));
832  mutt_buffer_pool_release(&unstuff_tempfile);
833 
834  /* check for error exit from child process */
835  if ((pid > 0) && (filter_wait(pid) != 0))
836  rc = 0;
837 
838  if ((rc == 0) || C_WaitKey)
840  return rc;
841 }
842 
849 static FILE *save_attachment_open(const char *path, enum SaveAttach opt)
850 {
851  if (opt == MUTT_SAVE_APPEND)
852  return fopen(path, "a");
853  if (opt == MUTT_SAVE_OVERWRITE)
854  return fopen(path, "w");
855 
856  return mutt_file_fopen(path, "w");
857 }
858 
869 int mutt_save_attachment(FILE *fp, struct Body *m, const char *path,
870  enum SaveAttach opt, struct Email *e)
871 {
872  if (!m)
873  return -1;
874 
875  if (fp)
876  {
877  /* recv mode */
878 
879  if (e && m->email && (m->encoding != ENC_BASE64) &&
881  {
882  /* message type attachments are written to mail folders. */
883 
884  char buf[8192];
885  struct Message *msg = NULL;
886  CopyHeaderFlags chflags = CH_NO_FLAGS;
887  int rc = -1;
888 
889  struct Email *e_new = m->email;
890  e_new->msgno = e->msgno; /* required for MH/maildir */
891  e_new->read = true;
892 
893  if (fseeko(fp, m->offset, SEEK_SET) < 0)
894  return -1;
895  if (!fgets(buf, sizeof(buf), fp))
896  return -1;
897  struct Mailbox *m_att = mx_path_resolve(path);
898  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
899  if (!ctx)
900  {
901  mailbox_free(&m_att);
902  return -1;
903  }
904  msg = mx_msg_open_new(ctx->mailbox, e_new,
905  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
906  if (!msg)
907  {
908  mx_mbox_close(&ctx);
909  return -1;
910  }
911  if ((ctx->mailbox->type == MUTT_MBOX) || (ctx->mailbox->type == MUTT_MMDF))
912  chflags = CH_FROM | CH_UPDATE_LEN;
913  chflags |= ((ctx->mailbox->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
914  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
915  (mx_msg_commit(ctx->mailbox, msg) == 0))
916  {
917  rc = 0;
918  }
919  else
920  {
921  rc = -1;
922  }
923 
924  mx_msg_close(ctx->mailbox, &msg);
925  mx_mbox_close(&ctx);
926  return rc;
927  }
928  else
929  {
930  /* In recv mode, extract from folder and decode */
931 
932  struct State s = { 0 };
933 
934  s.fp_out = save_attachment_open(path, opt);
935  if (!s.fp_out)
936  {
937  mutt_perror("fopen");
938  return -1;
939  }
940  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
941  mutt_decode_attachment(m, &s);
942 
943  if (mutt_file_fsync_close(&s.fp_out) != 0)
944  {
945  mutt_perror("fclose");
946  return -1;
947  }
948  }
949  }
950  else
951  {
952  if (!m->filename)
953  return -1;
954 
955  /* In send mode, just copy file */
956 
957  FILE *fp_old = fopen(m->filename, "r");
958  if (!fp_old)
959  {
960  mutt_perror("fopen");
961  return -1;
962  }
963 
964  FILE *fp_new = save_attachment_open(path, opt);
965  if (!fp_new)
966  {
967  mutt_perror("fopen");
968  mutt_file_fclose(&fp_old);
969  return -1;
970  }
971 
972  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
973  {
974  mutt_error(_("Write fault"));
975  mutt_file_fclose(&fp_old);
976  mutt_file_fclose(&fp_new);
977  return -1;
978  }
979  mutt_file_fclose(&fp_old);
980  if (mutt_file_fsync_close(&fp_new) != 0)
981  {
982  mutt_error(_("Write fault"));
983  return -1;
984  }
985  }
986 
987  return 0;
988 }
989 
1000 int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path,
1001  int displaying, enum SaveAttach opt)
1002 {
1003  struct State s = { 0 };
1004  unsigned int saved_encoding = 0;
1005  struct Body *saved_parts = NULL;
1006  struct Email *e_saved = NULL;
1007  int rc = 0;
1008 
1009  s.flags = displaying;
1010 
1011  if (opt == MUTT_SAVE_APPEND)
1012  s.fp_out = fopen(path, "a");
1013  else if (opt == MUTT_SAVE_OVERWRITE)
1014  s.fp_out = fopen(path, "w");
1015  else
1016  s.fp_out = mutt_file_fopen(path, "w");
1017 
1018  if (!s.fp_out)
1019  {
1020  mutt_perror("fopen");
1021  return -1;
1022  }
1023 
1024  if (!fp)
1025  {
1026  /* When called from the compose menu, the attachment isn't parsed,
1027  * so we need to do it here. */
1028  struct stat st;
1029 
1030  if (stat(m->filename, &st) == -1)
1031  {
1032  mutt_perror("stat");
1034  return -1;
1035  }
1036 
1037  s.fp_in = fopen(m->filename, "r");
1038  if (!s.fp_in)
1039  {
1040  mutt_perror("fopen");
1041  return -1;
1042  }
1043 
1044  saved_encoding = m->encoding;
1045  if (!is_multipart(m))
1046  m->encoding = ENC_8BIT;
1047 
1048  m->length = st.st_size;
1049  m->offset = 0;
1050  saved_parts = m->parts;
1051  e_saved = m->email;
1052  mutt_parse_part(s.fp_in, m);
1053 
1054  if (m->noconv || is_multipart(m))
1055  s.flags |= MUTT_CHARCONV;
1056  }
1057  else
1058  {
1059  s.fp_in = fp;
1060  s.flags |= MUTT_CHARCONV;
1061  }
1062 
1063  mutt_body_handler(m, &s);
1064 
1065  if (mutt_file_fsync_close(&s.fp_out) != 0)
1066  {
1067  mutt_perror("fclose");
1068  rc = -1;
1069  }
1070  if (!fp)
1071  {
1072  m->length = 0;
1073  m->encoding = saved_encoding;
1074  if (saved_parts)
1075  {
1076  email_free(&m->email);
1077  m->parts = saved_parts;
1078  m->email = e_saved;
1079  }
1080  mutt_file_fclose(&s.fp_in);
1081  }
1082 
1083  return rc;
1084 }
1085 
1099 int mutt_print_attachment(FILE *fp, struct Body *a)
1100 {
1101  char type[256];
1102  pid_t pid;
1103  FILE *fp_in = NULL, *fp_out = NULL;
1104  bool unlink_newfile = false;
1105  struct Buffer *newfile = mutt_buffer_pool_get();
1106  struct Buffer *cmd = mutt_buffer_pool_get();
1107 
1108  int rc = 0;
1109 
1110  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1111 
1112  if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1113  {
1114  int piped = false;
1115 
1116  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1117 
1118  struct MailcapEntry *entry = mailcap_entry_new();
1119  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1120  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
1121 
1122  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
1123  goto mailcap_cleanup;
1124  unlink_newfile = 1;
1125 
1127 
1128  mutt_buffer_strcpy(cmd, entry->printcommand);
1129  piped = mailcap_expand_command(a, mutt_b2s(newfile), type, cmd);
1130 
1131  mutt_endwin();
1132 
1133  /* interactive program */
1134  if (piped)
1135  {
1136  fp_in = fopen(mutt_b2s(newfile), "r");
1137  if (!fp_in)
1138  {
1139  mutt_perror("fopen");
1140  mailcap_entry_free(&entry);
1141  goto mailcap_cleanup;
1142  }
1143 
1144  pid = filter_create(mutt_b2s(cmd), &fp_out, NULL, NULL);
1145  if (pid < 0)
1146  {
1147  mutt_perror(_("Can't create filter"));
1148  mailcap_entry_free(&entry);
1149  mutt_file_fclose(&fp_in);
1150  goto mailcap_cleanup;
1151  }
1152  mutt_file_copy_stream(fp_in, fp_out);
1153  mutt_file_fclose(&fp_out);
1154  mutt_file_fclose(&fp_in);
1155  if (filter_wait(pid) || C_WaitKey)
1157  }
1158  else
1159  {
1160  int rc2 = mutt_system(mutt_b2s(cmd));
1161  if (rc2 == -1)
1162  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1163 
1164  if ((rc2 != 0) || C_WaitKey)
1166  }
1167 
1168  rc = 1;
1169 
1170  mailcap_cleanup:
1171  if (unlink_newfile)
1172  mutt_file_unlink(mutt_b2s(newfile));
1173 
1174  mailcap_entry_free(&entry);
1175  goto out;
1176  }
1177 
1178  if (mutt_istr_equal("text/plain", type) ||
1179  mutt_istr_equal("application/postscript", type))
1180  {
1181  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1182  goto out;
1183  }
1184  else if (mutt_can_decode(a))
1185  {
1186  /* decode and print */
1187 
1188  fp_in = NULL;
1189  fp_out = NULL;
1190 
1191  mutt_buffer_mktemp(newfile);
1192  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING,
1193  MUTT_SAVE_NO_FLAGS) == 0)
1194  {
1195  unlink_newfile = true;
1196  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1197  type, mutt_b2s(newfile));
1198 
1199  fp_in = fopen(mutt_b2s(newfile), "r");
1200  if (!fp_in)
1201  {
1202  mutt_perror("fopen");
1203  goto decode_cleanup;
1204  }
1205 
1206  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1207 
1208  mutt_endwin();
1209  pid = filter_create(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1210  if (pid < 0)
1211  {
1212  mutt_perror(_("Can't create filter"));
1213  goto decode_cleanup;
1214  }
1215 
1216  mutt_debug(LL_DEBUG2, "Filter created\n");
1217 
1218  mutt_file_copy_stream(fp_in, fp_out);
1219 
1220  mutt_file_fclose(&fp_out);
1221  mutt_file_fclose(&fp_in);
1222 
1223  if ((filter_wait(pid) != 0) || C_WaitKey)
1225  rc = 1;
1226  }
1227  decode_cleanup:
1228  mutt_file_fclose(&fp_in);
1229  mutt_file_fclose(&fp_out);
1230  if (unlink_newfile)
1231  mutt_file_unlink(mutt_b2s(newfile));
1232  }
1233  else
1234  {
1235  mutt_error(_("I don't know how to print that"));
1236  rc = 0;
1237  }
1238 
1239 out:
1240  mutt_buffer_pool_release(&newfile);
1242 
1243  return rc;
1244 }
1245 
1250 void mutt_add_temp_attachment(const char *filename)
1251 {
1252  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_dup(filename));
1253 }
1254 
1259 {
1260  struct ListNode *np = NULL;
1261 
1262  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1263  {
1264  mutt_file_chmod_add(np->data, S_IWUSR);
1265  mutt_file_unlink(np->data);
1266  }
1267 
1268  mutt_list_free(&TempAttachmentsList);
1269 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:54
Convenience wrapper for the gui headers.
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:50
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:65
A mailcap entry.
Definition: mailcap.h:38
The "current" mailbox.
Definition: context.h:38
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1843
FILE * fp
Source stream.
Definition: pager.h:70
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:427
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:891
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
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
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:123
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1366
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
#define mutt_perror(...)
Definition: logging.h:85
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:387
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:630
Structs that make up an email.
The "currently-open" mailbox.
#define is_multipart(body)
Definition: mime.h:82
Convenience wrapper for the send headers.
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
#define mutt_message(...)
Definition: logging.h:83
#define MUTT_PAGER_MESSAGE
Definition: pager.h:58
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1347
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
No flags set.
Definition: mutt_attach.h:55
char * composetypecommand
Definition: mailcap.h:43
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
String manipulation buffer.
Definition: buffer.h:33
Overwrite existing file.
Definition: mutt_attach.h:57
Type: &#39;audio/*&#39;.
Definition: mime.h:32
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
#define _(a)
Definition: message.h:28
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:57
8-bit text
Definition: mime.h:50
ViewAttachMode
Options for mutt_view_attachment()
Definition: mutt_attach.h:40
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:303
FILE * fp_out
File to write to.
Definition: state.h:47
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:51
struct Body * body
Current attachment.
Definition: pager.h:69
Force viewing as text.
Definition: mutt_attach.h:44
No flags set.
Definition: mailcap.h:58
A division of the screen.
Definition: mutt_window.h:115
WHERE struct Context * Context
Definition: mutt_globals.h:42
#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:1258
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:869
An email being displayed.
Definition: pager.h:65
View using default method.
Definition: mutt_attach.h:42
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:34
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
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: pager.h:55
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:465
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:69
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:533
bool mutt_istrn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:626
Some miscellaneous functions.
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
Mailcap compose field.
Definition: mailcap.h:60
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1206
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
bool read
Email is read.
Definition: email.h:51
int mutt_get_tmp_attachment(struct Body *a)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:69
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
struct Mailbox * mailbox
Definition: context.h:50
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:61
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
bool copiousoutput
needs pager, basically
Definition: mailcap.h:49
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 TAILQ_INIT(head)
Definition: queue.h:758
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:384
char * editcommand
Definition: mailcap.h:44
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1072
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: mutt_globals.h:104
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1250
Base-64 encoded text.
Definition: mime.h:52
&#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:888
char * command
Definition: mailcap.h:40
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
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:57
#define mutt_b2s(buf)
Definition: buffer.h:41
struct Context * ctx
Current mailbox.
Definition: pager.h:67
Prototypes for many functions.
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
A local copy of an email.
Definition: mx.h:83
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:571
WHERE char * C_Editor
Config: External command to use as an email editor.
Definition: mutt_globals.h:91
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
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:436
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
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:1000
Type: &#39;text/*&#39;.
Definition: mime.h:38
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1803
struct AttachCtx * actx
Attachment information.
Definition: pager.h:71
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.
API for encryption/signing of emails.
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:511
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
Handling of email attachments.
int imap_wait_keepalive(pid_t pid)
Wait for a process to change state.
Definition: util.c:1102
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:56
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
Force viewing using mailcap entry.
Definition: mutt_attach.h:43
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
char * printcommand
Definition: mailcap.h:45
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:604
char * nametemplate
Definition: mailcap.h:46
Keep track when processing files.
#define TYPE(body)
Definition: mime.h:89
GUI display a file/email/help in a viewport with paging.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1657
struct Email * email
Current message.
Definition: pager.h:68
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
char * data
String.
Definition: list.h:36
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Duplicate the structure of an entire email.
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:522
Log at debug level 1.
Definition: logging.h:40
int n
Definition: acutest.h:492
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:333
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:721
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:690
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:563
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
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:451
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
#define mutt_error(...)
Definition: logging.h:84
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:405
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:1185
Quoted-printable text.
Definition: mime.h:51
Type: &#39;model/*&#39;.
Definition: mime.h:36
FILE * fp
pointer to the message data
Definition: mx.h:85
Append to existing file.
Definition: mutt_attach.h:56
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:90
char * composecommand
Definition: mailcap.h:42
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1696
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:1067
WHERE bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:55
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:1593
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
Definition: mutt_attach.c:849
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
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define TAILQ_EMPTY(head)
Definition: queue.h:714
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:611
Mailcap edit field.
Definition: mailcap.h:59
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:588
A List node for strings.
Definition: list.h:34
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:66
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:43
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Decide how to display email content.
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:355
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:705
bool needsterminal
endwin() and system
Definition: mailcap.h:48
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
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:1267
int mutt_compose_attachment(struct Body *a)
Create an attachment.
Definition: mutt_attach.c:119
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: pager.h:43
int msgno
Number displayed to the user.
Definition: email.h:87
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:53
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:416
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: mutt_globals.h:171
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1099
void mutt_rfc3676_space_stuff_attachment(struct Body *b, const char *filename)
Stuff attachments.
Definition: rfc3676.c:532