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/lib-ui.h>
17 #include <lib-ui/enter.h>
18 #include <lib-ui/menu.h>
19 #include <lib-mx/mx.h>
24 #include "recvattach.h"
28 void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
34 for (x = 0; x < idxlen; x++) {
36 if (2 * (idx[x]->level + 2) < ssizeof (buf)) {
38 s = buf + 2 * (idx[x]->level - 1);
39 *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
49 if (m_strcmp(idx[x]->tree, buf) != 0)
50 m_strreplace(&idx[x]->tree, buf);
53 idx[x]->tree = m_strdup(buf);
55 if (2 * (idx[x]->level + 2) < ssizeof (buf) && idx[x]->level) {
56 s = buf + 2 * (idx[x]->level - 1);
57 *s++ = (idx[x]->content->next) ? '\005' : '\006';
63 ATTACHPTR **mutt_gen_attach_list (BODY * m,
67 short *idxmax, int level, int compose)
72 for (; m; m = m->next) {
73 if (*idxlen == *idxmax) {
74 p_realloc(&idx, (*idxmax) += 5);
75 for (i = *idxlen; i < *idxmax; i++)
79 if (m->type == TYPEMULTIPART && m->parts
82 && ascii_strcasecmp ("alternative", m->subtype)))
83 && (!mutt_is_multipart_encrypted (m))
86 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level,
91 idx[*idxlen] = p_new(ATTACHPTR, 1);
93 new = idx[(*idxlen)++];
96 new->parent_type = parent_type;
99 /* We don't support multipart messages in the compose menu yet */
100 if (!compose && !m->collapsed
101 && ((m->type == TYPEMULTIPART && !mutt_is_multipart_encrypted(m))
102 || mutt_is_message_type(m)))
104 idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
111 mutt_update_tree (idx, *idxlen);
116 /* %c = character set: convert?
120 * %e = MIME content-transfer-encoding
122 * %I = content-disposition, either I (inline) or A (attachment)
125 * %m = major MIME type
127 * %n = attachment number
132 mutt_attach_fmt(char *dest, ssize_t destlen, char op, const char *src,
133 const char *prefix, const char *ifstr, const char *elstr,
134 anytype data, format_flag flags)
138 char charset[STRING];
139 ATTACHPTR *aptr = data.ptr;
140 int optional = (flags & M_FORMAT_OPTIONAL);
146 if (mutt_is_text_part (aptr->content) &&
147 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
148 mutt_format_s (dest, destlen, prefix, charset);
150 mutt_format_s (dest, destlen, prefix, "");
152 else if (!mutt_is_text_part (aptr->content) ||
153 !mutt_get_body_charset (charset, sizeof (charset),
160 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
161 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
162 aptr->content->noconv ? 'n' : 'c');
164 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
169 if (aptr->content->description) {
170 mutt_format_s (dest, destlen, prefix, aptr->content->description);
173 if (mutt_is_message_type(aptr->content) && MsgFmt && aptr->content->hdr)
177 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
178 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT);
180 mutt_format_s (dest, destlen, prefix, s);
184 if (!aptr->content->filename) {
185 mutt_format_s (dest, destlen, prefix, "<no description>");
189 else if (aptr->content->description ||
190 (mutt_is_message_type(aptr->content)
191 && MsgFmt && aptr->content->hdr))
193 /* FALLS THROUGH TO 'f' */
196 if (aptr->content->filename && *aptr->content->filename == '/') {
197 char path[_POSIX_PATH_MAX];
199 m_strcpy(path, sizeof(path), aptr->content->filename);
200 mutt_pretty_mailbox (path);
201 mutt_format_s (dest, destlen, prefix, path);
204 mutt_format_s (dest, destlen, prefix,
205 NONULL (aptr->content->filename));
207 else if (!aptr->content->filename)
212 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
213 else if (!aptr->content->deleted)
218 mutt_format_s (dest, destlen, prefix,
219 ENCODING (aptr->content->encoding));
223 snprintf (dest, destlen, "%c",
224 (aptr->content->disposition == DISPINLINE) ? 'I' : 'A');
229 mutt_format_s (dest, destlen, prefix, TYPE (aptr->content));
233 mutt_format_s (dest, destlen, prefix, aptr->content->subtype);
234 else if (!aptr->content->subtype)
239 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
240 snprintf (dest, destlen, fmt, aptr->num + 1);
245 optional = aptr->content->attach_qualifies;
247 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
248 mutt_format_s (dest, destlen, fmt, "Q");
252 if (flags & M_FORMAT_STAT_FILE) {
255 stat (aptr->content->filename, &st);
259 l = aptr->content->length;
262 mutt_pretty_size (tmp, sizeof (tmp), l);
263 mutt_format_s (dest, destlen, prefix, tmp);
271 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
272 else if (!aptr->content->tagged)
277 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
278 else if (!aptr->tree)
283 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
284 else if (!aptr->content->unlink)
289 optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0;
291 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
292 snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
299 if (flags & M_FORMAT_OPTIONAL)
300 m_strformat(dest, destlen, 0, optional ? ifstr : elstr,
301 mutt_attach_fmt, data, 0);
305 static void attach_entry(char *b, ssize_t blen, MUTTMENU * menu, int num)
307 m_strformat(b, blen, getmaxx(main_w), AttachFormat, mutt_attach_fmt,
308 ((ATTACHPTR **) menu->data)[num], 0);
311 int mutt_tag_attach (MUTTMENU * menu, int n, int m)
313 BODY *cur = ((ATTACHPTR **) menu->data)[n]->content;
314 int ot = cur->tagged;
316 cur->tagged = (m >= 0 ? m : !cur->tagged);
317 return cur->tagged - ot;
320 static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
324 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
330 if (body->filename) {
331 if (directory && *directory)
332 mutt_concat_path(buf, sizeof(buf), *directory,
333 mutt_basename(body->filename));
335 m_strcpy(buf, sizeof(buf), body->filename);
337 else if (body->hdr &&
338 body->encoding != ENCBASE64 &&
339 body->encoding != ENCQUOTEDPRINTABLE &&
340 mutt_is_message_type(body))
341 mutt_default_save (buf, sizeof (buf), body->hdr);
345 prompt = _("Save to file ('#' for last used folder): ");
347 static char LastSaveFolder[_POSIX_PATH_MAX] = ".";
349 ret = mutt_get_field(prompt, buf, sizeof (buf),
350 M_FILE | M_CLEAR | M_LASTFOLDER);
351 if (((ret != 0) && (ret != 2)) || (!buf[0] && ret != 2))
355 char tmpbuf[_POSIX_PATH_MAX];
357 snprintf (tmpbuf, sizeof (tmpbuf), "%s/%s", LastSaveFolder, buf);
358 m_strcpy(buf, sizeof(buf), tmpbuf);
359 ret = mutt_get_field(_("Save to file: "), buf, sizeof (buf), M_FILE);
360 if ((ret != 0) || (!buf[0]))
363 m_dirname(LastSaveFolder, sizeof(LastSaveFolder), buf);
366 mutt_expand_path(buf, sizeof(buf));
368 is_message = (fp && body->hdr &&
369 body->encoding != ENCBASE64 &&
370 body->encoding != ENCQUOTEDPRINTABLE &&
371 mutt_is_message_type(body));
376 /* check to make sure that this file is really the one the user wants */
377 rc = mutt_save_confirm(buf, &st);
378 m_strcpy(tfile, sizeof(tfile), buf);
380 rc = mutt_check_overwrite(body->filename, buf, tfile, sizeof(tfile),
386 prompt = _("Save to file: ");
390 mutt_message _("Saving...");
392 if (mutt_save_attachment(fp, body, tfile, append,
393 (hdr || !is_message) ? hdr : body->hdr) == 0)
395 mutt_message _("Attachment saved.");
398 prompt = _("Save to file: ");
405 void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
408 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
409 char *directory = NULL;
411 int last = menu ? menu->current : -1;
416 for (; top; top = top->next) {
417 if (!tag || top->tagged) {
418 if (!option (OPTATTACHSPLIT)) {
422 m_strcpy(buf, sizeof(buf), NONULL(top->filename));
423 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
424 M_FILE | M_CLEAR) != 0 || !buf[0])
426 mutt_expand_path (buf, sizeof (buf));
427 if (mutt_check_overwrite (top->filename, buf, tfile,
428 sizeof (tfile), &append, NULL))
430 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
431 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
432 fprintf (fpout, "%s", AttachSep);
437 rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
438 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
439 fprintf (fpout, "%s", AttachSep);
444 if (tag && menu && top->aptr) {
445 menu->oldcurrent = menu->current;
446 menu->current = top->aptr->num;
447 menu_check_recenter (menu);
448 menu->redraw |= REDRAW_MOTION;
452 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
457 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
462 p_delete(&directory);
465 menu->oldcurrent = menu->current;
466 menu->current = last;
467 menu_check_recenter (menu);
468 menu->redraw |= REDRAW_MOTION;
471 if (!option (OPTATTACHSPLIT) && (rc == 0))
472 mutt_message _("Attachment saved.");
476 mutt_query_pipe_attachment(char *command, FILE * fp, BODY * body, int afilter)
478 char tfile[_POSIX_PATH_MAX];
479 char warning[STRING + _POSIX_PATH_MAX];
483 snprintf(warning, sizeof (warning),
484 _("WARNING! You are about to overwrite %s, continue?"),
486 if (mutt_yesorno (warning, M_NO) != M_YES)
488 tempfd = m_tempfd(tfile, sizeof(tfile), NONULL(mod_core.tmpdir), NULL);
491 if (mutt_pipe_attachment(fp, body, command, tempfd)) {
493 mutt_unlink (body->filename);
494 mutt_rename_file (tfile, body->filename);
495 mutt_update_encoding (body);
496 mutt_message _("Attachment filtered.");
498 } else if (afilter) {
504 static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
510 mutt_decode_attachment (b, state);
512 state_puts (AttachSep, state);
514 if ((ifp = fopen (b->filename, "r")) == NULL) {
515 mutt_perror ("fopen");
518 mutt_copy_stream (ifp, state->fpout);
521 state_puts (AttachSep, state);
526 pipe_attachment_list (char *command, FILE * fp, int tag, BODY * top,
527 int afilter, STATE * state)
529 for (; top; top = top->next) {
530 if (!tag || top->tagged) {
531 if (!afilter && !option (OPTATTACHSPLIT))
532 pipe_attachment (fp, top, state);
534 mutt_query_pipe_attachment (command, fp, top, afilter);
537 pipe_attachment_list (command, fp, tag, top->parts, afilter, state);
543 void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int afilter)
550 afilter = 0; /* sanity check: we can't filter in the recv case yet */
555 if (mutt_get_field ((afilter ? _("Filter through: ") : _("Pipe to: ")),
556 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
559 mutt_expand_path (buf, sizeof (buf));
561 if (!afilter && !option (OPTATTACHSPLIT)) {
563 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
564 pipe_attachment_list (buf, fp, tag, top, afilter, &state);
565 m_fclose(&state.fpout);
566 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
567 mutt_any_key_to_continue (NULL);
569 pipe_attachment_list (buf, fp, tag, top, afilter, &state);
573 static int can_print(BODY * top, int tag)
575 for (; top; top = top->next) {
577 int tok = mime_which_token(top->subtype, -1);
579 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
581 if (!tag || top->tagged) {
582 if (!rfc1524_mailcap_lookup(top, type, NULL, M_PRINT)
583 && !(top->type == TYPETEXT && tok == MIME_PLAIN)
584 && !(top->type == TYPEAPPLICATION && tok == MIME_POSTSCRIPT)
585 && !mutt_can_decode(top))
587 mutt_error(_("I dont know how to print %s attachments!"), type);
592 return (can_print(top->parts, tag));
599 static void print_attachment_list (FILE * fp, int tag, BODY * top,
604 for (; top; top = top->next) {
605 if (!tag || top->tagged) {
606 int tok = mime_which_token(top->subtype, -1);
608 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
609 if (!option (OPTATTACHSPLIT)
610 && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
611 if ((top->type == TYPETEXT && tok == MIME_PLAIN)
612 || (top->type == TYPEAPPLICATION && tok == MIME_POSTSCRIPT)) {
613 pipe_attachment (fp, top, state);
615 if (mutt_can_decode (top)) {
616 /* decode and print */
618 char newfile[_POSIX_PATH_MAX] = "";
622 newfile_fd = m_tempfd(newfile, sizeof(newfile), NONULL(mod_core.tmpdir), NULL);
623 if (mutt_decode_save_attachment (fp, top, newfile_fd, M_PRINTING) == 0) {
624 if ((ifp = fopen (newfile, "r")) != NULL) {
625 mutt_copy_stream (ifp, state->fpout);
628 state_puts (AttachSep, state);
631 mutt_unlink (newfile);
634 mutt_print_attachment(fp, top);
638 print_attachment_list (fp, tag, top->parts, state);
644 void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
650 if (query_quadoption(OPT_PRINT,
651 tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) !=
655 if (!option (OPTATTACHSPLIT)) {
656 if (!can_print (top, tag))
660 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
661 print_attachment_list (fp, tag, top, &state);
662 m_fclose(&state.fpout);
663 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
664 mutt_any_key_to_continue (NULL);
667 print_attachment_list (fp, tag, top, &state);
671 mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
672 short *idxlen, short *idxmax, MUTTMENU * menu)
674 ATTACHPTR **idx = *idxp;
676 while (--(*idxlen) >= 0)
677 idx[(*idxlen)]->content = NULL;
680 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
685 if (menu->current >= menu->max)
686 menu->current = menu->max - 1;
687 menu_check_recenter (menu);
688 menu->redraw |= REDRAW_INDEX;
692 mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
693 BODY * cur, ATTACHPTR *** idxp, short *idxlen,
694 short *idxmax, int recv)
696 ATTACHPTR **idx = *idxp;
700 case OP_DISPLAY_HEADERS:
701 toggle_option (OPTWEED);
705 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
710 case OP_MAIN_NEXT_UNDELETED: /* hack */
711 if (menu->current < menu->max - 1) {
719 case OP_MAIN_PREV_UNDELETED: /* hack */
720 if (menu->current > 0) {
728 /* when we edit the content-type, we should redisplay the attachment
730 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
732 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
737 /* functions which are passed through from the pager */
738 case OP_CHECK_TRADITIONAL:
739 if (hdr && hdr->security & PGP_TRADITIONAL_CHECKED) {
744 case OP_ATTACH_COLLAPSE:
751 while (op != OP_NULL);
756 static void attach_collapse (BODY * b, short collapse, short init,
761 for (; b; b = b->next) {
762 i = init || b->collapsed;
763 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
764 && mime_which_token(b->subtype, -1) == MIME_DIGEST)
765 attach_collapse (b->parts, 1, 1, 0);
766 else if (b->type == TYPEMULTIPART || mutt_is_message_type(b))
767 attach_collapse (b->parts, collapse, i, 0);
768 b->collapsed = collapse;
774 void mutt_attach_init (BODY * b)
776 for (; b; b = b->next) {
780 mutt_attach_init (b->parts);
784 void mutt_view_attachments (HEADER * hdr)
787 int need_secured = 0;
793 ATTACHPTR **idx = NULL;
799 /* make sure we have parsed this message */
800 mutt_parse_mime_message (Context, hdr);
802 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
804 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
807 if ((hdr->security & ENCRYPT) ||
808 (mutt_is_application_smime (hdr->content) & SMIMEOPAQUE))
812 if (hdr->security & APPLICATION_SMIME) {
813 if (mutt_is_application_smime (hdr->content)) {
814 secured = !crypt_smime_decrypt_mime (msg->fp, &fp,
818 if ((mutt_is_application_smime (cur) & SMIMEOPAQUE)) {
824 secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
826 body_list_wipe(&_cur);
833 if (hdr->security & APPLICATION_PGP) {
834 if (mutt_is_multipart_encrypted (hdr->content))
835 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
840 if (need_secured && !secured) {
841 mx_close_message (&msg);
842 mutt_error _("Can't decrypt encrypted message!");
852 menu = mutt_new_menu ();
853 menu->menu = MENU_ATTACH;
854 menu->title = _("Attachments");
855 menu->make_entry = attach_entry;
856 menu->tag = mutt_tag_attach;
858 mutt_attach_init (cur);
859 attach_collapse (cur, 0, 1, 0);
860 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
862 #define CHECK_READONLY \
863 if (Context->readonly) { \
865 mutt_error _("Mailbox is read-only."); \
869 #define CHECK_ATTACH \
870 if (option(OPTATTACHMSG)) { \
872 mutt_error _("Function not permitted in attach-message mode."); \
878 op = mutt_menuLoop(menu);
880 case OP_ATTACH_VIEW_MAILCAP:
881 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
883 menu->redraw = REDRAW_FULL;
886 case OP_ATTACH_VIEW_TEXT:
887 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
889 menu->redraw = REDRAW_FULL;
892 case OP_DISPLAY_HEADERS:
895 mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen,
897 menu->redraw = REDRAW_FULL;
900 case OP_ATTACH_COLLAPSE:
901 if (!idx[menu->current]->content->parts) {
902 mutt_error _("There are no subparts to show!");
906 if (!idx[menu->current]->content->collapsed)
907 attach_collapse (idx[menu->current]->content, 1, 0, 1);
909 attach_collapse (idx[menu->current]->content, 0, 1, 1);
910 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
913 case OP_EXTRACT_KEYS:
914 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
919 menu->redraw = REDRAW_FULL;
922 case OP_CHECK_TRADITIONAL:
923 if (crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
924 : idx[menu->current]->content,
927 hdr->security = crypt_query (cur);
928 menu->redraw = REDRAW_FULL;
933 mutt_print_attachment_list (fp, menu->tagprefix,
934 menu->tagprefix ? cur : idx[menu->current]->
939 mutt_pipe_attachment_list (fp, menu->tagprefix,
940 menu->tagprefix ? cur : idx[menu->current]->
945 mutt_save_attachment_list (fp, menu->tagprefix,
946 menu->tagprefix ? cur : idx[menu->current]->
949 if (!menu->tagprefix && option (OPTRESOLVE)
950 && menu->current < menu->max - 1)
953 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
959 if (Context->magic == M_POP) {
961 mutt_error _("Can't delete attachment from POP server.");
966 if (hdr->security & (~PGP_TRADITIONAL_CHECKED)) {
968 _("Deletion of attachments from encrypted messages is unsupported.");
971 if (!menu->tagprefix) {
972 if (idx[menu->current]->parent_type == TYPEMULTIPART) {
973 idx[menu->current]->content->deleted = 1;
974 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
976 menu->redraw = REDRAW_MOTION_RESYNCH;
979 menu->redraw = REDRAW_CURRENT;
983 _("Only deletion of multipart attachments is supported.");
988 for (x = 0; x < menu->max; x++) {
989 if (idx[x]->content->tagged) {
990 if (idx[x]->parent_type == TYPEMULTIPART) {
991 idx[x]->content->deleted = 1;
992 menu->redraw = REDRAW_INDEX;
996 _("Only deletion of multipart attachments is supported.");
1005 if (!menu->tagprefix) {
1006 idx[menu->current]->content->deleted = 0;
1007 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1009 menu->redraw = REDRAW_MOTION_RESYNCH;
1012 menu->redraw = REDRAW_CURRENT;
1017 for (x = 0; x < menu->max; x++) {
1018 if (idx[x]->content->tagged) {
1019 idx[x]->content->deleted = 0;
1020 menu->redraw = REDRAW_INDEX;
1028 mutt_attach_resend (fp, hdr, idx, idxlen,
1029 menu->tagprefix ? NULL : idx[menu->current]->
1031 menu->redraw = REDRAW_FULL;
1034 case OP_BOUNCE_MESSAGE:
1036 mutt_attach_bounce (fp, hdr, idx, idxlen,
1037 menu->tagprefix ? NULL : idx[menu->current]->
1039 menu->redraw = REDRAW_FULL;
1042 case OP_FORWARD_MESSAGE:
1044 mutt_attach_forward (fp, hdr, idx, idxlen,
1045 menu->tagprefix ? NULL : idx[menu->current]->
1047 menu->redraw = REDRAW_FULL;
1051 case OP_GROUP_REPLY:
1057 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1058 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1059 mutt_attach_reply (fp, hdr, idx, idxlen,
1060 menu->tagprefix ? NULL : idx[menu->current]->content,
1062 menu->redraw = REDRAW_FULL;
1066 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1067 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1071 mx_close_message (&msg);
1072 hdr->attach_del = 0;
1073 while (idxmax-- > 0) {
1076 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1077 hdr->attach_del = 1;
1078 if (idx[idxmax]->content)
1079 idx[idxmax]->content->aptr = NULL;
1080 p_delete(&idx[idxmax]->tree);
1081 p_delete(&idx[idxmax]);
1083 if (hdr->attach_del)
1088 if (need_secured && secured) {
1090 body_list_wipe(&cur);
1093 mutt_menuDestroy (&menu);
1099 #undef CHECK_READONLY