NeoMutt  2024-04-16-36-g75b6fb
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lib.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <ctype.h>
31#include <limits.h>
32#include <stdbool.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include "mutt/lib.h"
37#include "gui/lib.h"
38#include "key/lib.h"
39#include "menu/lib.h"
40#include "ncrypt/lib.h"
41
42extern const struct MenuFuncOp OpAlias[];
43extern const struct MenuFuncOp OpAttachment[];
44#ifdef USE_AUTOCRYPT
45extern const struct MenuFuncOp OpAutocrypt[];
46#endif
47extern const struct MenuFuncOp OpBrowser[];
48extern const struct MenuFuncOp OpCompose[];
49extern const struct MenuFuncOp OpEditor[];
50extern const struct MenuFuncOp OpIndex[];
51#ifdef MIXMASTER
52extern const struct MenuFuncOp OpMixmaster[];
53#endif
54extern const struct MenuFuncOp OpPager[];
55extern const struct MenuFuncOp OpPgp[];
56extern const struct MenuFuncOp OpPostponed[];
57extern const struct MenuFuncOp OpQuery[];
58extern const struct MenuFuncOp OpSmime[];
59
63struct Mapping KeyNames[] = {
64 { "<PageUp>", KEY_PPAGE },
65 { "<PageDown>", KEY_NPAGE },
66 { "<Up>", KEY_UP },
67 { "<Down>", KEY_DOWN },
68 { "<Right>", KEY_RIGHT },
69 { "<Left>", KEY_LEFT },
70 { "<Delete>", KEY_DC },
71 { "<BackSpace>", KEY_BACKSPACE },
72 { "<Insert>", KEY_IC },
73 { "<Home>", KEY_HOME },
74 { "<End>", KEY_END },
75 { "<Enter>", '\n' },
76 { "<Return>", '\r' },
77#ifdef KEY_ENTER
78 { "<KeypadEnter>", KEY_ENTER },
79#else
80 { "<KeypadEnter>", '\n' },
81#endif
82 { "<Esc>", '\033' }, // Escape
83 { "<Tab>", '\t' },
84 { "<Space>", ' ' },
85#ifdef KEY_BTAB
86 { "<BackTab>", KEY_BTAB },
87#endif
88#ifdef KEY_NEXT
89 { "<Next>", KEY_NEXT },
90#endif
91 /* extensions supported by ncurses. values are filled in during initialization */
92
93 /* CTRL+key */
94 { "<C-Up>", -1 },
95 { "<C-Down>", -1 },
96 { "<C-Left>", -1 },
97 { "<C-Right>", -1 },
98 { "<C-Home>", -1 },
99 { "<C-End>", -1 },
100 { "<C-Next>", -1 },
101 { "<C-Prev>", -1 },
102
103 /* SHIFT+key */
104 { "<S-Up>", -1 },
105 { "<S-Down>", -1 },
106 { "<S-Left>", -1 },
107 { "<S-Right>", -1 },
108 { "<S-Home>", -1 },
109 { "<S-End>", -1 },
110 { "<S-Next>", -1 },
111 { "<S-Prev>", -1 },
112
113 /* ALT+key */
114 { "<A-Up>", -1 },
115 { "<A-Down>", -1 },
116 { "<A-Left>", -1 },
117 { "<A-Right>", -1 },
118 { "<A-Home>", -1 },
119 { "<A-End>", -1 },
120 { "<A-Next>", -1 },
121 { "<A-Prev>", -1 },
122 { NULL, 0 },
123};
124
126
128struct KeymapList Keymaps[MENU_MAX];
129
134void mutt_keymap_free(struct Keymap **ptr)
135{
136 if (!ptr || !*ptr)
137 return;
138
139 struct Keymap *km = *ptr;
140 FREE(&km->macro);
141 FREE(&km->desc);
142 FREE(&km->keys);
143
144 FREE(ptr);
145}
146
154{
155 struct Keymap *p = mutt_mem_calloc(1, sizeof(struct Keymap));
156 p->len = len;
157 p->keys = mutt_mem_calloc(len, sizeof(keycode_t));
158 memcpy(p->keys, keys, len * sizeof(keycode_t));
159 return p;
160}
161
169static int parse_fkey(char *s)
170{
171 char *t = NULL;
172 int n = 0;
173
174 if ((s[0] != '<') || (tolower(s[1]) != 'f'))
175 return -1;
176
177 for (t = s + 2; *t && isdigit((unsigned char) *t); t++)
178 {
179 n *= 10;
180 n += *t - '0';
181 }
182
183 if (*t != '>')
184 return -1;
185 return n;
186}
187
196static int parse_keycode(const char *s)
197{
198 char *end_char = NULL;
199 long int result = strtol(s + 1, &end_char, 8);
200 /* allow trailing whitespace, eg. < 1001 > */
201 while (isspace(*end_char))
202 end_char++;
203 /* negative keycodes don't make sense, also detect overflow */
204 if ((*end_char != '>') || (result < 0) || (result == LONG_MAX))
205 {
206 return -1;
207 }
208
209 return result;
210}
211
219size_t parsekeys(const char *str, keycode_t *d, size_t max)
220{
221 int n;
222 size_t len = max;
223 char buf[128] = { 0 };
224 char c;
225 char *t = NULL;
226
227 mutt_str_copy(buf, str, sizeof(buf));
228 char *s = buf;
229
230 while (*s && len)
231 {
232 *d = '\0';
233 if ((*s == '<') && (t = strchr(s, '>')))
234 {
235 t++;
236 c = *t;
237 *t = '\0';
238
240 if (n != -1)
241 {
242 s = t;
243 *d = n;
244 }
245 else if ((n = parse_fkey(s)) > 0)
246 {
247 s = t;
248 *d = KEY_F(n);
249 }
250 else if ((n = parse_keycode(s)) > 0)
251 {
252 s = t;
253 *d = n;
254 }
255
256 *t = c;
257 }
258
259 if (!*d)
260 {
261 *d = (unsigned char) *s;
262 s++;
263 }
264 d++;
265 len--;
266 }
267
268 return max - len;
269}
270
278struct Keymap *km_compare_keys(struct Keymap *k1, struct Keymap *k2, size_t *pos)
279{
280 *pos = 0;
281
282 while (*pos < k1->len && *pos < k2->len)
283 {
284 if (k1->keys[*pos] < k2->keys[*pos])
285 return k2;
286 else if (k1->keys[*pos] > k2->keys[*pos])
287 return k1;
288 else
289 *pos = *pos + 1;
290 }
291
292 return NULL;
293}
294
302int get_op(const struct MenuFuncOp *funcs, const char *start, size_t len)
303{
304 for (int i = 0; funcs[i].name; i++)
305 {
306 if (mutt_istrn_equal(start, funcs[i].name, len) && (mutt_str_len(funcs[i].name) == len))
307 {
308 return funcs[i].op;
309 }
310 }
311
312 return OP_NULL;
313}
314
324const char *mutt_get_func(const struct MenuFuncOp *funcs, int op)
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
342{
343 char *pp = NULL;
344 char *p = s + mutt_str_len(s) - 1;
345 size_t l;
346 int i, op = OP_NULL;
347
348 while (p >= s)
349 {
350 /* if we see something like "<PageUp>", look to see if it is a real
351 * function name and return the corresponding value */
352 if (*p == '>')
353 {
354 for (pp = p - 1; pp >= s && *pp != '<'; pp--)
355 ; // do nothing
356
357 if (pp >= s)
358 {
359 i = parse_fkey(pp);
360 if (i > 0)
361 {
362 mutt_push_macro_event(KEY_F(i), 0);
363 p = pp - 1;
364 continue;
365 }
366
367 l = p - pp + 1;
368 for (i = 0; KeyNames[i].name; i++)
369 {
370 if (mutt_istrn_equal(pp, KeyNames[i].name, l))
371 break;
372 }
373 if (KeyNames[i].name)
374 {
375 /* found a match */
376 mutt_push_macro_event(KeyNames[i].value, 0);
377 p = pp - 1;
378 continue;
379 }
380
381 /* See if it is a valid command
382 * skip the '<' and the '>' when comparing */
383 for (enum MenuType j = 0; MenuNames[j].name; j++)
384 {
385 const struct MenuFuncOp *funcs = km_get_table(MenuNames[j].value);
386 if (funcs)
387 {
388 op = get_op(funcs, pp + 1, l - 2);
389 if (op != OP_NULL)
390 break;
391 }
392 }
393
394 if (op != OP_NULL)
395 {
397 p = pp - 1;
398 continue;
399 }
400 }
401 }
402 mutt_push_macro_event((unsigned char) *p--, 0); /* independent 8 bits chars */
403 }
404}
405
413const char *km_keyname(int c)
414{
415 static char buf[35];
416
417 const char *p = mutt_map_get_name(c, KeyNames);
418 if (p)
419 return p;
420
421 if ((c < 256) && (c > -128) && iscntrl((unsigned char) c))
422 {
423 if (c < 0)
424 c += 256;
425
426 if (c < 128)
427 {
428 buf[0] = '^';
429 buf[1] = (c + '@') & 0x7f;
430 buf[2] = '\0';
431 }
432 else
433 {
434 snprintf(buf, sizeof(buf), "\\%d%d%d", c >> 6, (c >> 3) & 7, c & 7);
435 }
436 }
437 else if ((c >= KEY_F0) && (c < KEY_F(256))) /* this maximum is just a guess */
438 {
439 snprintf(buf, sizeof(buf), "<F%d>", c - KEY_F0);
440 }
441 else if ((c < 256) && (c >= -128) && IsPrint(c))
442 {
443 snprintf(buf, sizeof(buf), "%c", (unsigned char) c);
444 }
445 else
446 {
447 snprintf(buf, sizeof(buf), "<%ho>", (unsigned short) c);
448 }
449 return buf;
450}
451
460int km_expand_key(char *s, size_t len, struct Keymap *map)
461{
462 if (!map)
463 return 0;
464
465 int p = 0;
466
467 while (true)
468 {
469 mutt_str_copy(s, km_keyname(map->keys[p]), len);
470 const size_t l = mutt_str_len(s);
471 len -= l;
472
473 if ((++p >= map->len) || !len)
474 return 1;
475
476 s += l;
477 }
478
479 /* not reached */
480}
481
489int km_expand_key_string(char *str, char *buf, size_t buflen)
490{
491 size_t len = 0;
492 for (; *str; str++)
493 {
494 const char *key = km_keyname(*str);
495 size_t keylen = mutt_str_len(key);
496
497 mutt_str_copy(buf, key, buflen);
498 buf += keylen;
499 buflen -= keylen;
500 len += keylen;
501 }
502
503 return len;
504}
505
512struct Keymap *km_find_func(enum MenuType mtype, int func)
513{
514 struct Keymap *np = NULL;
515 STAILQ_FOREACH(np, &Keymaps[mtype], entries)
516 {
517 if (np->op == func)
518 break;
519 }
520 return np;
521}
522
528const struct MenuFuncOp *km_get_table(enum MenuType mtype)
529{
530 switch (mtype)
531 {
532 case MENU_ALIAS:
533 return OpAlias;
534 case MENU_ATTACHMENT:
535 return OpAttachment;
536#ifdef USE_AUTOCRYPT
537 case MENU_AUTOCRYPT:
538 return OpAutocrypt;
539#endif
540 case MENU_COMPOSE:
541 return OpCompose;
542 case MENU_DIALOG:
543 return OpDialog;
544 case MENU_EDITOR:
545 return OpEditor;
546 case MENU_FOLDER:
547 return OpBrowser;
548 case MENU_GENERIC:
549 return OpGeneric;
550 case MENU_INDEX:
551 return OpIndex;
552#ifdef CRYPT_BACKEND_GPGME
554 return OpPgp;
556 return OpSmime;
557#endif
558#ifdef MIXMASTER
559 case MENU_MIXMASTER:
560 return OpMixmaster;
561#endif
562 case MENU_PAGER:
563 return OpPager;
564 case MENU_PGP:
565 return (WithCrypto & APPLICATION_PGP) ? OpPgp : NULL;
566 case MENU_POSTPONED:
567 return OpPostponed;
568 case MENU_QUERY:
569 return OpQuery;
570 default:
571 return NULL;
572 }
573}
void mutt_push_macro_event(int ch, int op)
Add the character/operation to the macro buffer.
Definition: get.c:154
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition: functions.c:68
const struct MenuFuncOp OpDialog[]
Functions for Simple Dialogs.
Definition: functions.c:60
Convenience wrapper for the gui headers.
const struct MenuFuncOp OpQuery[]
Functions for the external Query Menu.
Definition: functions.c:73
const char * km_keyname(int c)
Get the human name for a key.
Definition: lib.c:413
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: lib.c:512
void generic_tokenize_push_string(char *s)
Parse and queue a 'push' command.
Definition: lib.c:341
keycode_t AbortKey
code of key to abort prompts, normally Ctrl-G
Definition: lib.c:125
const struct MenuFuncOp OpPostponed[]
Functions for the Postpone Menu.
Definition: functions.c:52
const struct MenuFuncOp OpIndex[]
Functions for the Index Menu.
Definition: functions.c:94
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:278
struct Keymap * alloc_keys(size_t len, keycode_t *keys)
Allocate space for a sequence of keys.
Definition: lib.c:153
const struct MenuFuncOp OpCompose[]
Functions for the Compose Menu.
Definition: functions.c:90
const struct MenuFuncOp OpMixmaster[]
Functions for the Mixmaster Menu.
Definition: functions.c:49
void mutt_keymap_free(struct Keymap **ptr)
Free a Keymap.
Definition: lib.c:134
const struct MenuFuncOp OpSmime[]
Functions for the Smime Menu.
Definition: functions.c:52
const struct MenuFuncOp OpBrowser[]
Functions for the file Browser Menu.
Definition: functions.c:74
const struct MenuFuncOp OpAutocrypt[]
Functions for the Autocrypt Account.
Definition: functions.c:52
static int parse_keycode(const char *s)
Parse a numeric keycode.
Definition: lib.c:196
const struct MenuFuncOp OpPager[]
Functions for the Pager Menu.
Definition: functions.c:71
struct KeymapList Keymaps[MENU_MAX]
Array of key mappings, one for each MenuType.
Definition: lib.c:128
size_t parsekeys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition: lib.c:219
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: lib.c:460
const struct MenuFuncOp OpEditor[]
Functions for the Editor Menu.
Definition: functions.c:53
const char * mutt_get_func(const struct MenuFuncOp *funcs, int op)
Get the name of a function.
Definition: lib.c:324
const struct MenuFuncOp OpAttachment[]
Functions for the Attachment Menu.
Definition: functions.c:64
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:528
struct Mapping KeyNames[]
Key name lookup table.
Definition: lib.c:63
int get_op(const struct MenuFuncOp *funcs, const char *start, size_t len)
Get the function by its name.
Definition: lib.c:302
int km_expand_key_string(char *str, char *buf, size_t buflen)
Get a human-readable key string.
Definition: lib.c:489
const struct MenuFuncOp OpAlias[]
Functions for the Alias Menu.
Definition: functions.c:59
static int parse_fkey(char *s)
Parse a function key string.
Definition: lib.c:169
Manage keymappings.
short keycode_t
Type for key storage, the rest of neomutt works fine with int type.
Definition: lib.h:55
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
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:45
GUI present the user with a selectable list.
Convenience wrapper for the library headers.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:490
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:575
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:447
API for encryption/signing of emails.
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define WithCrypto
Definition: lib.h:116
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
A keyboard mapping.
Definition: lib.h:65
keycode_t * keys
key sequence
Definition: lib.h:71
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 len
Length of key sequence (unit: sizeof (keycode_t))
Definition: lib.h:70
short op
Operation to perform.
Definition: lib.h:68
Mapping between user-readable string and a constant.
Definition: mapping.h:33
const char * name
String value.
Definition: mapping.h:34
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
const struct Mapping MenuNames[]
Menu name lookup table.
Definition: type.c:37
MenuType
Types of GUI selections.
Definition: type.h:36
@ MENU_KEY_SELECT_PGP
Select a PGP key.
Definition: type.h:48
@ MENU_INDEX
Index panel (list of emails)
Definition: type.h:51
@ MENU_DIALOG
Simple Dialog.
Definition: type.h:43
@ MENU_MIXMASTER
Create/edit a Mixmaster chain.
Definition: type.h:53
@ MENU_KEY_SELECT_SMIME
Select a SMIME key.
Definition: type.h:49
@ MENU_QUERY
Select from results of external query.
Definition: type.h:58
@ MENU_AUTOCRYPT
Autocrypt Account menu.
Definition: type.h:40
@ MENU_COMPOSE
Compose an email.
Definition: type.h:42
@ MENU_ATTACHMENT
Select an attachment.
Definition: type.h:38
@ MENU_PGP
PGP encryption menu.
Definition: type.h:56
@ MENU_GENERIC
Generic selection list.
Definition: type.h:46
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:55
@ MENU_MAX
Definition: type.h:60
@ MENU_EDITOR
Text entry area.
Definition: type.h:44
@ MENU_ALIAS
Select an email address by its alias.
Definition: type.h:37
@ MENU_FOLDER
General file/mailbox browser.
Definition: type.h:45
@ MENU_POSTPONED
Select a postponed email.
Definition: type.h:57