2 * Copyright notice from original mutt:
3 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4 * Copyright (C) 2004 g10 Code GmbH
6 * Parts were written/modified by:
7 * Nico Golde <nico@ngolde.de>
9 * This file is part of mutt-ng, see http://www.muttng.org/.
10 * It's licensed under the GNU General Public License,
11 * please see the file GPL in the top level source directory.
18 #include <lib-lib/mem.h>
19 #include <lib-lib/str.h>
20 #include <lib-lib/macros.h>
21 #include <lib-lib/file.h>
22 #include <lib-lib/mapping.h>
24 #include <lib-mime/mime.h>
26 #include <lib-ui/curses.h>
27 #include <lib-ui/enter.h>
28 #include <lib-ui/menu.h>
31 #include "mutt_idna.h"
34 #include "recvattach.h"
57 static const char *There_are_no_attachments = N_("There are no attachments.");
59 #define CHECK_COUNT if (idxlen == 0) { mutt_error _(There_are_no_attachments); break; }
86 HDR_ATTACH = (HDR_FCC + 5) /* where to start printing the attachments */
88 HDR_ATTACH = (HDR_FCC + 7)
92 #define HDR_XOFFSET 14
93 #define TITLE_FMT "%14s" /* Used for Prompts, which are ASCII */
94 #define SW (option(OPTMBOXPANE)?SidebarWidth:0)
95 #define W (COLS - HDR_XOFFSET - SW)
97 static const char *Prompts[] = {
109 , "", "", "Newsgroups: ", "Followup-To: ", "X-Comment-To: "
113 static struct mapping_t ComposeHelp[] = {
114 {N_("Send"), OP_COMPOSE_SEND_MESSAGE},
115 {N_("Abort"), OP_EXIT},
116 {"To", OP_COMPOSE_EDIT_TO},
117 {"CC", OP_COMPOSE_EDIT_CC},
118 {"Subj", OP_COMPOSE_EDIT_SUBJECT},
119 {N_("Attach file"), OP_COMPOSE_ATTACH_FILE},
120 {N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION},
121 {N_("Help"), OP_HELP},
126 static struct mapping_t ComposeNewsHelp[] = {
127 {N_("Send"), OP_COMPOSE_SEND_MESSAGE},
128 {N_("Abort"), OP_EXIT},
129 {"Newsgroups", OP_COMPOSE_EDIT_NEWSGROUPS},
130 {"Subj", OP_COMPOSE_EDIT_SUBJECT},
131 {N_("Attach file"), OP_COMPOSE_ATTACH_FILE},
132 {N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION},
133 {N_("Help"), OP_HELP},
139 static void snd_entry (char *b, ssize_t blen, MUTTMENU * menu, int num) {
140 int w=(COLS-SW)>blen?blen:COLS-SW;
141 mutt_FormatString (b, w, NONULL (AttachFormat), mutt_attach_fmt,
142 (unsigned long) (((ATTACHPTR **) menu->data)[num]),
143 M_FORMAT_STAT_FILE | M_FORMAT_ARROWCURSOR);
146 #include <lib-crypt/crypt.h>
148 static void redraw_crypt_lines (HEADER * msg)
153 mvaddstr (HDR_CRYPT, SW, " Security: ");
154 else if (msg->security & APPLICATION_SMIME)
155 mvaddstr (HDR_CRYPT, SW, " S/MIME: ");
156 else if (msg->security & APPLICATION_PGP)
157 mvaddstr (HDR_CRYPT, SW, " PGP: ");
159 if ((msg->security & (ENCRYPT | SIGN)) == (ENCRYPT | SIGN))
160 addstr (_("Sign, Encrypt"));
161 else if (msg->security & ENCRYPT)
162 addstr (_("Encrypt"));
163 else if (msg->security & SIGN)
168 if ((msg->security & APPLICATION_PGP)
169 && (msg->security & (ENCRYPT | SIGN))) {
170 if ((msg->security & INLINE))
171 addstr (_(" (inline)"));
173 addstr (_(" (PGP/MIME)"));
177 move (HDR_CRYPTINFO, SW);
179 if (msg->security & APPLICATION_PGP && msg->security & SIGN)
180 printw ("%s%s", _(" sign as: "),
181 PgpSignAs ? PgpSignAs : _("<default>"));
183 if (msg->security & APPLICATION_SMIME && msg->security & SIGN) {
184 printw ("%s%s", _(" sign as: "),
185 SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
188 if ((msg->security & APPLICATION_SMIME)
189 && (msg->security & ENCRYPT)
190 && SmimeCryptAlg && *SmimeCryptAlg) {
191 mvprintw (HDR_CRYPTINFO, SW + 40, "%s%s", _("Encrypt with: "),
192 NONULL (SmimeCryptAlg));
200 static void redraw_mix_line (LIST * chain)
205 mvaddstr (HDR_MIX, SW, " Mix: ");
208 addstr ("<no chain defined>");
213 for (c = 12; chain; chain = chain->next) {
215 if (t && t[0] == '0' && t[1] == '\0')
218 if (c + m_strlen(t) + 2 >= COLS - SW)
225 c += m_strlen(t) + 2;
228 #endif /* MIXMASTER */
230 static int check_attachments (ATTACHPTR ** idx, short idxlen)
234 char pretty[_POSIX_PATH_MAX], msg[_POSIX_PATH_MAX + SHORT_STRING];
236 for (i = 0; i < idxlen; i++) {
237 m_strcpy(pretty, sizeof(pretty), idx[i]->content->filename);
238 if (stat (idx[i]->content->filename, &st) != 0) {
239 mutt_pretty_mailbox (pretty);
240 mutt_error (_("%s [#%d] no longer exists!"), pretty, i + 1);
244 if (idx[i]->content->stamp < st.st_mtime) {
245 mutt_pretty_mailbox (pretty);
246 snprintf (msg, sizeof (msg), _("%s [#%d] modified. Update encoding?"),
249 if ((r = mutt_yesorno (msg, M_YES)) == M_YES)
250 mutt_update_encoding (idx[i]->content);
259 static void draw_envelope_addr (int line, address_t * addr)
264 rfc822_write_address (buf, sizeof (buf), addr, 1);
265 mvprintw (line, SW, TITLE_FMT, Prompts[line - 1]);
266 mutt_paddstr (W, buf);
269 static void draw_envelope (HEADER * msg, char *fcc)
271 draw_envelope_addr (HDR_FROM, msg->env->from);
273 if (!option (OPTNEWSSEND)) {
275 draw_envelope_addr (HDR_TO, msg->env->to);
276 draw_envelope_addr (HDR_CC, msg->env->cc);
277 draw_envelope_addr (HDR_BCC, msg->env->bcc);
281 mvprintw (HDR_TO, SW, TITLE_FMT, Prompts[HDR_NEWSGROUPS - 1]);
282 mutt_paddstr (W, NONULL (msg->env->newsgroups));
283 mvprintw (HDR_CC, SW, TITLE_FMT, Prompts[HDR_FOLLOWUPTO - 1]);
284 mutt_paddstr (W, NONULL (msg->env->followup_to));
285 if (option (OPTXCOMMENTTO)) {
286 mvprintw (HDR_BCC, 0, TITLE_FMT, Prompts[HDR_XCOMMENTTO - 1]);
287 mutt_paddstr (W, NONULL (msg->env->x_comment_to));
291 mvprintw (HDR_SUBJECT, SW, TITLE_FMT, Prompts[HDR_SUBJECT - 1]);
292 mutt_paddstr (W, NONULL (msg->env->subject));
293 draw_envelope_addr (HDR_REPLYTO, msg->env->reply_to);
294 mvprintw (HDR_FCC, SW, TITLE_FMT, Prompts[HDR_FCC - 1]);
295 mutt_paddstr (W, fcc);
297 redraw_crypt_lines (msg);
300 redraw_mix_line (msg->chain);
303 SETCOLOR (MT_COLOR_STATUS);
304 mvaddstr (HDR_ATTACH - 1, SW, _("-- Attachments"));
305 BKGDSET (MT_COLOR_STATUS);
308 BKGDSET (MT_COLOR_NORMAL);
309 SETCOLOR (MT_COLOR_NORMAL);
312 static int edit_address_list (int line, address_t ** addr)
314 char buf[HUGE_STRING] = ""; /* needs to be large for alias expansion */
317 mutt_addrlist_to_local (*addr);
318 rfc822_write_address (buf, sizeof (buf), *addr, 0);
319 if (mutt_get_field (Prompts[line - 1], buf, sizeof (buf), M_ALIAS) == 0) {
320 address_delete (addr);
321 *addr = mutt_parse_adrlist (*addr, buf);
322 *addr = mutt_expand_aliases (*addr);
325 if (option (OPTNEEDREDRAW)) {
326 unset_option (OPTNEEDREDRAW);
327 return (REDRAW_FULL);
330 if (mutt_addrlist_to_idna (*addr, &err) != 0) {
331 mutt_error (_("Warning: '%s' is a bad IDN."), err);
336 /* redraw the expanded list so the user can see the result */
338 rfc822_write_address (buf, sizeof (buf), *addr, 1);
339 move (line, HDR_XOFFSET + SW);
340 mutt_paddstr (W, buf);
345 static int delete_attachment (MUTTMENU * menu, short *idxlen, int x)
347 ATTACHPTR **idx = (ATTACHPTR **) menu->data;
350 menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
352 if (x == 0 && menu->max == 1) {
353 mutt_error _("You may not delete the only attachment.");
355 idx[x]->content->tagged = 0;
359 for (y = 0; y < *idxlen; y++) {
360 if (idx[y]->content->next == idx[x]->content) {
361 idx[y]->content->next = idx[x]->content->next;
366 idx[x]->content->next = NULL;
367 idx[x]->content->parts = NULL;
368 mutt_free_body (&(idx[x]->content));
369 p_delete(&idx[x]->tree);
371 for (; x < *idxlen - 1; x++)
373 menu->max = --(*idxlen);
378 static void update_idx (MUTTMENU * menu, ATTACHPTR ** idx, short idxlen)
380 idx[idxlen]->level = (idxlen > 0) ? idx[idxlen - 1]->level : 0;
382 idx[idxlen - 1]->content->next = idx[idxlen]->content;
383 idx[idxlen]->content->aptr = idx[idxlen];
384 menu->current = idxlen++;
385 mutt_update_tree (idx, idxlen);
392 * cum_attachs_size: Cumulative Attachments Size
394 * Returns the total number of bytes used by the attachments in the
395 * attachment list _after_ content-transfer-encodings have been
400 static unsigned long cum_attachs_size (MUTTMENU * menu)
404 ATTACHPTR **idx = menu->data;
408 for (i = 0, s = 0; i < menu->max; i++) {
412 b->content = mutt_get_content_info (b->filename, b);
414 if ((info = b->content)) {
415 switch (b->encoding) {
416 case ENCQUOTEDPRINTABLE:
417 s += 3 * (info->lobin + info->hibin) + info->ascii + info->crlf;
420 s += (4 * (info->lobin + info->hibin + info->ascii + info->crlf)) / 3;
423 s += info->lobin + info->hibin + info->ascii + info->crlf;
433 * compose_format_str()
435 * %a = total number of attachments
436 * %h = hostname [option]
437 * %l = approx. length of current message (in bytes)
440 * This function is similar to status_format_str(). Look at that function for
441 * help when modifying this function.
444 static const char *compose_format_str (char *buf, size_t buflen, char op,
445 const char *src, const char *prefix,
446 const char *ifstring,
447 const char *elsestring,
448 unsigned long data, format_flag flags)
450 char fmt[SHORT_STRING], tmp[SHORT_STRING];
451 int optional = (flags & M_FORMAT_OPTIONAL);
452 MUTTMENU *menu = (MUTTMENU *) data;
456 case 'a': /* total number of attachments */
457 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
458 snprintf (buf, buflen, fmt, menu->max);
461 case 'h': /* hostname */
462 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
463 snprintf (buf, buflen, fmt, NONULL (Hostname));
466 case 'l': /* approx length of current message in bytes */
467 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
468 mutt_pretty_size (tmp, sizeof (tmp), menu ? cum_attachs_size (menu) : 0);
469 snprintf (buf, buflen, fmt, tmp);
473 m_strcpy(buf, buflen, mutt_make_version (0));
481 snprintf (buf, buflen, "%%%s%c", prefix, op);
486 compose_status_line (buf, buflen, menu, ifstring);
487 else if (flags & M_FORMAT_OPTIONAL)
488 compose_status_line (buf, buflen, menu, elsestring);
493 static void compose_status_line (char *buf, ssize_t buflen, MUTTMENU * menu,
496 int w=(COLS-SW)>buflen?buflen:(COLS-SW);
497 mutt_FormatString (buf, w, p, compose_format_str,
498 (unsigned long) menu, 0);
504 * 1 message should be postponed
508 int mutt_compose_menu (HEADER * msg, /* structure for new message */
509 char *fcc, /* where to save a copy of the message */
510 size_t fcclen, HEADER * cur)
511 { /* current message */
512 char helpstr[SHORT_STRING];
513 char buf[LONG_STRING];
514 char fname[_POSIX_PATH_MAX];
516 ATTACHPTR **idx = NULL;
520 int r = -1; /* return value */
523 int fccSet = 0; /* has the user edited the Fcc: field ? */
524 CONTEXT *ctx = NULL, *this = NULL;
526 /* Sort, SortAux could be changed in mutt_index_menu() */
527 int oldSort, oldSortAux;
531 int news = 0; /* is it a news article ? */
533 if (option (OPTNEWSSEND))
537 mutt_attach_init (msg->content);
538 idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
540 menu = mutt_new_menu ();
541 menu->menu = MENU_COMPOSE;
542 menu->offset = HDR_ATTACH;
544 menu->make_entry = snd_entry;
545 menu->tag = mutt_tag_attach;
550 mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE,
555 mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE,
558 if (option (OPTMBOXPANE))
562 unset_option (OPTNEWS); /* for any case */
564 switch (op = mutt_menuLoop (menu)) {
566 draw_envelope (msg, fcc);
567 menu->offset = HDR_ATTACH;
568 menu->pagelen = LINES - HDR_ATTACH - 2;
570 case OP_COMPOSE_EDIT_FROM:
571 menu->redraw = edit_address_list (HDR_FROM, &msg->env->from);
572 mutt_message_hook (NULL, msg, M_SEND2HOOK);
574 case OP_COMPOSE_EDIT_TO:
578 menu->redraw = edit_address_list (HDR_TO, &msg->env->to);
579 mutt_message_hook (NULL, msg, M_SEND2HOOK);
584 case OP_COMPOSE_EDIT_BCC:
588 menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc);
589 mutt_message_hook (NULL, msg, M_SEND2HOOK);
594 case OP_COMPOSE_EDIT_CC:
598 menu->redraw = edit_address_list (HDR_CC, &msg->env->cc);
599 mutt_message_hook (NULL, msg, M_SEND2HOOK);
605 case OP_COMPOSE_EDIT_NEWSGROUPS:
607 if (msg->env->newsgroups)
608 m_strcpy(buf, sizeof(buf), msg->env->newsgroups);
611 if (mutt_get_field ("Newsgroups: ", buf, sizeof (buf), 0) == 0
613 p_delete(&msg->env->newsgroups);
615 msg->env->newsgroups = m_strdup(skipspaces(buf));
616 move (HDR_TO, HDR_XOFFSET);
618 if (msg->env->newsgroups)
619 printw ("%-*.*s", W, W, msg->env->newsgroups);
624 case OP_COMPOSE_EDIT_FOLLOWUP_TO:
627 if (msg->env->followup_to)
628 m_strcpy(buf, sizeof(buf), msg->env->followup_to);
629 if (mutt_get_field ("Followup-To: ", buf, sizeof (buf), 0) == 0
631 p_delete(&msg->env->followup_to);
633 msg->env->followup_to = m_strdup(skipspaces(buf));
634 move (HDR_CC, HDR_XOFFSET);
636 if (msg->env->followup_to)
637 printw ("%-*.*s", W, W, msg->env->followup_to);
642 case OP_COMPOSE_EDIT_X_COMMENT_TO:
643 if (news && option (OPTXCOMMENTTO)) {
645 if (msg->env->x_comment_to)
646 m_strcpy(buf, sizeof(buf), msg->env->x_comment_to);
647 if (mutt_get_field ("X-Comment-To: ", buf, sizeof (buf), 0) == 0
649 p_delete(&msg->env->x_comment_to);
650 msg->env->x_comment_to = m_strdup(buf);
651 move (HDR_BCC, HDR_XOFFSET);
653 if (msg->env->x_comment_to)
654 printw ("%-*.*s", W, W, msg->env->x_comment_to);
659 case OP_COMPOSE_EDIT_SUBJECT:
660 if (msg->env->subject)
661 m_strcpy(buf, sizeof(buf), msg->env->subject);
664 if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) == 0) {
665 m_strreplace(&msg->env->subject, buf);
666 move (HDR_SUBJECT, HDR_XOFFSET + SW);
668 if (msg->env->subject)
669 mutt_paddstr (W, msg->env->subject);
671 mutt_message_hook (NULL, msg, M_SEND2HOOK);
673 case OP_COMPOSE_EDIT_REPLY_TO:
674 menu->redraw = edit_address_list (HDR_REPLYTO, &msg->env->reply_to);
675 mutt_message_hook (NULL, msg, M_SEND2HOOK);
677 case OP_COMPOSE_EDIT_FCC:
678 m_strcpy(buf, sizeof(buf), fcc);
679 if (mutt_get_field ("Fcc: ", buf, sizeof (buf), M_FILE | M_CLEAR) == 0) {
680 m_strcpy(fcc, _POSIX_PATH_MAX, buf);
681 mutt_pretty_mailbox (fcc);
682 move (HDR_FCC, HDR_XOFFSET + SW);
683 mutt_paddstr (W, fcc);
686 MAYBE_REDRAW (menu->redraw);
687 mutt_message_hook (NULL, msg, M_SEND2HOOK);
689 case OP_COMPOSE_EDIT_MESSAGE:
690 if (Editor && !option (OPTEDITHDRS)) {
691 mutt_edit_file (Editor, msg->content->filename);
692 mutt_update_encoding (msg->content);
693 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
694 mutt_message_hook (NULL, msg, M_SEND2HOOK);
698 case OP_COMPOSE_EDIT_HEADERS:
699 if ((op == OP_COMPOSE_EDIT_HEADERS ||
700 (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS)))) {
701 const char *tag = NULL;
702 const char *err = NULL;
704 mutt_env_to_local (msg->env);
705 mutt_edit_headers (NONULL (Editor), msg->content->filename, msg,
707 if (mutt_env_to_idna (msg->env, &tag, &err)) {
708 mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err);
712 mutt_update_encoding (msg->content);
714 /* attachments may have been added */
715 if (idxlen && idx[idxlen - 1]->content->next) {
716 for (i = 0; i < idxlen; i++)
720 mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0,
726 menu->redraw = REDRAW_FULL;
727 mutt_message_hook (NULL, msg, M_SEND2HOOK);
732 case OP_COMPOSE_ATTACH_KEY:
733 if (idxlen == idxmax) {
734 p_realloc(&idx, idxmax += 5);
738 idx[idxlen] = p_new(ATTACHPTR, 1);
739 if ((idx[idxlen]->content =
740 crypt_pgp_make_key_attachment (NULL)) != NULL) {
741 update_idx (menu, idx, idxlen++);
742 menu->redraw |= REDRAW_INDEX;
745 p_delete(&idx[idxlen]);
747 menu->redraw |= REDRAW_STATUS;
749 if (option (OPTNEEDREDRAW)) {
750 menu->redraw = REDRAW_FULL;
751 unset_option (OPTNEEDREDRAW);
754 mutt_message_hook (NULL, msg, M_SEND2HOOK);
758 case OP_COMPOSE_ATTACH_FILE:
760 char *prompt, **files;
764 prompt = _("Attach file");
768 if (_mutt_enter_fname
769 (prompt, fname, sizeof (fname), &menu->redraw, 0, 1, &files,
770 &numfiles) == -1 || *fname == '\0')
773 if (idxlen + numfiles >= idxmax) {
774 p_realloc(&idx, idxmax += 5 + numfiles);
780 mutt_message _("Attaching selected files...");
782 for (i = 0; i < numfiles; i++) {
783 char *att = files[i];
785 idx[idxlen] = p_new(ATTACHPTR, 1);
786 idx[idxlen]->unowned = 1;
787 idx[idxlen]->content = mutt_make_file_attach (att);
788 if (idx[idxlen]->content != NULL)
789 update_idx (menu, idx, idxlen++);
792 mutt_error (_("Unable to attach %s!"), att);
793 p_delete(&idx[idxlen]);
801 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
803 mutt_message_hook (NULL, msg, M_SEND2HOOK);
806 case OP_COMPOSE_ATTACH_MESSAGE:
808 case OP_COMPOSE_ATTACH_NEWS_MESSAGE:
815 prompt = _("Open mailbox to attach message from");
818 unset_option (OPTNEWS);
819 if (op == OP_COMPOSE_ATTACH_NEWS_MESSAGE) {
820 if (!(CurrentNewsSrv = mutt_select_newsserver (NewsServer)))
823 prompt = _("Open newsgroup to attach message from");
824 set_option (OPTNEWS);
830 if ((op == OP_COMPOSE_ATTACH_MESSAGE) ^ (Context->magic == M_NNTP))
833 m_strcpy(fname, sizeof(fname), NONULL(Context->path));
834 mutt_pretty_mailbox (fname);
837 if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1)
842 if (option (OPTNEWS))
843 nntp_expand_path (fname, sizeof (fname),
844 &CurrentNewsSrv->conn->account);
847 mutt_expand_path (fname, sizeof (fname));
848 if (mx_get_magic (fname) != M_IMAP)
849 if (mx_get_magic (fname) != M_POP)
851 if (mx_get_magic (fname) != M_NNTP && !option (OPTNEWS))
853 /* check to make sure the file exists and is readable */
854 if (access (fname, R_OK) == -1) {
859 menu->redraw = REDRAW_FULL;
861 ctx = mx_open_mailbox (fname, M_READONLY, NULL);
867 if (!ctx->msgcount) {
868 mx_close_mailbox (ctx, NULL);
870 mutt_error _("No messages in that folder.");
875 this = Context; /* remember current folder and sort methods */
877 oldSortAux = SortAux;
880 set_option (OPTATTACHMSG);
881 mutt_message _("Tag the messages you want to attach!");
883 closed = mutt_index_menu ();
884 unset_option (OPTATTACHMSG);
887 /* go back to the folder we started from */
889 /* Restore old $sort and $sort_aux */
891 SortAux = oldSortAux;
892 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
896 if (idxlen + Context->tagged >= idxmax) {
897 p_realloc(&idx, idxmax += 5 + Context->tagged);
901 for (i = 0; i < Context->msgcount; i++) {
902 h = Context->hdrs[i];
904 idx[idxlen] = p_new(ATTACHPTR, 1);
905 idx[idxlen]->content = mutt_make_message_attach (Context, h, 1);
906 if (idx[idxlen]->content != NULL)
907 update_idx (menu, idx, idxlen++);
909 mutt_error _("Unable to attach!");
911 p_delete(&idx[idxlen]);
915 menu->redraw |= REDRAW_FULL;
917 if (closed == OP_QUIT)
918 mx_close_mailbox (Context, NULL);
920 mx_fastclose_mailbox (Context);
923 /* go back to the folder we started from */
925 /* Restore old $sort and $sort_aux */
927 SortAux = oldSortAux;
929 mutt_message_hook (NULL, msg, M_SEND2HOOK);
934 if (idx[menu->current]->unowned)
935 idx[menu->current]->content->unlink = 0;
936 if (delete_attachment (menu, &idxlen, menu->current) == -1)
938 mutt_update_tree (idx, idxlen);
940 if (menu->current > idxlen - 1)
941 menu->current = idxlen - 1;
946 if (menu->current == 0)
947 msg->content = idx[0]->content;
949 menu->redraw |= REDRAW_STATUS;
950 mutt_message_hook (NULL, msg, M_SEND2HOOK);
953 #define CURRENT idx[menu->current]->content
955 case OP_COMPOSE_TOGGLE_RECODE:
958 if (!mutt_is_text_part (CURRENT)) {
959 mutt_error (_("Recoding only affects text attachments."));
962 CURRENT->noconv = !CURRENT->noconv;
964 mutt_message (_("The current attachment won't be converted."));
966 mutt_message (_("The current attachment will be converted."));
967 menu->redraw = REDRAW_CURRENT;
968 mutt_message_hook (NULL, msg, M_SEND2HOOK);
973 case OP_COMPOSE_EDIT_DESCRIPTION:
975 m_strcpy(buf, sizeof(buf),
976 NONULL(idx[menu->current]->content->description));
977 /* header names should not be translated */
978 if (mutt_get_field ("Description: ", buf, sizeof (buf), 0) == 0) {
979 m_strreplace(&idx[menu->current]->content->description, buf);
980 menu->redraw = REDRAW_CURRENT;
982 mutt_message_hook (NULL, msg, M_SEND2HOOK);
985 case OP_COMPOSE_UPDATE_ENCODING:
987 if (menu->tagprefix) {
990 for (top = msg->content; top; top = top->next) {
992 mutt_update_encoding (top);
994 menu->redraw = REDRAW_FULL;
997 mutt_update_encoding (idx[menu->current]->content);
998 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
1000 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1003 case OP_COMPOSE_TOGGLE_DISPOSITION:
1004 /* toggle the content-disposition between inline/attachment */
1005 idx[menu->current]->content->disposition =
1006 (idx[menu->current]->content->disposition ==
1007 DISPINLINE) ? DISPATTACH : DISPINLINE;
1008 menu->redraw = REDRAW_CURRENT;
1014 mutt_edit_content_type (NULL, idx[menu->current]->content, NULL);
1016 /* this may have been a change to text/something */
1017 mutt_update_encoding (idx[menu->current]->content);
1019 menu->redraw = REDRAW_CURRENT;
1021 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1024 case OP_COMPOSE_EDIT_ENCODING:
1026 m_strcpy(buf, sizeof(buf),
1027 ENCODING(idx[menu->current]->content->encoding));
1028 if (mutt_get_field ("Content-Transfer-Encoding: ", buf,
1029 sizeof (buf), 0) == 0 && buf[0]) {
1030 if ((i = mutt_check_encoding (buf)) != ENCOTHER && i != ENCUUENCODED) {
1031 idx[menu->current]->content->encoding = i;
1032 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
1033 mutt_clear_error ();
1036 mutt_error _("Invalid encoding.");
1038 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1041 case OP_COMPOSE_SEND_MESSAGE:
1043 /* Note: We don't invoke send2-hook here, since we want to leave
1044 * users an opportunity to change settings from the ":" prompt.
1047 if (check_attachments (idx, idxlen) != 0) {
1048 menu->redraw = REDRAW_FULL;
1054 if (msg->chain && mix_check_message (msg) != 0)
1058 if (!fccSet && *fcc) {
1059 if ((i = query_quadoption (OPT_COPY,
1060 _("Save a copy of this message?"))) == -1)
1070 case OP_COMPOSE_EDIT_FILE:
1072 mutt_edit_file (NONULL (Editor), idx[menu->current]->content->filename);
1073 mutt_update_encoding (idx[menu->current]->content);
1074 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
1075 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1078 case OP_COMPOSE_TOGGLE_UNLINK:
1080 idx[menu->current]->content->unlink =
1081 !idx[menu->current]->content->unlink;
1084 /* OPTRESOLVE is otherwise ignored on this menu.
1088 if (option (OPTRESOLVE) && menu->current + 1 < menu->max)
1091 menu->redraw = REDRAW_INDEX;
1092 /* No send2hook since this doesn't change the message. */
1095 case OP_COMPOSE_GET_ATTACHMENT:
1097 if (menu->tagprefix) {
1100 for (top = msg->content; top; top = top->next) {
1102 mutt_get_tmp_attachment (top);
1104 menu->redraw = REDRAW_FULL;
1106 else if (mutt_get_tmp_attachment (idx[menu->current]->content) == 0)
1107 menu->redraw = REDRAW_CURRENT;
1109 /* No send2hook since this doesn't change the message. */
1112 case OP_COMPOSE_RENAME_FILE:
1114 m_strcpy(fname, sizeof(fname), idx[menu->current]->content->filename);
1115 mutt_pretty_mailbox (fname);
1116 if (mutt_get_field (_("Rename to: "), fname, sizeof (fname), M_FILE)
1118 if (stat (idx[menu->current]->content->filename, &st) == -1) {
1119 mutt_error (_("Can't stat %s: %s"), fname, strerror (errno));
1123 mutt_expand_path (fname, sizeof (fname));
1124 if (mutt_rename_file (idx[menu->current]->content->filename, fname))
1127 m_strreplace(&idx[menu->current]->content->filename, fname);
1128 menu->redraw = REDRAW_CURRENT;
1130 if (idx[menu->current]->content->stamp >= st.st_mtime)
1131 mutt_stamp_attachment (idx[menu->current]->content);
1134 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1137 case OP_COMPOSE_NEW_MIME:
1144 CLEARLINE (LINES - 1);
1146 if (mutt_get_field (_("New file: "), fname, sizeof (fname), M_FILE)
1149 mutt_expand_path (fname, sizeof (fname));
1151 /* Call to lookup_mime_type () ? maybe later */
1153 if (mutt_get_field ("Content-Type: ", type, sizeof (type), 0) != 0
1157 if (!(p = strchr (type, '/'))) {
1158 mutt_error _("Content-Type is of the form base/sub");
1163 if ((itype = mutt_check_mime_type (type)) == TYPEOTHER) {
1164 mutt_error (_("Unknown Content-Type %s"), type);
1167 if (idxlen == idxmax) {
1168 p_realloc(&idx, idxmax += 5);
1172 idx[idxlen] = p_new(ATTACHPTR, 1);
1173 /* Touch the file */
1174 if (!(fp = safe_fopen (fname, "w"))) {
1175 mutt_error (_("Can't create file %s"), fname);
1176 p_delete(&idx[idxlen]);
1181 if ((idx[idxlen]->content = mutt_make_file_attach (fname)) == NULL) {
1183 _("What we have here is a failure to make an attachment");
1186 update_idx (menu, idx, idxlen++);
1188 idx[menu->current]->content->type = itype;
1189 m_strreplace(&idx[menu->current]->content->subtype, p);
1190 idx[menu->current]->content->unlink = 1;
1191 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1193 if (mutt_compose_attachment (idx[menu->current]->content)) {
1194 mutt_update_encoding (idx[menu->current]->content);
1195 menu->redraw = REDRAW_FULL;
1198 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1201 case OP_COMPOSE_EDIT_MIME:
1203 if (mutt_edit_attachment (idx[menu->current]->content)) {
1204 mutt_update_encoding (idx[menu->current]->content);
1205 menu->redraw = REDRAW_FULL;
1207 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1210 case OP_VIEW_ATTACH:
1211 case OP_DISPLAY_HEADERS:
1213 mutt_attach_display_loop (menu, op, NULL, NULL, NULL, &idx, &idxlen,
1215 menu->redraw = REDRAW_FULL;
1216 /* no send2hook, since this doesn't modify the message */
1221 mutt_save_attachment_list (NULL, menu->tagprefix,
1222 menu->tagprefix ? msg->content : idx[menu->
1224 content, NULL, menu);
1225 MAYBE_REDRAW (menu->redraw);
1226 /* no send2hook, since this doesn't modify the message */
1231 mutt_print_attachment_list (NULL, menu->tagprefix,
1232 menu->tagprefix ? msg->content : idx[menu->
1235 /* no send2hook, since this doesn't modify the message */
1241 mutt_pipe_attachment_list (NULL, menu->tagprefix,
1242 menu->tagprefix ? msg->content : idx[menu->
1244 content, op == OP_FILTER);
1245 if (op == OP_FILTER) /* cte might have changed */
1246 menu->redraw = menu->tagprefix ? REDRAW_FULL : REDRAW_CURRENT;
1247 menu->redraw |= REDRAW_STATUS;
1248 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1253 query_quadoption (OPT_POSTPONE,
1254 _("Postpone this message?"))) == M_NO) {
1255 while (idxlen-- > 0) {
1256 /* avoid freeing other attachments */
1257 idx[idxlen]->content->next = NULL;
1258 idx[idxlen]->content->parts = NULL;
1259 if (idx[idxlen]->unowned)
1260 idx[idxlen]->content->unlink = 0;
1261 mutt_free_body (&idx[idxlen]->content);
1262 p_delete(&idx[idxlen]->tree);
1263 p_delete(&idx[idxlen]);
1275 /* fall through to postpone! */
1277 case OP_COMPOSE_POSTPONE_MESSAGE:
1279 if (check_attachments (idx, idxlen) != 0) {
1280 menu->redraw = REDRAW_FULL;
1288 case OP_COMPOSE_ISPELL:
1290 snprintf (buf, sizeof (buf), "%s -x %s", NONULL (Ispell),
1291 msg->content->filename);
1292 if (mutt_system (buf) == -1)
1293 mutt_error (_("Error running \"%s\"!"), buf);
1295 mutt_update_encoding (msg->content);
1296 menu->redraw |= REDRAW_STATUS;
1300 case OP_COMPOSE_WRITE_MESSAGE:
1304 m_strcpy(fname, sizeof(fname), NONULL(Context->path));
1305 mutt_pretty_mailbox (fname);
1308 msg->content = idx[0]->content;
1309 if (mutt_enter_fname
1310 (_("Write message to mailbox"), fname, sizeof (fname),
1311 &menu->redraw, 1) != -1 && fname[0]) {
1312 mutt_message (_("Writing message to %s ..."), fname);
1313 mutt_expand_path (fname, sizeof (fname));
1315 if (msg->content->next)
1316 msg->content = mutt_make_multipart (msg->content);
1318 if (mutt_write_fcc (NONULL (fname), msg, NULL, 1, NULL) < 0)
1319 msg->content = mutt_remove_multipart (msg->content);
1321 mutt_message _("Message written.");
1327 case OP_COMPOSE_PGP_MENU:
1328 if (msg->security & APPLICATION_SMIME) {
1329 if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "),
1331 mutt_clear_error ();
1336 msg->security = crypt_pgp_send_menu (msg, &menu->redraw);
1337 redraw_crypt_lines (msg);
1338 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1342 case OP_FORGET_PASSPHRASE:
1343 crypt_forget_passphrase ();
1347 case OP_COMPOSE_SMIME_MENU:
1348 if (msg->security & APPLICATION_PGP) {
1349 if (mutt_yesorno (_("PGP already selected. Clear & continue ? "),
1351 mutt_clear_error ();
1356 msg->security = crypt_smime_send_menu (msg, &menu->redraw);
1357 redraw_crypt_lines (msg);
1358 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1363 case OP_COMPOSE_MIX:
1365 mix_make_chain (&msg->chain, &menu->redraw);
1366 mutt_message_hook (NULL, msg, M_SEND2HOOK);
1372 /* Draw formated compose status line */
1373 if (menu->redraw & REDRAW_STATUS) {
1374 compose_status_line (buf, sizeof (buf), menu, NONULL (ComposeFormat));
1375 CLEARLINE (option (OPTSTATUSONTOP) ? 0 : LINES - 2);
1376 SETCOLOR (MT_COLOR_STATUS);
1377 move (option (OPTSTATUSONTOP) ? 0 : LINES - 2, SW);
1378 printw ("%-*.*s", COLS-SW, COLS-SW, buf);
1379 SETCOLOR (MT_COLOR_NORMAL);
1380 menu->redraw &= ~REDRAW_STATUS;
1384 mutt_menuDestroy (&menu);
1387 msg->content = idx[0]->content;
1388 for (i = 0; i < idxlen; i++) {
1389 idx[i]->content->aptr = NULL;
1394 msg->content = NULL;