NeoMutt  2024-11-14-34-g5aaf0d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
recvattach.c
Go to the documentation of this file.
1
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 "mutt.h"
49#include "recvattach.h"
50#include "browser/lib.h"
51#include "editor/lib.h"
52#include "history/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 "globals.h"
60#include "handler.h"
61#include "hook.h"
62#include "mailcap.h"
63#include "mutt_attach.h"
64#include "mutt_thread.h"
65#include "muttlib.h"
66#include "rfc3676.h"
67#ifdef ENABLE_NLS
68#include <libintl.h>
69#endif
70
77struct AttachPtr *current_attachment(struct AttachCtx *actx, struct Menu *menu)
78{
79 const int virt = menu_get_index(menu);
80 const int index = actx->v2r[virt];
81
82 return actx->idx[index];
83}
84
91static void mutt_update_v2r(struct AttachCtx *actx)
92{
93 int vindex, rindex, curlevel;
94
95 vindex = 0;
96 rindex = 0;
97
98 while (rindex < actx->idxlen)
99 {
100 actx->v2r[vindex++] = rindex;
101 if (actx->idx[rindex]->collapsed)
102 {
103 curlevel = actx->idx[rindex]->level;
104 do
105 {
106 rindex++;
107 } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
108 }
109 else
110 {
111 rindex++;
112 }
113 }
114
115 actx->vcount = vindex;
116}
117
122void mutt_update_tree(struct AttachCtx *actx)
123{
124 char buf[256] = { 0 };
125 char *s = NULL;
126
127 mutt_update_v2r(actx);
128
129 for (int vindex = 0; vindex < actx->vcount; vindex++)
130 {
131 const int rindex = actx->v2r[vindex];
132 actx->idx[rindex]->num = vindex;
133 if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
134 {
135 if (actx->idx[rindex]->level)
136 {
137 s = buf + 2 * (actx->idx[rindex]->level - 1);
138 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
139 *s++ = MUTT_TREE_HLINE;
140 *s++ = MUTT_TREE_RARROW;
141 }
142 else
143 {
144 s = buf;
145 }
146 *s = '\0';
147 }
148
149 if (actx->idx[rindex]->tree)
150 {
151 if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
152 mutt_str_replace(&actx->idx[rindex]->tree, buf);
153 }
154 else
155 {
156 actx->idx[rindex]->tree = mutt_str_dup(buf);
157 }
158
159 if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
160 actx->idx[rindex]->level)
161 {
162 s = buf + 2 * (actx->idx[rindex]->level - 1);
163 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_VLINE : MUTT_TREE_SPACE;
164 *s++ = MUTT_TREE_SPACE;
165 }
166 }
167}
168
173static void prepend_savedir(struct Buffer *buf)
174{
175 if (!buf || !buf->data || (buf->data[0] == '/'))
176 return;
177
178 struct Buffer *tmp = buf_pool_get();
179 const char *const c_attach_save_dir = cs_subset_path(NeoMutt->sub, "attach_save_dir");
180 if (c_attach_save_dir)
181 {
182 buf_addstr(tmp, c_attach_save_dir);
183 if (tmp->dptr[-1] != '/')
184 buf_addch(tmp, '/');
185 }
186 else
187 {
188 buf_addstr(tmp, "./");
189 }
190
191 buf_addstr(tmp, buf_string(buf));
192 buf_copy(buf, tmp);
193 buf_pool_release(&tmp);
194}
195
201static bool has_a_message(struct Body *b)
202{
203 return (b->email && (b->encoding != ENC_BASE64) && (b->encoding != ENC_QUOTED_PRINTABLE) &&
205}
206
232static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path,
233 enum SaveAttach flags, struct Email *e)
234{
235 int rc = -1;
236
238 {
239 struct Body b_fake = { 0 };
240
241 struct Buffer *tempfile = buf_pool_get();
242 buf_mktemp(tempfile);
243
244 /* Pass MUTT_SAVE_NO_FLAGS to force mutt_file_fopen("w") */
245 rc = mutt_save_attachment(fp, b, buf_string(tempfile), MUTT_SAVE_NO_FLAGS, e);
246 if (rc != 0)
247 goto cleanup;
248
250
251 /* Now "really" save it. Send mode does this without touching anything,
252 * so force send-mode. */
253 memset(&b_fake, 0, sizeof(struct Body));
254 b_fake.filename = tempfile->data;
255 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
256
257 mutt_file_unlink(buf_string(tempfile));
258
259 cleanup:
260 buf_pool_release(&tempfile);
261 }
262 else
263 {
264 rc = mutt_save_attachment(fp, b, path, flags, e);
265 }
266
267 return rc;
268}
269
279static int query_save_attachment(FILE *fp, struct Body *b, struct Email *e, char **directory)
280{
281 char *prompt = NULL;
283 int rc = -1;
284
285 struct Buffer *buf = buf_pool_get();
286 struct Buffer *tfile = buf_pool_get();
287
288 if (b->filename)
289 {
290 if (directory && *directory)
291 {
292 buf_concat_path(buf, *directory, mutt_path_basename(b->filename));
293 }
294 else
295 {
296 buf_strcpy(buf, b->filename);
297 }
298 }
299 else if (has_a_message(b))
300 {
301 mutt_default_save(buf, b->email);
302 }
303
304 prepend_savedir(buf);
305
306 prompt = _("Save to file: ");
307 while (prompt)
308 {
309 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
310 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_FILE, &CompleteFileOps, &cdata) != 0) ||
311 buf_is_empty(buf))
312 {
313 goto cleanup;
314 }
315
316 prompt = NULL;
317 buf_expand_path(buf);
318
319 bool is_message = (fp && has_a_message(b));
320
321 if (is_message)
322 {
323 struct stat st = { 0 };
324
325 /* check to make sure that this file is really the one the user wants */
326 rc = mutt_save_confirm(buf_string(buf), &st);
327 if (rc == 1)
328 {
329 prompt = _("Save to file: ");
330 continue;
331 }
332 else if (rc == -1)
333 {
334 goto cleanup;
335 }
336 buf_copy(tfile, buf);
337 }
338 else
339 {
340 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, directory);
341 if (rc == -1)
342 {
343 goto cleanup;
344 }
345 else if (rc == 1)
346 {
347 prompt = _("Save to file: ");
348 continue;
349 }
350 }
351
352 mutt_message(_("Saving..."));
353 if (save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
354 (e || !is_message) ? e : b->email) == 0)
355 {
356 // This uses ngettext to avoid duplication of messages
357 int num = 1;
358 mutt_message(ngettext("Attachment saved", "%d attachments saved", num), num);
359 rc = 0;
360 goto cleanup;
361 }
362 else
363 {
364 prompt = _("Save to file: ");
365 continue;
366 }
367 }
368
369cleanup:
370 buf_pool_release(&buf);
371 buf_pool_release(&tfile);
372 return rc;
373}
374
383static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
384{
386 int rc = -1;
387 struct Buffer *buf = buf_pool_get();
388 struct Buffer *tfile = buf_pool_get();
389
390 if (b->filename)
391 {
392 buf_strcpy(buf, b->filename);
393 }
394 else if (has_a_message(b))
395 {
396 mutt_default_save(buf, b->email);
397 }
398
399 prepend_savedir(buf);
400 buf_expand_path(buf);
401
402 bool is_message = (fp && has_a_message(b));
403
404 if (is_message)
405 {
406 buf_copy(tfile, buf);
407 }
408 else
409 {
410 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL);
411 if (rc == -1) // abort or cancel
412 goto cleanup;
413 }
414
415 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
416 (e || !is_message) ? e : b->email);
417
418cleanup:
419 buf_pool_release(&buf);
420 buf_pool_release(&tfile);
421 return rc;
422}
423
433void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
434 struct Body *b, struct Email *e, struct Menu *menu)
435{
436 char *directory = NULL;
437 int rc = 1;
438 int last = menu_get_index(menu);
439 FILE *fp_out = NULL;
440 int saved_attachments = 0;
441
442 struct Buffer *buf = buf_pool_get();
443 struct Buffer *tfile = buf_pool_get();
444
445 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
446 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
447 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
448
449 for (int i = 0; !tag || (i < actx->idxlen); i++)
450 {
451 if (tag)
452 {
453 fp = actx->idx[i]->fp;
454 b = actx->idx[i]->body;
455 }
456 if (!tag || b->tagged)
457 {
458 if (c_attach_split)
459 {
460 if (tag && menu && b->aptr)
461 {
462 menu_set_index(menu, b->aptr->num);
464
465 menu_redraw(menu);
466 }
467 if (c_attach_save_without_prompting)
468 {
469 // Save each file, with no prompting, using the configured 'AttachSaveDir'
470 rc = save_without_prompting(fp, b, e);
471 if (rc == 0)
472 saved_attachments++;
473 }
474 else
475 {
476 // Save each file, prompting the user for the location each time.
477 if (query_save_attachment(fp, b, e, &directory) == -1)
478 break;
479 }
480 }
481 else
482 {
484
485 if (buf_is_empty(buf))
486 {
488 prepend_savedir(buf);
489
490 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
491 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
492 &CompleteFileOps, &cdata) != 0) ||
493 buf_is_empty(buf))
494 {
495 goto cleanup;
496 }
497 buf_expand_path(buf);
498 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
499 goto cleanup;
500 }
501 else
502 {
503 opt = MUTT_SAVE_APPEND;
504 }
505
506 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
507 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
508 {
509 fprintf(fp_out, "%s", c_attach_sep);
510 mutt_file_fclose(&fp_out);
511 }
512 }
513 }
514 if (!tag)
515 break;
516 }
517
518 FREE(&directory);
519
520 if (tag && menu)
521 {
522 menu_set_index(menu, last);
524 }
525
526 if (rc == 0)
527 {
528 if (!c_attach_split)
529 saved_attachments = 1;
530
531 if (!c_attach_split || c_attach_save_without_prompting)
532 {
533 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
534 saved_attachments);
535 }
536 }
537
538cleanup:
539 buf_pool_release(&buf);
540 buf_pool_release(&tfile);
541}
542
550static void query_pipe_attachment(const char *command, FILE *fp, struct Body *b, bool filter)
551{
552 struct Buffer *tfile = buf_pool_get();
553
554 if (filter)
555 {
556 char warning[PATH_MAX + 256];
557 snprintf(warning, sizeof(warning),
558 _("WARNING! You are about to overwrite %s, continue?"), b->filename);
559 if (query_yesorno(warning, MUTT_NO) != MUTT_YES)
560 {
561 msgwin_clear_text(NULL);
562 buf_pool_release(&tfile);
563 return;
564 }
565 buf_mktemp(tfile);
566 }
567
568 if (mutt_pipe_attachment(fp, b, command, buf_string(tfile)))
569 {
570 if (filter)
571 {
575 mutt_message(_("Attachment filtered"));
576 }
577 }
578 else
579 {
580 if (filter && !buf_is_empty(tfile))
582 }
583 buf_pool_release(&tfile);
584}
585
592static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
593{
594 if (!state || !state->fp_out)
595 return;
596
597 FILE *fp_in = NULL;
598 FILE *fp_unstuff = NULL;
599 bool is_flowed = false, unlink_unstuff = false;
600 struct Buffer *unstuff_tempfile = NULL;
601
603 {
604 is_flowed = true;
605 unstuff_tempfile = buf_pool_get();
606 buf_mktemp(unstuff_tempfile);
607 }
608
609 if (fp)
610 {
611 state->fp_in = fp;
612
613 if (is_flowed)
614 {
615 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
616 if (!fp_unstuff)
617 {
618 mutt_perror("mutt_file_fopen");
619 goto bail;
620 }
621 unlink_unstuff = true;
622
623 FILE *filter_fp = state->fp_out;
624 state->fp_out = fp_unstuff;
625 mutt_decode_attachment(b, state);
626 mutt_file_fclose(&fp_unstuff);
627 state->fp_out = filter_fp;
628
629 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
630 if (!fp_unstuff)
631 {
632 mutt_perror("mutt_file_fopen");
633 goto bail;
634 }
635 mutt_file_copy_stream(fp_unstuff, filter_fp);
636 mutt_file_fclose(&fp_unstuff);
637 }
638 else
639 {
640 mutt_decode_attachment(b, state);
641 }
642 }
643 else
644 {
645 const char *infile = NULL;
646
647 if (is_flowed)
648 {
649 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile), 0, NULL) == -1)
650 goto bail;
651 unlink_unstuff = true;
653 infile = buf_string(unstuff_tempfile);
654 }
655 else
656 {
657 infile = b->filename;
658 }
659
660 fp_in = mutt_file_fopen(infile, "r");
661 if (!fp_in)
662 {
663 mutt_perror("fopen");
664 goto bail;
665 }
666 mutt_file_copy_stream(fp_in, state->fp_out);
667 mutt_file_fclose(&fp_in);
668 }
669
670 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
671 if (c_attach_sep)
672 state_puts(state, c_attach_sep);
673
674bail:
675 mutt_file_fclose(&fp_unstuff);
676 mutt_file_fclose(&fp_in);
677
678 if (unlink_unstuff)
679 mutt_file_unlink(buf_string(unstuff_tempfile));
680 buf_pool_release(&unstuff_tempfile);
681}
682
693static void pipe_attachment_list(const char *command, struct AttachCtx *actx,
694 FILE *fp, bool tag, struct Body *top,
695 bool filter, struct State *state)
696{
697 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
698 for (int i = 0; !tag || (i < actx->idxlen); i++)
699 {
700 if (tag)
701 {
702 fp = actx->idx[i]->fp;
703 top = actx->idx[i]->body;
704 }
705 if (!tag || top->tagged)
706 {
707 if (!filter && !c_attach_split)
708 pipe_attachment(fp, top, state);
709 else
710 query_pipe_attachment(command, fp, top, filter);
711 }
712 if (!tag)
713 break;
714 }
715}
716
725void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
726 struct Body *b, bool filter)
727{
728 struct State state = { 0 };
729 struct Buffer *buf = NULL;
730
731 if (fp)
732 filter = false; /* sanity check: we can't filter in the recv case yet */
733
734 buf = buf_pool_get();
735 /* perform charset conversion on text attachments when piping */
736 state.flags = STATE_CHARCONV;
737
738 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
740 {
741 goto cleanup;
742 }
743
744 if (buf_is_empty(buf))
745 goto cleanup;
746
747 buf_expand_path(buf);
748
749 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
750 if (!filter && !c_attach_split)
751 {
752 mutt_endwin();
753 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL, EnvList);
754 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
755 mutt_file_fclose(&state.fp_out);
756 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
757 if ((filter_wait(pid) != 0) || c_wait_key)
759 }
760 else
761 {
762 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
763 }
764
765cleanup:
766 buf_pool_release(&buf);
767}
768
776static bool can_print(struct AttachCtx *actx, struct Body *b, bool tag)
777{
778 char type[256] = { 0 };
779
780 for (int i = 0; !tag || (i < actx->idxlen); i++)
781 {
782 if (tag)
783 b = actx->idx[i]->body;
784 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
785 if (!tag || b->tagged)
786 {
787 if (!mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
788 {
789 if (!mutt_istr_equal("text/plain", b->subtype) &&
790 !mutt_istr_equal("application/postscript", b->subtype))
791 {
792 if (!mutt_can_decode(b))
793 {
794 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
795 application/octet-stream. */
796 mutt_error(_("I don't know how to print %s attachments"), type);
797 return false;
798 }
799 }
800 }
801 }
802 if (!tag)
803 break;
804 }
805 return true;
806}
807
816static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
817 struct Body *b, struct State *state)
818{
819 char type[256] = { 0 };
820
821 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
822 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
823
824 for (int i = 0; !tag || (i < actx->idxlen); i++)
825 {
826 if (tag)
827 {
828 fp = actx->idx[i]->fp;
829 b = actx->idx[i]->body;
830 }
831 if (!tag || b->tagged)
832 {
833 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
834 if (!c_attach_split && !mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
835 {
836 if (mutt_istr_equal("text/plain", b->subtype) ||
837 mutt_istr_equal("application/postscript", b->subtype))
838 {
839 pipe_attachment(fp, b, state);
840 }
841 else if (mutt_can_decode(b))
842 {
843 /* decode and print */
844
845 FILE *fp_in = NULL;
846 struct Buffer *newfile = buf_pool_get();
847
848 buf_mktemp(newfile);
849 if (mutt_decode_save_attachment(fp, b, buf_string(newfile),
851 {
852 if (!state->fp_out)
853 {
854 mutt_error("BUG in print_attachment_list(). Please report this. ");
855 return;
856 }
857
858 fp_in = mutt_file_fopen(buf_string(newfile), "r");
859 if (fp_in)
860 {
861 mutt_file_copy_stream(fp_in, state->fp_out);
862 mutt_file_fclose(&fp_in);
863 if (c_attach_sep)
864 state_puts(state, c_attach_sep);
865 }
866 }
868 buf_pool_release(&newfile);
869 }
870 }
871 else
872 {
874 }
875 }
876 if (!tag)
877 break;
878 }
879}
880
888void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
889{
890 char prompt[128] = { 0 };
891 struct State state = { 0 };
892 int tagmsgcount = 0;
893
894 if (tag)
895 for (int i = 0; i < actx->idxlen; i++)
896 if (actx->idx[i]->body->tagged)
897 tagmsgcount++;
898
899 snprintf(prompt, sizeof(prompt),
900 tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
901 _("Print attachment?"),
902 tagmsgcount);
903 if (query_quadoption(prompt, NeoMutt->sub, "print") != MUTT_YES)
904 return;
905
906 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
907 if (c_attach_split)
908 {
909 print_attachment_list(actx, fp, tag, b, &state);
910 }
911 else
912 {
913 if (!can_print(actx, b, tag))
914 return;
915 mutt_endwin();
916 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
917 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL, NULL, EnvList);
918 print_attachment_list(actx, fp, tag, b, &state);
919 mutt_file_fclose(&state.fp_out);
920 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
921 if ((filter_wait(pid) != 0) || c_wait_key)
923 }
924}
925
932void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
933{
934 struct AttachPtr *cur_att = current_attachment(actx, menu);
935 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
936 return;
937
938 /* The mutt_update_recvattach_menu() will overwrite any changes
939 * made to a decrypted cur_att->body, so warn the user. */
940 if (cur_att->decrypted)
941 {
942 mutt_message(_("Structural changes to decrypted attachments are not supported"));
943 mutt_sleep(1);
944 }
945 /* Editing the content type can rewrite the body structure. */
946 for (int i = 0; i < actx->idxlen; i++)
947 actx->idx[i]->body = NULL;
949 mutt_update_recvattach_menu(actx, menu, true);
950}
951
962int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op,
963 struct Email *e, struct AttachCtx *actx, bool recv)
964{
965 do
966 {
967 switch (op)
968 {
969 case OP_DISPLAY_HEADERS:
970 bool_str_toggle(NeoMutt->sub, "weed", NULL);
972
973 case OP_ATTACHMENT_VIEW:
974 {
975 struct AttachPtr *cur_att = current_attachment(actx, menu);
976 if (!cur_att->fp)
977 {
978 if (cur_att->body->type == TYPE_MULTIPART)
979 {
980 struct Body *b = cur_att->body->parts;
981 while (b->parts)
982 b = b->parts;
983 cur_att = b->aptr;
984 }
985 }
986 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
987 e, actx, menu->win);
988 break;
989 }
990
991 case OP_NEXT_ENTRY:
992 case OP_MAIN_NEXT_UNDELETED: /* hack */
993 {
994 const int index = menu_get_index(menu) + 1;
995 if (index < menu->max)
996 {
997 menu_set_index(menu, index);
998 op = OP_ATTACHMENT_VIEW;
999 }
1000 else
1001 {
1002 op = OP_NULL;
1003 }
1004 break;
1005 }
1006
1007 case OP_PREV_ENTRY:
1008 case OP_MAIN_PREV_UNDELETED: /* hack */
1009 {
1010 const int index = menu_get_index(menu) - 1;
1011 if (index >= 0)
1012 {
1013 menu_set_index(menu, index);
1014 op = OP_ATTACHMENT_VIEW;
1015 }
1016 else
1017 {
1018 op = OP_NULL;
1019 }
1020 break;
1021 }
1022
1023 case OP_ATTACHMENT_EDIT_TYPE:
1024 {
1025 struct AttachPtr *cur_att = current_attachment(actx, menu);
1026 /* when we edit the content-type, we should redisplay the attachment
1027 * immediately */
1028 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1029 if (recv)
1030 recvattach_edit_content_type(actx, menu, e);
1031 else
1032 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1033
1035 op = OP_ATTACHMENT_VIEW;
1036 break;
1037 }
1038 /* functions which are passed through from the pager */
1039 case OP_PIPE:
1040 {
1041 struct AttachPtr *cur_att = current_attachment(actx, menu);
1042 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1043 op = OP_ATTACHMENT_VIEW;
1044 break;
1045 }
1046 case OP_ATTACHMENT_PRINT:
1047 {
1048 struct AttachPtr *cur_att = current_attachment(actx, menu);
1049 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1050 op = OP_ATTACHMENT_VIEW;
1051 break;
1052 }
1053 case OP_ATTACHMENT_SAVE:
1054 {
1055 struct AttachPtr *cur_att = current_attachment(actx, menu);
1056 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1057 op = OP_ATTACHMENT_VIEW;
1058 break;
1059 }
1060 case OP_CHECK_TRADITIONAL:
1062 {
1063 op = OP_NULL;
1064 break;
1065 }
1067
1068 case OP_ATTACHMENT_COLLAPSE:
1069 if (recv)
1070 return op;
1072
1073 default:
1074 op = OP_NULL;
1075 }
1076 } while (op != OP_NULL);
1077
1078 return op;
1079}
1080
1091void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e,
1092 struct Body *b, FILE *fp, int parent_type,
1093 int level, bool decrypted)
1094{
1095 struct Body *bp = NULL;
1096 struct Body *new_body = NULL;
1097 FILE *fp_new = NULL;
1099
1100 for (bp = b; bp; bp = bp->next)
1101 {
1102 bool need_secured = false;
1103 bool secured = false;
1104
1106 {
1107 need_secured = true;
1108
1109 if (type & SEC_ENCRYPT)
1110 {
1112 goto decrypt_failed;
1113
1114 if (e->env)
1116 }
1117
1118 secured = (crypt_smime_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1119 /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1120 * text/plain type will still be returned by mutt_read_mime_header().
1121 * We can't distinguish an actual part from a failure, so only use a
1122 * text/plain that results from a single top-level part. */
1123 if (secured && (new_body->type == TYPE_TEXT) &&
1124 mutt_istr_equal("plain", new_body->subtype) && ((b != bp) || bp->next))
1125 {
1126 mutt_body_free(&new_body);
1127 mutt_file_fclose(&fp_new);
1128 goto decrypt_failed;
1129 }
1130
1131 if (secured && (type & SEC_ENCRYPT))
1132 e->security |= SMIME_ENCRYPT;
1133 }
1134
1135 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1137 {
1138 need_secured = true;
1139
1141 goto decrypt_failed;
1142
1143 secured = (crypt_pgp_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1144
1145 if (secured)
1146 e->security |= PGP_ENCRYPT;
1147 }
1148
1149 if (need_secured && secured)
1150 {
1151 mutt_actx_add_fp(actx, fp_new);
1152 mutt_actx_add_body(actx, new_body);
1153 mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1154 continue;
1155 }
1156
1157 decrypt_failed:
1158 /* Fall through and show the original parts if decryption fails */
1159 if (need_secured && !secured)
1160 mutt_error(_("Can't decrypt encrypted message"));
1161
1162 struct AttachPtr *ap = mutt_aptr_new();
1163 mutt_actx_add_attach(actx, ap);
1164
1165 ap->body = bp;
1166 ap->fp = fp;
1167 bp->aptr = ap;
1169 ap->level = level;
1170 ap->decrypted = decrypted;
1171
1172 if (mutt_is_message_type(bp->type, bp->subtype))
1173 {
1174 mutt_generate_recvattach_list(actx, bp->email, bp->parts, fp, bp->type,
1175 level + 1, decrypted);
1176 e->security |= bp->email->security;
1177 }
1178 else
1179 {
1180 mutt_generate_recvattach_list(actx, e, bp->parts, fp, bp->type, level + 1, decrypted);
1181 }
1182 }
1183}
1184
1189void mutt_attach_init(struct AttachCtx *actx)
1190{
1191 /* Collapse the attachments if '$digest_collapse' is set AND if...
1192 * the outer container is of type 'multipart/digest' */
1193 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1194
1195 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1196 for (int i = 0; i < actx->idxlen; i++)
1197 {
1198 actx->idx[i]->body->tagged = false;
1199
1200 /* OR an inner container is of type 'multipart/digest' */
1201 actx->idx[i]->collapsed = (c_digest_collapse &&
1202 (digest ||
1203 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1204 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1205 }
1206}
1207
1214void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
1215{
1216 if (init)
1217 {
1218 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1219 actx->fp_root, -1, 0, 0);
1220 mutt_attach_init(actx);
1221 }
1222
1223 mutt_update_tree(actx);
1224
1225 menu->max = actx->vcount;
1226
1227 const int index = menu_get_index(menu);
1228 if (index >= menu->max)
1229 menu_set_index(menu, menu->max - 1);
1231}
1232
1241int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
1242{
1243 if (!ba || !actx || !menu)
1244 return -1;
1245
1246 if (menu->tag_prefix)
1247 {
1248 for (int i = 0; i < actx->idxlen; i++)
1249 {
1250 struct Body *b = actx->idx[i]->body;
1251 if (b->tagged)
1252 {
1253 ARRAY_ADD(ba, b);
1254 }
1255 }
1256 }
1257 else
1258 {
1259 struct AttachPtr *cur = current_attachment(actx, menu);
1260 if (!cur)
1261 return -1;
1262
1263 ARRAY_ADD(ba, cur->body);
1264 }
1265
1266 return ARRAY_SIZE(ba);
1267}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:156
#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:224
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
Select a Mailbox from a list.
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
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:132
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:480
Edit a string.
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:1498
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1070
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:287
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1371
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:221
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:75
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:274
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_perror(...)
Definition: logging2.h:93
Convenience wrapper for the gui headers.
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1865
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1905
Decide how to display email content.
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition: lib.h:57
@ HC_EXT_COMMAND
External commands.
Definition: lib.h:54
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition: hook.c:778
Parse and execute user-defined hooks.
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:483
RFC1524 Mailcap routines.
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:60
#define FREE(x)
Definition: memory.h:55
GUI present the user with a selectable list.
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:184
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:174
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:57
@ 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 TYPE(body)
Definition: mime.h:89
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:519
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:111
#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:672
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
#define PATH_MAX
Definition: mutt.h:42
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:57
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, const char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:739
int mutt_save_attachment(FILE *fp, struct Body *b, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:907
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1041
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:419
int mutt_print_attachment(FILE *fp, struct Body *b)
Print out an attachment.
Definition: mutt_attach.c:1141
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
No flags set.
Definition: mutt_attach.h:58
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:44
Create/manipulate threading in emails.
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition: mutt_thread.h:58
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:64
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:60
@ MUTT_TREE_VLINE
Vertical line.
Definition: mutt_thread.h:62
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:61
@ MUTT_TREE_SPACE
Blank space.
Definition: mutt_thread.h:63
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:843
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
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:541
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:746
Some miscellaneous functions.
API for encryption/signing of emails.
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define PGP_ENCRYPT
Definition: lib.h:96
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SMIME_ENCRYPT
Definition: lib.h:102
#define WithCrypto
Definition: lib.h:116
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
@ 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:379
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
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.
Definition: recvattach.c:1091
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1214
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:232
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:816
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:550
static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:383
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:433
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:693
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:77
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:962
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:173
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:725
static bool can_print(struct AttachCtx *actx, struct Body *b, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:776
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition: recvattach.c:592
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1189
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:122
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition: recvattach.c:888
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:279
static bool has_a_message(struct Body *b)
Determine if the Body has a message (to save)
Definition: recvattach.c:201
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition: recvattach.c:91
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:932
int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
Get an array of tagged Attachments.
Definition: recvattach.c:1241
Routines for managing attachments.
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:518
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:394
RFC3676 Format Flowed routines.
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:422
#define NONULL(x)
Definition: string2.h:37
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:37
struct Body * body
Attachment.
Definition: attach.h:38
bool collapsed
Group is collapsed.
Definition: attach.h:46
char * tree
Tree characters to display.
Definition: attach.h:41
int num
Attachment index number.
Definition: attach.h:43
int level
Nesting depth of attachment.
Definition: attach.h:42
FILE * fp
Used in the recvattach menu.
Definition: attach.h:39
bool decrypted
Not part of message as stored in the email->body.
Definition: attach.h:45
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:40
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:47
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:40
Definition: lib.h:79
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:86
bool tag_prefix
User has pressed <tag-prefix>
Definition: lib.h:85
int max
Number of entries in the menu.
Definition: lib.h:81
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
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