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