NeoMutt  2023-03-22-27-g3cb248
Teaching an old dog new tricks
DOXYGEN
recvattach.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <limits.h>
32#include <stdbool.h>
33#include <stdio.h>
34#include <string.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include "mutt/lib.h"
38#include "config/lib.h"
39#include "email/lib.h"
40#include "core/lib.h"
41#include "gui/lib.h"
42#include "mutt.h"
43#include "recvattach.h"
44#include "enter/lib.h"
45#include "menu/lib.h"
46#include "ncrypt/lib.h"
47#include "question/lib.h"
48#include "send/lib.h"
49#include "attach.h"
50#include "external.h"
51#include "handler.h"
52#include "hook.h"
53#include "mailcap.h"
54#include "mutt_attach.h"
55#include "mutt_thread.h"
56#include "muttlib.h"
57#include "opcodes.h"
58#include "rfc3676.h"
59#ifdef ENABLE_NLS
60#include <libintl.h>
61#endif
62
69struct AttachPtr *current_attachment(struct AttachCtx *actx, struct Menu *menu)
70{
71 const int virt = menu_get_index(menu);
72 const int index = actx->v2r[virt];
73
74 return actx->idx[index];
75}
76
83static void mutt_update_v2r(struct AttachCtx *actx)
84{
85 int vindex, rindex, curlevel;
86
87 vindex = 0;
88 rindex = 0;
89
90 while (rindex < actx->idxlen)
91 {
92 actx->v2r[vindex++] = rindex;
93 if (actx->idx[rindex]->collapsed)
94 {
95 curlevel = actx->idx[rindex]->level;
96 do
97 {
98 rindex++;
99 } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
100 }
101 else
102 {
103 rindex++;
104 }
105 }
106
107 actx->vcount = vindex;
108}
109
114void mutt_update_tree(struct AttachCtx *actx)
115{
116 char buf[256] = { 0 };
117 char *s = NULL;
118
119 mutt_update_v2r(actx);
120
121 for (int vindex = 0; vindex < actx->vcount; vindex++)
122 {
123 const int rindex = actx->v2r[vindex];
124 actx->idx[rindex]->num = vindex;
125 if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
126 {
127 if (actx->idx[rindex]->level)
128 {
129 s = buf + 2 * (actx->idx[rindex]->level - 1);
130 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
131 *s++ = MUTT_TREE_HLINE;
132 *s++ = MUTT_TREE_RARROW;
133 }
134 else
135 {
136 s = buf;
137 }
138 *s = '\0';
139 }
140
141 if (actx->idx[rindex]->tree)
142 {
143 if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
144 mutt_str_replace(&actx->idx[rindex]->tree, buf);
145 }
146 else
147 {
148 actx->idx[rindex]->tree = mutt_str_dup(buf);
149 }
150
151 if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
152 actx->idx[rindex]->level)
153 {
154 s = buf + 2 * (actx->idx[rindex]->level - 1);
155 *s++ = (actx->idx[rindex]->body->next) ? '\005' : '\006';
156 *s++ = '\006';
157 }
158 }
159}
160
165static void prepend_savedir(struct Buffer *buf)
166{
167 if (!buf || !buf->data || (buf->data[0] == '/'))
168 return;
169
170 struct Buffer *tmp = mutt_buffer_pool_get();
171 const char *const c_attach_save_dir = cs_subset_path(NeoMutt->sub, "attach_save_dir");
172 if (c_attach_save_dir)
173 {
174 mutt_buffer_addstr(tmp, c_attach_save_dir);
175 if (tmp->dptr[-1] != '/')
176 mutt_buffer_addch(tmp, '/');
177 }
178 else
179 {
180 mutt_buffer_addstr(tmp, "./");
181 }
182
184 mutt_buffer_copy(buf, tmp);
186}
187
193static bool has_a_message(struct Body *body)
194{
195 return (body->email && (body->encoding != ENC_BASE64) &&
196 (body->encoding != ENC_QUOTED_PRINTABLE) &&
197 mutt_is_message_type(body->type, body->subtype));
198}
199
225static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path,
226 enum SaveAttach flags, struct Email *e)
227{
228 int rc = -1;
229
231 {
232 struct Body b_fake = { 0 };
233
234 struct Buffer *tempfile = mutt_buffer_pool_get();
235 mutt_buffer_mktemp(tempfile);
236
237 /* Pass MUTT_SAVE_NO_FLAGS to force mutt_file_fopen("w") */
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
251
252 cleanup:
253 mutt_buffer_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 *body, struct Email *e, char **directory)
273{
274 char *prompt = NULL;
276 int rc = -1;
277
278 struct Buffer *buf = mutt_buffer_pool_get();
279 struct Buffer *tfile = mutt_buffer_pool_get();
280
281 if (body->filename)
282 {
283 if (directory && *directory)
284 {
285 mutt_buffer_concat_path(buf, *directory, mutt_path_basename(body->filename));
286 }
287 else
288 {
289 mutt_buffer_strcpy(buf, body->filename);
290 }
291 }
292 else if (has_a_message(body))
293 {
294 mutt_default_save(buf->data, buf->dsize, body->email);
296 }
297
298 prepend_savedir(buf);
299
300 prompt = _("Save to file: ");
301 while (prompt)
302 {
304 false, NULL, NULL, NULL) != 0) ||
306 {
307 goto cleanup;
308 }
309
310 prompt = NULL;
312
313 bool is_message = (fp && has_a_message(body));
314
315 if (is_message)
316 {
317 struct stat st = { 0 };
318
319 /* check to make sure that this file is really the one the user wants */
321 if (rc == 1)
322 {
323 prompt = _("Save to file: ");
324 continue;
325 }
326 else if (rc == -1)
327 goto cleanup;
328 mutt_buffer_copy(tfile, buf);
329 }
330 else
331 {
332 rc = mutt_check_overwrite(body->filename, mutt_buffer_string(buf), tfile,
333 &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, body, mutt_buffer_string(tfile), opt,
347 (e || !is_message) ? e : body->email) == 0)
348 {
349 // This uses ngettext to avoid duplication of messages
350 mutt_message(ngettext("Attachment saved", "%d attachments saved", 1), 1);
351 rc = 0;
352 goto cleanup;
353 }
354 else
355 {
356 prompt = _("Save to file: ");
357 continue;
358 }
359 }
360
361cleanup:
364 return rc;
365}
366
375static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
376{
378 int rc = -1;
379 struct Buffer *buf = mutt_buffer_pool_get();
380 struct Buffer *tfile = mutt_buffer_pool_get();
381
382 if (body->filename)
383 {
384 mutt_buffer_strcpy(buf, body->filename);
385 }
386 else if (has_a_message(body))
387 {
388 mutt_default_save(buf->data, buf->dsize, body->email);
389 }
390
391 prepend_savedir(buf);
393
394 bool is_message = (fp && has_a_message(body));
395
396 if (is_message)
397 {
398 mutt_buffer_copy(tfile, buf);
399 }
400 else
401 {
402 rc = mutt_check_overwrite(body->filename, mutt_buffer_string(buf), tfile, &opt, NULL);
403 if (rc == -1) // abort or cancel
404 goto cleanup;
405 }
406
407 rc = save_attachment_flowed_helper(fp, body, mutt_buffer_string(tfile), opt,
408 (e || !is_message) ? e : body->email);
409
410cleanup:
413 return rc;
414}
415
425void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
426 struct Body *top, struct Email *e, struct Menu *menu)
427{
428 char *directory = NULL;
429 int rc = 1;
430 int last = menu_get_index(menu);
431 FILE *fp_out = NULL;
432 int saved_attachments = 0;
433
434 struct Buffer *buf = mutt_buffer_pool_get();
435 struct Buffer *tfile = mutt_buffer_pool_get();
436
437 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
438 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
439 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
440
441 for (int i = 0; !tag || (i < actx->idxlen); i++)
442 {
443 if (tag)
444 {
445 fp = actx->idx[i]->fp;
446 top = actx->idx[i]->body;
447 }
448 if (!tag || top->tagged)
449 {
450 if (c_attach_split)
451 {
452 if (tag && menu && top->aptr)
453 {
454 menu_set_index(menu, top->aptr->num);
456
457 menu_redraw(menu);
458 }
459 if (c_attach_save_without_prompting)
460 {
461 // Save each file, with no prompting, using the configured 'AttachSaveDir'
462 rc = save_without_prompting(fp, top, e);
463 if (rc == 0)
464 saved_attachments++;
465 }
466 else
467 {
468 // Save each file, prompting the user for the location each time.
469 if (query_save_attachment(fp, top, e, &directory) == -1)
470 break;
471 }
472 }
473 else
474 {
476
477 if (mutt_buffer_is_empty(buf))
478 {
480 prepend_savedir(buf);
481
482 if ((mutt_buffer_get_field(_("Save to file: "), buf, MUTT_COMP_FILE | MUTT_COMP_CLEAR,
483 false, NULL, NULL, NULL) != 0) ||
485 {
486 goto cleanup;
487 }
489 if (mutt_check_overwrite(top->filename, mutt_buffer_string(buf), tfile, &opt, NULL))
490 goto cleanup;
491 }
492 else
493 {
494 opt = MUTT_SAVE_APPEND;
495 }
496
497 rc = save_attachment_flowed_helper(fp, top, mutt_buffer_string(tfile), opt, e);
498 if ((rc == 0) && c_attach_sep && (fp_out = fopen(mutt_buffer_string(tfile), "a")))
499 {
500 fprintf(fp_out, "%s", c_attach_sep);
501 mutt_file_fclose(&fp_out);
502 }
503 }
504 }
505 if (!tag)
506 break;
507 }
508
509 FREE(&directory);
510
511 if (tag && menu)
512 {
513 menu_set_index(menu, last);
515 }
516
517 if (rc == 0)
518 {
519 if (!c_attach_split)
520 saved_attachments = 1;
521
522 if (!c_attach_split || c_attach_save_without_prompting)
523 {
524 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
525 saved_attachments);
526 }
527 }
528
529cleanup:
532}
533
541static void query_pipe_attachment(const char *command, FILE *fp, struct Body *body, bool filter)
542{
543 char tfile[PATH_MAX] = { 0 };
544
545 if (filter)
546 {
547 char warning[PATH_MAX + 256];
548 snprintf(warning, sizeof(warning),
549 _("WARNING! You are about to overwrite %s, continue?"), body->filename);
550 if (mutt_yesorno(warning, MUTT_NO) != MUTT_YES)
551 {
553 return;
554 }
555 mutt_mktemp(tfile, sizeof(tfile));
556 }
557 else
558 {
559 tfile[0] = '\0';
560 }
561
562 if (mutt_pipe_attachment(fp, body, command, tfile))
563 {
564 if (filter)
565 {
567 mutt_file_rename(tfile, body->filename);
569 mutt_message(_("Attachment filtered"));
570 }
571 }
572 else
573 {
574 if (filter && tfile[0])
575 mutt_file_unlink(tfile);
576 }
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 = mutt_buffer_pool_get();
599 mutt_buffer_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(mutt_buffer_string(unstuff_tempfile), "w");
609 if (fp_unstuff == NULL)
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(mutt_buffer_string(unstuff_tempfile), "r");
623 if (fp_unstuff == NULL)
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, mutt_buffer_string(unstuff_tempfile), 0, NULL) == -1)
643 goto bail;
644 unlink_unstuff = true;
646 infile = mutt_buffer_string(unstuff_tempfile);
647 }
648 else
649 {
650 infile = b->filename;
651 }
652
653 fp_in = 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(mutt_buffer_string(unstuff_tempfile));
673 mutt_buffer_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 for (int i = 0; !tag || (i < actx->idxlen); i++)
691 {
692 if (tag)
693 {
694 fp = actx->idx[i]->fp;
695 top = actx->idx[i]->body;
696 }
697 if (!tag || top->tagged)
698 {
699 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
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 *top, 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 = mutt_buffer_pool_get();
728 /* perform charset conversion on text attachments when piping */
729 state.flags = STATE_CHARCONV;
730
731 if (mutt_buffer_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
732 MUTT_COMP_FILE_SIMPLE, false, NULL, NULL, NULL) != 0)
733 {
734 goto cleanup;
735 }
736
737 if (mutt_buffer_len(buf) == 0)
738 goto cleanup;
739
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(mutt_buffer_string(buf), &state.fp_out, NULL, NULL);
747 pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
748 mutt_file_fclose(&state.fp_out);
749 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
750 if ((filter_wait(pid) != 0) || c_wait_key)
752 }
753 else
754 {
755 pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
756 }
757
758cleanup:
760}
761
769static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
770{
771 char type[256] = { 0 };
772
773 for (int i = 0; !tag || (i < actx->idxlen); i++)
774 {
775 if (tag)
776 top = actx->idx[i]->body;
777 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
778 if (!tag || top->tagged)
779 {
780 if (!mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
781 {
782 if (!mutt_istr_equal("text/plain", top->subtype) &&
783 !mutt_istr_equal("application/postscript", top->subtype))
784 {
785 if (!mutt_can_decode(top))
786 {
787 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
788 application/octet-stream. */
789 mutt_error(_("I don't know how to print %s attachments"), type);
790 return false;
791 }
792 }
793 }
794 }
795 if (!tag)
796 break;
797 }
798 return true;
799}
800
809static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
810 struct Body *top, struct State *state)
811{
812 char type[256] = { 0 };
813
814 for (int i = 0; !tag || (i < actx->idxlen); i++)
815 {
816 if (tag)
817 {
818 fp = actx->idx[i]->fp;
819 top = actx->idx[i]->body;
820 }
821 if (!tag || top->tagged)
822 {
823 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
824 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
825 if (!c_attach_split && !mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
826 {
827 if (mutt_istr_equal("text/plain", top->subtype) ||
828 mutt_istr_equal("application/postscript", top->subtype))
829 {
830 pipe_attachment(fp, top, state);
831 }
832 else if (mutt_can_decode(top))
833 {
834 /* decode and print */
835
836 FILE *fp_in = NULL;
837 struct Buffer *newfile = mutt_buffer_pool_get();
838
839 mutt_buffer_mktemp(newfile);
842 {
843 if (!state->fp_out)
844 {
845 mutt_error("BUG in print_attachment_list(). Please report this. ");
846 return;
847 }
848
849 fp_in = fopen(mutt_buffer_string(newfile), "r");
850 if (fp_in)
851 {
852 mutt_file_copy_stream(fp_in, state->fp_out);
853 mutt_file_fclose(&fp_in);
854 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
855 if (c_attach_sep)
856 state_puts(state, c_attach_sep);
857 }
858 }
860 mutt_buffer_pool_release(&newfile);
861 }
862 }
863 else
864 {
865 mutt_print_attachment(fp, top);
866 }
867 }
868 if (!tag)
869 break;
870 }
871}
872
880void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
881{
882 char prompt[128] = { 0 };
883 struct State state = { 0 };
884 int tagmsgcount = 0;
885
886 if (tag)
887 for (int i = 0; i < actx->idxlen; i++)
888 if (actx->idx[i]->body->tagged)
889 tagmsgcount++;
890
891 snprintf(prompt, sizeof(prompt),
892 tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
893 _("Print attachment?"),
894 tagmsgcount);
895 const enum QuadOption c_print = cs_subset_quad(NeoMutt->sub, "print");
896 if (query_quadoption(c_print, prompt) != MUTT_YES)
897 return;
898
899 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
900 if (c_attach_split)
901 {
902 print_attachment_list(actx, fp, tag, top, &state);
903 }
904 else
905 {
906 if (!can_print(actx, top, tag))
907 return;
908 mutt_endwin();
909 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
910 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL, NULL);
911 print_attachment_list(actx, fp, tag, top, &state);
912 mutt_file_fclose(&state.fp_out);
913 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
914 if ((filter_wait(pid) != 0) || c_wait_key)
916 }
917}
918
925void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
926{
927 struct AttachPtr *cur_att = current_attachment(actx, menu);
928 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
929 return;
930
931 /* The mutt_update_recvattach_menu() will overwrite any changes
932 * made to a decrypted cur_att->body, so warn the user. */
933 if (cur_att->decrypted)
934 {
935 mutt_message(_("Structural changes to decrypted attachments are not supported"));
936 mutt_sleep(1);
937 }
938 /* Editing the content type can rewrite the body structure. */
939 for (int i = 0; i < actx->idxlen; i++)
940 actx->idx[i]->body = NULL;
942 mutt_update_recvattach_menu(actx, menu, true);
943}
944
955int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op,
956 struct Email *e, struct AttachCtx *actx, bool recv)
957{
958 do
959 {
960 switch (op)
961 {
962 case OP_DISPLAY_HEADERS:
963 bool_str_toggle(NeoMutt->sub, "weed", NULL);
964 /* fallthrough */
965
966 case OP_ATTACHMENT_VIEW:
967 {
968 struct AttachPtr *cur_att = current_attachment(actx, menu);
969 if (!cur_att->fp)
970 {
971 if (cur_att->body->type == TYPE_MULTIPART)
972 {
973 struct Body *b = cur_att->body->parts;
974 while (b->parts)
975 b = b->parts;
976 cur_att = b->aptr;
977 }
978 }
979 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
980 e, actx, menu->win);
981 break;
982 }
983
984 case OP_NEXT_ENTRY:
985 case OP_MAIN_NEXT_UNDELETED: /* hack */
986 {
987 const int index = menu_get_index(menu) + 1;
988 if (index < menu->max)
989 {
990 menu_set_index(menu, index);
991 op = OP_ATTACHMENT_VIEW;
992 }
993 else
994 {
995 op = OP_NULL;
996 }
997 break;
998 }
999
1000 case OP_PREV_ENTRY:
1001 case OP_MAIN_PREV_UNDELETED: /* hack */
1002 {
1003 const int index = menu_get_index(menu) - 1;
1004 if (index >= 0)
1005 {
1006 menu_set_index(menu, index);
1007 op = OP_ATTACHMENT_VIEW;
1008 }
1009 else
1010 {
1011 op = OP_NULL;
1012 }
1013 break;
1014 }
1015
1016 case OP_ATTACHMENT_EDIT_TYPE:
1017 {
1018 struct AttachPtr *cur_att = current_attachment(actx, menu);
1019 /* when we edit the content-type, we should redisplay the attachment
1020 * immediately */
1021 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1022 if (recv)
1023 recvattach_edit_content_type(actx, menu, e);
1024 else
1025 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1026
1028 op = OP_ATTACHMENT_VIEW;
1029 break;
1030 }
1031 /* functions which are passed through from the pager */
1032 case OP_PIPE:
1033 {
1034 struct AttachPtr *cur_att = current_attachment(actx, menu);
1035 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1036 op = OP_ATTACHMENT_VIEW;
1037 break;
1038 }
1039 case OP_ATTACHMENT_PRINT:
1040 {
1041 struct AttachPtr *cur_att = current_attachment(actx, menu);
1042 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1043 op = OP_ATTACHMENT_VIEW;
1044 break;
1045 }
1046 case OP_ATTACHMENT_SAVE:
1047 {
1048 struct AttachPtr *cur_att = current_attachment(actx, menu);
1049 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1050 op = OP_ATTACHMENT_VIEW;
1051 break;
1052 }
1053 case OP_CHECK_TRADITIONAL:
1055 {
1056 op = OP_NULL;
1057 break;
1058 }
1059 /* fallthrough */
1060 case OP_ATTACHMENT_COLLAPSE:
1061 if (recv)
1062 return op;
1063 /* fallthrough */
1064 default:
1065 op = OP_NULL;
1066 }
1067 } while (op != OP_NULL);
1068
1069 return op;
1070}
1071
1082void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e,
1083 struct Body *parts, FILE *fp,
1084 int parent_type, int level, bool decrypted)
1085{
1086 struct Body *m = NULL;
1087 struct Body *new_body = NULL;
1088 FILE *fp_new = NULL;
1090
1091 for (m = parts; m; m = m->next)
1092 {
1093 bool need_secured = false;
1094 bool secured = false;
1095
1097 {
1098 need_secured = true;
1099
1100 if (type & SEC_ENCRYPT)
1101 {
1103 goto decrypt_failed;
1104
1105 if (e->env)
1107 }
1108
1109 secured = (crypt_smime_decrypt_mime(fp, &fp_new, m, &new_body) == 0);
1110 /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1111 * text/plain type will still be returned by mutt_read_mime_header().
1112 * We can't distinguish an actual part from a failure, so only use a
1113 * text/plain that results from a single top-level part. */
1114 if (secured && (new_body->type == TYPE_TEXT) &&
1115 mutt_istr_equal("plain", new_body->subtype) && ((parts != m) || m->next))
1116 {
1117 mutt_body_free(&new_body);
1118 mutt_file_fclose(&fp_new);
1119 goto decrypt_failed;
1120 }
1121
1122 if (secured && (type & SEC_ENCRYPT))
1123 e->security |= SMIME_ENCRYPT;
1124 }
1125
1126 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1128 {
1129 need_secured = true;
1130
1132 goto decrypt_failed;
1133
1134 secured = (crypt_pgp_decrypt_mime(fp, &fp_new, m, &new_body) == 0);
1135
1136 if (secured)
1137 e->security |= PGP_ENCRYPT;
1138 }
1139
1140 if (need_secured && secured)
1141 {
1142 mutt_actx_add_fp(actx, fp_new);
1143 mutt_actx_add_body(actx, new_body);
1144 mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1145 continue;
1146 }
1147
1148 decrypt_failed:
1149 /* Fall through and show the original parts if decryption fails */
1150 if (need_secured && !secured)
1151 mutt_error(_("Can't decrypt encrypted message"));
1152
1153 /* Strip out the top level multipart */
1154 if ((m->type == TYPE_MULTIPART) && m->parts && !need_secured &&
1155 ((parent_type == -1) && !mutt_istr_equal("alternative", m->subtype) &&
1156 !mutt_istr_equal("multilingual", m->subtype)))
1157 {
1158 mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level, decrypted);
1159 }
1160 else
1161 {
1162 struct AttachPtr *ap = mutt_aptr_new();
1163 mutt_actx_add_attach(actx, ap);
1164
1165 ap->body = m;
1166 ap->fp = fp;
1167 m->aptr = ap;
1169 ap->level = level;
1170 ap->decrypted = decrypted;
1171
1172 if (m->type == TYPE_MULTIPART)
1173 {
1174 mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level + 1, decrypted);
1175 }
1176 else if (mutt_is_message_type(m->type, m->subtype))
1177 {
1179 level + 1, decrypted);
1180 e->security |= m->email->security;
1181 }
1182 }
1183 }
1184}
1185
1190void mutt_attach_init(struct AttachCtx *actx)
1191{
1192 /* Collapse the attachments if '$digest_collapse' is set AND if...
1193 * the outer container is of type 'multipart/digest' */
1194 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1195
1196 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1197 for (int i = 0; i < actx->idxlen; i++)
1198 {
1199 actx->idx[i]->body->tagged = false;
1200
1201 /* OR an inner container is of type 'multipart/digest' */
1202 actx->idx[i]->collapsed = (c_digest_collapse &&
1203 (digest ||
1204 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1205 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1206 }
1207}
1208
1215void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
1216{
1217 if (init)
1218 {
1219 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1220 actx->fp_root, -1, 0, 0);
1221 mutt_attach_init(actx);
1222 }
1223
1224 mutt_update_tree(actx);
1225
1226 menu->max = actx->vcount;
1227
1228 const int index = menu_get_index(menu);
1229 if (index >= menu->max)
1230 menu_set_index(menu, menu->max - 1);
1232}
1233
1242int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
1243{
1244 if (!ba || !actx || !menu)
1245 return -1;
1246
1247 if (menu->tag_prefix)
1248 {
1249 for (int i = 0; i < actx->idxlen; i++)
1250 {
1251 struct Body *b = actx->idx[i]->body;
1252 if (b->tagged)
1253 {
1254 ARRAY_ADD(ba, b);
1255 }
1256 }
1257 }
1258 else
1259 {
1260 struct AttachPtr *cur = current_attachment(actx, menu);
1261 if (!cur)
1262 return -1;
1263
1264 ARRAY_ADD(ba, cur->body);
1265 }
1266
1267 return ARRAY_SIZE(ba);
1268}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
void mutt_actx_add_body(struct AttachCtx *actx, struct Body *new_body)
Add an email body to an Attachment Context.
Definition: attach.c:142
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_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:214
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:298
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:365
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:409
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:189
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:500
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:427
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:598
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:133
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:436
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:497
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:433
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition: cryptglue.c:455
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:211
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:386
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:353
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:474
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
Structs that make up an email.
Enter a string.
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1092
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:259
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1390
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:193
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_perror(...)
Definition: logging.h:88
Convenience wrapper for the gui headers.
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1849
void mutt_decode_attachment(struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1889
Decide how to display email content.
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:735
Parse and execute user-defined hooks.
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:475
RFC1524 Mailcap routines.
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:59
#define FREE(x)
Definition: memory.h:43
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:178
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:154
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:168
#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 TYPE(body)
Definition: mime.h:89
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:249
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:329
#define state_puts(STATE, STR)
Definition: state.h:57
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:36
#define STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition: state.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
Many unsorted constants and some structs.
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:58
#define PATH_MAX
Definition: mutt.h:41
#define MUTT_COMP_FILE_SIMPLE
File completion (no browser)
Definition: mutt.h:60
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:65
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:745
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1048
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1148
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:422
int mutt_save_attachment(FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:914
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:44
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:50
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:46
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:47
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:325
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1408
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:568
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1309
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
All user-callable functions.
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1450
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ 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 mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
static bool has_a_message(struct Body *body)
Determine if the Body has a message (to save)
Definition: recvattach.c:193
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:425
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1215
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:225
static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct State *state)
Print a list of Attachments.
Definition: recvattach.c:809
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:69
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:955
void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
Definition: recvattach.c:1082
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:165
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:718
static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:375
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.
Definition: recvattach.c:1190
static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:769
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:114
static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
Ask the user if we should save the attachment.
Definition: recvattach.c:272
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition: recvattach.c:83
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:880
static void query_pipe_attachment(const char *command, FILE *fp, struct Body *body, bool filter)
Ask the user if we should pipe the attachment.
Definition: recvattach.c:541
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:925
int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
Get an array of tagged Attachments.
Definition: recvattach.c:1242
Routines for managing attachments.
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:515
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:391
RFC3676 Format Flowed routines.
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:415
#define NONULL(x)
Definition: string2.h:37
A set of attachments.
Definition: attach.h:51
short vcount
The number of virtual attachments.
Definition: attach.h:60
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:53
struct Email * email
Used by recvattach for updating.
Definition: attach.h:52
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:55
short idxlen
Number of attachmentes.
Definition: attach.h:56
short * v2r
Mapping from virtual to real attachment.
Definition: attach.h:59
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:72
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:74
struct Email * email
header information for message/rfc822
Definition: body.h:73
bool tagged
This attachment is tagged.
Definition: body.h:89
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
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:58
String manipulation buffer.
Definition: buffer.h:34
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
A set of inherited config items.
Definition: subset.h:47
The envelope/body of an email.
Definition: email.h:37
struct Envelope * env
Envelope information.
Definition: email.h:66
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
Definition: lib.h:70
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:77
bool tag_prefix
User has pressed <tag-prefix>
Definition: lib.h:76
int max
Number of entries in the menu.
Definition: lib.h:72
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Keep track when processing files.
Definition: state.h:47
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:51
FILE * fp_out
File to write to.
Definition: state.h:49
FILE * fp_in
File to read from.
Definition: state.h:48
#define mutt_buffer_mktemp(buf)
Definition: tmp.h:37
#define mutt_mktemp(buf, buflen)
Definition: tmp.h:34