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