]> git.llucax.com Git - software/mutt-debian.git/blob - curs_main.c
new patch from upstream to fix the atime issue
[software/mutt-debian.git] / curs_main.c
1 /*
2  * Copyright (C) 1996-2000,2002 Michael R. Elkins <me@mutt.org>
3  *
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  *
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  *
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18
19 #if HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include "mutt.h"
24 #include "mutt_curses.h"
25 #include "mutt_menu.h"
26 #include "mailbox.h"
27 #include "mapping.h"
28 #include "sort.h"
29 #include "mx.h"
30
31 #ifdef USE_POP
32 #include "pop.h"
33 #endif
34
35 #ifdef USE_IMAP
36 #include "imap_private.h"
37 #endif
38
39 #include "mutt_crypt.h"
40
41
42 #include <ctype.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <sys/wait.h>
46 #include <string.h>
47 #include <sys/stat.h>
48 #include <errno.h>
49
50 #include <assert.h>
51
52 static const char *No_mailbox_is_open = N_("No mailbox is open.");
53 static const char *There_are_no_messages = N_("There are no messages.");
54 static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
55 static const char *Function_not_permitted_in_attach_message_mode = N_("Function not permitted in attach-message mode.");
56 static const char *No_visible = N_("No visible messages.");
57
58 #define CHECK_IN_MAILBOX if (!Context) \
59         { \
60                 mutt_flushinp (); \
61                 mutt_error _(No_mailbox_is_open); \
62                 break; \
63         }
64
65 #define CHECK_MSGCOUNT if (!Context) \
66         { \
67                 mutt_flushinp (); \
68                 mutt_error _(No_mailbox_is_open); \
69                 break; \
70         } \
71         else if (!Context->msgcount) \
72         { \
73                 mutt_flushinp (); \
74                 mutt_error _(There_are_no_messages); \
75                 break; \
76         }
77
78 #define CHECK_VISIBLE if (Context && menu->current >= Context->vcount) \
79         {\
80                 mutt_flushinp (); \
81                 mutt_error _(No_visible); \
82                 break; \
83         }
84
85
86 #define CHECK_READONLY if (Context->readonly) \
87                         { \
88                                 mutt_flushinp (); \
89                                 mutt_error _(Mailbox_is_read_only); \
90                                 break; \
91                         }
92
93 #define CHECK_ACL(aclbit,action) \
94                 if (!mutt_bit_isset(Context->rights,aclbit)) { \
95                         mutt_flushinp(); \
96                         mutt_error (_("Cannot %s: Operation not permitted by ACL"), action); \
97                         break; \
98                 }
99
100 #define CHECK_ATTACH if(option(OPTATTACHMSG)) \
101                      {\
102                         mutt_flushinp (); \
103                         mutt_error _(Function_not_permitted_in_attach_message_mode); \
104                         break; \
105                      }
106
107 #define CURHDR Context->hdrs[Context->v2r[menu->current]]
108 #define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]]
109 #define UNREAD(h) mutt_thread_contains_unread (Context, h)
110
111 extern size_t UngetCount;
112
113 void index_make_entry (char *s, size_t l, MUTTMENU *menu, int num)
114 {
115   format_flag flag = M_FORMAT_MAKEPRINT | M_FORMAT_ARROWCURSOR | M_FORMAT_INDEX;
116   int edgemsgno, reverse = Sort & SORT_REVERSE;
117   HEADER *h = Context->hdrs[Context->v2r[num]];
118   THREAD *tmp;
119
120   if ((Sort & SORT_MASK) == SORT_THREADS && h->tree)
121   {
122     flag |= M_FORMAT_TREE; /* display the thread tree */
123     if (h->display_subject)
124       flag |= M_FORMAT_FORCESUBJ;
125     else
126     {
127       if (reverse)
128       {
129         if (menu->top + menu->pagelen > menu->max)
130           edgemsgno = Context->v2r[menu->max - 1];
131         else
132           edgemsgno = Context->v2r[menu->top + menu->pagelen - 1];
133       }
134       else
135         edgemsgno = Context->v2r[menu->top];
136
137       for (tmp = h->thread->parent; tmp; tmp = tmp->parent)
138       {
139         if (!tmp->message)
140           continue;
141
142         /* if no ancestor is visible on current screen, provisionally force
143          * subject... */
144         if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno < edgemsgno)
145         {
146           flag |= M_FORMAT_FORCESUBJ;
147           break;
148         }
149         else if (tmp->message->virtual >= 0)
150           break;
151       }
152       if (flag & M_FORMAT_FORCESUBJ)
153       {
154         for (tmp = h->thread->prev; tmp; tmp = tmp->prev)
155         {
156           if (!tmp->message)
157             continue;
158
159           /* ...but if a previous sibling is available, don't force it */
160           if (reverse ? tmp->message->msgno > edgemsgno : tmp->message->msgno < edgemsgno)
161             break;
162           else if (tmp->message->virtual >= 0)
163           {
164             flag &= ~M_FORMAT_FORCESUBJ;
165             break;
166           }
167         }
168       }
169     }
170   }
171
172   _mutt_make_string (s, l, NONULL (HdrFmt), Context, h, flag);
173 }
174
175 int index_color (int index_no)
176 {
177   HEADER *h = Context->hdrs[Context->v2r[index_no]];
178
179   if (h && h->pair)
180     return h->pair;
181
182   mutt_set_header_color (Context, h);
183   return h->pair;
184 }
185
186 static int ci_next_undeleted (int msgno)
187 {
188   int i;
189
190   for (i=msgno+1; i < Context->vcount; i++)
191     if (! Context->hdrs[Context->v2r[i]]->deleted)
192       return (i);
193   return (-1);
194 }
195
196 static int ci_previous_undeleted (int msgno)
197 {
198   int i;
199
200   for (i=msgno-1; i>=0; i--)
201     if (! Context->hdrs[Context->v2r[i]]->deleted)
202       return (i);
203   return (-1);
204 }
205
206 /* Return the index of the first new message, or failing that, the first
207  * unread message.
208  */
209 static int ci_first_message (void)
210 {
211   int old = -1, i;
212
213   if (Context && Context->msgcount)
214   {
215     for (i=0; i < Context->vcount; i++)
216     {
217       if (! Context->hdrs[Context->v2r[i]]->read &&
218           ! Context->hdrs[Context->v2r[i]]->deleted)
219       {
220         if (! Context->hdrs[Context->v2r[i]]->old)
221           return (i);
222         else if (old == -1)
223           old = i;
224       }
225     }
226     if (old != -1)
227       return (old);
228
229     /* If Sort is reverse and not threaded, the latest message is first.
230      * If Sort is threaded, the latest message is first iff exactly one
231      * of Sort and SortAux are reverse.
232      */
233     if (((Sort & SORT_REVERSE) && (Sort & SORT_MASK) != SORT_THREADS) ||
234         ((Sort & SORT_MASK) == SORT_THREADS &&
235          ((Sort ^ SortAux) & SORT_REVERSE)))
236       return 0;
237     else
238       return (Context->vcount ? Context->vcount - 1 : 0);
239   }
240   return 0;
241 }
242
243 /* This should be in mx.c, but it only gets used here. */
244 static int mx_toggle_write (CONTEXT *ctx)
245 {
246   if (!ctx)
247     return -1;
248
249   if (ctx->readonly)
250   {
251     mutt_error _("Cannot toggle write on a readonly mailbox!");
252     return -1;
253   }
254
255   if (ctx->dontwrite)
256   {
257     ctx->dontwrite = 0;
258     mutt_message _("Changes to folder will be written on folder exit.");
259   }
260   else
261   {
262     ctx->dontwrite = 1;
263     mutt_message _("Changes to folder will not be written.");
264   }
265
266   return 0;
267 }
268
269 static void update_index (MUTTMENU *menu, CONTEXT *ctx, int check,
270                           int oldcount, int index_hint)
271 {
272   /* store pointers to the newly added messages */
273   HEADER  **save_new = NULL;
274   int j;
275
276   /* take note of the current message */
277   if (oldcount)
278   {
279     if (menu->current < ctx->vcount)
280       menu->oldcurrent = index_hint;
281     else
282       oldcount = 0; /* invalid message number! */
283   }
284
285   /* We are in a limited view. Check if the new message(s) satisfy
286    * the limit criteria. If they do, set their virtual msgno so that
287    * they will be visible in the limited view */
288   if (ctx->pattern)
289   {
290 #define THIS_BODY ctx->hdrs[j]->content
291     for (j = (check == M_REOPENED) ? 0 : oldcount; j < ctx->msgcount; j++)
292     {
293       if (!j)
294         ctx->vcount = 0;
295
296       if (mutt_pattern_exec (ctx->limit_pattern,
297                              M_MATCH_FULL_ADDRESS,
298                              ctx, ctx->hdrs[j]))
299       {
300         assert (ctx->vcount < ctx->msgcount);
301         ctx->hdrs[j]->virtual = ctx->vcount;
302         ctx->v2r[ctx->vcount] = j;
303         ctx->hdrs[j]->limited = 1;
304         ctx->vcount++;
305         ctx->vsize += THIS_BODY->length + THIS_BODY->offset - THIS_BODY->hdr_offset;
306       }
307     }
308 #undef THIS_BODY
309   }
310
311   /* save the list of new messages */
312   if (oldcount && check != M_REOPENED
313       && ((Sort & SORT_MASK) == SORT_THREADS))
314   {
315     save_new = (HEADER **) safe_malloc (sizeof (HEADER *) * (ctx->msgcount - oldcount));
316     for (j = oldcount; j < ctx->msgcount; j++)
317       save_new[j-oldcount] = ctx->hdrs[j];
318   }
319
320   /* if the mailbox was reopened, need to rethread from scratch */
321   mutt_sort_headers (ctx, (check == M_REOPENED));
322
323   /* uncollapse threads with new mail */
324   if ((Sort & SORT_MASK) == SORT_THREADS)
325   {
326     if (check == M_REOPENED)
327     {
328       THREAD *h, *j;
329
330       ctx->collapsed = 0;
331
332       for (h = ctx->tree; h; h = h->next)
333       {
334         for (j = h; !j->message; j = j->child)
335           ;
336         mutt_uncollapse_thread (ctx, j->message);
337       }
338       mutt_set_virtual (ctx);
339     }
340     else if (oldcount)
341     {
342       for (j = 0; j < ctx->msgcount - oldcount; j++)
343       {
344         int k;
345
346         for (k = 0; k < ctx->msgcount; k++)
347         {
348           HEADER *h = ctx->hdrs[k];
349           if (h == save_new[j] && (!ctx->pattern || h->limited))
350             mutt_uncollapse_thread (ctx, h);
351         }
352       }
353       FREE (&save_new);
354       mutt_set_virtual (ctx);
355     }
356   }
357
358   menu->current = -1;
359   if (oldcount)
360   {
361     /* restore the current message to the message it was pointing to */
362     for (j = 0; j < ctx->vcount; j++)
363     {
364       if (ctx->hdrs[ctx->v2r[j]]->index == menu->oldcurrent)
365       {
366         menu->current = j;
367         break;
368       }
369     }
370   }
371
372   if (menu->current < 0)
373     menu->current = ci_first_message ();
374
375 }
376
377 static void resort_index (MUTTMENU *menu)
378 {
379   int i;
380   HEADER *current = CURHDR;
381
382   menu->current = -1;
383   mutt_sort_headers (Context, 0);
384   /* Restore the current message */
385
386   for (i = 0; i < Context->vcount; i++)
387   {
388     if (Context->hdrs[Context->v2r[i]] == current)
389     {
390       menu->current = i;
391       break;
392     }
393   }
394
395   if ((Sort & SORT_MASK) == SORT_THREADS && menu->current < 0)
396     menu->current = mutt_parent_message (Context, current);
397
398   if (menu->current < 0)
399     menu->current = ci_first_message ();
400
401   menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
402 }
403
404 static struct mapping_t IndexHelp[] = {
405   { N_("Quit"),  OP_QUIT },
406   { N_("Del"),   OP_DELETE },
407   { N_("Undel"), OP_UNDELETE },
408   { N_("Save"),  OP_SAVE },
409   { N_("Mail"),  OP_MAIL },
410   { N_("Reply"), OP_REPLY },
411   { N_("Group"), OP_GROUP_REPLY },
412   { N_("Help"),  OP_HELP },
413   { NULL,        0 }
414 };
415
416 /* This function handles the message index window as well as commands returned
417  * from the pager (MENU_PAGER).
418  */
419 int mutt_index_menu (void)
420 {
421   char buf[LONG_STRING], helpstr[LONG_STRING];
422   int op = OP_NULL;
423   int done = 0;                /* controls when to exit the "event" loop */
424   int i = 0, j;
425   int tag = 0;                 /* has the tag-prefix command been pressed? */
426   int newcount = -1;
427   int oldcount = -1;
428   int rc = -1;
429   MUTTMENU *menu;
430   char *cp;                    /* temporary variable. */
431   int index_hint;   /* used to restore cursor position */
432   int do_buffy_notify = 1;
433   int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
434   int attach_msg = option(OPTATTACHMSG);
435
436   menu = mutt_new_menu (MENU_MAIN);
437   menu->offset = 1;
438   menu->pagelen = LINES - 3;
439   menu->make_entry = index_make_entry;
440   menu->color = index_color;
441   menu->current = ci_first_message ();
442   menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN, IndexHelp);
443
444   if (!attach_msg)
445     mutt_buffy_check(1); /* force the buffy check after we enter the folder */
446
447   FOREVER
448   {
449     tag = 0; /* clear the tag-prefix */
450
451     /* check if we need to resort the index because just about
452      * any 'op' below could do mutt_enter_command(), either here or
453      * from any new menu launched, and change $sort/$sort_aux
454      */
455     if (option (OPTNEEDRESORT) && Context && Context->msgcount && menu->current >= 0)
456       resort_index (menu);
457
458     menu->max = Context ? Context->vcount : 0;
459     oldcount = Context ? Context->msgcount : 0;
460
461     if (option (OPTREDRAWTREE) && Context && Context->msgcount && (Sort & SORT_MASK) == SORT_THREADS)
462     {
463       mutt_draw_tree (Context);
464       menu->redraw |= REDRAW_STATUS;
465       unset_option (OPTREDRAWTREE);
466     }
467
468     if (Context && !attach_msg)
469     {
470       int check;
471       /* check for new mail in the mailbox.  If nonzero, then something has
472        * changed about the file (either we got new mail or the file was
473        * modified underneath us.)
474        */
475
476 #ifdef USE_IMAP
477       imap_allow_reopen (Context);
478 #endif
479
480       index_hint = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ? CURHDR->index : 0;
481
482       if ((check = mx_check_mailbox (Context, &index_hint, 0)) < 0)
483       {
484         if (!Context->path)
485         {
486           /* fatal error occurred */
487           FREE (&Context);
488           menu->redraw = REDRAW_FULL;
489         }
490
491         set_option (OPTSEARCHINVALID);
492       }
493       else if (check == M_NEW_MAIL || check == M_REOPENED || check == M_FLAGS)
494       {
495         update_index (menu, Context, check, oldcount, index_hint);
496
497         /* notify the user of new mail */
498         if (check == M_REOPENED)
499           mutt_error _("Mailbox was externally modified.  Flags may be wrong.");
500         else if (check == M_NEW_MAIL)
501         {
502           mutt_message _("New mail in this mailbox.");
503           if (option (OPTBEEPNEW))
504             beep ();
505         } else if (check == M_FLAGS)
506           mutt_message _("Mailbox was externally modified.");
507
508         /* avoid the message being overwritten by buffy */
509         do_buffy_notify = 0;
510
511         menu->redraw = REDRAW_FULL;
512         menu->max = Context->vcount;
513
514         set_option (OPTSEARCHINVALID);
515       }
516     }
517
518     if (!attach_msg)
519     {
520      /* check for new mail in the incoming folders */
521      oldcount = newcount;
522      if ((newcount = mutt_buffy_check (0)) != oldcount)
523        menu->redraw |= REDRAW_STATUS;
524      if (do_buffy_notify)
525      {
526        if (mutt_buffy_notify () && option (OPTBEEPNEW))
527         beep ();
528      }
529      else
530        do_buffy_notify = 1;
531     }
532
533     if (op != -1)
534       mutt_curs_set (0);
535
536     if (menu->redraw & REDRAW_FULL)
537     {
538       menu_redraw_full (menu);
539       mutt_show_error ();
540     }
541
542     if (menu->menu == MENU_MAIN)
543     {
544       if (Context && Context->hdrs && !(menu->current >= Context->vcount))
545       {
546         menu_check_recenter (menu);
547
548         if (menu->redraw & REDRAW_INDEX)
549         {
550           menu_redraw_index (menu);
551           menu->redraw |= REDRAW_STATUS;
552         }
553         else if (menu->redraw & (REDRAW_MOTION_RESYNCH | REDRAW_MOTION))
554           menu_redraw_motion (menu);
555         else if (menu->redraw & REDRAW_CURRENT)
556           menu_redraw_current (menu);
557       }
558
559       if (menu->redraw & REDRAW_STATUS)
560       {
561         menu_status_line (buf, sizeof (buf), menu, NONULL (Status));
562         CLEARLINE (option (OPTSTATUSONTOP) ? 0 : LINES-2);
563         SETCOLOR (MT_COLOR_STATUS);
564         BKGDSET (MT_COLOR_STATUS);
565         mutt_paddstr (COLS, buf);
566         SETCOLOR (MT_COLOR_NORMAL);
567         BKGDSET (MT_COLOR_NORMAL);
568         menu->redraw &= ~REDRAW_STATUS;
569       }
570
571       menu->redraw = 0;
572       if (menu->current < menu->max)
573         menu->oldcurrent = menu->current;
574       else
575         menu->oldcurrent = -1;
576
577       if (option (OPTARROWCURSOR))
578         move (menu->current - menu->top + menu->offset, 2);
579       else if (option (OPTBRAILLEFRIENDLY))
580         move (menu->current - menu->top + menu->offset, 0);
581       else
582         move (menu->current - menu->top + menu->offset, COLS - 1);
583       mutt_refresh ();
584
585 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
586       if (SigWinch)
587       {
588         mutt_flushinp ();
589         mutt_resize_screen ();
590         menu->redraw = REDRAW_FULL;
591         menu->menu = MENU_MAIN;
592         SigWinch = 0;
593         menu->top = 0; /* so we scroll the right amount */
594         /*
595          * force a real complete redraw.  clrtobot() doesn't seem to be able
596          * to handle every case without this.
597          */
598         clearok(stdscr,TRUE);
599         continue;
600       }
601 #endif
602
603       op = km_dokey (MENU_MAIN);
604
605       dprint(4, (debugfile, "mutt_index_menu[%d]: Got op %d\n", __LINE__, op));
606
607       if (op == -1)
608         continue; /* either user abort or timeout */
609
610       mutt_curs_set (1);
611
612       /* special handling for the tag-prefix function */
613       if (op == OP_TAG_PREFIX)
614       {
615         if (!Context)
616         {
617           mutt_error _("No mailbox is open.");
618           continue;
619         }
620
621         if (!Context->tagged)
622         {
623           mutt_error _("No tagged messages.");
624           continue;
625         }
626         tag = 1;
627
628         /* give visual indication that the next command is a tag- command */
629         mvaddstr (LINES - 1, 0, "tag-");
630         clrtoeol ();
631
632         /* get the real command */
633         if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX)
634         {
635           /* abort tag sequence */
636           CLEARLINE (LINES-1);
637           continue;
638         }
639       }
640       else if (option (OPTAUTOTAG) && Context && Context->tagged)
641         tag = 1;
642
643       if (op == OP_TAG_PREFIX_COND)
644       {
645         if (!Context)
646         {
647           mutt_error _("No mailbox is open.");
648           continue;
649         }
650
651         if (!Context->tagged)
652         {
653           event_t tmp;
654           while(UngetCount>0)
655           {
656             tmp=mutt_getch();
657             if(tmp.op==OP_END_COND)break;
658           }
659           mutt_message  _("Nothing to do.");
660           continue;
661         }
662         tag = 1;
663
664         /* give visual indication that the next command is a tag- command */
665         mvaddstr (LINES - 1, 0, "tag-");
666         clrtoeol ();
667
668         /* get the real command */
669         if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX)
670         {
671           /* abort tag sequence */
672           CLEARLINE (LINES-1);
673           continue;
674         }
675       }
676
677       mutt_clear_error ();
678     }
679     else
680     {
681       if (menu->current < menu->max)
682         menu->oldcurrent = menu->current;
683       else
684         menu->oldcurrent = -1;
685
686       mutt_curs_set (1);        /* fallback from the pager */
687     }
688
689 #ifdef USE_IMAP
690     imap_disallow_reopen (Context);
691 #endif
692
693     switch (op)
694     {
695
696       /* ----------------------------------------------------------------------
697        * movement commands
698        */
699
700       case OP_BOTTOM_PAGE:
701         menu_bottom_page (menu);
702         break;
703       case OP_FIRST_ENTRY:
704         menu_first_entry (menu);
705         break;
706       case OP_MIDDLE_PAGE:
707         menu_middle_page (menu);
708         break;
709       case OP_HALF_UP:
710         menu_half_up (menu);
711         break;
712       case OP_HALF_DOWN:
713         menu_half_down (menu);
714         break;
715       case OP_NEXT_LINE:
716         menu_next_line (menu);
717         break;
718       case OP_PREV_LINE:
719         menu_prev_line (menu);
720         break;
721       case OP_NEXT_PAGE:
722         menu_next_page (menu);
723         break;
724       case OP_PREV_PAGE:
725         menu_prev_page (menu);
726         break;
727       case OP_LAST_ENTRY:
728         menu_last_entry (menu);
729         break;
730       case OP_TOP_PAGE:
731         menu_top_page (menu);
732         break;
733       case OP_CURRENT_TOP:
734         menu_current_top (menu);
735         break;
736       case OP_CURRENT_MIDDLE:
737         menu_current_middle (menu);
738         break;
739       case OP_CURRENT_BOTTOM:
740         menu_current_bottom (menu);
741         break;
742
743       case OP_JUMP:
744
745         CHECK_MSGCOUNT;
746         CHECK_VISIBLE;
747         if (isdigit (LastKey)) mutt_ungetch (LastKey, 0);
748         buf[0] = 0;
749         if (mutt_get_field (_("Jump to message: "), buf, sizeof (buf), 0) != 0
750             || !buf[0])
751           break;
752
753         if (mutt_atoi (buf, &i) < 0)
754         {
755           mutt_error _("Argument must be a message number.");
756           break;
757         }
758
759         if (i > 0 && i <= Context->msgcount)
760         {
761           for (j = i-1; j < Context->msgcount; j++)
762           {
763             if (Context->hdrs[j]->virtual != -1)
764               break;
765           }
766           if (j >= Context->msgcount)
767           {
768             for (j = i-2; j >= 0; j--)
769             {
770               if (Context->hdrs[j]->virtual != -1)
771                 break;
772             }
773           }
774
775           if (j >= 0)
776           {
777             menu->current = Context->hdrs[j]->virtual;
778             if (menu->menu == MENU_PAGER)
779             {
780               op = OP_DISPLAY_MESSAGE;
781               continue;
782             }
783             else
784             menu->redraw = REDRAW_MOTION;
785           }
786           else
787             mutt_error _("That message is not visible.");
788         }
789         else
790           mutt_error _("Invalid message number.");
791
792         break;
793
794         /* --------------------------------------------------------------------
795          * `index' specific commands
796          */
797
798       case OP_MAIN_DELETE_PATTERN:
799
800         CHECK_MSGCOUNT;
801         CHECK_VISIBLE;
802         CHECK_READONLY;
803         CHECK_ACL(M_ACL_DELETE, _("delete message(s)"));
804
805         CHECK_ATTACH;
806         mutt_pattern_func (M_DELETE, _("Delete messages matching: "));
807         menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
808         break;
809
810 #ifdef USE_POP
811       case OP_MAIN_FETCH_MAIL:
812
813         CHECK_ATTACH;
814         pop_fetch_mail ();
815         menu->redraw = REDRAW_FULL;
816         break;
817 #endif /* USE_POP */
818
819       case OP_HELP:
820
821         mutt_help (MENU_MAIN);
822         menu->redraw = REDRAW_FULL;
823         break;
824
825       case OP_MAIN_SHOW_LIMIT:
826         CHECK_IN_MAILBOX;
827         if (!Context->pattern)
828            mutt_message _("No limit pattern is in effect.");
829         else
830         {
831            char buf[STRING];
832            /* i18n: ask for a limit to apply */
833            snprintf (buf, sizeof(buf), _("Limit: %s"),Context->pattern);
834            mutt_message ("%s", buf);
835         }
836         break;
837
838       case OP_MAIN_LIMIT:
839
840         CHECK_IN_MAILBOX;
841         menu->oldcurrent = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ?
842                 CURHDR->index : -1;
843         if (mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
844         {
845           if (menu->oldcurrent >= 0)
846           {
847             /* try to find what used to be the current message */
848             menu->current = -1;
849             for (i = 0; i < Context->vcount; i++)
850               if (Context->hdrs[Context->v2r[i]]->index == menu->oldcurrent)
851               {
852                 menu->current = i;
853                 break;
854               }
855             if (menu->current < 0) menu->current = 0;
856           }
857           else
858             menu->current = 0;
859           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
860           if (Context->msgcount && (Sort & SORT_MASK) == SORT_THREADS)
861             mutt_draw_tree (Context);
862           menu->redraw = REDRAW_FULL;
863         }
864         if (Context->pattern)
865           mutt_message _("To view all messages, limit to \"all\".");
866         break;
867
868       case OP_QUIT:
869
870         close = op;
871         if (attach_msg)
872         {
873          done = 1;
874          break;
875         }
876
877         if (query_quadoption (OPT_QUIT, _("Quit Mutt?")) == M_YES)
878         {
879           int check;
880
881           oldcount = Context ? Context->msgcount : 0;
882
883           if (!Context || (check = mx_close_mailbox (Context, &index_hint)) == 0)
884             done = 1;
885           else
886           {
887             if (check == M_NEW_MAIL || check == M_REOPENED)
888               update_index (menu, Context, check, oldcount, index_hint);
889
890             menu->redraw = REDRAW_FULL; /* new mail arrived? */
891             set_option (OPTSEARCHINVALID);
892           }
893         }
894         break;
895
896       case OP_REDRAW:
897
898         clearok (stdscr, TRUE);
899         menu->redraw = REDRAW_FULL;
900         break;
901
902       case OP_SEARCH:
903       case OP_SEARCH_REVERSE:
904       case OP_SEARCH_NEXT:
905       case OP_SEARCH_OPPOSITE:
906
907         CHECK_MSGCOUNT;
908         CHECK_VISIBLE;
909         if ((menu->current = mutt_search_command (menu->current, op)) == -1)
910           menu->current = menu->oldcurrent;
911         else
912           menu->redraw = REDRAW_MOTION;
913         break;
914
915       case OP_SORT:
916       case OP_SORT_REVERSE:
917
918         if (mutt_select_sort ((op == OP_SORT_REVERSE)) == 0)
919         {
920           if (Context && Context->msgcount)
921           {
922             resort_index (menu);
923             set_option (OPTSEARCHINVALID);
924           }
925           menu->redraw |= REDRAW_STATUS;
926         }
927         break;
928
929       case OP_TAG:
930
931         CHECK_MSGCOUNT;
932         CHECK_VISIBLE;
933         if (tag && !option (OPTAUTOTAG))
934         {
935           for (j = 0; j < Context->vcount; j++)
936             mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_TAG, 0);
937           menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
938         }
939         else
940         {
941           mutt_set_flag (Context, CURHDR, M_TAG, !CURHDR->tagged);
942
943           Context->last_tag = CURHDR->tagged ? CURHDR :
944             ((Context->last_tag == CURHDR && !CURHDR->tagged)
945              ? NULL : Context->last_tag);
946
947           menu->redraw = REDRAW_STATUS;
948           if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
949           {
950             menu->current++;
951             menu->redraw |= REDRAW_MOTION_RESYNCH;
952           }
953           else
954             menu->redraw |= REDRAW_CURRENT;
955         }
956         break;
957
958       case OP_MAIN_TAG_PATTERN:
959
960         CHECK_MSGCOUNT;
961         CHECK_VISIBLE;
962         mutt_pattern_func (M_TAG, _("Tag messages matching: "));
963         menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
964         break;
965
966       case OP_MAIN_UNDELETE_PATTERN:
967
968         CHECK_MSGCOUNT;
969         CHECK_VISIBLE;
970         CHECK_READONLY;
971         CHECK_ACL(M_ACL_DELETE, _("undelete message(s)"));
972
973         if (mutt_pattern_func (M_UNDELETE, _("Undelete messages matching: ")) == 0)
974           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
975         break;
976
977       case OP_MAIN_UNTAG_PATTERN:
978
979         CHECK_MSGCOUNT;
980         CHECK_VISIBLE;
981         if (mutt_pattern_func (M_UNTAG, _("Untag messages matching: ")) == 0)
982           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
983         break;
984
985         /* --------------------------------------------------------------------
986          * The following operations can be performed inside of the pager.
987          */
988
989 #ifdef USE_IMAP
990       case OP_MAIN_IMAP_FETCH:
991         if (Context && Context->magic == M_IMAP)
992           imap_check_mailbox (Context, &index_hint, 1);
993         break;
994 #endif
995
996       case OP_MAIN_SYNC_FOLDER:
997
998         if (Context && !Context->msgcount)
999           break;
1000
1001         CHECK_MSGCOUNT;
1002         CHECK_VISIBLE;
1003         CHECK_READONLY;
1004         {
1005           int oldvcount = Context->vcount;
1006           int oldcount  = Context->msgcount;
1007           int check, newidx;
1008           HEADER *newhdr = NULL;
1009
1010           /* threads may be reordered, so figure out what header the cursor
1011            * should be on. #3092 */
1012           newidx = menu->current;
1013           if (CURHDR->deleted)
1014             newidx = ci_next_undeleted (menu->current);
1015           if (newidx < 0)
1016             newidx = ci_previous_undeleted (menu->current);
1017           if (newidx >= 0)
1018             newhdr = Context->hdrs[Context->v2r[newidx]];
1019
1020           if ((check = mx_sync_mailbox (Context, &index_hint)) == 0)
1021           {
1022             if (newhdr && Context->vcount != oldvcount)
1023               for (j = 0; j < Context->vcount; j++)
1024               {
1025                 if (Context->hdrs[Context->v2r[j]] == newhdr)
1026                 {
1027                   menu->current = j;
1028                   break;
1029                 }
1030               }
1031             set_option (OPTSEARCHINVALID);
1032           }
1033           else if (check == M_NEW_MAIL || check == M_REOPENED)
1034             update_index (menu, Context, check, oldcount, index_hint);
1035
1036           /*
1037            * do a sanity check even if mx_sync_mailbox failed.
1038            */
1039
1040           if (menu->current < 0 || menu->current >= Context->vcount)
1041             menu->current = ci_first_message ();
1042         }
1043
1044         /* check for a fatal error, or all messages deleted */
1045         if (!Context->path)
1046           FREE (&Context);
1047
1048         /* if we were in the pager, redisplay the message */
1049         if (menu->menu == MENU_PAGER)
1050         {
1051           op = OP_DISPLAY_MESSAGE;
1052           continue;
1053         }
1054         else
1055           menu->redraw = REDRAW_FULL;
1056         break;
1057
1058       case OP_MAIN_CHANGE_FOLDER:
1059       case OP_MAIN_NEXT_UNREAD_MAILBOX:
1060
1061         if (attach_msg)
1062           op = OP_MAIN_CHANGE_FOLDER_READONLY;
1063
1064         /* fallback to the readonly case */
1065
1066       case OP_MAIN_CHANGE_FOLDER_READONLY:
1067
1068         if ((op == OP_MAIN_CHANGE_FOLDER_READONLY) || option (OPTREADONLY))
1069           cp = _("Open mailbox in read-only mode");
1070         else
1071           cp = _("Open mailbox");
1072
1073         buf[0] = '\0';
1074         if ((op == OP_MAIN_NEXT_UNREAD_MAILBOX) && Context && Context->path)
1075         {
1076           strfcpy (buf, Context->path, sizeof (buf));
1077           mutt_pretty_mailbox (buf, sizeof (buf));
1078           mutt_buffy (buf, sizeof (buf));
1079           if (!buf[0])
1080           {
1081             mutt_error _("No mailboxes have new mail");
1082             break;
1083           }
1084         }
1085         else
1086         {
1087           mutt_buffy (buf, sizeof (buf));
1088
1089           if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
1090           {
1091             if (menu->menu == MENU_PAGER)
1092             {
1093               op = OP_DISPLAY_MESSAGE;
1094               continue;
1095             }
1096             else
1097               break;
1098           }
1099           if (!buf[0])
1100           {
1101             CLEARLINE (LINES-1);
1102             break;
1103           }
1104         }
1105
1106         mutt_expand_path (buf, sizeof (buf));
1107         if (mx_get_magic (buf) <= 0)
1108         {
1109           mutt_error (_("%s is not a mailbox."), buf);
1110           break;
1111         }
1112         mutt_str_replace (&CurrentFolder, buf);
1113
1114         if (Context)
1115         {
1116           int check;
1117
1118           mutt_str_replace (&LastFolder, Context->path);
1119           oldcount = Context ? Context->msgcount : 0;
1120
1121           if ((check = mx_close_mailbox (Context, &index_hint)) != 0)
1122           {
1123             if (check == M_NEW_MAIL || check == M_REOPENED)
1124               update_index (menu, Context, check, oldcount, index_hint);
1125
1126             set_option (OPTSEARCHINVALID);
1127             menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1128             break;
1129           }
1130           FREE (&Context);
1131         }
1132
1133         mutt_sleep (0);
1134
1135         /* Set CurrentMenu to MENU_MAIN before executing any folder
1136          * hooks so that all the index menu functions are available to
1137          * the exec command.
1138          */
1139
1140         CurrentMenu = MENU_MAIN;
1141         mutt_folder_hook (buf);
1142
1143         if ((Context = mx_open_mailbox (buf,
1144                                         (option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
1145                                         M_READONLY : 0, NULL)) != NULL)
1146         {
1147           menu->current = ci_first_message ();
1148         }
1149         else
1150           menu->current = 0;
1151
1152         mutt_clear_error ();
1153         mutt_buffy_check(1); /* force the buffy check after we have changed
1154                               the folder */
1155         menu->redraw = REDRAW_FULL;
1156         set_option (OPTSEARCHINVALID);
1157         break;
1158
1159       case OP_DISPLAY_MESSAGE:
1160       case OP_DISPLAY_HEADERS: /* don't weed the headers */
1161
1162         CHECK_MSGCOUNT;
1163         CHECK_VISIBLE;
1164         /*
1165          * toggle the weeding of headers so that a user can press the key
1166          * again while reading the message.
1167          */
1168         if (op == OP_DISPLAY_HEADERS)
1169           toggle_option (OPTWEED);
1170
1171         unset_option (OPTNEEDRESORT);
1172
1173         if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed)
1174         {
1175           mutt_uncollapse_thread (Context, CURHDR);
1176           mutt_set_virtual (Context);
1177           if (option (OPTUNCOLLAPSEJUMP))
1178             menu->current = mutt_thread_next_unread (Context, CURHDR);
1179         }
1180
1181         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1182           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1183         if ((op = mutt_display_message (CURHDR)) == -1)
1184         {
1185           unset_option (OPTNEEDRESORT);
1186           break;
1187         }
1188
1189         menu->menu = MENU_PAGER;
1190         menu->oldcurrent = menu->current;
1191         continue;
1192
1193       case OP_EXIT:
1194
1195         close = op;
1196         if (menu->menu == MENU_MAIN && attach_msg)
1197         {
1198          done = 1;
1199          break;
1200         }
1201
1202         if ((menu->menu == MENU_MAIN)
1203             && (query_quadoption (OPT_QUIT,
1204                                   _("Exit Mutt without saving?")) == M_YES))
1205         {
1206           if (Context)
1207           {
1208             mx_fastclose_mailbox (Context);
1209             FREE (&Context);
1210           }
1211           done = 1;
1212         }
1213         break;
1214
1215       case OP_MAIN_BREAK_THREAD:
1216
1217         CHECK_MSGCOUNT;
1218         CHECK_VISIBLE;
1219         CHECK_READONLY;
1220
1221         if ((Sort & SORT_MASK) != SORT_THREADS)
1222           mutt_error _("Threading is not enabled.");
1223         else
1224         {
1225           {
1226             HEADER *oldcur = CURHDR;
1227
1228             mutt_break_thread (CURHDR);
1229             mutt_sort_headers (Context, 1);
1230             menu->current = oldcur->virtual;
1231           }
1232
1233           Context->changed = 1;
1234           mutt_message _("Thread broken");
1235
1236           if (menu->menu == MENU_PAGER)
1237           {
1238             op = OP_DISPLAY_MESSAGE;
1239             continue;
1240           }
1241           else
1242             menu->redraw |= REDRAW_INDEX;
1243         }
1244
1245           break;
1246
1247       case OP_MAIN_LINK_THREADS:
1248
1249         CHECK_MSGCOUNT;
1250         CHECK_VISIBLE;
1251         CHECK_READONLY;
1252         CHECK_ACL(M_ACL_DELETE, _("link threads"));
1253
1254         if ((Sort & SORT_MASK) != SORT_THREADS)
1255           mutt_error _("Threading is not enabled.");
1256         else if (!CURHDR->env->message_id)
1257           mutt_error _("No Message-ID: header available to link thread");
1258         else if (!tag && (!Context->last_tag || !Context->last_tag->tagged))
1259           mutt_error _("First, please tag a message to be linked here");
1260         else
1261         {
1262           HEADER *oldcur = CURHDR;
1263
1264           if (mutt_link_threads (CURHDR, tag ? NULL : Context->last_tag,
1265                                  Context))
1266           {
1267             mutt_sort_headers (Context, 1);
1268             menu->current = oldcur->virtual;
1269
1270             Context->changed = 1;
1271             mutt_message _("Threads linked");
1272           }
1273           else
1274             mutt_error _("No thread linked");
1275         }
1276
1277         if (menu->menu == MENU_PAGER)
1278         {
1279           op = OP_DISPLAY_MESSAGE;
1280           continue;
1281         }
1282         else
1283           menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
1284
1285         break;
1286
1287       case OP_EDIT_TYPE:
1288
1289         CHECK_MSGCOUNT;
1290         CHECK_VISIBLE;
1291         CHECK_ATTACH;
1292         mutt_edit_content_type (CURHDR, CURHDR->content, NULL);
1293         /* if we were in the pager, redisplay the message */
1294         if (menu->menu == MENU_PAGER)
1295         {
1296           op = OP_DISPLAY_MESSAGE;
1297           continue;
1298         }
1299         else
1300           menu->redraw = REDRAW_CURRENT;
1301         break;
1302
1303       case OP_MAIN_NEXT_UNDELETED:
1304
1305         CHECK_MSGCOUNT;
1306         CHECK_VISIBLE;
1307         if (menu->current >= Context->vcount - 1)
1308         {
1309           if (menu->menu == MENU_MAIN)
1310             mutt_error _("You are on the last message.");
1311           break;
1312         }
1313         if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1314         {
1315           menu->current = menu->oldcurrent;
1316           if (menu->menu == MENU_MAIN)
1317             mutt_error _("No undeleted messages.");
1318         }
1319         else if (menu->menu == MENU_PAGER)
1320         {
1321           op = OP_DISPLAY_MESSAGE;
1322           continue;
1323         }
1324         else
1325           menu->redraw = REDRAW_MOTION;
1326         break;
1327
1328       case OP_NEXT_ENTRY:
1329
1330         CHECK_MSGCOUNT;
1331         CHECK_VISIBLE;
1332         if (menu->current >= Context->vcount - 1)
1333         {
1334           if (menu->menu == MENU_MAIN)
1335             mutt_error _("You are on the last message.");
1336           break;
1337         }
1338         menu->current++;
1339         if (menu->menu == MENU_PAGER)
1340         {
1341           op = OP_DISPLAY_MESSAGE;
1342           continue;
1343         }
1344         else
1345           menu->redraw = REDRAW_MOTION;
1346         break;
1347
1348       case OP_MAIN_PREV_UNDELETED:
1349
1350         CHECK_MSGCOUNT;
1351         CHECK_VISIBLE;
1352         if (menu->current < 1)
1353         {
1354           mutt_error _("You are on the first message.");
1355           break;
1356         }
1357         if ((menu->current = ci_previous_undeleted (menu->current)) == -1)
1358         {
1359           menu->current = menu->oldcurrent;
1360           if (menu->menu == MENU_MAIN)
1361             mutt_error _("No undeleted messages.");
1362         }
1363         else if (menu->menu == MENU_PAGER)
1364         {
1365           op = OP_DISPLAY_MESSAGE;
1366           continue;
1367         }
1368         else
1369           menu->redraw = REDRAW_MOTION;
1370         break;
1371
1372       case OP_PREV_ENTRY:
1373
1374         CHECK_MSGCOUNT;
1375         CHECK_VISIBLE;
1376         if (menu->current < 1)
1377         {
1378           if (menu->menu == MENU_MAIN) mutt_error _("You are on the first message.");
1379           break;
1380         }
1381         menu->current--;
1382         if (menu->menu == MENU_PAGER)
1383         {
1384           op = OP_DISPLAY_MESSAGE;
1385           continue;
1386         }
1387         else
1388           menu->redraw = REDRAW_MOTION;
1389         break;
1390
1391       case OP_DECRYPT_COPY:
1392       case OP_DECRYPT_SAVE:
1393         if (!WithCrypto)
1394           break;
1395         /* fall thru */
1396       case OP_COPY_MESSAGE:
1397       case OP_SAVE:
1398       case OP_DECODE_COPY:
1399       case OP_DECODE_SAVE:
1400         CHECK_MSGCOUNT;
1401         CHECK_VISIBLE;
1402         if (mutt_save_message (tag ? NULL : CURHDR,
1403                                (op == OP_DECRYPT_SAVE) ||
1404                                (op == OP_SAVE) || (op == OP_DECODE_SAVE),
1405                                (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY),
1406                                (op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY) ||
1407                                0,
1408                                &menu->redraw) == 0 &&
1409              (op == OP_SAVE || op == OP_DECODE_SAVE || op == OP_DECRYPT_SAVE)
1410             )
1411         {
1412           if (tag)
1413             menu->redraw |= REDRAW_INDEX;
1414           else if (option (OPTRESOLVE))
1415           {
1416             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1417             {
1418               menu->current = menu->oldcurrent;
1419               menu->redraw |= REDRAW_CURRENT;
1420             }
1421             else
1422               menu->redraw |= REDRAW_MOTION_RESYNCH;
1423           }
1424           else
1425             menu->redraw |= REDRAW_CURRENT;
1426         }
1427         break;
1428
1429       case OP_MAIN_NEXT_NEW:
1430       case OP_MAIN_NEXT_UNREAD:
1431       case OP_MAIN_PREV_NEW:
1432       case OP_MAIN_PREV_UNREAD:
1433       case OP_MAIN_NEXT_NEW_THEN_UNREAD:
1434       case OP_MAIN_PREV_NEW_THEN_UNREAD:
1435
1436       {
1437         int first_unread = -1;
1438         int first_new    = -1;
1439
1440         CHECK_MSGCOUNT;
1441         CHECK_VISIBLE;
1442
1443         i = menu->current;
1444         menu->current = -1;
1445         for (j = 0; j != Context->vcount; j++)
1446         {
1447 #define CURHDRi Context->hdrs[Context->v2r[i]]
1448           if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_NEXT_NEW_THEN_UNREAD)
1449           {
1450             i++;
1451             if (i > Context->vcount - 1)
1452             {
1453               mutt_message _("Search wrapped to top.");
1454               i = 0;
1455             }
1456           }
1457           else
1458           {
1459             i--;
1460             if (i < 0)
1461             {
1462               mutt_message _("Search wrapped to bottom.");
1463               i = Context->vcount - 1;
1464             }
1465           }
1466
1467           if (CURHDRi->collapsed && (Sort & SORT_MASK) == SORT_THREADS)
1468           {
1469             if (UNREAD (CURHDRi) && first_unread == -1)
1470               first_unread = i;
1471             if (UNREAD (CURHDRi) == 1 && first_new == -1)
1472               first_new = i;
1473           }
1474           else if ((!CURHDRi->deleted && !CURHDRi->read))
1475           {
1476             if (first_unread == -1)
1477               first_unread = i;
1478             if ((!CURHDRi->old) && first_new == -1)
1479               first_new = i;
1480           }
1481
1482           if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD) &&
1483               first_unread != -1)
1484             break;
1485           if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
1486                op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1487               && first_new != -1)
1488             break;
1489         }
1490 #undef CURHDRi
1491         if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
1492              op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1493             && first_new != -1)
1494           menu->current = first_new;
1495         else if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD ||
1496                   op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1497                  && first_unread != -1)
1498           menu->current = first_unread;
1499
1500         if (menu->current == -1)
1501         {
1502           menu->current = menu->oldcurrent;
1503           mutt_error ("%s%s.", (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ? _("No new messages") : _("No unread messages"),
1504                       Context->pattern ? _(" in this limited view") : "");
1505         }
1506         else if (menu->menu == MENU_PAGER)
1507         {
1508           op = OP_DISPLAY_MESSAGE;
1509           continue;
1510         }
1511         else
1512           menu->redraw = REDRAW_MOTION;
1513         break;
1514       }
1515       case OP_FLAG_MESSAGE:
1516
1517         CHECK_MSGCOUNT;
1518         CHECK_VISIBLE;
1519         CHECK_READONLY;
1520         CHECK_ACL(M_ACL_WRITE, _("flag message"));
1521
1522         if (tag)
1523         {
1524           for (j = 0; j < Context->vcount; j++)
1525           {
1526             if (Context->hdrs[Context->v2r[j]]->tagged)
1527               mutt_set_flag (Context, Context->hdrs[Context->v2r[j]],
1528                              M_FLAG, !Context->hdrs[Context->v2r[j]]->flagged);
1529           }
1530
1531           menu->redraw |= REDRAW_INDEX;
1532         }
1533         else
1534         {
1535           mutt_set_flag (Context, CURHDR, M_FLAG, !CURHDR->flagged);
1536           if (option (OPTRESOLVE))
1537           {
1538             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1539             {
1540               menu->current = menu->oldcurrent;
1541               menu->redraw = REDRAW_CURRENT;
1542             }
1543             else
1544               menu->redraw = REDRAW_MOTION_RESYNCH;
1545           }
1546           else
1547             menu->redraw = REDRAW_CURRENT;
1548         }
1549         menu->redraw |= REDRAW_STATUS;
1550         break;
1551
1552       case OP_TOGGLE_NEW:
1553
1554         CHECK_MSGCOUNT;
1555         CHECK_VISIBLE;
1556         CHECK_READONLY;
1557         CHECK_ACL(M_ACL_SEEN, _("toggle new"));
1558
1559         if (tag)
1560         {
1561           for (j = 0; j < Context->vcount; j++)
1562           {
1563             if (Context->hdrs[Context->v2r[j]]->tagged)
1564             {
1565               if (Context->hdrs[Context->v2r[j]]->read ||
1566                   Context->hdrs[Context->v2r[j]]->old)
1567                 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_NEW, 1);
1568               else
1569                 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_READ, 1);
1570             }
1571           }
1572           menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1573         }
1574         else
1575         {
1576           if (CURHDR->read || CURHDR->old)
1577             mutt_set_flag (Context, CURHDR, M_NEW, 1);
1578           else
1579             mutt_set_flag (Context, CURHDR, M_READ, 1);
1580
1581           if (option (OPTRESOLVE))
1582           {
1583             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1584             {
1585               menu->current = menu->oldcurrent;
1586               menu->redraw = REDRAW_CURRENT;
1587             }
1588             else
1589               menu->redraw = REDRAW_MOTION_RESYNCH;
1590           }
1591           else
1592             menu->redraw = REDRAW_CURRENT;
1593           menu->redraw |= REDRAW_STATUS;
1594         }
1595         break;
1596
1597       case OP_TOGGLE_WRITE:
1598
1599         CHECK_IN_MAILBOX;
1600         if (mx_toggle_write (Context) == 0)
1601           menu->redraw |= REDRAW_STATUS;
1602         break;
1603
1604       case OP_MAIN_NEXT_THREAD:
1605       case OP_MAIN_NEXT_SUBTHREAD:
1606       case OP_MAIN_PREV_THREAD:
1607       case OP_MAIN_PREV_SUBTHREAD:
1608
1609         CHECK_MSGCOUNT;
1610         CHECK_VISIBLE;
1611         switch (op)
1612         {
1613           case OP_MAIN_NEXT_THREAD:
1614             menu->current = mutt_next_thread (CURHDR);
1615             break;
1616
1617           case OP_MAIN_NEXT_SUBTHREAD:
1618             menu->current = mutt_next_subthread (CURHDR);
1619             break;
1620
1621           case OP_MAIN_PREV_THREAD:
1622             menu->current = mutt_previous_thread (CURHDR);
1623             break;
1624
1625           case OP_MAIN_PREV_SUBTHREAD:
1626             menu->current = mutt_previous_subthread (CURHDR);
1627             break;
1628         }
1629
1630         if (menu->current < 0)
1631         {
1632           menu->current = menu->oldcurrent;
1633           if (op == OP_MAIN_NEXT_THREAD || op == OP_MAIN_NEXT_SUBTHREAD)
1634             mutt_error _("No more threads.");
1635           else
1636             mutt_error _("You are on the first thread.");
1637         }
1638         else if (menu->menu == MENU_PAGER)
1639         {
1640           op = OP_DISPLAY_MESSAGE;
1641           continue;
1642         }
1643         else
1644           menu->redraw = REDRAW_MOTION;
1645         break;
1646
1647       case OP_MAIN_PARENT_MESSAGE:
1648
1649         CHECK_MSGCOUNT;
1650         CHECK_VISIBLE;
1651
1652         if ((menu->current = mutt_parent_message (Context, CURHDR)) < 0)
1653         {
1654           menu->current = menu->oldcurrent;
1655         }
1656         else if (menu->menu == MENU_PAGER)
1657         {
1658           op = OP_DISPLAY_MESSAGE;
1659           continue;
1660         }
1661         else
1662           menu->redraw = REDRAW_MOTION;
1663         break;
1664
1665       case OP_MAIN_SET_FLAG:
1666       case OP_MAIN_CLEAR_FLAG:
1667
1668         CHECK_MSGCOUNT;
1669         CHECK_VISIBLE;
1670         CHECK_READONLY;
1671         /* CHECK_ACL(M_ACL_WRITE); */
1672
1673         if (mutt_change_flag (tag ? NULL : CURHDR, (op == OP_MAIN_SET_FLAG)) == 0)
1674         {
1675           menu->redraw = REDRAW_STATUS;
1676           if (tag)
1677             menu->redraw |= REDRAW_INDEX;
1678           else if (option (OPTRESOLVE))
1679           {
1680             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1681             {
1682               menu->current = menu->oldcurrent;
1683               menu->redraw |= REDRAW_CURRENT;
1684             }
1685             else
1686               menu->redraw |= REDRAW_MOTION_RESYNCH;
1687           }
1688           else
1689             menu->redraw |= REDRAW_CURRENT;
1690         }
1691         break;
1692
1693       case OP_MAIN_COLLAPSE_THREAD:
1694         CHECK_MSGCOUNT;
1695         CHECK_VISIBLE;
1696
1697         if ((Sort & SORT_MASK) != SORT_THREADS)
1698         {
1699           mutt_error _("Threading is not enabled.");
1700           break;
1701         }
1702
1703         if (CURHDR->collapsed)
1704         {
1705           menu->current = mutt_uncollapse_thread (Context, CURHDR);
1706           mutt_set_virtual (Context);
1707           if (option (OPTUNCOLLAPSEJUMP))
1708             menu->current = mutt_thread_next_unread (Context, CURHDR);
1709         }
1710         else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR))
1711         {
1712           menu->current = mutt_collapse_thread (Context, CURHDR);
1713           mutt_set_virtual (Context);
1714         }
1715         else
1716         {
1717           mutt_error _("Thread contains unread messages.");
1718           break;
1719         }
1720
1721         menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1722
1723        break;
1724
1725       case OP_MAIN_COLLAPSE_ALL:
1726         CHECK_MSGCOUNT;
1727         CHECK_VISIBLE;
1728
1729         if ((Sort & SORT_MASK) != SORT_THREADS)
1730         {
1731           mutt_error _("Threading is not enabled.");
1732           break;
1733         }
1734
1735         {
1736           HEADER *h, *base;
1737           THREAD *thread, *top;
1738           int final;
1739
1740           if (CURHDR->collapsed)
1741             final = mutt_uncollapse_thread (Context, CURHDR);
1742           else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR))
1743             final = mutt_collapse_thread (Context, CURHDR);
1744           else
1745             final = CURHDR->virtual;
1746
1747           base = Context->hdrs[Context->v2r[final]];
1748
1749           top = Context->tree;
1750           Context->collapsed = !Context->collapsed;
1751           while ((thread = top) != NULL)
1752           {
1753             while (!thread->message)
1754               thread = thread->child;
1755             h = thread->message;
1756
1757             if (h->collapsed != Context->collapsed)
1758             {
1759               if (h->collapsed)
1760                 mutt_uncollapse_thread (Context, h);
1761               else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (h))
1762                 mutt_collapse_thread (Context, h);
1763             }
1764             top = top->next;
1765           }
1766
1767           mutt_set_virtual (Context);
1768           for (j = 0; j < Context->vcount; j++)
1769           {
1770             if (Context->hdrs[Context->v2r[j]]->index == base->index)
1771             {
1772               menu->current = j;
1773               break;
1774             }
1775           }
1776
1777           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1778         }
1779         break;
1780
1781       /* --------------------------------------------------------------------
1782        * These functions are invoked directly from the internal-pager
1783        */
1784
1785       case OP_BOUNCE_MESSAGE:
1786
1787         CHECK_ATTACH;
1788         CHECK_MSGCOUNT;
1789         CHECK_VISIBLE;
1790         ci_bounce_message (tag ? NULL : CURHDR, &menu->redraw);
1791         break;
1792
1793       case OP_CREATE_ALIAS:
1794
1795         mutt_create_alias (Context && Context->vcount ? CURHDR->env : NULL, NULL);
1796         MAYBE_REDRAW (menu->redraw);
1797         menu->redraw |= REDRAW_CURRENT;
1798         break;
1799
1800       case OP_QUERY:
1801         CHECK_ATTACH;
1802         mutt_query_menu (NULL, 0);
1803         MAYBE_REDRAW (menu->redraw);
1804         break;
1805
1806       case OP_DELETE:
1807
1808         CHECK_MSGCOUNT;
1809         CHECK_VISIBLE;
1810         CHECK_READONLY;
1811         CHECK_ACL(M_ACL_DELETE, _("delete message"));
1812
1813         if (tag)
1814         {
1815           mutt_tag_set_flag (M_DELETE, 1);
1816           if (option (OPTDELETEUNTAG))
1817             mutt_tag_set_flag (M_TAG, 0);
1818           menu->redraw = REDRAW_INDEX;
1819         }
1820         else
1821         {
1822           mutt_set_flag (Context, CURHDR, M_DELETE, 1);
1823           if (option (OPTDELETEUNTAG))
1824             mutt_set_flag (Context, CURHDR, M_TAG, 0);
1825           if (option (OPTRESOLVE))
1826           {
1827             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1828             {
1829               menu->current = menu->oldcurrent;
1830               menu->redraw = REDRAW_CURRENT;
1831             }
1832             else if (menu->menu == MENU_PAGER)
1833             {
1834               op = OP_DISPLAY_MESSAGE;
1835               continue;
1836             }
1837             else
1838               menu->redraw |= REDRAW_MOTION_RESYNCH;
1839           }
1840           else
1841             menu->redraw = REDRAW_CURRENT;
1842         }
1843         menu->redraw |= REDRAW_STATUS;
1844         break;
1845
1846       case OP_DELETE_THREAD:
1847       case OP_DELETE_SUBTHREAD:
1848
1849         CHECK_MSGCOUNT;
1850         CHECK_VISIBLE;
1851         CHECK_READONLY;
1852         CHECK_ACL(M_ACL_DELETE, _("delete message(s)"));
1853
1854         rc = mutt_thread_set_flag (CURHDR, M_DELETE, 1,
1855                                    op == OP_DELETE_THREAD ? 0 : 1);
1856
1857         if (rc != -1)
1858         {
1859           if (option (OPTDELETEUNTAG))
1860             mutt_thread_set_flag (CURHDR, M_TAG, 0,
1861                                   op == OP_DELETE_THREAD ? 0 : 1);
1862           if (option (OPTRESOLVE))
1863             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1864               menu->current = menu->oldcurrent;
1865           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1866         }
1867         break;
1868
1869       case OP_DISPLAY_ADDRESS:
1870
1871         CHECK_MSGCOUNT;
1872         CHECK_VISIBLE;
1873         mutt_display_address (CURHDR->env);
1874         break;
1875
1876       case OP_ENTER_COMMAND:
1877
1878         CurrentMenu = MENU_MAIN;
1879         mutt_enter_command ();
1880         mutt_check_rescore (Context);
1881         if (option (OPTFORCEREDRAWINDEX))
1882           menu->redraw = REDRAW_FULL;
1883         unset_option (OPTFORCEREDRAWINDEX);
1884         unset_option (OPTFORCEREDRAWPAGER);
1885         break;
1886
1887       case OP_EDIT_MESSAGE:
1888
1889         CHECK_MSGCOUNT;
1890         CHECK_VISIBLE;
1891         CHECK_READONLY;
1892         CHECK_ATTACH;
1893         CHECK_ACL(M_ACL_INSERT, _("edit message"));
1894
1895         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1896           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1897         mutt_edit_message (Context, tag ? NULL : CURHDR);
1898         menu->redraw = REDRAW_FULL;
1899
1900         break;
1901
1902       case OP_FORWARD_MESSAGE:
1903
1904         CHECK_MSGCOUNT;
1905         CHECK_VISIBLE;
1906         CHECK_ATTACH;
1907         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1908           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1909         ci_send_message (SENDFORWARD, NULL, NULL, Context, tag ? NULL : CURHDR);
1910         menu->redraw = REDRAW_FULL;
1911         break;
1912
1913
1914       case OP_FORGET_PASSPHRASE:
1915         crypt_forget_passphrase ();
1916         break;
1917
1918       case OP_GROUP_REPLY:
1919
1920         CHECK_MSGCOUNT;
1921         CHECK_VISIBLE;
1922         CHECK_ATTACH;
1923         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1924           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1925         ci_send_message (SENDREPLY|SENDGROUPREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
1926         menu->redraw = REDRAW_FULL;
1927         break;
1928
1929       case OP_LIST_REPLY:
1930
1931         CHECK_ATTACH;
1932         CHECK_MSGCOUNT;
1933         CHECK_VISIBLE;
1934         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1935           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1936         ci_send_message (SENDREPLY|SENDLISTREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
1937         menu->redraw = REDRAW_FULL;
1938         break;
1939
1940       case OP_MAIL:
1941
1942         CHECK_ATTACH;
1943         ci_send_message (0, NULL, NULL, Context, NULL);
1944         menu->redraw = REDRAW_FULL;
1945         break;
1946
1947       case OP_MAIL_KEY:
1948         if (!(WithCrypto & APPLICATION_PGP))
1949           break;
1950         CHECK_ATTACH;
1951         ci_send_message (SENDKEY, NULL, NULL, NULL, NULL);
1952         menu->redraw = REDRAW_FULL;
1953         break;
1954
1955
1956       case OP_EXTRACT_KEYS:
1957         if (!WithCrypto)
1958           break;
1959         CHECK_MSGCOUNT;
1960         CHECK_VISIBLE;
1961         crypt_extract_keys_from_messages(tag ? NULL : CURHDR);
1962         menu->redraw = REDRAW_FULL;
1963         break;
1964
1965
1966       case OP_CHECK_TRADITIONAL:
1967         if (!(WithCrypto & APPLICATION_PGP))
1968           break;
1969         CHECK_MSGCOUNT;
1970         CHECK_VISIBLE;
1971         if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
1972           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1973
1974         if (menu->menu == MENU_PAGER)
1975         {
1976           op = OP_DISPLAY_MESSAGE;
1977           continue;
1978         }
1979         break;
1980
1981       case OP_PIPE:
1982
1983         CHECK_MSGCOUNT;
1984         CHECK_VISIBLE;
1985         mutt_pipe_message (tag ? NULL : CURHDR);
1986
1987 #ifdef USE_IMAP
1988         /* in an IMAP folder index with imap_peek=no, piping could change
1989          * new or old messages status to read. Redraw what's needed.
1990          */
1991         if (Context->magic == M_IMAP && !option (OPTIMAPPEEK))
1992         {
1993           menu->redraw = (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
1994         }
1995 #endif
1996
1997         MAYBE_REDRAW (menu->redraw);
1998         break;
1999
2000       case OP_PRINT:
2001
2002         CHECK_MSGCOUNT;
2003         CHECK_VISIBLE;
2004         mutt_print_message (tag ? NULL : CURHDR);
2005
2006 #ifdef USE_IMAP
2007         /* in an IMAP folder index with imap_peek=no, printing could change
2008          * new or old messages status to read. Redraw what's needed.
2009          */
2010         if (Context->magic == M_IMAP && !option (OPTIMAPPEEK))
2011         {
2012           menu->redraw = (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
2013         }
2014 #endif
2015
2016         break;
2017
2018       case OP_MAIN_READ_THREAD:
2019       case OP_MAIN_READ_SUBTHREAD:
2020
2021         CHECK_MSGCOUNT;
2022         CHECK_VISIBLE;
2023         CHECK_READONLY;
2024         CHECK_ACL(M_ACL_SEEN, _("mark message(s) as read"));
2025
2026         rc = mutt_thread_set_flag (CURHDR, M_READ, 1,
2027                                    op == OP_MAIN_READ_THREAD ? 0 : 1);
2028
2029         if (rc != -1)
2030         {
2031           if (option (OPTRESOLVE))
2032           {
2033             if ((menu->current = (op == OP_MAIN_READ_THREAD ?
2034                                   mutt_next_thread (CURHDR) : mutt_next_subthread (CURHDR))) == -1)
2035               menu->current = menu->oldcurrent;
2036           }
2037           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2038         }
2039         break;
2040
2041       case OP_RECALL_MESSAGE:
2042
2043         CHECK_ATTACH;
2044         ci_send_message (SENDPOSTPONED, NULL, NULL, Context, NULL);
2045         menu->redraw = REDRAW_FULL;
2046         break;
2047
2048       case OP_RESEND:
2049
2050         CHECK_ATTACH;
2051         CHECK_MSGCOUNT;
2052         CHECK_VISIBLE;
2053
2054         if (tag)
2055         {
2056           for (j = 0; j < Context->vcount; j++)
2057           {
2058             if (Context->hdrs[Context->v2r[j]]->tagged)
2059               mutt_resend_message (NULL, Context, Context->hdrs[Context->v2r[j]]);
2060           }
2061         }
2062         else
2063           mutt_resend_message (NULL, Context, CURHDR);
2064
2065         menu->redraw = REDRAW_FULL;
2066         break;
2067
2068       case OP_REPLY:
2069
2070         CHECK_ATTACH;
2071         CHECK_MSGCOUNT;
2072         CHECK_VISIBLE;
2073         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
2074           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
2075         ci_send_message (SENDREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
2076         menu->redraw = REDRAW_FULL;
2077         break;
2078
2079       case OP_SHELL_ESCAPE:
2080
2081         mutt_shell_escape ();
2082         MAYBE_REDRAW (menu->redraw);
2083         break;
2084
2085       case OP_TAG_THREAD:
2086       case OP_TAG_SUBTHREAD:
2087
2088         CHECK_MSGCOUNT;
2089         CHECK_VISIBLE;
2090         rc = mutt_thread_set_flag (CURHDR, M_TAG, !CURHDR->tagged,
2091                                    op == OP_TAG_THREAD ? 0 : 1);
2092
2093         if (rc != -1)
2094         {
2095           if (option (OPTRESOLVE))
2096           {
2097             if (op == OP_TAG_THREAD)
2098               menu->current = mutt_next_thread (CURHDR);
2099             else
2100               menu->current = mutt_next_subthread (CURHDR);
2101
2102             if (menu->current == -1)
2103               menu->current = menu->oldcurrent;
2104           }
2105           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2106         }
2107         break;
2108
2109       case OP_UNDELETE:
2110
2111         CHECK_MSGCOUNT;
2112         CHECK_VISIBLE;
2113         CHECK_READONLY;
2114         CHECK_ACL(M_ACL_DELETE, _("undelete message"));
2115
2116         if (tag)
2117         {
2118           mutt_tag_set_flag (M_DELETE, 0);
2119           menu->redraw = REDRAW_INDEX;
2120         }
2121         else
2122         {
2123           mutt_set_flag (Context, CURHDR, M_DELETE, 0);
2124           if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
2125           {
2126             menu->current++;
2127             menu->redraw = REDRAW_MOTION_RESYNCH;
2128           }
2129           else
2130             menu->redraw = REDRAW_CURRENT;
2131         }
2132         menu->redraw |= REDRAW_STATUS;
2133         break;
2134
2135       case OP_UNDELETE_THREAD:
2136       case OP_UNDELETE_SUBTHREAD:
2137
2138         CHECK_MSGCOUNT;
2139         CHECK_VISIBLE;
2140         CHECK_READONLY;
2141         CHECK_ACL(M_ACL_DELETE, _("undelete message(s)"));
2142
2143         rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
2144                                    op == OP_UNDELETE_THREAD ? 0 : 1);
2145
2146         if (rc != -1)
2147         {
2148           if (option (OPTRESOLVE))
2149           {
2150             if (op == OP_UNDELETE_THREAD)
2151               menu->current = mutt_next_thread (CURHDR);
2152             else
2153               menu->current = mutt_next_subthread (CURHDR);
2154
2155             if (menu->current == -1)
2156               menu->current = menu->oldcurrent;
2157           }
2158           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2159         }
2160         break;
2161
2162       case OP_VERSION:
2163         mutt_version ();
2164         break;
2165
2166       case OP_BUFFY_LIST:
2167         mutt_buffy_list ();
2168         break;
2169
2170       case OP_VIEW_ATTACHMENTS:
2171         CHECK_MSGCOUNT;
2172         CHECK_VISIBLE;
2173         mutt_view_attachments (CURHDR);
2174         if (CURHDR->attach_del)
2175           Context->changed = 1;
2176         menu->redraw = REDRAW_FULL;
2177         break;
2178
2179       case OP_END_COND:
2180         break;
2181
2182       case OP_WHAT_KEY:
2183         mutt_what_key();
2184         break;
2185
2186       default:
2187         if (menu->menu == MENU_MAIN)
2188           km_error_key (MENU_MAIN);
2189     }
2190
2191     if (menu->menu == MENU_PAGER)
2192     {
2193       menu->menu = MENU_MAIN;
2194       menu->redraw = REDRAW_FULL;
2195 #if 0
2196       set_option (OPTWEED); /* turn header weeding back on. */
2197 #endif
2198     }
2199
2200     if (done) break;
2201   }
2202
2203   mutt_menuDestroy (&menu);
2204   return (close);
2205 }
2206
2207 void mutt_set_header_color (CONTEXT *ctx, HEADER *curhdr)
2208 {
2209   COLOR_LINE *color;
2210
2211   if (!curhdr)
2212     return;
2213
2214   for (color = ColorIndexList; color; color = color->next)
2215    if (mutt_pattern_exec (color->color_pattern, M_MATCH_FULL_ADDRESS, ctx, curhdr))
2216    {
2217       curhdr->pair = color->pair;
2218       return;
2219    }
2220   curhdr->pair = ColorDefs[MT_COLOR_NORMAL];
2221 }