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.
15 #include <lib-lib/mem.h>
16 #include <lib-lib/str.h>
17 #include <lib-lib/macros.h>
18 #include <lib-lib/ascii.h>
19 #include <lib-lib/file.h>
24 #include "recvattach.h"
25 #include "mutt_curses.h"
26 #include "mutt_menu.h"
33 #include "mutt_crypt.h"
44 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
45 static char LastSaveFolder[_POSIX_PATH_MAX] = "";
47 #define CHECK_READONLY if (Context->readonly) \
50 mutt_error _(Mailbox_is_read_only); \
54 #define SW (option(OPTMBOXPANE)?SidebarWidth:0)
56 static struct mapping_t AttachHelp[] = {
57 {N_("Exit"), OP_EXIT},
58 {N_("Save"), OP_SAVE},
59 {N_("Pipe"), OP_PIPE},
60 {N_("Print"), OP_PRINT},
61 {N_("Help"), OP_HELP},
65 static int mutt_extract_path (char *filename, char *path)
67 char *tmp = p_new(char, _POSIX_PATH_MAX);
72 while (*filename != '\0') {
73 if (*filename == '/') {
74 *help_ptr++ = *filename++;
79 *help_ptr++ = *filename++;
85 void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
91 for (x = 0; x < idxlen; x++) {
93 if (2 * (idx[x]->level + 2) < sizeof (buf)) {
95 s = buf + 2 * (idx[x]->level - 1);
96 *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
106 if (m_strcmp(idx[x]->tree, buf) != 0)
107 str_replace (&idx[x]->tree, buf);
110 idx[x]->tree = m_strdup(buf);
112 if (2 * (idx[x]->level + 2) < sizeof (buf) && idx[x]->level) {
113 s = buf + 2 * (idx[x]->level - 1);
114 *s++ = (idx[x]->content->next) ? '\005' : '\006';
120 ATTACHPTR **mutt_gen_attach_list (BODY * m,
124 short *idxmax, int level, int compose)
129 for (; m; m = m->next) {
130 if (*idxlen == *idxmax) {
131 p_realloc(&idx, (*idxmax) += 5);
132 for (i = *idxlen; i < *idxmax; i++)
136 if (m->type == TYPEMULTIPART && m->parts
138 || (parent_type == -1
139 && ascii_strcasecmp ("alternative", m->subtype)))
140 && (!(WithCrypto & APPLICATION_PGP)
141 || !mutt_is_multipart_encrypted (m))
144 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level,
149 idx[*idxlen] = p_new(ATTACHPTR, 1);
151 new = idx[(*idxlen)++];
154 new->parent_type = parent_type;
157 /* We don't support multipart messages in the compose menu yet */
158 if (!compose && !m->collapsed &&
159 ((m->type == TYPEMULTIPART && (!(WithCrypto & APPLICATION_PGP)
160 || !mutt_is_multipart_encrypted (m))
162 || mutt_is_message_type (m->type, m->subtype))) {
164 mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
171 mutt_update_tree (idx, *idxlen);
176 /* %c = character set: convert?
180 * %e = MIME content-transfer-encoding
182 * %I = content-disposition, either I (inline) or A (attachment)
185 * %m = major MIME type
187 * %n = attachment number
191 const char *mutt_attach_fmt (char *dest,
196 const char *ifstring,
197 const char *elsestring,
198 unsigned long data, format_flag flags)
201 char tmp[SHORT_STRING];
202 char charset[SHORT_STRING];
203 ATTACHPTR *aptr = (ATTACHPTR *) data;
204 int optional = (flags & M_FORMAT_OPTIONAL);
210 if (mutt_is_text_part (aptr->content) &&
211 mutt_get_body_charset (charset, sizeof (charset), aptr->content))
212 mutt_format_s (dest, destlen, prefix, charset);
214 mutt_format_s (dest, destlen, prefix, "");
216 else if (!mutt_is_text_part (aptr->content) ||
217 !mutt_get_body_charset (charset, sizeof (charset),
224 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
225 snprintf (dest, destlen, fmt, aptr->content->type != TYPETEXT ||
226 aptr->content->noconv ? 'n' : 'c');
228 else if (aptr->content->type != TYPETEXT || aptr->content->noconv)
233 if (aptr->content->description) {
234 mutt_format_s (dest, destlen, prefix, aptr->content->description);
237 if (mutt_is_message_type (aptr->content->type, aptr->content->subtype)
238 && MsgFmt && aptr->content->hdr) {
239 char s[SHORT_STRING];
241 _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
242 M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT |
243 M_FORMAT_ARROWCURSOR);
245 mutt_format_s (dest, destlen, prefix, s);
249 if (!aptr->content->filename) {
250 mutt_format_s (dest, destlen, prefix, "<no description>");
254 else if (aptr->content->description ||
255 (mutt_is_message_type
256 (aptr->content->type, aptr->content->subtype)
257 && MsgFmt && aptr->content->hdr))
259 /* FALLS THROUGH TO 'f' */
262 if (aptr->content->filename && *aptr->content->filename == '/') {
263 char path[_POSIX_PATH_MAX];
265 strfcpy (path, aptr->content->filename, sizeof (path));
266 mutt_pretty_mailbox (path);
267 mutt_format_s (dest, destlen, prefix, path);
270 mutt_format_s (dest, destlen, prefix,
271 NONULL (aptr->content->filename));
273 else if (!aptr->content->filename)
278 snprintf (dest, destlen, "%c", aptr->content->deleted ? 'D' : ' ');
279 else if (!aptr->content->deleted)
284 mutt_format_s (dest, destlen, prefix,
285 ENCODING (aptr->content->encoding));
289 snprintf (dest, destlen, "%c",
290 (aptr->content->disposition == DISPINLINE) ? 'I' : 'A');
295 mutt_format_s (dest, destlen, prefix, TYPE (aptr->content));
299 mutt_format_s (dest, destlen, prefix, aptr->content->subtype);
300 else if (!aptr->content->subtype)
305 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
306 snprintf (dest, destlen, fmt, aptr->num + 1);
311 optional = aptr->content->attach_qualifies;
313 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
314 mutt_format_s (dest, destlen, fmt, "Q");
318 if (flags & M_FORMAT_STAT_FILE) {
321 stat (aptr->content->filename, &st);
325 l = aptr->content->length;
328 mutt_pretty_size (tmp, sizeof (tmp), l);
329 mutt_format_s (dest, destlen, prefix, tmp);
337 snprintf (dest, destlen, "%c", aptr->content->tagged ? '*' : ' ');
338 else if (!aptr->content->tagged)
343 mutt_format_s_tree (dest, destlen, prefix, NONULL (aptr->tree));
344 else if (!aptr->tree)
349 snprintf (dest, destlen, "%c", aptr->content->unlink ? '-' : ' ');
350 else if (!aptr->content->unlink)
355 optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0;
357 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
358 snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
366 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
367 else if (flags & M_FORMAT_OPTIONAL)
368 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
372 static void attach_entry (char *b, size_t blen, MUTTMENU * menu, int num)
374 int w=(COLS-SW)>blen?blen:(COLS-SW);
375 mutt_FormatString (b, w, NONULL (AttachFormat), mutt_attach_fmt,
376 (unsigned long) (((ATTACHPTR **) menu->data)[num]),
377 M_FORMAT_ARROWCURSOR);
380 int mutt_tag_attach (MUTTMENU * menu, int n, int m)
382 BODY *cur = ((ATTACHPTR **) menu->data)[n]->content;
383 int ot = cur->tagged;
385 cur->tagged = (m >= 0 ? m : !cur->tagged);
386 return cur->tagged - ot;
389 int mutt_is_message_type (int type, const char *subtype)
391 if (type != TYPEMESSAGE)
394 subtype = NONULL (subtype);
395 return (ascii_strcasecmp (subtype, "rfc822") == 0
396 || ascii_strcasecmp (subtype, "news") == 0);
399 static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
403 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
404 char path[_POSIX_PATH_MAX] = "";
410 if (body->filename) {
411 if (directory && *directory)
412 mutt_concat_path(buf, sizeof(buf), *directory,
413 mutt_basename(body->filename));
415 strfcpy (buf, body->filename, sizeof (buf));
417 else if (body->hdr &&
418 body->encoding != ENCBASE64 &&
419 body->encoding != ENCQUOTEDPRINTABLE &&
420 mutt_is_message_type (body->type, body->subtype))
421 mutt_default_save (buf, sizeof (buf), body->hdr);
425 prompt = _("Save to file ('#' for last used folder): ");
428 mutt_get_field (prompt, buf, sizeof (buf),
429 M_FILE | M_CLEAR | M_LASTFOLDER);
430 if (((ret != 0) && (ret != 2)) || (!buf[0] && ret != 2))
434 char tmpbuf[_POSIX_PATH_MAX];
436 snprintf (tmpbuf, sizeof (tmpbuf), "%s%s", LastSaveFolder, buf);
437 strfcpy (buf, tmpbuf, sizeof (buf));
438 ret = mutt_get_field (_("Save to file: ")
439 , buf, sizeof (buf), M_FILE);
440 if ((ret != 0) || (!buf[0]))
444 mutt_extract_path (buf, path);
445 strfcpy (LastSaveFolder, path, sizeof (LastSaveFolder));
449 mutt_expand_path (buf, sizeof (buf));
453 body->encoding != ENCBASE64 &&
454 body->encoding != ENCQUOTEDPRINTABLE &&
455 mutt_is_message_type (body->type, body->subtype));
460 /* check to make sure that this file is really the one the user wants */
461 if ((rc = mutt_save_confirm (buf, &st)) == 1) {
462 prompt = _("Save to file: ");
467 strfcpy (tfile, buf, sizeof (tfile));
471 mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile),
472 &append, directory)) == -1)
475 prompt = _("Save to file: ");
480 mutt_message _("Saving...");
482 if (mutt_save_attachment
483 (fp, body, tfile, append,
484 (hdr || !is_message) ? hdr : body->hdr) == 0) {
485 mutt_message _("Attachment saved.");
490 prompt = _("Save to file: ");
497 void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
500 char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
501 char *directory = NULL;
503 int last = menu ? menu->current : -1;
508 for (; top; top = top->next) {
509 if (!tag || top->tagged) {
510 if (!option (OPTATTACHSPLIT)) {
514 strfcpy (buf, NONULL (top->filename), sizeof (buf));
515 if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
516 M_FILE | M_CLEAR) != 0 || !buf[0])
518 mutt_expand_path (buf, sizeof (buf));
519 if (mutt_check_overwrite (top->filename, buf, tfile,
520 sizeof (tfile), &append, NULL))
522 rc = mutt_save_attachment (fp, top, tfile, append, hdr);
523 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
524 fprintf (fpout, "%s", AttachSep);
529 rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
530 if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
531 fprintf (fpout, "%s", AttachSep);
537 if (tag && menu && top->aptr) {
538 menu->oldcurrent = menu->current;
539 menu->current = top->aptr->num;
540 menu_check_recenter (menu);
541 menu->redraw |= REDRAW_MOTION;
545 if (mutt_query_save_attachment (fp, top, hdr, &directory) == -1)
550 mutt_save_attachment_list (fp, 1, top->parts, hdr, menu);
555 p_delete(&directory);
558 menu->oldcurrent = menu->current;
559 menu->current = last;
560 menu_check_recenter (menu);
561 menu->redraw |= REDRAW_MOTION;
564 if (!option (OPTATTACHSPLIT) && (rc == 0))
565 mutt_message _("Attachment saved.");
569 mutt_query_pipe_attachment (char *command, FILE * fp, BODY * body, int filter)
571 char tfile[_POSIX_PATH_MAX];
572 char warning[STRING + _POSIX_PATH_MAX];
575 snprintf (warning, sizeof (warning),
576 _("WARNING! You are about to overwrite %s, continue?"),
578 if (mutt_yesorno (warning, M_NO) != M_YES) {
579 CLEARLINE (LINES - 1);
587 if (mutt_pipe_attachment (fp, body, command, tfile)) {
589 mutt_unlink (body->filename);
590 mutt_rename_file (tfile, body->filename);
591 mutt_update_encoding (body);
592 mutt_message _("Attachment filtered.");
596 if (filter && tfile[0])
601 static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
607 mutt_decode_attachment (b, state);
609 state_puts (AttachSep, state);
612 if ((ifp = fopen (b->filename, "r")) == NULL) {
613 mutt_perror ("fopen");
616 mutt_copy_stream (ifp, state->fpout);
619 state_puts (AttachSep, state);
624 pipe_attachment_list (char *command, FILE * fp, int tag, BODY * top,
625 int filter, STATE * state)
627 for (; top; top = top->next) {
628 if (!tag || top->tagged) {
629 if (!filter && !option (OPTATTACHSPLIT))
630 pipe_attachment (fp, top, state);
632 mutt_query_pipe_attachment (command, fp, top, filter);
635 pipe_attachment_list (command, fp, tag, top->parts, filter, state);
641 void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int filter)
644 char buf[SHORT_STRING];
648 filter = 0; /* sanity check: we can't filter in the recv case yet */
653 if (mutt_get_field ((filter ? _("Filter through: ") : _("Pipe to: ")),
654 buf, sizeof (buf), M_CMD) != 0 || !buf[0])
657 mutt_expand_path (buf, sizeof (buf));
659 if (!filter && !option (OPTATTACHSPLIT)) {
661 thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
662 pipe_attachment_list (buf, fp, tag, top, filter, &state);
663 fclose (state.fpout);
664 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
665 mutt_any_key_to_continue (NULL);
668 pipe_attachment_list (buf, fp, tag, top, filter, &state);
671 static int can_print (BODY * top, int tag)
675 for (; top; top = top->next) {
676 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
677 if (!tag || top->tagged) {
678 if (!rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
679 if (ascii_strcasecmp ("text/plain", top->subtype) &&
680 ascii_strcasecmp ("application/postscript", top->subtype)) {
681 if (!mutt_can_decode (top)) {
682 mutt_error (_("I dont know how to print %s attachments!"), type);
689 return (can_print (top->parts, tag));
696 static void print_attachment_list (FILE * fp, int tag, BODY * top,
702 for (; top; top = top->next) {
703 if (!tag || top->tagged) {
704 snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
705 if (!option (OPTATTACHSPLIT)
706 && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
707 if (!ascii_strcasecmp ("text/plain", top->subtype)
708 || !ascii_strcasecmp ("application/postscript", top->subtype))
709 pipe_attachment (fp, top, state);
710 else if (mutt_can_decode (top)) {
711 /* decode and print */
713 char newfile[_POSIX_PATH_MAX] = "";
716 mutt_mktemp (newfile);
717 if (mutt_decode_save_attachment (fp, top, newfile, M_PRINTING, 0) ==
719 if ((ifp = fopen (newfile, "r")) != NULL) {
720 mutt_copy_stream (ifp, state->fpout);
723 state_puts (AttachSep, state);
726 mutt_unlink (newfile);
730 mutt_print_attachment (fp, top);
733 print_attachment_list (fp, tag, top->parts, state);
739 void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
747 tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) !=
751 if (!option (OPTATTACHSPLIT)) {
752 if (!can_print (top, tag))
756 thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
757 print_attachment_list (fp, tag, top, &state);
758 fclose (state.fpout);
759 if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
760 mutt_any_key_to_continue (NULL);
763 print_attachment_list (fp, tag, top, &state);
767 mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
768 short *idxlen, short *idxmax, MUTTMENU * menu)
770 ATTACHPTR **idx = *idxp;
772 while (--(*idxlen) >= 0)
773 idx[(*idxlen)]->content = NULL;
776 idx = *idxp = mutt_gen_attach_list (cur, -1, idx, idxlen, idxmax, 0, 0);
781 if (menu->current >= menu->max)
782 menu->current = menu->max - 1;
783 menu_check_recenter (menu);
784 menu->redraw |= REDRAW_INDEX;
790 mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
791 BODY * cur, ATTACHPTR *** idxp, short *idxlen,
792 short *idxmax, int recv)
794 ATTACHPTR **idx = *idxp;
797 int old_optweed = option (OPTWEED);
799 set_option (OPTWEED);
804 case OP_DISPLAY_HEADERS:
805 toggle_option (OPTWEED);
809 op = mutt_view_attachment (fp, idx[menu->current]->content, M_REGULAR,
814 case OP_MAIN_NEXT_UNDELETED: /* hack */
815 if (menu->current < menu->max - 1) {
823 case OP_MAIN_PREV_UNDELETED: /* hack */
824 if (menu->current > 0) {
832 /* when we edit the content-type, we should redisplay the attachment
834 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
836 mutt_update_attach_index (cur, idxp, idxlen, idxmax, menu);
841 /* functions which are passed through from the pager */
842 case OP_CHECK_TRADITIONAL:
843 if (!(WithCrypto & APPLICATION_PGP)
844 || (hdr && hdr->security & PGP_TRADITIONAL_CHECKED)) {
849 case OP_ATTACH_COLLAPSE:
856 while (op != OP_NULL);
859 if (option (OPTWEED) != old_optweed)
860 toggle_option (OPTWEED);
865 static void attach_collapse (BODY * b, short collapse, short init,
870 for (; b; b = b->next) {
871 i = init || b->collapsed;
872 if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
873 && !ascii_strcasecmp (b->subtype, "digest"))
874 attach_collapse (b->parts, 1, 1, 0);
875 else if (b->type == TYPEMULTIPART
876 || mutt_is_message_type (b->type, b->subtype))
877 attach_collapse (b->parts, collapse, i, 0);
878 b->collapsed = collapse;
884 void mutt_attach_init (BODY * b)
886 for (; b; b = b->next) {
890 mutt_attach_init (b->parts);
894 static const char *Function_not_permitted =
895 N_("Function not permitted in attach-message mode.");
897 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
900 mutt_error _(Function_not_permitted); \
907 void mutt_view_attachments (HEADER * hdr)
910 int need_secured = 0;
912 char helpstr[SHORT_STRING];
917 ATTACHPTR **idx = NULL;
923 /* make sure we have parsed this message */
924 mutt_parse_mime_message (Context, hdr);
926 mutt_message_hook (Context, hdr, M_MESSAGEHOOK);
928 if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
932 if (WithCrypto && ((hdr->security & ENCRYPT) ||
933 (mutt_is_application_smime (hdr->content) &
937 if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase (hdr->security)) {
938 mx_close_message (&msg);
941 if ((WithCrypto & APPLICATION_SMIME)
942 && (hdr->security & APPLICATION_SMIME)) {
944 crypt_smime_getkeys (hdr->env);
946 if (mutt_is_application_smime (hdr->content)) {
947 secured = !crypt_smime_decrypt_mime (msg->fp, &fp,
951 if ((mutt_is_application_smime (cur) & SMIMEOPAQUE)) {
957 secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
959 mutt_free_body (&_cur);
966 if ((WithCrypto & APPLICATION_PGP) && (hdr->security & APPLICATION_PGP)) {
967 if (mutt_is_multipart_encrypted (hdr->content))
968 secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
973 if (need_secured && !secured) {
974 mx_close_message (&msg);
975 mutt_error _("Can't decrypt encrypted message!");
981 if (!WithCrypto || !need_secured) {
986 menu = mutt_new_menu ();
987 menu->menu = MENU_ATTACH;
988 menu->title = _("Attachments");
989 menu->make_entry = attach_entry;
990 menu->tag = mutt_tag_attach;
992 mutt_compile_help (helpstr, sizeof (helpstr), MENU_ATTACH, AttachHelp);
994 mutt_attach_init (cur);
995 attach_collapse (cur, 0, 1, 0);
996 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1000 op = mutt_menuLoop (menu);
1002 case OP_ATTACH_VIEW_MAILCAP:
1003 mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
1005 menu->redraw = REDRAW_FULL;
1008 case OP_ATTACH_VIEW_TEXT:
1009 mutt_view_attachment (fp, idx[menu->current]->content, M_AS_TEXT,
1011 menu->redraw = REDRAW_FULL;
1014 case OP_DISPLAY_HEADERS:
1015 case OP_VIEW_ATTACH:
1017 mutt_attach_display_loop (menu, op, fp, hdr, cur, &idx, &idxlen,
1019 menu->redraw = REDRAW_FULL;
1022 case OP_ATTACH_COLLAPSE:
1023 if (!idx[menu->current]->content->parts) {
1024 mutt_error _("There are no subparts to show!");
1028 if (!idx[menu->current]->content->collapsed)
1029 attach_collapse (idx[menu->current]->content, 1, 0, 1);
1031 attach_collapse (idx[menu->current]->content, 0, 1, 1);
1032 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1035 case OP_FORGET_PASSPHRASE:
1036 crypt_forget_passphrase ();
1039 case OP_EXTRACT_KEYS:
1040 if ((WithCrypto & APPLICATION_PGP)) {
1041 crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
1044 idx[menu->current]->
1046 menu->redraw = REDRAW_FULL;
1050 case OP_CHECK_TRADITIONAL:
1051 if ((WithCrypto & APPLICATION_PGP)
1052 && crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
1053 : idx[menu->current]->content,
1055 hdr->security = crypt_query (cur);
1056 menu->redraw = REDRAW_FULL;
1061 mutt_print_attachment_list (fp, menu->tagprefix,
1062 menu->tagprefix ? cur : idx[menu->current]->
1067 mutt_pipe_attachment_list (fp, menu->tagprefix,
1068 menu->tagprefix ? cur : idx[menu->current]->
1073 mutt_save_attachment_list (fp, menu->tagprefix,
1074 menu->tagprefix ? cur : idx[menu->current]->
1075 content, hdr, menu);
1077 if (!menu->tagprefix && option (OPTRESOLVE)
1078 && menu->current < menu->max - 1)
1081 menu->redraw = REDRAW_MOTION_RESYNCH | REDRAW_FULL;
1088 if (Context->magic == M_POP) {
1090 mutt_error _("Can't delete attachment from POP server.");
1097 if (Context->magic == M_NNTP) {
1099 mutt_error _("Can't delete attachment from newsserver.");
1105 if (WithCrypto && (hdr->security & (~PGP_TRADITIONAL_CHECKED))) {
1108 ("Deletion of attachments from encrypted messages is unsupported.");
1111 if (!menu->tagprefix) {
1112 if (idx[menu->current]->parent_type == TYPEMULTIPART) {
1113 idx[menu->current]->content->deleted = 1;
1114 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1116 menu->redraw = REDRAW_MOTION_RESYNCH;
1119 menu->redraw = REDRAW_CURRENT;
1123 _("Only deletion of multipart attachments is supported.");
1128 for (x = 0; x < menu->max; x++) {
1129 if (idx[x]->content->tagged) {
1130 if (idx[x]->parent_type == TYPEMULTIPART) {
1131 idx[x]->content->deleted = 1;
1132 menu->redraw = REDRAW_INDEX;
1136 _("Only deletion of multipart attachments is supported.");
1145 if (!menu->tagprefix) {
1146 idx[menu->current]->content->deleted = 0;
1147 if (option (OPTRESOLVE) && menu->current < menu->max - 1) {
1149 menu->redraw = REDRAW_MOTION_RESYNCH;
1152 menu->redraw = REDRAW_CURRENT;
1157 for (x = 0; x < menu->max; x++) {
1158 if (idx[x]->content->tagged) {
1159 idx[x]->content->deleted = 0;
1160 menu->redraw = REDRAW_INDEX;
1168 mutt_attach_resend (fp, hdr, idx, idxlen,
1169 menu->tagprefix ? NULL : idx[menu->current]->
1171 menu->redraw = REDRAW_FULL;
1174 case OP_BOUNCE_MESSAGE:
1176 mutt_attach_bounce (fp, hdr, idx, idxlen,
1177 menu->tagprefix ? NULL : idx[menu->current]->
1179 menu->redraw = REDRAW_FULL;
1182 case OP_FORWARD_MESSAGE:
1184 mutt_attach_forward (fp, hdr, idx, idxlen,
1185 menu->tagprefix ? NULL : idx[menu->current]->
1187 menu->redraw = REDRAW_FULL;
1191 case OP_FORWARD_TO_GROUP:
1193 mutt_attach_forward (fp, hdr, idx, idxlen,
1194 menu->tagprefix ? NULL : idx[menu->current]->
1196 menu->redraw = REDRAW_FULL;
1202 if (!idx[menu->current]->content->hdr->env->followup_to ||
1203 str_casecmp (idx[menu->current]->content->hdr->env->followup_to,
1205 || query_quadoption (OPT_FOLLOWUPTOPOSTER,
1206 _("Reply by mail as poster prefers?")) !=
1208 mutt_attach_reply (fp, hdr, idx, idxlen,
1209 menu->tagprefix ? NULL : idx[menu->current]->
1210 content, SENDNEWS | SENDREPLY);
1211 menu->redraw = REDRAW_FULL;
1217 case OP_GROUP_REPLY:
1223 (op == OP_GROUP_REPLY ? SENDGROUPREPLY : 0) |
1224 (op == OP_LIST_REPLY ? SENDLISTREPLY : 0);
1225 mutt_attach_reply (fp, hdr, idx, idxlen,
1226 menu->tagprefix ? NULL : idx[menu->current]->content,
1228 menu->redraw = REDRAW_FULL;
1232 mutt_edit_content_type (hdr, idx[menu->current]->content, fp);
1233 mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
1237 mx_close_message (&msg);
1238 hdr->attach_del = 0;
1239 while (idxmax-- > 0) {
1242 if (idx[idxmax]->content && idx[idxmax]->content->deleted)
1243 hdr->attach_del = 1;
1244 if (idx[idxmax]->content)
1245 idx[idxmax]->content->aptr = NULL;
1246 p_delete(&idx[idxmax]->tree);
1247 p_delete(&idx[idxmax]);
1249 if (hdr->attach_del)
1254 if (WithCrypto && need_secured && secured) {
1256 mutt_free_body (&cur);
1259 mutt_menuDestroy (&menu);