NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lib.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <ctype.h>
31#include <limits.h>
32#include <stdbool.h>
33#include <stdlib.h>
34#include <string.h>
35#include "mutt/lib.h"
36#include "gui/lib.h"
37#include "lib.h"
38#include "menu/lib.h"
39
40extern const struct MenuFuncOp OpAlias[];
41extern const struct MenuFuncOp OpAttachment[];
42#ifdef USE_AUTOCRYPT
43extern const struct MenuFuncOp OpAutocrypt[];
44#endif
45extern const struct MenuFuncOp OpBrowser[];
46extern const struct MenuFuncOp OpCompose[];
47extern const struct MenuFuncOp OpEditor[];
48extern const struct MenuFuncOp OpIndex[];
49extern const struct MenuFuncOp OpPager[];
50extern const struct MenuFuncOp OpPgp[];
51extern const struct MenuFuncOp OpPostponed[];
52extern const struct MenuFuncOp OpQuery[];
53extern const struct MenuFuncOp OpSmime[];
54
58struct Mapping KeyNames[] = {
59 // clang-format off
60 { "<PageUp>", KEY_PPAGE },
61 { "<PageDown>", KEY_NPAGE },
62 { "<Up>", KEY_UP },
63 { "<Down>", KEY_DOWN },
64 { "<Right>", KEY_RIGHT },
65 { "<Left>", KEY_LEFT },
66 { "<Delete>", KEY_DC },
67 { "<BackSpace>", KEY_BACKSPACE },
68 { "<Insert>", KEY_IC },
69 { "<Home>", KEY_HOME },
70 { "<End>", KEY_END },
71 { "<Enter>", '\n' },
72 { "<Return>", '\r' },
73#ifdef KEY_ENTER
74 { "<KeypadEnter>", KEY_ENTER },
75#else
76 { "<KeypadEnter>", '\n' },
77#endif
78 { "<Esc>", '\033' }, // Escape
79 { "<Tab>", '\t' },
80 { "<Space>", ' ' },
81#ifdef KEY_BTAB
82 { "<BackTab>", KEY_BTAB },
83#endif
84#ifdef KEY_NEXT
85 { "<Next>", KEY_NEXT },
86#endif
87 /* extensions supported by ncurses. values are filled in during initialization */
88
89 /* CTRL+key */
90 { "<C-Up>", -1 },
91 { "<C-Down>", -1 },
92 { "<C-Left>", -1 },
93 { "<C-Right>", -1 },
94 { "<C-Home>", -1 },
95 { "<C-End>", -1 },
96 { "<C-Next>", -1 },
97 { "<C-Prev>", -1 },
98
99 /* SHIFT+key */
100 { "<S-Up>", -1 },
101 { "<S-Down>", -1 },
102 { "<S-Left>", -1 },
103 { "<S-Right>", -1 },
104 { "<S-Home>", -1 },
105 { "<S-End>", -1 },
106 { "<S-Next>", -1 },
107 { "<S-Prev>", -1 },
108
109 /* ALT+key */
110 { "<A-Up>", -1 },
111 { "<A-Down>", -1 },
112 { "<A-Left>", -1 },
113 { "<A-Right>", -1 },
114 { "<A-Home>", -1 },
115 { "<A-End>", -1 },
116 { "<A-Next>", -1 },
117 { "<A-Prev>", -1 },
118 { NULL, 0 },
119 // clang-format off
120};
121
123
125struct KeymapList Keymaps[MENU_MAX];
126
131void mutt_keymap_free(struct Keymap **ptr)
132{
133 if (!ptr || !*ptr)
134 return;
135
136 struct Keymap *km = *ptr;
137 FREE(&km->macro);
138 FREE(&km->desc);
139 FREE(&km->keys);
140
141 FREE(ptr);
142}
143
151{
152 struct Keymap *p = MUTT_MEM_CALLOC(1, struct Keymap);
153 p->len = len;
155 memcpy(p->keys, keys, len * sizeof(keycode_t));
156 return p;
157}
158
166int parse_fkey(char *s)
167{
168 char *t = NULL;
169 int n = 0;
170
171 if ((s[0] != '<') || (mutt_tolower(s[1]) != 'f'))
172 return -1;
173
174 for (t = s + 2; *t && mutt_isdigit(*t); t++)
175 {
176 n *= 10;
177 n += *t - '0';
178 }
179
180 if (*t != '>')
181 return -1;
182 return n;
183}
184
193static int parse_keycode(const char *s)
194{
195 char *end_char = NULL;
196 long int result = strtol(s + 1, &end_char, 8);
197 /* allow trailing whitespace, eg. < 1001 > */
198 while (mutt_isspace(*end_char))
199 end_char++;
200 /* negative keycodes don't make sense, also detect overflow */
201 if ((*end_char != '>') || (result < 0) || (result == LONG_MAX))
202 {
203 return -1;
204 }
205
206 return result;
207}
208
216size_t parsekeys(const char *str, keycode_t *d, size_t max)
217{
218 int n;
219 size_t len = max;
220 char buf[128] = { 0 };
221 char c;
222 char *t = NULL;
223
224 mutt_str_copy(buf, str, sizeof(buf));
225 char *s = buf;
226
227 while (*s && len)
228 {
229 *d = '\0';
230 if ((*s == '<') && (t = strchr(s, '>')))
231 {
232 t++;
233 c = *t;
234 *t = '\0';
235
237 if (n != -1)
238 {
239 s = t;
240 *d = n;
241 }
242 else if ((n = parse_fkey(s)) > 0)
243 {
244 s = t;
245 *d = KEY_F(n);
246 }
247 else if ((n = parse_keycode(s)) > 0)
248 {
249 s = t;
250 *d = n;
251 }
252
253 *t = c;
254 }
255
256 if (!*d)
257 {
258 *d = (unsigned char) *s;
259 s++;
260 }
261 d++;
262 len--;
263 }
264
265 return max - len;
266}
267
275struct Keymap *km_compare_keys(struct Keymap *k1, struct Keymap *k2, size_t *pos)
276{
277 *pos = 0;
278
279 while (*pos < k1->len && *pos < k2->len)
280 {
281 if (k1->keys[*pos] < k2->keys[*pos])
282 return k2;
283 else if (k1->keys[*pos] > k2->keys[*pos])
284 return k1;
285 else
286 *pos = *pos + 1;
287 }
288
289 return NULL;
290}
291
299int get_op(const struct MenuFuncOp *funcs, const char *start, size_t len)
300{
301 for (int i = 0; funcs[i].name; i++)
302 {
303 if (mutt_istrn_equal(start, funcs[i].name, len) && (mutt_str_len(funcs[i].name) == len))
304 {
305 return funcs[i].op;
306 }
307 }
308
309 return OP_NULL;
310}
311
321const char *mutt_get_func(const struct MenuFuncOp *funcs, int op)
322{
323 if (!funcs)
324 return NULL;
325
326 for (int i = 0; funcs[i].name; i++)
327 {
328 if (funcs[i].op == op)
329 return funcs[i].name;
330 }
331
332 return NULL;
333}
334
341bool is_bound(const struct KeymapList *km_list, int op)
342{
343 if (!km_list)
344 return false;
345
346 struct Keymap *map = NULL;
347 STAILQ_FOREACH(map, km_list, entries)
348 {
349 if (map->op == op)
350 return true;
351 }
352 return false;
353}
354
363int gather_unbound(const struct MenuFuncOp *funcs, const struct KeymapList *km_menu,
364 const struct KeymapList *km_aux, struct BindingInfoArray *bia_unbound)
365{
366 if (!funcs)
367 return 0;
368
369 for (int i = 0; funcs[i].name; i++)
370 {
371 if (!funcs[i].deprecated && !is_bound(km_menu, funcs[i].op) &&
372 (!km_aux || !is_bound(km_aux, funcs[i].op)))
373 {
374 struct BindingInfo bi = { 0 };
375 bi.a[0] = NULL;
376 bi.a[1] = funcs[i].name;
377 bi.a[2] = _(opcodes_get_description(funcs[i].op));
378 ARRAY_ADD(bia_unbound, bi);
379 }
380 }
381
382 return ARRAY_SIZE(bia_unbound);
383}
384
390void km_keyname(int c, struct Buffer *buf)
391{
392 const char *name = mutt_map_get_name(c, KeyNames);
393 if (name)
394 {
395 buf_addstr(buf, name);
396 return;
397 }
398
399 if ((c < 256) && (c > -128) && iscntrl((unsigned char) c))
400 {
401 if (c < 0)
402 c += 256;
403
404 if (c < 128)
405 {
406 buf_addch(buf, '^');
407 buf_addch(buf, (c + '@') & 0x7f);
408 }
409 else
410 {
411 buf_add_printf(buf, "\\%d%d%d", c >> 6, (c >> 3) & 7, c & 7);
412 }
413 }
414 else if ((c >= KEY_F0) && (c < KEY_F(256))) /* this maximum is just a guess */
415 {
416 buf_add_printf(buf, "<F%d>", c - KEY_F0);
417 }
418 else if ((c < 256) && (c >= -128) && IsPrint(c))
419 {
420 buf_add_printf(buf, "%c", (unsigned char) c);
421 }
422 else
423 {
424 buf_add_printf(buf, "<%ho>", (unsigned short) c);
425 }
426}
427
434bool km_expand_key(struct Keymap *map, struct Buffer *buf)
435{
436 if (!map || !buf)
437 return false;
438
439 for (int i = 0; i < map->len; i++)
440 {
441 km_keyname(map->keys[i], buf);
442 }
443
444 return true;
445}
446
452void km_expand_key_string(char *str, struct Buffer *buf)
453{
454 for (; *str; str++)
455 {
456 km_keyname(*str, buf);
457 }
458}
459
466struct Keymap *km_find_func(enum MenuType mtype, int func)
467{
468 struct Keymap *np = NULL;
469 STAILQ_FOREACH(np, &Keymaps[mtype], entries)
470 {
471 if (np->op == func)
472 break;
473 }
474 return np;
475}
476
482const struct MenuFuncOp *km_get_table(enum MenuType mtype)
483{
484 switch (mtype)
485 {
486 case MENU_ALIAS:
487 return OpAlias;
488 case MENU_ATTACHMENT:
489 return OpAttachment;
490#ifdef USE_AUTOCRYPT
491 case MENU_AUTOCRYPT:
492 return OpAutocrypt;
493#endif
494 case MENU_BROWSER:
495 return OpBrowser;
496 case MENU_COMPOSE:
497 return OpCompose;
498 case MENU_DIALOG:
499 return OpDialog;
500 case MENU_EDITOR:
501 return OpEditor;
502 case MENU_GENERIC:
503 return OpGeneric;
504 case MENU_INDEX:
505 return OpIndex;
506 case MENU_PAGER:
507 return OpPager;
508 case MENU_PGP:
509 return OpPgp;
510 case MENU_POSTPONED:
511 return OpPostponed;
512 case MENU_QUERY:
513 return OpQuery;
514 case MENU_SMIME:
515 return OpSmime;
516 default:
517 return NULL;
518 }
519}
520
const struct MenuFuncOp OpQuery[]
Functions for the external Query Menu.
Definition functions.c:75
const struct MenuFuncOp OpAlias[]
Functions for the Alias Menu.
Definition functions.c:59
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:156
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
const struct MenuFuncOp OpAttachment[]
Functions for the Attachment Menu.
Definition functions.c:62
const struct MenuFuncOp OpAutocrypt[]
Functions for the Autocrypt Account.
Definition functions.c:54
const struct MenuFuncOp OpBrowser[]
Functions for the file Browser Menu.
Definition functions.c:72
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
const struct MenuFuncOp OpCompose[]
Functions for the Compose Menu.
Definition functions.c:87
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:95
int mutt_tolower(int arg)
Wrapper for tolower(3)
Definition ctype.c:125
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:65
const struct MenuFuncOp OpEditor[]
Functions for the Editor Menu.
Definition functions.c:53
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition functions.c:69
const struct MenuFuncOp OpDialog[]
Functions for Simple Dialogs.
Definition functions.c:60
Convenience wrapper for the gui headers.
const struct MenuFuncOp OpIndex[]
Functions for the Index Menu.
Definition functions.c:90
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition lib.c:466
int parse_fkey(char *s)
Parse a function key string.
Definition lib.c:166
keycode_t AbortKey
code of key to abort prompts, normally Ctrl-G
Definition lib.c:122
const struct MenuFuncOp OpPostponed[]
Functions for the Postpone Menu.
Definition functions.c:52
struct Keymap * km_compare_keys(struct Keymap *k1, struct Keymap *k2, size_t *pos)
Compare two keymaps' keyscodes and return the bigger one.
Definition lib.c:275
struct Keymap * alloc_keys(size_t len, keycode_t *keys)
Allocate space for a sequence of keys.
Definition lib.c:150
void mutt_keymap_free(struct Keymap **ptr)
Free a Keymap.
Definition lib.c:131
const struct MenuFuncOp OpSmime[]
Functions for the Smime Menu.
Definition functions.c:52
static int parse_keycode(const char *s)
Parse a numeric keycode.
Definition lib.c:193
const struct MenuFuncOp OpPager[]
Functions for the Pager Menu.
Definition functions.c:70
bool is_bound(const struct KeymapList *km_list, int op)
Does a function have a keybinding?
Definition lib.c:341
struct KeymapList Keymaps[MENU_MAX]
Array of key mappings, one for each MenuType.
Definition lib.c:125
size_t parsekeys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition lib.c:216
const char * mutt_get_func(const struct MenuFuncOp *funcs, int op)
Get the name of a function.
Definition lib.c:321
void km_keyname(int c, struct Buffer *buf)
Get the human name for a key.
Definition lib.c:390
const struct MenuFuncOp OpPgp[]
Functions for the Pgp Menu.
Definition functions.c:42
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition lib.c:482
struct Mapping KeyNames[]
Key name lookup table.
Definition lib.c:58
int get_op(const struct MenuFuncOp *funcs, const char *start, size_t len)
Get the function by its name.
Definition lib.c:299
int gather_unbound(const struct MenuFuncOp *funcs, const struct KeymapList *km_menu, const struct KeymapList *km_aux, struct BindingInfoArray *bia_unbound)
Gather info about unbound functions for one menu.
Definition lib.c:363
bool km_expand_key(struct Keymap *map, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition lib.c:434
void km_expand_key_string(char *str, struct Buffer *buf)
Get a human-readable key string.
Definition lib.c:452
Manage keymappings.
short keycode_t
Type for key storage, the rest of neomutt works fine with int type.
Definition lib.h:57
int mutt_map_get_value(const char *name, const struct Mapping *map)
Lookup the constant for a string.
Definition mapping.c:85
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition mapping.c:42
#define IsPrint(ch)
Definition mbyte.h:40
#define FREE(x)
Definition memory.h:62
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
GUI present the user with a selectable list.
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:498
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:581
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition string.c:455
const char * opcodes_get_description(int op)
Get the description of an opcode.
Definition opcodes.c:68
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
Info about one keybinding.
Definition lib.h:95
const char * a[3]
Array of info.
Definition lib.h:96
String manipulation buffer.
Definition buffer.h:36
A keyboard mapping.
Definition lib.h:67
keycode_t * keys
Key sequence.
Definition lib.h:73
char * macro
Macro expansion (op == OP_MACRO)
Definition lib.h:68
char * desc
Description of a macro for the help menu.
Definition lib.h:69
short len
Length of key sequence (unit: sizeof (keycode_t))
Definition lib.h:72
short op
Operation to perform.
Definition lib.h:70
Mapping between user-readable string and a constant.
Definition mapping.h:33
Mapping between a function and an operation.
Definition lib.h:115
const char * name
Name of the function.
Definition lib.h:116
int op
Operation, e.g. OP_DELETE.
Definition lib.h:117
MenuType
Types of GUI selections.
Definition type.h:35
@ MENU_INDEX
Index panel (list of emails)
Definition type.h:46
@ MENU_DIALOG
Simple Dialog.
Definition type.h:43
@ MENU_QUERY
Select from results of external query.
Definition type.h:50
@ MENU_BROWSER
General file/mailbox browser.
Definition type.h:41
@ MENU_AUTOCRYPT
Autocrypt Account menu.
Definition type.h:39
@ MENU_COMPOSE
Compose an email.
Definition type.h:42
@ MENU_ATTACHMENT
Select an attachment.
Definition type.h:37
@ MENU_PGP
PGP encryption menu.
Definition type.h:48
@ MENU_GENERIC
Generic selection list.
Definition type.h:45
@ MENU_PAGER
Pager pager (email viewer)
Definition type.h:47
@ MENU_SMIME
SMIME encryption menu.
Definition type.h:51
@ MENU_MAX
Definition type.h:52
@ MENU_EDITOR
Text entry area.
Definition type.h:44
@ MENU_ALIAS
Select an email address by its alias.
Definition type.h:36
@ MENU_POSTPONED
Select a postponed email.
Definition type.h:49