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