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