2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 1999-2000 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 #include "mutt_curses.h"
26 #include "mutt_menu.h"
34 #include "mutt_crypt.h"
44 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
45 static char LastSaveFolder[_POSIX_PATH_MAX] = "";
47 #define CHECK_READONLY if (Context->readonly) \
50 mutt_error _(Mailbox_is_read_only); \
54 static struct mapping_t AttachHelp[] = {
55 {N_("Exit"), OP_EXIT},
56 {N_("Save"), OP_SAVE},
57 {N_("Pipe"), OP_PIPE},
58 {N_("Print"), OP_PRINT},
59 {N_("Help"), OP_HELP},
63 int mutt_extract_path (char *filename, char *path)
65 char *tmp = safe_malloc (sizeof (char) * _POSIX_PATH_MAX);
70 while (*filename != '\0') {
71 if (*filename == '/') {
72 *help_ptr++ = *filename++;
77 *help_ptr++ = *filename++;
83 void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
89 for (x = 0; x < idxlen; x++) {
91 if (2 * (idx[x]->level + 2) < sizeof (buf)) {
93 s = buf + 2 * (idx[x]->level - 1);
94 *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
104 if (mutt_strcmp (idx[x]->tree, buf) != 0)
105 mutt_str_replace (&idx[x]->tree, buf);
108 idx[x]->tree = safe_strdup (buf);
110 if (2 * (idx[x]->level + 2) < sizeof (buf) && idx[x]->level) {
111 s = buf + 2 * (idx[x]->level - 1);
112 *s++ = (idx[x]->content->next) ? '\005' : '\006';
118 ATTACHPTR **mutt_gen_attach_list (BODY * m,
122 short *idxmax, int level, int compose)
127 for (; m; m = m->next) {
128 if (*idxlen == *idxmax) {
129 safe_realloc (&idx, sizeof (ATTACHPTR *) * ((*idxmax) += 5));
130 for (i = *idxlen; i < *idxmax; i++)
134 if (m->type == TYPEMULTIPART && m->parts
136 || (parent_type == -1
137 && ascii_strcasecmp ("alternative", m->subtype)))
138 && (!(WithCrypto & APPLICATION_PGP)
139 || !mutt_is_multipart_encrypted (m))
142 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level,
147 idx[*idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
149 new = idx[(*idxlen)++];
152 new->parent_type = parent_type;
155 /* We don't support multipart messages in the compose menu yet */
156 if (!compose && !m->collapsed &&
157 ((m->type == TYPEMULTIPART && (!(WithCrypto & APPLICATION_PGP)
158 || !mutt_is_multipart_encrypted (m))
160 || mutt_is_message_type (m->type, m->subtype))) {
162 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
169 mutt_update_tree (idx, *idxlen);
174 /* %c = character set: convert?
178 * %e = MIME content-transfer-encoding
180 * %I = content-disposition, either I (inline) or A (attachment)
183 * %m = major MIME type
185 * %n = attachment number
189 const char *mutt_attach_fmt (char *dest,
194 const char *ifstring,
195 const char *elsestring,
196 unsigned long data, format_flag flags)
199 char tmp[SHORT_STRING];
200 char charset[SHORT_STRING];
201 ATTACHPTR *aptr = (ATTACHPTR *) data;
202 int optional = (flags & M_FORMAT_OPTIONAL);
208 if (mutt_is_text_part (aptr->content) &&
209 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
210 mutt_format_s (dest, destlen, prefix, charset);
212 mutt_format_s (dest, destlen, prefix, "");
214 else if (!mutt_is_text_part (aptr->content) ||
215 !mutt_get_body_charset (charset, sizeof (charset),
222 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
223 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
224 aptr->content->noconv ? 'n' : 'c');
226 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
231 if (aptr->content->description) {
232 mutt_format_s (dest, destlen, prefix, aptr->content->description);
235 if (mutt_is_message_type (aptr->content->type, aptr->content->subtype)
236 && MsgFmt && aptr->content->hdr) {
237 char s[SHORT_STRING];
239 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
240 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT |
241 M_FORMAT_ARROWCURSOR);
243 mutt_format_s (dest, destlen, prefix, s);
247 if (!aptr->content->filename) {
248 mutt_format_s (dest, destlen, prefix, "<no description>");
252 else if (aptr->content->description ||
253 (mutt_is_message_type
254 (aptr->content->type, aptr->content->subtype)
255 && MsgFmt && aptr->content->hdr))
257 /* FALLS THROUGH TO 'f' */
260 if (aptr->content->filename && *aptr->content->filename == '/') {
261 char path[_POSIX_PATH_MAX];
263 strfcpy (path, aptr->content->filename, sizeof (path));
264 mutt_pretty_mailbox (path);
265 mutt_format_s (dest, destlen, prefix, path);
268 mutt_format_s (dest, destlen, prefix,
269 NONULL (aptr->content->filename));
271 else if (!aptr->content->filename)
276 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
277 else if (!aptr->content->deleted)
282 mutt_format_s (dest, destlen, prefix,
283 ENCODING (aptr->content->encoding));
287 snprintf (dest, destlen, "%c",
288 (aptr->content->disposition == DISPINLINE) ? 'I' : 'A');
293 mutt_format_s (dest, destlen, prefix, TYPE (aptr->content));
297 mutt_format_s (dest, destlen, prefix, aptr->content->subtype);
298 else if (!aptr->content->subtype)
303 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
304 snprintf (dest, destlen, fmt, aptr->num + 1);
308 if (flags & M_FORMAT_STAT_FILE) {
311 stat (aptr->content->filename, &st);
315 l = aptr->content->length;
318 mutt_pretty_size (tmp, sizeof (tmp), l);
319 mutt_format_s (dest, destlen, prefix, tmp);
327 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
328 else if (!aptr->content->tagged)
333 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
334 else if (!aptr->tree)
339 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
340 else if (!aptr->content->unlink)
348 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
349 else if (flags & M_FORMAT_OPTIONAL)
350 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
354 void attach_entry (char *b, size_t blen, MUTTMENU * menu, int num)
356 mutt_FormatString (b, blen, NONULL (AttachFormat), mutt_attach_fmt,
357 (unsigned long) (((ATTACHPTR **) menu->data)[num]),
358 M_FORMAT_ARROWCURSOR);
361 int mutt_tag_attach (MUTTMENU * menu, int n, int m)
363 BODY *cur = ((ATTACHPTR **) menu->data)[n]->content;
364 int ot = cur->tagged;
366 cur->tagged = (m >= 0 ? m : !cur->tagged);
367 return cur->tagged - ot;
370 int mutt_is_message_type (int type, const char *subtype)
372 if (type != TYPEMESSAGE)
375 subtype = NONULL (subtype);
376 return (ascii_strcasecmp (subtype, "rfc822") == 0
377 || ascii_strcasecmp (subtype, "news") == 0);
380 static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
384 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
385 char path[_POSIX_PATH_MAX] = "";
391 if (body->filename) {
392 if (directory && *directory)
393 mutt_concat_path (buf, *directory, mutt_basename (body->filename),
396 strfcpy (buf, body->filename, sizeof (buf));
398 else if (body->hdr &&
399 body->encoding != ENCBASE64 &&
400 body->encoding != ENCQUOTEDPRINTABLE &&
401 mutt_is_message_type (body->type, body->subtype))
402 mutt_default_save (buf, sizeof (buf), body->hdr);
406 prompt = _("Save to file ('#' for last used folder): ");
409 mutt_get_field (prompt, buf, sizeof (buf),
410 M_FILE | M_CLEAR | M_LASTFOLDER);
411 if (((ret != 0) && (ret != 2)) || (!buf[0] && ret != 2))
415 char tmpbuf[_POSIX_PATH_MAX];
417 snprintf (tmpbuf, sizeof (tmpbuf), "%s%s", LastSaveFolder, buf);
418 strfcpy (buf, tmpbuf, sizeof (buf));
419 ret = mutt_get_field (_("Save to file: ")
420 , buf, sizeof (buf), M_FILE);
421 if ((ret != 0) || (!buf[0]))
425 mutt_extract_path (buf, path);
426 strfcpy (LastSaveFolder, path, sizeof (LastSaveFolder));
430 mutt_expand_path (buf, sizeof (buf));
434 body->encoding != ENCBASE64 &&
435 body->encoding != ENCQUOTEDPRINTABLE &&
436 mutt_is_message_type (body->type, body->subtype));
441 /* check to make sure that this file is really the one the user wants */
442 if ((rc = mutt_save_confirm (buf, &st)) == 1) {
443 prompt = _("Save to file: ");
448 strfcpy (tfile, buf, sizeof (tfile));
452 mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile),
453 &append, directory)) == -1)
456 prompt = _("Save to file: ");
461 mutt_message _("Saving...");
463 if (mutt_save_attachment
464 (fp, body, tfile, append,
465 (hdr || !is_message) ? hdr : body->hdr) == 0) {
466 mutt_message _("Attachment saved.");
471 prompt = _("Save to file: ");
478 void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
481 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
482 char *directory = NULL;
484 int last = menu ? menu->current : -1;
489 for (; top; top = top->next) {
490 if (!tag || top->tagged) {
491 if (!option (OPTATTACHSPLIT)) {
495 strfcpy (buf, NONULL (top->filename), sizeof (buf));
496 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
497 M_FILE | M_CLEAR) != 0 || !buf[0])
499 mutt_expand_path (buf, sizeof (buf));
500 if (mutt_check_overwrite (top->filename, buf, tfile,
501 sizeof (tfile), &append, NULL))
503 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
504 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
505 fprintf (fpout, "%s", AttachSep);
510 rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
511 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
512 fprintf (fpout, "%s", AttachSep);
518 if (tag && menu && top->aptr) {
519 menu->oldcurrent = menu->current;
520 menu->current = top->aptr->num;
521 menu_check_recenter (menu);
522 menu->redraw |= REDRAW_MOTION;
526 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
531 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
539 menu->oldcurrent = menu->current;
540 menu->current = last;
541 menu_check_recenter (menu);
542 menu->redraw |= REDRAW_MOTION;
545 if (!option (OPTATTACHSPLIT) && (rc == 0))
546 mutt_message _("Attachment saved.");
550 mutt_query_pipe_attachment (char *command, FILE * fp, BODY * body, int filter)
552 char tfile[_POSIX_PATH_MAX];
553 char warning[STRING + _POSIX_PATH_MAX];
556 snprintf (warning, sizeof (warning),
557 _("WARNING! You are about to overwrite %s, continue?"),
559 if (mutt_yesorno (warning, M_NO) != M_YES) {
560 CLEARLINE (LINES - 1);
568 if (mutt_pipe_attachment (fp, body, command, tfile)) {
570 mutt_unlink (body->filename);
571 mutt_rename_file (tfile, body->filename);
572 mutt_update_encoding (body);
573 mutt_message _("Attachment filtered.");
577 if (filter && tfile[0])
582 static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
588 mutt_decode_attachment (b, state);
590 state_puts (AttachSep, state);
593 if ((ifp = fopen (b->filename, "r")) == NULL) {
594 mutt_perror ("fopen");
597 mutt_copy_stream (ifp, state->fpout);
600 state_puts (AttachSep, state);
605 pipe_attachment_list (char *command, FILE * fp, int tag, BODY * top,
606 int filter, STATE * state)
608 for (; top; top = top->next) {
609 if (!tag || top->tagged) {
610 if (!filter && !option (OPTATTACHSPLIT))
611 pipe_attachment (fp, top, state);
613 mutt_query_pipe_attachment (command, fp, top, filter);
616 pipe_attachment_list (command, fp, tag, top->parts, filter, state);
622 void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int filter)
625 char buf[SHORT_STRING];
629 filter = 0; /* sanity check: we can't filter in the recv case yet */
632 memset (&state, 0, sizeof (STATE));
634 if (mutt_get_field ((filter ? _("Filter through: ") : _("Pipe to: ")),
635 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
638 mutt_expand_path (buf, sizeof (buf));
640 if (!filter && !option (OPTATTACHSPLIT)) {
642 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
643 pipe_attachment_list (buf, fp, tag, top, filter, &state);
644 fclose (state.fpout);
645 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
646 mutt_any_key_to_continue (NULL);
649 pipe_attachment_list (buf, fp, tag, top, filter, &state);
652 static int can_print (BODY * top, int tag)
656 for (; top; top = top->next) {
657 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
658 if (!tag || top->tagged) {
659 if (!rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
660 if (ascii_strcasecmp ("text/plain", top->subtype) &&
661 ascii_strcasecmp ("application/postscript", top->subtype)) {
662 if (!mutt_can_decode (top)) {
663 mutt_error (_("I dont know how to print %s attachments!"), type);
670 return (can_print (top->parts, tag));
677 static void print_attachment_list (FILE * fp, int tag, BODY * top,
683 for (; top; top = top->next) {
684 if (!tag || top->tagged) {
685 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
686 if (!option (OPTATTACHSPLIT)
687 && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
688 if (!ascii_strcasecmp ("text/plain", top->subtype)
689 || !ascii_strcasecmp ("application/postscript", top->subtype))
690 pipe_attachment (fp, top, state);
691 else if (mutt_can_decode (top)) {
692 /* decode and print */
694 char newfile[_POSIX_PATH_MAX] = "";
697 mutt_mktemp (newfile);
698 if (mutt_decode_save_attachment (fp, top, newfile, M_PRINTING, 0) ==
700 if ((ifp = fopen (newfile, "r")) != NULL) {
701 mutt_copy_stream (ifp, state->fpout);
704 state_puts (AttachSep, state);
707 mutt_unlink (newfile);
711 mutt_print_attachment (fp, top);
714 print_attachment_list (fp, tag, top->parts, state);
720 void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
728 tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) !=
732 if (!option (OPTATTACHSPLIT)) {
733 if (!can_print (top, tag))
736 memset (&state, 0, sizeof (STATE));
737 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
738 print_attachment_list (fp, tag, top, &state);
739 fclose (state.fpout);
740 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
741 mutt_any_key_to_continue (NULL);
744 print_attachment_list (fp, tag, top, &state);
748 mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
749 short *idxlen, short *idxmax, MUTTMENU * menu)
751 ATTACHPTR **idx = *idxp;
753 while (--(*idxlen) >= 0)
754 idx[(*idxlen)]->content = NULL;
757 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
762 if (menu->current >= menu->max)
763 menu->current = menu->max - 1;
764 menu_check_recenter (menu);
765 menu->redraw |= REDRAW_INDEX;
771 mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
772 BODY * cur, ATTACHPTR *** idxp, short *idxlen,
773 short *idxmax, int recv)
775 ATTACHPTR **idx = *idxp;
778 int old_optweed = option (OPTWEED);
780 set_option (OPTWEED);
785 case OP_DISPLAY_HEADERS:
786 toggle_option (OPTWEED);
790 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
795 case OP_MAIN_NEXT_UNDELETED: /* hack */
796 if (menu->current < menu->max - 1) {
804 case OP_MAIN_PREV_UNDELETED: /* hack */
805 if (menu->current > 0) {
813 /* when we edit the content-type, we should redisplay the attachment
815 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
817 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
822 /* functions which are passed through from the pager */
823 case OP_CHECK_TRADITIONAL:
824 if (!(WithCrypto & APPLICATION_PGP)
825 || (hdr && hdr->security & PGP_TRADITIONAL_CHECKED)) {
830 case OP_ATTACH_COLLAPSE:
837 while (op != OP_NULL);
840 if (option (OPTWEED) != old_optweed)
841 toggle_option (OPTWEED);
846 static void attach_collapse (BODY * b, short collapse, short init,
851 for (; b; b = b->next) {
852 i = init || b->collapsed;
853 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
854 && !ascii_strcasecmp (b->subtype, "digest"))
855 attach_collapse (b->parts, 1, 1, 0);
856 else if (b->type == TYPEMULTIPART
857 || mutt_is_message_type (b->type, b->subtype))
858 attach_collapse (b->parts, collapse, i, 0);
859 b->collapsed = collapse;
865 void mutt_attach_init (BODY * b)
867 for (; b; b = b->next) {
871 mutt_attach_init (b->parts);
875 static const char *Function_not_permitted =
876 N_("Function not permitted in attach-message mode.");
878 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
881 mutt_error _(Function_not_permitted); \
888 void mutt_view_attachments (HEADER * hdr)
891 int need_secured = 0;
893 char helpstr[SHORT_STRING];
898 ATTACHPTR **idx = NULL;
904 /* make sure we have parsed this message */
905 mutt_parse_mime_message (Context, hdr);
907 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
909 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
913 if (WithCrypto && ((hdr->security & ENCRYPT) ||
914 (mutt_is_application_smime (hdr->content) &
918 if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase (hdr->security)) {
919 mx_close_message (&msg);
922 if ((WithCrypto & APPLICATION_SMIME)
923 && (hdr->security & APPLICATION_SMIME)) {
925 crypt_smime_getkeys (hdr->env);
927 if (mutt_is_application_smime (hdr->content)) {
928 secured = !crypt_smime_decrypt_mime (msg->fp, &fp,
932 if ((mutt_is_application_smime (cur) & SMIMEOPAQUE)) {
938 secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
940 mutt_free_body (&_cur);
947 if ((WithCrypto & APPLICATION_PGP) && (hdr->security & APPLICATION_PGP)) {
948 if (mutt_is_multipart_encrypted (hdr->content))
949 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
954 if (need_secured && !secured) {
955 mx_close_message (&msg);
956 mutt_error _("Can't decrypt encrypted message!");
962 if (!WithCrypto || !need_secured) {
967 menu = mutt_new_menu ();
968 menu->menu = MENU_ATTACH;
969 menu->title = _("Attachments");
970 menu->make_entry = attach_entry;
971 menu->tag = mutt_tag_attach;
973 mutt_compile_help (helpstr, sizeof (helpstr), MENU_ATTACH, AttachHelp);
975 mutt_attach_init (cur);
976 attach_collapse (cur, 0, 1, 0);
977 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
981 op = mutt_menuLoop (menu);
983 case OP_ATTACH_VIEW_MAILCAP:
984 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
986 menu->redraw = REDRAW_FULL;
989 case OP_ATTACH_VIEW_TEXT:
990 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
992 menu->redraw = REDRAW_FULL;
995 case OP_DISPLAY_HEADERS:
998 mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen,
1000 menu->redraw = REDRAW_FULL;
1003 case OP_ATTACH_COLLAPSE:
1004 if (!idx[menu->current]->content->parts) {
1005 mutt_error _("There are no subparts to show!");
1009 if (!idx[menu->current]->content->collapsed)
1010 attach_collapse (idx[menu->current]->content, 1, 0, 1);
1012 attach_collapse (idx[menu->current]->content, 0, 1, 1);
1013 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1016 case OP_FORGET_PASSPHRASE:
1017 crypt_forget_passphrase ();
1020 case OP_EXTRACT_KEYS:
1021 if ((WithCrypto & APPLICATION_PGP)) {
1022 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
1025 idx[menu->current]->
1027 menu->redraw = REDRAW_FULL;
1031 case OP_CHECK_TRADITIONAL:
1032 if ((WithCrypto & APPLICATION_PGP)
1033 && crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
1034 : idx[menu->current]->content,
1036 hdr->security = crypt_query (cur);
1037 menu->redraw = REDRAW_FULL;
1042 mutt_print_attachment_list (fp, menu->tagprefix,
1043 menu->tagprefix ? cur : idx[menu->current]->
1048 mutt_pipe_attachment_list (fp, menu->tagprefix,
1049 menu->tagprefix ? cur : idx[menu->current]->
1054 mutt_save_attachment_list (fp, menu->tagprefix,
1055 menu->tagprefix ? cur : idx[menu->current]->
1056 content, hdr, menu);
1058 if (!menu->tagprefix && option (OPTRESOLVE)
1059 && menu->current < menu->max - 1)
1062 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
1069 if (Context->magic == M_POP) {
1071 mutt_error _("Can't delete attachment from POP server.");
1078 if (Context->magic == M_NNTP) {
1080 mutt_error _("Can't delete attachment from newsserver.");
1086 if (WithCrypto && hdr->security) {
1089 ("Deletion of attachments from encrypted messages is unsupported.");
1092 if (!menu->tagprefix) {
1093 if (idx[menu->current]->parent_type == TYPEMULTIPART) {
1094 idx[menu->current]->content->deleted = 1;
1095 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1097 menu->redraw = REDRAW_MOTION_RESYNCH;
1100 menu->redraw = REDRAW_CURRENT;
1104 _("Only deletion of multipart attachments is supported.");
1109 for (x = 0; x < menu->max; x++) {
1110 if (idx[x]->content->tagged) {
1111 if (idx[x]->parent_type == TYPEMULTIPART) {
1112 idx[x]->content->deleted = 1;
1113 menu->redraw = REDRAW_INDEX;
1117 _("Only deletion of multipart attachments is supported.");
1126 if (!menu->tagprefix) {
1127 idx[menu->current]->content->deleted = 0;
1128 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1130 menu->redraw = REDRAW_MOTION_RESYNCH;
1133 menu->redraw = REDRAW_CURRENT;
1138 for (x = 0; x < menu->max; x++) {
1139 if (idx[x]->content->tagged) {
1140 idx[x]->content->deleted = 0;
1141 menu->redraw = REDRAW_INDEX;
1149 mutt_attach_resend (fp, hdr, idx, idxlen,
1150 menu->tagprefix ? NULL : idx[menu->current]->
1152 menu->redraw = REDRAW_FULL;
1155 case OP_BOUNCE_MESSAGE:
1157 mutt_attach_bounce (fp, hdr, idx, idxlen,
1158 menu->tagprefix ? NULL : idx[menu->current]->
1160 menu->redraw = REDRAW_FULL;
1163 case OP_FORWARD_MESSAGE:
1165 mutt_attach_forward (fp, hdr, idx, idxlen,
1166 menu->tagprefix ? NULL : idx[menu->current]->
1168 menu->redraw = REDRAW_FULL;
1172 case OP_FORWARD_TO_GROUP:
1174 mutt_attach_forward (fp, hdr, idx, idxlen,
1175 menu->tagprefix ? NULL : idx[menu->current]->
1177 menu->redraw = REDRAW_FULL;
1183 if (!idx[menu->current]->content->hdr->env->followup_to ||
1184 mutt_strcasecmp (idx[menu->current]->content->hdr->env->followup_to,
1186 || query_quadoption (OPT_FOLLOWUPTOPOSTER,
1187 _("Reply by mail as poster prefers?")) !=
1189 mutt_attach_reply (fp, hdr, idx, idxlen,
1190 menu->tagprefix ? NULL : idx[menu->current]->
1191 content, SENDNEWS | SENDREPLY);
1192 menu->redraw = REDRAW_FULL;
1198 case OP_GROUP_REPLY:
1204 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1205 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1206 mutt_attach_reply (fp, hdr, idx, idxlen,
1207 menu->tagprefix ? NULL : idx[menu->current]->content,
1209 menu->redraw = REDRAW_FULL;
1213 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1214 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1218 mx_close_message (&msg);
1219 hdr->attach_del = 0;
1220 while (idxmax-- > 0) {
1223 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1224 hdr->attach_del = 1;
1225 if (idx[idxmax]->content)
1226 idx[idxmax]->content->aptr = NULL;
1227 FREE (&idx[idxmax]->tree);
1228 FREE (&idx[idxmax]);
1230 if (hdr->attach_del)
1235 if (WithCrypto && need_secured && secured) {
1237 mutt_free_body (&cur);
1240 mutt_menuDestroy (&menu);