NeoMutt  2024-11-14-34-g5aaf0d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
help.c
Go to the documentation of this file.
1
34#include "config.h"
35#include <limits.h>
36#include <stdbool.h>
37#include <stddef.h>
38#include <stdio.h>
39#include <string.h>
40#include <wchar.h>
41#include "mutt/lib.h"
42#include "config/lib.h"
43#include "core/lib.h"
44#include "gui/lib.h"
45#include "key/lib.h"
46#include "menu/lib.h"
47#include "pager/lib.h"
48#include "hdrline.h"
49#include "protos.h"
50
58static const struct MenuFuncOp *help_lookup_function(int op, enum MenuType menu)
59{
60 if (menu != MENU_PAGER && (menu != MENU_GENERIC))
61 {
62 /* first look in the generic map for the function */
63 for (int i = 0; OpGeneric[i].name; i++)
64 if (OpGeneric[i].op == op)
65 return &OpGeneric[i];
66 }
67
68 const struct MenuFuncOp *funcs = km_get_table(menu);
69 if (funcs)
70 {
71 for (int i = 0; funcs[i].name; i++)
72 if (funcs[i].op == op)
73 return &funcs[i];
74 }
75
76 return NULL;
77}
78
88static int print_macro(FILE *fp, int maxwidth, const char **macro)
89{
90 int n = maxwidth;
91 wchar_t wc = 0;
92 size_t k;
93 size_t len = mutt_str_len(*macro);
94 mbstate_t mbstate1 = { 0 };
95 mbstate_t mbstate2 = { 0 };
96
97 for (; len && (k = mbrtowc(&wc, *macro, len, &mbstate1)); *macro += k, len -= k)
98 {
99 if ((k == ICONV_ILLEGAL_SEQ) || (k == ICONV_BUF_TOO_SMALL))
100 {
101 if (k == ICONV_ILLEGAL_SEQ)
102 memset(&mbstate1, 0, sizeof(mbstate1));
103 k = (k == ICONV_ILLEGAL_SEQ) ? 1 : len;
104 wc = ReplacementChar;
105 }
106 /* glibc-2.1.3's wcwidth() returns 1 for unprintable chars! */
107 const int w = wcwidth(wc);
108 if (IsWPrint(wc) && (w >= 0))
109 {
110 if (w > n)
111 break;
112 n -= w;
113 {
114 char buf[MB_LEN_MAX * 2];
115 size_t n1, n2;
116 if (((n1 = wcrtomb(buf, wc, &mbstate2)) != ICONV_ILLEGAL_SEQ) &&
117 ((n2 = wcrtomb(buf + n1, 0, &mbstate2)) != ICONV_ILLEGAL_SEQ))
118 {
119 fputs(buf, fp);
120 }
121 }
122 }
123 else if ((wc < 0x20) || (wc == 0x7f))
124 {
125 if (n < 2)
126 break;
127 n -= 2;
128 if (wc == '\033') // Escape
129 fprintf(fp, "\\e");
130 else if (wc == '\n')
131 fprintf(fp, "\\n");
132 else if (wc == '\r')
133 fprintf(fp, "\\r");
134 else if (wc == '\t')
135 fprintf(fp, "\\t");
136 else
137 fprintf(fp, "^%c", (char) ((wc + '@') & 0x7f));
138 }
139 else
140 {
141 if (n < 1)
142 break;
143 n -= 1;
144 fprintf(fp, "?");
145 }
146 }
147 return maxwidth - n;
148}
149
158static int get_wrapped_width(const char *t, size_t wid)
159{
160 wchar_t wc = 0;
161 size_t k;
162 size_t m, n;
163 size_t len = mutt_str_len(t);
164 const char *s = t;
165 mbstate_t mbstate = { 0 };
166
167 for (m = wid, n = 0; len && (k = mbrtowc(&wc, s, len, &mbstate)) && (n <= wid);
168 s += k, len -= k)
169 {
170 if (*s == ' ')
171 m = n;
172 if ((k == ICONV_ILLEGAL_SEQ) || (k == ICONV_BUF_TOO_SMALL))
173 {
174 if (k == ICONV_ILLEGAL_SEQ)
175 memset(&mbstate, 0, sizeof(mbstate));
176 k = (k == ICONV_ILLEGAL_SEQ) ? 1 : len;
177 wc = ReplacementChar;
178 }
179 if (!IsWPrint(wc))
180 wc = '?';
181 n += wcwidth(wc);
182 }
183 if (n > wid)
184 n = m;
185 else
186 n = wid;
187 return n;
188}
189
199static int pad(FILE *fp, int col, int i)
200{
201 if (col < i)
202 {
203 char fmt[32] = { 0 };
204 snprintf(fmt, sizeof(fmt), "%%-%ds", i - col);
205 fprintf(fp, fmt, "");
206 return i;
207 }
208 fputc(' ', fp);
209 return col + 1;
210}
211
228static void format_line(FILE *fp, int ismacro, const char *t1, const char *t2,
229 const char *t3, int wraplen)
230{
231 int col;
232 int col_b;
233
234 fputs(t1, fp);
235
236 /* don't try to press string into one line with less than 40 characters. */
237 bool split = (wraplen < 40);
238 if (split)
239 {
240 col = 0;
241 col_b = 1024;
242 fputc('\n', fp);
243 }
244 else
245 {
246 const int col_a = (wraplen > 83) ? (wraplen - 32) >> 2 : 12;
247 col_b = (wraplen > 49) ? (wraplen - 10) >> 1 : 19;
248 col = pad(fp, mutt_strwidth(t1), col_a);
249 }
250
251 const char *const c_pager = pager_get_pager(NeoMutt->sub);
252 if (ismacro > 0)
253 {
254 if (!c_pager)
255 fputs("_\010", fp); // Ctrl-H (backspace)
256 fputs("M ", fp);
257 col += 2;
258
259 if (!split)
260 {
261 col += print_macro(fp, col_b - col - 4, &t2);
262 if (mutt_strwidth(t2) > col_b - col)
263 t2 = "...";
264 }
265 }
266
267 col += print_macro(fp, col_b - col - 1, &t2);
268 if (split)
269 fputc('\n', fp);
270 else
271 col = pad(fp, col, col_b);
272
273 if (split)
274 {
275 print_macro(fp, 1024, &t3);
276 fputc('\n', fp);
277 }
278 else
279 {
280 while (*t3)
281 {
282 int n = wraplen - col;
283
284 if (ismacro >= 0)
285 {
286 SKIPWS(t3);
287 n = get_wrapped_width(t3, n);
288 }
289
290 n = print_macro(fp, n, &t3);
291
292 if (*t3)
293 {
294 if (c_pager)
295 {
296 fputc('\n', fp);
297 n = 0;
298 }
299 else
300 {
301 n += col - wraplen;
302 const bool c_markers = cs_subset_bool(NeoMutt->sub, "markers");
303 if (c_markers)
304 n++;
305 }
306 col = pad(fp, n, col_b);
307 }
308 }
309 }
310
311 fputc('\n', fp);
312}
313
320static void dump_menu(FILE *fp, enum MenuType menu, int wraplen)
321{
322 struct Keymap *map = NULL;
323 char buf[128] = { 0 };
324
325 STAILQ_FOREACH(map, &Keymaps[menu], entries)
326 {
327 if (map->op != OP_NULL)
328 {
329 km_expand_key(buf, sizeof(buf), map);
330
331 if (map->op == OP_MACRO)
332 {
333 if (map->desc)
334 format_line(fp, 1, buf, map->macro, map->desc, wraplen);
335 else
336 format_line(fp, -1, buf, "macro", map->macro, wraplen);
337 }
338 else
339 {
340 const struct MenuFuncOp *funcs = help_lookup_function(map->op, menu);
341 format_line(fp, 0, buf, funcs ? funcs->name : "UNKNOWN",
342 funcs ? _(opcodes_get_description(funcs->op)) :
343 _("ERROR: please report this bug"),
344 wraplen);
345 }
346 }
347 }
348}
349
356static bool is_bound(struct KeymapList *km_list, int op)
357{
358 struct Keymap *map = NULL;
359 STAILQ_FOREACH(map, km_list, entries)
360 {
361 if (map->op == op)
362 return true;
363 }
364 return false;
365}
366
375static void dump_unbound(FILE *fp, const struct MenuFuncOp *funcs,
376 struct KeymapList *km_list, struct KeymapList *aux, int wraplen)
377{
378 for (int i = 0; funcs[i].name; i++)
379 {
380 if (!is_bound(km_list, funcs[i].op) && (!aux || !is_bound(aux, funcs[i].op)))
381 format_line(fp, 0, funcs[i].name, "", _(opcodes_get_description(funcs[i].op)), wraplen);
382 }
383}
384
393static void show_flag_if_present(FILE *fp, int wraplen, const struct MbTable *table,
394 int index, char *description)
395{
396 const char *flag = mbtable_get_nth_wchar(table, index);
397 if ((strlen(flag) < 1) || (*flag == ' '))
398 {
399 return;
400 }
401
402 format_line(fp, 0, flag, "", description, wraplen);
403}
404
410static void dump_message_flags(FILE *fp, int wraplen)
411{
412 const struct MbTable *c_flag_chars = cs_subset_mbtable(NeoMutt->sub, "flag_chars");
413 const struct MbTable *c_crypt_chars = cs_subset_mbtable(NeoMutt->sub, "crypt_chars");
414 const struct MbTable *c_to_chars = cs_subset_mbtable(NeoMutt->sub, "to_chars");
415
416 format_line(fp, 0, "$flag_chars:", "", "", wraplen);
417 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_TAGGED, _("message is tagged"));
418 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_IMPORTANT,
419 _("message is flagged"));
420 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_DELETED, _("message is deleted"));
421 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_DELETED_ATTACH,
422 _("attachment is deleted"));
423 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_REPLIED,
424 _("message has been replied to"));
425 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_OLD, _("message has been read"));
426 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_NEW, _("message is new"));
427 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_OLD_THREAD,
428 _("thread has been read"));
429 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_NEW_THREAD,
430 _("thread has at least one new message"));
431 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_SEMPTY,
432 _("message has been read (%S expando)"));
433 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_ZEMPTY,
434 _("message has been read (%Z expando)"));
435
436 format_line(fp, 0, "\n$crypt_chars:", "", "", wraplen);
437 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_GOOD_SIGN,
438 _("message signed with a verified key"));
439 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_ENCRYPTED,
440 _("message is PGP-encrypted"));
441 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_SIGNED,
442 _("message is signed"));
443 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_CONTAINS_KEY,
444 _("message contains a PGP key"));
445 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_NO_CRYPTO,
446 _("message has no cryptography information"));
447
448 format_line(fp, 0, "\n$to_chars:", "", "", wraplen);
449 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_NOT_IN_THE_LIST,
450 _("message is not To: you"));
451 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_UNIQUE,
452 _("message is To: you and only you"));
453 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_TO, _("message is To: you"));
454 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_CC, _("message is Cc: to you"));
455 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_ORIGINATOR,
456 _("message is From: you"));
457 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_SUBSCRIBED_LIST,
458 _("message is sent to a subscribed mailing list"));
459 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_REPLY_TO,
460 _("you are in the Reply-To: list"));
461}
462
467void mutt_help(enum MenuType menu)
468{
469 char banner[128] = { 0 };
470 FILE *fp = NULL;
471
472 struct Buffer *tmp_file = buf_pool_get();
473 buf_mktemp(tmp_file);
474
475 const struct MenuFuncOp *funcs = km_get_table(menu);
476 const char *desc = mutt_map_get_name(menu, MenuNames);
477 if (!desc)
478 desc = _("<UNKNOWN>");
479
480 struct PagerData pdata = { 0 };
481 struct PagerView pview = { &pdata };
482
483 pview.mode = PAGER_MODE_HELP;
486
487 do
488 {
489 fp = mutt_file_fopen(buf_string(tmp_file), "w");
490 if (!fp)
491 {
492 mutt_perror("%s", buf_string(tmp_file));
493 goto cleanup;
494 }
495
496 const int wraplen = AllDialogsWindow->state.cols;
497 dump_menu(fp, menu, wraplen);
498 if ((menu != MENU_EDITOR) && (menu != MENU_PAGER) && (menu != MENU_GENERIC))
499 {
500 fprintf(fp, "\n%s\n\n", _("Generic bindings:"));
501 dump_menu(fp, MENU_GENERIC, wraplen);
502 }
503
504 fprintf(fp, "\n%s\n\n", _("Unbound functions:"));
505 if (funcs)
506 dump_unbound(fp, funcs, &Keymaps[menu], NULL, wraplen);
507 if ((menu != MENU_EDITOR) && (menu != MENU_PAGER) && (menu != MENU_GENERIC))
508 dump_unbound(fp, OpGeneric, &Keymaps[MENU_GENERIC], &Keymaps[menu], wraplen);
509
510 if (menu == MENU_INDEX)
511 {
512 fprintf(fp, "\n%s\n\n", _("Message flags:"));
513 dump_message_flags(fp, wraplen);
514 }
515
516 mutt_file_fclose(&fp);
517
518 snprintf(banner, sizeof(banner), _("Help for %s"), desc);
519 pdata.fname = buf_string(tmp_file);
520 pview.banner = banner;
521 } while (mutt_do_pager(&pview, NULL) == OP_REFORMAT_WINCH);
522
523cleanup:
524 buf_pool_release(&tmp_file);
525}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
struct MbTable * cs_subset_mbtable(const struct ConfigSubset *sub, const char *name)
Get a Multibyte table config item by name.
Definition: helpers.c:119
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:443
struct MuttWindow * AllDialogsWindow
Parent of all Dialogs.
Definition: dialog.c:80
int mutt_do_pager(struct PagerView *pview, struct Email *e)
Display some page-able text to the user (help or attachment)
Definition: do_pager.c:122
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
#define mutt_perror(...)
Definition: logging2.h:93
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition: functions.c:68
Convenience wrapper for the gui headers.
String processing routines to generate the mail index.
@ FLAG_CHAR_TO_ORIGINATOR
Character denoting that the user is originator.
Definition: hdrline.h:74
@ FLAG_CHAR_TO_UNIQUE
Character denoting that the user is unique recipient.
Definition: hdrline.h:71
@ FLAG_CHAR_TO_NOT_IN_THE_LIST
Character denoting that the user is not in list.
Definition: hdrline.h:70
@ FLAG_CHAR_TO_TO
Character denoting that the user is in the TO list.
Definition: hdrline.h:72
@ FLAG_CHAR_TO_CC
Character denoting that the user is in the CC list.
Definition: hdrline.h:73
@ FLAG_CHAR_TO_REPLY_TO
Character denoting that the user is in the Reply-To list.
Definition: hdrline.h:76
@ FLAG_CHAR_TO_SUBSCRIBED_LIST
Character denoting that the message is sent to a subscribed mailing list.
Definition: hdrline.h:75
@ FLAG_CHAR_CRYPT_CONTAINS_KEY
Character denoting a message contains a PGP key.
Definition: hdrline.h:61
@ FLAG_CHAR_CRYPT_SIGNED
Character denoting a message is signed.
Definition: hdrline.h:60
@ FLAG_CHAR_CRYPT_NO_CRYPTO
Character denoting a message has no cryptography information.
Definition: hdrline.h:62
@ FLAG_CHAR_CRYPT_GOOD_SIGN
Character denoting a message signed with a verified key.
Definition: hdrline.h:58
@ FLAG_CHAR_CRYPT_ENCRYPTED
Character denoting a message is PGP-encrypted.
Definition: hdrline.h:59
@ FLAG_CHAR_OLD
Character denoting an email that has been read.
Definition: hdrline.h:45
@ FLAG_CHAR_REPLIED
Character denoting an email that has been replied to.
Definition: hdrline.h:44
@ FLAG_CHAR_OLD_THREAD
Character denoting a thread of emails that has been read.
Definition: hdrline.h:47
@ FLAG_CHAR_ZEMPTY
Character denoting a read email, $index_format Z expando.
Definition: hdrline.h:50
@ FLAG_CHAR_TAGGED
Character denoting a tagged email.
Definition: hdrline.h:40
@ FLAG_CHAR_NEW
Character denoting an unread email.
Definition: hdrline.h:46
@ FLAG_CHAR_DELETED
Character denoting a deleted email.
Definition: hdrline.h:42
@ FLAG_CHAR_NEW_THREAD
Character denoting a thread containing at least one new email.
Definition: hdrline.h:48
@ FLAG_CHAR_DELETED_ATTACH
Character denoting a deleted attachment.
Definition: hdrline.h:43
@ FLAG_CHAR_SEMPTY
Character denoting a read email, $index_format S expando.
Definition: hdrline.h:49
@ FLAG_CHAR_IMPORTANT
Character denoting a important (flagged) email.
Definition: hdrline.h:41
static void dump_unbound(FILE *fp, const struct MenuFuncOp *funcs, struct KeymapList *km_list, struct KeymapList *aux, int wraplen)
Write out all the operations with no key bindings.
Definition: help.c:375
static int pad(FILE *fp, int col, int i)
Write some padding to a file.
Definition: help.c:199
static void show_flag_if_present(FILE *fp, int wraplen, const struct MbTable *table, int index, char *description)
Write out a message flag if exists.
Definition: help.c:393
static bool is_bound(struct KeymapList *km_list, int op)
Does a function have a keybinding?
Definition: help.c:356
static void dump_message_flags(FILE *fp, int wraplen)
Write out all the message flags.
Definition: help.c:410
static void format_line(FILE *fp, int ismacro, const char *t1, const char *t2, const char *t3, int wraplen)
Write a formatted line to a file.
Definition: help.c:228
static int get_wrapped_width(const char *t, size_t wid)
Wrap a string at a sensible place.
Definition: help.c:158
static int print_macro(FILE *fp, int maxwidth, const char **macro)
Print a macro string to a file.
Definition: help.c:88
static void dump_menu(FILE *fp, enum MenuType menu, int wraplen)
Write all the key bindings to a file.
Definition: help.c:320
static const struct MenuFuncOp * help_lookup_function(int op, enum MenuType menu)
Find a keybinding for an operation.
Definition: help.c:58
void mutt_help(enum MenuType menu)
Display the help menu.
Definition: help.c:467
struct KeymapList Keymaps[MENU_MAX]
Array of key mappings, one for each MenuType.
Definition: lib.c:125
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: lib.c:457
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition: lib.c:525
Manage keymappings.
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition: mapping.c:42
const char * mbtable_get_nth_wchar(const struct MbTable *table, int index)
Extract one char from a multi-byte table.
Definition: mbtable.c:331
#define IsWPrint(wc)
Definition: mbyte.h:41
GUI present the user with a selectable list.
wchar_t ReplacementChar
When a Unicode character can't be displayed, use this instead.
Definition: charset.c:61
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:98
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:96
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
const char * opcodes_get_description(int op)
Get the description of an opcode.
Definition: opcodes.c:70
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition: config.c:108
GUI display a file/email/help in a viewport with paging.
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: lib.h:71
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: lib.h:69
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:73
#define MUTT_PAGER_STRIPES
Striped highlighting.
Definition: lib.h:76
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: lib.h:70
@ PAGER_MODE_HELP
Pager is invoked via 3rd path to show help.
Definition: lib.h:141
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
Prototypes for many functions.
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define SKIPWS(ch)
Definition: string2.h:45
String manipulation buffer.
Definition: buffer.h:36
A keyboard mapping.
Definition: lib.h:65
char * macro
Macro expansion (op == OP_MACRO)
Definition: lib.h:66
char * desc
Description of a macro for the help menu.
Definition: lib.h:67
short op
Operation to perform.
Definition: lib.h:68
Multibyte character table.
Definition: mbtable.h:36
Mapping between a function and an operation.
Definition: lib.h:101
const char * name
Name of the function.
Definition: lib.h:102
int op
Operation, e.g. OP_DELETE.
Definition: lib.h:103
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:126
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
Data to be displayed by PagerView.
Definition: lib.h:161
const char * fname
Name of the file to read.
Definition: lib.h:165
Paged view into some data.
Definition: lib.h:172
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:173
enum PagerMode mode
Pager mode.
Definition: lib.h:174
PagerFlags flags
Additional settings to tweak pager's function.
Definition: lib.h:175
const char * banner
Title to display in status bar.
Definition: lib.h:176
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
#define buf_mktemp(buf)
Definition: tmp.h:33
const struct Mapping MenuNames[]
Menu name lookup table.
Definition: type.c:37
MenuType
Types of GUI selections.
Definition: type.h:36
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:51
@ MENU_GENERIC
Generic selection list.
Definition: type.h:46
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:52
@ MENU_EDITOR
Text entry area.
Definition: type.h:44