NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
recvattach.c
Go to the documentation of this file.
1
29
35
36#include "config.h"
37#include <limits.h>
38#include <stdbool.h>
39#include <stdio.h>
40#include <string.h>
41#include <sys/stat.h>
42#include <sys/types.h>
43#include "mutt/lib.h"
44#include "config/lib.h"
45#include "email/lib.h"
46#include "core/lib.h"
47#include "gui/lib.h"
48#include "recvattach.h"
49#include "browser/lib.h"
50#include "editor/lib.h"
51#include "history/lib.h"
52#include "hooks/lib.h"
53#include "menu/lib.h"
54#include "ncrypt/lib.h"
55#include "question/lib.h"
56#include "send/lib.h"
57#include "attach.h"
58#include "external.h"
59#include "mutt_attach.h"
60#include "muttlib.h"
61#ifdef ENABLE_NLS
62#include <libintl.h>
63#endif
64
71struct AttachPtr *current_attachment(struct AttachCtx *actx, struct Menu *menu)
72{
73 const int virt = menu_get_index(menu);
74 const int index = actx->v2r[virt];
75
76 return actx->idx[index];
77}
78
85static void mutt_update_v2r(struct AttachCtx *actx)
86{
87 int vindex;
88 int rindex;
89 int curlevel;
90
91 vindex = 0;
92 rindex = 0;
93
94 while (rindex < actx->idxlen)
95 {
96 actx->v2r[vindex++] = rindex;
97 if (actx->idx[rindex]->collapsed)
98 {
99 curlevel = actx->idx[rindex]->level;
100 do
101 {
102 rindex++;
103 } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
104 }
105 else
106 {
107 rindex++;
108 }
109 }
110
111 actx->vcount = vindex;
112}
113
118void mutt_update_tree(struct AttachCtx *actx)
119{
120 char buf[256] = { 0 };
121 char *s = NULL;
122
123 mutt_update_v2r(actx);
124
125 for (int vindex = 0; vindex < actx->vcount; vindex++)
126 {
127 const int rindex = actx->v2r[vindex];
128 actx->idx[rindex]->num = vindex;
129 if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
130 {
131 if (actx->idx[rindex]->level)
132 {
133 s = buf + 2 * (actx->idx[rindex]->level - 1);
134 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
135 *s++ = MUTT_TREE_HLINE;
136 *s++ = MUTT_TREE_RARROW;
137 }
138 else
139 {
140 s = buf;
141 }
142 *s = '\0';
143 }
144
145 if (actx->idx[rindex]->tree)
146 {
147 if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
148 mutt_str_replace(&actx->idx[rindex]->tree, buf);
149 }
150 else
151 {
152 actx->idx[rindex]->tree = mutt_str_dup(buf);
153 }
154
155 if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
156 actx->idx[rindex]->level)
157 {
158 s = buf + 2 * (actx->idx[rindex]->level - 1);
159 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_VLINE : MUTT_TREE_SPACE;
160 *s++ = MUTT_TREE_SPACE;
161 }
162 }
163}
164
169static void prepend_savedir(struct Buffer *buf)
170{
171 if (buf_is_empty(buf) || (buf_at(buf, 0) == '/'))
172 return;
173
174 struct Buffer *tmp = buf_pool_get();
175 const char *const c_attach_save_dir = cs_subset_path(NeoMutt->sub, "attach_save_dir");
176 if (c_attach_save_dir)
177 {
178 buf_addstr(tmp, c_attach_save_dir);
179 if (tmp->dptr[-1] != '/')
180 buf_addch(tmp, '/');
181 }
182 else
183 {
184 buf_addstr(tmp, "./");
185 }
186
187 buf_addstr(tmp, buf_string(buf));
188 buf_copy(buf, tmp);
189 buf_pool_release(&tmp);
190}
191
197static bool has_a_message(struct Body *b)
198{
199 return (b->email && (b->encoding != ENC_BASE64) && (b->encoding != ENC_QUOTED_PRINTABLE) &&
201}
202
228static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path,
229 enum SaveAttach flags, struct Email *e)
230{
231 int rc = -1;
232
234 {
235 struct Body b_fake = { 0 };
236
237 struct Buffer *tempfile = buf_pool_get();
238 buf_mktemp(tempfile);
239
240 rc = mutt_save_attachment(fp, b, buf_string(tempfile), MUTT_SAVE_NONE, e);
241 if (rc != 0)
242 goto cleanup;
243
245
246 /* Now "really" save it. Send mode does this without touching anything,
247 * so force send-mode. */
248 memset(&b_fake, 0, sizeof(struct Body));
249 b_fake.filename = tempfile->data;
250 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
251
252 mutt_file_unlink(buf_string(tempfile));
253
254 cleanup:
255 buf_pool_release(&tempfile);
256 }
257 else
258 {
259 rc = mutt_save_attachment(fp, b, path, flags, e);
260 }
261
262 return rc;
263}
264
274static int query_save_attachment(FILE *fp, struct Body *b, struct Email *e, char **directory)
275{
276 char *prompt = NULL;
277 enum SaveAttach opt = MUTT_SAVE_NONE;
278 int rc = -1;
279
280 struct Buffer *buf = buf_pool_get();
281 struct Buffer *tfile = buf_pool_get();
282
283 if (b->filename)
284 {
285 if (directory && *directory)
286 {
287 buf_concat_path(buf, *directory, mutt_path_basename(b->filename));
288 }
289 else
290 {
291 buf_strcpy(buf, b->filename);
292 }
293 }
294 else if (has_a_message(b))
295 {
296 mutt_default_save(buf, b->email);
297 }
298
299 prepend_savedir(buf);
300
301 prompt = _("Save to file: ");
302 while (prompt)
303 {
304 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
305 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_FILE, &CompleteFileOps, &cdata) != 0) ||
306 buf_is_empty(buf))
307 {
308 goto cleanup;
309 }
310
311 prompt = NULL;
312 expand_path(buf, false);
313
314 bool is_message = (fp && has_a_message(b));
315
316 if (is_message)
317 {
318 struct stat st = { 0 };
319
320 /* check to make sure that this file is really the one the user wants */
321 rc = mutt_save_confirm(buf_string(buf), &st);
322 if (rc == 1)
323 {
324 prompt = _("Save to file: ");
325 continue;
326 }
327 else if (rc == -1)
328 {
329 goto cleanup;
330 }
331 buf_copy(tfile, buf);
332 }
333 else
334 {
335 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, directory);
336 if (rc == -1)
337 {
338 goto cleanup;
339 }
340 else if (rc == 1)
341 {
342 prompt = _("Save to file: ");
343 continue;
344 }
345 }
346
347 mutt_message(_("Saving..."));
348 if (save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
349 (e || !is_message) ? e : b->email) == 0)
350 {
351 // This uses ngettext to avoid duplication of messages
352 int num = 1;
353 mutt_message(ngettext("Attachment saved", "%d attachments saved", num), num);
354 rc = 0;
355 goto cleanup;
356 }
357 else
358 {
359 prompt = _("Save to file: ");
360 continue;
361 }
362 }
363
364cleanup:
365 buf_pool_release(&buf);
366 buf_pool_release(&tfile);
367 return rc;
368}
369
378static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
379{
380 enum SaveAttach opt = MUTT_SAVE_NONE;
381 int rc = -1;
382 struct Buffer *buf = buf_pool_get();
383 struct Buffer *tfile = buf_pool_get();
384
385 if (b->filename)
386 {
387 buf_strcpy(buf, b->filename);
388 }
389 else if (has_a_message(b))
390 {
391 mutt_default_save(buf, b->email);
392 }
393
394 prepend_savedir(buf);
395 expand_path(buf, false);
396
397 bool is_message = (fp && has_a_message(b));
398
399 if (is_message)
400 {
401 buf_copy(tfile, buf);
402 }
403 else
404 {
405 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL);
406 if (rc == -1) // abort or cancel
407 goto cleanup;
408 }
409
410 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
411 (e || !is_message) ? e : b->email);
412
413cleanup:
414 buf_pool_release(&buf);
415 buf_pool_release(&tfile);
416 return rc;
417}
418
425void mutt_save_attachment_list(struct AttachPtrArray *aa, struct Email *e, struct Menu *menu)
426{
427 char *directory = NULL;
428 int rc = 1;
429 int last = menu ? menu_get_index(menu) : 0;
430 FILE *fp_out = NULL;
431 int saved_attachments = 0;
432
433 struct Buffer *buf = buf_pool_get();
434 struct Buffer *tfile = buf_pool_get();
435
436 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
437 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
438 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
439
440 struct AttachPtr **app = NULL;
441 ARRAY_FOREACH(app, aa)
442 {
443 FILE *fp = (*app)->fp;
444 struct Body *b = (*app)->body;
445
446 /* Iterate through attachments.
447 * Behavior depends on attach_split: if true, save each to its own file;
448 * if false, concatenate all into one file with optional separator. */
449 if (c_attach_split)
450 {
451 if (menu)
452 {
453 menu_set_index(menu, (*app)->num);
455 menu_redraw(menu);
456 }
457 if (c_attach_save_without_prompting)
458 {
459 // Save each file, with no prompting, using the configured 'AttachSaveDir'
460 rc = save_without_prompting(fp, b, e);
461 if (rc == 0)
462 saved_attachments++;
463 }
464 else
465 {
466 // Save each file, prompting the user for the location each time.
467 if (query_save_attachment(fp, b, e, &directory) == -1)
468 break;
469 }
470 }
471 else
472 {
473 enum SaveAttach opt = MUTT_SAVE_NONE;
474
475 if (buf_is_empty(buf))
476 {
478 prepend_savedir(buf);
479
480 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
481 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
482 &CompleteFileOps, &cdata) != 0) ||
483 buf_is_empty(buf))
484 {
485 goto cleanup;
486 }
487 expand_path(buf, false);
488 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
489 goto cleanup;
490 }
491 else
492 {
493 opt = MUTT_SAVE_APPEND;
494 }
495
496 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
497 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
498 {
499 fprintf(fp_out, "%s", c_attach_sep);
500 mutt_file_fclose(&fp_out);
501 }
502 }
503 }
504
505 FREE(&directory);
506
507 if ((ARRAY_SIZE(aa) > 1) && menu)
508 {
509 menu_set_index(menu, last);
511 }
512
513 if (rc == 0)
514 {
515 if (!c_attach_split)
516 saved_attachments = 1;
517
518 if (!c_attach_split || c_attach_save_without_prompting)
519 {
520 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
521 saved_attachments);
522 }
523 }
524
525cleanup:
526 buf_pool_release(&buf);
527 buf_pool_release(&tfile);
528}
529
537static void query_pipe_attachment(const char *command, FILE *fp, struct Body *b, bool filter)
538{
539 struct Buffer *tfile = buf_pool_get();
540
541 if (filter)
542 {
543 char warning[PATH_MAX + 256] = { 0 };
544 snprintf(warning, sizeof(warning),
545 _("WARNING! You are about to overwrite %s, continue?"), b->filename);
546 if (query_yesorno(warning, MUTT_NO) != MUTT_YES)
547 {
548 msgwin_clear_text(NULL);
549 buf_pool_release(&tfile);
550 return;
551 }
552 buf_mktemp(tfile);
553 }
554
555 if (mutt_pipe_attachment(fp, b, command, buf_string(tfile)))
556 {
557 if (filter)
558 {
562 mutt_message(_("Attachment filtered"));
563 }
564 }
565 else
566 {
567 if (filter && !buf_is_empty(tfile))
569 }
570 buf_pool_release(&tfile);
571}
572
579static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
580{
581 if (!state || !state->fp_out)
582 return;
583
584 FILE *fp_in = NULL;
585 FILE *fp_unstuff = NULL;
586 bool is_flowed = false, unlink_unstuff = false;
587 struct Buffer *unstuff_tempfile = NULL;
588
590 {
591 is_flowed = true;
592 unstuff_tempfile = buf_pool_get();
593 buf_mktemp(unstuff_tempfile);
594 }
595
596 if (fp)
597 {
598 state->fp_in = fp;
599
600 if (is_flowed)
601 {
602 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
603 if (!fp_unstuff)
604 {
605 mutt_perror("mutt_file_fopen");
606 goto bail;
607 }
608 unlink_unstuff = true;
609
610 FILE *filter_fp = state->fp_out;
611 state->fp_out = fp_unstuff;
612 mutt_decode_attachment(b, state);
613 mutt_file_fclose(&fp_unstuff);
614 state->fp_out = filter_fp;
615
616 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
617 if (!fp_unstuff)
618 {
619 mutt_perror("mutt_file_fopen");
620 goto bail;
621 }
622 mutt_file_copy_stream(fp_unstuff, filter_fp);
623 mutt_file_fclose(&fp_unstuff);
624 }
625 else
626 {
627 mutt_decode_attachment(b, state);
628 }
629 }
630 else
631 {
632 const char *infile = NULL;
633
634 if (is_flowed)
635 {
636 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile), 0, NULL) == -1)
637 goto bail;
638 unlink_unstuff = true;
640 infile = buf_string(unstuff_tempfile);
641 }
642 else
643 {
644 infile = b->filename;
645 }
646
647 fp_in = mutt_file_fopen(infile, "r");
648 if (!fp_in)
649 {
650 mutt_perror("fopen");
651 goto bail;
652 }
653 mutt_file_copy_stream(fp_in, state->fp_out);
654 mutt_file_fclose(&fp_in);
655 }
656
657 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
658 if (c_attach_sep)
659 state_puts(state, c_attach_sep);
660
661bail:
662 mutt_file_fclose(&fp_unstuff);
663 mutt_file_fclose(&fp_in);
664
665 if (unlink_unstuff)
666 mutt_file_unlink(buf_string(unstuff_tempfile));
667 buf_pool_release(&unstuff_tempfile);
668}
669
677static void pipe_attachment_list(const char *command, struct AttachPtrArray *aa,
678 bool filter, struct State *state)
679{
680 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
681 struct AttachPtr **app = NULL;
682 ARRAY_FOREACH(app, aa)
683 {
684 FILE *fp = (*app)->fp;
685 struct Body *b = (*app)->body;
686
687 if (!filter && !c_attach_split)
688 pipe_attachment(fp, b, state);
689 else
690 query_pipe_attachment(command, fp, b, filter);
691 }
692}
693
699void mutt_pipe_attachment_list(struct AttachPtrArray *aa, bool filter)
700{
701 struct State state = { 0 };
702 struct Buffer *buf = NULL;
703
704 if (ARRAY_EMPTY(aa))
705 return;
706
707 struct AttachPtr **first = ARRAY_GET(aa, 0);
708 if (first && (*first)->fp)
709 filter = false; /* sanity check: we can't filter in the recv case yet */
710
711 buf = buf_pool_get();
712 /* perform charset conversion on text attachments when piping */
713 state.flags = STATE_CHARCONV;
714
715 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
717 {
718 goto cleanup;
719 }
720
721 if (buf_is_empty(buf))
722 goto cleanup;
723
724 expand_path(buf, false);
725
726 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
727 if (!filter && !c_attach_split)
728 {
729 mutt_endwin();
730 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL,
731 NeoMutt->env);
732 pipe_attachment_list(buf_string(buf), aa, filter, &state);
733 mutt_file_fclose(&state.fp_out);
734 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
735 if ((filter_wait(pid) != 0) || c_wait_key)
737 }
738 else
739 {
740 pipe_attachment_list(buf_string(buf), aa, filter, &state);
741 }
742
743cleanup:
744 buf_pool_release(&buf);
745}
746
752static bool can_print(struct AttachPtrArray *aa)
753{
754 char type[256] = { 0 };
755
756 struct AttachPtr **app = NULL;
757 ARRAY_FOREACH(app, aa)
758 {
759 struct Body *b = (*app)->body;
760 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
761 if (!mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
762 {
763 if (!mutt_istr_equal("text/plain", b->subtype) &&
764 !mutt_istr_equal("application/postscript", b->subtype))
765 {
766 if (!mutt_can_decode(b))
767 {
768 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
769 application/octet-stream. */
770 mutt_error(_("I don't know how to print %s attachments"), type);
771 return false;
772 }
773 }
774 }
775 }
776 return true;
777}
778
784static void print_attachment_list(struct AttachPtrArray *aa, struct State *state)
785{
786 char type[256] = { 0 };
787
788 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
789 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
790
791 struct AttachPtr **app = NULL;
792 ARRAY_FOREACH(app, aa)
793 {
794 FILE *fp = (*app)->fp;
795 struct Body *b = (*app)->body;
796
797 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
798 if (!c_attach_split && !mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
799 {
800 if (mutt_istr_equal("text/plain", b->subtype) ||
801 mutt_istr_equal("application/postscript", b->subtype))
802 {
803 pipe_attachment(fp, b, state);
804 }
805 else if (mutt_can_decode(b))
806 {
807 /* decode and print */
808
809 FILE *fp_in = NULL;
810 struct Buffer *newfile = buf_pool_get();
811
812 buf_mktemp(newfile);
813 if (mutt_decode_save_attachment(fp, b, buf_string(newfile),
815 {
816 if (!state->fp_out)
817 {
818 mutt_error("BUG in print_attachment_list(). Please report this. ");
820 buf_pool_release(&newfile);
821 return;
822 }
823
824 fp_in = mutt_file_fopen(buf_string(newfile), "r");
825 if (fp_in)
826 {
827 mutt_file_copy_stream(fp_in, state->fp_out);
828 mutt_file_fclose(&fp_in);
829 if (c_attach_sep)
830 state_puts(state, c_attach_sep);
831 }
832 }
834 buf_pool_release(&newfile);
835 }
836 }
837 else
838 {
840 }
841 }
842}
843
848void mutt_print_attachment_list(struct AttachPtrArray *aa)
849{
850 char prompt[128] = { 0 };
851 struct State state = { 0 };
852 const int count = ARRAY_SIZE(aa);
853
854 if (count == 0)
855 return;
856
857 snprintf(prompt, sizeof(prompt),
858 ngettext("Print attachment?", "Print %d attachments?", count), count);
859 if (query_quadoption(prompt, NeoMutt->sub, "print") != MUTT_YES)
860 return;
861
862 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
863 if (c_attach_split)
864 {
865 print_attachment_list(aa, &state);
866 }
867 else
868 {
869 if (!can_print(aa))
870 return;
871 mutt_endwin();
872 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
873 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL,
874 NULL, NeoMutt->env);
875 print_attachment_list(aa, &state);
876 mutt_file_fclose(&state.fp_out);
877 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
878 if ((filter_wait(pid) != 0) || c_wait_key)
880 }
881}
882
889void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
890{
891 struct AttachPtr *cur_att = current_attachment(actx, menu);
892 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
893 return;
894
895 /* The mutt_update_recvattach_menu() will overwrite any changes
896 * made to a decrypted cur_att->body, so warn the user. */
897 if (cur_att->decrypted)
898 {
899 mutt_message(_("Structural changes to decrypted attachments are not supported"));
900 mutt_sleep(1);
901 }
902 /* Editing the content type can rewrite the body structure. */
903 for (int i = 0; i < actx->idxlen; i++)
904 actx->idx[i]->body = NULL;
906 mutt_update_recvattach_menu(actx, menu, true);
907}
908
919int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op,
920 struct Email *e, struct AttachCtx *actx, bool recv)
921{
922 do
923 {
924 switch (op)
925 {
926 case OP_DISPLAY_HEADERS:
927 bool_str_toggle(NeoMutt->sub, "weed", NULL);
929
930 case OP_ATTACH_VIEW:
931 {
932 struct AttachPtr *cur_att = current_attachment(actx, menu);
933 if (!cur_att->fp)
934 {
935 if (cur_att->body->type == TYPE_MULTIPART)
936 {
937 struct Body *b = cur_att->body->parts;
938 while (b && b->parts)
939 b = b->parts;
940 if (b)
941 cur_att = b->aptr;
942 }
943 }
944 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
945 e, actx, menu->win);
946 break;
947 }
948
949 case OP_NEXT_ENTRY:
950 case OP_MAIN_NEXT_UNDELETED: /* hack */
951 {
952 const int index = menu_get_index(menu) + 1;
953 if (index < menu->max)
954 {
955 menu_set_index(menu, index);
956 op = OP_ATTACH_VIEW;
957 }
958 else
959 {
960 op = OP_NULL;
961 }
962 break;
963 }
964
965 case OP_PREV_ENTRY:
966 case OP_MAIN_PREV_UNDELETED: /* hack */
967 {
968 const int index = menu_get_index(menu) - 1;
969 if (index >= 0)
970 {
971 menu_set_index(menu, index);
972 op = OP_ATTACH_VIEW;
973 }
974 else
975 {
976 op = OP_NULL;
977 }
978 break;
979 }
980
981 case OP_ATTACH_EDIT_TYPE:
982 {
983 struct AttachPtr *cur_att = current_attachment(actx, menu);
984 /* when we edit the content-type, we should redisplay the attachment
985 * immediately */
986 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
987 if (recv)
988 recvattach_edit_content_type(actx, menu, e);
989 else
990 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
991
993 op = OP_ATTACH_VIEW;
994 break;
995 }
996 /* functions which are passed through from the pager */
997 case OP_PIPE:
998 {
999 struct AttachPtr *cur_att = current_attachment(actx, menu);
1000 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
1001 ARRAY_ADD(&aa, cur_att);
1002 mutt_pipe_attachment_list(&aa, false);
1003 ARRAY_FREE(&aa);
1004 op = OP_ATTACH_VIEW;
1005 break;
1006 }
1007 case OP_ATTACH_PRINT:
1008 {
1009 struct AttachPtr *cur_att = current_attachment(actx, menu);
1010 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
1011 ARRAY_ADD(&aa, cur_att);
1013 ARRAY_FREE(&aa);
1014 op = OP_ATTACH_VIEW;
1015 break;
1016 }
1017 case OP_ATTACH_SAVE:
1018 {
1019 struct AttachPtr *cur_att = current_attachment(actx, menu);
1020 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
1021 ARRAY_ADD(&aa, cur_att);
1022 mutt_save_attachment_list(&aa, e, NULL);
1023 ARRAY_FREE(&aa);
1024 op = OP_ATTACH_VIEW;
1025 break;
1026 }
1027 case OP_CHECK_TRADITIONAL:
1029 {
1030 op = OP_NULL;
1031 break;
1032 }
1034
1035 case OP_ATTACH_COLLAPSE:
1036 if (recv)
1037 return op;
1039
1040 default:
1041 op = OP_NULL;
1042 }
1043 } while (op != OP_NULL);
1044
1045 return op;
1046}
1047
1058void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e,
1059 struct Body *b, FILE *fp, int parent_type,
1060 int level, bool decrypted)
1061{
1062 struct Body *bp = NULL;
1063 struct Body *new_body = NULL;
1064 FILE *fp_new = NULL;
1066
1067 for (bp = b; bp; bp = bp->next)
1068 {
1069 bool need_secured = false;
1070 bool secured = false;
1071
1073 {
1074 need_secured = true;
1075
1076 if (type & SEC_ENCRYPT)
1077 {
1079 goto decrypt_failed;
1080
1081 if (e->env)
1083 }
1084
1085 secured = (crypt_smime_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1086 /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1087 * text/plain type will still be returned by mutt_read_mime_header().
1088 * We can't distinguish an actual part from a failure, so only use a
1089 * text/plain that results from a single top-level part. */
1090 if (secured && (new_body->type == TYPE_TEXT) &&
1091 mutt_istr_equal("plain", new_body->subtype) && ((b != bp) || bp->next))
1092 {
1093 mutt_body_free(&new_body);
1094 mutt_file_fclose(&fp_new);
1095 goto decrypt_failed;
1096 }
1097
1098 if (secured && (type & SEC_ENCRYPT))
1099 e->security |= SMIME_ENCRYPT;
1100 }
1101
1102 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1104 {
1105 need_secured = true;
1106
1108 goto decrypt_failed;
1109
1110 secured = (crypt_pgp_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1111
1112 if (secured)
1113 e->security |= PGP_ENCRYPT;
1114 }
1115
1116 if (need_secured && secured)
1117 {
1118 mutt_actx_add_fp(actx, fp_new);
1119 mutt_actx_add_body(actx, new_body);
1120 mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1121 continue;
1122 }
1123
1124 decrypt_failed:
1125 /* Fall through and show the original parts if decryption fails */
1126 if (need_secured && !secured)
1127 mutt_error(_("Can't decrypt encrypted message"));
1128
1129 struct AttachPtr *ap = mutt_aptr_new();
1130 mutt_actx_add_attach(actx, ap);
1131
1132 ap->body = bp;
1133 ap->fp = fp;
1134 bp->aptr = ap;
1136 ap->level = level;
1137 ap->decrypted = decrypted;
1138
1139 if (mutt_is_message_type(bp->type, bp->subtype))
1140 {
1141 mutt_generate_recvattach_list(actx, bp->email, bp->parts, fp, bp->type,
1142 level + 1, decrypted);
1143 e->security |= bp->email->security;
1144 }
1145 else
1146 {
1147 mutt_generate_recvattach_list(actx, e, bp->parts, fp, bp->type, level + 1, decrypted);
1148 }
1149 }
1150}
1151
1156void mutt_attach_init(struct AttachCtx *actx)
1157{
1158 /* Collapse the attachments if '$digest_collapse' is set AND if...
1159 * the outer container is of type 'multipart/digest' */
1160 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1161
1162 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1163 for (int i = 0; i < actx->idxlen; i++)
1164 {
1165 actx->idx[i]->body->tagged = false;
1166
1167 /* OR an inner container is of type 'multipart/digest' */
1168 actx->idx[i]->collapsed = (c_digest_collapse &&
1169 (digest ||
1170 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1171 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1172 }
1173}
1174
1181void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
1182{
1183 if (init)
1184 {
1185 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1186 actx->fp_root, -1, 0, 0);
1187 mutt_attach_init(actx);
1188 }
1189
1190 mutt_update_tree(actx);
1191
1192 menu->max = actx->vcount;
1193
1194 const int index = menu_get_index(menu);
1195 if (index >= menu->max)
1196 menu_set_index(menu, menu->max - 1);
1198}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition attach.c:65
void mutt_actx_add_fp(struct AttachCtx *actx, FILE *fp_new)
Save a File handle to the Attachment Context.
Definition attach.c:121
struct AttachPtr * mutt_aptr_new(void)
Create a new Attachment Pointer.
Definition attach.c:40
void mutt_actx_add_body(struct AttachCtx *actx, struct Body *b)
Add an email body to an Attachment Context.
Definition attach.c:142
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition attach.c:162
Handling of email attachments.
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:231
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
Select a Mailbox from a list.
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:674
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:607
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition buffer.c:515
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:610
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition crypt.c:444
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:505
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition cryptglue.c:237
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition cryptglue.c:538
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition cryptglue.c:510
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition draw.c:486
Edit a string.
@ MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:47
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
Structs that make up an email.
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1620
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1073
Manage where the email is piped to external commands.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition file.c:1258
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_perror(...)
Definition logging2.h:95
Convenience wrapper for the gui headers.
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition thread.h:57
@ MUTT_TREE_RARROW
Right arrow.
Definition thread.h:63
@ MUTT_TREE_LTEE
Left T-piece.
Definition thread.h:59
@ MUTT_TREE_VLINE
Vertical line.
Definition thread.h:61
@ MUTT_TREE_HLINE
Horizontal line.
Definition thread.h:60
@ MUTT_TREE_SPACE
Blank space.
Definition thread.h:62
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition handler.c:1903
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1943
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition lib.h:59
@ HC_EXT_COMMAND
External commands.
Definition lib.h:56
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition exec.c:218
Hook Commands.
bool mailcap_lookup(struct Body *b, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition mailcap.c:484
@ MUTT_MC_PRINT
Mailcap print field.
Definition mailcap.h:60
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
GUI present the user with a selectable list.
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:177
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:153
@ MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:61
@ MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition lib.h:62
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:167
@ ENC_BASE64
Base-64 encoded text.
Definition mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition mime.h:51
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
#define BODY_TYPE(body)
Get the type name of a body part.
Definition mime.h:93
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:556
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:220
Convenience wrapper for the library headers.
#define FALLTHROUGH
Definition lib.h:117
#define _(a)
Definition message.h:28
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition path.c:282
#define state_puts(STATE, STR)
Definition state.h:64
@ STATE_CHARCONV
Do character set conversions.
Definition state.h:41
@ STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition state.h:42
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
#define PATH_MAX
Definition mutt.h:49
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, const char *outfile)
Pipe an attachment to a command.
int mutt_save_attachment(FILE *fp, struct Body *b, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
int mutt_print_attachment(FILE *fp, struct Body *b)
Print out an attachment.
Handling of email attachments.
SaveAttach
Options for saving attachments.
Definition mutt_attach.h:58
@ MUTT_SAVE_APPEND
Append to existing file.
Definition mutt_attach.h:60
@ MUTT_SAVE_NONE
Overwrite existing file (the default)
Definition mutt_attach.h:59
@ MUTT_VA_REGULAR
View using default method.
Definition mutt_attach.h:45
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:787
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
int mutt_check_overwrite(const char *attname, const char *path, struct Buffer *fname, enum SaveAttach *opt, char **directory)
Ask the user if overwriting is necessary.
Definition muttlib.c:524
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition muttlib.c:690
Some miscellaneous functions.
API for encryption/signing of emails.
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:108
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:112
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
#define SMIME_ENCRYPT
Email is S/MIME encrypted.
Definition lib.h:118
#define WithCrypto
Definition lib.h:132
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:329
void mutt_save_attachment_list(struct AttachPtrArray *aa, struct Email *e, struct Menu *menu)
Save a list of selected attachments.
Definition recvattach.c:425
void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *b, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
void mutt_pipe_attachment_list(struct AttachPtrArray *aa, bool filter)
Pipe selected attachments to a command.
Definition recvattach.c:699
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path, enum SaveAttach flags, struct Email *e)
Helper for unstuffing attachments.
Definition recvattach.c:228
static void print_attachment_list(struct AttachPtrArray *aa, struct State *state)
Print a list of Attachments.
Definition recvattach.c:784
static void query_pipe_attachment(const char *command, FILE *fp, struct Body *b, bool filter)
Ask the user if we should pipe the attachment.
Definition recvattach.c:537
static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
Save the attachment, without prompting each time.
Definition recvattach.c:378
static void pipe_attachment_list(const char *command, struct AttachPtrArray *aa, bool filter, struct State *state)
Pipe a list of attachments to a command.
Definition recvattach.c:677
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition recvattach.c:71
int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op, struct Email *e, struct AttachCtx *actx, bool recv)
Event loop for the Attachment menu.
Definition recvattach.c:919
void mutt_print_attachment_list(struct AttachPtrArray *aa)
Print selected attachments.
Definition recvattach.c:848
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition recvattach.c:169
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition recvattach.c:579
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition recvattach.c:118
static int query_save_attachment(FILE *fp, struct Body *b, struct Email *e, char **directory)
Ask the user if we should save the attachment.
Definition recvattach.c:274
static bool has_a_message(struct Body *b)
Determine if the Body has a message (to save)
Definition recvattach.c:197
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition recvattach.c:85
static bool can_print(struct AttachPtrArray *aa)
Do we know how to print this attachment type?
Definition recvattach.c:752
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition recvattach.c:889
Routines for managing attachments.
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition rfc3676.c:524
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition rfc3676.c:400
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:424
#define NONULL(x)
Definition string2.h:44
A set of attachments.
Definition attach.h:65
short vcount
The number of virtual attachments.
Definition attach.h:74
FILE * fp_root
Used by recvattach for updating.
Definition attach.h:67
struct Email * email
Used by recvattach for updating.
Definition attach.h:66
struct AttachPtr ** idx
Array of attachments.
Definition attach.h:69
short idxlen
Number of attachmentes.
Definition attach.h:70
short * v2r
Mapping from virtual to real attachment.
Definition attach.h:73
An email to which things will be attached.
Definition attach.h:36
struct Body * body
Attachment.
Definition attach.h:37
bool collapsed
Group is collapsed.
Definition attach.h:45
char * tree
Tree characters to display.
Definition attach.h:40
int num
Attachment index number.
Definition attach.h:42
int level
Nesting depth of attachment.
Definition attach.h:41
FILE * fp
Used in the recvattach menu.
Definition attach.h:38
bool decrypted
Not part of message as stored in the email->body.
Definition attach.h:44
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition attach.h:39
The body of an email.
Definition body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition body.h:75
struct Email * email
header information for message/rfc822
Definition body.h:74
bool tagged
This attachment is tagged.
Definition body.h:90
struct Body * next
next attachment in the list
Definition body.h:72
char * subtype
content-type subtype
Definition body.h:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
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:59
String manipulation buffer.
Definition buffer.h:36
char * dptr
Current read/write position.
Definition buffer.h:38
char * data
Pointer to data.
Definition buffer.h:37
A set of inherited config items.
Definition subset.h:46
The envelope/body of an email.
Definition email.h:39
struct Envelope * env
Envelope information.
Definition email.h:68
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct Body * body
List of MIME parts.
Definition email.h:69
Input for the file completion function.
Definition curs_lib.h:39
Definition lib.h:86
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:94
int max
Number of entries in the menu.
Definition lib.h:88
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Keep track when processing files.
Definition state.h:54
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
#define buf_mktemp(buf)
Definition tmp.h:33