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