NeoMutt  2023-11-03-107-g582dc1
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
help.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <stddef.h>
31#include <limits.h>
32#include <stdbool.h>
33#include <stdio.h>
34#include <string.h>
35#include <wchar.h>
36#include "mutt/lib.h"
37#include "config/lib.h"
38#include "core/lib.h"
39#include "gui/lib.h"
40#include "key/lib.h"
41#include "menu/lib.h"
42#include "pager/lib.h"
43#include "hdrline.h"
44#include "protos.h"
45
53static const struct MenuFuncOp *help_lookup_function(int op, enum MenuType menu)
54{
55 if (menu != MENU_PAGER && (menu != MENU_GENERIC))
56 {
57 /* first look in the generic map for the function */
58 for (int i = 0; OpGeneric[i].name; i++)
59 if (OpGeneric[i].op == op)
60 return &OpGeneric[i];
61 }
62
63 const struct MenuFuncOp *funcs = km_get_table(menu);
64 if (funcs)
65 {
66 for (int i = 0; funcs[i].name; i++)
67 if (funcs[i].op == op)
68 return &funcs[i];
69 }
70
71 return NULL;
72}
73
83static int print_macro(FILE *fp, int maxwidth, const char **macro)
84{
85 int n = maxwidth;
86 wchar_t wc = 0;
87 size_t k;
88 size_t len = mutt_str_len(*macro);
89 mbstate_t mbstate1 = { 0 };
90 mbstate_t mbstate2 = { 0 };
91
92 for (; len && (k = mbrtowc(&wc, *macro, len, &mbstate1)); *macro += k, len -= k)
93 {
94 if ((k == ICONV_ILLEGAL_SEQ) || (k == ICONV_BUF_TOO_SMALL))
95 {
96 if (k == ICONV_ILLEGAL_SEQ)
97 memset(&mbstate1, 0, sizeof(mbstate1));
98 k = (k == ICONV_ILLEGAL_SEQ) ? 1 : len;
99 wc = ReplacementChar;
100 }
101 /* glibc-2.1.3's wcwidth() returns 1 for unprintable chars! */
102 const int w = wcwidth(wc);
103 if (IsWPrint(wc) && (w >= 0))
104 {
105 if (w > n)
106 break;
107 n -= w;
108 {
109 char buf[MB_LEN_MAX * 2];
110 size_t n1, n2;
111 if (((n1 = wcrtomb(buf, wc, &mbstate2)) != ICONV_ILLEGAL_SEQ) &&
112 ((n2 = wcrtomb(buf + n1, 0, &mbstate2)) != ICONV_ILLEGAL_SEQ))
113 {
114 fputs(buf, fp);
115 }
116 }
117 }
118 else if ((wc < 0x20) || (wc == 0x7f))
119 {
120 if (n < 2)
121 break;
122 n -= 2;
123 if (wc == '\033') // Escape
124 fprintf(fp, "\\e");
125 else if (wc == '\n')
126 fprintf(fp, "\\n");
127 else if (wc == '\r')
128 fprintf(fp, "\\r");
129 else if (wc == '\t')
130 fprintf(fp, "\\t");
131 else
132 fprintf(fp, "^%c", (char) ((wc + '@') & 0x7f));
133 }
134 else
135 {
136 if (n < 1)
137 break;
138 n -= 1;
139 fprintf(fp, "?");
140 }
141 }
142 return maxwidth - n;
143}
144
153static int get_wrapped_width(const char *t, size_t wid)
154{
155 wchar_t wc = 0;
156 size_t k;
157 size_t m, n;
158 size_t len = mutt_str_len(t);
159 const char *s = t;
160 mbstate_t mbstate = { 0 };
161
162 for (m = wid, n = 0; len && (k = mbrtowc(&wc, s, len, &mbstate)) && (n <= wid);
163 s += k, len -= k)
164 {
165 if (*s == ' ')
166 m = n;
167 if ((k == ICONV_ILLEGAL_SEQ) || (k == ICONV_BUF_TOO_SMALL))
168 {
169 if (k == ICONV_ILLEGAL_SEQ)
170 memset(&mbstate, 0, sizeof(mbstate));
171 k = (k == ICONV_ILLEGAL_SEQ) ? 1 : len;
172 wc = ReplacementChar;
173 }
174 if (!IsWPrint(wc))
175 wc = '?';
176 n += wcwidth(wc);
177 }
178 if (n > wid)
179 n = m;
180 else
181 n = wid;
182 return n;
183}
184
194static int pad(FILE *fp, int col, int i)
195{
196 if (col < i)
197 {
198 char fmt[32] = { 0 };
199 snprintf(fmt, sizeof(fmt), "%%-%ds", i - col);
200 fprintf(fp, fmt, "");
201 return i;
202 }
203 fputc(' ', fp);
204 return col + 1;
205}
206
223static void format_line(FILE *fp, int ismacro, const char *t1, const char *t2,
224 const char *t3, int wraplen)
225{
226 int col;
227 int col_b;
228
229 fputs(t1, fp);
230
231 /* don't try to press string into one line with less than 40 characters. */
232 bool split = (wraplen < 40);
233 if (split)
234 {
235 col = 0;
236 col_b = 1024;
237 fputc('\n', fp);
238 }
239 else
240 {
241 const int col_a = (wraplen > 83) ? (wraplen - 32) >> 2 : 12;
242 col_b = (wraplen > 49) ? (wraplen - 10) >> 1 : 19;
243 col = pad(fp, mutt_strwidth(t1), col_a);
244 }
245
246 const char *const c_pager = pager_get_pager(NeoMutt->sub);
247 if (ismacro > 0)
248 {
249 if (!c_pager)
250 fputs("_\010", fp); // Ctrl-H (backspace)
251 fputs("M ", fp);
252 col += 2;
253
254 if (!split)
255 {
256 col += print_macro(fp, col_b - col - 4, &t2);
257 if (mutt_strwidth(t2) > col_b - col)
258 t2 = "...";
259 }
260 }
261
262 col += print_macro(fp, col_b - col - 1, &t2);
263 if (split)
264 fputc('\n', fp);
265 else
266 col = pad(fp, col, col_b);
267
268 if (split)
269 {
270 print_macro(fp, 1024, &t3);
271 fputc('\n', fp);
272 }
273 else
274 {
275 while (*t3)
276 {
277 int n = wraplen - col;
278
279 if (ismacro >= 0)
280 {
281 SKIPWS(t3);
282 n = get_wrapped_width(t3, n);
283 }
284
285 n = print_macro(fp, n, &t3);
286
287 if (*t3)
288 {
289 if (c_pager)
290 {
291 fputc('\n', fp);
292 n = 0;
293 }
294 else
295 {
296 n += col - wraplen;
297 const bool c_markers = cs_subset_bool(NeoMutt->sub, "markers");
298 if (c_markers)
299 n++;
300 }
301 col = pad(fp, n, col_b);
302 }
303 }
304 }
305
306 fputc('\n', fp);
307}
308
315static void dump_menu(FILE *fp, enum MenuType menu, int wraplen)
316{
317 struct Keymap *map = NULL;
318 char buf[128] = { 0 };
319
320 STAILQ_FOREACH(map, &Keymaps[menu], entries)
321 {
322 if (map->op != OP_NULL)
323 {
324 km_expand_key(buf, sizeof(buf), map);
325
326 if (map->op == OP_MACRO)
327 {
328 if (map->desc)
329 format_line(fp, 1, buf, map->macro, map->desc, wraplen);
330 else
331 format_line(fp, -1, buf, "macro", map->macro, wraplen);
332 }
333 else
334 {
335 const struct MenuFuncOp *funcs = help_lookup_function(map->op, menu);
336 format_line(fp, 0, buf, funcs ? funcs->name : "UNKNOWN",
337 funcs ? _(opcodes_get_description(funcs->op)) :
338 _("ERROR: please report this bug"),
339 wraplen);
340 }
341 }
342 }
343}
344
351static bool is_bound(struct KeymapList *km_list, int op)
352{
353 struct Keymap *map = NULL;
354 STAILQ_FOREACH(map, km_list, entries)
355 {
356 if (map->op == op)
357 return true;
358 }
359 return false;
360}
361
370static void dump_unbound(FILE *fp, const struct MenuFuncOp *funcs,
371 struct KeymapList *km_list, struct KeymapList *aux, int wraplen)
372{
373 for (int i = 0; funcs[i].name; i++)
374 {
375 if (!is_bound(km_list, funcs[i].op) && (!aux || !is_bound(aux, funcs[i].op)))
376 format_line(fp, 0, funcs[i].name, "", _(opcodes_get_description(funcs[i].op)), wraplen);
377 }
378}
379
388static void show_flag_if_present(FILE *fp, int wraplen, const struct MbTable *table,
389 int index, char *description)
390{
391 const char *flag = mbtable_get_nth_wchar(table, index);
392 if ((strlen(flag) < 1) || (*flag == ' '))
393 {
394 return;
395 }
396
397 format_line(fp, 0, flag, "", description, wraplen);
398}
399
405static void dump_message_flags(FILE *fp, int wraplen)
406{
407 const struct MbTable *c_flag_chars = cs_subset_mbtable(NeoMutt->sub, "flag_chars");
408 const struct MbTable *c_crypt_chars = cs_subset_mbtable(NeoMutt->sub, "crypt_chars");
409 const struct MbTable *c_to_chars = cs_subset_mbtable(NeoMutt->sub, "to_chars");
410
411 format_line(fp, 0, "$flag_chars:", "", "", wraplen);
412 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_TAGGED, _("message is tagged"));
413 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_IMPORTANT,
414 _("message is flagged"));
415 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_DELETED, _("message is deleted"));
416 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_DELETED_ATTACH,
417 _("attachment is deleted"));
418 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_REPLIED,
419 _("message has been replied to"));
420 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_OLD, _("message has been read"));
421 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_NEW, _("message is new"));
422 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_OLD_THREAD,
423 _("thread has been read"));
424 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_NEW_THREAD,
425 _("thread has at least one new message"));
426 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_SEMPTY,
427 _("message has been read (%S expando)"));
428 show_flag_if_present(fp, wraplen, c_flag_chars, FLAG_CHAR_ZEMPTY,
429 _("message has been read (%Z expando)"));
430
431 format_line(fp, 0, "\n$crypt_chars:", "", "", wraplen);
432 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_GOOD_SIGN,
433 _("message signed with a verified key"));
434 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_ENCRYPTED,
435 _("message is PGP-encrypted"));
436 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_SIGNED,
437 _("message is signed"));
438 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_CONTAINS_KEY,
439 _("message contains a PGP key"));
440 show_flag_if_present(fp, wraplen, c_crypt_chars, FLAG_CHAR_CRYPT_NO_CRYPTO,
441 _("message has no cryptography information"));
442
443 format_line(fp, 0, "\n$to_chars:", "", "", wraplen);
444 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_NOT_IN_THE_LIST,
445 _("message is not To: you"));
446 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_UNIQUE,
447 _("message is To: you and only you"));
448 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_TO, _("message is To: you"));
449 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_CC, _("message is Cc: to you"));
450 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_ORIGINATOR,
451 _("message is From: you"));
452 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_SUBSCRIBED_LIST,
453 _("message is sent to a subscribed mailing list"));
454 show_flag_if_present(fp, wraplen, c_to_chars, FLAG_CHAR_TO_REPLY_TO,
455 _("you are in the Reply-To: list"));
456}
457
462void mutt_help(enum MenuType menu)
463{
464 char banner[128] = { 0 };
465 FILE *fp = NULL;
466
467 /* We don't use the buffer pool because of the extended lifetime of t */
468 struct Buffer t = buf_make(PATH_MAX);
469 buf_mktemp(&t);
470
471 const struct MenuFuncOp *funcs = km_get_table(menu);
472 const char *desc = mutt_map_get_name(menu, MenuNames);
473 if (!desc)
474 desc = _("<UNKNOWN>");
475
476 struct PagerData pdata = { 0 };
477 struct PagerView pview = { &pdata };
478
479 pview.mode = PAGER_MODE_HELP;
482
483 do
484 {
485 fp = mutt_file_fopen(buf_string(&t), "w");
486 if (!fp)
487 {
488 mutt_perror("%s", buf_string(&t));
489 goto cleanup;
490 }
491
492 const int wraplen = AllDialogsWindow->state.cols;
493 dump_menu(fp, menu, wraplen);
494 if ((menu != MENU_EDITOR) && (menu != MENU_PAGER) && (menu != MENU_GENERIC))
495 {
496 fprintf(fp, "\n%s\n\n", _("Generic bindings:"));
497 dump_menu(fp, MENU_GENERIC, wraplen);
498 }
499
500 fprintf(fp, "\n%s\n\n", _("Unbound functions:"));
501 if (funcs)
502 dump_unbound(fp, funcs, &Keymaps[menu], NULL, wraplen);
503 if ((menu != MENU_EDITOR) && (menu != MENU_PAGER) && (menu != MENU_GENERIC))
504 dump_unbound(fp, OpGeneric, &Keymaps[MENU_GENERIC], &Keymaps[menu], wraplen);
505
506 if (menu == MENU_INDEX)
507 {
508 fprintf(fp, "\n%s\n\n", _("Message flags:"));
509 dump_message_flags(fp, wraplen);
510 }
511
512 mutt_file_fclose(&fp);
513
514 snprintf(banner, sizeof(banner), _("Help for %s"), desc);
515 pdata.fname = buf_string(&t);
516 pview.banner = banner;
517 } while (mutt_do_pager(&pview, NULL) == OP_REFORMAT_WINCH);
518
519cleanup:
520 buf_dealloc(&t);
521}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:389
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
struct MbTable * cs_subset_mbtable(const struct ConfigSubset *sub, const char *name)
Get a Multibyte table config item by name.
Definition: helpers.c:120
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
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:454
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:123
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define mutt_perror(...)
Definition: logging2.h:93
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition: functions.c:67
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:72
@ FLAG_CHAR_TO_UNIQUE
Character denoting that the user is unique recipient.
Definition: hdrline.h:69
@ FLAG_CHAR_TO_NOT_IN_THE_LIST
Character denoting that the user is not in list.
Definition: hdrline.h:68
@ FLAG_CHAR_TO_TO
Character denoting that the user is in the TO list.
Definition: hdrline.h:70
@ FLAG_CHAR_TO_CC
Character denoting that the user is in the CC list.
Definition: hdrline.h:71
@ FLAG_CHAR_TO_REPLY_TO
Character denoting that the user is in the Reply-To list.
Definition: hdrline.h:74
@ FLAG_CHAR_TO_SUBSCRIBED_LIST
Character denoting that the message is sent to a subscribed mailing list.
Definition: hdrline.h:73
@ FLAG_CHAR_CRYPT_CONTAINS_KEY
Character denoting a message contains a PGP key.
Definition: hdrline.h:59
@ FLAG_CHAR_CRYPT_SIGNED
Character denoting a message is signed.
Definition: hdrline.h:58
@ FLAG_CHAR_CRYPT_NO_CRYPTO
Character denoting a message has no cryptography information.
Definition: hdrline.h:60
@ FLAG_CHAR_CRYPT_GOOD_SIGN
Character denoting a message signed with a verified key.
Definition: hdrline.h:56
@ FLAG_CHAR_CRYPT_ENCRYPTED
Character denoting a message is PGP-encrypted.
Definition: hdrline.h:57
@ FLAG_CHAR_OLD
Character denoting an email that has been read.
Definition: hdrline.h:43
@ FLAG_CHAR_REPLIED
Character denoting an email that has been replied to.
Definition: hdrline.h:42
@ FLAG_CHAR_OLD_THREAD
Character denoting a thread of emails that has been read.
Definition: hdrline.h:45
@ FLAG_CHAR_ZEMPTY
Character denoting a read email, $index_format Z expando.
Definition: hdrline.h:48
@ FLAG_CHAR_TAGGED
Character denoting a tagged email.
Definition: hdrline.h:38
@ FLAG_CHAR_NEW
Character denoting an unread email.
Definition: hdrline.h:44
@ FLAG_CHAR_DELETED
Character denoting a deleted email.
Definition: hdrline.h:40
@ FLAG_CHAR_NEW_THREAD
Character denoting a thread containing at least one new email.
Definition: hdrline.h:46
@ FLAG_CHAR_DELETED_ATTACH
Character denoting a deleted attachment.
Definition: hdrline.h:41
@ FLAG_CHAR_SEMPTY
Character denoting a read email, $index_format S expando.
Definition: hdrline.h:47
@ FLAG_CHAR_IMPORTANT
Character denoting a important (flagged) email.
Definition: hdrline.h:39
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:370
static int pad(FILE *fp, int col, int i)
Write some padding to a file.
Definition: help.c:194
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:388
static bool is_bound(struct KeymapList *km_list, int op)
Does a function have a keybinding?
Definition: help.c:351
static void dump_message_flags(FILE *fp, int wraplen)
Write out all the message flags.
Definition: help.c:405
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:223
static int get_wrapped_width(const char *t, size_t wid)
Wrap a string at a sensible place.
Definition: help.c:153
static int print_macro(FILE *fp, int maxwidth, const char **macro)
Print a macro string to a file.
Definition: help.c:83
static void dump_menu(FILE *fp, enum MenuType menu, int wraplen)
Write all the key bindings to a file.
Definition: help.c:315
static const struct MenuFuncOp * help_lookup_function(int op, enum MenuType menu)
Find a keybinding for an operation.
Definition: help.c:53
void mutt_help(enum MenuType menu)
Display the help menu.
Definition: help.c:462
struct KeymapList Keymaps[MENU_MAX]
Array of key mappings, one for each MenuType.
Definition: lib.c:129
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: lib.c:461
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition: lib.c:529
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:330
#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:58
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:105
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:103
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:568
#define PATH_MAX
Definition: mutt.h:41
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:103
GUI display a file/email/help in a viewport with paging.
#define MUTT_PAGER_RETWINCH
Need reformatting on SIGWINCH.
Definition: lib.h:70
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: lib.h:68
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:72
#define MUTT_PAGER_STRIPES
Striped highlighting.
Definition: lib.h:75
#define MUTT_PAGER_MARKER
Use markers if option is set.
Definition: lib.h:69
@ PAGER_MODE_HELP
Pager is invoked via 3rd path to show help.
Definition: lib.h:140
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:34
A keyboard mapping.
Definition: lib.h:66
char * macro
Macro expansion (op == OP_MACRO)
Definition: lib.h:67
char * desc
Description of a macro for the help menu.
Definition: lib.h:68
short op
Operation to perform.
Definition: lib.h:69
Multibyte character table.
Definition: mbtable.h:36
Mapping between a function and an operation.
Definition: lib.h:102
const char * name
Name of the function.
Definition: lib.h:103
int op
Operation, e.g. OP_DELETE.
Definition: lib.h:104
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
Data to be displayed by PagerView.
Definition: lib.h:160
const char * fname
Name of the file to read.
Definition: lib.h:164
Paged view into some data.
Definition: lib.h:171
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:172
enum PagerMode mode
Pager mode.
Definition: lib.h:173
PagerFlags flags
Additional settings to tweak pager's function.
Definition: lib.h:174
const char * banner
Title to display in status bar.
Definition: lib.h:175
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:55
@ MENU_EDITOR
Text entry area.
Definition: type.h:44