NeoMutt  2022-04-29-247-gc6aae8
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 "lib.h"
46#include "ncrypt/lib.h"
47#include "pager/lib.h"
48#include "question/lib.h"
49#include "send/lib.h"
50#include "cid.h"
51#include "copy.h"
52#include "handler.h"
53#include "mailcap.h"
54#include "mutt_globals.h"
55#include "muttlib.h"
56#include "mx.h"
57#include "protos.h"
58#include "rfc3676.h"
59#ifdef USE_IMAP
60#include "imap/lib.h"
61#endif
62
70{
71 char type[256] = { 0 };
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);
81
82 mailcap_entry_free(&entry);
83
84 FILE *fp_in = NULL, *fp_out = NULL;
85 if ((fp_in = fopen(a->filename, "r")) &&
86 (fp_out = mutt_file_fopen(mutt_buffer_string(tmpfile), "w")))
87 {
88 mutt_file_copy_stream(fp_in, fp_out);
90 a->unlink = true;
91
92 struct stat st = { 0 };
93 if ((fstat(fileno(fp_in), &st) == 0) && (a->stamp >= st.st_mtime))
94 {
96 }
97 }
98 else
99 mutt_perror(fp_in ? mutt_buffer_string(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] = { 0 };
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
134
135 mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
136 mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", a->filename,
137 mutt_buffer_string(newfile));
138 if (mutt_file_symlink(a->filename, mutt_buffer_string(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_buffer_string(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();
158 if (r == -1)
159 mutt_error(_("Error running \"%s\""), mutt_buffer_string(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;
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 const LOFF_T offset = b->offset;
197 mutt_body_free(&b);
198 if (!mutt_file_seek(fp, offset, SEEK_SET))
199 {
200 goto bailout;
201 }
202
203 mutt_buffer_mktemp(tmpfile);
204 FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tmpfile), "w");
205 if (!fp_tmp)
206 {
207 mutt_perror(_("Failure to open file to strip headers"));
208 mutt_file_fclose(&fp);
209 goto bailout;
210 }
211 mutt_file_copy_stream(fp, fp_tmp);
212 mutt_file_fclose(&fp);
213 mutt_file_fclose(&fp_tmp);
215 if (mutt_file_rename(mutt_buffer_string(tmpfile), a->filename) != 0)
216 {
217 mutt_perror(_("Failure to rename file"));
218 goto bailout;
219 }
220 }
221 }
222 }
223 }
224 }
225 else
226 {
227 mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
228 rc = 1;
229 goto bailout;
230 }
231
232 rc = 1;
233
234bailout:
235
236 if (unlink_newfile)
237 unlink(mutt_buffer_string(newfile));
238
240 mutt_buffer_pool_release(&newfile);
241 mutt_buffer_pool_release(&tmpfile);
242
243 mailcap_entry_free(&entry);
244 return rc;
245}
246
261{
262 char type[256] = { 0 };
263 struct MailcapEntry *entry = mailcap_entry_new();
264 bool unlink_newfile = false;
265 bool rc = false;
266 struct Buffer *cmd = mutt_buffer_pool_get();
267 struct Buffer *newfile = mutt_buffer_pool_get();
268
269 snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
270 if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_EDIT))
271 {
272 if (entry->editcommand)
273 {
274 mutt_buffer_strcpy(cmd, entry->editcommand);
275 mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
276 mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", a->filename,
277 mutt_buffer_string(newfile));
278 if (mutt_file_symlink(a->filename, mutt_buffer_string(newfile)) == -1)
279 {
280 if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
281 goto bailout;
282 mutt_buffer_strcpy(newfile, a->filename);
283 }
284 else
285 unlink_newfile = true;
286
287 if (mailcap_expand_command(a, mutt_buffer_string(newfile), type, cmd))
288 {
289 /* For now, editing requires a file, no piping */
290 mutt_error(_("Mailcap Edit entry requires %%s"));
291 goto bailout;
292 }
293 else
294 {
295 mutt_endwin();
296 if (mutt_system(mutt_buffer_string(cmd)) == -1)
297 {
298 mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
299 goto bailout;
300 }
301 }
302 }
303 }
304 else if (a->type == TYPE_TEXT)
305 {
306 /* On text, default to editor */
307 const char *const c_editor = cs_subset_string(NeoMutt->sub, "editor");
308 mutt_edit_file(NONULL(c_editor), a->filename);
309 }
310 else
311 {
312 mutt_error(_("No mailcap edit entry for %s"), type);
313 goto bailout;
314 }
315
316 rc = true;
317
318bailout:
319
320 if (unlink_newfile)
321 unlink(mutt_buffer_string(newfile));
322
324 mutt_buffer_pool_release(&newfile);
325
326 mailcap_entry_free(&entry);
327 return rc;
328}
329
336void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
337{
338 struct ListNode *np = NULL;
339 STAILQ_FOREACH(np, &MimeLookupList, entries)
340 {
341 const int i = mutt_str_len(np->data) - 1;
342 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
343 mutt_istrn_equal(type, np->data, i)) ||
344 mutt_istr_equal(type, np->data))
345 {
346 struct Body tmp = { 0 };
347 enum ContentType n;
348 if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
350 {
351 snprintf(type, len, "%s/%s",
352 (n == TYPE_AUDIO) ? "audio" :
353 (n == TYPE_APPLICATION) ? "application" :
354 (n == TYPE_IMAGE) ? "image" :
355 (n == TYPE_MESSAGE) ? "message" :
356 (n == TYPE_MODEL) ? "model" :
357 (n == TYPE_MULTIPART) ? "multipart" :
358 (n == TYPE_TEXT) ? "text" :
359 (n == TYPE_VIDEO) ? "video" :
360 "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
383static 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}
397
416int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode,
417 struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
418{
419 bool use_mailcap = false;
420 bool use_pipe = false;
421 bool use_pager = true;
422 char type[256] = { 0 };
423 char desc[256] = { 0 };
424 char *fname = NULL;
425 struct MailcapEntry *entry = NULL;
426 int rc = -1;
427 bool has_tempfile = false;
428 bool unlink_pagerfile = false;
429
430 bool is_message = mutt_is_message_type(a->type, a->subtype);
431 if ((WithCrypto != 0) && is_message && a->email &&
433 {
434 return rc;
435 }
436
437 struct Buffer *tmpfile = mutt_buffer_pool_get();
438 struct Buffer *pagerfile = mutt_buffer_pool_get();
439 struct Buffer *cmd = mutt_buffer_pool_get();
440
441 use_mailcap = ((mode == MUTT_VA_MAILCAP) ||
442 ((mode == MUTT_VA_REGULAR) && mutt_needs_mailcap(a)) ||
443 (mode == MUTT_VA_PAGER));
444 snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
445
446 char columns[16] = { 0 };
447 snprintf(columns, sizeof(columns), "%d", win->state.cols);
448 mutt_envlist_set("COLUMNS", columns, true);
449
450 if (use_mailcap)
451 {
452 entry = mailcap_entry_new();
453 enum MailcapLookup mailcap_opt = (mode == MUTT_VA_PAGER) ? MUTT_MC_AUTOVIEW : MUTT_MC_NO_FLAGS;
454 if (!mailcap_lookup(a, type, sizeof(type), entry, mailcap_opt))
455 {
456 if ((mode == MUTT_VA_REGULAR) || (mode == MUTT_VA_PAGER))
457 {
458 /* fallback to view as text */
459 mailcap_entry_free(&entry);
460 mutt_error(_("No matching mailcap entry found. Viewing as text."));
461 mode = MUTT_VA_AS_TEXT;
462 use_mailcap = false;
463 }
464 else
465 goto return_error;
466 }
467 }
468
469 if (use_mailcap)
470 {
471 if (!entry->command)
472 {
473 mutt_error(_("MIME type not defined. Can't view attachment."));
474 goto return_error;
475 }
476 mutt_buffer_strcpy(cmd, entry->command);
477
478 fname = mutt_str_dup(a->filename);
479 /* In send mode(!fp), we allow slashes because those are part of
480 * the tmpfile. The path will be removed in expand_filename */
481 mutt_file_sanitize_filename(fname, fp ? true : false);
482 mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
483 FREE(&fname);
484
485 if (mutt_save_attachment(fp, a, mutt_buffer_string(tmpfile), 0, NULL) == -1)
486 goto return_error;
487 has_tempfile = true;
488
490
491 /* check for multipart/related and save attachments with a Content-ID */
492 if (mutt_str_equal(type, "text/html"))
493 {
494 struct Body *related_ancestor = NULL;
495 if (actx->body_idx && (WithCrypto != 0) && (e->security & SEC_ENCRYPT))
496 related_ancestor = attach_body_ancestor(actx->body_idx[0], a, "related");
497 else
498 related_ancestor = attach_body_ancestor(e->body, a, "related");
499 if (related_ancestor)
500 {
501 struct CidMapList cid_map_list = STAILQ_HEAD_INITIALIZER(cid_map_list);
502 mutt_debug(LL_DEBUG2, "viewing text/html attachment in multipart/related group\n");
503 /* save attachments and build cid_map_list Content-ID to filename mapping list */
504 cid_save_attachments(related_ancestor->parts, &cid_map_list);
505 /* replace Content-IDs with filenames */
506 cid_to_filename(tmpfile, &cid_map_list);
507 /* empty Content-ID to filename mapping list */
508 cid_map_list_clear(&cid_map_list);
509 }
510 }
511
512 use_pipe = mailcap_expand_command(a, mutt_buffer_string(tmpfile), type, cmd);
513 use_pager = entry->copiousoutput;
514 }
515
516 if (use_pager)
517 {
518 if (fp && !use_mailcap && a->filename)
519 {
520 /* recv case */
521 mutt_buffer_strcpy(pagerfile, a->filename);
522 mutt_adv_mktemp(pagerfile);
523 }
524 else
525 mutt_buffer_mktemp(pagerfile);
526 }
527
528 if (use_mailcap)
529 {
530 pid_t pid = 0;
531 int fd_temp = -1, fd_pager = -1;
532
533 if (!use_pager)
534 mutt_endwin();
535
536 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
537 if (use_pager || use_pipe)
538 {
539 if (use_pager && ((fd_pager = mutt_file_open(mutt_buffer_string(pagerfile),
540 O_CREAT | O_EXCL | O_WRONLY)) == -1))
541 {
542 mutt_perror("open");
543 goto return_error;
544 }
545 unlink_pagerfile = true;
546
547 if (use_pipe && ((fd_temp = open(mutt_buffer_string(tmpfile), 0)) == -1))
548 {
549 if (fd_pager != -1)
550 close(fd_pager);
551 mutt_perror("open");
552 goto return_error;
553 }
554 unlink_pagerfile = true;
555
556 pid = filter_create_fd(mutt_buffer_string(cmd), NULL, NULL, NULL,
557 use_pipe ? fd_temp : -1, use_pager ? fd_pager : -1, -1);
558
559 if (pid == -1)
560 {
561 if (fd_pager != -1)
562 close(fd_pager);
563
564 if (fd_temp != -1)
565 close(fd_temp);
566
567 mutt_error(_("Can't create filter"));
568 goto return_error;
569 }
570
571 if (use_pager)
572 {
573 if (a->description)
574 {
575 snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
577 }
578 else
579 {
580 snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
581 mutt_buffer_string(cmd), type);
582 }
583 filter_wait(pid);
584 }
585 else
586 {
587 if (wait_interactive_filter(pid) || (entry->needsterminal && c_wait_key))
589 }
590
591 if (fd_temp != -1)
592 close(fd_temp);
593 if (fd_pager != -1)
594 close(fd_pager);
595 }
596 else
597 {
598 /* interactive cmd */
599 int rv = mutt_system(mutt_buffer_string(cmd));
600 if (rv == -1)
601 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
602
603 if ((rv != 0) || (entry->needsterminal && c_wait_key))
605 }
606 }
607 else
608 {
609 /* Don't use mailcap; the attachment is viewed in the pager */
610
611 if (mode == MUTT_VA_AS_TEXT)
612 {
613 /* just let me see the raw data */
614 if (fp)
615 {
616 /* Viewing from a received message.
617 *
618 * Don't use mutt_save_attachment() because we want to perform charset
619 * conversion since this will be displayed by the internal pager. */
620 struct State decode_state = { 0 };
621
622 decode_state.fp_out = mutt_file_fopen(mutt_buffer_string(pagerfile), "w");
623 if (!decode_state.fp_out)
624 {
625 mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
626 mutt_buffer_string(pagerfile), errno, strerror(errno));
628 goto return_error;
629 }
630 decode_state.fp_in = fp;
631 decode_state.flags = MUTT_CHARCONV;
632 mutt_decode_attachment(a, &decode_state);
633 if (mutt_file_fclose(&decode_state.fp_out) == EOF)
634 {
635 mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n",
636 mutt_buffer_string(pagerfile), errno, strerror(errno));
637 }
638 }
639 else
640 {
641 /* in compose mode, just copy the file. we can't use
642 * mutt_decode_attachment() since it assumes the content-encoding has
643 * already been applied */
644 if (mutt_save_attachment(fp, a, mutt_buffer_string(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
645 goto return_error;
646 unlink_pagerfile = true;
647 }
649 }
650 else
651 {
652 /* Use built-in handler */
655 {
656 goto return_error;
657 }
658 unlink_pagerfile = true;
659 }
660
661 if (a->description)
662 mutt_str_copy(desc, a->description, sizeof(desc));
663 else if (a->filename)
664 snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
665 else
666 snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
667 }
668
669 /* We only reach this point if there have been no errors */
670
671 if (use_pager)
672 {
673 struct PagerData pdata = { 0 };
674 struct PagerView pview = { &pdata };
675
676 pdata.actx = actx;
677 pdata.body = a;
678 pdata.fname = mutt_buffer_string(pagerfile);
679 pdata.fp = fp;
680
681 pview.banner = desc;
683 (is_message ? MUTT_PAGER_MESSAGE : MUTT_PAGER_NO_FLAGS) |
684 ((use_mailcap && entry->xneomuttnowrap) ? MUTT_PAGER_NOWRAP :
686 pview.mode = PAGER_MODE_ATTACH;
687
688 rc = mutt_do_pager(&pview, e);
689
690 mutt_buffer_reset(pagerfile);
691 unlink_pagerfile = false;
692 }
693 else
694 rc = 0;
695
696return_error:
697
698 if (!entry || !entry->xneomuttkeep)
699 {
700 if ((fp && !mutt_buffer_is_empty(tmpfile)) || has_tempfile)
701 {
702 /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
704 }
705 }
706
707 mailcap_entry_free(&entry);
708
709 if (unlink_pagerfile)
711
712 mutt_buffer_pool_release(&tmpfile);
713 mutt_buffer_pool_release(&pagerfile);
715 mutt_envlist_unset("COLUMNS");
716
717 return rc;
718}
719
729int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
730{
731 pid_t pid = 0;
732 int out = -1, rc = 0;
733 bool is_flowed = false;
734 bool unlink_unstuff = false;
735 FILE *fp_filter = NULL, *fp_unstuff = NULL, *fp_in = NULL;
736 struct Buffer *unstuff_tempfile = NULL;
737
738 if (outfile && *outfile)
739 {
740 out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
741 if (out < 0)
742 {
743 mutt_perror("open");
744 return 0;
745 }
746 }
747
749 {
750 is_flowed = true;
751 unstuff_tempfile = mutt_buffer_pool_get();
752 mutt_buffer_mktemp(unstuff_tempfile);
753 }
754
755 mutt_endwin();
756
757 if (outfile && *outfile)
758 pid = filter_create_fd(path, &fp_filter, NULL, NULL, -1, out, -1);
759 else
760 pid = filter_create(path, &fp_filter, NULL, NULL);
761 if (pid < 0)
762 {
763 mutt_perror(_("Can't create filter"));
764 goto bail;
765 }
766
767 /* recv case */
768 if (fp)
769 {
770 struct State s = { 0 };
771
772 /* perform charset conversion on text attachments when piping */
774
775 if (is_flowed)
776 {
777 fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "w");
778 if (fp_unstuff == NULL)
779 {
780 mutt_perror("mutt_file_fopen");
781 goto bail;
782 }
783 unlink_unstuff = true;
784
785 s.fp_in = fp;
786 s.fp_out = fp_unstuff;
788 mutt_file_fclose(&fp_unstuff);
789
791
792 fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "r");
793 if (fp_unstuff == NULL)
794 {
795 mutt_perror("mutt_file_fopen");
796 goto bail;
797 }
798 mutt_file_copy_stream(fp_unstuff, fp_filter);
799 mutt_file_fclose(&fp_unstuff);
800 }
801 else
802 {
803 s.fp_in = fp;
804 s.fp_out = fp_filter;
806 }
807 }
808
809 /* send case */
810 else
811 {
812 const char *infile = NULL;
813
814 if (is_flowed)
815 {
816 if (mutt_save_attachment(fp, b, mutt_buffer_string(unstuff_tempfile),
817 MUTT_SAVE_NO_FLAGS, NULL) == -1)
818 {
819 goto bail;
820 }
821 unlink_unstuff = true;
823 infile = mutt_buffer_string(unstuff_tempfile);
824 }
825 else
826 infile = b->filename;
827
828 fp_in = fopen(infile, "r");
829 if (!fp_in)
830 {
831 mutt_perror("fopen");
832 goto bail;
833 }
834
835 mutt_file_copy_stream(fp_in, fp_filter);
837 }
838
839 mutt_file_fclose(&fp_filter);
840 rc = 1;
841
842bail:
843 if (outfile && *outfile)
844 {
845 close(out);
846 if (rc == 0)
847 unlink(outfile);
848 else if (is_flowed)
850 }
851
852 mutt_file_fclose(&fp_unstuff);
853 mutt_file_fclose(&fp_filter);
855
856 if (unlink_unstuff)
857 mutt_file_unlink(mutt_buffer_string(unstuff_tempfile));
858 mutt_buffer_pool_release(&unstuff_tempfile);
859
860 /* check for error exit from child process */
861 if ((pid > 0) && (filter_wait(pid) != 0))
862 rc = 0;
863
864 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
865 if ((rc == 0) || c_wait_key)
867 return rc;
868}
869
876static FILE *save_attachment_open(const char *path, enum SaveAttach opt)
877{
878 if (opt == MUTT_SAVE_APPEND)
879 return fopen(path, "a");
880 if (opt == MUTT_SAVE_OVERWRITE)
881 return fopen(path, "w");
882
883 return mutt_file_fopen(path, "w");
884}
885
896int mutt_save_attachment(FILE *fp, struct Body *m, const char *path,
897 enum SaveAttach opt, struct Email *e)
898{
899 if (!m)
900 return -1;
901
902 if (fp)
903 {
904 /* recv mode */
905
906 if (e && m->email && (m->encoding != ENC_BASE64) &&
908 {
909 /* message type attachments are written to mail folders. */
910
911 char buf[8192] = { 0 };
912 struct Message *msg = NULL;
914 int rc = -1;
915
916 struct Email *e_new = m->email;
917 e_new->msgno = e->msgno; /* required for MH/maildir */
918 e_new->read = true;
919
920 if (!mutt_file_seek(fp, m->offset, SEEK_SET))
921 return -1;
922 if (!fgets(buf, sizeof(buf), fp))
923 return -1;
924 struct Mailbox *m_att = mx_path_resolve(path);
925 if (!mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET))
926 {
927 mailbox_free(&m_att);
928 return -1;
929 }
930 msg = mx_msg_open_new(m_att, e_new,
931 is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
932 if (!msg)
933 {
934 mx_mbox_close(m_att);
935 return -1;
936 }
937 if ((m_att->type == MUTT_MBOX) || (m_att->type == MUTT_MMDF))
938 chflags = CH_FROM | CH_UPDATE_LEN;
939 chflags |= ((m_att->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
940 if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
941 (mx_msg_commit(m_att, msg) == 0))
942 {
943 rc = 0;
944 }
945 else
946 {
947 rc = -1;
948 }
949
950 mx_msg_close(m_att, &msg);
951 mx_mbox_close(m_att);
952 return rc;
953 }
954 else
955 {
956 /* In recv mode, extract from folder and decode */
957
958 struct State s = { 0 };
959
960 s.fp_out = save_attachment_open(path, opt);
961 if (!s.fp_out)
962 {
963 mutt_perror("fopen");
964 return -1;
965 }
966 if (!mutt_file_seek((s.fp_in = fp), m->offset, SEEK_SET))
967 {
969 return -1;
970 }
972
973 if (mutt_file_fsync_close(&s.fp_out) != 0)
974 {
975 mutt_perror("fclose");
976 return -1;
977 }
978 }
979 }
980 else
981 {
982 if (!m->filename)
983 return -1;
984
985 /* In send mode, just copy file */
986
987 FILE *fp_old = fopen(m->filename, "r");
988 if (!fp_old)
989 {
990 mutt_perror("fopen");
991 return -1;
992 }
993
994 FILE *fp_new = save_attachment_open(path, opt);
995 if (!fp_new)
996 {
997 mutt_perror("fopen");
998 mutt_file_fclose(&fp_old);
999 return -1;
1000 }
1001
1002 if (mutt_file_copy_stream(fp_old, fp_new) == -1)
1003 {
1004 mutt_error(_("Write fault"));
1005 mutt_file_fclose(&fp_old);
1006 mutt_file_fclose(&fp_new);
1007 return -1;
1008 }
1009 mutt_file_fclose(&fp_old);
1010 if (mutt_file_fsync_close(&fp_new) != 0)
1011 {
1012 mutt_error(_("Write fault"));
1013 return -1;
1014 }
1015 }
1016
1017 return 0;
1018}
1019
1030int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path,
1031 int displaying, enum SaveAttach opt)
1032{
1033 struct State s = { 0 };
1034 unsigned int saved_encoding = 0;
1035 struct Body *saved_parts = NULL;
1036 struct Email *e_saved = NULL;
1037 int rc = 0;
1038
1039 s.flags = displaying;
1040
1041 if (opt == MUTT_SAVE_APPEND)
1042 s.fp_out = fopen(path, "a");
1043 else if (opt == MUTT_SAVE_OVERWRITE)
1044 s.fp_out = fopen(path, "w");
1045 else
1046 s.fp_out = mutt_file_fopen(path, "w");
1047
1048 if (!s.fp_out)
1049 {
1050 mutt_perror("fopen");
1051 return -1;
1052 }
1053
1054 if (!fp)
1055 {
1056 /* When called from the compose menu, the attachment isn't parsed,
1057 * so we need to do it here. */
1058 s.fp_in = fopen(m->filename, "r");
1059 if (!s.fp_in)
1060 {
1061 mutt_perror("fopen");
1063 return -1;
1064 }
1065
1066 struct stat st = { 0 };
1067 if (fstat(fileno(s.fp_in), &st) == -1)
1068 {
1069 mutt_perror("stat");
1072 return -1;
1073 }
1074
1075 saved_encoding = m->encoding;
1076 if (!is_multipart(m))
1077 m->encoding = ENC_8BIT;
1078
1079 m->length = st.st_size;
1080 m->offset = 0;
1081 saved_parts = m->parts;
1082 e_saved = m->email;
1083 mutt_parse_part(s.fp_in, m);
1084
1085 if (m->noconv || is_multipart(m))
1086 s.flags |= MUTT_CHARCONV;
1087 }
1088 else
1089 {
1090 s.fp_in = fp;
1091 s.flags |= MUTT_CHARCONV;
1092 }
1093
1094 mutt_body_handler(m, &s);
1095
1096 if (mutt_file_fsync_close(&s.fp_out) != 0)
1097 {
1098 mutt_perror("fclose");
1099 rc = -1;
1100 }
1101 if (!fp)
1102 {
1103 m->length = 0;
1104 m->encoding = saved_encoding;
1105 if (saved_parts)
1106 {
1107 email_free(&m->email);
1108 m->parts = saved_parts;
1109 m->email = e_saved;
1110 }
1112 }
1113
1114 return rc;
1115}
1116
1130int mutt_print_attachment(FILE *fp, struct Body *a)
1131{
1132 char type[256] = { 0 };
1133 pid_t pid;
1134 FILE *fp_in = NULL, *fp_out = NULL;
1135 bool unlink_newfile = false;
1136 struct Buffer *newfile = mutt_buffer_pool_get();
1137 struct Buffer *cmd = mutt_buffer_pool_get();
1138
1139 int rc = 0;
1140
1141 snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1142
1143 if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1144 {
1145 mutt_debug(LL_DEBUG2, "Using mailcap\n");
1146
1147 struct MailcapEntry *entry = mailcap_entry_new();
1148 mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1149
1150 char *sanitized_fname = mutt_str_dup(a->filename);
1151 /* In send mode (!fp), we allow slashes because those are part of
1152 * the tempfile. The path will be removed in expand_filename */
1153 mutt_file_sanitize_filename(sanitized_fname, fp ? true : false);
1154 mailcap_expand_filename(entry->nametemplate, sanitized_fname, newfile);
1155 FREE(&sanitized_fname);
1156
1157 if (mutt_save_attachment(fp, a, mutt_buffer_string(newfile),
1158 MUTT_SAVE_NO_FLAGS, NULL) == -1)
1159 {
1160 goto mailcap_cleanup;
1161 }
1162 unlink_newfile = 1;
1163
1165
1166 mutt_buffer_strcpy(cmd, entry->printcommand);
1167
1168 bool piped = mailcap_expand_command(a, mutt_buffer_string(newfile), type, cmd);
1169
1170 mutt_endwin();
1171
1172 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1173 /* interactive program */
1174 if (piped)
1175 {
1176 fp_in = fopen(mutt_buffer_string(newfile), "r");
1177 if (!fp_in)
1178 {
1179 mutt_perror("fopen");
1180 mailcap_entry_free(&entry);
1181 goto mailcap_cleanup;
1182 }
1183
1184 pid = filter_create(mutt_buffer_string(cmd), &fp_out, NULL, NULL);
1185 if (pid < 0)
1186 {
1187 mutt_perror(_("Can't create filter"));
1188 mailcap_entry_free(&entry);
1189 mutt_file_fclose(&fp_in);
1190 goto mailcap_cleanup;
1191 }
1192 mutt_file_copy_stream(fp_in, fp_out);
1193 mutt_file_fclose(&fp_out);
1194 mutt_file_fclose(&fp_in);
1195 if (filter_wait(pid) || c_wait_key)
1197 }
1198 else
1199 {
1200 int rc2 = mutt_system(mutt_buffer_string(cmd));
1201 if (rc2 == -1)
1202 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
1203
1204 if ((rc2 != 0) || c_wait_key)
1206 }
1207
1208 rc = 1;
1209
1210 mailcap_cleanup:
1211 if (unlink_newfile)
1213
1214 mailcap_entry_free(&entry);
1215 goto out;
1216 }
1217
1218 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
1219 if (mutt_istr_equal("text/plain", type) || mutt_istr_equal("application/postscript", type))
1220 {
1221 rc = (mutt_pipe_attachment(fp, a, NONULL(c_print_command), NULL));
1222 goto out;
1223 }
1224 else if (mutt_can_decode(a))
1225 {
1226 /* decode and print */
1227
1228 fp_in = NULL;
1229 fp_out = NULL;
1230
1231 mutt_buffer_mktemp(newfile);
1234 {
1235 unlink_newfile = true;
1236 mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1237 type, mutt_buffer_string(newfile));
1238
1239 fp_in = fopen(mutt_buffer_string(newfile), "r");
1240 if (!fp_in)
1241 {
1242 mutt_perror("fopen");
1243 goto decode_cleanup;
1244 }
1245
1246 mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n",
1247 mutt_buffer_string(newfile));
1248
1249 mutt_endwin();
1250 pid = filter_create(NONULL(c_print_command), &fp_out, NULL, NULL);
1251 if (pid < 0)
1252 {
1253 mutt_perror(_("Can't create filter"));
1254 goto decode_cleanup;
1255 }
1256
1257 mutt_debug(LL_DEBUG2, "Filter created\n");
1258
1259 mutt_file_copy_stream(fp_in, fp_out);
1260
1261 mutt_file_fclose(&fp_out);
1262 mutt_file_fclose(&fp_in);
1263
1264 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1265 if ((filter_wait(pid) != 0) || c_wait_key)
1267 rc = 1;
1268 }
1269 decode_cleanup:
1270 mutt_file_fclose(&fp_in);
1271 mutt_file_fclose(&fp_out);
1272 if (unlink_newfile)
1274 }
1275 else
1276 {
1277 mutt_error(_("I don't know how to print that"));
1278 rc = 0;
1279 }
1280
1281out:
1282 mutt_buffer_pool_release(&newfile);
1284
1285 return rc;
1286}
1287
1292void mutt_add_temp_attachment(const char *filename)
1293{
1295}
1296
1301{
1302 struct ListNode *np = NULL;
1303
1304 STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1305 {
1306 (void) mutt_file_chmod_add(np->data, S_IWUSR);
1308 }
1309
1311}
struct Body * attach_body_ancestor(struct Body *start, struct Body *body, const char *subtype)
Find the ancestor of a body with specified subtype.
Definition: lib.c:116
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
void cid_save_attachments(struct Body *body, struct CidMapList *cid_map_list)
Save all attachments in a "multipart/related" group with a Content-ID.
Definition: cid.c:150
void cid_to_filename(struct Buffer *filename, const struct CidMapList *cid_map_list)
Replace Content-IDs with filenames.
Definition: cid.c:169
void cid_map_list_clear(struct CidMapList *cid_map_list)
Empty a CidMapList.
Definition: cid.c:81
Attachment Content-ID header functions.
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
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:640
Duplicate the structure of an entire email.
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:58
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
Convenience wrapper for the core headers.
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:312
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:387
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:354
int mutt_do_pager(struct PagerView *pview, struct Email *e)
Display some page-able text to the user (help or attachment)
Definition: do_pager.c:123
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Structs that make up an email.
bool mutt_envlist_unset(const char *name)
Unset an environment variable.
Definition: envlist.c:132
bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:85
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:260
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
Definition: file.c:549
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:647
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:690
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1403
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:288
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1123
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
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
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
Convenience wrapper for the gui headers.
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1827
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1867
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1597
Decide how to display email content.
IMAP network mailbox.
int imap_wait_keepalive(pid_t pid)
Wait for a process to change state.
Definition: util.c:969
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
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:473
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:444
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:435
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:67
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:542
RFC1524 Mailcap routines.
MailcapLookup
Mailcap actions.
Definition: mailcap.h:55
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:59
@ MUTT_MC_EDIT
Mailcap edit field.
Definition: mailcap.h:57
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:60
@ MUTT_MC_NO_FLAGS
No flags set.
Definition: mailcap.h:56
@ MUTT_MC_COMPOSE
Mailcap compose field.
Definition: mailcap.h:58
#define FREE(x)
Definition: memory.h:43
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_8BIT
8-bit text
Definition: mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
ContentType
Content-Type.
Definition: mime.h:30
@ TYPE_AUDIO
Type: 'audio/*'.
Definition: mime.h:32
@ TYPE_IMAGE
Type: 'image/*'.
Definition: mime.h:34
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MODEL
Type: 'model/*'.
Definition: mime.h:36
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
@ TYPE_VIDEO
Type: 'video/*'.
Definition: mime.h:39
#define TYPE(body)
Definition: mime.h:89
#define is_multipart(body)
Definition: mime.h:82
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define MUTT_DISPLAY_ATTACH
We are displaying an attachment.
Definition: state.h:40
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:524
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:729
bool mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:260
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:336
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:1030
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1130
static int wait_interactive_filter(pid_t pid)
Wait after an interactive filter.
Definition: mutt_attach.c:383
int mutt_get_tmp_attachment(struct Body *a)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:69
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1292
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:416
int mutt_compose_attachment(struct Body *a)
Create an attachment.
Definition: mutt_attach.c:115
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1300
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
Definition: mutt_attach.c:876
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:896
Handling of email attachments.
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:56
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:58
@ MUTT_SAVE_OVERWRITE
Overwrite existing file.
Definition: mutt_attach.h:59
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:57
ViewAttachMode
Options for mutt_view_attachment()
Definition: mutt_attach.h:42
@ MUTT_VA_MAILCAP
Force viewing using mailcap entry.
Definition: mutt_attach.h:44
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:43
@ MUTT_VA_PAGER
View attachment in pager using copiousoutput mailcap.
Definition: mutt_attach.h:46
@ MUTT_VA_AS_TEXT
Force viewing as text.
Definition: mutt_attach.h:45
Hundreds of global variables to back the user variables.
struct ListHead TempAttachmentsList
List of temporary files for displaying attachments.
Definition: mutt_globals.h:65
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition: mutt_globals.h:63
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:405
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:84
Some miscellaneous functions.
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1172
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
API for mailboxes.
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:43
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:42
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:63
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:65
API for encryption/signing of emails.
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
GUI display a file/email/help in a viewport with paging.
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: lib.h:58
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:71
@ PAGER_MODE_ATTACH
Pager is invoked via 2nd path. A user-selected attachment (mime part or a nested email) will be shown...
Definition: lib.h:136
#define MUTT_PAGER_MESSAGE
Definition: lib.h:74
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: lib.h:70
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1736
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1317
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1441
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define TAILQ_INIT(head)
Definition: queue.h:765
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void mutt_rfc3676_space_stuff_attachment(struct Body *b, const char *filename)
Stuff attachments.
Definition: rfc3676.c:534
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:513
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:389
RFC3676 Format Flowed routines.
Convenience wrapper for the send headers.
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:401
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:71
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:207
Key value store.
#define NONULL(x)
Definition: string2.h:37
A set of attachments.
Definition: attach.h:51
struct Body ** body_idx
Extra struct Body* used for decryption.
Definition: attach.h:66
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
char * xtype
content-type if x-unknown
Definition: body.h:61
bool noconv
Don't do character set conversion.
Definition: body.h:46
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
time_t stamp
Time stamp of last encoding update.
Definition: body.h:76
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
struct Email * email
header information for message/rfc822
Definition: body.h:73
char * description
content-description
Definition: body.h:55
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
char * form_name
Content-Disposition form-data name param.
Definition: body.h:59
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
int msgno
Number displayed to the user.
Definition: email.h:111
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
A mailbox.
Definition: mailbox.h:79
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
A mailcap entry.
Definition: mailcap.h:36
char * composecommand
Definition: mailcap.h:39
bool needsterminal
endwin() and system
Definition: mailcap.h:45
char * nametemplate
Definition: mailcap.h:43
char * printcommand
Definition: mailcap.h:42
char * composetypecommand
Definition: mailcap.h:40
char * editcommand
Definition: mailcap.h:41
char * command
Definition: mailcap.h:37
bool copiousoutput
needs pager, basically
Definition: mailcap.h:46
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:47
bool xneomuttnowrap
do not wrap the output in the pager
Definition: mailcap.h:48
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Data to be displayed by PagerView.
Definition: lib.h:158
const char * fname
Name of the file to read.
Definition: lib.h:162
FILE * fp
Source stream.
Definition: lib.h:160
struct Body * body
Current attachment.
Definition: lib.h:159
struct AttachCtx * actx
Attachment information.
Definition: lib.h:161
Paged view into some data.
Definition: lib.h:169
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:170
enum PagerMode mode
Pager mode.
Definition: lib.h:171
PagerFlags flags
Additional settings to tweak pager's function.
Definition: lib.h:172
const char * banner
Title to display in status bar.
Definition: lib.h:173
Keep track when processing files.
Definition: state.h:46
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:50
FILE * fp_out
File to write to.
Definition: state.h:48
FILE * fp_in
File to read from.
Definition: state.h:47
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60