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.
11 #include <lib-lib/lib-lib.h>
13 #include <lib-mime/mime.h>
14 #include <lib-sys/unix.h>
16 #include <lib-ui/curses.h>
17 #include <lib-ui/enter.h>
18 #include <lib-ui/menu.h>
19 #include <lib-mx/mx.h>
24 #include "recvattach.h"
28 #define SW (option(OPTMBOXPANE)?SidebarWidth:0)
30 void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
36 for (x = 0; x < idxlen; x++) {
38 if (2 * (idx[x]->level + 2) < ssizeof (buf)) {
40 s = buf + 2 * (idx[x]->level - 1);
41 *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
51 if (m_strcmp(idx[x]->tree, buf) != 0)
52 m_strreplace(&idx[x]->tree, buf);
55 idx[x]->tree = m_strdup(buf);
57 if (2 * (idx[x]->level + 2) < ssizeof (buf) && idx[x]->level) {
58 s = buf + 2 * (idx[x]->level - 1);
59 *s++ = (idx[x]->content->next) ? '\005' : '\006';
65 ATTACHPTR **mutt_gen_attach_list (BODY * m,
69 short *idxmax, int level, int compose)
74 for (; m; m = m->next) {
75 if (*idxlen == *idxmax) {
76 p_realloc(&idx, (*idxmax) += 5);
77 for (i = *idxlen; i < *idxmax; i++)
81 if (m->type == TYPEMULTIPART && m->parts
84 && ascii_strcasecmp ("alternative", m->subtype)))
85 && (!mutt_is_multipart_encrypted (m))
88 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level,
93 idx[*idxlen] = p_new(ATTACHPTR, 1);
95 new = idx[(*idxlen)++];
98 new->parent_type = parent_type;
101 /* We don't support multipart messages in the compose menu yet */
102 if (!compose && !m->collapsed
103 && ((m->type == TYPEMULTIPART && !mutt_is_multipart_encrypted(m))
104 || mutt_is_message_type(m)))
106 idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
113 mutt_update_tree (idx, *idxlen);
118 /* %c = character set: convert?
122 * %e = MIME content-transfer-encoding
124 * %I = content-disposition, either I (inline) or A (attachment)
127 * %m = major MIME type
129 * %n = attachment number
134 mutt_attach_fmt(char *dest, ssize_t destlen, char op, const char *src,
135 const char *prefix, const char *ifstr, const char *elstr,
136 anytype data, format_flag flags)
140 char charset[STRING];
141 ATTACHPTR *aptr = data.ptr;
142 int optional = (flags & M_FORMAT_OPTIONAL);
148 if (mutt_is_text_part (aptr->content) &&
149 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
150 mutt_format_s (dest, destlen, prefix, charset);
152 mutt_format_s (dest, destlen, prefix, "");
154 else if (!mutt_is_text_part (aptr->content) ||
155 !mutt_get_body_charset (charset, sizeof (charset),
162 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
163 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
164 aptr->content->noconv ? 'n' : 'c');
166 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
171 if (aptr->content->description) {
172 mutt_format_s (dest, destlen, prefix, aptr->content->description);
175 if (mutt_is_message_type(aptr->content) && MsgFmt && aptr->content->hdr)
179 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
180 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT);
182 mutt_format_s (dest, destlen, prefix, s);
186 if (!aptr->content->filename) {
187 mutt_format_s (dest, destlen, prefix, "<no description>");
191 else if (aptr->content->description ||
192 (mutt_is_message_type(aptr->content)
193 && MsgFmt && aptr->content->hdr))
195 /* FALLS THROUGH TO 'f' */
198 if (aptr->content->filename && *aptr->content->filename == '/') {
199 char path[_POSIX_PATH_MAX];
201 m_strcpy(path, sizeof(path), aptr->content->filename);
202 mutt_pretty_mailbox (path);
203 mutt_format_s (dest, destlen, prefix, path);
206 mutt_format_s (dest, destlen, prefix,
207 NONULL (aptr->content->filename));
209 else if (!aptr->content->filename)
214 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
215 else if (!aptr->content->deleted)
220 mutt_format_s (dest, destlen, prefix,
221 ENCODING (aptr->content->encoding));
225 snprintf (dest, destlen, "%c",
226 (aptr->content->disposition == DISPINLINE) ? 'I' : 'A');
231 mutt_format_s (dest, destlen, prefix, TYPE (aptr->content));
235 mutt_format_s (dest, destlen, prefix, aptr->content->subtype);
236 else if (!aptr->content->subtype)
241 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
242 snprintf (dest, destlen, fmt, aptr->num + 1);
247 optional = aptr->content->attach_qualifies;
249 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
250 mutt_format_s (dest, destlen, fmt, "Q");
254 if (flags & M_FORMAT_STAT_FILE) {
257 stat (aptr->content->filename, &st);
261 l = aptr->content->length;
264 mutt_pretty_size (tmp, sizeof (tmp), l);
265 mutt_format_s (dest, destlen, prefix, tmp);
273 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
274 else if (!aptr->content->tagged)
279 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
280 else if (!aptr->tree)
285 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
286 else if (!aptr->content->unlink)
291 optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0;
293 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
294 snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
301 if (flags & M_FORMAT_OPTIONAL)
302 m_strformat(dest, destlen, 0, optional ? ifstr : elstr,
303 mutt_attach_fmt, data, 0);
307 static void attach_entry(char *b, ssize_t blen, MUTTMENU * menu, int num)
309 m_strformat(b, blen, COLS - SW, AttachFormat, mutt_attach_fmt,
310 ((ATTACHPTR **) menu->data)[num], 0);
313 int mutt_tag_attach (MUTTMENU * menu, int n, int m)
315 BODY *cur = ((ATTACHPTR **) menu->data)[n]->content;
316 int ot = cur->tagged;
318 cur->tagged = (m >= 0 ? m : !cur->tagged);
319 return cur->tagged - ot;
322 static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
326 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
332 if (body->filename) {
333 if (directory && *directory)
334 mutt_concat_path(buf, sizeof(buf), *directory,
335 mutt_basename(body->filename));
337 m_strcpy(buf, sizeof(buf), body->filename);
339 else if (body->hdr &&
340 body->encoding != ENCBASE64 &&
341 body->encoding != ENCQUOTEDPRINTABLE &&
342 mutt_is_message_type(body))
343 mutt_default_save (buf, sizeof (buf), body->hdr);
347 prompt = _("Save to file ('#' for last used folder): ");
349 static char LastSaveFolder[_POSIX_PATH_MAX] = ".";
351 ret = mutt_get_field(prompt, buf, sizeof (buf),
352 M_FILE | M_CLEAR | M_LASTFOLDER);
353 if (((ret != 0) && (ret != 2)) || (!buf[0] && ret != 2))
357 char tmpbuf[_POSIX_PATH_MAX];
359 snprintf (tmpbuf, sizeof (tmpbuf), "%s/%s", LastSaveFolder, buf);
360 m_strcpy(buf, sizeof(buf), tmpbuf);
361 ret = mutt_get_field(_("Save to file: "), buf, sizeof (buf), M_FILE);
362 if ((ret != 0) || (!buf[0]))
365 m_dirname(LastSaveFolder, sizeof(LastSaveFolder), buf);
368 mutt_expand_path(buf, sizeof(buf));
370 is_message = (fp && body->hdr &&
371 body->encoding != ENCBASE64 &&
372 body->encoding != ENCQUOTEDPRINTABLE &&
373 mutt_is_message_type(body));
378 /* check to make sure that this file is really the one the user wants */
379 rc = mutt_save_confirm(buf, &st);
380 m_strcpy(tfile, sizeof(tfile), buf);
382 rc = mutt_check_overwrite(body->filename, buf, tfile, sizeof(tfile),
388 prompt = _("Save to file: ");
392 mutt_message _("Saving...");
394 if (mutt_save_attachment(fp, body, tfile, append,
395 (hdr || !is_message) ? hdr : body->hdr) == 0)
397 mutt_message _("Attachment saved.");
400 prompt = _("Save to file: ");
407 void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
410 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
411 char *directory = NULL;
413 int last = menu ? menu->current : -1;
418 for (; top; top = top->next) {
419 if (!tag || top->tagged) {
420 if (!option (OPTATTACHSPLIT)) {
424 m_strcpy(buf, sizeof(buf), NONULL(top->filename));
425 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
426 M_FILE | M_CLEAR) != 0 || !buf[0])
428 mutt_expand_path (buf, sizeof (buf));
429 if (mutt_check_overwrite (top->filename, buf, tfile,
430 sizeof (tfile), &append, NULL))
432 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
433 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
434 fprintf (fpout, "%s", AttachSep);
439 rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
440 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
441 fprintf (fpout, "%s", AttachSep);
446 if (tag && menu && top->aptr) {
447 menu->oldcurrent = menu->current;
448 menu->current = top->aptr->num;
449 menu_check_recenter (menu);
450 menu->redraw |= REDRAW_MOTION;
454 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
459 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
464 p_delete(&directory);
467 menu->oldcurrent = menu->current;
468 menu->current = last;
469 menu_check_recenter (menu);
470 menu->redraw |= REDRAW_MOTION;
473 if (!option (OPTATTACHSPLIT) && (rc == 0))
474 mutt_message _("Attachment saved.");
478 mutt_query_pipe_attachment(char *command, FILE * fp, BODY * body, int afilter)
480 char tfile[_POSIX_PATH_MAX];
481 char warning[STRING + _POSIX_PATH_MAX];
485 snprintf(warning, sizeof (warning),
486 _("WARNING! You are about to overwrite %s, continue?"),
488 if (mutt_yesorno (warning, M_NO) != M_YES) {
489 CLEARLINE (LINES - 1);
492 tempfd = m_tempfd(tfile, sizeof(tfile), NONULL(mod_core.tmpdir), NULL);
495 if (mutt_pipe_attachment(fp, body, command, tempfd)) {
497 mutt_unlink (body->filename);
498 mutt_rename_file (tfile, body->filename);
499 mutt_update_encoding (body);
500 mutt_message _("Attachment filtered.");
502 } else if (afilter) {
508 static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
514 mutt_decode_attachment (b, state);
516 state_puts (AttachSep, state);
518 if ((ifp = fopen (b->filename, "r")) == NULL) {
519 mutt_perror ("fopen");
522 mutt_copy_stream (ifp, state->fpout);
525 state_puts (AttachSep, state);
530 pipe_attachment_list (char *command, FILE * fp, int tag, BODY * top,
531 int afilter, STATE * state)
533 for (; top; top = top->next) {
534 if (!tag || top->tagged) {
535 if (!afilter && !option (OPTATTACHSPLIT))
536 pipe_attachment (fp, top, state);
538 mutt_query_pipe_attachment (command, fp, top, afilter);
541 pipe_attachment_list (command, fp, tag, top->parts, afilter, state);
547 void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int afilter)
554 afilter = 0; /* sanity check: we can't filter in the recv case yet */
559 if (mutt_get_field ((afilter ? _("Filter through: ") : _("Pipe to: ")),
560 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
563 mutt_expand_path (buf, sizeof (buf));
565 if (!afilter && !option (OPTATTACHSPLIT)) {
567 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
568 pipe_attachment_list (buf, fp, tag, top, afilter, &state);
569 m_fclose(&state.fpout);
570 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
571 mutt_any_key_to_continue (NULL);
573 pipe_attachment_list (buf, fp, tag, top, afilter, &state);
577 static int can_print(BODY * top, int tag)
579 for (; top; top = top->next) {
581 int tok = mime_which_token(top->subtype, -1);
583 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
585 if (!tag || top->tagged) {
586 if (!rfc1524_mailcap_lookup(top, type, NULL, M_PRINT)
587 && !(top->type == TYPETEXT && tok == MIME_PLAIN)
588 && !(top->type == TYPEAPPLICATION && tok == MIME_POSTSCRIPT)
589 && !mutt_can_decode(top))
591 mutt_error(_("I dont know how to print %s attachments!"), type);
596 return (can_print(top->parts, tag));
603 static void print_attachment_list (FILE * fp, int tag, BODY * top,
608 for (; top; top = top->next) {
609 if (!tag || top->tagged) {
610 int tok = mime_which_token(top->subtype, -1);
612 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
613 if (!option (OPTATTACHSPLIT)
614 && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
615 if ((top->type == TYPETEXT && tok == MIME_PLAIN)
616 || (top->type == TYPEAPPLICATION && tok == MIME_POSTSCRIPT)) {
617 pipe_attachment (fp, top, state);
619 if (mutt_can_decode (top)) {
620 /* decode and print */
622 char newfile[_POSIX_PATH_MAX] = "";
626 newfile_fd = m_tempfd(newfile, sizeof(newfile), NONULL(mod_core.tmpdir), NULL);
627 if (mutt_decode_save_attachment (fp, top, newfile_fd, M_PRINTING) == 0) {
628 if ((ifp = fopen (newfile, "r")) != NULL) {
629 mutt_copy_stream (ifp, state->fpout);
632 state_puts (AttachSep, state);
635 mutt_unlink (newfile);
638 mutt_print_attachment(fp, top);
642 print_attachment_list (fp, tag, top->parts, state);
648 void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
654 if (query_quadoption(OPT_PRINT,
655 tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) !=
659 if (!option (OPTATTACHSPLIT)) {
660 if (!can_print (top, tag))
664 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
665 print_attachment_list (fp, tag, top, &state);
666 m_fclose(&state.fpout);
667 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
668 mutt_any_key_to_continue (NULL);
671 print_attachment_list (fp, tag, top, &state);
675 mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
676 short *idxlen, short *idxmax, MUTTMENU * menu)
678 ATTACHPTR **idx = *idxp;
680 while (--(*idxlen) >= 0)
681 idx[(*idxlen)]->content = NULL;
684 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
689 if (menu->current >= menu->max)
690 menu->current = menu->max - 1;
691 menu_check_recenter (menu);
692 menu->redraw |= REDRAW_INDEX;
696 mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
697 BODY * cur, ATTACHPTR *** idxp, short *idxlen,
698 short *idxmax, int recv)
700 ATTACHPTR **idx = *idxp;
704 case OP_DISPLAY_HEADERS:
705 toggle_option (OPTWEED);
709 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
714 case OP_MAIN_NEXT_UNDELETED: /* hack */
715 if (menu->current < menu->max - 1) {
723 case OP_MAIN_PREV_UNDELETED: /* hack */
724 if (menu->current > 0) {
732 /* when we edit the content-type, we should redisplay the attachment
734 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
736 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
741 /* functions which are passed through from the pager */
742 case OP_CHECK_TRADITIONAL:
743 if (hdr && hdr->security & PGP_TRADITIONAL_CHECKED) {
748 case OP_ATTACH_COLLAPSE:
755 while (op != OP_NULL);
760 static void attach_collapse (BODY * b, short collapse, short init,
765 for (; b; b = b->next) {
766 i = init || b->collapsed;
767 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
768 && mime_which_token(b->subtype, -1) == MIME_DIGEST)
769 attach_collapse (b->parts, 1, 1, 0);
770 else if (b->type == TYPEMULTIPART || mutt_is_message_type(b))
771 attach_collapse (b->parts, collapse, i, 0);
772 b->collapsed = collapse;
778 void mutt_attach_init (BODY * b)
780 for (; b; b = b->next) {
784 mutt_attach_init (b->parts);
788 void mutt_view_attachments (HEADER * hdr)
791 int need_secured = 0;
797 ATTACHPTR **idx = NULL;
803 /* make sure we have parsed this message */
804 mutt_parse_mime_message (Context, hdr);
806 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
808 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
811 if ((hdr->security & ENCRYPT) ||
812 (mutt_is_application_smime (hdr->content) & SMIMEOPAQUE))
816 if (hdr->security & APPLICATION_SMIME) {
817 if (mutt_is_application_smime (hdr->content)) {
818 secured = !crypt_smime_decrypt_mime (msg->fp, &fp,
822 if ((mutt_is_application_smime (cur) & SMIMEOPAQUE)) {
828 secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
830 body_list_wipe(&_cur);
837 if (hdr->security & APPLICATION_PGP) {
838 if (mutt_is_multipart_encrypted (hdr->content))
839 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
844 if (need_secured && !secured) {
845 mx_close_message (&msg);
846 mutt_error _("Can't decrypt encrypted message!");
856 menu = mutt_new_menu ();
857 menu->menu = MENU_ATTACH;
858 menu->title = _("Attachments");
859 menu->make_entry = attach_entry;
860 menu->tag = mutt_tag_attach;
862 mutt_attach_init (cur);
863 attach_collapse (cur, 0, 1, 0);
864 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
866 #define CHECK_READONLY \
867 if (Context->readonly) { \
869 mutt_error _("Mailbox is read-only."); \
873 #define CHECK_ATTACH \
874 if (option(OPTATTACHMSG)) { \
876 mutt_error _("Function not permitted in attach-message mode."); \
882 op = mutt_menuLoop(menu);
884 case OP_ATTACH_VIEW_MAILCAP:
885 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
887 menu->redraw = REDRAW_FULL;
890 case OP_ATTACH_VIEW_TEXT:
891 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
893 menu->redraw = REDRAW_FULL;
896 case OP_DISPLAY_HEADERS:
899 mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen,
901 menu->redraw = REDRAW_FULL;
904 case OP_ATTACH_COLLAPSE:
905 if (!idx[menu->current]->content->parts) {
906 mutt_error _("There are no subparts to show!");
910 if (!idx[menu->current]->content->collapsed)
911 attach_collapse (idx[menu->current]->content, 1, 0, 1);
913 attach_collapse (idx[menu->current]->content, 0, 1, 1);
914 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
917 case OP_EXTRACT_KEYS:
918 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
923 menu->redraw = REDRAW_FULL;
926 case OP_CHECK_TRADITIONAL:
927 if (crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
928 : idx[menu->current]->content,
931 hdr->security = crypt_query (cur);
932 menu->redraw = REDRAW_FULL;
937 mutt_print_attachment_list (fp, menu->tagprefix,
938 menu->tagprefix ? cur : idx[menu->current]->
943 mutt_pipe_attachment_list (fp, menu->tagprefix,
944 menu->tagprefix ? cur : idx[menu->current]->
949 mutt_save_attachment_list (fp, menu->tagprefix,
950 menu->tagprefix ? cur : idx[menu->current]->
953 if (!menu->tagprefix && option (OPTRESOLVE)
954 && menu->current < menu->max - 1)
957 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
963 if (Context->magic == M_POP) {
965 mutt_error _("Can't delete attachment from POP server.");
971 if (Context->magic == M_NNTP) {
973 mutt_error _("Can't delete attachment from newsserver.");
979 if (hdr->security & (~PGP_TRADITIONAL_CHECKED)) {
981 _("Deletion of attachments from encrypted messages is unsupported.");
984 if (!menu->tagprefix) {
985 if (idx[menu->current]->parent_type == TYPEMULTIPART) {
986 idx[menu->current]->content->deleted = 1;
987 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
989 menu->redraw = REDRAW_MOTION_RESYNCH;
992 menu->redraw = REDRAW_CURRENT;
996 _("Only deletion of multipart attachments is supported.");
1001 for (x = 0; x < menu->max; x++) {
1002 if (idx[x]->content->tagged) {
1003 if (idx[x]->parent_type == TYPEMULTIPART) {
1004 idx[x]->content->deleted = 1;
1005 menu->redraw = REDRAW_INDEX;
1009 _("Only deletion of multipart attachments is supported.");
1018 if (!menu->tagprefix) {
1019 idx[menu->current]->content->deleted = 0;
1020 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1022 menu->redraw = REDRAW_MOTION_RESYNCH;
1025 menu->redraw = REDRAW_CURRENT;
1030 for (x = 0; x < menu->max; x++) {
1031 if (idx[x]->content->tagged) {
1032 idx[x]->content->deleted = 0;
1033 menu->redraw = REDRAW_INDEX;
1041 mutt_attach_resend (fp, hdr, idx, idxlen,
1042 menu->tagprefix ? NULL : idx[menu->current]->
1044 menu->redraw = REDRAW_FULL;
1047 case OP_BOUNCE_MESSAGE:
1049 mutt_attach_bounce (fp, hdr, idx, idxlen,
1050 menu->tagprefix ? NULL : idx[menu->current]->
1052 menu->redraw = REDRAW_FULL;
1055 case OP_FORWARD_MESSAGE:
1057 mutt_attach_forward (fp, hdr, idx, idxlen,
1058 menu->tagprefix ? NULL : idx[menu->current]->
1060 menu->redraw = REDRAW_FULL;
1064 case OP_FORWARD_TO_GROUP:
1066 mutt_attach_forward (fp, hdr, idx, idxlen,
1067 menu->tagprefix ? NULL : idx[menu->current]->
1069 menu->redraw = REDRAW_FULL;
1075 if (!idx[menu->current]->content->hdr->env->followup_to ||
1076 m_strcasecmp(idx[menu->current]->content->hdr->env->followup_to,
1078 || query_quadoption (OPT_FOLLOWUPTOPOSTER,
1079 _("Reply by mail as poster prefers?")) !=
1081 mutt_attach_reply (fp, hdr, idx, idxlen,
1082 menu->tagprefix ? NULL : idx[menu->current]->
1083 content, SENDNEWS | SENDREPLY);
1084 menu->redraw = REDRAW_FULL;
1090 case OP_GROUP_REPLY:
1096 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1097 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1098 mutt_attach_reply (fp, hdr, idx, idxlen,
1099 menu->tagprefix ? NULL : idx[menu->current]->content,
1101 menu->redraw = REDRAW_FULL;
1105 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1106 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1110 mx_close_message (&msg);
1111 hdr->attach_del = 0;
1112 while (idxmax-- > 0) {
1115 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1116 hdr->attach_del = 1;
1117 if (idx[idxmax]->content)
1118 idx[idxmax]->content->aptr = NULL;
1119 p_delete(&idx[idxmax]->tree);
1120 p_delete(&idx[idxmax]);
1122 if (hdr->attach_del)
1127 if (need_secured && secured) {
1129 body_list_wipe(&cur);
1132 mutt_menuDestroy (&menu);
1138 #undef CHECK_READONLY