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>
15 #include <lib-ui/curses.h>
16 #include <lib-ui/enter.h>
17 #include <lib-ui/menu.h>
18 #include <lib-mx/mx.h>
20 #include <lib-sys/unix.h>
24 #include "recvattach.h"
27 #include <lib-crypt/crypt.h>
30 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
31 static char LastSaveFolder[_POSIX_PATH_MAX] = "";
33 #define CHECK_READONLY if (Context->readonly) \
36 mutt_error _(Mailbox_is_read_only); \
40 #define SW (option(OPTMBOXPANE)?SidebarWidth:0)
42 static struct mapping_t AttachHelp[] = {
43 {N_("Exit"), OP_EXIT},
44 {N_("Save"), OP_SAVE},
45 {N_("Pipe"), OP_PIPE},
46 {N_("Print"), OP_PRINT},
47 {N_("Help"), OP_HELP},
51 static int mutt_extract_path (char *filename, char *path, ssize_t pathlen)
53 char *tmp = p_new(char, _POSIX_PATH_MAX);
58 while (*filename != '\0') {
59 if (*filename == '/') {
60 *help_ptr++ = *filename++;
62 m_strcat(path, pathlen, tmp);
65 *help_ptr++ = *filename++;
71 void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
77 for (x = 0; x < idxlen; x++) {
79 if (2 * (idx[x]->level + 2) < ssizeof (buf)) {
81 s = buf + 2 * (idx[x]->level - 1);
82 *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
92 if (m_strcmp(idx[x]->tree, buf) != 0)
93 m_strreplace(&idx[x]->tree, buf);
96 idx[x]->tree = m_strdup(buf);
98 if (2 * (idx[x]->level + 2) < ssizeof (buf) && idx[x]->level) {
99 s = buf + 2 * (idx[x]->level - 1);
100 *s++ = (idx[x]->content->next) ? '\005' : '\006';
106 ATTACHPTR **mutt_gen_attach_list (BODY * m,
110 short *idxmax, int level, int compose)
115 for (; m; m = m->next) {
116 if (*idxlen == *idxmax) {
117 p_realloc(&idx, (*idxmax) += 5);
118 for (i = *idxlen; i < *idxmax; i++)
122 if (m->type == TYPEMULTIPART && m->parts
124 || (parent_type == -1
125 && ascii_strcasecmp ("alternative", m->subtype)))
126 && (!mutt_is_multipart_encrypted (m))
129 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level,
134 idx[*idxlen] = p_new(ATTACHPTR, 1);
136 new = idx[(*idxlen)++];
139 new->parent_type = parent_type;
142 /* We don't support multipart messages in the compose menu yet */
143 if (!compose && !m->collapsed
144 && ((m->type == TYPEMULTIPART && !mutt_is_multipart_encrypted(m))
145 || mutt_is_message_type(m)))
147 idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
154 mutt_update_tree (idx, *idxlen);
159 /* %c = character set: convert?
163 * %e = MIME content-transfer-encoding
165 * %I = content-disposition, either I (inline) or A (attachment)
168 * %m = major MIME type
170 * %n = attachment number
174 const char *mutt_attach_fmt (char *dest,
179 const char *ifstring,
180 const char *elsestring,
181 unsigned long data, format_flag flags)
184 char tmp[SHORT_STRING];
185 char charset[SHORT_STRING];
186 ATTACHPTR *aptr = (ATTACHPTR *) data;
187 int optional = (flags & M_FORMAT_OPTIONAL);
193 if (mutt_is_text_part (aptr->content) &&
194 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
195 mutt_format_s (dest, destlen, prefix, charset);
197 mutt_format_s (dest, destlen, prefix, "");
199 else if (!mutt_is_text_part (aptr->content) ||
200 !mutt_get_body_charset (charset, sizeof (charset),
207 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
208 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
209 aptr->content->noconv ? 'n' : 'c');
211 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
216 if (aptr->content->description) {
217 mutt_format_s (dest, destlen, prefix, aptr->content->description);
220 if (mutt_is_message_type(aptr->content) && MsgFmt && aptr->content->hdr)
222 char s[SHORT_STRING];
224 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
225 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT |
226 M_FORMAT_ARROWCURSOR);
228 mutt_format_s (dest, destlen, prefix, s);
232 if (!aptr->content->filename) {
233 mutt_format_s (dest, destlen, prefix, "<no description>");
237 else if (aptr->content->description ||
238 (mutt_is_message_type(aptr->content)
239 && MsgFmt && aptr->content->hdr))
241 /* FALLS THROUGH TO 'f' */
244 if (aptr->content->filename && *aptr->content->filename == '/') {
245 char path[_POSIX_PATH_MAX];
247 m_strcpy(path, sizeof(path), aptr->content->filename);
248 mutt_pretty_mailbox (path);
249 mutt_format_s (dest, destlen, prefix, path);
252 mutt_format_s (dest, destlen, prefix,
253 NONULL (aptr->content->filename));
255 else if (!aptr->content->filename)
260 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
261 else if (!aptr->content->deleted)
266 mutt_format_s (dest, destlen, prefix,
267 ENCODING (aptr->content->encoding));
271 snprintf (dest, destlen, "%c",
272 (aptr->content->disposition == DISPINLINE) ? 'I' : 'A');
277 mutt_format_s (dest, destlen, prefix, TYPE (aptr->content));
281 mutt_format_s (dest, destlen, prefix, aptr->content->subtype);
282 else if (!aptr->content->subtype)
287 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
288 snprintf (dest, destlen, fmt, aptr->num + 1);
293 optional = aptr->content->attach_qualifies;
295 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
296 mutt_format_s (dest, destlen, fmt, "Q");
300 if (flags & M_FORMAT_STAT_FILE) {
303 stat (aptr->content->filename, &st);
307 l = aptr->content->length;
310 mutt_pretty_size (tmp, sizeof (tmp), l);
311 mutt_format_s (dest, destlen, prefix, tmp);
319 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
320 else if (!aptr->content->tagged)
325 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
326 else if (!aptr->tree)
331 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
332 else if (!aptr->content->unlink)
337 optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0;
339 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
340 snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
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 static void attach_entry (char *b, ssize_t blen, MUTTMENU * menu, int num)
356 int w=(COLS-SW)>blen?blen:(COLS-SW);
357 mutt_FormatString (b, w, NONULL (AttachFormat), mutt_attach_fmt,
358 (unsigned long) (((ATTACHPTR **) menu->data)[num]),
359 M_FORMAT_ARROWCURSOR);
362 int mutt_tag_attach (MUTTMENU * menu, int n, int m)
364 BODY *cur = ((ATTACHPTR **) menu->data)[n]->content;
365 int ot = cur->tagged;
367 cur->tagged = (m >= 0 ? m : !cur->tagged);
368 return cur->tagged - ot;
371 static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
375 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
376 char path[_POSIX_PATH_MAX] = "";
382 if (body->filename) {
383 if (directory && *directory)
384 mutt_concat_path(buf, sizeof(buf), *directory,
385 mutt_basename(body->filename));
387 m_strcpy(buf, sizeof(buf), body->filename);
389 else if (body->hdr &&
390 body->encoding != ENCBASE64 &&
391 body->encoding != ENCQUOTEDPRINTABLE &&
392 mutt_is_message_type(body))
393 mutt_default_save (buf, sizeof (buf), body->hdr);
397 prompt = _("Save to file ('#' for last used folder): ");
400 mutt_get_field (prompt, buf, sizeof (buf),
401 M_FILE | M_CLEAR | M_LASTFOLDER);
402 if (((ret != 0) && (ret != 2)) || (!buf[0] && ret != 2))
406 char tmpbuf[_POSIX_PATH_MAX];
408 snprintf (tmpbuf, sizeof (tmpbuf), "%s%s", LastSaveFolder, buf);
409 m_strcpy(buf, sizeof(buf), tmpbuf);
410 ret = mutt_get_field (_("Save to file: ")
411 , buf, sizeof (buf), M_FILE);
412 if ((ret != 0) || (!buf[0]))
416 mutt_extract_path (buf, path, sizeof(path));
417 m_strcpy(LastSaveFolder, sizeof(LastSaveFolder), path);
421 mutt_expand_path (buf, sizeof (buf));
425 body->encoding != ENCBASE64 &&
426 body->encoding != ENCQUOTEDPRINTABLE &&
427 mutt_is_message_type(body));
432 /* check to make sure that this file is really the one the user wants */
433 if ((rc = mutt_save_confirm (buf, &st)) == 1) {
434 prompt = _("Save to file: ");
439 m_strcpy(tfile, sizeof(tfile), buf);
443 mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile),
444 &append, directory)) == -1)
447 prompt = _("Save to file: ");
452 mutt_message _("Saving...");
454 if (mutt_save_attachment
455 (fp, body, tfile, append,
456 (hdr || !is_message) ? hdr : body->hdr) == 0) {
457 mutt_message _("Attachment saved.");
462 prompt = _("Save to file: ");
469 void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
472 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
473 char *directory = NULL;
475 int last = menu ? menu->current : -1;
480 for (; top; top = top->next) {
481 if (!tag || top->tagged) {
482 if (!option (OPTATTACHSPLIT)) {
486 m_strcpy(buf, sizeof(buf), NONULL(top->filename));
487 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
488 M_FILE | M_CLEAR) != 0 || !buf[0])
490 mutt_expand_path (buf, sizeof (buf));
491 if (mutt_check_overwrite (top->filename, buf, tfile,
492 sizeof (tfile), &append, NULL))
494 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
495 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
496 fprintf (fpout, "%s", AttachSep);
501 rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
502 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
503 fprintf (fpout, "%s", AttachSep);
509 if (tag && menu && top->aptr) {
510 menu->oldcurrent = menu->current;
511 menu->current = top->aptr->num;
512 menu_check_recenter (menu);
513 menu->redraw |= REDRAW_MOTION;
517 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
522 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
527 p_delete(&directory);
530 menu->oldcurrent = menu->current;
531 menu->current = last;
532 menu_check_recenter (menu);
533 menu->redraw |= REDRAW_MOTION;
536 if (!option (OPTATTACHSPLIT) && (rc == 0))
537 mutt_message _("Attachment saved.");
541 mutt_query_pipe_attachment (char *command, FILE * fp, BODY * body, int afilter)
543 char tfile[_POSIX_PATH_MAX];
544 char warning[STRING + _POSIX_PATH_MAX];
547 snprintf (warning, sizeof (warning),
548 _("WARNING! You are about to overwrite %s, continue?"),
550 if (mutt_yesorno (warning, M_NO) != M_YES) {
551 CLEARLINE (LINES - 1);
559 if (mutt_pipe_attachment (fp, body, command, tfile)) {
561 mutt_unlink (body->filename);
562 mutt_rename_file (tfile, body->filename);
563 mutt_update_encoding (body);
564 mutt_message _("Attachment filtered.");
568 if (afilter && tfile[0])
573 static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
579 mutt_decode_attachment (b, state);
581 state_puts (AttachSep, state);
584 if ((ifp = fopen (b->filename, "r")) == NULL) {
585 mutt_perror ("fopen");
588 mutt_copy_stream (ifp, state->fpout);
591 state_puts (AttachSep, state);
596 pipe_attachment_list (char *command, FILE * fp, int tag, BODY * top,
597 int afilter, STATE * state)
599 for (; top; top = top->next) {
600 if (!tag || top->tagged) {
601 if (!afilter && !option (OPTATTACHSPLIT))
602 pipe_attachment (fp, top, state);
604 mutt_query_pipe_attachment (command, fp, top, afilter);
607 pipe_attachment_list (command, fp, tag, top->parts, afilter, state);
613 void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int afilter)
616 char buf[SHORT_STRING];
620 afilter = 0; /* sanity check: we can't filter in the recv case yet */
625 if (mutt_get_field ((afilter ? _("Filter through: ") : _("Pipe to: ")),
626 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
629 mutt_expand_path (buf, sizeof (buf));
631 if (!afilter && !option (OPTATTACHSPLIT)) {
633 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
634 pipe_attachment_list (buf, fp, tag, top, afilter, &state);
635 m_fclose(&state.fpout);
636 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
637 mutt_any_key_to_continue (NULL);
640 pipe_attachment_list (buf, fp, tag, top, afilter, &state);
643 static int can_print (BODY * top, int tag)
647 for (; top; top = top->next) {
648 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
649 if (!tag || top->tagged) {
650 if (!rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
651 if (ascii_strcasecmp ("text/plain", top->subtype) &&
652 ascii_strcasecmp ("application/postscript", top->subtype)) {
653 if (!mutt_can_decode (top)) {
654 mutt_error (_("I dont know how to print %s attachments!"), type);
661 return (can_print (top->parts, tag));
668 static void print_attachment_list (FILE * fp, int tag, BODY * top,
674 for (; top; top = top->next) {
675 if (!tag || top->tagged) {
676 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
677 if (!option (OPTATTACHSPLIT)
678 && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
679 if (!ascii_strcasecmp ("text/plain", top->subtype)
680 || !ascii_strcasecmp ("application/postscript", top->subtype))
681 pipe_attachment (fp, top, state);
682 else if (mutt_can_decode (top)) {
683 /* decode and print */
685 char newfile[_POSIX_PATH_MAX] = "";
688 mutt_mktemp (newfile);
689 if (mutt_decode_save_attachment (fp, top, newfile, M_PRINTING, 0) ==
691 if ((ifp = fopen (newfile, "r")) != NULL) {
692 mutt_copy_stream (ifp, state->fpout);
695 state_puts (AttachSep, state);
698 mutt_unlink (newfile);
702 mutt_print_attachment (fp, top);
705 print_attachment_list (fp, tag, top->parts, state);
711 void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
719 tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) !=
723 if (!option (OPTATTACHSPLIT)) {
724 if (!can_print (top, tag))
728 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
729 print_attachment_list (fp, tag, top, &state);
730 m_fclose(&state.fpout);
731 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
732 mutt_any_key_to_continue (NULL);
735 print_attachment_list (fp, tag, top, &state);
739 mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
740 short *idxlen, short *idxmax, MUTTMENU * menu)
742 ATTACHPTR **idx = *idxp;
744 while (--(*idxlen) >= 0)
745 idx[(*idxlen)]->content = NULL;
748 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
753 if (menu->current >= menu->max)
754 menu->current = menu->max - 1;
755 menu_check_recenter (menu);
756 menu->redraw |= REDRAW_INDEX;
762 mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
763 BODY * cur, ATTACHPTR *** idxp, short *idxlen,
764 short *idxmax, int recv)
766 ATTACHPTR **idx = *idxp;
770 case OP_DISPLAY_HEADERS:
771 toggle_option (OPTWEED);
775 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
780 case OP_MAIN_NEXT_UNDELETED: /* hack */
781 if (menu->current < menu->max - 1) {
789 case OP_MAIN_PREV_UNDELETED: /* hack */
790 if (menu->current > 0) {
798 /* when we edit the content-type, we should redisplay the attachment
800 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
802 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
807 /* functions which are passed through from the pager */
808 case OP_CHECK_TRADITIONAL:
809 if (hdr && hdr->security & PGP_TRADITIONAL_CHECKED) {
814 case OP_ATTACH_COLLAPSE:
821 while (op != OP_NULL);
826 static void attach_collapse (BODY * b, short collapse, short init,
831 for (; b; b = b->next) {
832 i = init || b->collapsed;
833 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
834 && mime_which_token(b->subtype, -1) == MIME_DIGEST)
835 attach_collapse (b->parts, 1, 1, 0);
836 else if (b->type == TYPEMULTIPART || mutt_is_message_type(b))
837 attach_collapse (b->parts, collapse, i, 0);
838 b->collapsed = collapse;
844 void mutt_attach_init (BODY * b)
846 for (; b; b = b->next) {
850 mutt_attach_init (b->parts);
854 void mutt_view_attachments (HEADER * hdr)
857 int need_secured = 0;
859 char helpstr[SHORT_STRING];
864 ATTACHPTR **idx = NULL;
870 /* make sure we have parsed this message */
871 mutt_parse_mime_message (Context, hdr);
873 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
875 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
879 if ((hdr->security & ENCRYPT) ||
880 (mutt_is_application_smime (hdr->content) & SMIMEOPAQUE))
884 if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase (hdr->security)) {
885 mx_close_message (&msg);
888 if (hdr->security & APPLICATION_SMIME) {
890 crypt_smime_getkeys (hdr->env);
892 if (mutt_is_application_smime (hdr->content)) {
893 secured = !crypt_smime_decrypt_mime (msg->fp, &fp,
897 if ((mutt_is_application_smime (cur) & SMIMEOPAQUE)) {
903 secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
905 body_list_wipe(&_cur);
912 if (hdr->security & APPLICATION_PGP) {
913 if (mutt_is_multipart_encrypted (hdr->content))
914 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
919 if (need_secured && !secured) {
920 mx_close_message (&msg);
921 mutt_error _("Can't decrypt encrypted message!");
932 menu = mutt_new_menu ();
933 menu->menu = MENU_ATTACH;
934 menu->title = _("Attachments");
935 menu->make_entry = attach_entry;
936 menu->tag = mutt_tag_attach;
938 mutt_compile_help (helpstr, sizeof (helpstr), MENU_ATTACH, AttachHelp);
940 mutt_attach_init (cur);
941 attach_collapse (cur, 0, 1, 0);
942 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
944 #define CHECK_ATTACH \
945 if (option(OPTATTACHMSG)) { \
947 mutt_error _("Function not permitted in attach-message mode."); \
953 op = mutt_menuLoop(menu);
955 case OP_ATTACH_VIEW_MAILCAP:
956 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
958 menu->redraw = REDRAW_FULL;
961 case OP_ATTACH_VIEW_TEXT:
962 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
964 menu->redraw = REDRAW_FULL;
967 case OP_DISPLAY_HEADERS:
970 mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen,
972 menu->redraw = REDRAW_FULL;
975 case OP_ATTACH_COLLAPSE:
976 if (!idx[menu->current]->content->parts) {
977 mutt_error _("There are no subparts to show!");
981 if (!idx[menu->current]->content->collapsed)
982 attach_collapse (idx[menu->current]->content, 1, 0, 1);
984 attach_collapse (idx[menu->current]->content, 0, 1, 1);
985 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
988 case OP_FORGET_PASSPHRASE:
989 crypt_forget_passphrase ();
992 case OP_EXTRACT_KEYS:
993 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
998 menu->redraw = REDRAW_FULL;
1001 case OP_CHECK_TRADITIONAL:
1002 if (crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
1003 : idx[menu->current]->content,
1006 hdr->security = crypt_query (cur);
1007 menu->redraw = REDRAW_FULL;
1012 mutt_print_attachment_list (fp, menu->tagprefix,
1013 menu->tagprefix ? cur : idx[menu->current]->
1018 mutt_pipe_attachment_list (fp, menu->tagprefix,
1019 menu->tagprefix ? cur : idx[menu->current]->
1024 mutt_save_attachment_list (fp, menu->tagprefix,
1025 menu->tagprefix ? cur : idx[menu->current]->
1026 content, hdr, menu);
1028 if (!menu->tagprefix && option (OPTRESOLVE)
1029 && menu->current < menu->max - 1)
1032 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
1038 if (Context->magic == M_POP) {
1040 mutt_error _("Can't delete attachment from POP server.");
1046 if (Context->magic == M_NNTP) {
1048 mutt_error _("Can't delete attachment from newsserver.");
1054 if (hdr->security & (~PGP_TRADITIONAL_CHECKED)) {
1056 _("Deletion of attachments from encrypted messages is unsupported.");
1059 if (!menu->tagprefix) {
1060 if (idx[menu->current]->parent_type == TYPEMULTIPART) {
1061 idx[menu->current]->content->deleted = 1;
1062 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1064 menu->redraw = REDRAW_MOTION_RESYNCH;
1067 menu->redraw = REDRAW_CURRENT;
1071 _("Only deletion of multipart attachments is supported.");
1076 for (x = 0; x < menu->max; x++) {
1077 if (idx[x]->content->tagged) {
1078 if (idx[x]->parent_type == TYPEMULTIPART) {
1079 idx[x]->content->deleted = 1;
1080 menu->redraw = REDRAW_INDEX;
1084 _("Only deletion of multipart attachments is supported.");
1093 if (!menu->tagprefix) {
1094 idx[menu->current]->content->deleted = 0;
1095 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1097 menu->redraw = REDRAW_MOTION_RESYNCH;
1100 menu->redraw = REDRAW_CURRENT;
1105 for (x = 0; x < menu->max; x++) {
1106 if (idx[x]->content->tagged) {
1107 idx[x]->content->deleted = 0;
1108 menu->redraw = REDRAW_INDEX;
1116 mutt_attach_resend (fp, hdr, idx, idxlen,
1117 menu->tagprefix ? NULL : idx[menu->current]->
1119 menu->redraw = REDRAW_FULL;
1122 case OP_BOUNCE_MESSAGE:
1124 mutt_attach_bounce (fp, hdr, idx, idxlen,
1125 menu->tagprefix ? NULL : idx[menu->current]->
1127 menu->redraw = REDRAW_FULL;
1130 case OP_FORWARD_MESSAGE:
1132 mutt_attach_forward (fp, hdr, idx, idxlen,
1133 menu->tagprefix ? NULL : idx[menu->current]->
1135 menu->redraw = REDRAW_FULL;
1139 case OP_FORWARD_TO_GROUP:
1141 mutt_attach_forward (fp, hdr, idx, idxlen,
1142 menu->tagprefix ? NULL : idx[menu->current]->
1144 menu->redraw = REDRAW_FULL;
1150 if (!idx[menu->current]->content->hdr->env->followup_to ||
1151 m_strcasecmp(idx[menu->current]->content->hdr->env->followup_to,
1153 || query_quadoption (OPT_FOLLOWUPTOPOSTER,
1154 _("Reply by mail as poster prefers?")) !=
1156 mutt_attach_reply (fp, hdr, idx, idxlen,
1157 menu->tagprefix ? NULL : idx[menu->current]->
1158 content, SENDNEWS | SENDREPLY);
1159 menu->redraw = REDRAW_FULL;
1165 case OP_GROUP_REPLY:
1171 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1172 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1173 mutt_attach_reply (fp, hdr, idx, idxlen,
1174 menu->tagprefix ? NULL : idx[menu->current]->content,
1176 menu->redraw = REDRAW_FULL;
1180 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1181 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1185 mx_close_message (&msg);
1186 hdr->attach_del = 0;
1187 while (idxmax-- > 0) {
1190 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1191 hdr->attach_del = 1;
1192 if (idx[idxmax]->content)
1193 idx[idxmax]->content->aptr = NULL;
1194 p_delete(&idx[idxmax]->tree);
1195 p_delete(&idx[idxmax]);
1197 if (hdr->attach_del)
1202 if (need_secured && secured) {
1204 body_list_wipe(&cur);
1207 mutt_menuDestroy (&menu);