begin to move ui code into the lib-ui
[apps/madmutt.git] / compose.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  * Copyright (C) 2004 g10 Code GmbH
5  *
6  * Parts were written/modified by:
7  * Nico Golde <nico@ngolde.de>
8  *
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.
12  */
13
14 #if HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
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>
23
24 #include <lib-mime/mime.h>
25
26 #include <lib-ui/curses.h>
27
28 #include "mutt.h"
29 #include "enter.h"
30 #include "mutt_idna.h"
31 #include "mutt_menu.h"
32 #include "rfc1524.h"
33 #include "attach.h"
34 #include "recvattach.h"
35 #include "sort.h"
36 #include "charset.h"
37 #include "mx.h"
38 #include "buffy.h"
39 #include "compose.h"
40
41 #ifdef MIXMASTER
42 #include "remailer.h"
43 #endif
44
45 #ifdef USE_NNTP
46 #include "nntp.h"
47 #endif
48
49
50 #include <errno.h>
51 #include <string.h>
52 #include <sys/stat.h>
53 #include <sys/wait.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56
57 static const char *There_are_no_attachments = N_("There are no attachments.");
58
59 #define CHECK_COUNT if (idxlen == 0) { mutt_error _(There_are_no_attachments); break; }
60
61
62
63 enum {
64   HDR_FROM = 1,
65   HDR_TO,
66   HDR_CC,
67   HDR_BCC,
68   HDR_SUBJECT,
69   HDR_REPLYTO,
70   HDR_FCC,
71
72 #ifdef MIXMASTER
73   HDR_MIX,
74 #endif
75
76   HDR_CRYPT,
77   HDR_CRYPTINFO,
78
79 #ifdef USE_NNTP
80   HDR_NEWSGROUPS,
81   HDR_FOLLOWUPTO,
82   HDR_XCOMMENTTO,
83 #endif
84
85 #ifndef USE_NNTP
86   HDR_ATTACH = (HDR_FCC + 5)    /* where to start printing the attachments */
87 #else
88   HDR_ATTACH = (HDR_FCC + 7)
89 #endif
90 };
91
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)
96
97 static const char *Prompts[] = {
98   "From: ",
99   "To: ",
100   "Cc: ",
101   "Bcc: ",
102   "Subject: ",
103   "Reply-To: ",
104   "Fcc: "
105 #ifdef USE_NNTP
106 #ifdef MIXMASTER
107     , ""
108 #endif
109     , "", "", "Newsgroups: ", "Followup-To: ", "X-Comment-To: "
110 #endif
111 };
112
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},
122   {NULL, OP_NULL}
123 };
124
125 #ifdef USE_NNTP
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},
134   {NULL, OP_NULL}
135 };
136 #endif
137
138
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);
144 }
145
146 #include <lib-crypt/crypt.h>
147
148 static void redraw_crypt_lines (HEADER * msg)
149 {
150   int off = 0;
151
152   if (!msg->security)
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: ");
158
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)
164     addstr (_("Sign"));
165   else
166     addstr (_("Clear"));
167
168   if ((msg->security & APPLICATION_PGP)
169       && (msg->security & (ENCRYPT | SIGN))) {
170     if ((msg->security & INLINE))
171       addstr (_(" (inline)"));
172     else
173       addstr (_(" (PGP/MIME)"));
174   }
175   clrtoeol ();
176
177   move (HDR_CRYPTINFO, SW);
178   clrtoeol ();
179   if (msg->security & APPLICATION_PGP && msg->security & SIGN)
180     printw ("%s%s", _("     sign as: "),
181             PgpSignAs ? PgpSignAs : _("<default>"));
182
183   if (msg->security & APPLICATION_SMIME && msg->security & SIGN) {
184     printw ("%s%s", _("     sign as: "),
185             SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
186   }
187
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));
193     off = 20;
194   }
195 }
196
197
198 #ifdef MIXMASTER
199
200 static void redraw_mix_line (LIST * chain)
201 {
202   int c;
203   const char *t;
204
205   mvaddstr (HDR_MIX, SW, "         Mix: ");
206
207   if (!chain) {
208     addstr ("<no chain defined>");
209     clrtoeol ();
210     return;
211   }
212
213   for (c = 12; chain; chain = chain->next) {
214     t = chain->data;
215     if (t && t[0] == '0' && t[1] == '\0')
216       t = "<random>";
217
218     if (c + m_strlen(t) + 2 >= COLS - SW)
219       break;
220
221     addstr (NONULL (t));
222     if (chain->next)
223       addstr (", ");
224
225     c += m_strlen(t) + 2;
226   }
227 }
228 #endif /* MIXMASTER */
229
230 static int check_attachments (ATTACHPTR ** idx, short idxlen)
231 {
232   int i, r;
233   struct stat st;
234   char pretty[_POSIX_PATH_MAX], msg[_POSIX_PATH_MAX + SHORT_STRING];
235
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);
241       return -1;
242     }
243
244     if (idx[i]->content->stamp < st.st_mtime) {
245       mutt_pretty_mailbox (pretty);
246       snprintf (msg, sizeof (msg), _("%s [#%d] modified. Update encoding?"),
247                 pretty, i + 1);
248
249       if ((r = mutt_yesorno (msg, M_YES)) == M_YES)
250         mutt_update_encoding (idx[i]->content);
251       else if (r == -1)
252         return -1;
253     }
254   }
255
256   return 0;
257 }
258
259 static void draw_envelope_addr (int line, address_t * addr)
260 {
261   char buf[STRING];
262
263   buf[0] = 0;
264   rfc822_write_address (buf, sizeof (buf), addr, 1);
265   mvprintw (line, SW, TITLE_FMT, Prompts[line - 1]);
266   mutt_paddstr (W, buf);
267 }
268
269 static void draw_envelope (HEADER * msg, char *fcc)
270 {
271   draw_envelope_addr (HDR_FROM, msg->env->from);
272 #ifdef USE_NNTP
273   if (!option (OPTNEWSSEND)) {
274 #endif
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);
278 #ifdef USE_NNTP
279   }
280   else {
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));
288     }
289   }
290 #endif
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);
296
297   redraw_crypt_lines (msg);
298
299 #ifdef MIXMASTER
300   redraw_mix_line (msg->chain);
301 #endif
302
303   SETCOLOR (MT_COLOR_STATUS);
304   mvaddstr (HDR_ATTACH - 1, SW, _("-- Attachments"));
305   BKGDSET (MT_COLOR_STATUS);
306   clrtoeol ();
307
308   BKGDSET (MT_COLOR_NORMAL);
309   SETCOLOR (MT_COLOR_NORMAL);
310 }
311
312 static int edit_address_list (int line, address_t ** addr)
313 {
314   char buf[HUGE_STRING] = "";   /* needs to be large for alias expansion */
315   char *err = NULL;
316
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);
323   }
324
325   if (option (OPTNEEDREDRAW)) {
326     unset_option (OPTNEEDREDRAW);
327     return (REDRAW_FULL);
328   }
329
330   if (mutt_addrlist_to_idna (*addr, &err) != 0) {
331     mutt_error (_("Warning: '%s' is a bad IDN."), err);
332     mutt_refresh ();
333     p_delete(&err);
334   }
335
336   /* redraw the expanded list so the user can see the result */
337   buf[0] = 0;
338   rfc822_write_address (buf, sizeof (buf), *addr, 1);
339   move (line, HDR_XOFFSET + SW);
340   mutt_paddstr (W, buf);
341
342   return 0;
343 }
344
345 static int delete_attachment (MUTTMENU * menu, short *idxlen, int x)
346 {
347   ATTACHPTR **idx = (ATTACHPTR **) menu->data;
348   int y;
349
350   menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
351
352   if (x == 0 && menu->max == 1) {
353     mutt_error _("You may not delete the only attachment.");
354
355     idx[x]->content->tagged = 0;
356     return (-1);
357   }
358
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;
362       break;
363     }
364   }
365
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);
370   p_delete(&idx[x]);
371   for (; x < *idxlen - 1; x++)
372     idx[x] = idx[x + 1];
373   menu->max = --(*idxlen);
374
375   return (0);
376 }
377
378 static void update_idx (MUTTMENU * menu, ATTACHPTR ** idx, short idxlen)
379 {
380   idx[idxlen]->level = (idxlen > 0) ? idx[idxlen - 1]->level : 0;
381   if (idxlen)
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);
386   menu->max = idxlen;
387   return;
388 }
389
390
391 /* 
392  * cum_attachs_size: Cumulative Attachments Size
393  *
394  * Returns the total number of bytes used by the attachments in the
395  * attachment list _after_ content-transfer-encodings have been
396  * applied.
397  * 
398  */
399
400 static unsigned long cum_attachs_size (MUTTMENU * menu)
401 {
402   size_t s;
403   unsigned short i;
404   ATTACHPTR **idx = menu->data;
405   CONTENT *info;
406   BODY *b;
407
408   for (i = 0, s = 0; i < menu->max; i++) {
409     b = idx[i]->content;
410
411     if (!b->content)
412       b->content = mutt_get_content_info (b->filename, b);
413
414     if ((info = b->content)) {
415       switch (b->encoding) {
416       case ENCQUOTEDPRINTABLE:
417         s += 3 * (info->lobin + info->hibin) + info->ascii + info->crlf;
418         break;
419       case ENCBASE64:
420         s += (4 * (info->lobin + info->hibin + info->ascii + info->crlf)) / 3;
421         break;
422       default:
423         s += info->lobin + info->hibin + info->ascii + info->crlf;
424         break;
425       }
426     }
427   }
428
429   return s;
430 }
431
432 /*
433  * compose_format_str()
434  *
435  * %a = total number of attachments 
436  * %h = hostname  [option]
437  * %l = approx. length of current message (in bytes) 
438  * %v = Mutt version 
439  *
440  * This function is similar to status_format_str().  Look at that function for
441  * help when modifying this function.
442  */
443
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)
449 {
450   char fmt[SHORT_STRING], tmp[SHORT_STRING];
451   int optional = (flags & M_FORMAT_OPTIONAL);
452   MUTTMENU *menu = (MUTTMENU *) data;
453
454   *buf = 0;
455   switch (op) {
456   case 'a':                    /* total number of attachments */
457     snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
458     snprintf (buf, buflen, fmt, menu->max);
459     break;
460
461   case 'h':                    /* hostname */
462     snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
463     snprintf (buf, buflen, fmt, NONULL (Hostname));
464     break;
465
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);
470     break;
471
472   case 'v':
473     m_strcpy(buf, buflen, mutt_make_version (0));
474     break;
475
476   case 0:
477     *buf = 0;
478     return (src);
479
480   default:
481     snprintf (buf, buflen, "%%%s%c", prefix, op);
482     break;
483   }
484
485   if (optional)
486     compose_status_line (buf, buflen, menu, ifstring);
487   else if (flags & M_FORMAT_OPTIONAL)
488     compose_status_line (buf, buflen, menu, elsestring);
489
490   return (src);
491 }
492
493 static void compose_status_line (char *buf, ssize_t buflen, MUTTMENU * menu,
494                                  const char *p)
495 {
496   int w=(COLS-SW)>buflen?buflen:(COLS-SW);
497   mutt_FormatString (buf, w, p, compose_format_str,
498                      (unsigned long) menu, 0);
499 }
500
501
502 /* return values:
503  *
504  * 1    message should be postponed
505  * 0    normal exit
506  * -1   abort message
507  */
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];
515   MUTTMENU *menu;
516   ATTACHPTR **idx = NULL;
517   short idxlen = 0;
518   short idxmax = 0;
519   int i, closed = 0;
520   int r = -1;                   /* return value */
521   int op = 0;
522   int loop = 1;
523   int fccSet = 0;               /* has the user edited the Fcc: field ? */
524   CONTEXT *ctx = NULL, *this = NULL;
525
526   /* Sort, SortAux could be changed in mutt_index_menu() */
527   int oldSort, oldSortAux;
528   struct stat st;
529
530 #ifdef USE_NNTP
531   int news = 0;                 /* is it a news article ? */
532
533   if (option (OPTNEWSSEND))
534     news++;
535 #endif
536
537   mutt_attach_init (msg->content);
538   idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
539
540   menu = mutt_new_menu ();
541   menu->menu = MENU_COMPOSE;
542   menu->offset = HDR_ATTACH;
543   menu->max = idxlen;
544   menu->make_entry = snd_entry;
545   menu->tag = mutt_tag_attach;
546   menu->data = idx;
547 #ifdef USE_NNTP
548   if (news)
549     menu->help =
550       mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE,
551                          ComposeNewsHelp);
552   else
553 #endif
554     menu->help =
555       mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE,
556                          ComposeHelp);
557
558   if (option (OPTMBOXPANE))
559     buffy_check (0);
560   while (loop) {
561 #ifdef USE_NNTP
562     unset_option (OPTNEWS);     /* for any case */
563 #endif
564     switch (op = mutt_menuLoop (menu)) {
565     case OP_REDRAW:
566       draw_envelope (msg, fcc);
567       menu->offset = HDR_ATTACH;
568       menu->pagelen = LINES - HDR_ATTACH - 2;
569       break;
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);
573       break;
574     case OP_COMPOSE_EDIT_TO:
575 #ifdef USE_NNTP
576       if (!news) {
577 #endif
578         menu->redraw = edit_address_list (HDR_TO, &msg->env->to);
579         mutt_message_hook (NULL, msg, M_SEND2HOOK);
580 #ifdef USE_NNTP
581       }
582 #endif
583       break;
584     case OP_COMPOSE_EDIT_BCC:
585 #ifdef USE_NNTP
586       if (!news) {
587 #endif
588         menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc);
589         mutt_message_hook (NULL, msg, M_SEND2HOOK);
590 #ifdef USE_NNTP
591       }
592 #endif
593       break;
594     case OP_COMPOSE_EDIT_CC:
595 #ifdef USE_NNTP
596       if (!news) {
597 #endif
598         menu->redraw = edit_address_list (HDR_CC, &msg->env->cc);
599         mutt_message_hook (NULL, msg, M_SEND2HOOK);
600 #ifdef USE_NNTP
601       }
602 #endif
603       break;
604 #ifdef USE_NNTP
605     case OP_COMPOSE_EDIT_NEWSGROUPS:
606       if (news) {
607         if (msg->env->newsgroups)
608           m_strcpy(buf, sizeof(buf), msg->env->newsgroups);
609         else
610           buf[0] = 0;
611         if (mutt_get_field ("Newsgroups: ", buf, sizeof (buf), 0) == 0
612             && buf[0]) {
613           p_delete(&msg->env->newsgroups);
614           m_strrtrim(buf);
615           msg->env->newsgroups = m_strdup(skipspaces(buf));
616           move (HDR_TO, HDR_XOFFSET);
617           clrtoeol ();
618           if (msg->env->newsgroups)
619             printw ("%-*.*s", W, W, msg->env->newsgroups);
620         }
621       }
622       break;
623
624     case OP_COMPOSE_EDIT_FOLLOWUP_TO:
625       if (news) {
626         buf[0] = 0;
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
630             && buf[0]) {
631           p_delete(&msg->env->followup_to);
632           m_strrtrim(buf);
633           msg->env->followup_to = m_strdup(skipspaces(buf));
634           move (HDR_CC, HDR_XOFFSET);
635           clrtoeol ();
636           if (msg->env->followup_to)
637             printw ("%-*.*s", W, W, msg->env->followup_to);
638         }
639       }
640       break;
641
642     case OP_COMPOSE_EDIT_X_COMMENT_TO:
643       if (news && option (OPTXCOMMENTTO)) {
644         buf[0] = 0;
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
648             && buf[0]) {
649           p_delete(&msg->env->x_comment_to);
650           msg->env->x_comment_to = m_strdup(buf);
651           move (HDR_BCC, HDR_XOFFSET);
652           clrtoeol ();
653           if (msg->env->x_comment_to)
654             printw ("%-*.*s", W, W, msg->env->x_comment_to);
655         }
656       }
657       break;
658 #endif
659     case OP_COMPOSE_EDIT_SUBJECT:
660       if (msg->env->subject)
661         m_strcpy(buf, sizeof(buf), msg->env->subject);
662       else
663         buf[0] = 0;
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);
667         clrtoeol ();
668         if (msg->env->subject)
669           mutt_paddstr (W, msg->env->subject);
670       }
671       mutt_message_hook (NULL, msg, M_SEND2HOOK);
672       break;
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);
676       break;
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);
684         fccSet = 1;
685       }
686       MAYBE_REDRAW (menu->redraw);
687       mutt_message_hook (NULL, msg, M_SEND2HOOK);
688       break;
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);
695         break;
696       }
697       /* fall through */
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;
703
704         mutt_env_to_local (msg->env);
705         mutt_edit_headers (NONULL (Editor), msg->content->filename, msg,
706                            fcc, fcclen);
707         if (mutt_env_to_idna (msg->env, &tag, &err)) {
708           mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err);
709           p_delete(&err);
710         }
711       }
712       mutt_update_encoding (msg->content);
713
714       /* attachments may have been added */
715       if (idxlen && idx[idxlen - 1]->content->next) {
716         for (i = 0; i < idxlen; i++)
717           p_delete(&idx[i]);
718         idxlen = 0;
719         idx =
720           mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0,
721                                 1);
722         menu->data = idx;
723         menu->max = idxlen;
724       }
725
726       menu->redraw = REDRAW_FULL;
727       mutt_message_hook (NULL, msg, M_SEND2HOOK);
728       break;
729
730
731
732     case OP_COMPOSE_ATTACH_KEY:
733       if (idxlen == idxmax) {
734         p_realloc(&idx, idxmax += 5);
735         menu->data = idx;
736       }
737
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;
743       }
744       else
745         p_delete(&idx[idxlen]);
746
747       menu->redraw |= REDRAW_STATUS;
748
749       if (option (OPTNEEDREDRAW)) {
750         menu->redraw = REDRAW_FULL;
751         unset_option (OPTNEEDREDRAW);
752       }
753
754       mutt_message_hook (NULL, msg, M_SEND2HOOK);
755       break;
756
757
758     case OP_COMPOSE_ATTACH_FILE:
759       {
760         char *prompt, **files;
761         int error, numfiles;
762
763         fname[0] = 0;
764         prompt = _("Attach file");
765         numfiles = 0;
766         files = NULL;
767
768         if (_mutt_enter_fname
769             (prompt, fname, sizeof (fname), &menu->redraw, 0, 1, &files,
770              &numfiles) == -1 || *fname == '\0')
771           break;
772
773         if (idxlen + numfiles >= idxmax) {
774           p_realloc(&idx, idxmax += 5 + numfiles);
775           menu->data = idx;
776         }
777
778         error = 0;
779         if (numfiles > 1)
780           mutt_message _("Attaching selected files...");
781
782         for (i = 0; i < numfiles; i++) {
783           char *att = files[i];
784
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++);
790           else {
791             error = 1;
792             mutt_error (_("Unable to attach %s!"), att);
793             p_delete(&idx[idxlen]);
794           }
795         }
796
797         p_delete(&files);
798         if (!error)
799           mutt_clear_error ();
800
801         menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
802       }
803       mutt_message_hook (NULL, msg, M_SEND2HOOK);
804       break;
805
806     case OP_COMPOSE_ATTACH_MESSAGE:
807 #ifdef USE_NNTP
808     case OP_COMPOSE_ATTACH_NEWS_MESSAGE:
809 #endif
810       {
811         char *prompt;
812         HEADER *h;
813
814         fname[0] = 0;
815         prompt = _("Open mailbox to attach message from");
816
817 #ifdef USE_NNTP
818         unset_option (OPTNEWS);
819         if (op == OP_COMPOSE_ATTACH_NEWS_MESSAGE) {
820           if (!(CurrentNewsSrv = mutt_select_newsserver (NewsServer)))
821             break;
822
823           prompt = _("Open newsgroup to attach message from");
824           set_option (OPTNEWS);
825         }
826 #endif
827
828         if (Context)
829 #ifdef USE_NNTP
830           if ((op == OP_COMPOSE_ATTACH_MESSAGE) ^ (Context->magic == M_NNTP))
831 #endif
832           {
833             m_strcpy(fname, sizeof(fname), NONULL(Context->path));
834             mutt_pretty_mailbox (fname);
835           }
836
837         if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1)
838             == -1 || !fname[0])
839           break;
840
841 #ifdef USE_NNTP
842         if (option (OPTNEWS))
843           nntp_expand_path (fname, sizeof (fname),
844                             &CurrentNewsSrv->conn->account);
845         else
846 #endif
847           mutt_expand_path (fname, sizeof (fname));
848         if (mx_get_magic (fname) != M_IMAP)
849           if (mx_get_magic (fname) != M_POP)
850 #ifdef USE_NNTP
851             if (mx_get_magic (fname) != M_NNTP && !option (OPTNEWS))
852 #endif
853               /* check to make sure the file exists and is readable */
854               if (access (fname, R_OK) == -1) {
855                 mutt_perror (fname);
856                 break;
857               }
858
859         menu->redraw = REDRAW_FULL;
860
861         ctx = mx_open_mailbox (fname, M_READONLY, NULL);
862         if (ctx == NULL) {
863           mutt_perror (fname);
864           break;
865         }
866
867         if (!ctx->msgcount) {
868           mx_close_mailbox (ctx, NULL);
869           p_delete(&ctx);
870           mutt_error _("No messages in that folder.");
871
872           break;
873         }
874
875         this = Context;         /* remember current folder and sort methods */
876         oldSort = Sort;
877         oldSortAux = SortAux;
878
879         Context = ctx;
880         set_option (OPTATTACHMSG);
881         mutt_message _("Tag the messages you want to attach!");
882
883         closed = mutt_index_menu ();
884         unset_option (OPTATTACHMSG);
885
886         if (!Context) {
887           /* go back to the folder we started from */
888           Context = this;
889           /* Restore old $sort and $sort_aux */
890           Sort = oldSort;
891           SortAux = oldSortAux;
892           menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
893           break;
894         }
895
896         if (idxlen + Context->tagged >= idxmax) {
897           p_realloc(&idx, idxmax += 5 + Context->tagged);
898           menu->data = idx;
899         }
900
901         for (i = 0; i < Context->msgcount; i++) {
902           h = Context->hdrs[i];
903           if (h->tagged) {
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++);
908             else {
909               mutt_error _("Unable to attach!");
910
911               p_delete(&idx[idxlen]);
912             }
913           }
914         }
915         menu->redraw |= REDRAW_FULL;
916
917         if (closed == OP_QUIT)
918           mx_close_mailbox (Context, NULL);
919         else
920           mx_fastclose_mailbox (Context);
921         p_delete(&Context);
922
923         /* go back to the folder we started from */
924         Context = this;
925         /* Restore old $sort and $sort_aux */
926         Sort = oldSort;
927         SortAux = oldSortAux;
928       }
929       mutt_message_hook (NULL, msg, M_SEND2HOOK);
930       break;
931
932     case OP_DELETE:
933       CHECK_COUNT;
934       if (idx[menu->current]->unowned)
935         idx[menu->current]->content->unlink = 0;
936       if (delete_attachment (menu, &idxlen, menu->current) == -1)
937         break;
938       mutt_update_tree (idx, idxlen);
939       if (idxlen) {
940         if (menu->current > idxlen - 1)
941           menu->current = idxlen - 1;
942       }
943       else
944         menu->current = 0;
945
946       if (menu->current == 0)
947         msg->content = idx[0]->content;
948
949       menu->redraw |= REDRAW_STATUS;
950       mutt_message_hook (NULL, msg, M_SEND2HOOK);
951       break;
952
953 #define CURRENT idx[menu->current]->content
954
955     case OP_COMPOSE_TOGGLE_RECODE:
956       {
957         CHECK_COUNT;
958         if (!mutt_is_text_part (CURRENT)) {
959           mutt_error (_("Recoding only affects text attachments."));
960           break;
961         }
962         CURRENT->noconv = !CURRENT->noconv;
963         if (CURRENT->noconv)
964           mutt_message (_("The current attachment won't be converted."));
965         else
966           mutt_message (_("The current attachment will be converted."));
967         menu->redraw = REDRAW_CURRENT;
968         mutt_message_hook (NULL, msg, M_SEND2HOOK);
969         break;
970       }
971 #undef CURRENT
972
973     case OP_COMPOSE_EDIT_DESCRIPTION:
974       CHECK_COUNT;
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;
981       }
982       mutt_message_hook (NULL, msg, M_SEND2HOOK);
983       break;
984
985     case OP_COMPOSE_UPDATE_ENCODING:
986       CHECK_COUNT;
987       if (menu->tagprefix) {
988         BODY *top;
989
990         for (top = msg->content; top; top = top->next) {
991           if (top->tagged)
992             mutt_update_encoding (top);
993         }
994         menu->redraw = REDRAW_FULL;
995       }
996       else {
997         mutt_update_encoding (idx[menu->current]->content);
998         menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
999       }
1000       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1001       break;
1002
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;
1009       break;
1010
1011     case OP_EDIT_TYPE:
1012       CHECK_COUNT;
1013       {
1014         mutt_edit_content_type (NULL, idx[menu->current]->content, NULL);
1015
1016         /* this may have been a change to text/something */
1017         mutt_update_encoding (idx[menu->current]->content);
1018
1019         menu->redraw = REDRAW_CURRENT;
1020       }
1021       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1022       break;
1023
1024     case OP_COMPOSE_EDIT_ENCODING:
1025       CHECK_COUNT;
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 ();
1034         }
1035         else
1036           mutt_error _("Invalid encoding.");
1037       }
1038       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1039       break;
1040
1041     case OP_COMPOSE_SEND_MESSAGE:
1042
1043       /* Note: We don't invoke send2-hook here, since we want to leave
1044        * users an opportunity to change settings from the ":" prompt.
1045        */
1046
1047       if (check_attachments (idx, idxlen) != 0) {
1048         menu->redraw = REDRAW_FULL;
1049         break;
1050       }
1051
1052
1053 #ifdef MIXMASTER
1054       if (msg->chain && mix_check_message (msg) != 0)
1055         break;
1056 #endif
1057
1058       if (!fccSet && *fcc) {
1059         if ((i = query_quadoption (OPT_COPY,
1060                                    _("Save a copy of this message?"))) == -1)
1061           break;
1062         else if (i == M_NO)
1063           *fcc = 0;
1064       }
1065
1066       loop = 0;
1067       r = 0;
1068       break;
1069
1070     case OP_COMPOSE_EDIT_FILE:
1071       CHECK_COUNT;
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);
1076       break;
1077
1078     case OP_COMPOSE_TOGGLE_UNLINK:
1079       CHECK_COUNT;
1080       idx[menu->current]->content->unlink =
1081         !idx[menu->current]->content->unlink;
1082
1083 #if 0
1084       /* OPTRESOLVE is otherwise ignored on this menu.
1085        * Where's the bug?
1086        */
1087
1088       if (option (OPTRESOLVE) && menu->current + 1 < menu->max)
1089         menu->current++;
1090 # endif
1091       menu->redraw = REDRAW_INDEX;
1092       /* No send2hook since this doesn't change the message. */
1093       break;
1094
1095     case OP_COMPOSE_GET_ATTACHMENT:
1096       CHECK_COUNT;
1097       if (menu->tagprefix) {
1098         BODY *top;
1099
1100         for (top = msg->content; top; top = top->next) {
1101           if (top->tagged)
1102             mutt_get_tmp_attachment (top);
1103         }
1104         menu->redraw = REDRAW_FULL;
1105       }
1106       else if (mutt_get_tmp_attachment (idx[menu->current]->content) == 0)
1107         menu->redraw = REDRAW_CURRENT;
1108
1109       /* No send2hook since this doesn't change the message. */
1110       break;
1111
1112     case OP_COMPOSE_RENAME_FILE:
1113       CHECK_COUNT;
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)
1117           == 0 && fname[0]) {
1118         if (stat (idx[menu->current]->content->filename, &st) == -1) {
1119           mutt_error (_("Can't stat %s: %s"), fname, strerror (errno));
1120           break;
1121         }
1122
1123         mutt_expand_path (fname, sizeof (fname));
1124         if (mutt_rename_file (idx[menu->current]->content->filename, fname))
1125           break;
1126
1127         m_strreplace(&idx[menu->current]->content->filename, fname);
1128         menu->redraw = REDRAW_CURRENT;
1129
1130         if (idx[menu->current]->content->stamp >= st.st_mtime)
1131           mutt_stamp_attachment (idx[menu->current]->content);
1132
1133       }
1134       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1135       break;
1136
1137     case OP_COMPOSE_NEW_MIME:
1138       {
1139         char type[STRING];
1140         char *p;
1141         int itype;
1142         FILE *fp;
1143
1144         CLEARLINE (LINES - 1);
1145         fname[0] = 0;
1146         if (mutt_get_field (_("New file: "), fname, sizeof (fname), M_FILE)
1147             != 0 || !fname[0])
1148           continue;
1149         mutt_expand_path (fname, sizeof (fname));
1150
1151         /* Call to lookup_mime_type () ?  maybe later */
1152         type[0] = 0;
1153         if (mutt_get_field ("Content-Type: ", type, sizeof (type), 0) != 0
1154             || !type[0])
1155           continue;
1156
1157         if (!(p = strchr (type, '/'))) {
1158           mutt_error _("Content-Type is of the form base/sub");
1159
1160           continue;
1161         }
1162         *p++ = 0;
1163         if ((itype = mutt_check_mime_type (type)) == TYPEOTHER) {
1164           mutt_error (_("Unknown Content-Type %s"), type);
1165           continue;
1166         }
1167         if (idxlen == idxmax) {
1168           p_realloc(&idx, idxmax += 5);
1169           menu->data = idx;
1170         }
1171
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]);
1177           continue;
1178         }
1179         fclose (fp);
1180
1181         if ((idx[idxlen]->content = mutt_make_file_attach (fname)) == NULL) {
1182           mutt_error
1183             _("What we have here is a failure to make an attachment");
1184           continue;
1185         }
1186         update_idx (menu, idx, idxlen++);
1187
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;
1192
1193         if (mutt_compose_attachment (idx[menu->current]->content)) {
1194           mutt_update_encoding (idx[menu->current]->content);
1195           menu->redraw = REDRAW_FULL;
1196         }
1197       }
1198       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1199       break;
1200
1201     case OP_COMPOSE_EDIT_MIME:
1202       CHECK_COUNT;
1203       if (mutt_edit_attachment (idx[menu->current]->content)) {
1204         mutt_update_encoding (idx[menu->current]->content);
1205         menu->redraw = REDRAW_FULL;
1206       }
1207       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1208       break;
1209
1210     case OP_VIEW_ATTACH:
1211     case OP_DISPLAY_HEADERS:
1212       CHECK_COUNT;
1213       mutt_attach_display_loop (menu, op, NULL, NULL, NULL, &idx, &idxlen,
1214                                 NULL, 0);
1215       menu->redraw = REDRAW_FULL;
1216       /* no send2hook, since this doesn't modify the message */
1217       break;
1218
1219     case OP_SAVE:
1220       CHECK_COUNT;
1221       mutt_save_attachment_list (NULL, menu->tagprefix,
1222                                  menu->tagprefix ? msg->content : idx[menu->
1223                                                                       current]->
1224                                  content, NULL, menu);
1225       MAYBE_REDRAW (menu->redraw);
1226       /* no send2hook, since this doesn't modify the message */
1227       break;
1228
1229     case OP_PRINT:
1230       CHECK_COUNT;
1231       mutt_print_attachment_list (NULL, menu->tagprefix,
1232                                   menu->tagprefix ? msg->content : idx[menu->
1233                                                                        current]->
1234                                   content);
1235       /* no send2hook, since this doesn't modify the message */
1236       break;
1237
1238     case OP_PIPE:
1239     case OP_FILTER:
1240       CHECK_COUNT;
1241       mutt_pipe_attachment_list (NULL, menu->tagprefix,
1242                                  menu->tagprefix ? msg->content : idx[menu->
1243                                                                       current]->
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);
1249       break;
1250
1251     case OP_EXIT:
1252       if ((i =
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]);
1264         }
1265         p_delete(&idx);
1266         idxlen = 0;
1267         idxmax = 0;
1268         r = -1;
1269         loop = 0;
1270         break;
1271       }
1272       else if (i == -1)
1273         break;                  /* abort */
1274
1275       /* fall through to postpone! */
1276
1277     case OP_COMPOSE_POSTPONE_MESSAGE:
1278
1279       if (check_attachments (idx, idxlen) != 0) {
1280         menu->redraw = REDRAW_FULL;
1281         break;
1282       }
1283
1284       loop = 0;
1285       r = 1;
1286       break;
1287
1288     case OP_COMPOSE_ISPELL:
1289       endwin ();
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);
1294       else {
1295         mutt_update_encoding (msg->content);
1296         menu->redraw |= REDRAW_STATUS;
1297       }
1298       break;
1299
1300     case OP_COMPOSE_WRITE_MESSAGE:
1301
1302       fname[0] = '\0';
1303       if (Context) {
1304         m_strcpy(fname, sizeof(fname), NONULL(Context->path));
1305         mutt_pretty_mailbox (fname);
1306       }
1307       if (idxlen)
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));
1314
1315         if (msg->content->next)
1316           msg->content = mutt_make_multipart (msg->content);
1317
1318         if (mutt_write_fcc (NONULL (fname), msg, NULL, 1, NULL) < 0)
1319           msg->content = mutt_remove_multipart (msg->content);
1320         else
1321           mutt_message _("Message written.");
1322       }
1323       break;
1324
1325
1326
1327     case OP_COMPOSE_PGP_MENU:
1328       if (msg->security & APPLICATION_SMIME) {
1329         if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "),
1330                           M_YES) != M_YES) {
1331           mutt_clear_error ();
1332           break;
1333         }
1334         msg->security = 0;
1335       }
1336       msg->security = crypt_pgp_send_menu (msg, &menu->redraw);
1337       redraw_crypt_lines (msg);
1338       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1339       break;
1340
1341
1342     case OP_FORGET_PASSPHRASE:
1343       crypt_forget_passphrase ();
1344       break;
1345
1346
1347     case OP_COMPOSE_SMIME_MENU:
1348       if (msg->security & APPLICATION_PGP) {
1349         if (mutt_yesorno (_("PGP already selected. Clear & continue ? "),
1350                           M_YES) != M_YES) {
1351           mutt_clear_error ();
1352           break;
1353         }
1354         msg->security = 0;
1355       }
1356       msg->security = crypt_smime_send_menu (msg, &menu->redraw);
1357       redraw_crypt_lines (msg);
1358       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1359       break;
1360
1361
1362 #ifdef MIXMASTER
1363     case OP_COMPOSE_MIX:
1364
1365       mix_make_chain (&msg->chain, &menu->redraw);
1366       mutt_message_hook (NULL, msg, M_SEND2HOOK);
1367       break;
1368 #endif
1369
1370     }
1371
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;
1381     }
1382   }
1383
1384   mutt_menuDestroy (&menu);
1385
1386   if (idxlen) {
1387     msg->content = idx[0]->content;
1388     for (i = 0; i < idxlen; i++) {
1389       idx[i]->content->aptr = NULL;
1390       p_delete(&idx[i]);
1391     }
1392   }
1393   else
1394     msg->content = NULL;
1395
1396   p_delete(&idx);
1397
1398   return (r);
1399 }