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