Andreas Krennmair:
[apps/madmutt.git] / menu.c
1 /*
2  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
3  *
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  *
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  *
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18
19 #include "mutt.h"
20 #include "mutt_curses.h"
21 #include "mutt_menu.h"
22 #include "mbyte.h"
23 #include "sidebar.h"
24
25 #ifdef USE_IMAP
26 #include "imap.h"
27 #endif
28
29 #include <string.h>
30 #include <stdlib.h>
31
32 extern int Charset_is_utf8; /* FIXME: bad modularisation */
33
34 extern size_t UngetCount;
35
36 static void print_enriched_string (int attr, unsigned char *s, int do_color)
37 {
38   size_t k;
39   size_t n = mutt_strlen ((char *)s);
40
41   while (*s)
42   {
43     if (*s < M_TREE_MAX)
44     {
45       if (do_color)
46         SETCOLOR (MT_COLOR_TREE);
47       while (*s && *s < M_TREE_MAX)
48       {
49         switch (*s)
50         {
51           case M_TREE_LLCORNER:
52             if (option (OPTASCIICHARS))
53               addch ('`');
54             else if (Charset_is_utf8)
55               addstr ("\342\224\224"); /* WACS_LLCORNER */
56             else
57               addch (ACS_LLCORNER);
58             break;
59           case M_TREE_ULCORNER:
60             if (option (OPTASCIICHARS))
61               addch (',');
62             else if (Charset_is_utf8)
63               addstr ("\342\224\214"); /* WACS_ULCORNER */
64             else
65               addch (ACS_ULCORNER);
66             break;
67           case M_TREE_LTEE:
68             if (option (OPTASCIICHARS))
69               addch ('|');
70             else if (Charset_is_utf8)
71               addstr ("\342\224\234"); /* WACS_LTEE */
72             else
73               addch (ACS_LTEE);
74             break;
75           case M_TREE_HLINE:
76             if (option (OPTASCIICHARS))
77               addch ('-');
78             else if (Charset_is_utf8)
79               addstr ("\342\224\200"); /* WACS_HLINE */
80             else
81               addch (ACS_HLINE);
82             break;
83           case M_TREE_VLINE:
84             if (option (OPTASCIICHARS))
85               addch ('|');
86             else if (Charset_is_utf8)
87               addstr ("\342\224\202"); /* WACS_VLINE */
88             else
89               addch (ACS_VLINE);
90             break;
91           case M_TREE_TTEE:
92             if (option (OPTASCIICHARS))
93               addch ('-');
94             else if (Charset_is_utf8)
95               addstr ("\342\224\254"); /* WACS_TTEE */
96             else
97               addch (ACS_TTEE);
98             break;
99           case M_TREE_BTEE:
100             if (option (OPTASCIICHARS))
101               addch ('-');
102             else if (Charset_is_utf8)
103               addstr ("\342\224\264"); /* WACS_BTEE */
104             else
105               addch (ACS_BTEE);
106             break;
107           case M_TREE_SPACE:
108             addch (' ');
109             break;
110           case M_TREE_RARROW:
111             addch ('>');
112             break;
113           case M_TREE_STAR:
114             addch ('*'); /* fake thread indicator */
115             break;
116           case M_TREE_HIDDEN:
117             addch ('&');
118             break;
119           case M_TREE_EQUALS:
120             addch ('=');
121             break;
122           case M_TREE_MISSING:
123             addch ('?');
124             break;
125         }
126         s++, n--;
127       }
128       if (do_color) attrset(attr);
129     }
130     else if (*s > 0)
131     {
132       addnstr ((char *)s, 1);
133       s += 1, n-= 1;
134     }
135     else
136       break;
137   }
138 }
139
140 static void menu_make_entry (char *s, int l, MUTTMENU *menu, int i) 
141 {
142   if (menu->dialog) 
143   {
144     strncpy (s, menu->dialog[i], l);
145     menu->current = -1; /* hide menubar */
146   }
147   else
148     menu->make_entry (s, l, menu, i);
149 }
150
151 void menu_pad_string (char *s, size_t n)
152 {
153   int shift = option (OPTARROWCURSOR) ? 3 : 0;
154   int cols = COLS - shift - SidebarWidth;
155
156   mutt_format_string (s, n, cols, cols, 0, ' ', s, strlen (s), 1);
157   s[n - 1] = 0;
158 }
159
160 void menu_redraw_full (MUTTMENU *menu)
161 {
162   SETCOLOR (MT_COLOR_NORMAL);
163   /* clear() doesn't optimize screen redraws */
164   move (0, 0);
165   clrtobot ();
166
167   if (option (OPTHELP))
168   {
169     SETCOLOR (MT_COLOR_STATUS);
170     move (option (OPTSTATUSONTOP) ? LINES-2 : 0, 0);
171     mutt_paddstr (COLS, menu->help);
172     SETCOLOR (MT_COLOR_NORMAL);
173     menu->offset = 1;
174     menu->pagelen = LINES - 3;
175   }
176   else
177   {
178     menu->offset = option (OPTSTATUSONTOP) ? 1 : 0;
179     menu->pagelen = LINES - 2;
180   }
181
182   mutt_show_error ();
183
184   menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
185 }
186
187 void menu_redraw_status (MUTTMENU *menu)
188 {
189   char buf[STRING];
190
191   snprintf (buf, sizeof (buf), M_MODEFMT, menu->title);
192   SETCOLOR (MT_COLOR_STATUS);
193   move (option (OPTSTATUSONTOP) ? 0 : LINES - 2, 0);
194   mutt_paddstr (COLS, buf);
195   SETCOLOR (MT_COLOR_NORMAL);
196   menu->redraw &= ~REDRAW_STATUS;
197 }
198
199 void menu_redraw_index (MUTTMENU *menu)
200 {
201   char buf[STRING];
202   int i;
203
204   draw_sidebar(1);
205   for (i = menu->top; i < menu->top + menu->pagelen; i++)
206   {
207     if (i < menu->max)
208     {
209       menu_make_entry (buf, sizeof (buf), menu, i);
210       menu_pad_string (buf, sizeof (buf));
211
212       if (option (OPTARROWCURSOR))
213       {
214         attrset (menu->color (i));
215         CLEARLINE_WIN (i - menu->top + menu->offset);
216
217         if (i == menu->current)
218         {
219           attrset (menu->color (i));
220           ADDCOLOR (MT_COLOR_INDICATOR);
221           addstr ("->");
222           attrset (menu->color (i));
223           addch (' ');
224         }
225         else
226           move (i - menu->top + menu->offset, SidebarWidth + 3);
227
228         print_enriched_string (menu->color(i), (unsigned char *) buf, 1);
229         SETCOLOR (MT_COLOR_NORMAL);          
230       }
231       else
232       {
233         attrset (menu->color (i));
234             
235         if (i == menu->current)
236         {
237           ADDCOLOR (MT_COLOR_INDICATOR);
238           BKGDSET (MT_COLOR_INDICATOR);
239         }
240
241         CLEARLINE_WIN (i - menu->top + menu->offset);
242         print_enriched_string (menu->color(i), (unsigned char *) buf, i != menu->current);
243         SETCOLOR (MT_COLOR_NORMAL);
244         BKGDSET (MT_COLOR_NORMAL);
245       }
246     }
247     else
248       CLEARLINE_WIN (i - menu->top + menu->offset);
249   }
250   menu->redraw = 0;
251 }
252
253 void menu_redraw_motion (MUTTMENU *menu)
254 {
255   char buf[STRING];
256
257   if (menu->dialog) 
258   {
259     menu->redraw &= ~REDRAW_MOTION;
260     return;
261   }
262   
263   move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth);
264   SETCOLOR (MT_COLOR_NORMAL);
265   BKGDSET (MT_COLOR_NORMAL);
266
267   if (option (OPTARROWCURSOR))
268   {
269     /* clear the pointer */
270     attrset (menu->color (menu->oldcurrent));
271     addstr ("  ");
272
273     if (menu->redraw & REDRAW_MOTION_RESYNCH)
274     {
275       clrtoeol ();
276       menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
277       menu_pad_string (buf, sizeof (buf));
278       move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth + 3);
279       print_enriched_string (menu->color(menu->oldcurrent), (unsigned char *) buf, 1);
280       SETCOLOR (MT_COLOR_NORMAL);
281     }
282
283     /* now draw it in the new location */
284     move (menu->current + menu->offset - menu->top, SidebarWidth);
285     attrset (menu->color (menu->current));
286     ADDCOLOR (MT_COLOR_INDICATOR);
287     addstr ("->");
288     SETCOLOR (MT_COLOR_NORMAL);
289   }
290   else
291   {
292     /* erase the current indicator */
293     attrset (menu->color (menu->oldcurrent));
294     clrtoeol ();
295     menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
296     menu_pad_string (buf, sizeof (buf));
297     print_enriched_string (menu->color(menu->oldcurrent), (unsigned char *) buf, 1);
298
299     /* now draw the new one to reflect the change */
300     menu_make_entry (buf, sizeof (buf), menu, menu->current);
301     menu_pad_string (buf, sizeof (buf));
302     attrset (menu->color (menu->current));
303     ADDCOLOR (MT_COLOR_INDICATOR);
304     BKGDSET (MT_COLOR_INDICATOR);
305     CLEARLINE_WIN (menu->current - menu->top + menu->offset);
306     print_enriched_string (menu->color(menu->current), (unsigned char *) buf, 0);
307     SETCOLOR (MT_COLOR_NORMAL);
308     BKGDSET (MT_COLOR_NORMAL);
309   }
310   menu->redraw &= REDRAW_STATUS;
311 }
312
313 void menu_redraw_current (MUTTMENU *menu)
314 {
315   char buf[STRING];
316   
317   move (menu->current + menu->offset - menu->top, SidebarWidth);
318   menu_make_entry (buf, sizeof (buf), menu, menu->current);
319   menu_pad_string (buf, sizeof (buf));
320
321   if (option (OPTARROWCURSOR))
322   {
323     int attr = menu->color (menu->current);
324     attrset (attr);
325     clrtoeol ();
326     attrset (menu->color (menu->current));
327     ADDCOLOR (MT_COLOR_INDICATOR);
328     addstr ("->");
329     attrset (attr);
330     addch (' ');
331     menu_pad_string (buf, sizeof (buf));
332     print_enriched_string (menu->color(menu->current), (unsigned char *) buf, 1);
333     SETCOLOR (MT_COLOR_NORMAL);
334   }
335   else
336   {
337     attrset (menu->color (menu->current));
338     ADDCOLOR (MT_COLOR_INDICATOR);
339     BKGDSET (MT_COLOR_INDICATOR);
340     clrtoeol ();
341     print_enriched_string (menu->color(menu->current), (unsigned char *) buf, 0);
342     SETCOLOR (MT_COLOR_NORMAL);
343     BKGDSET (MT_COLOR_NORMAL);
344   }
345   menu->redraw &= REDRAW_STATUS;
346 }
347
348 void menu_redraw_prompt (MUTTMENU *menu)
349 {
350   if (menu->dialog) 
351   {
352     if (option (OPTMSGERR)) 
353     {
354       mutt_sleep (1);
355       unset_option (OPTMSGERR);
356     }
357
358     if (*Errorbuf)
359       mutt_clear_error ();
360
361     SETCOLOR (MT_COLOR_NORMAL);
362     mvaddstr (LINES - 1, 0, menu->prompt);
363     clrtoeol ();
364   }
365 }
366
367 void menu_check_recenter (MUTTMENU *menu)
368 {
369   if (menu->max <= menu->pagelen && menu->top != 0)
370   {
371     menu->top = 0;
372     set_option (OPTNEEDREDRAW);
373     menu->redraw |= REDRAW_INDEX;
374   }
375   else if (menu->current >= menu->top + menu->pagelen)
376   {
377     if (option (OPTMENUSCROLL) || (menu->pagelen <= 0))
378       menu->top = menu->current - menu->pagelen + 1;
379     else
380       menu->top += menu->pagelen * ((menu->current - menu->top) / menu->pagelen);
381     menu->redraw |= REDRAW_INDEX;
382   }
383   else if (menu->current < menu->top)
384   {
385     if (option (OPTMENUSCROLL) || (menu->pagelen <= 0))
386       menu->top = menu->current;
387     else
388     {
389       menu->top -= menu->pagelen * ((menu->top + menu->pagelen - 1 - menu->current) / menu->pagelen);
390       if (menu->top < 0)
391         menu->top = 0;
392     }
393     menu->redraw |= REDRAW_INDEX;
394   }
395 }
396
397 void menu_jump (MUTTMENU *menu)
398 {
399   int n;
400   char buf[SHORT_STRING];
401
402   if (menu->max)
403   {
404     mutt_ungetch (LastKey, 0);
405     buf[0] = 0;
406     if (mutt_get_field (_("Jump to: "), buf, sizeof (buf), 0) == 0 && buf[0])
407     {
408       n = atoi (buf) - 1;
409       if (n >= 0 && n < menu->max)
410       {
411         menu->current = n;
412         menu->redraw = REDRAW_MOTION;
413       }
414       else
415         mutt_error _("Invalid index number.");
416     }
417   }
418   else
419     mutt_error _("No entries.");
420 }
421
422 void menu_next_line (MUTTMENU *menu)
423 {
424   if (menu->max)
425   {
426     if (menu->top + 1 < menu->max)
427     {
428       menu->top++;
429       if (menu->current < menu->top)
430         menu->current++;
431       menu->redraw = REDRAW_INDEX;
432     }
433     else
434       mutt_error _("You cannot scroll down farther.");
435   }
436   else
437     mutt_error _("No entries.");
438 }
439
440 void menu_prev_line (MUTTMENU *menu)
441 {
442   if (menu->top > 0)
443   {
444     menu->top--;
445     if (menu->current >= menu->top + menu->pagelen)
446       menu->current--;
447     menu->redraw = REDRAW_INDEX;
448   }
449   else
450     mutt_error _("You cannot scroll up farther.");
451 }
452
453 void menu_next_page (MUTTMENU *menu)
454 {
455   if (menu->max)
456   {
457     if (menu->top + menu->pagelen < menu->max)
458     {
459       menu->top += menu->pagelen;
460       if (menu->current < menu->top)
461         menu->current = menu->top;
462       menu->redraw = REDRAW_INDEX;
463     }
464     else if (menu->current != menu->max - 1 && !menu->dialog)
465     {
466       menu->current = menu->max - 1;
467       menu->redraw = REDRAW_MOTION;
468     }
469     else
470       mutt_error _("You are on the last page.");
471   }
472   else
473     mutt_error _("No entries.");
474 }
475
476 void menu_prev_page (MUTTMENU *menu)
477 {
478   if (menu->top > 0)
479   {
480     if ((menu->top -= menu->pagelen) < 0)
481       menu->top = 0;
482     if (menu->current >= menu->top + menu->pagelen)
483       menu->current = menu->top + menu->pagelen - 1;
484     menu->redraw = REDRAW_INDEX;
485   }
486   else if (menu->current && !menu->dialog)
487   {
488     menu->current = 0;
489     menu->redraw = REDRAW_MOTION;
490   }
491   else
492     mutt_error _("You are on the first page.");
493 }
494
495 void menu_top_page (MUTTMENU *menu)
496 {
497   if (menu->current != menu->top)
498   {
499     menu->current = menu->top;
500     menu->redraw = REDRAW_MOTION;
501   }
502 }
503
504 void menu_bottom_page (MUTTMENU *menu)
505 {
506   if (menu->max)
507   {
508     menu->current = menu->top + menu->pagelen - 1;
509     if (menu->current > menu->max - 1)
510       menu->current = menu->max - 1;
511     menu->redraw = REDRAW_MOTION;
512   }
513   else
514     mutt_error _("No entries.");
515 }
516
517 void menu_middle_page (MUTTMENU *menu)
518 {
519   int i;
520
521   if (menu->max)
522   {
523     i = menu->top + menu->pagelen;
524     if (i > menu->max - 1)
525       i = menu->max - 1;
526     menu->current = menu->top + (i - menu->top) / 2;
527     menu->redraw = REDRAW_MOTION;
528   }
529   else
530     mutt_error _("No entries.");
531 }
532
533 void menu_first_entry (MUTTMENU *menu)
534 {
535   if (menu->max)
536   {
537     menu->current = 0;
538     menu->redraw = REDRAW_MOTION;
539   }
540   else
541     mutt_error _("No entries.");
542 }
543
544 void menu_last_entry (MUTTMENU *menu)
545 {
546   if (menu->max)
547   {
548     menu->current = menu->max - 1;
549     menu->redraw = REDRAW_MOTION;
550   }
551   else
552     mutt_error _("No entries.");
553 }
554
555 void menu_half_up (MUTTMENU *menu)
556 {
557   if (menu->top > 0)
558   {
559     if ((menu->top -= menu->pagelen / 2) < 0)
560       menu->top = 0;
561     if (menu->current >= menu->top + menu->pagelen)
562       menu->current = menu->top + menu->pagelen - 1;
563     menu->redraw = REDRAW_INDEX;
564   }
565   else if (menu->current && !menu->dialog)
566   {
567     menu->current = 0;
568     menu->redraw = REDRAW_MOTION;
569   }
570   else
571     mutt_error _("First entry is shown.");
572 }
573
574 void menu_half_down (MUTTMENU *menu)
575 {
576   if (menu->max)
577   {
578     if (menu->top + menu->pagelen < menu->max)
579     {
580       menu->top += menu->pagelen / 2;
581       if (menu->current < menu->top)
582         menu->current = menu->top;
583       menu->redraw = REDRAW_INDEX;
584     }
585     else if (menu->current != menu->max - 1 && !menu->dialog)
586     {
587       menu->current = menu->max - 1;
588       menu->redraw = REDRAW_INDEX;
589     }
590     else
591       mutt_error _("Last entry is shown.");
592   }
593   else
594     mutt_error _("No entries.");
595 }
596
597 void menu_current_top (MUTTMENU *menu)
598 {
599   if (menu->max)
600   {
601     menu->top = menu->current;
602     menu->redraw = REDRAW_INDEX;
603   }
604   else
605     mutt_error _("No entries.");
606 }
607
608 void menu_current_middle (MUTTMENU *menu)
609 {
610   if (menu->max)
611   {
612     menu->top = menu->current - menu->pagelen / 2;
613     if (menu->top < 0)
614       menu->top = 0;
615     menu->redraw = REDRAW_INDEX;
616   }
617   else
618     mutt_error _("No entries.");
619 }
620
621 void menu_current_bottom (MUTTMENU *menu)
622 {
623   if (menu->max)
624   {
625     menu->top = menu->current - menu->pagelen + 1;
626     if (menu->top < 0)
627       menu->top = 0;
628     menu->redraw = REDRAW_INDEX;
629   }
630   else
631     mutt_error _("No entries.");
632 }
633
634 void menu_next_entry (MUTTMENU *menu)
635 {
636   if (menu->current < menu->max - 1)
637   {
638     menu->current++;
639     menu->redraw = REDRAW_MOTION;
640   }
641   else
642     mutt_error _("You are on the last entry.");
643 }
644
645 void menu_prev_entry (MUTTMENU *menu)
646 {
647   if (menu->current)
648   {
649     menu->current--;
650     menu->redraw = REDRAW_MOTION;
651   }
652   else
653     mutt_error _("You are on the first entry.");
654 }
655
656 static int default_color (int i)
657 {
658    return ColorDefs[MT_COLOR_NORMAL];
659 }
660
661 static int menu_search_generic (MUTTMENU *m, regex_t *re, int n)
662 {
663   char buf[LONG_STRING];
664
665   menu_make_entry (buf, sizeof (buf), m, n);
666   return (regexec (re, buf, 0, NULL, 0));
667 }
668
669 MUTTMENU *mutt_new_menu (void)
670 {
671   MUTTMENU *p = (MUTTMENU *) safe_calloc (1, sizeof (MUTTMENU));
672
673   p->current = 0;
674   p->top = 0;
675   p->offset = 1;
676   p->redraw = REDRAW_FULL;
677   p->pagelen = PAGELEN;
678   p->color = default_color;
679   p->search = menu_search_generic;
680   return (p);
681 }
682
683 void mutt_menuDestroy (MUTTMENU **p)
684 {
685   int i;
686
687   FREE (&(*p)->searchBuf);
688
689   if ((*p)->dialog) 
690   {
691     for (i=0; i < (*p)->max; i++)
692       FREE (&(*p)->dialog[i]);
693
694     FREE (& (*p)->dialog);
695   }
696
697   FREE (p);
698 }
699
700 #define M_SEARCH_UP   1
701 #define M_SEARCH_DOWN 2
702
703 static int menu_search (MUTTMENU *menu, int op)
704 {
705   int r;
706   int searchDir;
707   regex_t re;
708   char buf[SHORT_STRING];
709
710   if (op != OP_SEARCH_NEXT && op != OP_SEARCH_OPPOSITE)
711   {
712     strfcpy (buf, menu->searchBuf ? menu->searchBuf : "", sizeof (buf));
713     if (mutt_get_field ((op == OP_SEARCH) ? _("Search for: ") : 
714                                             _("Reverse search for: "),
715                          buf, sizeof (buf), M_CLEAR) != 0 || !buf[0])
716       return (-1);
717     mutt_str_replace (&menu->searchBuf, buf);
718     menu->searchDir = (op == OP_SEARCH) ? M_SEARCH_DOWN : M_SEARCH_UP;
719   }
720   else 
721   {
722     if (!menu->searchBuf)
723     {
724       mutt_error _("No search pattern.");
725       return (-1);
726     }
727   }
728
729   searchDir = (menu->searchDir == M_SEARCH_UP) ? -1 : 1;
730   if (op == OP_SEARCH_OPPOSITE)
731     searchDir = -searchDir;
732
733   if ((r = REGCOMP (&re, menu->searchBuf, REG_NOSUB | mutt_which_case (menu->searchBuf))) != 0)
734   {
735     regerror (r, &re, buf, sizeof (buf));
736     regfree (&re);
737     mutt_error ("%s", buf);
738     return (-1);
739   }
740
741   r = menu->current + searchDir;
742   while (r >= 0 && r < menu->max)
743   {
744     if (menu->search (menu, &re, r) == 0)
745     {
746       regfree (&re);
747       return r;
748     }
749
750     r += searchDir;
751   }
752
753   regfree (&re);
754   mutt_error _("Not found.");
755   return (-1);
756 }
757
758 static int menu_dialog_translate_op (int i)
759 {
760   switch (i)
761   {
762     case OP_NEXT_ENTRY:   
763       return OP_NEXT_LINE;
764     case OP_PREV_ENTRY:          
765       return OP_PREV_LINE;
766     case OP_CURRENT_TOP:   case OP_FIRST_ENTRY:  
767       return OP_TOP_PAGE;
768     case OP_CURRENT_BOTTOM:    case OP_LAST_ENTRY:          
769       return OP_BOTTOM_PAGE;
770     case OP_CURRENT_MIDDLE: 
771       return OP_MIDDLE_PAGE; 
772   }
773   
774   return i;
775 }
776
777 static int menu_dialog_dokey (MUTTMENU *menu, int *ip)
778 {
779   event_t ch;
780   char *p;
781
782   ch = mutt_getch ();
783
784   if (ch.ch == -1)
785   {
786     *ip = -1;
787     return 0;
788   }
789
790   if (ch.ch && (p = strchr (menu->keys, ch.ch)))
791   {
792     *ip = OP_MAX + (p - menu->keys + 1);
793     return 0;
794   }
795   else
796   {
797     mutt_ungetch (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0);
798     return -1;
799   }
800 }
801
802 int menu_redraw (MUTTMENU *menu)
803 {
804   /* See if all or part of the screen needs to be updated.  */
805   if (menu->redraw & REDRAW_FULL)
806   {
807     menu_redraw_full (menu);
808     /* allow the caller to do any local configuration */
809     return (OP_REDRAW);
810   }
811   
812   if (!menu->dialog)
813     menu_check_recenter (menu);
814   
815   if (menu->redraw & REDRAW_STATUS)
816     menu_redraw_status (menu);
817   if (menu->redraw & REDRAW_INDEX)
818     menu_redraw_index (menu);
819   else if (menu->redraw & (REDRAW_MOTION | REDRAW_MOTION_RESYNCH))
820     menu_redraw_motion (menu);
821   else if (menu->redraw == REDRAW_CURRENT)
822     menu_redraw_current (menu);
823   
824   if (menu->dialog)
825     menu_redraw_prompt (menu);
826   
827   return OP_NULL;
828 }
829
830 int mutt_menuLoop (MUTTMENU *menu)
831 {
832   int i = OP_NULL;
833
834   FOREVER
835   {
836     if (option (OPTMENUCALLER))
837     {
838       unset_option (OPTMENUCALLER);
839       return OP_NULL;
840     }
841     
842     
843     mutt_curs_set (0);
844
845 #ifdef USE_IMAP
846     imap_keepalive ();
847 #endif
848
849     if (menu_redraw (menu) == OP_REDRAW)
850       return OP_REDRAW;
851     
852     menu->oldcurrent = menu->current;
853
854
855     /* move the cursor out of the way */
856     move (menu->current - menu->top + menu->offset,
857           (option (OPTARROWCURSOR) ? 2 : COLS-1));
858
859     mutt_refresh ();
860     
861     /* try to catch dialog keys before ops */
862     if (menu->dialog && menu_dialog_dokey (menu, &i) == 0)
863       return i;
864                     
865     i = km_dokey (menu->menu);
866     if (i == OP_TAG_PREFIX || i == OP_TAG_PREFIX_COND)
867     {
868       if (menu->tagged)
869       {
870         mvaddstr (LINES - 1, 0, "Tag-");
871         clrtoeol ();
872         i = km_dokey (menu->menu);
873         menu->tagprefix = 1;
874         CLEARLINE (LINES - 1);
875       }
876       else if (i == OP_TAG_PREFIX)
877       {
878         mutt_error _("No tagged entries.");
879         i = -1;
880       }
881       else /* None tagged, OP_TAG_PREFIX_COND */
882       {
883         event_t tmp;
884         while(UngetCount>0)
885         {
886           tmp=mutt_getch();
887           if(tmp.op==OP_END_COND)break;
888         }
889         mutt_message _("Nothing to do.");
890         i = -1;
891       }
892     }
893     else if (menu->tagged && option (OPTAUTOTAG))
894       menu->tagprefix = 1;
895     else
896       menu->tagprefix = 0;
897
898     mutt_curs_set (1);
899
900 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
901     if (SigWinch)
902     {
903       mutt_resize_screen ();
904       menu->redraw = REDRAW_FULL;
905       SigWinch = 0;
906       clearok(stdscr,TRUE);/*force complete redraw*/
907     }
908 #endif
909
910     if (i == -1)
911       continue;
912
913     if (!menu->dialog)
914       mutt_clear_error ();
915
916     /* Convert menubar movement to scrolling */
917     if (menu->dialog) 
918       i = menu_dialog_translate_op (i);
919
920     switch (i)
921     {
922       case OP_NEXT_ENTRY:
923         menu_next_entry (menu);
924         break;
925       case OP_PREV_ENTRY:
926         menu_prev_entry (menu);
927         break;
928       case OP_HALF_DOWN:
929         menu_half_down (menu);
930         break;
931       case OP_HALF_UP:
932         menu_half_up (menu);
933         break;
934       case OP_NEXT_PAGE:
935         menu_next_page (menu);
936         break;
937       case OP_PREV_PAGE:
938         menu_prev_page (menu);
939         break;
940       case OP_NEXT_LINE:
941         menu_next_line (menu);
942         break;
943       case OP_PREV_LINE:
944         menu_prev_line (menu);
945         break;
946       case OP_FIRST_ENTRY:
947         menu_first_entry (menu);
948         break;
949       case OP_LAST_ENTRY:
950         menu_last_entry (menu);
951         break;
952       case OP_TOP_PAGE:
953         menu_top_page (menu);
954         break;
955       case OP_MIDDLE_PAGE:
956         menu_middle_page (menu);
957         break;
958       case OP_BOTTOM_PAGE:
959         menu_bottom_page (menu);
960         break;
961       case OP_CURRENT_TOP:
962         menu_current_top (menu);
963         break;
964       case OP_CURRENT_MIDDLE:
965         menu_current_middle (menu);
966         break;
967       case OP_CURRENT_BOTTOM:
968         menu_current_bottom (menu);
969         break;
970       case OP_SEARCH:
971       case OP_SEARCH_REVERSE:
972       case OP_SEARCH_NEXT:
973       case OP_SEARCH_OPPOSITE:
974         if (menu->search && !menu->dialog) /* Searching dialogs won't work */
975         {
976           menu->oldcurrent = menu->current;
977           if ((menu->current = menu_search (menu, i)) != -1)
978             menu->redraw = REDRAW_MOTION;
979           else
980             menu->current = menu->oldcurrent;
981         }
982         else
983           mutt_error _("Search is not implemented for this menu.");
984         break;
985
986       case OP_JUMP:
987         if (menu->dialog)
988           mutt_error _("Jumping is not implemented for dialogs.");
989         else
990           menu_jump (menu);
991         break;
992
993       case OP_ENTER_COMMAND:
994         CurrentMenu = menu->menu;
995         mutt_enter_command ();
996         if (option (OPTFORCEREDRAWINDEX))
997         {
998           menu->redraw = REDRAW_FULL;
999           unset_option (OPTFORCEREDRAWINDEX);
1000           unset_option (OPTFORCEREDRAWPAGER);
1001         }
1002         break;
1003
1004       case OP_TAG:
1005         if (menu->tag && !menu->dialog)
1006         {
1007           if (menu->tagprefix && !option (OPTAUTOTAG))
1008           {
1009             for (i = 0; i < menu->max; i++)
1010               menu->tagged += menu->tag (menu, i, 0);
1011             menu->redraw = REDRAW_INDEX;
1012           }
1013           else if (menu->max)
1014           {
1015             int i = menu->tag (menu, menu->current, -1);
1016             menu->tagged += i;
1017             if (i && option (OPTRESOLVE) && menu->current < menu->max - 1)
1018             {
1019               menu->current++;
1020               menu->redraw = REDRAW_MOTION_RESYNCH;
1021             }
1022             else
1023               menu->redraw = REDRAW_CURRENT;
1024           }
1025           else
1026             mutt_error _("No entries.");
1027         }
1028         else
1029           mutt_error _("Tagging is not supported.");
1030         break;
1031
1032       case OP_SHELL_ESCAPE:
1033         mutt_shell_escape ();
1034         MAYBE_REDRAW (menu->redraw);
1035         break;
1036
1037       case OP_WHAT_KEY:
1038         mutt_what_key ();
1039         break;
1040
1041       case OP_REDRAW:
1042         clearok (stdscr, TRUE);
1043         menu->redraw = REDRAW_FULL;
1044         break;
1045
1046       case OP_HELP:
1047         mutt_help (menu->menu);
1048         menu->redraw = REDRAW_FULL;
1049         break;
1050
1051       case OP_NULL:
1052         km_error_key (menu->menu);
1053         break;
1054
1055       case OP_END_COND:
1056         break;
1057
1058       default:
1059         return (i);
1060     }
1061   }
1062   /* not reached */
1063 }