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.
19 #include "recvattach.h"
20 #include "mutt_curses.h"
21 #include "mutt_menu.h"
28 #include "mutt_crypt.h"
42 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
43 static char LastSaveFolder[_POSIX_PATH_MAX] = "";
45 #define CHECK_READONLY if (Context->readonly) \
48 mutt_error _(Mailbox_is_read_only); \
52 static struct mapping_t AttachHelp[] = {
53 {N_("Exit"), OP_EXIT},
54 {N_("Save"), OP_SAVE},
55 {N_("Pipe"), OP_PIPE},
56 {N_("Print"), OP_PRINT},
57 {N_("Help"), OP_HELP},
61 static int mutt_extract_path (char *filename, char *path)
63 char *tmp = mem_malloc (sizeof (char) * _POSIX_PATH_MAX);
68 while (*filename != '\0') {
69 if (*filename == '/') {
70 *help_ptr++ = *filename++;
75 *help_ptr++ = *filename++;
81 void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
87 for (x = 0; x < idxlen; x++) {
89 if (2 * (idx[x]->level + 2) < sizeof (buf)) {
91 s = buf + 2 * (idx[x]->level - 1);
92 *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
102 if (str_cmp (idx[x]->tree, buf) != 0)
103 str_replace (&idx[x]->tree, buf);
106 idx[x]->tree = str_dup (buf);
108 if (2 * (idx[x]->level + 2) < sizeof (buf) && idx[x]->level) {
109 s = buf + 2 * (idx[x]->level - 1);
110 *s++ = (idx[x]->content->next) ? '\005' : '\006';
116 ATTACHPTR **mutt_gen_attach_list (BODY * m,
120 short *idxmax, int level, int compose)
125 for (; m; m = m->next) {
126 if (*idxlen == *idxmax) {
127 mem_realloc (&idx, sizeof (ATTACHPTR *) * ((*idxmax) += 5));
128 for (i = *idxlen; i < *idxmax; i++)
132 if (m->type == TYPEMULTIPART && m->parts
134 || (parent_type == -1
135 && ascii_strcasecmp ("alternative", m->subtype)))
136 && (!(WithCrypto & APPLICATION_PGP)
137 || !mutt_is_multipart_encrypted (m))
140 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level,
145 idx[*idxlen] = (ATTACHPTR *) mem_calloc (1, sizeof (ATTACHPTR));
147 new = idx[(*idxlen)++];
150 new->parent_type = parent_type;
153 /* We don't support multipart messages in the compose menu yet */
154 if (!compose && !m->collapsed &&
155 ((m->type == TYPEMULTIPART && (!(WithCrypto & APPLICATION_PGP)
156 || !mutt_is_multipart_encrypted (m))
158 || mutt_is_message_type (m->type, m->subtype))) {
160 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
167 mutt_update_tree (idx, *idxlen);
172 /* %c = character set: convert?
176 * %e = MIME content-transfer-encoding
178 * %I = content-disposition, either I (inline) or A (attachment)
181 * %m = major MIME type
183 * %n = attachment number
187 const char *mutt_attach_fmt (char *dest,
192 const char *ifstring,
193 const char *elsestring,
194 unsigned long data, format_flag flags)
197 char tmp[SHORT_STRING];
198 char charset[SHORT_STRING];
199 ATTACHPTR *aptr = (ATTACHPTR *) data;
200 int optional = (flags & M_FORMAT_OPTIONAL);
206 if (mutt_is_text_part (aptr->content) &&
207 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
208 mutt_format_s (dest, destlen, prefix, charset);
210 mutt_format_s (dest, destlen, prefix, "");
212 else if (!mutt_is_text_part (aptr->content) ||
213 !mutt_get_body_charset (charset, sizeof (charset),
220 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
221 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
222 aptr->content->noconv ? 'n' : 'c');
224 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
229 if (aptr->content->description) {
230 mutt_format_s (dest, destlen, prefix, aptr->content->description);
233 if (mutt_is_message_type (aptr->content->type, aptr->content->subtype)
234 && MsgFmt && aptr->content->hdr) {
235 char s[SHORT_STRING];
237 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
238 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT |
239 M_FORMAT_ARROWCURSOR);
241 mutt_format_s (dest, destlen, prefix, s);
245 if (!aptr->content->filename) {
246 mutt_format_s (dest, destlen, prefix, "<no description>");
250 else if (aptr->content->description ||
251 (mutt_is_message_type
252 (aptr->content->type, aptr->content->subtype)
253 && MsgFmt && aptr->content->hdr))
255 /* FALLS THROUGH TO 'f' */
258 if (aptr->content->filename && *aptr->content->filename == '/') {
259 char path[_POSIX_PATH_MAX];
261 strfcpy (path, aptr->content->filename, sizeof (path));
262 mutt_pretty_mailbox (path);
263 mutt_format_s (dest, destlen, prefix, path);
266 mutt_format_s (dest, destlen, prefix,
267 NONULL (aptr->content->filename));
269 else if (!aptr->content->filename)
274 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
275 else if (!aptr->content->deleted)
280 mutt_format_s (dest, destlen, prefix,
281 ENCODING (aptr->content->encoding));
285 snprintf (dest, destlen, "%c",
286 (aptr->content->disposition == DISPINLINE) ? 'I' : 'A');
291 mutt_format_s (dest, destlen, prefix, TYPE (aptr->content));
295 mutt_format_s (dest, destlen, prefix, aptr->content->subtype);
296 else if (!aptr->content->subtype)
301 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
302 snprintf (dest, destlen, fmt, aptr->num + 1);
306 if (flags & M_FORMAT_STAT_FILE) {
309 stat (aptr->content->filename, &st);
313 l = aptr->content->length;
316 mutt_pretty_size (tmp, sizeof (tmp), l);
317 mutt_format_s (dest, destlen, prefix, tmp);
325 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
326 else if (!aptr->content->tagged)
331 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
332 else if (!aptr->tree)
337 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
338 else if (!aptr->content->unlink)
346 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
347 else if (flags & M_FORMAT_OPTIONAL)
348 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
352 static void attach_entry (char *b, size_t blen, MUTTMENU * menu, int num)
354 mutt_FormatString (b, blen, NONULL (AttachFormat), mutt_attach_fmt,
355 (unsigned long) (((ATTACHPTR **) menu->data)[num]),
356 M_FORMAT_ARROWCURSOR);
359 int mutt_tag_attach (MUTTMENU * menu, int n, int m)
361 BODY *cur = ((ATTACHPTR **) menu->data)[n]->content;
362 int ot = cur->tagged;
364 cur->tagged = (m >= 0 ? m : !cur->tagged);
365 return cur->tagged - ot;
368 int mutt_is_message_type (int type, const char *subtype)
370 if (type != TYPEMESSAGE)
373 subtype = NONULL (subtype);
374 return (ascii_strcasecmp (subtype, "rfc822") == 0
375 || ascii_strcasecmp (subtype, "news") == 0);
378 static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
382 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
383 char path[_POSIX_PATH_MAX] = "";
389 if (body->filename) {
390 if (directory && *directory)
391 mutt_concat_path (buf, *directory, mutt_basename (body->filename),
394 strfcpy (buf, body->filename, sizeof (buf));
396 else if (body->hdr &&
397 body->encoding != ENCBASE64 &&
398 body->encoding != ENCQUOTEDPRINTABLE &&
399 mutt_is_message_type (body->type, body->subtype))
400 mutt_default_save (buf, sizeof (buf), body->hdr);
404 prompt = _("Save to file ('#' for last used folder): ");
407 mutt_get_field (prompt, buf, sizeof (buf),
408 M_FILE | M_CLEAR | M_LASTFOLDER);
409 if (((ret != 0) && (ret != 2)) || (!buf[0] && ret != 2))
413 char tmpbuf[_POSIX_PATH_MAX];
415 snprintf (tmpbuf, sizeof (tmpbuf), "%s%s", LastSaveFolder, buf);
416 strfcpy (buf, tmpbuf, sizeof (buf));
417 ret = mutt_get_field (_("Save to file: ")
418 , buf, sizeof (buf), M_FILE);
419 if ((ret != 0) || (!buf[0]))
423 mutt_extract_path (buf, path);
424 strfcpy (LastSaveFolder, path, sizeof (LastSaveFolder));
428 mutt_expand_path (buf, sizeof (buf));
432 body->encoding != ENCBASE64 &&
433 body->encoding != ENCQUOTEDPRINTABLE &&
434 mutt_is_message_type (body->type, body->subtype));
439 /* check to make sure that this file is really the one the user wants */
440 if ((rc = mutt_save_confirm (buf, &st)) == 1) {
441 prompt = _("Save to file: ");
446 strfcpy (tfile, buf, sizeof (tfile));
450 mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile),
451 &append, directory)) == -1)
454 prompt = _("Save to file: ");
459 mutt_message _("Saving...");
461 if (mutt_save_attachment
462 (fp, body, tfile, append,
463 (hdr || !is_message) ? hdr : body->hdr) == 0) {
464 mutt_message _("Attachment saved.");
469 prompt = _("Save to file: ");
476 void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
479 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
480 char *directory = NULL;
482 int last = menu ? menu->current : -1;
487 for (; top; top = top->next) {
488 if (!tag || top->tagged) {
489 if (!option (OPTATTACHSPLIT)) {
493 strfcpy (buf, NONULL (top->filename), sizeof (buf));
494 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
495 M_FILE | M_CLEAR) != 0 || !buf[0])
497 mutt_expand_path (buf, sizeof (buf));
498 if (mutt_check_overwrite (top->filename, buf, tfile,
499 sizeof (tfile), &append, NULL))
501 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
502 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
503 fprintf (fpout, "%s", AttachSep);
508 rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
509 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
510 fprintf (fpout, "%s", AttachSep);
516 if (tag && menu && top->aptr) {
517 menu->oldcurrent = menu->current;
518 menu->current = top->aptr->num;
519 menu_check_recenter (menu);
520 menu->redraw |= REDRAW_MOTION;
524 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
529 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
534 mem_free (&directory);
537 menu->oldcurrent = menu->current;
538 menu->current = last;
539 menu_check_recenter (menu);
540 menu->redraw |= REDRAW_MOTION;
543 if (!option (OPTATTACHSPLIT) && (rc == 0))
544 mutt_message _("Attachment saved.");
548 mutt_query_pipe_attachment (char *command, FILE * fp, BODY * body, int filter)
550 char tfile[_POSIX_PATH_MAX];
551 char warning[STRING + _POSIX_PATH_MAX];
554 snprintf (warning, sizeof (warning),
555 _("WARNING! You are about to overwrite %s, continue?"),
557 if (mutt_yesorno (warning, M_NO) != M_YES) {
558 CLEARLINE (LINES - 1);
566 if (mutt_pipe_attachment (fp, body, command, tfile)) {
568 mutt_unlink (body->filename);
569 mutt_rename_file (tfile, body->filename);
570 mutt_update_encoding (body);
571 mutt_message _("Attachment filtered.");
575 if (filter && tfile[0])
580 static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
586 mutt_decode_attachment (b, state);
588 state_puts (AttachSep, state);
591 if ((ifp = fopen (b->filename, "r")) == NULL) {
592 mutt_perror ("fopen");
595 mutt_copy_stream (ifp, state->fpout);
598 state_puts (AttachSep, state);
603 pipe_attachment_list (char *command, FILE * fp, int tag, BODY * top,
604 int filter, STATE * state)
606 for (; top; top = top->next) {
607 if (!tag || top->tagged) {
608 if (!filter && !option (OPTATTACHSPLIT))
609 pipe_attachment (fp, top, state);
611 mutt_query_pipe_attachment (command, fp, top, filter);
614 pipe_attachment_list (command, fp, tag, top->parts, filter, state);
620 void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int filter)
623 char buf[SHORT_STRING];
627 filter = 0; /* sanity check: we can't filter in the recv case yet */
630 memset (&state, 0, sizeof (STATE));
632 if (mutt_get_field ((filter ? _("Filter through: ") : _("Pipe to: ")),
633 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
636 mutt_expand_path (buf, sizeof (buf));
638 if (!filter && !option (OPTATTACHSPLIT)) {
640 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
641 pipe_attachment_list (buf, fp, tag, top, filter, &state);
642 fclose (state.fpout);
643 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
644 mutt_any_key_to_continue (NULL);
647 pipe_attachment_list (buf, fp, tag, top, filter, &state);
650 static int can_print (BODY * top, int tag)
654 for (; top; top = top->next) {
655 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
656 if (!tag || top->tagged) {
657 if (!rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
658 if (ascii_strcasecmp ("text/plain", top->subtype) &&
659 ascii_strcasecmp ("application/postscript", top->subtype)) {
660 if (!mutt_can_decode (top)) {
661 mutt_error (_("I dont know how to print %s attachments!"), type);
668 return (can_print (top->parts, tag));
675 static void print_attachment_list (FILE * fp, int tag, BODY * top,
681 for (; top; top = top->next) {
682 if (!tag || top->tagged) {
683 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
684 if (!option (OPTATTACHSPLIT)
685 && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
686 if (!ascii_strcasecmp ("text/plain", top->subtype)
687 || !ascii_strcasecmp ("application/postscript", top->subtype))
688 pipe_attachment (fp, top, state);
689 else if (mutt_can_decode (top)) {
690 /* decode and print */
692 char newfile[_POSIX_PATH_MAX] = "";
695 mutt_mktemp (newfile);
696 if (mutt_decode_save_attachment (fp, top, newfile, M_PRINTING, 0) ==
698 if ((ifp = fopen (newfile, "r")) != NULL) {
699 mutt_copy_stream (ifp, state->fpout);
702 state_puts (AttachSep, state);
705 mutt_unlink (newfile);
709 mutt_print_attachment (fp, top);
712 print_attachment_list (fp, tag, top->parts, state);
718 void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
726 tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) !=
730 if (!option (OPTATTACHSPLIT)) {
731 if (!can_print (top, tag))
734 memset (&state, 0, sizeof (STATE));
735 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
736 print_attachment_list (fp, tag, top, &state);
737 fclose (state.fpout);
738 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
739 mutt_any_key_to_continue (NULL);
742 print_attachment_list (fp, tag, top, &state);
746 mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
747 short *idxlen, short *idxmax, MUTTMENU * menu)
749 ATTACHPTR **idx = *idxp;
751 while (--(*idxlen) >= 0)
752 idx[(*idxlen)]->content = NULL;
755 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
760 if (menu->current >= menu->max)
761 menu->current = menu->max - 1;
762 menu_check_recenter (menu);
763 menu->redraw |= REDRAW_INDEX;
769 mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
770 BODY * cur, ATTACHPTR *** idxp, short *idxlen,
771 short *idxmax, int recv)
773 ATTACHPTR **idx = *idxp;
776 int old_optweed = option (OPTWEED);
778 set_option (OPTWEED);
783 case OP_DISPLAY_HEADERS:
784 toggle_option (OPTWEED);
788 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
793 case OP_MAIN_NEXT_UNDELETED: /* hack */
794 if (menu->current < menu->max - 1) {
802 case OP_MAIN_PREV_UNDELETED: /* hack */
803 if (menu->current > 0) {
811 /* when we edit the content-type, we should redisplay the attachment
813 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
815 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
820 /* functions which are passed through from the pager */
821 case OP_CHECK_TRADITIONAL:
822 if (!(WithCrypto & APPLICATION_PGP)
823 || (hdr && hdr->security & PGP_TRADITIONAL_CHECKED)) {
828 case OP_ATTACH_COLLAPSE:
835 while (op != OP_NULL);
838 if (option (OPTWEED) != old_optweed)
839 toggle_option (OPTWEED);
844 static void attach_collapse (BODY * b, short collapse, short init,
849 for (; b; b = b->next) {
850 i = init || b->collapsed;
851 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
852 && !ascii_strcasecmp (b->subtype, "digest"))
853 attach_collapse (b->parts, 1, 1, 0);
854 else if (b->type == TYPEMULTIPART
855 || mutt_is_message_type (b->type, b->subtype))
856 attach_collapse (b->parts, collapse, i, 0);
857 b->collapsed = collapse;
863 void mutt_attach_init (BODY * b)
865 for (; b; b = b->next) {
869 mutt_attach_init (b->parts);
873 static const char *Function_not_permitted =
874 N_("Function not permitted in attach-message mode.");
876 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
879 mutt_error _(Function_not_permitted); \
886 void mutt_view_attachments (HEADER * hdr)
889 int need_secured = 0;
891 char helpstr[SHORT_STRING];
896 ATTACHPTR **idx = NULL;
902 /* make sure we have parsed this message */
903 mutt_parse_mime_message (Context, hdr);
905 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
907 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
911 if (WithCrypto && ((hdr->security & ENCRYPT) ||
912 (mutt_is_application_smime (hdr->content) &
916 if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase (hdr->security)) {
917 mx_close_message (&msg);
920 if ((WithCrypto & APPLICATION_SMIME)
921 && (hdr->security & APPLICATION_SMIME)) {
923 crypt_smime_getkeys (hdr->env);
925 if (mutt_is_application_smime (hdr->content)) {
926 secured = !crypt_smime_decrypt_mime (msg->fp, &fp,
930 if ((mutt_is_application_smime (cur) & SMIMEOPAQUE)) {
936 secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
938 mutt_free_body (&_cur);
945 if ((WithCrypto & APPLICATION_PGP) && (hdr->security & APPLICATION_PGP)) {
946 if (mutt_is_multipart_encrypted (hdr->content))
947 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
952 if (need_secured && !secured) {
953 mx_close_message (&msg);
954 mutt_error _("Can't decrypt encrypted message!");
960 if (!WithCrypto || !need_secured) {
965 menu = mutt_new_menu ();
966 menu->menu = MENU_ATTACH;
967 menu->title = _("Attachments");
968 menu->make_entry = attach_entry;
969 menu->tag = mutt_tag_attach;
971 mutt_compile_help (helpstr, sizeof (helpstr), MENU_ATTACH, AttachHelp);
973 mutt_attach_init (cur);
974 attach_collapse (cur, 0, 1, 0);
975 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
979 op = mutt_menuLoop (menu);
981 case OP_ATTACH_VIEW_MAILCAP:
982 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
984 menu->redraw = REDRAW_FULL;
987 case OP_ATTACH_VIEW_TEXT:
988 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
990 menu->redraw = REDRAW_FULL;
993 case OP_DISPLAY_HEADERS:
996 mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen,
998 menu->redraw = REDRAW_FULL;
1001 case OP_ATTACH_COLLAPSE:
1002 if (!idx[menu->current]->content->parts) {
1003 mutt_error _("There are no subparts to show!");
1007 if (!idx[menu->current]->content->collapsed)
1008 attach_collapse (idx[menu->current]->content, 1, 0, 1);
1010 attach_collapse (idx[menu->current]->content, 0, 1, 1);
1011 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1014 case OP_FORGET_PASSPHRASE:
1015 crypt_forget_passphrase ();
1018 case OP_EXTRACT_KEYS:
1019 if ((WithCrypto & APPLICATION_PGP)) {
1020 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
1023 idx[menu->current]->
1025 menu->redraw = REDRAW_FULL;
1029 case OP_CHECK_TRADITIONAL:
1030 if ((WithCrypto & APPLICATION_PGP)
1031 && crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
1032 : idx[menu->current]->content,
1034 hdr->security = crypt_query (cur);
1035 menu->redraw = REDRAW_FULL;
1040 mutt_print_attachment_list (fp, menu->tagprefix,
1041 menu->tagprefix ? cur : idx[menu->current]->
1046 mutt_pipe_attachment_list (fp, menu->tagprefix,
1047 menu->tagprefix ? cur : idx[menu->current]->
1052 mutt_save_attachment_list (fp, menu->tagprefix,
1053 menu->tagprefix ? cur : idx[menu->current]->
1054 content, hdr, menu);
1056 if (!menu->tagprefix && option (OPTRESOLVE)
1057 && menu->current < menu->max - 1)
1060 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
1067 if (Context->magic == M_POP) {
1069 mutt_error _("Can't delete attachment from POP server.");
1076 if (Context->magic == M_NNTP) {
1078 mutt_error _("Can't delete attachment from newsserver.");
1084 if (WithCrypto && (hdr->security & (~PGP_TRADITIONAL_CHECKED))) {
1087 ("Deletion of attachments from encrypted messages is unsupported.");
1090 if (!menu->tagprefix) {
1091 if (idx[menu->current]->parent_type == TYPEMULTIPART) {
1092 idx[menu->current]->content->deleted = 1;
1093 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1095 menu->redraw = REDRAW_MOTION_RESYNCH;
1098 menu->redraw = REDRAW_CURRENT;
1102 _("Only deletion of multipart attachments is supported.");
1107 for (x = 0; x < menu->max; x++) {
1108 if (idx[x]->content->tagged) {
1109 if (idx[x]->parent_type == TYPEMULTIPART) {
1110 idx[x]->content->deleted = 1;
1111 menu->redraw = REDRAW_INDEX;
1115 _("Only deletion of multipart attachments is supported.");
1124 if (!menu->tagprefix) {
1125 idx[menu->current]->content->deleted = 0;
1126 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1128 menu->redraw = REDRAW_MOTION_RESYNCH;
1131 menu->redraw = REDRAW_CURRENT;
1136 for (x = 0; x < menu->max; x++) {
1137 if (idx[x]->content->tagged) {
1138 idx[x]->content->deleted = 0;
1139 menu->redraw = REDRAW_INDEX;
1147 mutt_attach_resend (fp, hdr, idx, idxlen,
1148 menu->tagprefix ? NULL : idx[menu->current]->
1150 menu->redraw = REDRAW_FULL;
1153 case OP_BOUNCE_MESSAGE:
1155 mutt_attach_bounce (fp, hdr, idx, idxlen,
1156 menu->tagprefix ? NULL : idx[menu->current]->
1158 menu->redraw = REDRAW_FULL;
1161 case OP_FORWARD_MESSAGE:
1163 mutt_attach_forward (fp, hdr, idx, idxlen,
1164 menu->tagprefix ? NULL : idx[menu->current]->
1166 menu->redraw = REDRAW_FULL;
1170 case OP_FORWARD_TO_GROUP:
1172 mutt_attach_forward (fp, hdr, idx, idxlen,
1173 menu->tagprefix ? NULL : idx[menu->current]->
1175 menu->redraw = REDRAW_FULL;
1181 if (!idx[menu->current]->content->hdr->env->followup_to ||
1182 str_casecmp (idx[menu->current]->content->hdr->env->followup_to,
1184 || query_quadoption (OPT_FOLLOWUPTOPOSTER,
1185 _("Reply by mail as poster prefers?")) !=
1187 mutt_attach_reply (fp, hdr, idx, idxlen,
1188 menu->tagprefix ? NULL : idx[menu->current]->
1189 content, SENDNEWS | SENDREPLY);
1190 menu->redraw = REDRAW_FULL;
1196 case OP_GROUP_REPLY:
1202 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1203 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1204 mutt_attach_reply (fp, hdr, idx, idxlen,
1205 menu->tagprefix ? NULL : idx[menu->current]->content,
1207 menu->redraw = REDRAW_FULL;
1211 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1212 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1216 mx_close_message (&msg);
1217 hdr->attach_del = 0;
1218 while (idxmax-- > 0) {
1221 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1222 hdr->attach_del = 1;
1223 if (idx[idxmax]->content)
1224 idx[idxmax]->content->aptr = NULL;
1225 mem_free (&idx[idxmax]->tree);
1226 mem_free (&idx[idxmax]);
1228 if (hdr->attach_del)
1233 if (WithCrypto && need_secured && secured) {
1235 mutt_free_body (&cur);
1238 mutt_menuDestroy (&menu);