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.
21 #include "mutt_curses.h"
22 #include "mutt_menu.h"
30 #include "mutt_crypt.h"
40 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
42 static char LastSaveFolder[_POSIX_PATH_MAX] = "";
44 #define CHECK_READONLY if (Context->readonly) \
47 mutt_error _(Mailbox_is_read_only); \
51 static struct mapping_t AttachHelp[] = {
52 { N_("Exit"), OP_EXIT },
53 { N_("Save"), OP_SAVE },
54 { N_("Pipe"), OP_PIPE },
55 { N_("Print"), OP_PRINT },
56 { N_("Help"), OP_HELP },
60 int mutt_extract_path(char *filename, char *path)
62 char *tmp=safe_malloc(sizeof(char) * _POSIX_PATH_MAX);
67 while(*filename != '\0')
71 *help_ptr++=*filename++;
76 *help_ptr++=*filename++;
78 safe_free((void **) &tmp);
84 void mutt_update_tree (ATTACHPTR **idx, short idxlen)
90 for (x = 0; x < idxlen; x++)
93 if (2 * (idx[x]->level + 2) < sizeof (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;
109 if (mutt_strcmp (idx[x]->tree, buf) != 0)
110 mutt_str_replace (&idx[x]->tree, buf);
113 idx[x]->tree = safe_strdup (buf);
115 if (2 * (idx[x]->level + 2) < sizeof (buf) && idx[x]->level)
117 s = buf + 2 * (idx[x]->level - 1);
118 *s++ = (idx[x]->content->next) ? '\005' : '\006';
124 ATTACHPTR **mutt_gen_attach_list (BODY *m,
135 for (; m; m = m->next)
137 if (*idxlen == *idxmax)
139 safe_realloc (&idx, sizeof (ATTACHPTR *) * ((*idxmax) += 5));
140 for (i = *idxlen; i < *idxmax; i++)
144 if (m->type == TYPEMULTIPART && m->parts
145 && (compose || (parent_type == -1 && ascii_strcasecmp ("alternative", m->subtype)))
146 && (!(WithCrypto & APPLICATION_PGP) || !mutt_is_multipart_encrypted(m))
149 idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level, compose);
154 idx[*idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
156 new = idx[(*idxlen)++];
159 new->parent_type = parent_type;
162 /* We don't support multipart messages in the compose menu yet */
163 if (!compose && !m->collapsed &&
164 ((m->type == TYPEMULTIPART
165 && (!(WithCrypto & APPLICATION_PGP)
166 || !mutt_is_multipart_encrypted (m))
168 || mutt_is_message_type(m->type, m->subtype)))
170 idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level + 1, compose);
176 mutt_update_tree (idx, *idxlen);
181 /* %c = character set: convert?
185 * %e = MIME content-transfer-encoding
187 * %I = content-disposition, either I (inline) or A (attachment)
190 * %m = major MIME type
192 * %n = attachment number
196 const char *mutt_attach_fmt (char *dest,
201 const char *ifstring,
202 const char *elsestring,
207 char tmp[SHORT_STRING];
208 char charset[SHORT_STRING];
209 ATTACHPTR *aptr = (ATTACHPTR *) data;
210 int optional = (flags & M_FORMAT_OPTIONAL);
218 if (mutt_is_text_part (aptr->content) &&
219 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
220 mutt_format_s (dest, destlen, prefix, charset);
222 mutt_format_s (dest, destlen, prefix, "");
224 else if (!mutt_is_text_part (aptr->content) ||
225 !mutt_get_body_charset (charset, sizeof (charset), aptr->content))
232 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
233 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
234 aptr->content->noconv ? 'n' : 'c');
236 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
242 if (aptr->content->description)
244 mutt_format_s (dest, destlen, prefix, aptr->content->description);
247 if (mutt_is_message_type(aptr->content->type, aptr->content->subtype) &&
248 MsgFmt && aptr->content->hdr)
250 char s[SHORT_STRING];
251 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
252 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT | M_FORMAT_ARROWCURSOR);
255 mutt_format_s (dest, destlen, prefix, s);
259 if (!aptr->content->filename)
261 mutt_format_s (dest, destlen, prefix, "<no description>");
265 else if(aptr->content->description ||
266 (mutt_is_message_type (aptr->content->type, aptr->content->subtype)
267 && MsgFmt && aptr->content->hdr))
269 /* FALLS THROUGH TO 'f' */
273 if (aptr->content->filename && *aptr->content->filename == '/')
275 char path[_POSIX_PATH_MAX];
277 strfcpy (path, aptr->content->filename, sizeof (path));
278 mutt_pretty_mailbox (path);
279 mutt_format_s (dest, destlen, prefix, path);
282 mutt_format_s (dest, destlen, prefix, NONULL (aptr->content->filename));
284 else if(!aptr->content->filename)
289 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
290 else if(!aptr->content->deleted)
295 mutt_format_s (dest, destlen, prefix,
296 ENCODING (aptr->content->encoding));
301 snprintf (dest, destlen, "%c",
302 (aptr->content->disposition == DISPINLINE) ? 'I' : 'A');
307 mutt_format_s (dest, destlen, prefix, TYPE (aptr->content));
311 mutt_format_s (dest, destlen, prefix, aptr->content->subtype);
312 else if(!aptr->content->subtype)
318 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
319 snprintf (dest, destlen, fmt, aptr->num + 1);
323 if (flags & M_FORMAT_STAT_FILE)
326 stat (aptr->content->filename, &st);
330 l = aptr->content->length;
334 mutt_pretty_size (tmp, sizeof(tmp), l);
335 mutt_format_s (dest, destlen, prefix, tmp);
343 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
344 else if(!aptr->content->tagged)
349 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
350 else if (!aptr->tree)
355 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
356 else if (!aptr->content->unlink)
364 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
365 else if (flags & M_FORMAT_OPTIONAL)
366 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
370 void attach_entry (char *b, size_t blen, MUTTMENU *menu, int num)
372 mutt_FormatString (b, blen, NONULL (AttachFormat), mutt_attach_fmt, (unsigned long) (((ATTACHPTR **)menu->data)[num]), M_FORMAT_ARROWCURSOR);
375 int mutt_tag_attach (MUTTMENU *menu, int n, int m)
377 BODY *cur = ((ATTACHPTR **) menu->data)[n]->content;
378 int ot = cur->tagged;
380 cur->tagged = (m >= 0 ? m : !cur->tagged);
381 return cur->tagged - ot;
384 int mutt_is_message_type (int type, const char *subtype)
386 if (type != TYPEMESSAGE)
389 subtype = NONULL(subtype);
390 return (ascii_strcasecmp (subtype, "rfc822") == 0 || ascii_strcasecmp (subtype, "news") == 0);
393 static int mutt_query_save_attachment (FILE *fp, BODY *body, HEADER *hdr, char **directory)
396 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
397 char path[_POSIX_PATH_MAX]="";
406 if (directory && *directory)
407 mutt_concat_path (buf, *directory, mutt_basename (body->filename), sizeof (buf));
409 strfcpy (buf, body->filename, sizeof (buf));
412 body->encoding != ENCBASE64 &&
413 body->encoding != ENCQUOTEDPRINTABLE &&
414 mutt_is_message_type(body->type, body->subtype))
415 mutt_default_save(buf, sizeof(buf), body->hdr);
419 prompt = _("Save to file: ");
422 ret = mutt_get_field_att (_("Save to file ('.' for last used folder): ")
423 , buf, sizeof (buf), M_FILE | M_CLEAR);
424 if (((ret != 0) && (ret != 2)) || (!buf[0]))
429 strfcpy (buf, LastSaveFolder, sizeof (buf));
430 strcat(buf,body->filename);
431 ret = mutt_get_field (_("Save to file: ")
432 , buf, sizeof (buf), M_FILE | M_CLEAR);
433 if ((ret != 0) || (!buf[0]))
438 mutt_extract_path(buf,path);
439 strfcpy (LastSaveFolder, path, sizeof (LastSaveFolder));
443 mutt_expand_path (buf, sizeof (buf));
447 body->encoding != ENCBASE64 &&
448 body->encoding != ENCQUOTEDPRINTABLE &&
449 mutt_is_message_type (body->type, body->subtype));
455 /* check to make sure that this file is really the one the user wants */
456 if ((rc = mutt_save_confirm (buf, &st)) == 1)
458 prompt = _("Save to file: ");
463 strfcpy(tfile, buf, sizeof(tfile));
467 if ((rc = mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile), &append, directory)) == -1)
471 prompt = _("Save to file: ");
476 mutt_message _("Saving...");
477 if (mutt_save_attachment (fp, body, tfile, append, (hdr || !is_message) ? hdr : body->hdr) == 0)
479 mutt_message _("Attachment saved.");
484 prompt = _("Save to file: ");
491 void mutt_save_attachment_list (FILE *fp, int tag, BODY *top, HEADER *hdr, MUTTMENU *menu)
493 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
494 char *directory = NULL;
496 int last = menu ? menu->current : -1;
501 for (; top; top = top->next)
503 if (!tag || top->tagged)
505 if (!option (OPTATTACHSPLIT))
511 strfcpy (buf, NONULL (top->filename), sizeof (buf));
512 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
513 M_FILE | M_CLEAR) != 0 || !buf[0])
515 mutt_expand_path (buf, sizeof (buf));
516 if (mutt_check_overwrite (top->filename, buf, tfile,
517 sizeof (tfile), &append, NULL))
519 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
520 if (rc == 0 && AttachSep && (fpout = fopen (tfile,"a")) != NULL)
522 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)
531 fprintf(fpout, "%s", AttachSep);
538 if (tag && menu && top->aptr)
540 menu->oldcurrent = menu->current;
541 menu->current = top->aptr->num;
542 menu_check_recenter (menu);
543 menu->redraw |= REDRAW_MOTION;
547 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
552 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
561 menu->oldcurrent = menu->current;
562 menu->current = last;
563 menu_check_recenter (menu);
564 menu->redraw |= REDRAW_MOTION;
567 if (!option (OPTATTACHSPLIT) && (rc == 0))
568 mutt_message _("Attachment saved.");
572 mutt_query_pipe_attachment (char *command, FILE *fp, BODY *body, int filter)
574 char tfile[_POSIX_PATH_MAX];
575 char warning[STRING+_POSIX_PATH_MAX];
579 snprintf (warning, sizeof (warning),
580 _("WARNING! You are about to overwrite %s, continue?"),
582 if (mutt_yesorno (warning, M_NO) != M_YES) {
591 if (mutt_pipe_attachment (fp, body, command, tfile))
595 mutt_unlink (body->filename);
596 mutt_rename_file (tfile, body->filename);
597 mutt_update_encoding (body);
598 mutt_message _("Attachment filtered.");
603 if (filter && tfile[0])
608 static void pipe_attachment (FILE *fp, BODY *b, STATE *state)
615 mutt_decode_attachment (b, state);
617 state_puts (AttachSep, state);
621 if ((ifp = fopen (b->filename, "r")) == NULL)
623 mutt_perror ("fopen");
626 mutt_copy_stream (ifp, state->fpout);
629 state_puts (AttachSep, state);
634 pipe_attachment_list (char *command, FILE *fp, int tag, BODY *top, int filter,
637 for (; top; top = top->next)
639 if (!tag || top->tagged)
641 if (!filter && !option (OPTATTACHSPLIT))
642 pipe_attachment (fp, top, state);
644 mutt_query_pipe_attachment (command, fp, top, filter);
647 pipe_attachment_list (command, fp, tag, top->parts, filter, state);
653 void mutt_pipe_attachment_list (FILE *fp, int tag, BODY *top, int filter)
656 char buf[SHORT_STRING];
660 filter = 0; /* sanity check: we can't filter in the recv case yet */
663 memset (&state, 0, sizeof (STATE));
665 if (mutt_get_field ((filter ? _("Filter through: ") : _("Pipe to: ")),
666 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
669 mutt_expand_path (buf, sizeof (buf));
671 if (!filter && !option (OPTATTACHSPLIT))
674 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
675 pipe_attachment_list (buf, fp, tag, top, filter, &state);
676 fclose (state.fpout);
677 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
678 mutt_any_key_to_continue (NULL);
681 pipe_attachment_list (buf, fp, tag, top, filter, &state);
684 static int can_print (BODY *top, int tag)
688 for (; top; top = top->next)
690 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
691 if (!tag || top->tagged)
693 if (!rfc1524_mailcap_lookup (top, type, NULL, M_PRINT))
695 if (ascii_strcasecmp ("text/plain", top->subtype) &&
696 ascii_strcasecmp ("application/postscript", top->subtype))
698 if (!mutt_can_decode (top))
700 mutt_error (_("I dont know how to print %s attachments!"), type);
707 return (can_print (top->parts, tag));
714 static void print_attachment_list (FILE *fp, int tag, BODY *top, STATE *state)
719 for (; top; top = top->next)
721 if (!tag || top->tagged)
723 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
724 if (!option (OPTATTACHSPLIT) && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT))
726 if (!ascii_strcasecmp ("text/plain", top->subtype) ||
727 !ascii_strcasecmp ("application/postscript", top->subtype))
728 pipe_attachment (fp, top, state);
729 else if (mutt_can_decode (top))
731 /* decode and print */
733 char newfile[_POSIX_PATH_MAX] = "";
736 mutt_mktemp (newfile);
737 if (mutt_decode_save_attachment (fp, top, newfile, M_PRINTING, 0) == 0)
739 if ((ifp = fopen (newfile, "r")) != NULL)
741 mutt_copy_stream (ifp, state->fpout);
744 state_puts (AttachSep, state);
747 mutt_unlink (newfile);
751 mutt_print_attachment (fp, top);
754 print_attachment_list (fp, tag, top->parts, state);
760 void mutt_print_attachment_list (FILE *fp, int tag, BODY *top)
765 if (query_quadoption (OPT_PRINT, tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) != M_YES)
768 if (!option (OPTATTACHSPLIT))
770 if (!can_print (top, tag))
773 memset (&state, 0, sizeof (STATE));
774 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
775 print_attachment_list (fp, tag, top, &state);
776 fclose (state.fpout);
777 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
778 mutt_any_key_to_continue (NULL);
781 print_attachment_list (fp, tag, top, &state);
785 mutt_update_attach_index (BODY *cur, ATTACHPTR ***idxp,
786 short *idxlen, short *idxmax,
789 ATTACHPTR **idx = *idxp;
790 while (--(*idxlen) >= 0)
791 idx[(*idxlen)]->content = NULL;
794 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
799 if (menu->current >= menu->max)
800 menu->current = menu->max - 1;
801 menu_check_recenter (menu);
802 menu->redraw |= REDRAW_INDEX;
808 mutt_attach_display_loop (MUTTMENU *menu, int op, FILE *fp, HEADER *hdr,
809 BODY *cur, ATTACHPTR ***idxp, short *idxlen, short *idxmax,
812 ATTACHPTR **idx = *idxp;
814 int old_optweed = option (OPTWEED);
815 set_option (OPTWEED);
822 case OP_DISPLAY_HEADERS:
823 toggle_option (OPTWEED);
827 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
832 case OP_MAIN_NEXT_UNDELETED: /* hack */
833 if (menu->current < menu->max - 1)
842 case OP_MAIN_PREV_UNDELETED: /* hack */
843 if (menu->current > 0)
852 /* when we edit the content-type, we should redisplay the attachment
854 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
857 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
862 /* functions which are passed through from the pager */
863 case OP_CHECK_TRADITIONAL:
864 if (!(WithCrypto & APPLICATION_PGP))
870 case OP_ATTACH_COLLAPSE:
877 while (op != OP_NULL);
880 if (option (OPTWEED) != old_optweed)
881 toggle_option (OPTWEED);
886 static void attach_collapse (BODY *b, short collapse, short init, short just_one)
889 for (; b; b = b->next)
891 i = init || b->collapsed;
892 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
893 && !ascii_strcasecmp (b->subtype, "digest"))
894 attach_collapse (b->parts, 1, 1, 0);
895 else if (b->type == TYPEMULTIPART || mutt_is_message_type (b->type, b->subtype))
896 attach_collapse (b->parts, collapse, i, 0);
897 b->collapsed = collapse;
903 void mutt_attach_init (BODY *b)
905 for (; b; b = b->next)
910 mutt_attach_init (b->parts);
914 static const char *Function_not_permitted = N_("Function not permitted in attach-message mode.");
916 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
919 mutt_error _(Function_not_permitted); \
926 void mutt_view_attachments (HEADER *hdr)
929 int need_secured = 0;
931 char helpstr[SHORT_STRING];
936 ATTACHPTR **idx = NULL;
942 /* make sure we have parsed this message */
943 mutt_parse_mime_message (Context, hdr);
945 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
947 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
951 if (WithCrypto && ((hdr->security & ENCRYPT) ||
952 (mutt_is_application_smime(hdr->content) & SMIMEOPAQUE)))
956 if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase(hdr->security))
958 mx_close_message (&msg);
961 if ((WithCrypto & APPLICATION_SMIME) && hdr->security & APPLICATION_SMIME)
964 crypt_smime_getkeys (hdr->env);
966 if (mutt_is_application_smime(hdr->content))
967 secured = ! crypt_smime_decrypt_mime (msg->fp, &fp,
972 if ((WithCrypto & APPLICATION_PGP) && hdr->security & APPLICATION_PGP)
974 if (mutt_is_multipart_encrypted(hdr->content))
975 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
980 if (need_secured && !secured)
982 mx_close_message (&msg);
983 mutt_error _("Can't decrypt encrypted message!");
988 if (!WithCrypto || !need_secured)
994 menu = mutt_new_menu ();
995 menu->menu = MENU_ATTACH;
996 menu->title = _("Attachments");
997 menu->make_entry = attach_entry;
998 menu->tag = mutt_tag_attach;
999 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_ATTACH, AttachHelp);
1001 mutt_attach_init (cur);
1002 attach_collapse (cur, 0, 1, 0);
1003 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1008 op = mutt_menuLoop (menu);
1011 case OP_ATTACH_VIEW_MAILCAP:
1012 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
1014 menu->redraw = REDRAW_FULL;
1017 case OP_ATTACH_VIEW_TEXT:
1018 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
1020 menu->redraw = REDRAW_FULL;
1023 case OP_DISPLAY_HEADERS:
1024 case OP_VIEW_ATTACH:
1025 op = mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen, &idxmax, 1);
1026 menu->redraw = REDRAW_FULL;
1029 case OP_ATTACH_COLLAPSE:
1030 if (!idx[menu->current]->content->parts)
1032 mutt_error _("There are no subparts to show!");
1035 if (!idx[menu->current]->content->collapsed)
1036 attach_collapse (idx[menu->current]->content, 1, 0, 1);
1038 attach_collapse (idx[menu->current]->content, 0, 1, 1);
1039 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1042 case OP_FORGET_PASSPHRASE:
1043 crypt_forget_passphrase ();
1046 case OP_EXTRACT_KEYS:
1047 if ((WithCrypto & APPLICATION_PGP))
1049 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
1050 menu->tagprefix ? cur : idx[menu->current]->content);
1051 menu->redraw = REDRAW_FULL;
1055 case OP_CHECK_TRADITIONAL:
1056 if ((WithCrypto & APPLICATION_PGP)
1057 && crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
1058 : idx[menu->current]->content,
1061 hdr->security = crypt_query (cur);
1062 menu->redraw = REDRAW_FULL;
1067 mutt_print_attachment_list (fp, menu->tagprefix,
1068 menu->tagprefix ? cur : idx[menu->current]->content);
1072 mutt_pipe_attachment_list (fp, menu->tagprefix,
1073 menu->tagprefix ? cur : idx[menu->current]->content, 0);
1077 mutt_save_attachment_list (fp, menu->tagprefix,
1078 menu->tagprefix ? cur : idx[menu->current]->content, hdr, menu);
1080 if (!menu->tagprefix && option (OPTRESOLVE) && menu->current < menu->max - 1)
1083 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
1090 if (Context->magic == M_POP)
1093 mutt_error _("Can't delete attachment from POP server.");
1099 if (Context->magic == M_NNTP)
1102 mutt_error _("Can't delete attachment from newsserver.");
1107 if (WithCrypto && hdr->security)
1110 "Deletion of attachments from encrypted messages is unsupported.");
1114 if (!menu->tagprefix)
1116 if (idx[menu->current]->parent_type == TYPEMULTIPART)
1118 idx[menu->current]->content->deleted = 1;
1119 if (option (OPTRESOLVE) && menu->current < menu->max - 1)
1122 menu->redraw = REDRAW_MOTION_RESYNCH;
1125 menu->redraw = REDRAW_CURRENT;
1129 "Only deletion of multipart attachments is supported.");
1135 for (x = 0; x < menu->max; x++)
1137 if (idx[x]->content->tagged)
1139 if (idx[x]->parent_type == TYPEMULTIPART)
1141 idx[x]->content->deleted = 1;
1142 menu->redraw = REDRAW_INDEX;
1146 "Only deletion of multipart attachments is supported.");
1155 if (!menu->tagprefix)
1157 idx[menu->current]->content->deleted = 0;
1158 if (option (OPTRESOLVE) && menu->current < menu->max - 1)
1161 menu->redraw = REDRAW_MOTION_RESYNCH;
1164 menu->redraw = REDRAW_CURRENT;
1170 for (x = 0; x < menu->max; x++)
1172 if (idx[x]->content->tagged)
1174 idx[x]->content->deleted = 0;
1175 menu->redraw = REDRAW_INDEX;
1183 mutt_attach_resend (fp, hdr, idx, idxlen,
1184 menu->tagprefix ? NULL : idx[menu->current]->content);
1185 menu->redraw = REDRAW_FULL;
1188 case OP_BOUNCE_MESSAGE:
1190 mutt_attach_bounce (fp, hdr, idx, idxlen,
1191 menu->tagprefix ? NULL : idx[menu->current]->content);
1192 menu->redraw = REDRAW_FULL;
1195 case OP_FORWARD_MESSAGE:
1197 mutt_attach_forward (fp, hdr, idx, idxlen,
1198 menu->tagprefix ? NULL : idx[menu->current]->content, 0);
1199 menu->redraw = REDRAW_FULL;
1203 case OP_FORWARD_TO_GROUP:
1205 mutt_attach_forward (fp, hdr, idx, idxlen,
1206 menu->tagprefix ? NULL : idx[menu->current]->content, SENDNEWS);
1207 menu->redraw = REDRAW_FULL;
1213 if (!idx[menu->current]->content->hdr->env->followup_to ||
1214 mutt_strcasecmp (idx[menu->current]->content->hdr->env->followup_to, "poster") ||
1215 query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
1217 mutt_attach_reply (fp, hdr, idx, idxlen,
1218 menu->tagprefix ? NULL : idx[menu->current]->content,
1219 SENDNEWS|SENDREPLY);
1220 menu->redraw = REDRAW_FULL;
1226 case OP_GROUP_REPLY:
1232 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1233 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1234 mutt_attach_reply (fp, hdr, idx, idxlen,
1235 menu->tagprefix ? NULL : idx[menu->current]->content, flags);
1236 menu->redraw = REDRAW_FULL;
1240 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1241 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1245 mx_close_message (&msg);
1246 hdr->attach_del = 0;
1247 while (idxmax-- > 0)
1251 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1252 hdr->attach_del = 1;
1253 if (idx[idxmax]->content)
1254 idx[idxmax]->content->aptr = NULL;
1255 FREE (&idx[idxmax]->tree);
1256 FREE (&idx[idxmax]);
1258 if (hdr->attach_del)
1263 if (WithCrypto && need_secured && secured)
1266 mutt_free_body (&cur);
1269 mutt_menuDestroy (&menu);