2 * Copyright notice from original mutt:
3 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
6 * This file is part of mutt-ng, see http://www.muttng.org/.
7 * It's licensed under the GNU General Public License,
8 * please see the file GPL in the top level source directory.
15 #include <lib-lib/mem.h>
16 #include <lib-lib/str.h>
17 #include <lib-lib/macros.h>
18 #include <lib-lib/ascii.h>
19 #include <lib-lib/file.h>
20 #include <lib-lib/mapping.h>
22 #include <lib-mime/mime.h>
24 #include <lib-ui/curses.h>
25 #include <lib-ui/enter.h>
26 #include <lib-ui/menu.h>
30 #include "recvattach.h"
35 #include <lib-crypt/crypt.h>
46 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
47 static char LastSaveFolder[_POSIX_PATH_MAX] = "";
49 #define CHECK_READONLY if (Context->readonly) \
52 mutt_error _(Mailbox_is_read_only); \
56 #define SW (option(OPTMBOXPANE)?SidebarWidth:0)
58 static struct mapping_t AttachHelp[] = {
59 {N_("Exit"), OP_EXIT},
60 {N_("Save"), OP_SAVE},
61 {N_("Pipe"), OP_PIPE},
62 {N_("Print"), OP_PRINT},
63 {N_("Help"), OP_HELP},
67 static int mutt_extract_path (char *filename, char *path)
69 char *tmp = p_new(char, _POSIX_PATH_MAX);
74 while (*filename != '\0') {
75 if (*filename == '/') {
76 *help_ptr++ = *filename++;
81 *help_ptr++ = *filename++;
87 void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
93 for (x = 0; x < idxlen; x++) {
95 if (2 * (idx[x]->level + 2) < ssizeof (buf)) {
97 s = buf + 2 * (idx[x]->level - 1);
98 *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
100 *s++ = M_TREE_RARROW;
108 if (m_strcmp(idx[x]->tree, buf) != 0)
109 m_strreplace(&idx[x]->tree, buf);
112 idx[x]->tree = m_strdup(buf);
114 if (2 * (idx[x]->level + 2) < ssizeof (buf) && idx[x]->level) {
115 s = buf + 2 * (idx[x]->level - 1);
116 *s++ = (idx[x]->content->next) ? '\005' : '\006';
122 ATTACHPTR **mutt_gen_attach_list (BODY * m,
126 short *idxmax, int level, int compose)
131 for (; m; m = m->next) {
132 if (*idxlen == *idxmax) {
133 p_realloc(&idx, (*idxmax) += 5);
134 for (i = *idxlen; i < *idxmax; i++)
138 if (m->type == TYPEMULTIPART && m->parts
140 || (parent_type == -1
141 && ascii_strcasecmp ("alternative", m->subtype)))
142 && (!mutt_is_multipart_encrypted (m))
145 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level,
150 idx[*idxlen] = p_new(ATTACHPTR, 1);
152 new = idx[(*idxlen)++];
155 new->parent_type = parent_type;
158 /* We don't support multipart messages in the compose menu yet */
159 if (!compose && !m->collapsed
160 && ((m->type == TYPEMULTIPART && !mutt_is_multipart_encrypted(m))
161 || mutt_is_message_type (m->type, m->subtype)))
163 idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
170 mutt_update_tree (idx, *idxlen);
175 /* %c = character set: convert?
179 * %e = MIME content-transfer-encoding
181 * %I = content-disposition, either I (inline) or A (attachment)
184 * %m = major MIME type
186 * %n = attachment number
190 const char *mutt_attach_fmt (char *dest,
195 const char *ifstring,
196 const char *elsestring,
197 unsigned long data, format_flag flags)
200 char tmp[SHORT_STRING];
201 char charset[SHORT_STRING];
202 ATTACHPTR *aptr = (ATTACHPTR *) data;
203 int optional = (flags & M_FORMAT_OPTIONAL);
209 if (mutt_is_text_part (aptr->content) &&
210 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
211 mutt_format_s (dest, destlen, prefix, charset);
213 mutt_format_s (dest, destlen, prefix, "");
215 else if (!mutt_is_text_part (aptr->content) ||
216 !mutt_get_body_charset (charset, sizeof (charset),
223 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
224 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
225 aptr->content->noconv ? 'n' : 'c');
227 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
232 if (aptr->content->description) {
233 mutt_format_s (dest, destlen, prefix, aptr->content->description);
236 if (mutt_is_message_type (aptr->content->type, aptr->content->subtype)
237 && MsgFmt && aptr->content->hdr) {
238 char s[SHORT_STRING];
240 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
241 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT |
242 M_FORMAT_ARROWCURSOR);
244 mutt_format_s (dest, destlen, prefix, s);
248 if (!aptr->content->filename) {
249 mutt_format_s (dest, destlen, prefix, "<no description>");
253 else if (aptr->content->description ||
254 (mutt_is_message_type
255 (aptr->content->type, aptr->content->subtype)
256 && MsgFmt && aptr->content->hdr))
258 /* FALLS THROUGH TO 'f' */
261 if (aptr->content->filename && *aptr->content->filename == '/') {
262 char path[_POSIX_PATH_MAX];
264 m_strcpy(path, sizeof(path), aptr->content->filename);
265 mutt_pretty_mailbox (path);
266 mutt_format_s (dest, destlen, prefix, path);
269 mutt_format_s (dest, destlen, prefix,
270 NONULL (aptr->content->filename));
272 else if (!aptr->content->filename)
277 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
278 else if (!aptr->content->deleted)
283 mutt_format_s (dest, destlen, prefix,
284 ENCODING (aptr->content->encoding));
288 snprintf (dest, destlen, "%c",
289 (aptr->content->disposition == DISPINLINE) ? 'I' : 'A');
294 mutt_format_s (dest, destlen, prefix, TYPE (aptr->content));
298 mutt_format_s (dest, destlen, prefix, aptr->content->subtype);
299 else if (!aptr->content->subtype)
304 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
305 snprintf (dest, destlen, fmt, aptr->num + 1);
310 optional = aptr->content->attach_qualifies;
312 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
313 mutt_format_s (dest, destlen, fmt, "Q");
317 if (flags & M_FORMAT_STAT_FILE) {
320 stat (aptr->content->filename, &st);
324 l = aptr->content->length;
327 mutt_pretty_size (tmp, sizeof (tmp), l);
328 mutt_format_s (dest, destlen, prefix, tmp);
336 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
337 else if (!aptr->content->tagged)
342 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
343 else if (!aptr->tree)
348 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
349 else if (!aptr->content->unlink)
354 optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0;
356 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
357 snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
365 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
366 else if (flags & M_FORMAT_OPTIONAL)
367 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
371 static void attach_entry (char *b, ssize_t blen, MUTTMENU * menu, int num)
373 int w=(COLS-SW)>blen?blen:(COLS-SW);
374 mutt_FormatString (b, w, NONULL (AttachFormat), mutt_attach_fmt,
375 (unsigned long) (((ATTACHPTR **) menu->data)[num]),
376 M_FORMAT_ARROWCURSOR);
379 int mutt_tag_attach (MUTTMENU * menu, int n, int m)
381 BODY *cur = ((ATTACHPTR **) menu->data)[n]->content;
382 int ot = cur->tagged;
384 cur->tagged = (m >= 0 ? m : !cur->tagged);
385 return cur->tagged - ot;
388 int mutt_is_message_type (int type, const char *subtype)
390 if (type != TYPEMESSAGE)
393 subtype = NONULL (subtype);
394 return (ascii_strcasecmp (subtype, "rfc822") == 0
395 || ascii_strcasecmp (subtype, "news") == 0);
398 static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
402 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
403 char path[_POSIX_PATH_MAX] = "";
409 if (body->filename) {
410 if (directory && *directory)
411 mutt_concat_path(buf, sizeof(buf), *directory,
412 mutt_basename(body->filename));
414 m_strcpy(buf, sizeof(buf), body->filename);
416 else if (body->hdr &&
417 body->encoding != ENCBASE64 &&
418 body->encoding != ENCQUOTEDPRINTABLE &&
419 mutt_is_message_type (body->type, body->subtype))
420 mutt_default_save (buf, sizeof (buf), body->hdr);
424 prompt = _("Save to file ('#' for last used folder): ");
427 mutt_get_field (prompt, buf, sizeof (buf),
428 M_FILE | M_CLEAR | M_LASTFOLDER);
429 if (((ret != 0) && (ret != 2)) || (!buf[0] && ret != 2))
433 char tmpbuf[_POSIX_PATH_MAX];
435 snprintf (tmpbuf, sizeof (tmpbuf), "%s%s", LastSaveFolder, buf);
436 m_strcpy(buf, sizeof(buf), tmpbuf);
437 ret = mutt_get_field (_("Save to file: ")
438 , buf, sizeof (buf), M_FILE);
439 if ((ret != 0) || (!buf[0]))
443 mutt_extract_path (buf, path);
444 m_strcpy(LastSaveFolder, sizeof(LastSaveFolder), path);
448 mutt_expand_path (buf, sizeof (buf));
452 body->encoding != ENCBASE64 &&
453 body->encoding != ENCQUOTEDPRINTABLE &&
454 mutt_is_message_type (body->type, body->subtype));
459 /* check to make sure that this file is really the one the user wants */
460 if ((rc = mutt_save_confirm (buf, &st)) == 1) {
461 prompt = _("Save to file: ");
466 m_strcpy(tfile, sizeof(tfile), buf);
470 mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile),
471 &append, directory)) == -1)
474 prompt = _("Save to file: ");
479 mutt_message _("Saving...");
481 if (mutt_save_attachment
482 (fp, body, tfile, append,
483 (hdr || !is_message) ? hdr : body->hdr) == 0) {
484 mutt_message _("Attachment saved.");
489 prompt = _("Save to file: ");
496 void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
499 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
500 char *directory = NULL;
502 int last = menu ? menu->current : -1;
507 for (; top; top = top->next) {
508 if (!tag || top->tagged) {
509 if (!option (OPTATTACHSPLIT)) {
513 m_strcpy(buf, sizeof(buf), NONULL(top->filename));
514 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
515 M_FILE | M_CLEAR) != 0 || !buf[0])
517 mutt_expand_path (buf, sizeof (buf));
518 if (mutt_check_overwrite (top->filename, buf, tfile,
519 sizeof (tfile), &append, NULL))
521 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
522 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
523 fprintf (fpout, "%s", AttachSep);
528 rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
529 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
530 fprintf (fpout, "%s", AttachSep);
536 if (tag && menu && top->aptr) {
537 menu->oldcurrent = menu->current;
538 menu->current = top->aptr->num;
539 menu_check_recenter (menu);
540 menu->redraw |= REDRAW_MOTION;
544 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
549 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
554 p_delete(&directory);
557 menu->oldcurrent = menu->current;
558 menu->current = last;
559 menu_check_recenter (menu);
560 menu->redraw |= REDRAW_MOTION;
563 if (!option (OPTATTACHSPLIT) && (rc == 0))
564 mutt_message _("Attachment saved.");
568 mutt_query_pipe_attachment (char *command, FILE * fp, BODY * body, int afilter)
570 char tfile[_POSIX_PATH_MAX];
571 char warning[STRING + _POSIX_PATH_MAX];
574 snprintf (warning, sizeof (warning),
575 _("WARNING! You are about to overwrite %s, continue?"),
577 if (mutt_yesorno (warning, M_NO) != M_YES) {
578 CLEARLINE (LINES - 1);
586 if (mutt_pipe_attachment (fp, body, command, tfile)) {
588 mutt_unlink (body->filename);
589 mutt_rename_file (tfile, body->filename);
590 mutt_update_encoding (body);
591 mutt_message _("Attachment filtered.");
595 if (afilter && tfile[0])
600 static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
606 mutt_decode_attachment (b, state);
608 state_puts (AttachSep, state);
611 if ((ifp = fopen (b->filename, "r")) == NULL) {
612 mutt_perror ("fopen");
615 mutt_copy_stream (ifp, state->fpout);
618 state_puts (AttachSep, state);
623 pipe_attachment_list (char *command, FILE * fp, int tag, BODY * top,
624 int afilter, STATE * state)
626 for (; top; top = top->next) {
627 if (!tag || top->tagged) {
628 if (!afilter && !option (OPTATTACHSPLIT))
629 pipe_attachment (fp, top, state);
631 mutt_query_pipe_attachment (command, fp, top, afilter);
634 pipe_attachment_list (command, fp, tag, top->parts, afilter, state);
640 void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int afilter)
643 char buf[SHORT_STRING];
647 afilter = 0; /* sanity check: we can't filter in the recv case yet */
652 if (mutt_get_field ((afilter ? _("Filter through: ") : _("Pipe to: ")),
653 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
656 mutt_expand_path (buf, sizeof (buf));
658 if (!afilter && !option (OPTATTACHSPLIT)) {
660 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
661 pipe_attachment_list (buf, fp, tag, top, afilter, &state);
662 fclose (state.fpout);
663 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
664 mutt_any_key_to_continue (NULL);
667 pipe_attachment_list (buf, fp, tag, top, afilter, &state);
670 static int can_print (BODY * top, int tag)
674 for (; top; top = top->next) {
675 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
676 if (!tag || top->tagged) {
677 if (!rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
678 if (ascii_strcasecmp ("text/plain", top->subtype) &&
679 ascii_strcasecmp ("application/postscript", top->subtype)) {
680 if (!mutt_can_decode (top)) {
681 mutt_error (_("I dont know how to print %s attachments!"), type);
688 return (can_print (top->parts, tag));
695 static void print_attachment_list (FILE * fp, int tag, BODY * top,
701 for (; top; top = top->next) {
702 if (!tag || top->tagged) {
703 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
704 if (!option (OPTATTACHSPLIT)
705 && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
706 if (!ascii_strcasecmp ("text/plain", top->subtype)
707 || !ascii_strcasecmp ("application/postscript", top->subtype))
708 pipe_attachment (fp, top, state);
709 else if (mutt_can_decode (top)) {
710 /* decode and print */
712 char newfile[_POSIX_PATH_MAX] = "";
715 mutt_mktemp (newfile);
716 if (mutt_decode_save_attachment (fp, top, newfile, M_PRINTING, 0) ==
718 if ((ifp = fopen (newfile, "r")) != NULL) {
719 mutt_copy_stream (ifp, state->fpout);
722 state_puts (AttachSep, state);
725 mutt_unlink (newfile);
729 mutt_print_attachment (fp, top);
732 print_attachment_list (fp, tag, top->parts, state);
738 void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
746 tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) !=
750 if (!option (OPTATTACHSPLIT)) {
751 if (!can_print (top, tag))
755 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
756 print_attachment_list (fp, tag, top, &state);
757 fclose (state.fpout);
758 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
759 mutt_any_key_to_continue (NULL);
762 print_attachment_list (fp, tag, top, &state);
766 mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
767 short *idxlen, short *idxmax, MUTTMENU * menu)
769 ATTACHPTR **idx = *idxp;
771 while (--(*idxlen) >= 0)
772 idx[(*idxlen)]->content = NULL;
775 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
780 if (menu->current >= menu->max)
781 menu->current = menu->max - 1;
782 menu_check_recenter (menu);
783 menu->redraw |= REDRAW_INDEX;
789 mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
790 BODY * cur, ATTACHPTR *** idxp, short *idxlen,
791 short *idxmax, int recv)
793 ATTACHPTR **idx = *idxp;
796 int old_optweed = option (OPTWEED);
798 set_option (OPTWEED);
803 case OP_DISPLAY_HEADERS:
804 toggle_option (OPTWEED);
808 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
813 case OP_MAIN_NEXT_UNDELETED: /* hack */
814 if (menu->current < menu->max - 1) {
822 case OP_MAIN_PREV_UNDELETED: /* hack */
823 if (menu->current > 0) {
831 /* when we edit the content-type, we should redisplay the attachment
833 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
835 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
840 /* functions which are passed through from the pager */
841 case OP_CHECK_TRADITIONAL:
842 if (hdr && hdr->security & PGP_TRADITIONAL_CHECKED) {
847 case OP_ATTACH_COLLAPSE:
854 while (op != OP_NULL);
857 if (option (OPTWEED) != old_optweed)
858 toggle_option (OPTWEED);
863 static void attach_collapse (BODY * b, short collapse, short init,
868 for (; b; b = b->next) {
869 i = init || b->collapsed;
870 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
871 && !ascii_strcasecmp (b->subtype, "digest"))
872 attach_collapse (b->parts, 1, 1, 0);
873 else if (b->type == TYPEMULTIPART
874 || mutt_is_message_type (b->type, b->subtype))
875 attach_collapse (b->parts, collapse, i, 0);
876 b->collapsed = collapse;
882 void mutt_attach_init (BODY * b)
884 for (; b; b = b->next) {
888 mutt_attach_init (b->parts);
892 static const char *Function_not_permitted =
893 N_("Function not permitted in attach-message mode.");
895 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
898 mutt_error _(Function_not_permitted); \
905 void mutt_view_attachments (HEADER * hdr)
908 int need_secured = 0;
910 char helpstr[SHORT_STRING];
915 ATTACHPTR **idx = NULL;
921 /* make sure we have parsed this message */
922 mutt_parse_mime_message (Context, hdr);
924 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
926 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
930 if ((hdr->security & ENCRYPT) ||
931 (mutt_is_application_smime (hdr->content) & SMIMEOPAQUE))
935 if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase (hdr->security)) {
936 mx_close_message (&msg);
939 if (hdr->security & APPLICATION_SMIME) {
941 crypt_smime_getkeys (hdr->env);
943 if (mutt_is_application_smime (hdr->content)) {
944 secured = !crypt_smime_decrypt_mime (msg->fp, &fp,
948 if ((mutt_is_application_smime (cur) & SMIMEOPAQUE)) {
954 secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
956 mutt_free_body (&_cur);
963 if (hdr->security & APPLICATION_PGP) {
964 if (mutt_is_multipart_encrypted (hdr->content))
965 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
970 if (need_secured && !secured) {
971 mx_close_message (&msg);
972 mutt_error _("Can't decrypt encrypted message!");
983 menu = mutt_new_menu ();
984 menu->menu = MENU_ATTACH;
985 menu->title = _("Attachments");
986 menu->make_entry = attach_entry;
987 menu->tag = mutt_tag_attach;
989 mutt_compile_help (helpstr, sizeof (helpstr), MENU_ATTACH, AttachHelp);
991 mutt_attach_init (cur);
992 attach_collapse (cur, 0, 1, 0);
993 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
997 op = mutt_menuLoop (menu);
999 case OP_ATTACH_VIEW_MAILCAP:
1000 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
1002 menu->redraw = REDRAW_FULL;
1005 case OP_ATTACH_VIEW_TEXT:
1006 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
1008 menu->redraw = REDRAW_FULL;
1011 case OP_DISPLAY_HEADERS:
1012 case OP_VIEW_ATTACH:
1014 mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen,
1016 menu->redraw = REDRAW_FULL;
1019 case OP_ATTACH_COLLAPSE:
1020 if (!idx[menu->current]->content->parts) {
1021 mutt_error _("There are no subparts to show!");
1025 if (!idx[menu->current]->content->collapsed)
1026 attach_collapse (idx[menu->current]->content, 1, 0, 1);
1028 attach_collapse (idx[menu->current]->content, 0, 1, 1);
1029 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1032 case OP_FORGET_PASSPHRASE:
1033 crypt_forget_passphrase ();
1036 case OP_EXTRACT_KEYS:
1037 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
1040 idx[menu->current]->
1042 menu->redraw = REDRAW_FULL;
1045 case OP_CHECK_TRADITIONAL:
1046 if (crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
1047 : idx[menu->current]->content,
1050 hdr->security = crypt_query (cur);
1051 menu->redraw = REDRAW_FULL;
1056 mutt_print_attachment_list (fp, menu->tagprefix,
1057 menu->tagprefix ? cur : idx[menu->current]->
1062 mutt_pipe_attachment_list (fp, menu->tagprefix,
1063 menu->tagprefix ? cur : idx[menu->current]->
1068 mutt_save_attachment_list (fp, menu->tagprefix,
1069 menu->tagprefix ? cur : idx[menu->current]->
1070 content, hdr, menu);
1072 if (!menu->tagprefix && option (OPTRESOLVE)
1073 && menu->current < menu->max - 1)
1076 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
1082 if (Context->magic == M_POP) {
1084 mutt_error _("Can't delete attachment from POP server.");
1090 if (Context->magic == M_NNTP) {
1092 mutt_error _("Can't delete attachment from newsserver.");
1098 if (hdr->security & (~PGP_TRADITIONAL_CHECKED)) {
1100 _("Deletion of attachments from encrypted messages is unsupported.");
1103 if (!menu->tagprefix) {
1104 if (idx[menu->current]->parent_type == TYPEMULTIPART) {
1105 idx[menu->current]->content->deleted = 1;
1106 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1108 menu->redraw = REDRAW_MOTION_RESYNCH;
1111 menu->redraw = REDRAW_CURRENT;
1115 _("Only deletion of multipart attachments is supported.");
1120 for (x = 0; x < menu->max; x++) {
1121 if (idx[x]->content->tagged) {
1122 if (idx[x]->parent_type == TYPEMULTIPART) {
1123 idx[x]->content->deleted = 1;
1124 menu->redraw = REDRAW_INDEX;
1128 _("Only deletion of multipart attachments is supported.");
1137 if (!menu->tagprefix) {
1138 idx[menu->current]->content->deleted = 0;
1139 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1141 menu->redraw = REDRAW_MOTION_RESYNCH;
1144 menu->redraw = REDRAW_CURRENT;
1149 for (x = 0; x < menu->max; x++) {
1150 if (idx[x]->content->tagged) {
1151 idx[x]->content->deleted = 0;
1152 menu->redraw = REDRAW_INDEX;
1160 mutt_attach_resend (fp, hdr, idx, idxlen,
1161 menu->tagprefix ? NULL : idx[menu->current]->
1163 menu->redraw = REDRAW_FULL;
1166 case OP_BOUNCE_MESSAGE:
1168 mutt_attach_bounce (fp, hdr, idx, idxlen,
1169 menu->tagprefix ? NULL : idx[menu->current]->
1171 menu->redraw = REDRAW_FULL;
1174 case OP_FORWARD_MESSAGE:
1176 mutt_attach_forward (fp, hdr, idx, idxlen,
1177 menu->tagprefix ? NULL : idx[menu->current]->
1179 menu->redraw = REDRAW_FULL;
1183 case OP_FORWARD_TO_GROUP:
1185 mutt_attach_forward (fp, hdr, idx, idxlen,
1186 menu->tagprefix ? NULL : idx[menu->current]->
1188 menu->redraw = REDRAW_FULL;
1194 if (!idx[menu->current]->content->hdr->env->followup_to ||
1195 m_strcasecmp(idx[menu->current]->content->hdr->env->followup_to,
1197 || query_quadoption (OPT_FOLLOWUPTOPOSTER,
1198 _("Reply by mail as poster prefers?")) !=
1200 mutt_attach_reply (fp, hdr, idx, idxlen,
1201 menu->tagprefix ? NULL : idx[menu->current]->
1202 content, SENDNEWS | SENDREPLY);
1203 menu->redraw = REDRAW_FULL;
1209 case OP_GROUP_REPLY:
1215 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1216 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1217 mutt_attach_reply (fp, hdr, idx, idxlen,
1218 menu->tagprefix ? NULL : idx[menu->current]->content,
1220 menu->redraw = REDRAW_FULL;
1224 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1225 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1229 mx_close_message (&msg);
1230 hdr->attach_del = 0;
1231 while (idxmax-- > 0) {
1234 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1235 hdr->attach_del = 1;
1236 if (idx[idxmax]->content)
1237 idx[idxmax]->content->aptr = NULL;
1238 p_delete(&idx[idxmax]->tree);
1239 p_delete(&idx[idxmax]);
1241 if (hdr->attach_del)
1246 if (need_secured && secured) {
1248 mutt_free_body (&cur);
1251 mutt_menuDestroy (&menu);