NeoMutt  2018-07-16 +2481-68dcde
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 <unistd.h>
38 #include "mutt/mutt.h"
39 #include "config/lib.h"
40 #include "email/lib.h"
41 #include "core/lib.h"
42 #include "mutt_attach.h"
43 #include "context.h"
44 #include "copy.h"
45 #include "curs_lib.h"
46 #include "filter.h"
47 #include "globals.h"
48 #include "handler.h"
49 #include "mailcap.h"
50 #include "muttlib.h"
51 #include "mx.h"
52 #include "ncrypt/ncrypt.h"
53 #include "options.h"
54 #include "pager.h"
55 #include "protos.h"
56 #include "sendlib.h"
57 #include "state.h"
58 
66 {
67  char type[256];
68  struct stat st;
69 
70  if (a->unlink)
71  return 0;
72 
73  struct Buffer *tmpfile = mutt_buffer_pool_get();
74  struct MailcapEntry *entry = mailcap_entry_new();
75  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
76  mailcap_lookup(a, type, entry, MUTT_MC_NO_FLAGS);
77  mailcap_expand_filename(entry->nametemplate, a->filename, tmpfile);
78 
79  mailcap_entry_free(&entry);
80 
81  if (stat(a->filename, &st) == -1)
82  {
83  mutt_buffer_pool_release(&tmpfile);
84  return -1;
85  }
86 
87  FILE *fp_in = NULL, *fp_out = NULL;
88  if ((fp_in = fopen(a->filename, "r")) &&
89  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
90  {
91  mutt_file_copy_stream(fp_in, fp_out);
92  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
93  a->unlink = true;
94 
95  if (a->stamp >= st.st_mtime)
97  }
98  else
99  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
100 
101  mutt_file_fclose(&fp_in);
102  mutt_file_fclose(&fp_out);
103 
104  mutt_buffer_pool_release(&tmpfile);
105 
106  return a->unlink ? 0 : -1;
107 }
108 
116 {
117  char type[256];
118  struct MailcapEntry *entry = mailcap_entry_new();
119  bool unlink_newfile = false;
120  int rc = 0;
121  struct Buffer *cmd = mutt_buffer_pool_get();
122  struct Buffer *newfile = mutt_buffer_pool_get();
123  struct Buffer *tmpfile = mutt_buffer_pool_get();
124 
125  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
126  if (mailcap_lookup(a, type, entry, MUTT_MC_COMPOSE))
127  {
128  if (entry->composecommand || entry->composetypecommand)
129  {
130  if (entry->composetypecommand)
132  else
133  mutt_buffer_strcpy(cmd, entry->composecommand);
134 
135  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
136  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
137  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
138  {
139  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
140  goto bailout;
141  mutt_buffer_strcpy(newfile, a->filename);
142  }
143  else
144  unlink_newfile = true;
145 
146  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
147  {
148  /* For now, editing requires a file, no piping */
149  mutt_error(_("Mailcap compose entry requires %%s"));
150  }
151  else
152  {
153  int r;
154 
155  mutt_endwin();
156  r = mutt_system(mutt_b2s(cmd));
157  if (r == -1)
158  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
159 
160  if ((r != -1) && entry->composetypecommand)
161  {
162  struct Body *b = NULL;
163 
164  FILE *fp = mutt_file_fopen(a->filename, "r");
165  if (!fp)
166  {
167  mutt_perror(_("Failure to open file to parse headers"));
168  goto bailout;
169  }
170 
171  b = mutt_read_mime_header(fp, 0);
172  if (b)
173  {
174  if (!TAILQ_EMPTY(&b->parameter))
175  {
177  a->parameter = b->parameter;
178  TAILQ_INIT(&b->parameter);
179  }
180  if (b->description)
181  {
182  FREE(&a->description);
183  a->description = b->description;
184  b->description = NULL;
185  }
186  if (b->form_name)
187  {
188  FREE(&a->form_name);
189  a->form_name = b->form_name;
190  b->form_name = NULL;
191  }
192 
193  /* Remove headers by copying out data to another file, then
194  * copying the file back */
195  fseeko(fp, b->offset, SEEK_SET);
196  mutt_body_free(&b);
197  mutt_buffer_mktemp(tmpfile);
198  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpfile), "w");
199  if (!fp_tmp)
200  {
201  mutt_perror(_("Failure to open file to strip headers"));
202  mutt_file_fclose(&fp);
203  goto bailout;
204  }
205  mutt_file_copy_stream(fp, fp_tmp);
206  mutt_file_fclose(&fp);
207  mutt_file_fclose(&fp_tmp);
209  if (mutt_file_rename(mutt_b2s(tmpfile), a->filename) != 0)
210  {
211  mutt_perror(_("Failure to rename file"));
212  goto bailout;
213  }
214  }
215  }
216  }
217  }
218  }
219  else
220  {
221  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
222  rc = 1;
223  goto bailout;
224  }
225 
226  rc = 1;
227 
228 bailout:
229 
230  if (unlink_newfile)
231  unlink(mutt_b2s(newfile));
232 
234  mutt_buffer_pool_release(&newfile);
235  mutt_buffer_pool_release(&tmpfile);
236 
237  mailcap_entry_free(&entry);
238  return rc;
239 }
240 
255 {
256  char type[256];
257  struct MailcapEntry *entry = mailcap_entry_new();
258  bool unlink_newfile = false;
259  int rc = 0;
260  struct Buffer *cmd = mutt_buffer_pool_get();
261  struct Buffer *newfile = mutt_buffer_pool_get();
262 
263  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
264  if (mailcap_lookup(a, type, entry, MUTT_MC_EDIT))
265  {
266  if (entry->editcommand)
267  {
268  mutt_buffer_strcpy(cmd, entry->editcommand);
269  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
270  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
271  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
272  {
273  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
274  goto bailout;
275  mutt_buffer_strcpy(newfile, a->filename);
276  }
277  else
278  unlink_newfile = true;
279 
280  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
281  {
282  /* For now, editing requires a file, no piping */
283  mutt_error(_("Mailcap Edit entry requires %%s"));
284  goto bailout;
285  }
286  else
287  {
288  mutt_endwin();
289  if (mutt_system(mutt_b2s(cmd)) == -1)
290  {
291  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
292  goto bailout;
293  }
294  }
295  }
296  }
297  else if (a->type == TYPE_TEXT)
298  {
299  /* On text, default to editor */
301  }
302  else
303  {
304  mutt_error(_("No mailcap edit entry for %s"), type);
305  rc = 0;
306  goto bailout;
307  }
308 
309  rc = 1;
310 
311 bailout:
312 
313  if (unlink_newfile)
314  unlink(mutt_b2s(newfile));
315 
317  mutt_buffer_pool_release(&newfile);
318 
319  mailcap_entry_free(&entry);
320  return rc;
321 }
322 
329 void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
330 {
331  struct ListNode *np = NULL;
332  STAILQ_FOREACH(np, &MimeLookupList, entries)
333  {
334  const int i = mutt_str_strlen(np->data) - 1;
335  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
336  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
337  (mutt_str_strcasecmp(type, np->data) == 0))
338  {
339  struct Body tmp = { 0 };
340  enum ContentType n;
341  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
342  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
343  {
344  snprintf(type, len, "%s/%s",
345  (n == TYPE_AUDIO) ?
346  "audio" :
347  (n == TYPE_APPLICATION) ?
348  "application" :
349  (n == TYPE_IMAGE) ?
350  "image" :
351  (n == TYPE_MESSAGE) ?
352  "message" :
353  (n == TYPE_MODEL) ?
354  "model" :
355  (n == TYPE_MULTIPART) ?
356  "multipart" :
357  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
358  tmp.subtype);
359  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
360  }
361  FREE(&tmp.subtype);
362  FREE(&tmp.xtype);
363  }
364  }
365 }
366 
384 int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode,
385  struct Email *e, struct AttachCtx *actx)
386 {
387  bool use_mailcap = false;
388  bool use_pipe = false;
389  bool use_pager = true;
390  char type[256];
391  char desc[256];
392  char *fname = NULL;
393  struct MailcapEntry *entry = NULL;
394  int rc = -1;
395  bool unlink_tempfile = false;
396 
397  bool is_message = mutt_is_message_type(a->type, a->subtype);
398  if ((WithCrypto != 0) && is_message && a->email &&
400  {
401  return rc;
402  }
403 
404  struct Buffer *tmpfile = mutt_buffer_pool_get();
405  struct Buffer *pagerfile = mutt_buffer_pool_get();
406  struct Buffer *cmd = mutt_buffer_pool_get();
407 
408  use_mailcap =
409  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
410  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
411 
412  if (use_mailcap)
413  {
414  entry = mailcap_entry_new();
415  if (!mailcap_lookup(a, type, entry, MUTT_MC_NO_FLAGS))
416  {
417  if (mode == MUTT_VA_REGULAR)
418  {
419  /* fallback to view as text */
420  mailcap_entry_free(&entry);
421  mutt_error(_("No matching mailcap entry found. Viewing as text."));
422  mode = MUTT_VA_AS_TEXT;
423  use_mailcap = false;
424  }
425  else
426  goto return_error;
427  }
428  }
429 
430  if (use_mailcap)
431  {
432  if (!entry->command)
433  {
434  mutt_error(_("MIME type not defined. Can't view attachment."));
435  goto return_error;
436  }
437  mutt_buffer_strcpy(cmd, entry->command);
438 
439  if (fp)
440  {
441  fname = mutt_str_strdup(a->filename);
442  mutt_file_sanitize_filename(fname, true);
443  }
444  else
445  fname = a->filename;
446 
447  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
448  /* send case: the file is already there; symlink to it */
449  if (!fp)
450  {
451  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
452  {
453  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
454  goto return_error;
455  mutt_buffer_strcpy(tmpfile, a->filename);
456  }
457  else
458  unlink_tempfile = true;
459  }
460  /* recv case: we need to save the attachment to a file */
461  else
462  {
463  FREE(&fname);
464  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
465  goto return_error;
466  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
467  }
468 
469  use_pipe = mailcap_expand_command(a, mutt_b2s(tmpfile), type, cmd);
470  use_pager = entry->copiousoutput;
471  }
472 
473  if (use_pager)
474  {
475  if (fp && !use_mailcap && a->filename)
476  {
477  /* recv case */
478  mutt_buffer_strcpy(pagerfile, a->filename);
479  mutt_adv_mktemp(pagerfile);
480  }
481  else
482  mutt_buffer_mktemp(pagerfile);
483  }
484 
485  if (use_mailcap)
486  {
487  pid_t pid = 0;
488  int fd_temp = -1, fd_pager = -1;
489 
490  if (!use_pager)
491  mutt_endwin();
492 
493  if (use_pager || use_pipe)
494  {
495  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
496  O_CREAT | O_EXCL | O_WRONLY)) == -1))
497  {
498  mutt_perror("open");
499  goto return_error;
500  }
501  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
502  {
503  if (fd_pager != -1)
504  close(fd_pager);
505  mutt_perror("open");
506  goto return_error;
507  }
508 
509  pid = mutt_create_filter_fd(mutt_b2s(cmd), NULL, NULL, NULL,
510  use_pipe ? fd_temp : -1,
511  use_pager ? fd_pager : -1, -1);
512  if (pid == -1)
513  {
514  if (fd_pager != -1)
515  close(fd_pager);
516 
517  if (fd_temp != -1)
518  close(fd_temp);
519 
520  mutt_error(_("Can't create filter"));
521  goto return_error;
522  }
523 
524  if (use_pager)
525  {
526  if (a->description)
527  {
528  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
529  mutt_b2s(cmd), a->description);
530  }
531  else
532  {
533  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
534  mutt_b2s(cmd), type);
535  }
536  }
537 
538  if ((mutt_wait_filter(pid) || (entry->needsterminal && C_WaitKey)) && !use_pager)
540 
541  if (fd_temp != -1)
542  close(fd_temp);
543  if (fd_pager != -1)
544  close(fd_pager);
545  }
546  else
547  {
548  /* interactive cmd */
549  int rv = mutt_system(mutt_b2s(cmd));
550  if (rv == -1)
551  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
552 
553  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
555  }
556  }
557  else
558  {
559  /* Don't use mailcap; the attachment is viewed in the pager */
560 
561  if (mode == MUTT_VA_AS_TEXT)
562  {
563  /* just let me see the raw data */
564  if (fp)
565  {
566  /* Viewing from a received message.
567  *
568  * Don't use mutt_save_attachment() because we want to perform charset
569  * conversion since this will be displayed by the internal pager. */
570  struct State decode_state = { 0 };
571 
572  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
573  if (!decode_state.fp_out)
574  {
575  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
576  mutt_b2s(pagerfile), errno, strerror(errno));
577  mutt_perror(mutt_b2s(pagerfile));
578  goto return_error;
579  }
580  decode_state.fp_in = fp;
581  decode_state.flags = MUTT_CHARCONV;
582  mutt_decode_attachment(a, &decode_state);
583  if (fclose(decode_state.fp_out) == EOF)
584  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
585  errno, strerror(errno));
586  }
587  else
588  {
589  /* in compose mode, just copy the file. we can't use
590  * mutt_decode_attachment() since it assumes the content-encoding has
591  * already been applied */
592  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
593  goto return_error;
594  }
595  }
596  else
597  {
598  /* Use built-in handler */
599  OptViewAttach = true; /* disable the "use 'v' to view this part"
600  * message in case of error */
602  {
603  OptViewAttach = false;
604  goto return_error;
605  }
606  OptViewAttach = false;
607  }
608 
609  if (a->description)
610  mutt_str_strfcpy(desc, a->description, sizeof(desc));
611  else if (a->filename)
612  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
613  else
614  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
615  }
616 
617  /* We only reach this point if there have been no errors */
618 
619  if (use_pager)
620  {
621  struct Pager info = { 0 };
622  info.fp = fp;
623  info.body = a;
624  info.ctx = Context;
625  info.actx = actx;
626  info.email = e;
627 
628  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
630  &info);
631  mutt_buffer_reset(pagerfile);
632  }
633  else
634  rc = 0;
635 
636 return_error:
637 
638  if (!entry || !entry->xneomuttkeep)
639  {
640  if (fp && mutt_b2s(tmpfile)[0])
641  {
642  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
644  }
645  else if (unlink_tempfile)
646  {
647  unlink(mutt_b2s(tmpfile));
648  }
649  }
650 
651  mailcap_entry_free(&entry);
652 
653  if (mutt_b2s(pagerfile)[0] != '\0')
654  mutt_file_unlink(mutt_b2s(pagerfile));
655 
656  mutt_buffer_pool_release(&tmpfile);
657  mutt_buffer_pool_release(&pagerfile);
659 
660  return rc;
661 }
662 
672 int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
673 {
674  pid_t pid;
675  int out = -1;
676  int rc = 0;
677 
678  if (outfile && *outfile)
679  {
680  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
681  if (out < 0)
682  {
683  mutt_perror("open");
684  return 0;
685  }
686  }
687 
688  mutt_endwin();
689 
690  if (fp)
691  {
692  /* recv case */
693 
694  struct State s = { 0 };
695 
696  /* perform charset conversion on text attachments when piping */
697  s.flags = MUTT_CHARCONV;
698 
699  if (outfile && *outfile)
700  pid = mutt_create_filter_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
701  else
702  pid = mutt_create_filter(path, &s.fp_out, NULL, NULL);
703 
704  if (pid < 0)
705  {
706  mutt_perror(_("Can't create filter"));
707  goto bail;
708  }
709 
710  s.fp_in = fp;
711  mutt_decode_attachment(b, &s);
713  }
714  else
715  {
716  /* send case */
717  FILE *fp_in = fopen(b->filename, "r");
718  if (!fp_in)
719  {
720  mutt_perror("fopen");
721  if (outfile && *outfile)
722  {
723  close(out);
724  unlink(outfile);
725  }
726  return 0;
727  }
728 
729  FILE *fp_out = NULL;
730  if (outfile && *outfile)
731  pid = mutt_create_filter_fd(path, &fp_out, NULL, NULL, -1, out, -1);
732  else
733  pid = mutt_create_filter(path, &fp_out, NULL, NULL);
734 
735  if (pid < 0)
736  {
737  mutt_perror(_("Can't create filter"));
738  mutt_file_fclose(&fp_in);
739  goto bail;
740  }
741 
742  mutt_file_copy_stream(fp_in, fp_out);
743  mutt_file_fclose(&fp_out);
744  mutt_file_fclose(&fp_in);
745  }
746 
747  rc = 1;
748 
749 bail:
750 
751  if (outfile && *outfile)
752  close(out);
753 
754  /* check for error exit from child process */
755  if (mutt_wait_filter(pid) != 0)
756  rc = 0;
757 
758  if ((rc == 0) || C_WaitKey)
760  return rc;
761 }
762 
769 static FILE *save_attachment_open(const char *path, enum SaveAttach opt)
770 {
771  if (opt == MUTT_SAVE_APPEND)
772  return fopen(path, "a");
773  if (opt == MUTT_SAVE_OVERWRITE)
774  return fopen(path, "w");
775 
776  return mutt_file_fopen(path, "w");
777 }
778 
789 int mutt_save_attachment(FILE *fp, struct Body *m, const char *path,
790  enum SaveAttach opt, struct Email *e)
791 {
792  if (!m)
793  return -1;
794 
795  if (fp)
796  {
797  /* recv mode */
798 
799  if (e && m->email && (m->encoding != ENC_BASE64) &&
801  {
802  /* message type attachments are written to mail folders. */
803 
804  char buf[8192];
805  struct Message *msg = NULL;
806  CopyHeaderFlags chflags = CH_NO_FLAGS;
807  int rc = -1;
808 
809  struct Email *e_new = m->email;
810  e_new->msgno = e->msgno; /* required for MH/maildir */
811  e_new->read = true;
812 
813  if (fseeko(fp, m->offset, SEEK_SET) < 0)
814  return -1;
815  if (!fgets(buf, sizeof(buf), fp))
816  return -1;
817  struct Mailbox *m_att = mx_path_resolve(path);
818  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
819  if (!ctx)
820  {
821  mailbox_free(&m_att);
822  return -1;
823  }
824  msg = mx_msg_open_new(ctx->mailbox, e_new,
825  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
826  if (!msg)
827  {
828  mx_mbox_close(&ctx);
829  return -1;
830  }
831  if ((ctx->mailbox->magic == MUTT_MBOX) || (ctx->mailbox->magic == MUTT_MMDF))
832  chflags = CH_FROM | CH_UPDATE_LEN;
833  chflags |= ((ctx->mailbox->magic == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
834  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags) == 0) &&
835  (mx_msg_commit(ctx->mailbox, msg) == 0))
836  {
837  rc = 0;
838  }
839  else
840  {
841  rc = -1;
842  }
843 
844  mx_msg_close(ctx->mailbox, &msg);
845  mx_mbox_close(&ctx);
846  return rc;
847  }
848  else
849  {
850  /* In recv mode, extract from folder and decode */
851 
852  struct State s = { 0 };
853 
854  s.fp_out = save_attachment_open(path, opt);
855  if (!s.fp_out)
856  {
857  mutt_perror("fopen");
858  return -1;
859  }
860  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
861  mutt_decode_attachment(m, &s);
862 
863  if (mutt_file_fsync_close(&s.fp_out) != 0)
864  {
865  mutt_perror("fclose");
866  return -1;
867  }
868  }
869  }
870  else
871  {
872  if (!m->filename)
873  return -1;
874 
875  /* In send mode, just copy file */
876 
877  FILE *fp_old = fopen(m->filename, "r");
878  if (!fp_old)
879  {
880  mutt_perror("fopen");
881  return -1;
882  }
883 
884  FILE *fp_new = save_attachment_open(path, opt);
885  if (!fp_new)
886  {
887  mutt_perror("fopen");
888  mutt_file_fclose(&fp_old);
889  return -1;
890  }
891 
892  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
893  {
894  mutt_error(_("Write fault"));
895  mutt_file_fclose(&fp_old);
896  mutt_file_fclose(&fp_new);
897  return -1;
898  }
899  mutt_file_fclose(&fp_old);
900  if (mutt_file_fsync_close(&fp_new) != 0)
901  {
902  mutt_error(_("Write fault"));
903  return -1;
904  }
905  }
906 
907  return 0;
908 }
909 
920 int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path,
921  int displaying, enum SaveAttach opt)
922 {
923  struct State s = { 0 };
924  unsigned int saved_encoding = 0;
925  struct Body *saved_parts = NULL;
926  struct Email *e_saved = NULL;
927  int rc = 0;
928 
929  s.flags = displaying;
930 
931  if (opt == MUTT_SAVE_APPEND)
932  s.fp_out = fopen(path, "a");
933  else if (opt == MUTT_SAVE_OVERWRITE)
934  s.fp_out = fopen(path, "w");
935  else
936  s.fp_out = mutt_file_fopen(path, "w");
937 
938  if (!s.fp_out)
939  {
940  mutt_perror("fopen");
941  return -1;
942  }
943 
944  if (!fp)
945  {
946  /* When called from the compose menu, the attachment isn't parsed,
947  * so we need to do it here. */
948  struct stat st;
949 
950  if (stat(m->filename, &st) == -1)
951  {
952  mutt_perror("stat");
954  return -1;
955  }
956 
957  s.fp_in = fopen(m->filename, "r");
958  if (!s.fp_in)
959  {
960  mutt_perror("fopen");
961  return -1;
962  }
963 
964  saved_encoding = m->encoding;
965  if (!is_multipart(m))
966  m->encoding = ENC_8BIT;
967 
968  m->length = st.st_size;
969  m->offset = 0;
970  saved_parts = m->parts;
971  e_saved = m->email;
972  mutt_parse_part(s.fp_in, m);
973 
974  if (m->noconv || is_multipart(m))
975  s.flags |= MUTT_CHARCONV;
976  }
977  else
978  {
979  s.fp_in = fp;
980  s.flags |= MUTT_CHARCONV;
981  }
982 
983  mutt_body_handler(m, &s);
984 
985  if (mutt_file_fsync_close(&s.fp_out) != 0)
986  {
987  mutt_perror("fclose");
988  rc = -1;
989  }
990  if (!fp)
991  {
992  m->length = 0;
993  m->encoding = saved_encoding;
994  if (saved_parts)
995  {
996  email_free(&m->email);
997  m->parts = saved_parts;
998  m->email = e_saved;
999  }
1000  mutt_file_fclose(&s.fp_in);
1001  }
1002 
1003  return rc;
1004 }
1005 
1019 int mutt_print_attachment(FILE *fp, struct Body *a)
1020 {
1021  char type[256];
1022  pid_t pid;
1023  FILE *fp_in = NULL, *fp_out = NULL;
1024  bool unlink_newfile = false;
1025  struct Buffer *newfile = mutt_buffer_pool_get();
1026  struct Buffer *cmd = mutt_buffer_pool_get();
1027 
1028  int rc = 0;
1029 
1030  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1031 
1032  if (mailcap_lookup(a, type, NULL, MUTT_MC_PRINT))
1033  {
1034  int piped = false;
1035 
1036  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1037 
1038  struct MailcapEntry *entry = mailcap_entry_new();
1039  mailcap_lookup(a, type, entry, MUTT_MC_PRINT);
1040  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
1041  /* send mode: symlink from existing file to the newfile */
1042  if (!fp)
1043  {
1044  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1045  {
1046  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1047  goto mailcap_cleanup;
1048  mutt_buffer_strcpy(newfile, a->filename);
1049  }
1050  else
1051  unlink_newfile = true;
1052  }
1053  /* in recv mode, save file to newfile first */
1054  else
1055  {
1056  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), 0, NULL) == -1)
1057  goto mailcap_cleanup;
1058  }
1059 
1060  mutt_buffer_strcpy(cmd, entry->printcommand);
1061  piped = mailcap_expand_command(a, mutt_b2s(newfile), type, cmd);
1062 
1063  mutt_endwin();
1064 
1065  /* interactive program */
1066  if (piped)
1067  {
1068  fp_in = fopen(mutt_b2s(newfile), "r");
1069  if (!fp_in)
1070  {
1071  mutt_perror("fopen");
1072  mailcap_entry_free(&entry);
1073  goto mailcap_cleanup;
1074  }
1075 
1076  pid = mutt_create_filter(mutt_b2s(cmd), &fp_out, NULL, NULL);
1077  if (pid < 0)
1078  {
1079  mutt_perror(_("Can't create filter"));
1080  mailcap_entry_free(&entry);
1081  mutt_file_fclose(&fp_in);
1082  goto mailcap_cleanup;
1083  }
1084  mutt_file_copy_stream(fp_in, fp_out);
1085  mutt_file_fclose(&fp_out);
1086  mutt_file_fclose(&fp_in);
1087  if (mutt_wait_filter(pid) || C_WaitKey)
1089  }
1090  else
1091  {
1092  int rc2 = mutt_system(mutt_b2s(cmd));
1093  if (rc2 == -1)
1094  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1095 
1096  if ((rc2 != 0) || C_WaitKey)
1098  }
1099 
1100  rc = 1;
1101 
1102  mailcap_cleanup:
1103  if (fp)
1104  mutt_file_unlink(mutt_b2s(newfile));
1105  else if (unlink_newfile)
1106  unlink(mutt_b2s(newfile));
1107 
1108  mailcap_entry_free(&entry);
1109  goto out;
1110  }
1111 
1112  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1113  (mutt_str_strcasecmp("application/postscript", type) == 0))
1114  {
1115  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1116  goto out;
1117  }
1118  else if (mutt_can_decode(a))
1119  {
1120  /* decode and print */
1121 
1122  fp_in = NULL;
1123  fp_out = NULL;
1124 
1125  mutt_buffer_mktemp(newfile);
1126  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1127  {
1128  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1129  type, mutt_b2s(newfile));
1130 
1131  fp_in = fopen(mutt_b2s(newfile), "r");
1132  if (!fp_in)
1133  {
1134  mutt_perror("fopen");
1135  goto decode_cleanup;
1136  }
1137 
1138  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1139 
1140  mutt_endwin();
1141  pid = mutt_create_filter(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1142  if (pid < 0)
1143  {
1144  mutt_perror(_("Can't create filter"));
1145  goto decode_cleanup;
1146  }
1147 
1148  mutt_debug(LL_DEBUG2, "Filter created\n");
1149 
1150  mutt_file_copy_stream(fp_in, fp_out);
1151 
1152  mutt_file_fclose(&fp_out);
1153  mutt_file_fclose(&fp_in);
1154 
1155  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
1157  rc = 1;
1158  }
1159  decode_cleanup:
1160  mutt_file_fclose(&fp_in);
1161  mutt_file_fclose(&fp_out);
1162  mutt_file_unlink(mutt_b2s(newfile));
1163  }
1164  else
1165  {
1166  mutt_error(_("I don't know how to print that"));
1167  rc = 0;
1168  }
1169 
1170 out:
1171  mutt_buffer_pool_release(&newfile);
1173 
1174  return rc;
1175 }
1176 
1181 void mutt_add_temp_attachment(const char *filename)
1182 {
1183  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1184 }
1185 
1190 {
1191  struct ListNode *np = NULL;
1192 
1193  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1194  {
1195  mutt_file_chmod_add(np->data, S_IWUSR);
1196  mutt_file_unlink(np->data);
1197  }
1198 
1199  mutt_list_free(&TempAttachmentsList);
1200 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:52
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:217
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:49
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:63
A mailcap entry.
Definition: mailcap.h:37
The "current" mailbox.
Definition: context.h:36
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1790
FILE * fp
Source stream.
Definition: pager.h:70
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:428
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:1418
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
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
#define NONULL(x)
Definition: string2.h:37
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1383
The envelope/body of an email.
Definition: email.h:39
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#define mutt_perror(...)
Definition: logging.h:85
GUI miscellaneous curses (window drawing) routines.
#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:558
Structs that make up an email.
The "currently-open" mailbox.
#define is_multipart(body)
Definition: mime.h:77
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:166
#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:1332
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
No flags set.
Definition: mutt_attach.h:54
Pass files through external commands (filters)
char * composetypecommand
Definition: mailcap.h:42
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
make a copy of a message from a FILE pointer
Definition: copy.c:597
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:192
RFC1524 Mailcap routines.
int mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:254
String manipulation buffer.
Definition: buffer.h:33
Overwrite existing file.
Definition: mutt_attach.h:56
Type: &#39;audio/*&#39;.
Definition: mime.h:32
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:39
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:254
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:43
No flags set.
Definition: mailcap.h:57
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
#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:1189
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:789
An email being displayed.
Definition: pager.h:65
View using default method.
Definition: mutt_attach.h:41
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:122
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:123
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.
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:70
Hundreds of global variables to back the user variables.
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:517
Some miscellaneous functions.
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
Mailcap compose field.
Definition: mailcap.h:59
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1087
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:147
bool read
Email is read.
Definition: email.h:53
int mutt_get_tmp_attachment(struct Body *a)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:65
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
struct Mailbox * mailbox
Definition: context.h:50
Type: &#39;video/*&#39;.
Definition: mime.h:39
Log at debug level 2.
Definition: logging.h:57
API for mailboxes.
Mailcap print field.
Definition: mailcap.h:60
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:55
bool copiousoutput
needs pager, basically
Definition: mailcap.h:48
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:150
Convenience wrapper for the core headers.
#define TAILQ_INIT(head)
Definition: queue.h:759
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
char * editcommand
Definition: mailcap.h:43
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
int mutt_file_chmod(const char *path, mode_t mode)
Set permissions of a file.
Definition: file.c:1031
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:956
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1181
Base-64 encoded text.
Definition: mime.h:52
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:50
char * command
Definition: mailcap.h:39
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:65
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:613
#define mutt_b2s(buf)
Definition: buffer.h:41
struct Context * ctx
Current mailbox.
Definition: pager.h:67
Prototypes for many functions.
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
int mutt_str_strncasecmp(const char *a, const char *b, size_t l)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:656
WHERE struct Context * Context
Definition: globals.h:42
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:271
A local copy of an email.
Definition: mx.h:81
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:92
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:437
#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:920
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:1749
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
pid_t mutt_create_filter_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:65
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:48
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
Handling of email attachments.
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:54
API for encryption/signing of emails.
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/ncrypt.h pgplib.h, smime.h
Definition: email.h:41
Force viewing using mailcap entry.
Definition: mutt_attach.h:42
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
unsigned int type
content-type primary type
Definition: body.h:65
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:47
Type: &#39;message/*&#39;.
Definition: mime.h:35
char * printcommand
Definition: mailcap.h:44
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:532
char * nametemplate
Definition: mailcap.h:45
Keep track when processing files.
#define TYPE(body)
Definition: mime.h:83
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:1398
struct Email * email
Current message.
Definition: pager.h:68
char * data
String.
Definition: list.h:35
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:517
Log at debug level 1.
Definition: logging.h:56
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:329
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:586
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:1101
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:268
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
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:1066
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:141
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
Quoted-printable text.
Definition: mime.h:51
Type: &#39;model/*&#39;.
Definition: mime.h:36
WHERE char * C_Editor
Config: External command to use as an email editor.
Definition: globals.h:114
FILE * fp
pointer to the message data
Definition: mx.h:83
Append to existing file.
Definition: mutt_attach.h:55
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:90
char * composecommand
Definition: mailcap.h:41
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1539
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:1055
WHERE bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:53
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1545
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
Definition: mutt_attach.c:769
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:49
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Miscellaneous functions for sending an email.
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define TAILQ_EMPTY(head)
Definition: queue.h:715
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx)
View an attachment.
Definition: mutt_attach.c:384
Mailcap edit field.
Definition: mailcap.h:58
bool mailcap_lookup(struct Body *a, char *type, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:465
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:294
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:583
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:228
A List node for strings.
Definition: list.h:33
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:64
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
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
#define WithCrypto
Definition: ncrypt.h:160
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:308
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:672
bool needsterminal
endwin() and system
Definition: mailcap.h:47
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:1284
int mutt_compose_attachment(struct Body *a)
Create an attachment.
Definition: mutt_attach.c:115
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: pager.h:43
int msgno
Number displayed to the user.
Definition: email.h:88
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:52
ContentType
Content-Type.
Definition: mime.h:29
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1019