2 * Copyright (C) 1996-2000,2002,2007 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 1999-2006 Thomas Roessler <roessler@does-not-exist.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "mutt_curses.h"
26 #include "mutt_menu.h"
33 #include "mutt_crypt.h"
43 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
45 #define CHECK_READONLY if (Context->readonly) \
48 mutt_error _(Mailbox_is_read_only); \
52 static struct mapping_t AttachHelp[] = {
53 { N_("Exit"), OP_EXIT },
54 { N_("Save"), OP_SAVE },
55 { N_("Pipe"), OP_PIPE },
56 { N_("Print"), OP_PRINT },
57 { N_("Help"), OP_HELP },
61 void mutt_update_tree (ATTACHPTR **idx, short idxlen)
67 for (x = 0; x < idxlen; x++)
70 if (2 * (idx[x]->level + 2) < sizeof (buf))
74 s = buf + 2 * (idx[x]->level - 1);
75 *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
86 if (mutt_strcmp (idx[x]->tree, buf) != 0)
87 mutt_str_replace (&idx[x]->tree, buf);
90 idx[x]->tree = safe_strdup (buf);
92 if (2 * (idx[x]->level + 2) < sizeof (buf) && idx[x]->level)
94 s = buf + 2 * (idx[x]->level - 1);
95 *s++ = (idx[x]->content->next) ? '\005' : '\006';
101 ATTACHPTR **mutt_gen_attach_list (BODY *m,
112 for (; m; m = m->next)
114 if (*idxlen == *idxmax)
116 safe_realloc (&idx, sizeof (ATTACHPTR *) * ((*idxmax) += 5));
117 for (i = *idxlen; i < *idxmax; i++)
121 if (m->type == TYPEMULTIPART && m->parts
122 && (compose || (parent_type == -1 && ascii_strcasecmp ("alternative", m->subtype)))
123 && (!(WithCrypto & APPLICATION_PGP) || !mutt_is_multipart_encrypted(m))
126 idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level, compose);
131 idx[*idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
133 new = idx[(*idxlen)++];
136 new->parent_type = parent_type;
139 /* We don't support multipart messages in the compose menu yet */
140 if (!compose && !m->collapsed &&
141 ((m->type == TYPEMULTIPART
142 && (!(WithCrypto & APPLICATION_PGP)
143 || !mutt_is_multipart_encrypted (m))
145 || mutt_is_message_type(m->type, m->subtype)))
147 idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level + 1, compose);
153 mutt_update_tree (idx, *idxlen);
158 /* %c = character set: convert?
162 * %e = MIME content-transfer-encoding
164 * %I = content-disposition, either I (inline) or A (attachment)
167 * %m = major MIME type
169 * %n = attachment number
173 const char *mutt_attach_fmt (char *dest,
179 const char *ifstring,
180 const char *elsestring,
185 char tmp[SHORT_STRING];
186 char charset[SHORT_STRING];
187 ATTACHPTR *aptr = (ATTACHPTR *) data;
188 int optional = (flags & M_FORMAT_OPTIONAL);
196 if (mutt_is_text_part (aptr->content) &&
197 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
198 mutt_format_s (dest, destlen, prefix, charset);
200 mutt_format_s (dest, destlen, prefix, "");
202 else if (!mutt_is_text_part (aptr->content) ||
203 !mutt_get_body_charset (charset, sizeof (charset), aptr->content))
210 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
211 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
212 aptr->content->noconv ? 'n' : 'c');
214 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
220 if (aptr->content->description)
222 mutt_format_s (dest, destlen, prefix, aptr->content->description);
225 if (mutt_is_message_type(aptr->content->type, aptr->content->subtype) &&
226 MsgFmt && aptr->content->hdr)
228 char s[SHORT_STRING];
229 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
230 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT | M_FORMAT_ARROWCURSOR);
233 mutt_format_s (dest, destlen, prefix, s);
237 if (!aptr->content->filename)
239 mutt_format_s (dest, destlen, prefix, "<no description>");
243 else if(aptr->content->description ||
244 (mutt_is_message_type (aptr->content->type, aptr->content->subtype)
245 && MsgFmt && aptr->content->hdr))
247 /* FALLS THROUGH TO 'f' */
251 if (aptr->content->filename && *aptr->content->filename == '/')
253 char path[_POSIX_PATH_MAX];
255 strfcpy (path, aptr->content->filename, sizeof (path));
256 mutt_pretty_mailbox (path, sizeof (path));
257 mutt_format_s (dest, destlen, prefix, path);
260 mutt_format_s (dest, destlen, prefix, NONULL (aptr->content->filename));
262 else if(!aptr->content->filename)
267 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
268 else if(!aptr->content->deleted)
273 mutt_format_s (dest, destlen, prefix,
274 ENCODING (aptr->content->encoding));
279 const char dispchar[] = { 'I', 'A', 'F', '-' };
282 if (aptr->content->disposition < sizeof(dispchar))
283 ch = dispchar[aptr->content->disposition];
286 dprint(1, (debugfile, "ERROR: invalid content-disposition %d\n", aptr->content->disposition));
289 snprintf (dest, destlen, "%c", ch);
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)
305 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
306 snprintf (dest, destlen, fmt, aptr->num + 1);
311 optional = aptr->content->attach_qualifies;
313 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
314 mutt_format_s (dest, destlen, fmt, "Q");
318 if (flags & M_FORMAT_STAT_FILE)
321 stat (aptr->content->filename, &st);
325 l = aptr->content->length;
329 mutt_pretty_size (tmp, sizeof(tmp), l);
330 mutt_format_s (dest, destlen, prefix, tmp);
338 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
339 else if(!aptr->content->tagged)
344 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
345 else if (!aptr->tree)
350 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
351 else if (!aptr->content->unlink)
356 optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0;
359 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
360 snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
368 mutt_FormatString (dest, destlen, col, ifstring, mutt_attach_fmt, data, 0);
369 else if (flags & M_FORMAT_OPTIONAL)
370 mutt_FormatString (dest, destlen, col, elsestring, mutt_attach_fmt, data, 0);
374 static void attach_entry (char *b, size_t blen, MUTTMENU *menu, int num)
376 mutt_FormatString (b, blen, 0, NONULL (AttachFormat), mutt_attach_fmt, (unsigned long) (((ATTACHPTR **)menu->data)[num]), 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 || ascii_strcasecmp (subtype, "news") == 0);
397 static void prepend_curdir (char *dst, size_t dstlen)
401 if (!dst || !*dst || *dst == '/' || dstlen < 3 ||
402 /* XXX bad modularization, these are special to mutt_expand_path() */
403 !strchr ("~=+@<>!-^", *dst))
407 l = strlen (dst) + 2;
408 l = (l > dstlen ? dstlen : l);
409 memmove (dst + 2, dst, l);
415 static int mutt_query_save_attachment (FILE *fp, BODY *body, HEADER *hdr, char **directory)
418 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
425 if (directory && *directory)
426 mutt_concat_path (buf, *directory, mutt_basename (body->filename), sizeof (buf));
428 strfcpy (buf, body->filename, sizeof (buf));
431 body->encoding != ENCBASE64 &&
432 body->encoding != ENCQUOTEDPRINTABLE &&
433 mutt_is_message_type(body->type, body->subtype))
434 mutt_default_save(buf, sizeof(buf), body->hdr);
438 prepend_curdir (buf, sizeof (buf));
440 prompt = _("Save to file: ");
443 if (mutt_get_field (prompt, buf, sizeof (buf), M_FILE | M_CLEAR) != 0
451 mutt_expand_path (buf, sizeof (buf));
455 body->encoding != ENCBASE64 &&
456 body->encoding != ENCQUOTEDPRINTABLE &&
457 mutt_is_message_type (body->type, body->subtype));
463 /* check to make sure that this file is really the one the user wants */
464 if ((rc = mutt_save_confirm (buf, &st)) == 1)
466 prompt = _("Save to file: ");
471 strfcpy(tfile, buf, sizeof(tfile));
475 if ((rc = mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile), &append, directory)) == -1)
479 prompt = _("Save to file: ");
484 mutt_message _("Saving...");
485 if (mutt_save_attachment (fp, body, tfile, append, (hdr || !is_message) ? hdr : body->hdr) == 0)
487 mutt_message _("Attachment saved.");
492 prompt = _("Save to file: ");
499 void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr, MUTTMENU *menu)
501 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
502 char *directory = NULL;
504 int last = menu ? menu->current : -1;
509 for (; top; top = top->next)
511 if (!tag || top->tagged)
513 if (!option (OPTATTACHSPLIT))
519 strfcpy (buf, mutt_basename (NONULL (top->filename)), sizeof (buf));
520 prepend_curdir (buf, sizeof (buf));
522 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
523 M_FILE | M_CLEAR) != 0 || !buf[0])
525 mutt_expand_path (buf, sizeof (buf));
526 if (mutt_check_overwrite (top->filename, buf, tfile,
527 sizeof (tfile), &append, NULL))
529 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
530 if (rc == 0 && AttachSep && (fpout = fopen (tfile,"a")) != NULL)
532 fprintf(fpout, "%s", AttachSep);
533 safe_fclose (&fpout);
538 rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
539 if (rc == 0 && AttachSep && (fpout = fopen (tfile,"a")) != NULL)
541 fprintf(fpout, "%s", AttachSep);
542 safe_fclose (&fpout);
548 if (tag && menu && top->aptr)
550 menu->oldcurrent = menu->current;
551 menu->current = top->aptr->num;
552 menu_check_recenter (menu);
553 menu->redraw |= REDRAW_MOTION;
557 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
562 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
571 menu->oldcurrent = menu->current;
572 menu->current = last;
573 menu_check_recenter (menu);
574 menu->redraw |= REDRAW_MOTION;
577 if (!option (OPTATTACHSPLIT) && (rc == 0))
578 mutt_message _("Attachment saved.");
582 mutt_query_pipe_attachment (char *command, FILE *fp, BODY *body, int filter)
584 char tfile[_POSIX_PATH_MAX];
585 char warning[STRING+_POSIX_PATH_MAX];
589 snprintf (warning, sizeof (warning),
590 _("WARNING! You are about to overwrite %s, continue?"),
592 if (mutt_yesorno (warning, M_NO) != M_YES) {
596 mutt_mktemp (tfile, sizeof (tfile));
601 if (mutt_pipe_attachment (fp, body, command, tfile))
605 mutt_unlink (body->filename);
606 mutt_rename_file (tfile, body->filename);
607 mutt_update_encoding (body);
608 mutt_message _("Attachment filtered.");
613 if (filter && tfile[0])
618 static void pipe_attachment (FILE *fp, BODY *b, STATE *state)
625 mutt_decode_attachment (b, state);
627 state_puts (AttachSep, state);
631 if ((ifp = fopen (b->filename, "r")) == NULL)
633 mutt_perror ("fopen");
636 mutt_copy_stream (ifp, state->fpout);
639 state_puts (AttachSep, state);
644 pipe_attachment_list (char *command, FILE *fp, int tag, BODY *top, int filter,
647 for (; top; top = top->next)
649 if (!tag || top->tagged)
651 if (!filter && !option (OPTATTACHSPLIT))
652 pipe_attachment (fp, top, state);
654 mutt_query_pipe_attachment (command, fp, top, filter);
657 pipe_attachment_list (command, fp, tag, top->parts, filter, state);
663 void mutt_pipe_attachment_list (FILE *fp, int tag, BODY *top, int filter)
666 char buf[SHORT_STRING];
670 filter = 0; /* sanity check: we can't filter in the recv case yet */
673 memset (&state, 0, sizeof (STATE));
675 if (mutt_get_field ((filter ? _("Filter through: ") : _("Pipe to: ")),
676 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
679 mutt_expand_path (buf, sizeof (buf));
681 if (!filter && !option (OPTATTACHSPLIT))
684 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
685 pipe_attachment_list (buf, fp, tag, top, filter, &state);
686 safe_fclose (&state.fpout);
687 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
688 mutt_any_key_to_continue (NULL);
691 pipe_attachment_list (buf, fp, tag, top, filter, &state);
694 static int can_print (BODY *top, int tag)
698 for (; top; top = top->next)
700 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
701 if (!tag || top->tagged)
703 if (!rfc1524_mailcap_lookup (top, type, NULL, M_PRINT))
705 if (ascii_strcasecmp ("text/plain", top->subtype) &&
706 ascii_strcasecmp ("application/postscript", top->subtype))
708 if (!mutt_can_decode (top))
710 mutt_error (_("I dont know how to print %s attachments!"), type);
717 return (can_print (top->parts, tag));
724 static void print_attachment_list (FILE *fp, int tag, BODY *top, STATE *state)
729 for (; top; top = top->next)
731 if (!tag || top->tagged)
733 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
734 if (!option (OPTATTACHSPLIT) && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT))
736 if (!ascii_strcasecmp ("text/plain", top->subtype) ||
737 !ascii_strcasecmp ("application/postscript", top->subtype))
738 pipe_attachment (fp, top, state);
739 else if (mutt_can_decode (top))
741 /* decode and print */
743 char newfile[_POSIX_PATH_MAX] = "";
746 mutt_mktemp (newfile, sizeof (newfile));
747 if (mutt_decode_save_attachment (fp, top, newfile, M_PRINTING, 0) == 0)
749 if ((ifp = fopen (newfile, "r")) != NULL)
751 mutt_copy_stream (ifp, state->fpout);
754 state_puts (AttachSep, state);
757 mutt_unlink (newfile);
761 mutt_print_attachment (fp, top);
764 print_attachment_list (fp, tag, top->parts, state);
770 void mutt_print_attachment_list (FILE *fp, int tag, BODY *top)
775 if (query_quadoption (OPT_PRINT, tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) != M_YES)
778 if (!option (OPTATTACHSPLIT))
780 if (!can_print (top, tag))
783 memset (&state, 0, sizeof (STATE));
784 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
785 print_attachment_list (fp, tag, top, &state);
786 safe_fclose (&state.fpout);
787 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
788 mutt_any_key_to_continue (NULL);
791 print_attachment_list (fp, tag, top, &state);
795 mutt_update_attach_index (BODY *cur, ATTACHPTR ***idxp,
796 short *idxlen, short *idxmax,
799 ATTACHPTR **idx = *idxp;
800 while (--(*idxlen) >= 0)
801 idx[(*idxlen)]->content = NULL;
804 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
809 if (menu->current >= menu->max)
810 menu->current = menu->max - 1;
811 menu_check_recenter (menu);
812 menu->redraw |= REDRAW_INDEX;
818 mutt_attach_display_loop (MUTTMENU *menu, int op, FILE *fp, HEADER *hdr,
819 BODY *cur, ATTACHPTR ***idxp, short *idxlen, short *idxmax,
822 ATTACHPTR **idx = *idxp;
824 int old_optweed = option (OPTWEED);
825 set_option (OPTWEED);
832 case OP_DISPLAY_HEADERS:
833 toggle_option (OPTWEED);
837 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
842 case OP_MAIN_NEXT_UNDELETED: /* hack */
843 if (menu->current < menu->max - 1)
852 case OP_MAIN_PREV_UNDELETED: /* hack */
853 if (menu->current > 0)
862 /* when we edit the content-type, we should redisplay the attachment
864 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
867 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
872 /* functions which are passed through from the pager */
873 case OP_CHECK_TRADITIONAL:
874 if (!(WithCrypto & APPLICATION_PGP) || (hdr && hdr->security & PGP_TRADITIONAL_CHECKED))
880 case OP_ATTACH_COLLAPSE:
887 while (op != OP_NULL);
890 if (option (OPTWEED) != old_optweed)
891 toggle_option (OPTWEED);
896 static void attach_collapse (BODY *b, short collapse, short init, short just_one)
899 for (; b; b = b->next)
901 i = init || b->collapsed;
902 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
903 && !ascii_strcasecmp (b->subtype, "digest"))
904 attach_collapse (b->parts, 1, 1, 0);
905 else if (b->type == TYPEMULTIPART || mutt_is_message_type (b->type, b->subtype))
906 attach_collapse (b->parts, collapse, i, 0);
907 b->collapsed = collapse;
913 void mutt_attach_init (BODY *b)
915 for (; b; b = b->next)
920 mutt_attach_init (b->parts);
924 static const char *Function_not_permitted = N_("Function not permitted in attach-message mode.");
926 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
929 mutt_error _(Function_not_permitted); \
936 void mutt_view_attachments (HEADER *hdr)
939 int need_secured = 0;
941 char helpstr[LONG_STRING];
946 ATTACHPTR **idx = NULL;
952 /* make sure we have parsed this message */
953 mutt_parse_mime_message (Context, hdr);
955 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
957 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
961 if (WithCrypto && ((hdr->security & ENCRYPT) ||
962 (mutt_is_application_smime(hdr->content) & SMIMEOPAQUE)))
966 if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase(hdr->security))
968 mx_close_message (&msg);
971 if ((WithCrypto & APPLICATION_SMIME) && (hdr->security & APPLICATION_SMIME))
974 crypt_smime_getkeys (hdr->env);
976 if (mutt_is_application_smime(hdr->content))
978 secured = ! crypt_smime_decrypt_mime (msg->fp, &fp,
982 if ((mutt_is_application_smime (cur) & SMIMEOPAQUE))
987 fp = NULL; cur = NULL;
988 secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
990 mutt_free_body (&_cur);
997 if ((WithCrypto & APPLICATION_PGP) && (hdr->security & APPLICATION_PGP))
999 if (mutt_is_multipart_encrypted(hdr->content))
1000 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
1005 if (need_secured && !secured)
1007 mx_close_message (&msg);
1008 mutt_error _("Can't decrypt encrypted message!");
1013 if (!WithCrypto || !need_secured)
1019 menu = mutt_new_menu (MENU_ATTACH);
1020 menu->title = _("Attachments");
1021 menu->make_entry = attach_entry;
1022 menu->tag = mutt_tag_attach;
1023 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_ATTACH, AttachHelp);
1025 mutt_attach_init (cur);
1026 attach_collapse (cur, 0, 1, 0);
1027 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1032 op = mutt_menuLoop (menu);
1035 case OP_ATTACH_VIEW_MAILCAP:
1036 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
1038 menu->redraw = REDRAW_FULL;
1041 case OP_ATTACH_VIEW_TEXT:
1042 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
1044 menu->redraw = REDRAW_FULL;
1047 case OP_DISPLAY_HEADERS:
1048 case OP_VIEW_ATTACH:
1049 op = mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen, &idxmax, 1);
1050 menu->redraw = REDRAW_FULL;
1053 case OP_ATTACH_COLLAPSE:
1054 if (!idx[menu->current]->content->parts)
1056 mutt_error _("There are no subparts to show!");
1059 if (!idx[menu->current]->content->collapsed)
1060 attach_collapse (idx[menu->current]->content, 1, 0, 1);
1062 attach_collapse (idx[menu->current]->content, 0, 1, 1);
1063 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1066 case OP_FORGET_PASSPHRASE:
1067 crypt_forget_passphrase ();
1070 case OP_EXTRACT_KEYS:
1071 if ((WithCrypto & APPLICATION_PGP))
1073 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
1074 menu->tagprefix ? cur : idx[menu->current]->content);
1075 menu->redraw = REDRAW_FULL;
1079 case OP_CHECK_TRADITIONAL:
1080 if ((WithCrypto & APPLICATION_PGP)
1081 && crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
1082 : idx[menu->current]->content,
1085 hdr->security = crypt_query (cur);
1086 menu->redraw = REDRAW_FULL;
1091 mutt_print_attachment_list (fp, menu->tagprefix,
1092 menu->tagprefix ? cur : idx[menu->current]->content);
1096 mutt_pipe_attachment_list (fp, menu->tagprefix,
1097 menu->tagprefix ? cur : idx[menu->current]->content, 0);
1101 mutt_save_attachment_list (fp, menu->tagprefix,
1102 menu->tagprefix ? cur : idx[menu->current]->content, hdr, menu);
1104 if (!menu->tagprefix && option (OPTRESOLVE) && menu->current < menu->max - 1)
1107 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
1114 if (Context->magic == M_POP)
1117 mutt_error _("Can't delete attachment from POP server.");
1122 if (WithCrypto && hdr->security & ~PGP_TRADITIONAL_CHECKED)
1125 "Deletion of attachments from encrypted messages is unsupported.");
1129 if (!menu->tagprefix)
1131 if (idx[menu->current]->parent_type == TYPEMULTIPART)
1133 idx[menu->current]->content->deleted = 1;
1134 if (option (OPTRESOLVE) && menu->current < menu->max - 1)
1137 menu->redraw = REDRAW_MOTION_RESYNCH;
1140 menu->redraw = REDRAW_CURRENT;
1144 "Only deletion of multipart attachments is supported.");
1150 for (x = 0; x < menu->max; x++)
1152 if (idx[x]->content->tagged)
1154 if (idx[x]->parent_type == TYPEMULTIPART)
1156 idx[x]->content->deleted = 1;
1157 menu->redraw = REDRAW_INDEX;
1161 "Only deletion of multipart attachments is supported.");
1170 if (!menu->tagprefix)
1172 idx[menu->current]->content->deleted = 0;
1173 if (option (OPTRESOLVE) && menu->current < menu->max - 1)
1176 menu->redraw = REDRAW_MOTION_RESYNCH;
1179 menu->redraw = REDRAW_CURRENT;
1185 for (x = 0; x < menu->max; x++)
1187 if (idx[x]->content->tagged)
1189 idx[x]->content->deleted = 0;
1190 menu->redraw = REDRAW_INDEX;
1198 mutt_attach_resend (fp, hdr, idx, idxlen,
1199 menu->tagprefix ? NULL : idx[menu->current]->content);
1200 menu->redraw = REDRAW_FULL;
1203 case OP_BOUNCE_MESSAGE:
1205 mutt_attach_bounce (fp, hdr, idx, idxlen,
1206 menu->tagprefix ? NULL : idx[menu->current]->content);
1207 menu->redraw = REDRAW_FULL;
1210 case OP_FORWARD_MESSAGE:
1212 mutt_attach_forward (fp, hdr, idx, idxlen,
1213 menu->tagprefix ? NULL : idx[menu->current]->content);
1214 menu->redraw = REDRAW_FULL;
1218 case OP_GROUP_REPLY:
1224 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1225 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1226 mutt_attach_reply (fp, hdr, idx, idxlen,
1227 menu->tagprefix ? NULL : idx[menu->current]->content, flags);
1228 menu->redraw = REDRAW_FULL;
1232 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1233 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1237 mx_close_message (&msg);
1238 hdr->attach_del = 0;
1239 while (idxmax-- > 0)
1243 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1244 hdr->attach_del = 1;
1245 if (idx[idxmax]->content)
1246 idx[idxmax]->content->aptr = NULL;
1247 FREE (&idx[idxmax]->tree);
1248 FREE (&idx[idxmax]);
1250 if (hdr->attach_del)
1255 if (WithCrypto && need_secured && secured)
1258 mutt_free_body (&cur);
1261 mutt_menuDestroy (&menu);