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