NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 "browser/lib.h"
45#include "editor/lib.h"
46#include "history/lib.h"
47#include "menu/lib.h"
48#include "ncrypt/lib.h"
49#include "question/lib.h"
50#include "send/lib.h"
51#include "attach.h"
52#include "external.h"
53#include "globals.h" // IWYU pragma: keep
54#include "handler.h"
55#include "hook.h"
56#include "mailcap.h"
57#include "mutt_attach.h"
58#include "mutt_thread.h"
59#include "muttlib.h"
60#include "rfc3676.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) ? '\005' : '\006';
158 *s++ = '\006';
159 }
160 }
161}
162
167static void prepend_savedir(struct Buffer *buf)
168{
169 if (!buf || !buf->data || (buf->data[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 *body)
196{
197 return (body->email && (body->encoding != ENC_BASE64) &&
198 (body->encoding != ENC_QUOTED_PRINTABLE) &&
199 mutt_is_message_type(body->type, body->subtype));
200}
201
227static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path,
228 enum SaveAttach flags, struct Email *e)
229{
230 int rc = -1;
231
233 {
234 struct Body b_fake = { 0 };
235
236 struct Buffer *tempfile = buf_pool_get();
237 buf_mktemp(tempfile);
238
239 /* Pass MUTT_SAVE_NO_FLAGS to force mutt_file_fopen("w") */
240 rc = mutt_save_attachment(fp, b, buf_string(tempfile), MUTT_SAVE_NO_FLAGS, e);
241 if (rc != 0)
242 goto cleanup;
243
245
246 /* Now "really" save it. Send mode does this without touching anything,
247 * so force send-mode. */
248 memset(&b_fake, 0, sizeof(struct Body));
249 b_fake.filename = tempfile->data;
250 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
251
252 mutt_file_unlink(buf_string(tempfile));
253
254 cleanup:
255 buf_pool_release(&tempfile);
256 }
257 else
258 {
259 rc = mutt_save_attachment(fp, b, path, flags, e);
260 }
261
262 return rc;
263}
264
274static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
275{
276 char *prompt = NULL;
278 int rc = -1;
279
280 struct Buffer *buf = buf_pool_get();
281 struct Buffer *tfile = buf_pool_get();
282
283 if (body->filename)
284 {
285 if (directory && *directory)
286 {
287 buf_concat_path(buf, *directory, mutt_path_basename(body->filename));
288 }
289 else
290 {
291 buf_strcpy(buf, body->filename);
292 }
293 }
294 else if (has_a_message(body))
295 {
296 mutt_default_save(buf->data, buf->dsize, body->email);
297 buf_fix_dptr(buf);
298 }
299
300 prepend_savedir(buf);
301
302 prompt = _("Save to file: ");
303 while (prompt)
304 {
305 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
306 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_FILE, &CompleteMailboxOps, &cdata) != 0) ||
307 buf_is_empty(buf))
308 {
309 goto cleanup;
310 }
311
312 prompt = NULL;
313 buf_expand_path(buf);
314
315 bool is_message = (fp && has_a_message(body));
316
317 if (is_message)
318 {
319 struct stat st = { 0 };
320
321 /* check to make sure that this file is really the one the user wants */
322 rc = mutt_save_confirm(buf_string(buf), &st);
323 if (rc == 1)
324 {
325 prompt = _("Save to file: ");
326 continue;
327 }
328 else if (rc == -1)
329 {
330 goto cleanup;
331 }
332 buf_copy(tfile, buf);
333 }
334 else
335 {
336 rc = mutt_check_overwrite(body->filename, buf_string(buf), tfile, &opt, directory);
337 if (rc == -1)
338 {
339 goto cleanup;
340 }
341 else if (rc == 1)
342 {
343 prompt = _("Save to file: ");
344 continue;
345 }
346 }
347
348 mutt_message(_("Saving..."));
349 if (save_attachment_flowed_helper(fp, body, buf_string(tfile), opt,
350 (e || !is_message) ? e : body->email) == 0)
351 {
352 // This uses ngettext to avoid duplication of messages
353 const int num = 1;
354 mutt_message(ngettext("Attachment saved", "%d attachments saved", num), num);
355 rc = 0;
356 goto cleanup;
357 }
358 else
359 {
360 prompt = _("Save to file: ");
361 continue;
362 }
363 }
364
365cleanup:
366 buf_pool_release(&buf);
367 buf_pool_release(&tfile);
368 return rc;
369}
370
379static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
380{
382 int rc = -1;
383 struct Buffer *buf = buf_pool_get();
384 struct Buffer *tfile = buf_pool_get();
385
386 if (body->filename)
387 {
388 buf_strcpy(buf, body->filename);
389 }
390 else if (has_a_message(body))
391 {
392 mutt_default_save(buf->data, buf->dsize, body->email);
393 }
394
395 prepend_savedir(buf);
396 buf_expand_path(buf);
397
398 bool is_message = (fp && has_a_message(body));
399
400 if (is_message)
401 {
402 buf_copy(tfile, buf);
403 }
404 else
405 {
406 rc = mutt_check_overwrite(body->filename, buf_string(buf), tfile, &opt, NULL);
407 if (rc == -1) // abort or cancel
408 goto cleanup;
409 }
410
411 rc = save_attachment_flowed_helper(fp, body, buf_string(tfile), opt,
412 (e || !is_message) ? e : body->email);
413
414cleanup:
415 buf_pool_release(&buf);
416 buf_pool_release(&tfile);
417 return rc;
418}
419
429void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
430 struct Body *top, struct Email *e, struct Menu *menu)
431{
432 char *directory = NULL;
433 int rc = 1;
434 int last = menu_get_index(menu);
435 FILE *fp_out = NULL;
436 int saved_attachments = 0;
437
438 struct Buffer *buf = buf_pool_get();
439 struct Buffer *tfile = buf_pool_get();
440
441 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
442 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
443 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
444
445 for (int i = 0; !tag || (i < actx->idxlen); i++)
446 {
447 if (tag)
448 {
449 fp = actx->idx[i]->fp;
450 top = actx->idx[i]->body;
451 }
452 if (!tag || top->tagged)
453 {
454 if (c_attach_split)
455 {
456 if (tag && menu && top->aptr)
457 {
458 menu_set_index(menu, top->aptr->num);
460
461 menu_redraw(menu);
462 }
463 if (c_attach_save_without_prompting)
464 {
465 // Save each file, with no prompting, using the configured 'AttachSaveDir'
466 rc = save_without_prompting(fp, top, e);
467 if (rc == 0)
468 saved_attachments++;
469 }
470 else
471 {
472 // Save each file, prompting the user for the location each time.
473 if (query_save_attachment(fp, top, e, &directory) == -1)
474 break;
475 }
476 }
477 else
478 {
480
481 if (buf_is_empty(buf))
482 {
484 prepend_savedir(buf);
485
486 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
487 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
488 &CompleteMailboxOps, &cdata) != 0) ||
489 buf_is_empty(buf))
490 {
491 goto cleanup;
492 }
493 buf_expand_path(buf);
494 if (mutt_check_overwrite(top->filename, buf_string(buf), tfile, &opt, NULL))
495 goto cleanup;
496 }
497 else
498 {
499 opt = MUTT_SAVE_APPEND;
500 }
501
502 rc = save_attachment_flowed_helper(fp, top, buf_string(tfile), opt, e);
503 if ((rc == 0) && c_attach_sep && (fp_out = fopen(buf_string(tfile), "a")))
504 {
505 fprintf(fp_out, "%s", c_attach_sep);
506 mutt_file_fclose(&fp_out);
507 }
508 }
509 }
510 if (!tag)
511 break;
512 }
513
514 FREE(&directory);
515
516 if (tag && menu)
517 {
518 menu_set_index(menu, last);
520 }
521
522 if (rc == 0)
523 {
524 if (!c_attach_split)
525 saved_attachments = 1;
526
527 if (!c_attach_split || c_attach_save_without_prompting)
528 {
529 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
530 saved_attachments);
531 }
532 }
533
534cleanup:
535 buf_pool_release(&buf);
536 buf_pool_release(&tfile);
537}
538
546static void query_pipe_attachment(const char *command, FILE *fp, struct Body *body, bool filter)
547{
548 struct Buffer *tfile = buf_pool_get();
549
550 if (filter)
551 {
552 char warning[PATH_MAX + 256];
553 snprintf(warning, sizeof(warning),
554 _("WARNING! You are about to overwrite %s, continue?"), body->filename);
555 if (query_yesorno(warning, MUTT_NO) != MUTT_YES)
556 {
557 msgwin_clear_text(NULL);
558 buf_pool_release(&tfile);
559 return;
560 }
561 buf_mktemp(tfile);
562 }
563
564 if (mutt_pipe_attachment(fp, body, command, buf_string(tfile)))
565 {
566 if (filter)
567 {
569 mutt_file_rename(buf_string(tfile), body->filename);
571 mutt_message(_("Attachment filtered"));
572 }
573 }
574 else
575 {
576 if (filter && !buf_is_empty(tfile))
578 }
579 buf_pool_release(&tfile);
580}
581
588static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
589{
590 if (!state || !state->fp_out)
591 return;
592
593 FILE *fp_in = NULL;
594 FILE *fp_unstuff = NULL;
595 bool is_flowed = false, unlink_unstuff = false;
596 struct Buffer *unstuff_tempfile = NULL;
597
599 {
600 is_flowed = true;
601 unstuff_tempfile = buf_pool_get();
602 buf_mktemp(unstuff_tempfile);
603 }
604
605 if (fp)
606 {
607 state->fp_in = fp;
608
609 if (is_flowed)
610 {
611 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
612 if (!fp_unstuff)
613 {
614 mutt_perror("mutt_file_fopen");
615 goto bail;
616 }
617 unlink_unstuff = true;
618
619 FILE *filter_fp = state->fp_out;
620 state->fp_out = fp_unstuff;
621 mutt_decode_attachment(b, state);
622 mutt_file_fclose(&fp_unstuff);
623 state->fp_out = filter_fp;
624
625 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
626 if (!fp_unstuff)
627 {
628 mutt_perror("mutt_file_fopen");
629 goto bail;
630 }
631 mutt_file_copy_stream(fp_unstuff, filter_fp);
632 mutt_file_fclose(&fp_unstuff);
633 }
634 else
635 {
636 mutt_decode_attachment(b, state);
637 }
638 }
639 else
640 {
641 const char *infile = NULL;
642
643 if (is_flowed)
644 {
645 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile), 0, NULL) == -1)
646 goto bail;
647 unlink_unstuff = true;
649 infile = buf_string(unstuff_tempfile);
650 }
651 else
652 {
653 infile = b->filename;
654 }
655
656 fp_in = fopen(infile, "r");
657 if (!fp_in)
658 {
659 mutt_perror("fopen");
660 goto bail;
661 }
662 mutt_file_copy_stream(fp_in, state->fp_out);
663 mutt_file_fclose(&fp_in);
664 }
665
666 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
667 if (c_attach_sep)
668 state_puts(state, c_attach_sep);
669
670bail:
671 mutt_file_fclose(&fp_unstuff);
672 mutt_file_fclose(&fp_in);
673
674 if (unlink_unstuff)
675 mutt_file_unlink(buf_string(unstuff_tempfile));
676 buf_pool_release(&unstuff_tempfile);
677}
678
689static void pipe_attachment_list(const char *command, struct AttachCtx *actx,
690 FILE *fp, bool tag, struct Body *top,
691 bool filter, struct State *state)
692{
693 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
694 for (int i = 0; !tag || (i < actx->idxlen); i++)
695 {
696 if (tag)
697 {
698 fp = actx->idx[i]->fp;
699 top = actx->idx[i]->body;
700 }
701 if (!tag || top->tagged)
702 {
703 if (!filter && !c_attach_split)
704 pipe_attachment(fp, top, state);
705 else
706 query_pipe_attachment(command, fp, top, filter);
707 }
708 if (!tag)
709 break;
710 }
711}
712
721void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
722 struct Body *top, bool filter)
723{
724 struct State state = { 0 };
725 struct Buffer *buf = NULL;
726
727 if (fp)
728 filter = false; /* sanity check: we can't filter in the recv case yet */
729
730 buf = buf_pool_get();
731 /* perform charset conversion on text attachments when piping */
732 state.flags = STATE_CHARCONV;
733
734 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
736 {
737 goto cleanup;
738 }
739
740 if (buf_len(buf) == 0)
741 goto cleanup;
742
743 buf_expand_path(buf);
744
745 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
746 if (!filter && !c_attach_split)
747 {
748 mutt_endwin();
749 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL, EnvList);
750 pipe_attachment_list(buf_string(buf), actx, fp, tag, top, filter, &state);
751 mutt_file_fclose(&state.fp_out);
752 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
753 if ((filter_wait(pid) != 0) || c_wait_key)
755 }
756 else
757 {
758 pipe_attachment_list(buf_string(buf), actx, fp, tag, top, filter, &state);
759 }
760
761cleanup:
762 buf_pool_release(&buf);
763}
764
772static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
773{
774 char type[256] = { 0 };
775
776 for (int i = 0; !tag || (i < actx->idxlen); i++)
777 {
778 if (tag)
779 top = actx->idx[i]->body;
780 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
781 if (!tag || top->tagged)
782 {
783 if (!mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
784 {
785 if (!mutt_istr_equal("text/plain", top->subtype) &&
786 !mutt_istr_equal("application/postscript", top->subtype))
787 {
788 if (!mutt_can_decode(top))
789 {
790 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
791 application/octet-stream. */
792 mutt_error(_("I don't know how to print %s attachments"), type);
793 return false;
794 }
795 }
796 }
797 }
798 if (!tag)
799 break;
800 }
801 return true;
802}
803
812static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag,
813 struct Body *top, struct State *state)
814{
815 char type[256] = { 0 };
816
817 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
818 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
819
820 for (int i = 0; !tag || (i < actx->idxlen); i++)
821 {
822 if (tag)
823 {
824 fp = actx->idx[i]->fp;
825 top = actx->idx[i]->body;
826 }
827 if (!tag || top->tagged)
828 {
829 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
830 if (!c_attach_split && !mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
831 {
832 if (mutt_istr_equal("text/plain", top->subtype) ||
833 mutt_istr_equal("application/postscript", top->subtype))
834 {
835 pipe_attachment(fp, top, state);
836 }
837 else if (mutt_can_decode(top))
838 {
839 /* decode and print */
840
841 FILE *fp_in = NULL;
842 struct Buffer *newfile = buf_pool_get();
843
844 buf_mktemp(newfile);
845 if (mutt_decode_save_attachment(fp, top, buf_string(newfile),
847 {
848 if (!state->fp_out)
849 {
850 mutt_error("BUG in print_attachment_list(). Please report this. ");
851 return;
852 }
853
854 fp_in = 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 {
869 mutt_print_attachment(fp, top);
870 }
871 }
872 if (!tag)
873 break;
874 }
875}
876
884void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
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, top, &state);
906 }
907 else
908 {
909 if (!can_print(actx, top, 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, NULL, EnvList);
914 print_attachment_list(actx, fp, tag, top, &state);
915 mutt_file_fclose(&state.fp_out);
916 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
917 if ((filter_wait(pid) != 0) || c_wait_key)
919 }
920}
921
928void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
929{
930 struct AttachPtr *cur_att = current_attachment(actx, menu);
931 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
932 return;
933
934 /* The mutt_update_recvattach_menu() will overwrite any changes
935 * made to a decrypted cur_att->body, so warn the user. */
936 if (cur_att->decrypted)
937 {
938 mutt_message(_("Structural changes to decrypted attachments are not supported"));
939 mutt_sleep(1);
940 }
941 /* Editing the content type can rewrite the body structure. */
942 for (int i = 0; i < actx->idxlen; i++)
943 actx->idx[i]->body = NULL;
945 mutt_update_recvattach_menu(actx, menu, true);
946}
947
958int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op,
959 struct Email *e, struct AttachCtx *actx, bool recv)
960{
961 do
962 {
963 switch (op)
964 {
965 case OP_DISPLAY_HEADERS:
966 bool_str_toggle(NeoMutt->sub, "weed", NULL);
967 /* fallthrough */
968
969 case OP_ATTACHMENT_VIEW:
970 {
971 struct AttachPtr *cur_att = current_attachment(actx, menu);
972 if (!cur_att->fp)
973 {
974 if (cur_att->body->type == TYPE_MULTIPART)
975 {
976 struct Body *b = cur_att->body->parts;
977 while (b->parts)
978 b = b->parts;
979 cur_att = b->aptr;
980 }
981 }
982 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
983 e, actx, menu->win);
984 break;
985 }
986
987 case OP_NEXT_ENTRY:
988 case OP_MAIN_NEXT_UNDELETED: /* hack */
989 {
990 const int index = menu_get_index(menu) + 1;
991 if (index < menu->max)
992 {
993 menu_set_index(menu, index);
994 op = OP_ATTACHMENT_VIEW;
995 }
996 else
997 {
998 op = OP_NULL;
999 }
1000 break;
1001 }
1002
1003 case OP_PREV_ENTRY:
1004 case OP_MAIN_PREV_UNDELETED: /* hack */
1005 {
1006 const int index = menu_get_index(menu) - 1;
1007 if (index >= 0)
1008 {
1009 menu_set_index(menu, index);
1010 op = OP_ATTACHMENT_VIEW;
1011 }
1012 else
1013 {
1014 op = OP_NULL;
1015 }
1016 break;
1017 }
1018
1019 case OP_ATTACHMENT_EDIT_TYPE:
1020 {
1021 struct AttachPtr *cur_att = current_attachment(actx, menu);
1022 /* when we edit the content-type, we should redisplay the attachment
1023 * immediately */
1024 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1025 if (recv)
1026 recvattach_edit_content_type(actx, menu, e);
1027 else
1028 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1029
1031 op = OP_ATTACHMENT_VIEW;
1032 break;
1033 }
1034 /* functions which are passed through from the pager */
1035 case OP_PIPE:
1036 {
1037 struct AttachPtr *cur_att = current_attachment(actx, menu);
1038 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1039 op = OP_ATTACHMENT_VIEW;
1040 break;
1041 }
1042 case OP_ATTACHMENT_PRINT:
1043 {
1044 struct AttachPtr *cur_att = current_attachment(actx, menu);
1045 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1046 op = OP_ATTACHMENT_VIEW;
1047 break;
1048 }
1049 case OP_ATTACHMENT_SAVE:
1050 {
1051 struct AttachPtr *cur_att = current_attachment(actx, menu);
1052 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1053 op = OP_ATTACHMENT_VIEW;
1054 break;
1055 }
1056 case OP_CHECK_TRADITIONAL:
1058 {
1059 op = OP_NULL;
1060 break;
1061 }
1062 /* fallthrough */
1063 case OP_ATTACHMENT_COLLAPSE:
1064 if (recv)
1065 return op;
1066 /* fallthrough */
1067 default:
1068 op = OP_NULL;
1069 }
1070 } while (op != OP_NULL);
1071
1072 return op;
1073}
1074
1085void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e,
1086 struct Body *parts, FILE *fp,
1087 int parent_type, int level, bool decrypted)
1088{
1089 struct Body *m = NULL;
1090 struct Body *new_body = NULL;
1091 FILE *fp_new = NULL;
1093
1094 for (m = parts; m; m = m->next)
1095 {
1096 bool need_secured = false;
1097 bool secured = false;
1098
1100 {
1101 need_secured = true;
1102
1103 if (type & SEC_ENCRYPT)
1104 {
1106 goto decrypt_failed;
1107
1108 if (e->env)
1110 }
1111
1112 secured = (crypt_smime_decrypt_mime(fp, &fp_new, m, &new_body) == 0);
1113 /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1114 * text/plain type will still be returned by mutt_read_mime_header().
1115 * We can't distinguish an actual part from a failure, so only use a
1116 * text/plain that results from a single top-level part. */
1117 if (secured && (new_body->type == TYPE_TEXT) &&
1118 mutt_istr_equal("plain", new_body->subtype) && ((parts != m) || m->next))
1119 {
1120 mutt_body_free(&new_body);
1121 mutt_file_fclose(&fp_new);
1122 goto decrypt_failed;
1123 }
1124
1125 if (secured && (type & SEC_ENCRYPT))
1126 e->security |= SMIME_ENCRYPT;
1127 }
1128
1129 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1131 {
1132 need_secured = true;
1133
1135 goto decrypt_failed;
1136
1137 secured = (crypt_pgp_decrypt_mime(fp, &fp_new, m, &new_body) == 0);
1138
1139 if (secured)
1140 e->security |= PGP_ENCRYPT;
1141 }
1142
1143 if (need_secured && secured)
1144 {
1145 mutt_actx_add_fp(actx, fp_new);
1146 mutt_actx_add_body(actx, new_body);
1147 mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1148 continue;
1149 }
1150
1151 decrypt_failed:
1152 /* Fall through and show the original parts if decryption fails */
1153 if (need_secured && !secured)
1154 mutt_error(_("Can't decrypt encrypted message"));
1155
1156 struct AttachPtr *ap = mutt_aptr_new();
1157 mutt_actx_add_attach(actx, ap);
1158
1159 ap->body = m;
1160 ap->fp = fp;
1161 m->aptr = ap;
1163 ap->level = level;
1164 ap->decrypted = decrypted;
1165
1166 if (mutt_is_message_type(m->type, m->subtype))
1167 {
1169 level + 1, decrypted);
1170 e->security |= m->email->security;
1171 }
1172 else
1173 {
1174 mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level + 1, decrypted);
1175 }
1176 }
1177}
1178
1183void mutt_attach_init(struct AttachCtx *actx)
1184{
1185 /* Collapse the attachments if '$digest_collapse' is set AND if...
1186 * the outer container is of type 'multipart/digest' */
1187 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1188
1189 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1190 for (int i = 0; i < actx->idxlen; i++)
1191 {
1192 actx->idx[i]->body->tagged = false;
1193
1194 /* OR an inner container is of type 'multipart/digest' */
1195 actx->idx[i]->collapsed = (c_digest_collapse &&
1196 (digest ||
1197 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1198 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1199 }
1200}
1201
1208void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
1209{
1210 if (init)
1211 {
1212 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1213 actx->fp_root, -1, 0, 0);
1214 mutt_attach_init(actx);
1215 }
1216
1217 mutt_update_tree(actx);
1218
1219 menu->max = actx->vcount;
1220
1221 const int index = menu_get_index(menu);
1222 if (index >= menu->max)
1223 menu_set_index(menu, menu->max - 1);
1225}
1226
1235int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
1236{
1237 if (!ba || !actx || !menu)
1238 return -1;
1239
1240 if (menu->tag_prefix)
1241 {
1242 for (int i = 0; i < actx->idxlen; i++)
1243 {
1244 struct Body *b = actx->idx[i]->body;
1245 if (b->tagged)
1246 {
1247 ARRAY_ADD(ba, b);
1248 }
1249 }
1250 }
1251 else
1252 {
1253 struct AttachPtr *cur = current_attachment(actx, menu);
1254 if (!cur)
1255 return -1;
1256
1257 ARRAY_ADD(ba, cur->body);
1258 }
1259
1260 return ARRAY_SIZE(ba);
1261}
#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
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
const struct CompleteOps CompleteMailboxOps
Auto-Completion of Files / Mailboxes.
Definition: complete.c:160
Select a Mailbox from a list.
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:194
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:572
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:484
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
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:135
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:432
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:493
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:188
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:154
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:474
Enter a string.
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
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:1482
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1078
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:262
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1412
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:196
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:218
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:207
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:85
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:275
#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:1852
void mutt_decode_attachment(struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1892
Decide how to display email content.
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition: lib.h:52
@ HC_COMMAND
NeoMutt commands.
Definition: lib.h:51
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:736
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:480
RFC1524 Mailcap routines.
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:59
#define FREE(x)
Definition: memory.h:45
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:180
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:156
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:170
#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(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:515
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition: path.c:314
#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:810
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
#define PATH_MAX
Definition: mutt.h:41
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:56
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:746
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:423
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:56
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:62
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:58
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:59
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1428
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:335
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:584
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1327
Some miscellaneous functions.
API for encryption/signing of emails.
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:77
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:93
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define PGP_ENCRYPT
Definition: lib.h:97
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:92
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:79
#define SMIME_ENCRYPT
Definition: lib.h:103
#define WithCrypto
Definition: lib.h:117
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:369
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:330
static bool has_a_message(struct Body *body)
Determine if the Body has a message (to save)
Definition: recvattach.c:195
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:429
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1208
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:227
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:812
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:689
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:958
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:1085
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 *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:721
static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:379
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition: recvattach.c:588
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1183
static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:772
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:116
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:274
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition: recvattach.c:85
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:884
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:546
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:928
int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
Get an array of tagged Attachments.
Definition: recvattach.c:1235
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:420
#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
Input for the file completion function.
Definition: curs_lib.h:49
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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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 buf_mktemp(buf)
Definition: tmp.h:33