NeoMutt  2019-12-07-60-g0cfa53
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 "gui/lib.h"
43 #include "mutt_attach.h"
44 #include "context.h"
45 #include "copy.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, sizeof(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, sizeof(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, sizeof(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 
385 int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode,
386  struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
387 {
388  bool use_mailcap = false;
389  bool use_pipe = false;
390  bool use_pager = true;
391  char type[256];
392  char desc[256];
393  char *fname = NULL;
394  struct MailcapEntry *entry = NULL;
395  int rc = -1;
396  bool unlink_tempfile = false;
397 
398  bool is_message = mutt_is_message_type(a->type, a->subtype);
399  if ((WithCrypto != 0) && is_message && a->email &&
401  {
402  return rc;
403  }
404 
405  struct Buffer *tmpfile = mutt_buffer_pool_get();
406  struct Buffer *pagerfile = mutt_buffer_pool_get();
407  struct Buffer *cmd = mutt_buffer_pool_get();
408 
409  use_mailcap =
410  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
411  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
412 
413  char columns[16];
414  snprintf(columns, sizeof(columns), "%d", win->state.cols);
415  mutt_envlist_set("COLUMNS", columns, true);
416 
417  if (use_mailcap)
418  {
419  entry = mailcap_entry_new();
420  if (!mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS))
421  {
422  if (mode == MUTT_VA_REGULAR)
423  {
424  /* fallback to view as text */
425  mailcap_entry_free(&entry);
426  mutt_error(_("No matching mailcap entry found. Viewing as text."));
427  mode = MUTT_VA_AS_TEXT;
428  use_mailcap = false;
429  }
430  else
431  goto return_error;
432  }
433  }
434 
435  if (use_mailcap)
436  {
437  if (!entry->command)
438  {
439  mutt_error(_("MIME type not defined. Can't view attachment."));
440  goto return_error;
441  }
442  mutt_buffer_strcpy(cmd, entry->command);
443 
444  if (fp)
445  {
446  fname = mutt_str_strdup(a->filename);
447  mutt_file_sanitize_filename(fname, true);
448  }
449  else
450  fname = a->filename;
451 
452  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
453  /* send case: the file is already there; symlink to it */
454  if (!fp)
455  {
456  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
457  {
458  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
459  goto return_error;
460  mutt_buffer_strcpy(tmpfile, a->filename);
461  }
462  else
463  unlink_tempfile = true;
464  }
465  /* recv case: we need to save the attachment to a file */
466  else
467  {
468  FREE(&fname);
469  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
470  goto return_error;
471  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
472  }
473 
474  use_pipe = mailcap_expand_command(a, mutt_b2s(tmpfile), type, cmd);
475  use_pager = entry->copiousoutput;
476  }
477 
478  if (use_pager)
479  {
480  if (fp && !use_mailcap && a->filename)
481  {
482  /* recv case */
483  mutt_buffer_strcpy(pagerfile, a->filename);
484  mutt_adv_mktemp(pagerfile);
485  }
486  else
487  mutt_buffer_mktemp(pagerfile);
488  }
489 
490  if (use_mailcap)
491  {
492  pid_t pid = 0;
493  int fd_temp = -1, fd_pager = -1;
494 
495  if (!use_pager)
496  mutt_endwin();
497 
498  if (use_pager || use_pipe)
499  {
500  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
501  O_CREAT | O_EXCL | O_WRONLY)) == -1))
502  {
503  mutt_perror("open");
504  goto return_error;
505  }
506  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
507  {
508  if (fd_pager != -1)
509  close(fd_pager);
510  mutt_perror("open");
511  goto return_error;
512  }
513 
514  pid = mutt_create_filter_fd(mutt_b2s(cmd), NULL, NULL, NULL,
515  use_pipe ? fd_temp : -1,
516  use_pager ? fd_pager : -1, -1);
517 
518  if (pid == -1)
519  {
520  if (fd_pager != -1)
521  close(fd_pager);
522 
523  if (fd_temp != -1)
524  close(fd_temp);
525 
526  mutt_error(_("Can't create filter"));
527  goto return_error;
528  }
529 
530  if (use_pager)
531  {
532  if (a->description)
533  {
534  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
535  mutt_b2s(cmd), a->description);
536  }
537  else
538  {
539  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
540  mutt_b2s(cmd), type);
541  }
542  }
543 
544  if ((mutt_wait_filter(pid) || (entry->needsterminal && C_WaitKey)) && !use_pager)
546 
547  if (fd_temp != -1)
548  close(fd_temp);
549  if (fd_pager != -1)
550  close(fd_pager);
551  }
552  else
553  {
554  /* interactive cmd */
555  int rv = mutt_system(mutt_b2s(cmd));
556  if (rv == -1)
557  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
558 
559  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
561  }
562  }
563  else
564  {
565  /* Don't use mailcap; the attachment is viewed in the pager */
566 
567  if (mode == MUTT_VA_AS_TEXT)
568  {
569  /* just let me see the raw data */
570  if (fp)
571  {
572  /* Viewing from a received message.
573  *
574  * Don't use mutt_save_attachment() because we want to perform charset
575  * conversion since this will be displayed by the internal pager. */
576  struct State decode_state = { 0 };
577 
578  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
579  if (!decode_state.fp_out)
580  {
581  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
582  mutt_b2s(pagerfile), errno, strerror(errno));
583  mutt_perror(mutt_b2s(pagerfile));
584  goto return_error;
585  }
586  decode_state.fp_in = fp;
587  decode_state.flags = MUTT_CHARCONV;
588  mutt_decode_attachment(a, &decode_state);
589  if (mutt_file_fclose(&decode_state.fp_out) == EOF)
590  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
591  errno, strerror(errno));
592  }
593  else
594  {
595  /* in compose mode, just copy the file. we can't use
596  * mutt_decode_attachment() since it assumes the content-encoding has
597  * already been applied */
598  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
599  goto return_error;
600  }
601  }
602  else
603  {
604  /* Use built-in handler */
605  OptViewAttach = true; /* disable the "use 'v' to view this part"
606  * message in case of error */
608  {
609  OptViewAttach = false;
610  goto return_error;
611  }
612  OptViewAttach = false;
613  }
614 
615  if (a->description)
616  mutt_str_strfcpy(desc, a->description, sizeof(desc));
617  else if (a->filename)
618  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
619  else
620  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
621  }
622 
623  /* We only reach this point if there have been no errors */
624 
625  if (use_pager)
626  {
627  struct Pager info = { 0 };
628  info.fp = fp;
629  info.body = a;
630  info.ctx = Context;
631  info.actx = actx;
632  info.email = e;
633 
634  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
636  &info);
637  mutt_buffer_reset(pagerfile);
638  }
639  else
640  rc = 0;
641 
642 return_error:
643 
644  if (!entry || !entry->xneomuttkeep)
645  {
646  if (fp && !mutt_buffer_is_empty(tmpfile))
647  {
648  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
650  }
651  else if (unlink_tempfile)
652  {
653  unlink(mutt_b2s(tmpfile));
654  }
655  }
656 
657  mailcap_entry_free(&entry);
658 
659  if (!mutt_buffer_is_empty(pagerfile))
660  mutt_file_unlink(mutt_b2s(pagerfile));
661 
662  mutt_buffer_pool_release(&tmpfile);
663  mutt_buffer_pool_release(&pagerfile);
665  mutt_envlist_unset("COLUMNS");
666 
667  return rc;
668 }
669 
679 int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
680 {
681  pid_t pid;
682  int out = -1;
683  int rc = 0;
684 
685  if (outfile && *outfile)
686  {
687  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
688  if (out < 0)
689  {
690  mutt_perror("open");
691  return 0;
692  }
693  }
694 
695  mutt_endwin();
696 
697  if (fp)
698  {
699  /* recv case */
700 
701  struct State s = { 0 };
702 
703  /* perform charset conversion on text attachments when piping */
704  s.flags = MUTT_CHARCONV;
705 
706  if (outfile && *outfile)
707  pid = mutt_create_filter_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
708  else
709  pid = mutt_create_filter(path, &s.fp_out, NULL, NULL);
710 
711  if (pid < 0)
712  {
713  mutt_perror(_("Can't create filter"));
714  goto bail;
715  }
716 
717  s.fp_in = fp;
718  mutt_decode_attachment(b, &s);
720  }
721  else
722  {
723  /* send case */
724  FILE *fp_in = fopen(b->filename, "r");
725  if (!fp_in)
726  {
727  mutt_perror("fopen");
728  if (outfile && *outfile)
729  {
730  close(out);
731  unlink(outfile);
732  }
733  return 0;
734  }
735 
736  FILE *fp_out = NULL;
737  if (outfile && *outfile)
738  pid = mutt_create_filter_fd(path, &fp_out, NULL, NULL, -1, out, -1);
739  else
740  pid = mutt_create_filter(path, &fp_out, NULL, NULL);
741 
742  if (pid < 0)
743  {
744  mutt_perror(_("Can't create filter"));
745  mutt_file_fclose(&fp_in);
746  goto bail;
747  }
748 
749  mutt_file_copy_stream(fp_in, fp_out);
750  mutt_file_fclose(&fp_out);
751  mutt_file_fclose(&fp_in);
752  }
753 
754  rc = 1;
755 
756 bail:
757 
758  if (outfile && *outfile)
759  close(out);
760 
761  /* check for error exit from child process */
762  if (mutt_wait_filter(pid) != 0)
763  rc = 0;
764 
765  if ((rc == 0) || C_WaitKey)
767  return rc;
768 }
769 
776 static FILE *save_attachment_open(const char *path, enum SaveAttach opt)
777 {
778  if (opt == MUTT_SAVE_APPEND)
779  return fopen(path, "a");
780  if (opt == MUTT_SAVE_OVERWRITE)
781  return fopen(path, "w");
782 
783  return mutt_file_fopen(path, "w");
784 }
785 
796 int mutt_save_attachment(FILE *fp, struct Body *m, const char *path,
797  enum SaveAttach opt, struct Email *e)
798 {
799  if (!m)
800  return -1;
801 
802  if (fp)
803  {
804  /* recv mode */
805 
806  if (e && m->email && (m->encoding != ENC_BASE64) &&
808  {
809  /* message type attachments are written to mail folders. */
810 
811  char buf[8192];
812  struct Message *msg = NULL;
813  CopyHeaderFlags chflags = CH_NO_FLAGS;
814  int rc = -1;
815 
816  struct Email *e_new = m->email;
817  e_new->msgno = e->msgno; /* required for MH/maildir */
818  e_new->read = true;
819 
820  if (fseeko(fp, m->offset, SEEK_SET) < 0)
821  return -1;
822  if (!fgets(buf, sizeof(buf), fp))
823  return -1;
824  struct Mailbox *m_att = mx_path_resolve(path);
825  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
826  if (!ctx)
827  {
828  mailbox_free(&m_att);
829  return -1;
830  }
831  msg = mx_msg_open_new(ctx->mailbox, e_new,
832  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
833  if (!msg)
834  {
835  mx_mbox_close(&ctx);
836  return -1;
837  }
838  if ((ctx->mailbox->magic == MUTT_MBOX) || (ctx->mailbox->magic == MUTT_MMDF))
839  chflags = CH_FROM | CH_UPDATE_LEN;
840  chflags |= ((ctx->mailbox->magic == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
841  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
842  (mx_msg_commit(ctx->mailbox, msg) == 0))
843  {
844  rc = 0;
845  }
846  else
847  {
848  rc = -1;
849  }
850 
851  mx_msg_close(ctx->mailbox, &msg);
852  mx_mbox_close(&ctx);
853  return rc;
854  }
855  else
856  {
857  /* In recv mode, extract from folder and decode */
858 
859  struct State s = { 0 };
860 
861  s.fp_out = save_attachment_open(path, opt);
862  if (!s.fp_out)
863  {
864  mutt_perror("fopen");
865  return -1;
866  }
867  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
868  mutt_decode_attachment(m, &s);
869 
870  if (mutt_file_fsync_close(&s.fp_out) != 0)
871  {
872  mutt_perror("fclose");
873  return -1;
874  }
875  }
876  }
877  else
878  {
879  if (!m->filename)
880  return -1;
881 
882  /* In send mode, just copy file */
883 
884  FILE *fp_old = fopen(m->filename, "r");
885  if (!fp_old)
886  {
887  mutt_perror("fopen");
888  return -1;
889  }
890 
891  FILE *fp_new = save_attachment_open(path, opt);
892  if (!fp_new)
893  {
894  mutt_perror("fopen");
895  mutt_file_fclose(&fp_old);
896  return -1;
897  }
898 
899  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
900  {
901  mutt_error(_("Write fault"));
902  mutt_file_fclose(&fp_old);
903  mutt_file_fclose(&fp_new);
904  return -1;
905  }
906  mutt_file_fclose(&fp_old);
907  if (mutt_file_fsync_close(&fp_new) != 0)
908  {
909  mutt_error(_("Write fault"));
910  return -1;
911  }
912  }
913 
914  return 0;
915 }
916 
927 int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path,
928  int displaying, enum SaveAttach opt)
929 {
930  struct State s = { 0 };
931  unsigned int saved_encoding = 0;
932  struct Body *saved_parts = NULL;
933  struct Email *e_saved = NULL;
934  int rc = 0;
935 
936  s.flags = displaying;
937 
938  if (opt == MUTT_SAVE_APPEND)
939  s.fp_out = fopen(path, "a");
940  else if (opt == MUTT_SAVE_OVERWRITE)
941  s.fp_out = fopen(path, "w");
942  else
943  s.fp_out = mutt_file_fopen(path, "w");
944 
945  if (!s.fp_out)
946  {
947  mutt_perror("fopen");
948  return -1;
949  }
950 
951  if (!fp)
952  {
953  /* When called from the compose menu, the attachment isn't parsed,
954  * so we need to do it here. */
955  struct stat st;
956 
957  if (stat(m->filename, &st) == -1)
958  {
959  mutt_perror("stat");
961  return -1;
962  }
963 
964  s.fp_in = fopen(m->filename, "r");
965  if (!s.fp_in)
966  {
967  mutt_perror("fopen");
968  return -1;
969  }
970 
971  saved_encoding = m->encoding;
972  if (!is_multipart(m))
973  m->encoding = ENC_8BIT;
974 
975  m->length = st.st_size;
976  m->offset = 0;
977  saved_parts = m->parts;
978  e_saved = m->email;
979  mutt_parse_part(s.fp_in, m);
980 
981  if (m->noconv || is_multipart(m))
982  s.flags |= MUTT_CHARCONV;
983  }
984  else
985  {
986  s.fp_in = fp;
987  s.flags |= MUTT_CHARCONV;
988  }
989 
990  mutt_body_handler(m, &s);
991 
992  if (mutt_file_fsync_close(&s.fp_out) != 0)
993  {
994  mutt_perror("fclose");
995  rc = -1;
996  }
997  if (!fp)
998  {
999  m->length = 0;
1000  m->encoding = saved_encoding;
1001  if (saved_parts)
1002  {
1003  email_free(&m->email);
1004  m->parts = saved_parts;
1005  m->email = e_saved;
1006  }
1007  mutt_file_fclose(&s.fp_in);
1008  }
1009 
1010  return rc;
1011 }
1012 
1026 int mutt_print_attachment(FILE *fp, struct Body *a)
1027 {
1028  char type[256];
1029  pid_t pid;
1030  FILE *fp_in = NULL, *fp_out = NULL;
1031  bool unlink_newfile = false;
1032  struct Buffer *newfile = mutt_buffer_pool_get();
1033  struct Buffer *cmd = mutt_buffer_pool_get();
1034 
1035  int rc = 0;
1036 
1037  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1038 
1039  if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1040  {
1041  int piped = false;
1042 
1043  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1044 
1045  struct MailcapEntry *entry = mailcap_entry_new();
1046  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1047  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
1048  /* send mode: symlink from existing file to the newfile */
1049  if (!fp)
1050  {
1051  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1052  {
1053  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1054  goto mailcap_cleanup;
1055  mutt_buffer_strcpy(newfile, a->filename);
1056  }
1057  else
1058  unlink_newfile = true;
1059  }
1060  /* in recv mode, save file to newfile first */
1061  else
1062  {
1063  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), 0, NULL) == -1)
1064  goto mailcap_cleanup;
1065  }
1066 
1067  mutt_buffer_strcpy(cmd, entry->printcommand);
1068  piped = mailcap_expand_command(a, mutt_b2s(newfile), type, cmd);
1069 
1070  mutt_endwin();
1071 
1072  /* interactive program */
1073  if (piped)
1074  {
1075  fp_in = fopen(mutt_b2s(newfile), "r");
1076  if (!fp_in)
1077  {
1078  mutt_perror("fopen");
1079  mailcap_entry_free(&entry);
1080  goto mailcap_cleanup;
1081  }
1082 
1083  pid = mutt_create_filter(mutt_b2s(cmd), &fp_out, NULL, NULL);
1084  if (pid < 0)
1085  {
1086  mutt_perror(_("Can't create filter"));
1087  mailcap_entry_free(&entry);
1088  mutt_file_fclose(&fp_in);
1089  goto mailcap_cleanup;
1090  }
1091  mutt_file_copy_stream(fp_in, fp_out);
1092  mutt_file_fclose(&fp_out);
1093  mutt_file_fclose(&fp_in);
1094  if (mutt_wait_filter(pid) || C_WaitKey)
1096  }
1097  else
1098  {
1099  int rc2 = mutt_system(mutt_b2s(cmd));
1100  if (rc2 == -1)
1101  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1102 
1103  if ((rc2 != 0) || C_WaitKey)
1105  }
1106 
1107  rc = 1;
1108 
1109  mailcap_cleanup:
1110  if (fp)
1111  mutt_file_unlink(mutt_b2s(newfile));
1112  else if (unlink_newfile)
1113  unlink(mutt_b2s(newfile));
1114 
1115  mailcap_entry_free(&entry);
1116  goto out;
1117  }
1118 
1119  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1120  (mutt_str_strcasecmp("application/postscript", type) == 0))
1121  {
1122  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1123  goto out;
1124  }
1125  else if (mutt_can_decode(a))
1126  {
1127  /* decode and print */
1128 
1129  fp_in = NULL;
1130  fp_out = NULL;
1131 
1132  mutt_buffer_mktemp(newfile);
1133  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1134  {
1135  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1136  type, mutt_b2s(newfile));
1137 
1138  fp_in = fopen(mutt_b2s(newfile), "r");
1139  if (!fp_in)
1140  {
1141  mutt_perror("fopen");
1142  goto decode_cleanup;
1143  }
1144 
1145  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1146 
1147  mutt_endwin();
1148  pid = mutt_create_filter(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1149  if (pid < 0)
1150  {
1151  mutt_perror(_("Can't create filter"));
1152  goto decode_cleanup;
1153  }
1154 
1155  mutt_debug(LL_DEBUG2, "Filter created\n");
1156 
1157  mutt_file_copy_stream(fp_in, fp_out);
1158 
1159  mutt_file_fclose(&fp_out);
1160  mutt_file_fclose(&fp_in);
1161 
1162  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
1164  rc = 1;
1165  }
1166  decode_cleanup:
1167  mutt_file_fclose(&fp_in);
1168  mutt_file_fclose(&fp_out);
1169  mutt_file_unlink(mutt_b2s(newfile));
1170  }
1171  else
1172  {
1173  mutt_error(_("I don't know how to print that"));
1174  rc = 0;
1175  }
1176 
1177 out:
1178  mutt_buffer_pool_release(&newfile);
1180 
1181  return rc;
1182 }
1183 
1188 void mutt_add_temp_attachment(const char *filename)
1189 {
1190  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1191 }
1192 
1197 {
1198  struct ListNode *np = NULL;
1199 
1200  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1201  {
1202  mutt_file_chmod_add(np->data, S_IWUSR);
1203  mutt_file_unlink(np->data);
1204  }
1205 
1206  mutt_list_free(&TempAttachmentsList);
1207 }
#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
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: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:1795
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
#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:583
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:40
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:254
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:86
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:1196
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:796
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:1140
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:145
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:65
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:376
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
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:104
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:758
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:1009
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1188
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
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:56
#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:42
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:91
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:260
A local copy of an email.
Definition: mx.h:81
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:545
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:80
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:927
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:1754
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: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/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:578
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: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:664
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:424
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:1119
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:136
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:109
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:95
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:1603
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:1551
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
Definition: mutt_attach.c:776
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: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: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:352
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:679
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:115
#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:385
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1026