NeoMutt  2025-12-11-435-g4ac674
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, rindex, curlevel;
88
89 vindex = 0;
90 rindex = 0;
91
92 while (rindex < actx->idxlen)
93 {
94 actx->v2r[vindex++] = rindex;
95 if (actx->idx[rindex]->collapsed)
96 {
97 curlevel = actx->idx[rindex]->level;
98 do
99 {
100 rindex++;
101 } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
102 }
103 else
104 {
105 rindex++;
106 }
107 }
108
109 actx->vcount = vindex;
110}
111
116void mutt_update_tree(struct AttachCtx *actx)
117{
118 char buf[256] = { 0 };
119 char *s = NULL;
120
121 mutt_update_v2r(actx);
122
123 for (int vindex = 0; vindex < actx->vcount; vindex++)
124 {
125 const int rindex = actx->v2r[vindex];
126 actx->idx[rindex]->num = vindex;
127 if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
128 {
129 if (actx->idx[rindex]->level)
130 {
131 s = buf + 2 * (actx->idx[rindex]->level - 1);
132 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
133 *s++ = MUTT_TREE_HLINE;
134 *s++ = MUTT_TREE_RARROW;
135 }
136 else
137 {
138 s = buf;
139 }
140 *s = '\0';
141 }
142
143 if (actx->idx[rindex]->tree)
144 {
145 if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
146 mutt_str_replace(&actx->idx[rindex]->tree, buf);
147 }
148 else
149 {
150 actx->idx[rindex]->tree = mutt_str_dup(buf);
151 }
152
153 if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
154 actx->idx[rindex]->level)
155 {
156 s = buf + 2 * (actx->idx[rindex]->level - 1);
157 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_VLINE : MUTT_TREE_SPACE;
158 *s++ = MUTT_TREE_SPACE;
159 }
160 }
161}
162
167static void prepend_savedir(struct Buffer *buf)
168{
169 if (buf_is_empty(buf) || (buf_at(buf, 0) == '/'))
170 return;
171
172 struct Buffer *tmp = buf_pool_get();
173 const char *const c_attach_save_dir = cs_subset_path(NeoMutt->sub, "attach_save_dir");
174 if (c_attach_save_dir)
175 {
176 buf_addstr(tmp, c_attach_save_dir);
177 if (tmp->dptr[-1] != '/')
178 buf_addch(tmp, '/');
179 }
180 else
181 {
182 buf_addstr(tmp, "./");
183 }
184
185 buf_addstr(tmp, buf_string(buf));
186 buf_copy(buf, tmp);
187 buf_pool_release(&tmp);
188}
189
195static bool has_a_message(struct Body *b)
196{
197 return (b->email && (b->encoding != ENC_BASE64) && (b->encoding != ENC_QUOTED_PRINTABLE) &&
199}
200
226static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path,
227 enum SaveAttach flags, struct Email *e)
228{
229 int rc = -1;
230
232 {
233 struct Body b_fake = { 0 };
234
235 struct Buffer *tempfile = buf_pool_get();
236 buf_mktemp(tempfile);
237
238 rc = mutt_save_attachment(fp, b, buf_string(tempfile), MUTT_SAVE_NO_FLAGS, e);
239 if (rc != 0)
240 goto cleanup;
241
243
244 /* Now "really" save it. Send mode does this without touching anything,
245 * so force send-mode. */
246 memset(&b_fake, 0, sizeof(struct Body));
247 b_fake.filename = tempfile->data;
248 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
249
250 mutt_file_unlink(buf_string(tempfile));
251
252 cleanup:
253 buf_pool_release(&tempfile);
254 }
255 else
256 {
257 rc = mutt_save_attachment(fp, b, path, flags, e);
258 }
259
260 return rc;
261}
262
272static int query_save_attachment(FILE *fp, struct Body *b, struct Email *e, char **directory)
273{
274 char *prompt = NULL;
276 int rc = -1;
277
278 struct Buffer *buf = buf_pool_get();
279 struct Buffer *tfile = buf_pool_get();
280
281 if (b->filename)
282 {
283 if (directory && *directory)
284 {
285 buf_concat_path(buf, *directory, mutt_path_basename(b->filename));
286 }
287 else
288 {
289 buf_strcpy(buf, b->filename);
290 }
291 }
292 else if (has_a_message(b))
293 {
294 mutt_default_save(buf, b->email);
295 }
296
297 prepend_savedir(buf);
298
299 prompt = _("Save to file: ");
300 while (prompt)
301 {
302 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
303 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_FILE, &CompleteFileOps, &cdata) != 0) ||
304 buf_is_empty(buf))
305 {
306 goto cleanup;
307 }
308
309 prompt = NULL;
310 expand_path(buf, false);
311
312 bool is_message = (fp && has_a_message(b));
313
314 if (is_message)
315 {
316 struct stat st = { 0 };
317
318 /* check to make sure that this file is really the one the user wants */
319 rc = mutt_save_confirm(buf_string(buf), &st);
320 if (rc == 1)
321 {
322 prompt = _("Save to file: ");
323 continue;
324 }
325 else if (rc == -1)
326 {
327 goto cleanup;
328 }
329 buf_copy(tfile, buf);
330 }
331 else
332 {
333 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, directory);
334 if (rc == -1)
335 {
336 goto cleanup;
337 }
338 else if (rc == 1)
339 {
340 prompt = _("Save to file: ");
341 continue;
342 }
343 }
344
345 mutt_message(_("Saving..."));
346 if (save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
347 (e || !is_message) ? e : b->email) == 0)
348 {
349 // This uses ngettext to avoid duplication of messages
350 int num = 1;
351 mutt_message(ngettext("Attachment saved", "%d attachments saved", num), num);
352 rc = 0;
353 goto cleanup;
354 }
355 else
356 {
357 prompt = _("Save to file: ");
358 continue;
359 }
360 }
361
362cleanup:
363 buf_pool_release(&buf);
364 buf_pool_release(&tfile);
365 return rc;
366}
367
376static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
377{
379 int rc = -1;
380 struct Buffer *buf = buf_pool_get();
381 struct Buffer *tfile = buf_pool_get();
382
383 if (b->filename)
384 {
385 buf_strcpy(buf, b->filename);
386 }
387 else if (has_a_message(b))
388 {
389 mutt_default_save(buf, b->email);
390 }
391
392 prepend_savedir(buf);
393 expand_path(buf, false);
394
395 bool is_message = (fp && has_a_message(b));
396
397 if (is_message)
398 {
399 buf_copy(tfile, buf);
400 }
401 else
402 {
403 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL);
404 if (rc == -1) // abort or cancel
405 goto cleanup;
406 }
407
408 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
409 (e || !is_message) ? e : b->email);
410
411cleanup:
412 buf_pool_release(&buf);
413 buf_pool_release(&tfile);
414 return rc;
415}
416
426void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
427 struct Body *b, struct Email *e, struct Menu *menu)
428{
429 char *directory = NULL;
430 int rc = 1;
431 int last = menu_get_index(menu);
432 FILE *fp_out = NULL;
433 int saved_attachments = 0;
434
435 struct Buffer *buf = buf_pool_get();
436 struct Buffer *tfile = buf_pool_get();
437
438 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
439 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
440 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
441
442 for (int i = 0; !tag || (i < actx->idxlen); i++)
443 {
444 if (tag)
445 {
446 fp = actx->idx[i]->fp;
447 b = actx->idx[i]->body;
448 }
449 if (!tag || b->tagged)
450 {
451 if (c_attach_split)
452 {
453 if (tag && menu && b->aptr)
454 {
455 menu_set_index(menu, b->aptr->num);
457
458 menu_redraw(menu);
459 }
460 if (c_attach_save_without_prompting)
461 {
462 // Save each file, with no prompting, using the configured 'AttachSaveDir'
463 rc = save_without_prompting(fp, b, e);
464 if (rc == 0)
465 saved_attachments++;
466 }
467 else
468 {
469 // Save each file, prompting the user for the location each time.
470 if (query_save_attachment(fp, b, e, &directory) == -1)
471 break;
472 }
473 }
474 else
475 {
477
478 if (buf_is_empty(buf))
479 {
481 prepend_savedir(buf);
482
483 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
484 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
485 &CompleteFileOps, &cdata) != 0) ||
486 buf_is_empty(buf))
487 {
488 goto cleanup;
489 }
490 expand_path(buf, false);
491 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
492 goto cleanup;
493 }
494 else
495 {
496 opt = MUTT_SAVE_APPEND;
497 }
498
499 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
500 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
501 {
502 fprintf(fp_out, "%s", c_attach_sep);
503 mutt_file_fclose(&fp_out);
504 }
505 }
506 }
507 if (!tag)
508 break;
509 }
510
511 FREE(&directory);
512
513 if (tag && menu)
514 {
515 menu_set_index(menu, last);
517 }
518
519 if (rc == 0)
520 {
521 if (!c_attach_split)
522 saved_attachments = 1;
523
524 if (!c_attach_split || c_attach_save_without_prompting)
525 {
526 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
527 saved_attachments);
528 }
529 }
530
531cleanup:
532 buf_pool_release(&buf);
533 buf_pool_release(&tfile);
534}
535
543static void query_pipe_attachment(const char *command, FILE *fp, struct Body *b, bool filter)
544{
545 struct Buffer *tfile = buf_pool_get();
546
547 if (filter)
548 {
549 char warning[PATH_MAX + 256];
550 snprintf(warning, sizeof(warning),
551 _("WARNING! You are about to overwrite %s, continue?"), b->filename);
552 if (query_yesorno(warning, MUTT_NO) != MUTT_YES)
553 {
554 msgwin_clear_text(NULL);
555 buf_pool_release(&tfile);
556 return;
557 }
558 buf_mktemp(tfile);
559 }
560
561 if (mutt_pipe_attachment(fp, b, command, buf_string(tfile)))
562 {
563 if (filter)
564 {
568 mutt_message(_("Attachment filtered"));
569 }
570 }
571 else
572 {
573 if (filter && !buf_is_empty(tfile))
575 }
576 buf_pool_release(&tfile);
577}
578
585static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
586{
587 if (!state || !state->fp_out)
588 return;
589
590 FILE *fp_in = NULL;
591 FILE *fp_unstuff = NULL;
592 bool is_flowed = false, unlink_unstuff = false;
593 struct Buffer *unstuff_tempfile = NULL;
594
596 {
597 is_flowed = true;
598 unstuff_tempfile = buf_pool_get();
599 buf_mktemp(unstuff_tempfile);
600 }
601
602 if (fp)
603 {
604 state->fp_in = fp;
605
606 if (is_flowed)
607 {
608 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
609 if (!fp_unstuff)
610 {
611 mutt_perror("mutt_file_fopen");
612 goto bail;
613 }
614 unlink_unstuff = true;
615
616 FILE *filter_fp = state->fp_out;
617 state->fp_out = fp_unstuff;
618 mutt_decode_attachment(b, state);
619 mutt_file_fclose(&fp_unstuff);
620 state->fp_out = filter_fp;
621
622 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
623 if (!fp_unstuff)
624 {
625 mutt_perror("mutt_file_fopen");
626 goto bail;
627 }
628 mutt_file_copy_stream(fp_unstuff, filter_fp);
629 mutt_file_fclose(&fp_unstuff);
630 }
631 else
632 {
633 mutt_decode_attachment(b, state);
634 }
635 }
636 else
637 {
638 const char *infile = NULL;
639
640 if (is_flowed)
641 {
642 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile), 0, NULL) == -1)
643 goto bail;
644 unlink_unstuff = true;
646 infile = buf_string(unstuff_tempfile);
647 }
648 else
649 {
650 infile = b->filename;
651 }
652
653 fp_in = mutt_file_fopen(infile, "r");
654 if (!fp_in)
655 {
656 mutt_perror("fopen");
657 goto bail;
658 }
659 mutt_file_copy_stream(fp_in, state->fp_out);
660 mutt_file_fclose(&fp_in);
661 }
662
663 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
664 if (c_attach_sep)
665 state_puts(state, c_attach_sep);
666
667bail:
668 mutt_file_fclose(&fp_unstuff);
669 mutt_file_fclose(&fp_in);
670
671 if (unlink_unstuff)
672 mutt_file_unlink(buf_string(unstuff_tempfile));
673 buf_pool_release(&unstuff_tempfile);
674}
675
686static void pipe_attachment_list(const char *command, struct AttachCtx *actx,
687 FILE *fp, bool tag, struct Body *top,
688 bool filter, struct State *state)
689{
690 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
691 for (int i = 0; !tag || (i < actx->idxlen); i++)
692 {
693 if (tag)
694 {
695 fp = actx->idx[i]->fp;
696 top = actx->idx[i]->body;
697 }
698 if (!tag || top->tagged)
699 {
700 if (!filter && !c_attach_split)
701 pipe_attachment(fp, top, state);
702 else
703 query_pipe_attachment(command, fp, top, filter);
704 }
705 if (!tag)
706 break;
707 }
708}
709
718void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
719 struct Body *b, bool filter)
720{
721 struct State state = { 0 };
722 struct Buffer *buf = NULL;
723
724 if (fp)
725 filter = false; /* sanity check: we can't filter in the recv case yet */
726
727 buf = buf_pool_get();
728 /* perform charset conversion on text attachments when piping */
729 state.flags = STATE_CHARCONV;
730
731 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
733 {
734 goto cleanup;
735 }
736
737 if (buf_is_empty(buf))
738 goto cleanup;
739
740 expand_path(buf, false);
741
742 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
743 if (!filter && !c_attach_split)
744 {
745 mutt_endwin();
746 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL,
747 NeoMutt->env);
748 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
749 mutt_file_fclose(&state.fp_out);
750 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
751 if ((filter_wait(pid) != 0) || c_wait_key)
753 }
754 else
755 {
756 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
757 }
758
759cleanup:
760 buf_pool_release(&buf);
761}
762
770static bool can_print(struct AttachCtx *actx, struct Body *b, bool tag)
771{
772 char type[256] = { 0 };
773
774 for (int i = 0; !tag || (i < actx->idxlen); i++)
775 {
776 if (tag)
777 b = actx->idx[i]->body;
778 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
779 if (!tag || b->tagged)
780 {
781 if (!mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
782 {
783 if (!mutt_istr_equal("text/plain", b->subtype) &&
784 !mutt_istr_equal("application/postscript", b->subtype))
785 {
786 if (!mutt_can_decode(b))
787 {
788 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
789 application/octet-stream. */
790 mutt_error(_("I don't know how to print %s attachments"), type);
791 return false;
792 }
793 }
794 }
795 }
796 if (!tag)
797 break;
798 }
799 return true;
800}
801
810static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
811 struct Body *b, struct State *state)
812{
813 char type[256] = { 0 };
814
815 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
816 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
817
818 for (int i = 0; !tag || (i < actx->idxlen); i++)
819 {
820 if (tag)
821 {
822 fp = actx->idx[i]->fp;
823 b = actx->idx[i]->body;
824 }
825 if (!tag || b->tagged)
826 {
827 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
828 if (!c_attach_split && !mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
829 {
830 if (mutt_istr_equal("text/plain", b->subtype) ||
831 mutt_istr_equal("application/postscript", b->subtype))
832 {
833 pipe_attachment(fp, b, state);
834 }
835 else if (mutt_can_decode(b))
836 {
837 /* decode and print */
838
839 FILE *fp_in = NULL;
840 struct Buffer *newfile = buf_pool_get();
841
842 buf_mktemp(newfile);
843 if (mutt_decode_save_attachment(fp, b, buf_string(newfile),
845 {
846 if (!state->fp_out)
847 {
848 mutt_error("BUG in print_attachment_list(). Please report this. ");
850 buf_pool_release(&newfile);
851 return;
852 }
853
854 fp_in = mutt_file_fopen(buf_string(newfile), "r");
855 if (fp_in)
856 {
857 mutt_file_copy_stream(fp_in, state->fp_out);
858 mutt_file_fclose(&fp_in);
859 if (c_attach_sep)
860 state_puts(state, c_attach_sep);
861 }
862 }
864 buf_pool_release(&newfile);
865 }
866 }
867 else
868 {
870 }
871 }
872 if (!tag)
873 break;
874 }
875}
876
884void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
885{
886 char prompt[128] = { 0 };
887 struct State state = { 0 };
888 int tagmsgcount = 0;
889
890 if (tag)
891 for (int i = 0; i < actx->idxlen; i++)
892 if (actx->idx[i]->body->tagged)
893 tagmsgcount++;
894
895 snprintf(prompt, sizeof(prompt),
896 tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
897 _("Print attachment?"),
898 tagmsgcount);
899 if (query_quadoption(prompt, NeoMutt->sub, "print") != MUTT_YES)
900 return;
901
902 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
903 if (c_attach_split)
904 {
905 print_attachment_list(actx, fp, tag, b, &state);
906 }
907 else
908 {
909 if (!can_print(actx, b, tag))
910 return;
911 mutt_endwin();
912 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
913 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL,
914 NULL, NeoMutt->env);
915 print_attachment_list(actx, fp, tag, b, &state);
916 mutt_file_fclose(&state.fp_out);
917 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
918 if ((filter_wait(pid) != 0) || c_wait_key)
920 }
921}
922
929void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
930{
931 struct AttachPtr *cur_att = current_attachment(actx, menu);
932 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
933 return;
934
935 /* The mutt_update_recvattach_menu() will overwrite any changes
936 * made to a decrypted cur_att->body, so warn the user. */
937 if (cur_att->decrypted)
938 {
939 mutt_message(_("Structural changes to decrypted attachments are not supported"));
940 mutt_sleep(1);
941 }
942 /* Editing the content type can rewrite the body structure. */
943 for (int i = 0; i < actx->idxlen; i++)
944 actx->idx[i]->body = NULL;
946 mutt_update_recvattach_menu(actx, menu, true);
947}
948
959int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op,
960 struct Email *e, struct AttachCtx *actx, bool recv)
961{
962 do
963 {
964 switch (op)
965 {
966 case OP_DISPLAY_HEADERS:
967 bool_str_toggle(NeoMutt->sub, "weed", NULL);
969
970 case OP_ATTACHMENT_VIEW:
971 {
972 struct AttachPtr *cur_att = current_attachment(actx, menu);
973 if (!cur_att->fp)
974 {
975 if (cur_att->body->type == TYPE_MULTIPART)
976 {
977 struct Body *b = cur_att->body->parts;
978 while (b && b->parts)
979 b = b->parts;
980 if (b)
981 cur_att = b->aptr;
982 }
983 }
984 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
985 e, actx, menu->win);
986 break;
987 }
988
989 case OP_NEXT_ENTRY:
990 case OP_MAIN_NEXT_UNDELETED: /* hack */
991 {
992 const int index = menu_get_index(menu) + 1;
993 if (index < menu->max)
994 {
995 menu_set_index(menu, index);
996 op = OP_ATTACHMENT_VIEW;
997 }
998 else
999 {
1000 op = OP_NULL;
1001 }
1002 break;
1003 }
1004
1005 case OP_PREV_ENTRY:
1006 case OP_MAIN_PREV_UNDELETED: /* hack */
1007 {
1008 const int index = menu_get_index(menu) - 1;
1009 if (index >= 0)
1010 {
1011 menu_set_index(menu, index);
1012 op = OP_ATTACHMENT_VIEW;
1013 }
1014 else
1015 {
1016 op = OP_NULL;
1017 }
1018 break;
1019 }
1020
1021 case OP_ATTACHMENT_EDIT_TYPE:
1022 {
1023 struct AttachPtr *cur_att = current_attachment(actx, menu);
1024 /* when we edit the content-type, we should redisplay the attachment
1025 * immediately */
1026 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1027 if (recv)
1028 recvattach_edit_content_type(actx, menu, e);
1029 else
1030 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1031
1033 op = OP_ATTACHMENT_VIEW;
1034 break;
1035 }
1036 /* functions which are passed through from the pager */
1037 case OP_PIPE:
1038 {
1039 struct AttachPtr *cur_att = current_attachment(actx, menu);
1040 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1041 op = OP_ATTACHMENT_VIEW;
1042 break;
1043 }
1044 case OP_ATTACHMENT_PRINT:
1045 {
1046 struct AttachPtr *cur_att = current_attachment(actx, menu);
1047 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1048 op = OP_ATTACHMENT_VIEW;
1049 break;
1050 }
1051 case OP_ATTACHMENT_SAVE:
1052 {
1053 struct AttachPtr *cur_att = current_attachment(actx, menu);
1054 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1055 op = OP_ATTACHMENT_VIEW;
1056 break;
1057 }
1058 case OP_CHECK_TRADITIONAL:
1060 {
1061 op = OP_NULL;
1062 break;
1063 }
1065
1066 case OP_ATTACHMENT_COLLAPSE:
1067 if (recv)
1068 return op;
1070
1071 default:
1072 op = OP_NULL;
1073 }
1074 } while (op != OP_NULL);
1075
1076 return op;
1077}
1078
1089void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e,
1090 struct Body *b, FILE *fp, int parent_type,
1091 int level, bool decrypted)
1092{
1093 struct Body *bp = NULL;
1094 struct Body *new_body = NULL;
1095 FILE *fp_new = NULL;
1097
1098 for (bp = b; bp; bp = bp->next)
1099 {
1100 bool need_secured = false;
1101 bool secured = false;
1102
1104 {
1105 need_secured = true;
1106
1107 if (type & SEC_ENCRYPT)
1108 {
1110 goto decrypt_failed;
1111
1112 if (e->env)
1114 }
1115
1116 secured = (crypt_smime_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1117 /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1118 * text/plain type will still be returned by mutt_read_mime_header().
1119 * We can't distinguish an actual part from a failure, so only use a
1120 * text/plain that results from a single top-level part. */
1121 if (secured && (new_body->type == TYPE_TEXT) &&
1122 mutt_istr_equal("plain", new_body->subtype) && ((b != bp) || bp->next))
1123 {
1124 mutt_body_free(&new_body);
1125 mutt_file_fclose(&fp_new);
1126 goto decrypt_failed;
1127 }
1128
1129 if (secured && (type & SEC_ENCRYPT))
1130 e->security |= SMIME_ENCRYPT;
1131 }
1132
1133 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1135 {
1136 need_secured = true;
1137
1139 goto decrypt_failed;
1140
1141 secured = (crypt_pgp_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1142
1143 if (secured)
1144 e->security |= PGP_ENCRYPT;
1145 }
1146
1147 if (need_secured && secured)
1148 {
1149 mutt_actx_add_fp(actx, fp_new);
1150 mutt_actx_add_body(actx, new_body);
1151 mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1152 continue;
1153 }
1154
1155 decrypt_failed:
1156 /* Fall through and show the original parts if decryption fails */
1157 if (need_secured && !secured)
1158 mutt_error(_("Can't decrypt encrypted message"));
1159
1160 struct AttachPtr *ap = mutt_aptr_new();
1161 mutt_actx_add_attach(actx, ap);
1162
1163 ap->body = bp;
1164 ap->fp = fp;
1165 bp->aptr = ap;
1167 ap->level = level;
1168 ap->decrypted = decrypted;
1169
1170 if (mutt_is_message_type(bp->type, bp->subtype))
1171 {
1172 mutt_generate_recvattach_list(actx, bp->email, bp->parts, fp, bp->type,
1173 level + 1, decrypted);
1174 e->security |= bp->email->security;
1175 }
1176 else
1177 {
1178 mutt_generate_recvattach_list(actx, e, bp->parts, fp, bp->type, level + 1, decrypted);
1179 }
1180 }
1181}
1182
1187void mutt_attach_init(struct AttachCtx *actx)
1188{
1189 /* Collapse the attachments if '$digest_collapse' is set AND if...
1190 * the outer container is of type 'multipart/digest' */
1191 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1192
1193 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1194 for (int i = 0; i < actx->idxlen; i++)
1195 {
1196 actx->idx[i]->body->tagged = false;
1197
1198 /* OR an inner container is of type 'multipart/digest' */
1199 actx->idx[i]->collapsed = (c_digest_collapse &&
1200 (digest ||
1201 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1202 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1203 }
1204}
1205
1212void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
1213{
1214 if (init)
1215 {
1216 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1217 actx->fp_root, -1, 0, 0);
1218 mutt_attach_init(actx);
1219 }
1220
1221 mutt_update_tree(actx);
1222
1223 menu->max = actx->vcount;
1224
1225 const int index = menu_get_index(menu);
1226 if (index >= menu->max)
1227 menu_set_index(menu, menu->max - 1);
1229}
1230
1239int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
1240{
1241 if (!ba || !actx || !menu)
1242 return -1;
1243
1244 if (menu->tag_prefix)
1245 {
1246 for (int i = 0; i < actx->idxlen; i++)
1247 {
1248 struct Body *b = actx->idx[i]->body;
1249 if (b->tagged)
1250 {
1251 ARRAY_ADD(ba, b);
1252 }
1253 }
1254 }
1255 else
1256 {
1257 struct AttachPtr *cur = current_attachment(actx, menu);
1258 if (!cur)
1259 return -1;
1260
1261 ARRAY_ADD(ba, cur->body);
1262 }
1263
1264 return ARRAY_SIZE(ba);
1265}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
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:229
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:291
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:668
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:601
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition buffer.c:509
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:609
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:443
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:504
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:210
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition cryptglue.c:454
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:432
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:173
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:151
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition draw.c:482
Edit a string.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:43
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:1506
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1072
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:222
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition file.c:1261
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
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:270
#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:1893
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1933
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition lib.h:58
@ HC_EXT_COMMAND
External commands.
Definition lib.h:55
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition exec.c:214
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.
#define MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:57
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:188
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:164
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:178
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition lib.h:58
@ 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:518
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:220
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:209
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:58
#define STATE_CHARCONV
Do character set conversions.
Definition state.h:37
#define STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition state.h:38
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:674
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:662
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:57
@ MUTT_SAVE_APPEND
Append to existing file.
Definition mutt_attach.h:59
@ MUTT_SAVE_NO_FLAGS
Overwrite existing file (the default)
Definition mutt_attach.h:58
@ MUTT_VA_REGULAR
View using default method.
Definition mutt_attach.h:44
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:786
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:121
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:523
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition muttlib.c:689
Some miscellaneous functions.
API for encryption/signing of emails.
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:84
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:100
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:104
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:99
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:86
#define SMIME_ENCRYPT
Email is S/MIME encrypted.
Definition lib.h:110
#define WithCrypto
Definition lib.h:124
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:378
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:326
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_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:226
static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct State *state)
Print a list of Attachments.
Definition recvattach.c:810
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:543
static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
Save the attachment, without prompting each time.
Definition recvattach.c:376
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition recvattach.c:426
static void pipe_attachment_list(const char *command, struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter, struct State *state)
Pipe a list of attachments to a command.
Definition recvattach.c:686
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:959
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition recvattach.c:167
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, bool filter)
Pipe a list of attachments to a command.
Definition recvattach.c:718
static bool can_print(struct AttachCtx *actx, struct Body *b, bool tag)
Do we know how to print this attachment type?
Definition recvattach.c:770
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition recvattach.c:585
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:116
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition recvattach.c:884
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:272
static bool has_a_message(struct Body *b)
Determine if the Body has a message (to save)
Definition recvattach.c:195
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition recvattach.c:85
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition recvattach.c:929
int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
Get an array of tagged Attachments.
Routines for managing attachments.
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition rfc3676.c:522
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition rfc3676.c:398
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:421
#define NONULL(x)
Definition string2.h:44
A set of attachments.
Definition attach.h:63
short vcount
The number of virtual attachments.
Definition attach.h:72
FILE * fp_root
Used by recvattach for updating.
Definition attach.h:65
struct Email * email
Used by recvattach for updating.
Definition attach.h:64
struct AttachPtr ** idx
Array of attachments.
Definition attach.h:67
short idxlen
Number of attachmentes.
Definition attach.h:68
short * v2r
Mapping from virtual to real attachment.
Definition attach.h:71
An email to which things will be attached.
Definition attach.h:35
struct Body * body
Attachment.
Definition attach.h:36
bool collapsed
Group is collapsed.
Definition attach.h:44
char * tree
Tree characters to display.
Definition attach.h:39
int num
Attachment index number.
Definition attach.h:41
int level
Nesting depth of attachment.
Definition attach.h:40
FILE * fp
Used in the recvattach menu.
Definition attach.h:37
bool decrypted
Not part of message as stored in the email->body.
Definition attach.h:43
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition attach.h:38
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:80
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:88
bool tag_prefix
User has pressed <tag-prefix>
Definition lib.h:86
int max
Number of entries in the menu.
Definition lib.h:82
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:58
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Keep track when processing files.
Definition state.h:48
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:52
FILE * fp_out
File to write to.
Definition state.h:50
FILE * fp_in
File to read from.
Definition state.h:49
#define buf_mktemp(buf)
Definition tmp.h:33