]> git.llucax.com Git - software/mutt-debian.git/blob - curs_main.c
Update and enable NNTP patch
[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       index_hint = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ? CURHDR->index : 0;
477
478       if ((check = mx_check_mailbox (Context, &index_hint, 0)) < 0)
479       {
480         if (!Context->path)
481         {
482           /* fatal error occurred */
483           FREE (&Context);
484           menu->redraw = REDRAW_FULL;
485         }
486
487         set_option (OPTSEARCHINVALID);
488       }
489       else if (check == M_NEW_MAIL || check == M_REOPENED || check == M_FLAGS)
490       {
491         update_index (menu, Context, check, oldcount, index_hint);
492
493         /* notify the user of new mail */
494         if (check == M_REOPENED)
495           mutt_error _("Mailbox was externally modified.  Flags may be wrong.");
496         else if (check == M_NEW_MAIL)
497         {
498           mutt_message _("New mail in this mailbox.");
499           if (option (OPTBEEPNEW))
500             beep ();
501         } else if (check == M_FLAGS)
502           mutt_message _("Mailbox was externally modified.");
503
504         /* avoid the message being overwritten by buffy */
505         do_buffy_notify = 0;
506
507         menu->redraw = REDRAW_FULL;
508         menu->max = Context->vcount;
509
510         set_option (OPTSEARCHINVALID);
511       }
512     }
513
514     if (!attach_msg)
515     {
516      /* check for new mail in the incoming folders */
517      oldcount = newcount;
518      if ((newcount = mutt_buffy_check (0)) != oldcount)
519        menu->redraw |= REDRAW_STATUS;
520      if (do_buffy_notify)
521      {
522        if (mutt_buffy_notify () && option (OPTBEEPNEW))
523         beep ();
524      }
525      else
526        do_buffy_notify = 1;
527     }
528
529     if (op != -1)
530       mutt_curs_set (0);
531
532     if (menu->redraw & REDRAW_FULL)
533     {
534       menu_redraw_full (menu);
535       mutt_show_error ();
536     }
537
538     if (menu->menu == MENU_MAIN)
539     {
540       if (Context && Context->hdrs && !(menu->current >= Context->vcount))
541       {
542         menu_check_recenter (menu);
543
544         if (menu->redraw & REDRAW_INDEX)
545         {
546           menu_redraw_index (menu);
547           menu->redraw |= REDRAW_STATUS;
548         }
549         else if (menu->redraw & (REDRAW_MOTION_RESYNCH | REDRAW_MOTION))
550           menu_redraw_motion (menu);
551         else if (menu->redraw & REDRAW_CURRENT)
552           menu_redraw_current (menu);
553       }
554
555       if (menu->redraw & REDRAW_STATUS)
556       {
557         menu_status_line (buf, sizeof (buf), menu, NONULL (Status));
558         CLEARLINE (option (OPTSTATUSONTOP) ? 0 : LINES-2);
559         SETCOLOR (MT_COLOR_STATUS);
560         BKGDSET (MT_COLOR_STATUS);
561         mutt_paddstr (COLS, buf);
562         SETCOLOR (MT_COLOR_NORMAL);
563         BKGDSET (MT_COLOR_NORMAL);
564         menu->redraw &= ~REDRAW_STATUS;
565       }
566
567       menu->redraw = 0;
568       if (menu->current < menu->max)
569         menu->oldcurrent = menu->current;
570       else
571         menu->oldcurrent = -1;
572
573       if (option (OPTARROWCURSOR))
574         move (menu->current - menu->top + menu->offset, 2);
575       else if (option (OPTBRAILLEFRIENDLY))
576         move (menu->current - menu->top + menu->offset, 0);
577       else
578         move (menu->current - menu->top + menu->offset, COLS - 1);
579       mutt_refresh ();
580
581 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
582       if (SigWinch)
583       {
584         mutt_flushinp ();
585         mutt_resize_screen ();
586         menu->redraw = REDRAW_FULL;
587         menu->menu = MENU_MAIN;
588         SigWinch = 0;
589         menu->top = 0; /* so we scroll the right amount */
590         /*
591          * force a real complete redraw.  clrtobot() doesn't seem to be able
592          * to handle every case without this.
593          */
594         clearok(stdscr,TRUE);
595         continue;
596       }
597 #endif
598
599       op = km_dokey (MENU_MAIN);
600
601       dprint(4, (debugfile, "mutt_index_menu[%d]: Got op %d\n", __LINE__, op));
602
603       if (op == -1)
604         continue; /* either user abort or timeout */
605
606       mutt_curs_set (1);
607
608       /* special handling for the tag-prefix function */
609       if (op == OP_TAG_PREFIX)
610       {
611         if (!Context)
612         {
613           mutt_error _("No mailbox is open.");
614           continue;
615         }
616
617         if (!Context->tagged)
618         {
619           mutt_error _("No tagged messages.");
620           continue;
621         }
622         tag = 1;
623
624         /* give visual indication that the next command is a tag- command */
625         mvaddstr (LINES - 1, 0, "tag-");
626         clrtoeol ();
627
628         /* get the real command */
629         if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX)
630         {
631           /* abort tag sequence */
632           CLEARLINE (LINES-1);
633           continue;
634         }
635       }
636       else if (option (OPTAUTOTAG) && Context && Context->tagged)
637         tag = 1;
638
639       if (op == OP_TAG_PREFIX_COND)
640       {
641         if (!Context)
642         {
643           mutt_error _("No mailbox is open.");
644           continue;
645         }
646
647         if (!Context->tagged)
648         {
649           event_t tmp;
650           while(UngetCount>0)
651           {
652             tmp=mutt_getch();
653             if(tmp.op==OP_END_COND)break;
654           }
655           mutt_message  _("Nothing to do.");
656           continue;
657         }
658         tag = 1;
659
660         /* give visual indication that the next command is a tag- command */
661         mvaddstr (LINES - 1, 0, "tag-");
662         clrtoeol ();
663
664         /* get the real command */
665         if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX)
666         {
667           /* abort tag sequence */
668           CLEARLINE (LINES-1);
669           continue;
670         }
671       }
672
673       mutt_clear_error ();
674     }
675     else
676     {
677       if (menu->current < menu->max)
678         menu->oldcurrent = menu->current;
679       else
680         menu->oldcurrent = -1;
681
682       mutt_curs_set (1);        /* fallback from the pager */
683     }
684
685     switch (op)
686     {
687
688       /* ----------------------------------------------------------------------
689        * movement commands
690        */
691
692       case OP_BOTTOM_PAGE:
693         menu_bottom_page (menu);
694         break;
695       case OP_FIRST_ENTRY:
696         menu_first_entry (menu);
697         break;
698       case OP_MIDDLE_PAGE:
699         menu_middle_page (menu);
700         break;
701       case OP_HALF_UP:
702         menu_half_up (menu);
703         break;
704       case OP_HALF_DOWN:
705         menu_half_down (menu);
706         break;
707       case OP_NEXT_LINE:
708         menu_next_line (menu);
709         break;
710       case OP_PREV_LINE:
711         menu_prev_line (menu);
712         break;
713       case OP_NEXT_PAGE:
714         menu_next_page (menu);
715         break;
716       case OP_PREV_PAGE:
717         menu_prev_page (menu);
718         break;
719       case OP_LAST_ENTRY:
720         menu_last_entry (menu);
721         break;
722       case OP_TOP_PAGE:
723         menu_top_page (menu);
724         break;
725       case OP_CURRENT_TOP:
726         menu_current_top (menu);
727         break;
728       case OP_CURRENT_MIDDLE:
729         menu_current_middle (menu);
730         break;
731       case OP_CURRENT_BOTTOM:
732         menu_current_bottom (menu);
733         break;
734
735       case OP_JUMP:
736
737         CHECK_MSGCOUNT;
738         CHECK_VISIBLE;
739         if (isdigit (LastKey)) mutt_ungetch (LastKey, 0);
740         buf[0] = 0;
741         if (mutt_get_field (_("Jump to message: "), buf, sizeof (buf), 0) != 0
742             || !buf[0])
743           break;
744
745         if (mutt_atoi (buf, &i) < 0)
746         {
747           mutt_error _("Argument must be a message number.");
748           break;
749         }
750
751         if (i > 0 && i <= Context->msgcount)
752         {
753           for (j = i-1; j < Context->msgcount; j++)
754           {
755             if (Context->hdrs[j]->virtual != -1)
756               break;
757           }
758           if (j >= Context->msgcount)
759           {
760             for (j = i-2; j >= 0; j--)
761             {
762               if (Context->hdrs[j]->virtual != -1)
763                 break;
764             }
765           }
766
767           if (j >= 0)
768           {
769             menu->current = Context->hdrs[j]->virtual;
770             if (menu->menu == MENU_PAGER)
771             {
772               op = OP_DISPLAY_MESSAGE;
773               continue;
774             }
775             else
776             menu->redraw = REDRAW_MOTION;
777           }
778           else
779             mutt_error _("That message is not visible.");
780         }
781         else
782           mutt_error _("Invalid message number.");
783
784         break;
785
786         /* --------------------------------------------------------------------
787          * `index' specific commands
788          */
789
790       case OP_MAIN_DELETE_PATTERN:
791
792         CHECK_MSGCOUNT;
793         CHECK_VISIBLE;
794         CHECK_READONLY;
795         CHECK_ACL(M_ACL_DELETE, _("delete message(s)"));
796
797         CHECK_ATTACH;
798         mutt_pattern_func (M_DELETE, _("Delete messages matching: "));
799         menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
800         break;
801
802 #ifdef USE_POP
803       case OP_MAIN_FETCH_MAIL:
804
805         CHECK_ATTACH;
806         pop_fetch_mail ();
807         menu->redraw = REDRAW_FULL;
808         break;
809 #endif /* USE_POP */
810
811       case OP_HELP:
812
813         mutt_help (MENU_MAIN);
814         menu->redraw = REDRAW_FULL;
815         break;
816
817       case OP_MAIN_SHOW_LIMIT:
818         CHECK_IN_MAILBOX;
819         if (!Context->pattern)
820            mutt_message _("No limit pattern is in effect.");
821         else
822         {
823            char buf[STRING];
824            /* i18n: ask for a limit to apply */
825            snprintf (buf, sizeof(buf), _("Limit: %s"),Context->pattern);
826            mutt_message ("%s", buf);
827         }
828         break;
829
830       case OP_MAIN_LIMIT:
831
832         CHECK_IN_MAILBOX;
833         menu->oldcurrent = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ?
834                 CURHDR->index : -1;
835         if (mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
836         {
837           if (menu->oldcurrent >= 0)
838           {
839             /* try to find what used to be the current message */
840             menu->current = -1;
841             for (i = 0; i < Context->vcount; i++)
842               if (Context->hdrs[Context->v2r[i]]->index == menu->oldcurrent)
843               {
844                 menu->current = i;
845                 break;
846               }
847             if (menu->current < 0) menu->current = 0;
848           }
849           else
850             menu->current = 0;
851           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
852           if (Context->msgcount && (Sort & SORT_MASK) == SORT_THREADS)
853             mutt_draw_tree (Context);
854           menu->redraw = REDRAW_FULL;
855         }
856         if (Context->pattern)
857           mutt_message _("To view all messages, limit to \"all\".");
858         break;
859
860       case OP_QUIT:
861
862         close = op;
863         if (attach_msg)
864         {
865          done = 1;
866          break;
867         }
868
869         if (query_quadoption (OPT_QUIT, _("Quit Mutt?")) == M_YES)
870         {
871           int check;
872
873           oldcount = Context ? Context->msgcount : 0;
874
875           if (!Context || (check = mx_close_mailbox (Context, &index_hint)) == 0)
876             done = 1;
877           else
878           {
879             if (check == M_NEW_MAIL || check == M_REOPENED)
880               update_index (menu, Context, check, oldcount, index_hint);
881
882             menu->redraw = REDRAW_FULL; /* new mail arrived? */
883             set_option (OPTSEARCHINVALID);
884           }
885         }
886         break;
887
888       case OP_REDRAW:
889
890         clearok (stdscr, TRUE);
891         menu->redraw = REDRAW_FULL;
892         break;
893
894       case OP_SEARCH:
895       case OP_SEARCH_REVERSE:
896       case OP_SEARCH_NEXT:
897       case OP_SEARCH_OPPOSITE:
898
899         CHECK_MSGCOUNT;
900         CHECK_VISIBLE;
901         if ((menu->current = mutt_search_command (menu->current, op)) == -1)
902           menu->current = menu->oldcurrent;
903         else
904           menu->redraw = REDRAW_MOTION;
905         break;
906
907       case OP_SORT:
908       case OP_SORT_REVERSE:
909
910         if (mutt_select_sort ((op == OP_SORT_REVERSE)) == 0)
911         {
912           if (Context && Context->msgcount)
913           {
914             resort_index (menu);
915             set_option (OPTSEARCHINVALID);
916           }
917           if (menu->menu == MENU_PAGER)
918           {
919             op = OP_DISPLAY_MESSAGE;
920             continue;
921           }
922           menu->redraw |= REDRAW_STATUS;
923         }
924         break;
925
926       case OP_TAG:
927
928         CHECK_MSGCOUNT;
929         CHECK_VISIBLE;
930         if (tag && !option (OPTAUTOTAG))
931         {
932           for (j = 0; j < Context->vcount; j++)
933             mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_TAG, 0);
934           menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
935         }
936         else
937         {
938           mutt_set_flag (Context, CURHDR, M_TAG, !CURHDR->tagged);
939
940           Context->last_tag = CURHDR->tagged ? CURHDR :
941             ((Context->last_tag == CURHDR && !CURHDR->tagged)
942              ? NULL : Context->last_tag);
943
944           menu->redraw = REDRAW_STATUS;
945           if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
946           {
947             menu->current++;
948             menu->redraw |= REDRAW_MOTION_RESYNCH;
949           }
950           else
951             menu->redraw |= REDRAW_CURRENT;
952         }
953         break;
954
955       case OP_MAIN_TAG_PATTERN:
956
957         CHECK_MSGCOUNT;
958         CHECK_VISIBLE;
959         mutt_pattern_func (M_TAG, _("Tag messages matching: "));
960         menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
961         break;
962
963       case OP_MAIN_UNDELETE_PATTERN:
964
965         CHECK_MSGCOUNT;
966         CHECK_VISIBLE;
967         CHECK_READONLY;
968         CHECK_ACL(M_ACL_DELETE, _("undelete message(s)"));
969
970         if (mutt_pattern_func (M_UNDELETE, _("Undelete messages matching: ")) == 0)
971           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
972         break;
973
974       case OP_MAIN_UNTAG_PATTERN:
975
976         CHECK_MSGCOUNT;
977         CHECK_VISIBLE;
978         if (mutt_pattern_func (M_UNTAG, _("Untag messages matching: ")) == 0)
979           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
980         break;
981
982         /* --------------------------------------------------------------------
983          * The following operations can be performed inside of the pager.
984          */
985
986 #ifdef USE_IMAP
987       case OP_MAIN_IMAP_FETCH:
988         if (Context && Context->magic == M_IMAP)
989           imap_check_mailbox (Context, &index_hint, 1);
990         break;
991
992       case OP_MAIN_IMAP_LOGOUT_ALL:
993         if (Context && Context->magic == M_IMAP)
994         {
995           if (mx_close_mailbox (Context, &index_hint) != 0)
996           {
997             set_option (OPTSEARCHINVALID);
998             menu->redraw = REDRAW_FULL;
999             break;
1000           }
1001           FREE (&Context);
1002         }
1003         imap_logout_all();
1004         mutt_message _("Logged out of IMAP servers.");
1005         set_option (OPTSEARCHINVALID);
1006         menu->redraw = REDRAW_FULL;
1007         break;
1008 #endif
1009
1010       case OP_MAIN_SYNC_FOLDER:
1011
1012         if (Context && !Context->msgcount)
1013           break;
1014
1015         CHECK_MSGCOUNT;
1016         CHECK_VISIBLE;
1017         CHECK_READONLY;
1018         {
1019           int oldvcount = Context->vcount;
1020           int oldcount  = Context->msgcount;
1021           int check, newidx;
1022           HEADER *newhdr = NULL;
1023
1024           /* threads may be reordered, so figure out what header the cursor
1025            * should be on. #3092 */
1026           newidx = menu->current;
1027           if (CURHDR->deleted)
1028             newidx = ci_next_undeleted (menu->current);
1029           if (newidx < 0)
1030             newidx = ci_previous_undeleted (menu->current);
1031           if (newidx >= 0)
1032             newhdr = Context->hdrs[Context->v2r[newidx]];
1033
1034           if ((check = mx_sync_mailbox (Context, &index_hint)) == 0)
1035           {
1036             if (newhdr && Context->vcount != oldvcount)
1037               for (j = 0; j < Context->vcount; j++)
1038               {
1039                 if (Context->hdrs[Context->v2r[j]] == newhdr)
1040                 {
1041                   menu->current = j;
1042                   break;
1043                 }
1044               }
1045             set_option (OPTSEARCHINVALID);
1046           }
1047           else if (check == M_NEW_MAIL || check == M_REOPENED)
1048             update_index (menu, Context, check, oldcount, index_hint);
1049
1050           /*
1051            * do a sanity check even if mx_sync_mailbox failed.
1052            */
1053
1054           if (menu->current < 0 || menu->current >= Context->vcount)
1055             menu->current = ci_first_message ();
1056         }
1057
1058         /* check for a fatal error, or all messages deleted */
1059         if (!Context->path)
1060           FREE (&Context);
1061
1062         /* if we were in the pager, redisplay the message */
1063         if (menu->menu == MENU_PAGER)
1064         {
1065           op = OP_DISPLAY_MESSAGE;
1066           continue;
1067         }
1068         else
1069           menu->redraw = REDRAW_FULL;
1070         break;
1071
1072       case OP_MAIN_CHANGE_FOLDER:
1073       case OP_MAIN_NEXT_UNREAD_MAILBOX:
1074
1075         if (attach_msg)
1076           op = OP_MAIN_CHANGE_FOLDER_READONLY;
1077
1078         /* fallback to the readonly case */
1079
1080       case OP_MAIN_CHANGE_FOLDER_READONLY:
1081
1082         if ((op == OP_MAIN_CHANGE_FOLDER_READONLY) || option (OPTREADONLY))
1083           cp = _("Open mailbox in read-only mode");
1084         else
1085           cp = _("Open mailbox");
1086
1087         buf[0] = '\0';
1088         if ((op == OP_MAIN_NEXT_UNREAD_MAILBOX) && Context && Context->path)
1089         {
1090           strfcpy (buf, Context->path, sizeof (buf));
1091           mutt_pretty_mailbox (buf, sizeof (buf));
1092           mutt_buffy (buf, sizeof (buf));
1093           if (!buf[0])
1094           {
1095             mutt_error _("No mailboxes have new mail");
1096             break;
1097           }
1098         }
1099         else
1100         {
1101           mutt_buffy (buf, sizeof (buf));
1102
1103           if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
1104           {
1105             if (menu->menu == MENU_PAGER)
1106             {
1107               op = OP_DISPLAY_MESSAGE;
1108               continue;
1109             }
1110             else
1111               break;
1112           }
1113           if (!buf[0])
1114           {
1115             CLEARLINE (LINES-1);
1116             break;
1117           }
1118         }
1119
1120         mutt_expand_path (buf, sizeof (buf));
1121         if (mx_get_magic (buf) <= 0)
1122         {
1123           mutt_error (_("%s is not a mailbox."), buf);
1124           break;
1125         }
1126         mutt_str_replace (&CurrentFolder, buf);
1127
1128         /* keepalive failure in mutt_enter_fname may kill connection. #3028 */
1129         if (Context && !Context->path)
1130           FREE (&Context);
1131
1132         if (Context)
1133         {
1134           int check;
1135
1136           mutt_str_replace (&LastFolder, Context->path);
1137           oldcount = Context ? Context->msgcount : 0;
1138
1139           if ((check = mx_close_mailbox (Context, &index_hint)) != 0)
1140           {
1141             if (check == M_NEW_MAIL || check == M_REOPENED)
1142               update_index (menu, Context, check, oldcount, index_hint);
1143
1144             set_option (OPTSEARCHINVALID);
1145             menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1146             break;
1147           }
1148           FREE (&Context);
1149         }
1150
1151         mutt_sleep (0);
1152
1153         /* Set CurrentMenu to MENU_MAIN before executing any folder
1154          * hooks so that all the index menu functions are available to
1155          * the exec command.
1156          */
1157
1158         CurrentMenu = MENU_MAIN;
1159         mutt_folder_hook (buf);
1160
1161         if ((Context = mx_open_mailbox (buf,
1162                                         (option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
1163                                         M_READONLY : 0, NULL)) != NULL)
1164         {
1165           menu->current = ci_first_message ();
1166         }
1167         else
1168           menu->current = 0;
1169
1170         mutt_clear_error ();
1171         mutt_buffy_check(1); /* force the buffy check after we have changed
1172                               the folder */
1173         menu->redraw = REDRAW_FULL;
1174         set_option (OPTSEARCHINVALID);
1175         break;
1176
1177       case OP_DISPLAY_MESSAGE:
1178       case OP_DISPLAY_HEADERS: /* don't weed the headers */
1179
1180         CHECK_MSGCOUNT;
1181         CHECK_VISIBLE;
1182         /*
1183          * toggle the weeding of headers so that a user can press the key
1184          * again while reading the message.
1185          */
1186         if (op == OP_DISPLAY_HEADERS)
1187           toggle_option (OPTWEED);
1188
1189         unset_option (OPTNEEDRESORT);
1190
1191         if ((Sort & SORT_MASK) == SORT_THREADS && CURHDR->collapsed)
1192         {
1193           mutt_uncollapse_thread (Context, CURHDR);
1194           mutt_set_virtual (Context);
1195           if (option (OPTUNCOLLAPSEJUMP))
1196             menu->current = mutt_thread_next_unread (Context, CURHDR);
1197         }
1198
1199         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1200           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1201         if ((op = mutt_display_message (CURHDR)) == -1)
1202         {
1203           unset_option (OPTNEEDRESORT);
1204           break;
1205         }
1206
1207         menu->menu = MENU_PAGER;
1208         menu->oldcurrent = menu->current;
1209         continue;
1210
1211       case OP_EXIT:
1212
1213         close = op;
1214         if (menu->menu == MENU_MAIN && attach_msg)
1215         {
1216          done = 1;
1217          break;
1218         }
1219
1220         if ((menu->menu == MENU_MAIN)
1221             && (query_quadoption (OPT_QUIT,
1222                                   _("Exit Mutt without saving?")) == M_YES))
1223         {
1224           if (Context)
1225           {
1226             mx_fastclose_mailbox (Context);
1227             FREE (&Context);
1228           }
1229           done = 1;
1230         }
1231         break;
1232
1233       case OP_MAIN_BREAK_THREAD:
1234
1235         CHECK_MSGCOUNT;
1236         CHECK_VISIBLE;
1237         CHECK_READONLY;
1238
1239         if ((Sort & SORT_MASK) != SORT_THREADS)
1240           mutt_error _("Threading is not enabled.");
1241         else if (CURHDR->env->in_reply_to || CURHDR->env->references)
1242         {
1243           {
1244             HEADER *oldcur = CURHDR;
1245
1246             mutt_break_thread (CURHDR);
1247             mutt_sort_headers (Context, 1);
1248             menu->current = oldcur->virtual;
1249           }
1250
1251           Context->changed = 1;
1252           mutt_message _("Thread broken");
1253
1254           if (menu->menu == MENU_PAGER)
1255           {
1256             op = OP_DISPLAY_MESSAGE;
1257             continue;
1258           }
1259           else
1260             menu->redraw |= REDRAW_INDEX;
1261         }
1262         else
1263           mutt_error _("Thread cannot be broken, message is not part of a thread");
1264
1265         break;
1266
1267       case OP_MAIN_LINK_THREADS:
1268
1269         CHECK_MSGCOUNT;
1270         CHECK_VISIBLE;
1271         CHECK_READONLY;
1272         CHECK_ACL(M_ACL_DELETE, _("link threads"));
1273
1274         if ((Sort & SORT_MASK) != SORT_THREADS)
1275           mutt_error _("Threading is not enabled.");
1276         else if (!CURHDR->env->message_id)
1277           mutt_error _("No Message-ID: header available to link thread");
1278         else if (!tag && (!Context->last_tag || !Context->last_tag->tagged))
1279           mutt_error _("First, please tag a message to be linked here");
1280         else
1281         {
1282           HEADER *oldcur = CURHDR;
1283
1284           if (mutt_link_threads (CURHDR, tag ? NULL : Context->last_tag,
1285                                  Context))
1286           {
1287             mutt_sort_headers (Context, 1);
1288             menu->current = oldcur->virtual;
1289
1290             Context->changed = 1;
1291             mutt_message _("Threads linked");
1292           }
1293           else
1294             mutt_error _("No thread linked");
1295         }
1296
1297         if (menu->menu == MENU_PAGER)
1298         {
1299           op = OP_DISPLAY_MESSAGE;
1300           continue;
1301         }
1302         else
1303           menu->redraw |= REDRAW_STATUS | REDRAW_INDEX;
1304
1305         break;
1306
1307       case OP_EDIT_TYPE:
1308
1309         CHECK_MSGCOUNT;
1310         CHECK_VISIBLE;
1311         CHECK_ATTACH;
1312         mutt_edit_content_type (CURHDR, CURHDR->content, NULL);
1313         /* if we were in the pager, redisplay the message */
1314         if (menu->menu == MENU_PAGER)
1315         {
1316           op = OP_DISPLAY_MESSAGE;
1317           continue;
1318         }
1319         else
1320           menu->redraw = REDRAW_CURRENT;
1321         break;
1322
1323       case OP_MAIN_NEXT_UNDELETED:
1324
1325         CHECK_MSGCOUNT;
1326         CHECK_VISIBLE;
1327         if (menu->current >= Context->vcount - 1)
1328         {
1329           if (menu->menu == MENU_MAIN)
1330             mutt_error _("You are on the last message.");
1331           break;
1332         }
1333         if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1334         {
1335           menu->current = menu->oldcurrent;
1336           if (menu->menu == MENU_MAIN)
1337             mutt_error _("No undeleted messages.");
1338         }
1339         else 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_NEXT_ENTRY:
1349
1350         CHECK_MSGCOUNT;
1351         CHECK_VISIBLE;
1352         if (menu->current >= Context->vcount - 1)
1353         {
1354           if (menu->menu == MENU_MAIN)
1355             mutt_error _("You are on the last message.");
1356           break;
1357         }
1358         menu->current++;
1359         if (menu->menu == MENU_PAGER)
1360         {
1361           op = OP_DISPLAY_MESSAGE;
1362           continue;
1363         }
1364         else
1365           menu->redraw = REDRAW_MOTION;
1366         break;
1367
1368       case OP_MAIN_PREV_UNDELETED:
1369
1370         CHECK_MSGCOUNT;
1371         CHECK_VISIBLE;
1372         if (menu->current < 1)
1373         {
1374           mutt_error _("You are on the first message.");
1375           break;
1376         }
1377         if ((menu->current = ci_previous_undeleted (menu->current)) == -1)
1378         {
1379           menu->current = menu->oldcurrent;
1380           if (menu->menu == MENU_MAIN)
1381             mutt_error _("No undeleted messages.");
1382         }
1383         else if (menu->menu == MENU_PAGER)
1384         {
1385           op = OP_DISPLAY_MESSAGE;
1386           continue;
1387         }
1388         else
1389           menu->redraw = REDRAW_MOTION;
1390         break;
1391
1392       case OP_PREV_ENTRY:
1393
1394         CHECK_MSGCOUNT;
1395         CHECK_VISIBLE;
1396         if (menu->current < 1)
1397         {
1398           if (menu->menu == MENU_MAIN) mutt_error _("You are on the first message.");
1399           break;
1400         }
1401         menu->current--;
1402         if (menu->menu == MENU_PAGER)
1403         {
1404           op = OP_DISPLAY_MESSAGE;
1405           continue;
1406         }
1407         else
1408           menu->redraw = REDRAW_MOTION;
1409         break;
1410
1411       case OP_DECRYPT_COPY:
1412       case OP_DECRYPT_SAVE:
1413         if (!WithCrypto)
1414           break;
1415         /* fall thru */
1416       case OP_COPY_MESSAGE:
1417       case OP_SAVE:
1418       case OP_DECODE_COPY:
1419       case OP_DECODE_SAVE:
1420         CHECK_MSGCOUNT;
1421         CHECK_VISIBLE;
1422         if (mutt_save_message (tag ? NULL : CURHDR,
1423                                (op == OP_DECRYPT_SAVE) ||
1424                                (op == OP_SAVE) || (op == OP_DECODE_SAVE),
1425                                (op == OP_DECODE_SAVE) || (op == OP_DECODE_COPY),
1426                                (op == OP_DECRYPT_SAVE) || (op == OP_DECRYPT_COPY) ||
1427                                0,
1428                                &menu->redraw) == 0 &&
1429              (op == OP_SAVE || op == OP_DECODE_SAVE || op == OP_DECRYPT_SAVE)
1430             )
1431         {
1432           if (tag)
1433             menu->redraw |= REDRAW_INDEX;
1434           else if (option (OPTRESOLVE))
1435           {
1436             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1437             {
1438               menu->current = menu->oldcurrent;
1439               menu->redraw |= REDRAW_CURRENT;
1440             }
1441             else
1442               menu->redraw |= REDRAW_MOTION_RESYNCH;
1443           }
1444           else
1445             menu->redraw |= REDRAW_CURRENT;
1446         }
1447         break;
1448
1449       case OP_MAIN_NEXT_NEW:
1450       case OP_MAIN_NEXT_UNREAD:
1451       case OP_MAIN_PREV_NEW:
1452       case OP_MAIN_PREV_UNREAD:
1453       case OP_MAIN_NEXT_NEW_THEN_UNREAD:
1454       case OP_MAIN_PREV_NEW_THEN_UNREAD:
1455
1456       {
1457         int first_unread = -1;
1458         int first_new    = -1;
1459
1460         CHECK_MSGCOUNT;
1461         CHECK_VISIBLE;
1462
1463         i = menu->current;
1464         menu->current = -1;
1465         for (j = 0; j != Context->vcount; j++)
1466         {
1467 #define CURHDRi Context->hdrs[Context->v2r[i]]
1468           if (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_NEXT_NEW_THEN_UNREAD)
1469           {
1470             i++;
1471             if (i > Context->vcount - 1)
1472             {
1473               mutt_message _("Search wrapped to top.");
1474               i = 0;
1475             }
1476           }
1477           else
1478           {
1479             i--;
1480             if (i < 0)
1481             {
1482               mutt_message _("Search wrapped to bottom.");
1483               i = Context->vcount - 1;
1484             }
1485           }
1486
1487           if (CURHDRi->collapsed && (Sort & SORT_MASK) == SORT_THREADS)
1488           {
1489             if (UNREAD (CURHDRi) && first_unread == -1)
1490               first_unread = i;
1491             if (UNREAD (CURHDRi) == 1 && first_new == -1)
1492               first_new = i;
1493           }
1494           else if ((!CURHDRi->deleted && !CURHDRi->read))
1495           {
1496             if (first_unread == -1)
1497               first_unread = i;
1498             if ((!CURHDRi->old) && first_new == -1)
1499               first_new = i;
1500           }
1501
1502           if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD) &&
1503               first_unread != -1)
1504             break;
1505           if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
1506                op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1507               && first_new != -1)
1508             break;
1509         }
1510 #undef CURHDRi
1511         if ((op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW ||
1512              op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1513             && first_new != -1)
1514           menu->current = first_new;
1515         else if ((op == OP_MAIN_NEXT_UNREAD || op == OP_MAIN_PREV_UNREAD ||
1516                   op == OP_MAIN_NEXT_NEW_THEN_UNREAD || op == OP_MAIN_PREV_NEW_THEN_UNREAD)
1517                  && first_unread != -1)
1518           menu->current = first_unread;
1519
1520         if (menu->current == -1)
1521         {
1522           menu->current = menu->oldcurrent;
1523           mutt_error ("%s%s.", (op == OP_MAIN_NEXT_NEW || op == OP_MAIN_PREV_NEW) ? _("No new messages") : _("No unread messages"),
1524                       Context->pattern ? _(" in this limited view") : "");
1525         }
1526         else if (menu->menu == MENU_PAGER)
1527         {
1528           op = OP_DISPLAY_MESSAGE;
1529           continue;
1530         }
1531         else
1532           menu->redraw = REDRAW_MOTION;
1533         break;
1534       }
1535       case OP_FLAG_MESSAGE:
1536
1537         CHECK_MSGCOUNT;
1538         CHECK_VISIBLE;
1539         CHECK_READONLY;
1540         CHECK_ACL(M_ACL_WRITE, _("flag message"));
1541
1542         if (tag)
1543         {
1544           for (j = 0; j < Context->vcount; j++)
1545           {
1546             if (Context->hdrs[Context->v2r[j]]->tagged)
1547               mutt_set_flag (Context, Context->hdrs[Context->v2r[j]],
1548                              M_FLAG, !Context->hdrs[Context->v2r[j]]->flagged);
1549           }
1550
1551           menu->redraw |= REDRAW_INDEX;
1552         }
1553         else
1554         {
1555           mutt_set_flag (Context, CURHDR, M_FLAG, !CURHDR->flagged);
1556           if (option (OPTRESOLVE))
1557           {
1558             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1559             {
1560               menu->current = menu->oldcurrent;
1561               menu->redraw = REDRAW_CURRENT;
1562             }
1563             else
1564               menu->redraw = REDRAW_MOTION_RESYNCH;
1565           }
1566           else
1567             menu->redraw = REDRAW_CURRENT;
1568         }
1569         menu->redraw |= REDRAW_STATUS;
1570         break;
1571
1572       case OP_TOGGLE_NEW:
1573
1574         CHECK_MSGCOUNT;
1575         CHECK_VISIBLE;
1576         CHECK_READONLY;
1577         CHECK_ACL(M_ACL_SEEN, _("toggle new"));
1578
1579         if (tag)
1580         {
1581           for (j = 0; j < Context->vcount; j++)
1582           {
1583             if (Context->hdrs[Context->v2r[j]]->tagged)
1584             {
1585               if (Context->hdrs[Context->v2r[j]]->read ||
1586                   Context->hdrs[Context->v2r[j]]->old)
1587                 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_NEW, 1);
1588               else
1589                 mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], M_READ, 1);
1590             }
1591           }
1592           menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
1593         }
1594         else
1595         {
1596           if (CURHDR->read || CURHDR->old)
1597             mutt_set_flag (Context, CURHDR, M_NEW, 1);
1598           else
1599             mutt_set_flag (Context, CURHDR, M_READ, 1);
1600
1601           if (option (OPTRESOLVE))
1602           {
1603             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1604             {
1605               menu->current = menu->oldcurrent;
1606               menu->redraw = REDRAW_CURRENT;
1607             }
1608             else
1609               menu->redraw = REDRAW_MOTION_RESYNCH;
1610           }
1611           else
1612             menu->redraw = REDRAW_CURRENT;
1613           menu->redraw |= REDRAW_STATUS;
1614         }
1615         break;
1616
1617       case OP_TOGGLE_WRITE:
1618
1619         CHECK_IN_MAILBOX;
1620         if (mx_toggle_write (Context) == 0)
1621           menu->redraw |= REDRAW_STATUS;
1622         break;
1623
1624       case OP_MAIN_NEXT_THREAD:
1625       case OP_MAIN_NEXT_SUBTHREAD:
1626       case OP_MAIN_PREV_THREAD:
1627       case OP_MAIN_PREV_SUBTHREAD:
1628
1629         CHECK_MSGCOUNT;
1630         CHECK_VISIBLE;
1631         switch (op)
1632         {
1633           case OP_MAIN_NEXT_THREAD:
1634             menu->current = mutt_next_thread (CURHDR);
1635             break;
1636
1637           case OP_MAIN_NEXT_SUBTHREAD:
1638             menu->current = mutt_next_subthread (CURHDR);
1639             break;
1640
1641           case OP_MAIN_PREV_THREAD:
1642             menu->current = mutt_previous_thread (CURHDR);
1643             break;
1644
1645           case OP_MAIN_PREV_SUBTHREAD:
1646             menu->current = mutt_previous_subthread (CURHDR);
1647             break;
1648         }
1649
1650         if (menu->current < 0)
1651         {
1652           menu->current = menu->oldcurrent;
1653           if (op == OP_MAIN_NEXT_THREAD || op == OP_MAIN_NEXT_SUBTHREAD)
1654             mutt_error _("No more threads.");
1655           else
1656             mutt_error _("You are on the first thread.");
1657         }
1658         else if (menu->menu == MENU_PAGER)
1659         {
1660           op = OP_DISPLAY_MESSAGE;
1661           continue;
1662         }
1663         else
1664           menu->redraw = REDRAW_MOTION;
1665         break;
1666
1667       case OP_MAIN_PARENT_MESSAGE:
1668
1669         CHECK_MSGCOUNT;
1670         CHECK_VISIBLE;
1671
1672         if ((menu->current = mutt_parent_message (Context, CURHDR)) < 0)
1673         {
1674           menu->current = menu->oldcurrent;
1675         }
1676         else if (menu->menu == MENU_PAGER)
1677         {
1678           op = OP_DISPLAY_MESSAGE;
1679           continue;
1680         }
1681         else
1682           menu->redraw = REDRAW_MOTION;
1683         break;
1684
1685       case OP_MAIN_SET_FLAG:
1686       case OP_MAIN_CLEAR_FLAG:
1687
1688         CHECK_MSGCOUNT;
1689         CHECK_VISIBLE;
1690         CHECK_READONLY;
1691         /* CHECK_ACL(M_ACL_WRITE); */
1692
1693         if (mutt_change_flag (tag ? NULL : CURHDR, (op == OP_MAIN_SET_FLAG)) == 0)
1694         {
1695           menu->redraw = REDRAW_STATUS;
1696           if (tag)
1697             menu->redraw |= REDRAW_INDEX;
1698           else if (option (OPTRESOLVE))
1699           {
1700             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1701             {
1702               menu->current = menu->oldcurrent;
1703               menu->redraw |= REDRAW_CURRENT;
1704             }
1705             else
1706               menu->redraw |= REDRAW_MOTION_RESYNCH;
1707           }
1708           else
1709             menu->redraw |= REDRAW_CURRENT;
1710         }
1711         break;
1712
1713       case OP_MAIN_COLLAPSE_THREAD:
1714         CHECK_MSGCOUNT;
1715         CHECK_VISIBLE;
1716
1717         if ((Sort & SORT_MASK) != SORT_THREADS)
1718         {
1719           mutt_error _("Threading is not enabled.");
1720           break;
1721         }
1722
1723         if (CURHDR->collapsed)
1724         {
1725           menu->current = mutt_uncollapse_thread (Context, CURHDR);
1726           mutt_set_virtual (Context);
1727           if (option (OPTUNCOLLAPSEJUMP))
1728             menu->current = mutt_thread_next_unread (Context, CURHDR);
1729         }
1730         else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR))
1731         {
1732           menu->current = mutt_collapse_thread (Context, CURHDR);
1733           mutt_set_virtual (Context);
1734         }
1735         else
1736         {
1737           mutt_error _("Thread contains unread messages.");
1738           break;
1739         }
1740
1741         menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1742
1743        break;
1744
1745       case OP_MAIN_COLLAPSE_ALL:
1746         CHECK_MSGCOUNT;
1747         CHECK_VISIBLE;
1748
1749         if ((Sort & SORT_MASK) != SORT_THREADS)
1750         {
1751           mutt_error _("Threading is not enabled.");
1752           break;
1753         }
1754
1755         {
1756           HEADER *h, *base;
1757           THREAD *thread, *top;
1758           int final;
1759
1760           if (CURHDR->collapsed)
1761             final = mutt_uncollapse_thread (Context, CURHDR);
1762           else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (CURHDR))
1763             final = mutt_collapse_thread (Context, CURHDR);
1764           else
1765             final = CURHDR->virtual;
1766
1767           base = Context->hdrs[Context->v2r[final]];
1768
1769           top = Context->tree;
1770           Context->collapsed = !Context->collapsed;
1771           while ((thread = top) != NULL)
1772           {
1773             while (!thread->message)
1774               thread = thread->child;
1775             h = thread->message;
1776
1777             if (h->collapsed != Context->collapsed)
1778             {
1779               if (h->collapsed)
1780                 mutt_uncollapse_thread (Context, h);
1781               else if (option (OPTCOLLAPSEUNREAD) || !UNREAD (h))
1782                 mutt_collapse_thread (Context, h);
1783             }
1784             top = top->next;
1785           }
1786
1787           mutt_set_virtual (Context);
1788           for (j = 0; j < Context->vcount; j++)
1789           {
1790             if (Context->hdrs[Context->v2r[j]]->index == base->index)
1791             {
1792               menu->current = j;
1793               break;
1794             }
1795           }
1796
1797           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1798         }
1799         break;
1800
1801       /* --------------------------------------------------------------------
1802        * These functions are invoked directly from the internal-pager
1803        */
1804
1805       case OP_BOUNCE_MESSAGE:
1806
1807         CHECK_ATTACH;
1808         CHECK_MSGCOUNT;
1809         CHECK_VISIBLE;
1810         ci_bounce_message (tag ? NULL : CURHDR, &menu->redraw);
1811         break;
1812
1813       case OP_CREATE_ALIAS:
1814
1815         mutt_create_alias (Context && Context->vcount ? CURHDR->env : NULL, NULL);
1816         MAYBE_REDRAW (menu->redraw);
1817         menu->redraw |= REDRAW_CURRENT;
1818         break;
1819
1820       case OP_QUERY:
1821         CHECK_ATTACH;
1822         mutt_query_menu (NULL, 0);
1823         MAYBE_REDRAW (menu->redraw);
1824         break;
1825
1826       case OP_DELETE:
1827
1828         CHECK_MSGCOUNT;
1829         CHECK_VISIBLE;
1830         CHECK_READONLY;
1831         CHECK_ACL(M_ACL_DELETE, _("delete message"));
1832
1833         if (tag)
1834         {
1835           mutt_tag_set_flag (M_DELETE, 1);
1836           if (option (OPTDELETEUNTAG))
1837             mutt_tag_set_flag (M_TAG, 0);
1838           menu->redraw = REDRAW_INDEX;
1839         }
1840         else
1841         {
1842           mutt_set_flag (Context, CURHDR, M_DELETE, 1);
1843           if (option (OPTDELETEUNTAG))
1844             mutt_set_flag (Context, CURHDR, M_TAG, 0);
1845           if (option (OPTRESOLVE))
1846           {
1847             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1848             {
1849               menu->current = menu->oldcurrent;
1850               menu->redraw = REDRAW_CURRENT;
1851             }
1852             else if (menu->menu == MENU_PAGER)
1853             {
1854               op = OP_DISPLAY_MESSAGE;
1855               continue;
1856             }
1857             else
1858               menu->redraw |= REDRAW_MOTION_RESYNCH;
1859           }
1860           else
1861             menu->redraw = REDRAW_CURRENT;
1862         }
1863         menu->redraw |= REDRAW_STATUS;
1864         break;
1865
1866       case OP_DELETE_THREAD:
1867       case OP_DELETE_SUBTHREAD:
1868
1869         CHECK_MSGCOUNT;
1870         CHECK_VISIBLE;
1871         CHECK_READONLY;
1872         CHECK_ACL(M_ACL_DELETE, _("delete message(s)"));
1873
1874         rc = mutt_thread_set_flag (CURHDR, M_DELETE, 1,
1875                                    op == OP_DELETE_THREAD ? 0 : 1);
1876
1877         if (rc != -1)
1878         {
1879           if (option (OPTDELETEUNTAG))
1880             mutt_thread_set_flag (CURHDR, M_TAG, 0,
1881                                   op == OP_DELETE_THREAD ? 0 : 1);
1882           if (option (OPTRESOLVE))
1883             if ((menu->current = ci_next_undeleted (menu->current)) == -1)
1884               menu->current = menu->oldcurrent;
1885           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
1886         }
1887         break;
1888
1889       case OP_DISPLAY_ADDRESS:
1890
1891         CHECK_MSGCOUNT;
1892         CHECK_VISIBLE;
1893         mutt_display_address (CURHDR->env);
1894         break;
1895
1896       case OP_ENTER_COMMAND:
1897
1898         CurrentMenu = MENU_MAIN;
1899         mutt_enter_command ();
1900         mutt_check_rescore (Context);
1901         if (option (OPTFORCEREDRAWINDEX))
1902           menu->redraw = REDRAW_FULL;
1903         unset_option (OPTFORCEREDRAWINDEX);
1904         unset_option (OPTFORCEREDRAWPAGER);
1905         break;
1906
1907       case OP_EDIT_MESSAGE:
1908
1909         CHECK_MSGCOUNT;
1910         CHECK_VISIBLE;
1911         CHECK_READONLY;
1912         CHECK_ATTACH;
1913         CHECK_ACL(M_ACL_INSERT, _("edit message"));
1914
1915         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1916           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1917         mutt_edit_message (Context, tag ? NULL : CURHDR);
1918         menu->redraw = REDRAW_FULL;
1919
1920         break;
1921
1922       case OP_FORWARD_MESSAGE:
1923
1924         CHECK_MSGCOUNT;
1925         CHECK_VISIBLE;
1926         CHECK_ATTACH;
1927         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1928           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1929         ci_send_message (SENDFORWARD, NULL, NULL, Context, tag ? NULL : CURHDR);
1930         menu->redraw = REDRAW_FULL;
1931         break;
1932
1933
1934       case OP_FORGET_PASSPHRASE:
1935         crypt_forget_passphrase ();
1936         break;
1937
1938       case OP_GROUP_REPLY:
1939
1940         CHECK_MSGCOUNT;
1941         CHECK_VISIBLE;
1942         CHECK_ATTACH;
1943         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1944           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1945         ci_send_message (SENDREPLY|SENDGROUPREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
1946         menu->redraw = REDRAW_FULL;
1947         break;
1948
1949       case OP_LIST_REPLY:
1950
1951         CHECK_ATTACH;
1952         CHECK_MSGCOUNT;
1953         CHECK_VISIBLE;
1954         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
1955           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1956         ci_send_message (SENDREPLY|SENDLISTREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
1957         menu->redraw = REDRAW_FULL;
1958         break;
1959
1960       case OP_MAIL:
1961
1962         CHECK_ATTACH;
1963         ci_send_message (0, NULL, NULL, Context, NULL);
1964         menu->redraw = REDRAW_FULL;
1965         break;
1966
1967       case OP_MAIL_KEY:
1968         if (!(WithCrypto & APPLICATION_PGP))
1969           break;
1970         CHECK_ATTACH;
1971         ci_send_message (SENDKEY, NULL, NULL, NULL, NULL);
1972         menu->redraw = REDRAW_FULL;
1973         break;
1974
1975
1976       case OP_EXTRACT_KEYS:
1977         if (!WithCrypto)
1978           break;
1979         CHECK_MSGCOUNT;
1980         CHECK_VISIBLE;
1981         crypt_extract_keys_from_messages(tag ? NULL : CURHDR);
1982         menu->redraw = REDRAW_FULL;
1983         break;
1984
1985
1986       case OP_CHECK_TRADITIONAL:
1987         if (!(WithCrypto & APPLICATION_PGP))
1988           break;
1989         CHECK_MSGCOUNT;
1990         CHECK_VISIBLE;
1991         if (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED))
1992           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
1993
1994         if (menu->menu == MENU_PAGER)
1995         {
1996           op = OP_DISPLAY_MESSAGE;
1997           continue;
1998         }
1999         break;
2000
2001       case OP_PIPE:
2002
2003         CHECK_MSGCOUNT;
2004         CHECK_VISIBLE;
2005         mutt_pipe_message (tag ? NULL : CURHDR);
2006
2007 #ifdef USE_IMAP
2008         /* in an IMAP folder index with imap_peek=no, piping could change
2009          * new or old messages status to read. Redraw what's needed.
2010          */
2011         if (Context->magic == M_IMAP && !option (OPTIMAPPEEK))
2012         {
2013           menu->redraw = (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
2014         }
2015 #endif
2016
2017         MAYBE_REDRAW (menu->redraw);
2018         break;
2019
2020       case OP_PRINT:
2021
2022         CHECK_MSGCOUNT;
2023         CHECK_VISIBLE;
2024         mutt_print_message (tag ? NULL : CURHDR);
2025
2026 #ifdef USE_IMAP
2027         /* in an IMAP folder index with imap_peek=no, printing could change
2028          * new or old messages status to read. Redraw what's needed.
2029          */
2030         if (Context->magic == M_IMAP && !option (OPTIMAPPEEK))
2031         {
2032           menu->redraw = (tag ? REDRAW_INDEX : REDRAW_CURRENT) | REDRAW_STATUS;
2033         }
2034 #endif
2035
2036         break;
2037
2038       case OP_MAIN_READ_THREAD:
2039       case OP_MAIN_READ_SUBTHREAD:
2040
2041         CHECK_MSGCOUNT;
2042         CHECK_VISIBLE;
2043         CHECK_READONLY;
2044         CHECK_ACL(M_ACL_SEEN, _("mark message(s) as read"));
2045
2046         rc = mutt_thread_set_flag (CURHDR, M_READ, 1,
2047                                    op == OP_MAIN_READ_THREAD ? 0 : 1);
2048
2049         if (rc != -1)
2050         {
2051           if (option (OPTRESOLVE))
2052           {
2053             if ((menu->current = (op == OP_MAIN_READ_THREAD ?
2054                                   mutt_next_thread (CURHDR) : mutt_next_subthread (CURHDR))) == -1)
2055               menu->current = menu->oldcurrent;
2056             else if (menu->menu == MENU_PAGER)
2057             {
2058               op = OP_DISPLAY_MESSAGE;
2059               continue;
2060             }
2061           }
2062           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2063         }
2064         break;
2065
2066       case OP_RECALL_MESSAGE:
2067
2068         CHECK_ATTACH;
2069         ci_send_message (SENDPOSTPONED, NULL, NULL, Context, NULL);
2070         menu->redraw = REDRAW_FULL;
2071         break;
2072
2073       case OP_RESEND:
2074
2075         CHECK_ATTACH;
2076         CHECK_MSGCOUNT;
2077         CHECK_VISIBLE;
2078
2079         if (tag)
2080         {
2081           for (j = 0; j < Context->vcount; j++)
2082           {
2083             if (Context->hdrs[Context->v2r[j]]->tagged)
2084               mutt_resend_message (NULL, Context, Context->hdrs[Context->v2r[j]]);
2085           }
2086         }
2087         else
2088           mutt_resend_message (NULL, Context, CURHDR);
2089
2090         menu->redraw = REDRAW_FULL;
2091         break;
2092
2093       case OP_REPLY:
2094
2095         CHECK_ATTACH;
2096         CHECK_MSGCOUNT;
2097         CHECK_VISIBLE;
2098         if (option (OPTPGPAUTODEC) && (tag || !(CURHDR->security & PGP_TRADITIONAL_CHECKED)))
2099           mutt_check_traditional_pgp (tag ? NULL : CURHDR, &menu->redraw);
2100         ci_send_message (SENDREPLY, NULL, NULL, Context, tag ? NULL : CURHDR);
2101         menu->redraw = REDRAW_FULL;
2102         break;
2103
2104       case OP_SHELL_ESCAPE:
2105
2106         mutt_shell_escape ();
2107         MAYBE_REDRAW (menu->redraw);
2108         break;
2109
2110       case OP_TAG_THREAD:
2111       case OP_TAG_SUBTHREAD:
2112
2113         CHECK_MSGCOUNT;
2114         CHECK_VISIBLE;
2115         rc = mutt_thread_set_flag (CURHDR, M_TAG, !CURHDR->tagged,
2116                                    op == OP_TAG_THREAD ? 0 : 1);
2117
2118         if (rc != -1)
2119         {
2120           if (option (OPTRESOLVE))
2121           {
2122             if (op == OP_TAG_THREAD)
2123               menu->current = mutt_next_thread (CURHDR);
2124             else
2125               menu->current = mutt_next_subthread (CURHDR);
2126
2127             if (menu->current == -1)
2128               menu->current = menu->oldcurrent;
2129           }
2130           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2131         }
2132         break;
2133
2134       case OP_UNDELETE:
2135
2136         CHECK_MSGCOUNT;
2137         CHECK_VISIBLE;
2138         CHECK_READONLY;
2139         CHECK_ACL(M_ACL_DELETE, _("undelete message"));
2140
2141         if (tag)
2142         {
2143           mutt_tag_set_flag (M_DELETE, 0);
2144           menu->redraw = REDRAW_INDEX;
2145         }
2146         else
2147         {
2148           mutt_set_flag (Context, CURHDR, M_DELETE, 0);
2149           if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
2150           {
2151             menu->current++;
2152             menu->redraw = REDRAW_MOTION_RESYNCH;
2153           }
2154           else
2155             menu->redraw = REDRAW_CURRENT;
2156         }
2157         menu->redraw |= REDRAW_STATUS;
2158         break;
2159
2160       case OP_UNDELETE_THREAD:
2161       case OP_UNDELETE_SUBTHREAD:
2162
2163         CHECK_MSGCOUNT;
2164         CHECK_VISIBLE;
2165         CHECK_READONLY;
2166         CHECK_ACL(M_ACL_DELETE, _("undelete message(s)"));
2167
2168         rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
2169                                    op == OP_UNDELETE_THREAD ? 0 : 1);
2170
2171         if (rc != -1)
2172         {
2173           if (option (OPTRESOLVE))
2174           {
2175             if (op == OP_UNDELETE_THREAD)
2176               menu->current = mutt_next_thread (CURHDR);
2177             else
2178               menu->current = mutt_next_subthread (CURHDR);
2179
2180             if (menu->current == -1)
2181               menu->current = menu->oldcurrent;
2182           }
2183           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
2184         }
2185         break;
2186
2187       case OP_VERSION:
2188         mutt_version ();
2189         break;
2190
2191       case OP_BUFFY_LIST:
2192         mutt_buffy_list ();
2193         break;
2194
2195       case OP_VIEW_ATTACHMENTS:
2196         CHECK_MSGCOUNT;
2197         CHECK_VISIBLE;
2198         mutt_view_attachments (CURHDR);
2199         if (CURHDR->attach_del)
2200           Context->changed = 1;
2201         menu->redraw = REDRAW_FULL;
2202         break;
2203
2204       case OP_END_COND:
2205         break;
2206
2207       case OP_WHAT_KEY:
2208         mutt_what_key();
2209         break;
2210
2211       default:
2212         if (menu->menu == MENU_MAIN)
2213           km_error_key (MENU_MAIN);
2214     }
2215
2216     if (menu->menu == MENU_PAGER)
2217     {
2218       menu->menu = MENU_MAIN;
2219       menu->redraw = REDRAW_FULL;
2220 #if 0
2221       set_option (OPTWEED); /* turn header weeding back on. */
2222 #endif
2223     }
2224
2225     if (done) break;
2226   }
2227
2228   mutt_menuDestroy (&menu);
2229   return (close);
2230 }
2231
2232 void mutt_set_header_color (CONTEXT *ctx, HEADER *curhdr)
2233 {
2234   COLOR_LINE *color;
2235
2236   if (!curhdr)
2237     return;
2238
2239   for (color = ColorIndexList; color; color = color->next)
2240    if (mutt_pattern_exec (color->color_pattern, M_MATCH_FULL_ADDRESS, ctx, curhdr))
2241    {
2242       curhdr->pair = color->pair;
2243       return;
2244    }
2245   curhdr->pair = ColorDefs[MT_COLOR_NORMAL];
2246 }