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