NeoMutt  2020-04-24
Teaching an old dog new tricks
DOXYGEN
mutt_attach.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38 #include <unistd.h>
39 #include "mutt/lib.h"
40 #include "config/lib.h"
41 #include "email/lib.h"
42 #include "core/lib.h"
43 #include "gui/lib.h"
44 #include "mutt_attach.h"
45 #include "context.h"
46 #include "copy.h"
47 #include "globals.h"
48 #include "handler.h"
49 #include "mailcap.h"
50 #include "muttlib.h"
51 #include "mx.h"
52 #include "options.h"
53 #include "pager.h"
54 #include "protos.h"
55 #include "sendlib.h"
56 #include "state.h"
57 #include "ncrypt/lib.h"
58 #ifdef USE_IMAP
59 #include "imap/lib.h"
60 #endif
61 
69 {
70  char type[256];
71  struct stat st;
72 
73  if (a->unlink)
74  return 0;
75 
76  struct Buffer *tmpfile = mutt_buffer_pool_get();
77  struct MailcapEntry *entry = mailcap_entry_new();
78  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
79  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS);
80  mailcap_expand_filename(entry->nametemplate, a->filename, tmpfile);
81 
82  mailcap_entry_free(&entry);
83 
84  if (stat(a->filename, &st) == -1)
85  {
86  mutt_buffer_pool_release(&tmpfile);
87  return -1;
88  }
89 
90  FILE *fp_in = NULL, *fp_out = NULL;
91  if ((fp_in = fopen(a->filename, "r")) &&
92  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
93  {
94  mutt_file_copy_stream(fp_in, fp_out);
95  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
96  a->unlink = true;
97 
98  if (a->stamp >= st.st_mtime)
100  }
101  else
102  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
103 
104  mutt_file_fclose(&fp_in);
105  mutt_file_fclose(&fp_out);
106 
107  mutt_buffer_pool_release(&tmpfile);
108 
109  return a->unlink ? 0 : -1;
110 }
111 
119 {
120  char type[256];
121  struct MailcapEntry *entry = mailcap_entry_new();
122  bool unlink_newfile = false;
123  int rc = 0;
124  struct Buffer *cmd = mutt_buffer_pool_get();
125  struct Buffer *newfile = mutt_buffer_pool_get();
126  struct Buffer *tmpfile = mutt_buffer_pool_get();
127 
128  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
129  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_COMPOSE))
130  {
131  if (entry->composecommand || entry->composetypecommand)
132  {
133  if (entry->composetypecommand)
135  else
136  mutt_buffer_strcpy(cmd, entry->composecommand);
137 
138  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
139  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
140  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
141  {
142  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
143  goto bailout;
144  mutt_buffer_strcpy(newfile, a->filename);
145  }
146  else
147  unlink_newfile = true;
148 
149  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
150  {
151  /* For now, editing requires a file, no piping */
152  mutt_error(_("Mailcap compose entry requires %%s"));
153  }
154  else
155  {
156  int r;
157 
158  mutt_endwin();
159  r = mutt_system(mutt_b2s(cmd));
160  if (r == -1)
161  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
162 
163  if ((r != -1) && entry->composetypecommand)
164  {
165  struct Body *b = NULL;
166 
167  FILE *fp = mutt_file_fopen(a->filename, "r");
168  if (!fp)
169  {
170  mutt_perror(_("Failure to open file to parse headers"));
171  goto bailout;
172  }
173 
174  b = mutt_read_mime_header(fp, 0);
175  if (b)
176  {
177  if (!TAILQ_EMPTY(&b->parameter))
178  {
180  a->parameter = b->parameter;
181  TAILQ_INIT(&b->parameter);
182  }
183  if (b->description)
184  {
185  FREE(&a->description);
186  a->description = b->description;
187  b->description = NULL;
188  }
189  if (b->form_name)
190  {
191  FREE(&a->form_name);
192  a->form_name = b->form_name;
193  b->form_name = NULL;
194  }
195 
196  /* Remove headers by copying out data to another file, then
197  * copying the file back */
198  fseeko(fp, b->offset, SEEK_SET);
199  mutt_body_free(&b);
200  mutt_buffer_mktemp(tmpfile);
201  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpfile), "w");
202  if (!fp_tmp)
203  {
204  mutt_perror(_("Failure to open file to strip headers"));
205  mutt_file_fclose(&fp);
206  goto bailout;
207  }
208  mutt_file_copy_stream(fp, fp_tmp);
209  mutt_file_fclose(&fp);
210  mutt_file_fclose(&fp_tmp);
212  if (mutt_file_rename(mutt_b2s(tmpfile), a->filename) != 0)
213  {
214  mutt_perror(_("Failure to rename file"));
215  goto bailout;
216  }
217  }
218  }
219  }
220  }
221  }
222  else
223  {
224  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
225  rc = 1;
226  goto bailout;
227  }
228 
229  rc = 1;
230 
231 bailout:
232 
233  if (unlink_newfile)
234  unlink(mutt_b2s(newfile));
235 
237  mutt_buffer_pool_release(&newfile);
238  mutt_buffer_pool_release(&tmpfile);
239 
240  mailcap_entry_free(&entry);
241  return rc;
242 }
243 
258 {
259  char type[256];
260  struct MailcapEntry *entry = mailcap_entry_new();
261  bool unlink_newfile = false;
262  int rc = 0;
263  struct Buffer *cmd = mutt_buffer_pool_get();
264  struct Buffer *newfile = mutt_buffer_pool_get();
265 
266  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
267  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_EDIT))
268  {
269  if (entry->editcommand)
270  {
271  mutt_buffer_strcpy(cmd, entry->editcommand);
272  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
273  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
274  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
275  {
276  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
277  goto bailout;
278  mutt_buffer_strcpy(newfile, a->filename);
279  }
280  else
281  unlink_newfile = true;
282 
283  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
284  {
285  /* For now, editing requires a file, no piping */
286  mutt_error(_("Mailcap Edit entry requires %%s"));
287  goto bailout;
288  }
289  else
290  {
291  mutt_endwin();
292  if (mutt_system(mutt_b2s(cmd)) == -1)
293  {
294  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
295  goto bailout;
296  }
297  }
298  }
299  }
300  else if (a->type == TYPE_TEXT)
301  {
302  /* On text, default to editor */
304  }
305  else
306  {
307  mutt_error(_("No mailcap edit entry for %s"), type);
308  rc = 0;
309  goto bailout;
310  }
311 
312  rc = 1;
313 
314 bailout:
315 
316  if (unlink_newfile)
317  unlink(mutt_b2s(newfile));
318 
320  mutt_buffer_pool_release(&newfile);
321 
322  mailcap_entry_free(&entry);
323  return rc;
324 }
325 
332 void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
333 {
334  struct ListNode *np = NULL;
335  STAILQ_FOREACH(np, &MimeLookupList, entries)
336  {
337  const int i = mutt_str_strlen(np->data) - 1;
338  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
339  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
340  (mutt_str_strcasecmp(type, np->data) == 0))
341  {
342  struct Body tmp = { 0 };
343  enum ContentType n;
344  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
345  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
346  {
347  snprintf(type, len, "%s/%s",
348  (n == TYPE_AUDIO) ?
349  "audio" :
350  (n == TYPE_APPLICATION) ?
351  "application" :
352  (n == TYPE_IMAGE) ?
353  "image" :
354  (n == TYPE_MESSAGE) ?
355  "message" :
356  (n == TYPE_MODEL) ?
357  "model" :
358  (n == TYPE_MULTIPART) ?
359  "multipart" :
360  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
361  tmp.subtype);
362  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
363  }
364  FREE(&tmp.subtype);
365  FREE(&tmp.xtype);
366  }
367  }
368 }
369 
383 static int wait_interactive_filter(pid_t pid)
384 {
385  int rc;
386 
387 #ifdef USE_IMAP
388  rc = imap_wait_keepalive(pid);
389 #else
390  waitpid(pid, &rc, 0);
391 #endif
393  rc = WIFEXITED(rc) ? WEXITSTATUS(rc) : -1;
394 
395  return rc;
396 }
415 int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode,
416  struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
417 {
418  bool use_mailcap = false;
419  bool use_pipe = false;
420  bool use_pager = true;
421  char type[256];
422  char desc[256];
423  char *fname = NULL;
424  struct MailcapEntry *entry = NULL;
425  int rc = -1;
426  bool unlink_tempfile = false;
427 
428  bool is_message = mutt_is_message_type(a->type, a->subtype);
429  if ((WithCrypto != 0) && is_message && a->email &&
431  {
432  return rc;
433  }
434 
435  struct Buffer *tmpfile = mutt_buffer_pool_get();
436  struct Buffer *pagerfile = mutt_buffer_pool_get();
437  struct Buffer *cmd = mutt_buffer_pool_get();
438 
439  use_mailcap =
440  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
441  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
442 
443  char columns[16];
444  snprintf(columns, sizeof(columns), "%d", win->state.cols);
445  mutt_envlist_set("COLUMNS", columns, true);
446 
447  if (use_mailcap)
448  {
449  entry = mailcap_entry_new();
450  if (!mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS))
451  {
452  if (mode == MUTT_VA_REGULAR)
453  {
454  /* fallback to view as text */
455  mailcap_entry_free(&entry);
456  mutt_error(_("No matching mailcap entry found. Viewing as text."));
457  mode = MUTT_VA_AS_TEXT;
458  use_mailcap = false;
459  }
460  else
461  goto return_error;
462  }
463  }
464 
465  if (use_mailcap)
466  {
467  if (!entry->command)
468  {
469  mutt_error(_("MIME type not defined. Can't view attachment."));
470  goto return_error;
471  }
472  mutt_buffer_strcpy(cmd, entry->command);
473 
474  if (fp)
475  {
476  fname = mutt_str_strdup(a->filename);
477  mutt_file_sanitize_filename(fname, true);
478  }
479  else
480  fname = a->filename;
481 
482  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
483  /* send case: the file is already there; symlink to it */
484  if (!fp)
485  {
486  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
487  {
488  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
489  goto return_error;
490  mutt_buffer_strcpy(tmpfile, a->filename);
491  }
492  else
493  unlink_tempfile = true;
494  }
495  /* recv case: we need to save the attachment to a file */
496  else
497  {
498  FREE(&fname);
499  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
500  goto return_error;
501  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
502  }
503 
504  use_pipe = mailcap_expand_command(a, mutt_b2s(tmpfile), type, cmd);
505  use_pager = entry->copiousoutput;
506  }
507 
508  if (use_pager)
509  {
510  if (fp && !use_mailcap && a->filename)
511  {
512  /* recv case */
513  mutt_buffer_strcpy(pagerfile, a->filename);
514  mutt_adv_mktemp(pagerfile);
515  }
516  else
517  mutt_buffer_mktemp(pagerfile);
518  }
519 
520  if (use_mailcap)
521  {
522  pid_t pid = 0;
523  int fd_temp = -1, fd_pager = -1;
524 
525  if (!use_pager)
526  mutt_endwin();
527 
528  if (use_pager || use_pipe)
529  {
530  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
531  O_CREAT | O_EXCL | O_WRONLY)) == -1))
532  {
533  mutt_perror("open");
534  goto return_error;
535  }
536  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
537  {
538  if (fd_pager != -1)
539  close(fd_pager);
540  mutt_perror("open");
541  goto return_error;
542  }
543 
544  pid = filter_create_fd(mutt_b2s(cmd), NULL, NULL, NULL,
545  use_pipe ? fd_temp : -1, use_pager ? fd_pager : -1, -1);
546 
547  if (pid == -1)
548  {
549  if (fd_pager != -1)
550  close(fd_pager);
551 
552  if (fd_temp != -1)
553  close(fd_temp);
554 
555  mutt_error(_("Can't create filter"));
556  goto return_error;
557  }
558 
559  if (use_pager)
560  {
561  if (a->description)
562  {
563  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
564  mutt_b2s(cmd), a->description);
565  }
566  else
567  {
568  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
569  mutt_b2s(cmd), type);
570  }
571  filter_wait(pid);
572  }
573  else
574  {
575  if (wait_interactive_filter(pid) || (entry->needsterminal && C_WaitKey))
577  }
578 
579  if (fd_temp != -1)
580  close(fd_temp);
581  if (fd_pager != -1)
582  close(fd_pager);
583  }
584  else
585  {
586  /* interactive cmd */
587  int rv = mutt_system(mutt_b2s(cmd));
588  if (rv == -1)
589  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
590 
591  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
593  }
594  }
595  else
596  {
597  /* Don't use mailcap; the attachment is viewed in the pager */
598 
599  if (mode == MUTT_VA_AS_TEXT)
600  {
601  /* just let me see the raw data */
602  if (fp)
603  {
604  /* Viewing from a received message.
605  *
606  * Don't use mutt_save_attachment() because we want to perform charset
607  * conversion since this will be displayed by the internal pager. */
608  struct State decode_state = { 0 };
609 
610  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
611  if (!decode_state.fp_out)
612  {
613  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
614  mutt_b2s(pagerfile), errno, strerror(errno));
615  mutt_perror(mutt_b2s(pagerfile));
616  goto return_error;
617  }
618  decode_state.fp_in = fp;
619  decode_state.flags = MUTT_CHARCONV;
620  mutt_decode_attachment(a, &decode_state);
621  if (mutt_file_fclose(&decode_state.fp_out) == EOF)
622  {
623  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
624  errno, strerror(errno));
625  }
626  }
627  else
628  {
629  /* in compose mode, just copy the file. we can't use
630  * mutt_decode_attachment() since it assumes the content-encoding has
631  * already been applied */
632  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
633  goto return_error;
634  }
635  }
636  else
637  {
638  /* Use built-in handler */
639  OptViewAttach = true; /* disable the "use 'v' to view this part"
640  * message in case of error */
642  {
643  OptViewAttach = false;
644  goto return_error;
645  }
646  OptViewAttach = false;
647  }
648 
649  if (a->description)
650  mutt_str_strfcpy(desc, a->description, sizeof(desc));
651  else if (a->filename)
652  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
653  else
654  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
655  }
656 
657  /* We only reach this point if there have been no errors */
658 
659  if (use_pager)
660  {
661  struct Pager info = { 0 };
662  info.fp = fp;
663  info.body = a;
664  info.ctx = Context;
665  info.actx = actx;
666  info.email = e;
667 
668  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
670  &info);
671  mutt_buffer_reset(pagerfile);
672  }
673  else
674  rc = 0;
675 
676 return_error:
677 
678  if (!entry || !entry->xneomuttkeep)
679  {
680  if (fp && !mutt_buffer_is_empty(tmpfile))
681  {
682  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
684  }
685  else if (unlink_tempfile)
686  {
687  unlink(mutt_b2s(tmpfile));
688  }
689  }
690 
691  mailcap_entry_free(&entry);
692 
693  if (!mutt_buffer_is_empty(pagerfile))
694  mutt_file_unlink(mutt_b2s(pagerfile));
695 
696  mutt_buffer_pool_release(&tmpfile);
697  mutt_buffer_pool_release(&pagerfile);
699  mutt_envlist_unset("COLUMNS");
700 
701  return rc;
702 }
703 
713 int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
714 {
715  pid_t pid;
716  int out = -1;
717  int rc = 0;
718 
719  if (outfile && *outfile)
720  {
721  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
722  if (out < 0)
723  {
724  mutt_perror("open");
725  return 0;
726  }
727  }
728 
729  mutt_endwin();
730 
731  if (fp)
732  {
733  /* recv case */
734 
735  struct State s = { 0 };
736 
737  /* perform charset conversion on text attachments when piping */
738  s.flags = MUTT_CHARCONV;
739 
740  if (outfile && *outfile)
741  pid = filter_create_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
742  else
743  pid = filter_create(path, &s.fp_out, NULL, NULL);
744 
745  if (pid < 0)
746  {
747  mutt_perror(_("Can't create filter"));
748  goto bail;
749  }
750 
751  s.fp_in = fp;
752  mutt_decode_attachment(b, &s);
754  }
755  else
756  {
757  /* send case */
758  FILE *fp_in = fopen(b->filename, "r");
759  if (!fp_in)
760  {
761  mutt_perror("fopen");
762  if (outfile && *outfile)
763  {
764  close(out);
765  unlink(outfile);
766  }
767  return 0;
768  }
769 
770  FILE *fp_out = NULL;
771  if (outfile && *outfile)
772  pid = filter_create_fd(path, &fp_out, NULL, NULL, -1, out, -1);
773  else
774  pid = filter_create(path, &fp_out, NULL, NULL);
775 
776  if (pid < 0)
777  {
778  mutt_perror(_("Can't create filter"));
779  mutt_file_fclose(&fp_in);
780  goto bail;
781  }
782 
783  mutt_file_copy_stream(fp_in, fp_out);
784  mutt_file_fclose(&fp_out);
785  mutt_file_fclose(&fp_in);
786  }
787 
788  rc = 1;
789 
790 bail:
791 
792  if (outfile && *outfile)
793  close(out);
794 
795  /* check for error exit from child process */
796  if (filter_wait(pid) != 0)
797  rc = 0;
798 
799  if ((rc == 0) || C_WaitKey)
801  return rc;
802 }
803 
810 static FILE *save_attachment_open(const char *path, enum SaveAttach opt)
811 {
812  if (opt == MUTT_SAVE_APPEND)
813  return fopen(path, "a");
814  if (opt == MUTT_SAVE_OVERWRITE)
815  return fopen(path, "w");
816 
817  return mutt_file_fopen(path, "w");
818 }
819 
830 int mutt_save_attachment(FILE *fp, struct Body *m, const char *path,
831  enum SaveAttach opt, struct Email *e)
832 {
833  if (!m)
834  return -1;
835 
836  if (fp)
837  {
838  /* recv mode */
839 
840  if (e && m->email && (m->encoding != ENC_BASE64) &&
842  {
843  /* message type attachments are written to mail folders. */
844 
845  char buf[8192];
846  struct Message *msg = NULL;
847  CopyHeaderFlags chflags = CH_NO_FLAGS;
848  int rc = -1;
849 
850  struct Email *e_new = m->email;
851  e_new->msgno = e->msgno; /* required for MH/maildir */
852  e_new->read = true;
853 
854  if (fseeko(fp, m->offset, SEEK_SET) < 0)
855  return -1;
856  if (!fgets(buf, sizeof(buf), fp))
857  return -1;
858  struct Mailbox *m_att = mx_path_resolve(path);
859  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
860  if (!ctx)
861  {
862  mailbox_free(&m_att);
863  return -1;
864  }
865  msg = mx_msg_open_new(ctx->mailbox, e_new,
866  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
867  if (!msg)
868  {
869  mx_mbox_close(&ctx);
870  return -1;
871  }
872  if ((ctx->mailbox->type == MUTT_MBOX) || (ctx->mailbox->type == MUTT_MMDF))
873  chflags = CH_FROM | CH_UPDATE_LEN;
874  chflags |= ((ctx->mailbox->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
875  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
876  (mx_msg_commit(ctx->mailbox, msg) == 0))
877  {
878  rc = 0;
879  }
880  else
881  {
882  rc = -1;
883  }
884 
885  mx_msg_close(ctx->mailbox, &msg);
886  mx_mbox_close(&ctx);
887  return rc;
888  }
889  else
890  {
891  /* In recv mode, extract from folder and decode */
892 
893  struct State s = { 0 };
894 
895  s.fp_out = save_attachment_open(path, opt);
896  if (!s.fp_out)
897  {
898  mutt_perror("fopen");
899  return -1;
900  }
901  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
902  mutt_decode_attachment(m, &s);
903 
904  if (mutt_file_fsync_close(&s.fp_out) != 0)
905  {
906  mutt_perror("fclose");
907  return -1;
908  }
909  }
910  }
911  else
912  {
913  if (!m->filename)
914  return -1;
915 
916  /* In send mode, just copy file */
917 
918  FILE *fp_old = fopen(m->filename, "r");
919  if (!fp_old)
920  {
921  mutt_perror("fopen");
922  return -1;
923  }
924 
925  FILE *fp_new = save_attachment_open(path, opt);
926  if (!fp_new)
927  {
928  mutt_perror("fopen");
929  mutt_file_fclose(&fp_old);
930  return -1;
931  }
932 
933  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
934  {
935  mutt_error(_("Write fault"));
936  mutt_file_fclose(&fp_old);
937  mutt_file_fclose(&fp_new);
938  return -1;
939  }
940  mutt_file_fclose(&fp_old);
941  if (mutt_file_fsync_close(&fp_new) != 0)
942  {
943  mutt_error(_("Write fault"));
944  return -1;
945  }
946  }
947 
948  return 0;
949 }
950 
961 int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path,
962  int displaying, enum SaveAttach opt)
963 {
964  struct State s = { 0 };
965  unsigned int saved_encoding = 0;
966  struct Body *saved_parts = NULL;
967  struct Email *e_saved = NULL;
968  int rc = 0;
969 
970  s.flags = displaying;
971 
972  if (opt == MUTT_SAVE_APPEND)
973  s.fp_out = fopen(path, "a");
974  else if (opt == MUTT_SAVE_OVERWRITE)
975  s.fp_out = fopen(path, "w");
976  else
977  s.fp_out = mutt_file_fopen(path, "w");
978 
979  if (!s.fp_out)
980  {
981  mutt_perror("fopen");
982  return -1;
983  }
984 
985  if (!fp)
986  {
987  /* When called from the compose menu, the attachment isn't parsed,
988  * so we need to do it here. */
989  struct stat st;
990 
991  if (stat(m->filename, &st) == -1)
992  {
993  mutt_perror("stat");
995  return -1;
996  }
997 
998  s.fp_in = fopen(m->filename, "r");
999  if (!s.fp_in)
1000  {
1001  mutt_perror("fopen");
1002  return -1;
1003  }
1004 
1005  saved_encoding = m->encoding;
1006  if (!is_multipart(m))
1007  m->encoding = ENC_8BIT;
1008 
1009  m->length = st.st_size;
1010  m->offset = 0;
1011  saved_parts = m->parts;
1012  e_saved = m->email;
1013  mutt_parse_part(s.fp_in, m);
1014 
1015  if (m->noconv || is_multipart(m))
1016  s.flags |= MUTT_CHARCONV;
1017  }
1018  else
1019  {
1020  s.fp_in = fp;
1021  s.flags |= MUTT_CHARCONV;
1022  }
1023 
1024  mutt_body_handler(m, &s);
1025 
1026  if (mutt_file_fsync_close(&s.fp_out) != 0)
1027  {
1028  mutt_perror("fclose");
1029  rc = -1;
1030  }
1031  if (!fp)
1032  {
1033  m->length = 0;
1034  m->encoding = saved_encoding;
1035  if (saved_parts)
1036  {
1037  email_free(&m->email);
1038  m->parts = saved_parts;
1039  m->email = e_saved;
1040  }
1041  mutt_file_fclose(&s.fp_in);
1042  }
1043 
1044  return rc;
1045 }
1046 
1060 int mutt_print_attachment(FILE *fp, struct Body *a)
1061 {
1062  char type[256];
1063  pid_t pid;
1064  FILE *fp_in = NULL, *fp_out = NULL;
1065  bool unlink_newfile = false;
1066  struct Buffer *newfile = mutt_buffer_pool_get();
1067  struct Buffer *cmd = mutt_buffer_pool_get();
1068 
1069  int rc = 0;
1070 
1071  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1072 
1073  if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1074  {
1075  int piped = false;
1076 
1077  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1078 
1079  struct MailcapEntry *entry = mailcap_entry_new();
1080  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1081  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
1082  /* send mode: symlink from existing file to the newfile */
1083  if (!fp)
1084  {
1085  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1086  {
1087  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1088  goto mailcap_cleanup;
1089  mutt_buffer_strcpy(newfile, a->filename);
1090  }
1091  else
1092  unlink_newfile = true;
1093  }
1094  /* in recv mode, save file to newfile first */
1095  else
1096  {
1097  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), 0, NULL) == -1)
1098  goto mailcap_cleanup;
1099  }
1100 
1101  mutt_buffer_strcpy(cmd, entry->printcommand);
1102  piped = mailcap_expand_command(a, mutt_b2s(newfile), type, cmd);
1103 
1104  mutt_endwin();
1105 
1106  /* interactive program */
1107  if (piped)
1108  {
1109  fp_in = fopen(mutt_b2s(newfile), "r");
1110  if (!fp_in)
1111  {
1112  mutt_perror("fopen");
1113  mailcap_entry_free(&entry);
1114  goto mailcap_cleanup;
1115  }
1116 
1117  pid = filter_create(mutt_b2s(cmd), &fp_out, NULL, NULL);
1118  if (pid < 0)
1119  {
1120  mutt_perror(_("Can't create filter"));
1121  mailcap_entry_free(&entry);
1122  mutt_file_fclose(&fp_in);
1123  goto mailcap_cleanup;
1124  }
1125  mutt_file_copy_stream(fp_in, fp_out);
1126  mutt_file_fclose(&fp_out);
1127  mutt_file_fclose(&fp_in);
1128  if (filter_wait(pid) || C_WaitKey)
1130  }
1131  else
1132  {
1133  int rc2 = mutt_system(mutt_b2s(cmd));
1134  if (rc2 == -1)
1135  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1136 
1137  if ((rc2 != 0) || C_WaitKey)
1139  }
1140 
1141  rc = 1;
1142 
1143  mailcap_cleanup:
1144  if (fp)
1145  mutt_file_unlink(mutt_b2s(newfile));
1146  else if (unlink_newfile)
1147  unlink(mutt_b2s(newfile));
1148 
1149  mailcap_entry_free(&entry);
1150  goto out;
1151  }
1152 
1153  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1154  (mutt_str_strcasecmp("application/postscript", type) == 0))
1155  {
1156  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1157  goto out;
1158  }
1159  else if (mutt_can_decode(a))
1160  {
1161  /* decode and print */
1162 
1163  fp_in = NULL;
1164  fp_out = NULL;
1165 
1166  mutt_buffer_mktemp(newfile);
1167  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1168  {
1169  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1170  type, mutt_b2s(newfile));
1171 
1172  fp_in = fopen(mutt_b2s(newfile), "r");
1173  if (!fp_in)
1174  {
1175  mutt_perror("fopen");
1176  goto decode_cleanup;
1177  }
1178 
1179  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1180 
1181  mutt_endwin();
1182  pid = filter_create(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1183  if (pid < 0)
1184  {
1185  mutt_perror(_("Can't create filter"));
1186  goto decode_cleanup;
1187  }
1188 
1189  mutt_debug(LL_DEBUG2, "Filter created\n");
1190 
1191  mutt_file_copy_stream(fp_in, fp_out);
1192 
1193  mutt_file_fclose(&fp_out);
1194  mutt_file_fclose(&fp_in);
1195 
1196  if ((filter_wait(pid) != 0) || C_WaitKey)
1198  rc = 1;
1199  }
1200  decode_cleanup:
1201  mutt_file_fclose(&fp_in);
1202  mutt_file_fclose(&fp_out);
1203  mutt_file_unlink(mutt_b2s(newfile));
1204  }
1205  else
1206  {
1207  mutt_error(_("I don't know how to print that"));
1208  rc = 0;
1209  }
1210 
1211 out:
1212  mutt_buffer_pool_release(&newfile);
1214 
1215  return rc;
1216 }
1217 
1222 void mutt_add_temp_attachment(const char *filename)
1223 {
1224  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1225 }
1226 
1231 {
1232  struct ListNode *np = NULL;
1233 
1234  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1235  {
1236  mutt_file_chmod_add(np->data, S_IWUSR);
1237  mutt_file_unlink(np->data);
1238  }
1239 
1240  mutt_list_free(&TempAttachmentsList);
1241 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:54
Convenience wrapper for the gui headers.
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:50
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:65
A mailcap entry.
Definition: mailcap.h:38
The "current" mailbox.
Definition: context.h:37
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1803
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:1443
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:81
Unknown Content-Type.
Definition: mime.h:31
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define WithCrypto
Definition: lib.h:163
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1392
IMAP network mailbox.
The envelope/body of an email.
Definition: email.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
#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:593
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:169
#define mutt_message(...)
Definition: logging.h:83
#define MUTT_PAGER_MESSAGE
Definition: pager.h:58
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1341
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:125
No flags set.
Definition: mutt_attach.h:55
char * composetypecommand
Definition: mailcap.h:43
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
RFC1524 Mailcap routines.
int mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:257
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:255
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:88
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:692
#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:1230
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:830
An email being displayed.
Definition: pager.h:65
View using default method.
Definition: mutt_attach.h:42
char * form_name
Content-Disposition form-data name param.
Definition: body.h:41
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
FILE * fp_in
File to read from.
Definition: state.h:46
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c: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:1171
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:146
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:68
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:377
struct Mailbox * mailbox
Definition: context.h:51
Type: &#39;video/*&#39;.
Definition: mime.h:39
Log at debug level 2.
Definition: logging.h:41
API for mailboxes.
Mailcap print field.
Definition: mailcap.h:61
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
bool copiousoutput
needs pager, basically
Definition: mailcap.h:49
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:207
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
Convenience wrapper for the core headers.
#define TAILQ_INIT(head)
Definition: queue.h:758
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
static int wait_interactive_filter(pid_t pid)
Wait after an interactive filter.
Definition: mutt_attach.c:383
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:1036
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1036
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1222
Base-64 encoded text.
Definition: mime.h:52
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
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:618
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
#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:682
WHERE struct Context * Context
Definition: globals.h:42
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:93
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:257
A local copy of an email.
Definition: mx.h:83
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:546
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:81
bool mutt_envlist_unset(const char *name)
Unset an environment variable.
Definition: envlist.c:132
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c: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:961
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:1762
struct AttachCtx * actx
Attachment information.
Definition: pager.h:71
char * data
Pointer to data.
Definition: buffer.h:35
char * xtype
content-type if x-unknown
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
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:776
API for encryption/signing of emails.
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
Handling of email attachments.
int imap_wait_keepalive(pid_t pid)
Wait for a process to change state.
Definition: util.c:1117
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:56
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
Force viewing using mailcap entry.
Definition: mutt_attach.h:43
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:455
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:48
Type: &#39;message/*&#39;.
Definition: mime.h:35
char * printcommand
Definition: mailcap.h:45
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:579
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:1407
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:522
Log at debug level 1.
Definition: logging.h:40
int n
Definition: acutest.h:492
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:332
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:665
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:1119
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
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:409
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:1150
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:654
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:111
FILE * fp
pointer to the message data
Definition: mx.h:85
Append to existing file.
Definition: mutt_attach.h:56
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:94
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:1655
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:1061
WHERE bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:56
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:810
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:299
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
A List node for strings.
Definition: list.h:33
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:66
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Decide how to display email content.
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
struct Email * email
header information for message/rfc822
Definition: body.h:55
A set of attachments.
Definition: attach.h:49
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:353
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:713
bool needsterminal
endwin() and system
Definition: mailcap.h:48
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
Type: &#39;application/*&#39;.
Definition: mime.h:33
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1293
int mutt_compose_attachment(struct Body *a)
Create an attachment.
Definition: mutt_attach.c:118
#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:415
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1060