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