NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
keymap.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 "config/lib.h"
38 #include "core/lib.h"
39 #include "gui/lib.h"
40 #include "mutt.h"
41 #include "keymap.h"
42 #include "menu/lib.h"
43 #include "ncrypt/lib.h"
44 #include "functions.h"
45 #include "init.h"
46 #include "mutt_commands.h"
47 #include "mutt_globals.h"
48 #include "mutt_logging.h"
49 #include "opcodes.h"
50 #include "options.h"
51 #ifndef USE_SLANG_CURSES
52 #include <strings.h>
53 #endif
54 #ifdef USE_IMAP
55 #include "imap/lib.h"
56 #endif
57 #ifdef USE_INOTIFY
58 #include "monitor.h"
59 #endif
60 
64 static struct Mapping KeyNames[] = {
65  { "<PageUp>", KEY_PPAGE },
66  { "<PageDown>", KEY_NPAGE },
67  { "<Up>", KEY_UP },
68  { "<Down>", KEY_DOWN },
69  { "<Right>", KEY_RIGHT },
70  { "<Left>", KEY_LEFT },
71  { "<Delete>", KEY_DC },
72  { "<BackSpace>", KEY_BACKSPACE },
73  { "<Insert>", KEY_IC },
74  { "<Home>", KEY_HOME },
75  { "<End>", KEY_END },
76  { "<Enter>", '\n' },
77  { "<Return>", '\r' },
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 #ifdef NCURSES_VERSION
88  /* extensions supported by ncurses. values are filled in during initialization */
89 
90  /* CTRL+key */
91  { "<C-Up>", -1 },
92  { "<C-Down>", -1 },
93  { "<C-Left>", -1 },
94  { "<C-Right>", -1 },
95  { "<C-Home>", -1 },
96  { "<C-End>", -1 },
97  { "<C-Next>", -1 },
98  { "<C-Prev>", -1 },
99 
100  /* SHIFT+key */
101  { "<S-Up>", -1 },
102  { "<S-Down>", -1 },
103  { "<S-Left>", -1 },
104  { "<S-Right>", -1 },
105  { "<S-Home>", -1 },
106  { "<S-End>", -1 },
107  { "<S-Next>", -1 },
108  { "<S-Prev>", -1 },
109 
110  /* ALT+key */
111  { "<A-Up>", -1 },
112  { "<A-Down>", -1 },
113  { "<A-Left>", -1 },
114  { "<A-Right>", -1 },
115  { "<A-Home>", -1 },
116  { "<A-End>", -1 },
117  { "<A-Next>", -1 },
118  { "<A-Prev>", -1 },
119 #endif /* NCURSES_VERSION */
120  { NULL, 0 },
121 };
122 
123 int LastKey;
125 
126 struct KeymapList Keymaps[MENU_MAX];
127 
128 #ifdef NCURSES_VERSION
129 
132 struct Extkey
133 {
134  const char *name;
135  const char *sym;
136 };
137 
138 static const struct Extkey ExtKeys[] = {
139  { "<c-up>", "kUP5" },
140  { "<s-up>", "kUP" },
141  { "<a-up>", "kUP3" },
142 
143  { "<s-down>", "kDN" },
144  { "<a-down>", "kDN3" },
145  { "<c-down>", "kDN5" },
146 
147  { "<c-right>", "kRIT5" },
148  { "<s-right>", "kRIT" },
149  { "<a-right>", "kRIT3" },
150 
151  { "<s-left>", "kLFT" },
152  { "<a-left>", "kLFT3" },
153  { "<c-left>", "kLFT5" },
154 
155  { "<s-home>", "kHOM" },
156  { "<a-home>", "kHOM3" },
157  { "<c-home>", "kHOM5" },
158 
159  { "<s-end>", "kEND" },
160  { "<a-end>", "kEND3" },
161  { "<c-end>", "kEND5" },
162 
163  { "<s-next>", "kNXT" },
164  { "<a-next>", "kNXT3" },
165  { "<c-next>", "kNXT5" },
166 
167  { "<s-prev>", "kPRV" },
168  { "<a-prev>", "kPRV3" },
169  { "<c-prev>", "kPRV5" },
170 
171  { 0, 0 },
172 };
173 #endif
174 
179 static void mutt_keymap_free(struct Keymap **km)
180 {
181  if (!km || !*km)
182  return;
183 
184  FREE(&(*km)->macro);
185  FREE(&(*km)->desc);
186  FREE(&(*km)->keys);
187  FREE(km);
188 }
189 
194 static void mutt_keymaplist_free(struct KeymapList *km_list)
195 {
196  struct Keymap *np = NULL, *tmp = NULL;
197  STAILQ_FOREACH_SAFE(np, km_list, entries, tmp)
198  {
199  STAILQ_REMOVE(km_list, np, Keymap, entries);
200  mutt_keymap_free(&np);
201  }
202 }
203 
210 static struct Keymap *alloc_keys(size_t len, keycode_t *keys)
211 {
212  struct Keymap *p = mutt_mem_calloc(1, sizeof(struct Keymap));
213  p->len = len;
214  p->keys = mutt_mem_calloc(len, sizeof(keycode_t));
215  memcpy(p->keys, keys, len * sizeof(keycode_t));
216  return p;
217 }
218 
226 static int parse_fkey(char *s)
227 {
228  char *t = NULL;
229  int n = 0;
230 
231  if ((s[0] != '<') || (tolower(s[1]) != 'f'))
232  return -1;
233 
234  for (t = s + 2; *t && isdigit((unsigned char) *t); t++)
235  {
236  n *= 10;
237  n += *t - '0';
238  }
239 
240  if (*t != '>')
241  return -1;
242  return n;
243 }
244 
253 static int parse_keycode(const char *s)
254 {
255  char *end_char = NULL;
256  long int result = strtol(s + 1, &end_char, 8);
257  /* allow trailing whitespace, eg. < 1001 > */
258  while (IS_SPACE(*end_char))
259  end_char++;
260  /* negative keycodes don't make sense, also detect overflow */
261  if ((*end_char != '>') || (result < 0) || (result == LONG_MAX))
262  {
263  return -1;
264  }
265 
266  return result;
267 }
268 
276 static size_t parsekeys(const char *str, keycode_t *d, size_t max)
277 {
278  int n;
279  size_t len = max;
280  char buf[128];
281  char c;
282  char *t = NULL;
283 
284  mutt_str_copy(buf, str, sizeof(buf));
285  char *s = buf;
286 
287  while (*s && len)
288  {
289  *d = '\0';
290  if ((*s == '<') && (t = strchr(s, '>')))
291  {
292  t++;
293  c = *t;
294  *t = '\0';
295 
296  n = mutt_map_get_value(s, KeyNames);
297  if (n != -1)
298  {
299  s = t;
300  *d = n;
301  }
302  else if ((n = parse_fkey(s)) > 0)
303  {
304  s = t;
305  *d = KEY_F(n);
306  }
307  else if ((n = parse_keycode(s)) > 0)
308  {
309  s = t;
310  *d = n;
311  }
312 
313  *t = c;
314  }
315 
316  if (!*d)
317  {
318  *d = (unsigned char) *s;
319  s++;
320  }
321  d++;
322  len--;
323  }
324 
325  return max - len;
326 }
327 
335 static struct Keymap *km_compare_keys(struct Keymap *k1, struct Keymap *k2, size_t *pos)
336 {
337  while (*pos < k1->len && *pos < k2->len)
338  {
339  if (k1->keys[*pos] < k2->keys[*pos])
340  return k2;
341  else if (k1->keys[*pos] > k2->keys[*pos])
342  return k1;
343  else
344  *pos = *pos + 1;
345  }
346 
347  return NULL;
348 }
349 
363 static enum CommandResult km_bind_err(const char *s, enum MenuType mtype, int op,
364  char *macro, char *desc, struct Buffer *err)
365 {
367  struct Keymap *last = NULL, *np = NULL, *compare = NULL;
368  keycode_t buf[MAX_SEQ];
369  size_t pos = 0, lastpos = 0;
370 
371  size_t len = parsekeys(s, buf, MAX_SEQ);
372 
373  struct Keymap *map = alloc_keys(len, buf);
374  map->op = op;
375  map->macro = mutt_str_dup(macro);
376  map->desc = mutt_str_dup(desc);
377 
378  /* find position to place new keymap */
379  STAILQ_FOREACH(np, &Keymaps[mtype], entries)
380  {
381  compare = km_compare_keys(map, np, &pos);
382 
383  if (compare == map) /* map's keycode is bigger */
384  {
385  last = np;
386  lastpos = pos;
387  if (pos > np->eq)
388  pos = np->eq;
389  }
390  else if (compare == np) /* np's keycode is bigger, found insert location */
391  {
392  map->eq = pos;
393  break;
394  }
395  else /* equal keycodes */
396  {
397  /* Don't warn on overwriting a 'noop' binding */
398  if ((np->len != len) && (np->op != OP_NULL))
399  {
400  /* Overwrite with the different lengths, warn */
401  /* TODO: MAX_SEQ here is wrong */
402  char old_binding[MAX_SEQ];
403  char new_binding[MAX_SEQ];
404  km_expand_key(old_binding, MAX_SEQ, map);
405  km_expand_key(new_binding, MAX_SEQ, np);
406  char *err_msg =
407  _("Binding '%s' will alias '%s' Before, try: 'bind %s %s noop' "
408  "https://neomutt.org/guide/configuration.html#bind-warnings");
409  if (err)
410  {
411  /* err was passed, put the string there */
412  snprintf(err->data, err->dsize, err_msg, old_binding, new_binding,
413  mutt_map_get_name(mtype, MenuNames), new_binding);
414  }
415  else
416  {
417  mutt_error(err_msg, old_binding, new_binding,
418  mutt_map_get_name(mtype, MenuNames), new_binding);
419  }
420  rc = MUTT_CMD_WARNING;
421  }
422 
423  map->eq = np->eq;
424  STAILQ_REMOVE(&Keymaps[mtype], np, Keymap, entries);
425  mutt_keymap_free(&np);
426  break;
427  }
428  }
429 
430  if (last) /* if queue has at least one entry */
431  {
432  if (STAILQ_NEXT(last, entries))
433  STAILQ_INSERT_AFTER(&Keymaps[mtype], last, map, entries);
434  else /* last entry in the queue */
435  STAILQ_INSERT_TAIL(&Keymaps[mtype], map, entries);
436  last->eq = lastpos;
437  }
438  else /* queue is empty, so insert from head */
439  {
440  STAILQ_INSERT_HEAD(&Keymaps[mtype], map, entries);
441  }
442 
443  return rc;
444 }
445 
455 enum CommandResult km_bind(char *s, enum MenuType mtype, int op, char *macro, char *desc)
456 {
457  return km_bind_err(s, mtype, op, macro, desc, NULL);
458 }
459 
468 static enum CommandResult km_bindkey_err(const char *s, enum MenuType mtype,
469  int op, struct Buffer *err)
470 {
471  return km_bind_err(s, mtype, op, NULL, NULL, err);
472 }
473 
481 static enum CommandResult km_bindkey(const char *s, enum MenuType mtype, int op)
482 {
483  return km_bindkey_err(s, mtype, op, NULL);
484 }
485 
493 static int get_op(const struct Binding *bindings, const char *start, size_t len)
494 {
495  for (int i = 0; bindings[i].name; i++)
496  {
497  if (mutt_istrn_equal(start, bindings[i].name, len) &&
498  (mutt_str_len(bindings[i].name) == len))
499  {
500  return bindings[i].op;
501  }
502  }
503 
504  return OP_NULL;
505 }
506 
516 const char *mutt_get_func(const struct Binding *bindings, int op)
517 {
518  for (int i = 0; bindings[i].name; i++)
519  {
520  if (bindings[i].op == op)
521  return bindings[i].name;
522  }
523 
524  return NULL;
525 }
526 
536 static void generic_tokenize_push_string(char *s, void (*generic_push)(int, int))
537 {
538  char *pp = NULL;
539  char *p = s + mutt_str_len(s) - 1;
540  size_t l;
541  int i, op = OP_NULL;
542 
543  while (p >= s)
544  {
545  /* if we see something like "<PageUp>", look to see if it is a real
546  * function name and return the corresponding value */
547  if (*p == '>')
548  {
549  for (pp = p - 1; pp >= s && *pp != '<'; pp--)
550  ; // do nothing
551 
552  if (pp >= s)
553  {
554  i = parse_fkey(pp);
555  if (i > 0)
556  {
557  generic_push(KEY_F(i), 0);
558  p = pp - 1;
559  continue;
560  }
561 
562  l = p - pp + 1;
563  for (i = 0; KeyNames[i].name; i++)
564  {
565  if (mutt_istrn_equal(pp, KeyNames[i].name, l))
566  break;
567  }
568  if (KeyNames[i].name)
569  {
570  /* found a match */
571  generic_push(KeyNames[i].value, 0);
572  p = pp - 1;
573  continue;
574  }
575 
576  /* See if it is a valid command
577  * skip the '<' and the '>' when comparing */
578  for (enum MenuType j = 0; MenuNames[j].name; j++)
579  {
580  const struct Binding *binding = km_get_table(MenuNames[j].value);
581  if (binding)
582  {
583  op = get_op(binding, pp + 1, l - 2);
584  if (op != OP_NULL)
585  break;
586  }
587  }
588 
589  if (op != OP_NULL)
590  {
591  generic_push(0, op);
592  p = pp - 1;
593  continue;
594  }
595  }
596  }
597  generic_push((unsigned char) *p--, 0); /* independent 8 bits chars */
598  }
599 }
600 
609 static int retry_generic(enum MenuType mtype, keycode_t *keys, int keyslen, int lastkey)
610 {
611  if ((mtype != MENU_EDITOR) && (mtype != MENU_GENERIC) && (mtype != MENU_PAGER))
612  {
613  if (lastkey)
614  mutt_unget_event(lastkey, 0);
615  for (; keyslen; keyslen--)
616  mutt_unget_event(keys[keyslen - 1], 0);
617  return km_dokey(MENU_GENERIC);
618  }
619  if (mtype != MENU_EDITOR)
620  {
621  /* probably a good idea to flush input here so we can abort macros */
622  mutt_flushinp();
623  }
624  return OP_NULL;
625 }
626 
635 int km_dokey(enum MenuType mtype)
636 {
637  struct KeyEvent tmp;
638  struct Keymap *map = STAILQ_FIRST(&Keymaps[mtype]);
639  int pos = 0;
640  int n = 0;
641 
642  if (!map && (mtype != MENU_EDITOR))
643  return retry_generic(mtype, NULL, 0, 0);
644 
645 #ifdef USE_IMAP
646  const short c_imap_keepalive =
647  cs_subset_number(NeoMutt->sub, "imap_keepalive");
648 #endif
649 
650  while (true)
651  {
652  const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
653  int i = (c_timeout > 0) ? c_timeout : 60;
654 #ifdef USE_IMAP
655  /* keepalive may need to run more frequently than `$timeout` allows */
656  if (c_imap_keepalive)
657  {
658  if (c_imap_keepalive >= i)
659  imap_keepalive();
660  else
661  {
662  while (c_imap_keepalive && (c_imap_keepalive < i))
663  {
664  mutt_getch_timeout(c_imap_keepalive * 1000);
665  tmp = mutt_getch();
666  mutt_getch_timeout(-1);
667  /* If a timeout was not received, or the window was resized, exit the
668  * loop now. Otherwise, continue to loop until reaching a total of
669  * $timeout seconds. */
670  if ((tmp.ch != -2) || SigWinch)
671  goto gotkey;
672 #ifdef USE_INOTIFY
674  goto gotkey;
675 #endif
676  i -= c_imap_keepalive;
677  imap_keepalive();
678  }
679  }
680  }
681 #endif
682 
683  mutt_getch_timeout(i * 1000);
684  tmp = mutt_getch();
685  mutt_getch_timeout(-1);
686 
687 #ifdef USE_IMAP
688  gotkey:
689 #endif
690  /* hide timeouts, but not window resizes, from the line editor. */
691  if ((mtype == MENU_EDITOR) && (tmp.ch == -2) && !SigWinch)
692  continue;
693 
694  LastKey = tmp.ch;
695  if (LastKey < 0)
696  return LastKey;
697 
698  /* do we have an op already? */
699  if (tmp.op)
700  {
701  const char *func = NULL;
702  const struct Binding *bindings = NULL;
703 
704  /* is this a valid op for this menu type? */
705  if ((bindings = km_get_table(mtype)) && (func = mutt_get_func(bindings, tmp.op)))
706  return tmp.op;
707 
708  if ((mtype == MENU_EDITOR) && mutt_get_func(OpEditor, tmp.op))
709  return tmp.op;
710 
711  if ((mtype != MENU_EDITOR) && (mtype != MENU_PAGER))
712  {
713  /* check generic menu type */
714  bindings = OpGeneric;
715  func = mutt_get_func(bindings, tmp.op);
716  if (func)
717  return tmp.op;
718  }
719 
720  /* Sigh. Valid function but not in this context.
721  * Find the literal string and push it back */
722  for (i = 0; MenuNames[i].name; i++)
723  {
724  bindings = km_get_table(MenuNames[i].value);
725  if (bindings)
726  {
727  func = mutt_get_func(bindings, tmp.op);
728  if (func)
729  {
730  mutt_unget_event('>', 0);
731  mutt_unget_string(func);
732  mutt_unget_event('<', 0);
733  break;
734  }
735  }
736  }
737  /* continue to chew */
738  if (func)
739  continue;
740  }
741 
742  if (!map)
743  return tmp.op;
744 
745  /* Nope. Business as usual */
746  while (LastKey > map->keys[pos])
747  {
748  if ((pos > map->eq) || !STAILQ_NEXT(map, entries))
749  return retry_generic(mtype, map->keys, pos, LastKey);
750  map = STAILQ_NEXT(map, entries);
751  }
752 
753  if (LastKey != map->keys[pos])
754  return retry_generic(mtype, map->keys, pos, LastKey);
755 
756  if (++pos == map->len)
757  {
758  if (map->op != OP_MACRO)
759  return map->op;
760 
761  /* OptIgnoreMacroEvents turns off processing the MacroEvents buffer
762  * in mutt_getch(). Generating new macro events during that time would
763  * result in undesired behavior once the option is turned off.
764  *
765  * Originally this returned -1, however that results in an unbuffered
766  * username or password prompt being aborted. Returning OP_NULL allows
767  * mutt_enter_string_full() to display the keybinding pressed instead.
768  *
769  * It may be unexpected for a macro's keybinding to be returned,
770  * but less so than aborting the prompt. */
772  {
773  return OP_NULL;
774  }
775 
776  if (n++ == 10)
777  {
778  mutt_flushinp();
779  mutt_error(_("Macro loop detected"));
780  return -1;
781  }
782 
784  map = STAILQ_FIRST(&Keymaps[mtype]);
785  pos = 0;
786  }
787  }
788 
789  /* not reached */
790 }
791 
797 static void create_bindings(const struct Binding *map, enum MenuType mtype)
798 {
799  STAILQ_INIT(&Keymaps[mtype]);
800 
801  for (int i = 0; map[i].name; i++)
802  if (map[i].seq)
803  km_bindkey(map[i].seq, mtype, map[i].op);
804 }
805 
813 static const char *km_keyname(int c)
814 {
815  static char buf[35];
816 
817  const char *p = mutt_map_get_name(c, KeyNames);
818  if (p)
819  return p;
820 
821  if ((c < 256) && (c > -128) && iscntrl((unsigned char) c))
822  {
823  if (c < 0)
824  c += 256;
825 
826  if (c < 128)
827  {
828  buf[0] = '^';
829  buf[1] = (c + '@') & 0x7f;
830  buf[2] = '\0';
831  }
832  else
833  snprintf(buf, sizeof(buf), "\\%d%d%d", c >> 6, (c >> 3) & 7, c & 7);
834  }
835  else if ((c >= KEY_F0) && (c < KEY_F(256))) /* this maximum is just a guess */
836  sprintf(buf, "<F%d>", c - KEY_F0);
837  else if (IsPrint(c))
838  snprintf(buf, sizeof(buf), "%c", (unsigned char) c);
839  else
840  snprintf(buf, sizeof(buf), "\\x%hx", (unsigned short) c);
841  return buf;
842 }
843 
850 {
851  keycode_t buf[2];
852  const char *const c_abort_key = cs_subset_string(NeoMutt->sub, "abort_key");
853  size_t len = parsekeys(c_abort_key, buf, mutt_array_size(buf));
854  if (len == 0)
855  {
856  mutt_error(_("Abort key is not set, defaulting to Ctrl-G"));
857  AbortKey = ctrl('G');
858  return;
859  }
860  if (len > 1)
861  {
862  mutt_warning(
863  _("Specified abort key sequence (%s) will be truncated to first key"), c_abort_key);
864  }
865  AbortKey = buf[0];
866 }
867 
872 {
873  if ((nc->event_type != NT_CONFIG) || !nc->event_data)
874  return -1;
875 
876  struct EventConfig *ev_c = nc->event_data;
877 
878  if (!mutt_str_equal(ev_c->name, "abort_key"))
879  return 0;
880 
882  mutt_debug(LL_DEBUG5, "config done\n");
883  return 0;
884 }
885 
893 static int km_expand_key_string(char *str, char *buf, size_t buflen)
894 {
895  size_t len = 0;
896  for (; *str; str++)
897  {
898  const char *key = km_keyname(*str);
899  size_t keylen = mutt_str_len(key);
900 
901  mutt_str_copy(buf, key, buflen);
902  buf += keylen;
903  buflen -= keylen;
904  len += keylen;
905  }
906 
907  return len;
908 }
909 
918 int km_expand_key(char *s, size_t len, struct Keymap *map)
919 {
920  if (!map)
921  return 0;
922 
923  int p = 0;
924 
925  while (true)
926  {
927  mutt_str_copy(s, km_keyname(map->keys[p]), len);
928  const size_t l = mutt_str_len(s);
929  len -= l;
930 
931  if ((++p >= map->len) || !len)
932  return 1;
933 
934  s += l;
935  }
936 
937  /* not reached */
938 }
939 
946 struct Keymap *km_find_func(enum MenuType mtype, int func)
947 {
948  struct Keymap *np = NULL;
949  STAILQ_FOREACH(np, &Keymaps[mtype], entries)
950  {
951  if (np->op == func)
952  break;
953  }
954  return np;
955 }
956 
957 #ifdef NCURSES_VERSION
958 
967 static const char *find_ext_name(const char *key)
968 {
969  for (int j = 0; ExtKeys[j].name; j++)
970  {
971  if (strcasecmp(key, ExtKeys[j].name) == 0)
972  return ExtKeys[j].sym;
973  }
974  return 0;
975 }
976 #endif /* NCURSES_VERSION */
977 
989 {
990 #ifdef NCURSES_VERSION
991  use_extended_names(true);
992 
993  for (int j = 0; KeyNames[j].name; j++)
994  {
995  if (KeyNames[j].value == -1)
996  {
997  const char *keyname = find_ext_name(KeyNames[j].name);
998 
999  if (keyname)
1000  {
1001  char *s = tigetstr((char *) keyname);
1002  if (s && ((long) (s) != -1))
1003  {
1004  int code = key_defined(s);
1005  if (code > 0)
1006  KeyNames[j].value = code;
1007  }
1008  }
1009  }
1010  }
1011 #endif
1012 }
1013 
1017 void km_init(void)
1018 {
1019  memset(Keymaps, 0, sizeof(struct KeymapList) * MENU_MAX);
1020 
1029 
1032 
1035 
1036 #ifdef CRYPT_BACKEND_GPGME
1039 #endif
1040 
1041 #ifdef MIXMASTER
1043 
1044  km_bindkey("<space>", MENU_MIX, OP_GENERIC_SELECT_ENTRY);
1045  km_bindkey("h", MENU_MIX, OP_MIX_CHAIN_PREV);
1046  km_bindkey("l", MENU_MIX, OP_MIX_CHAIN_NEXT);
1047 #endif
1048 
1049 #ifdef USE_AUTOCRYPT
1051 #endif
1052 
1053  /* bindings for the line editor */
1055 
1056  km_bindkey("<up>", MENU_EDITOR, OP_EDITOR_HISTORY_UP);
1057  km_bindkey("<down>", MENU_EDITOR, OP_EDITOR_HISTORY_DOWN);
1058  km_bindkey("<left>", MENU_EDITOR, OP_EDITOR_BACKWARD_CHAR);
1059  km_bindkey("<right>", MENU_EDITOR, OP_EDITOR_FORWARD_CHAR);
1060  km_bindkey("<home>", MENU_EDITOR, OP_EDITOR_BOL);
1061  km_bindkey("<end>", MENU_EDITOR, OP_EDITOR_EOL);
1062  km_bindkey("<backspace>", MENU_EDITOR, OP_EDITOR_BACKSPACE);
1063  km_bindkey("<delete>", MENU_EDITOR, OP_EDITOR_DELETE_CHAR);
1064  km_bindkey("\177", MENU_EDITOR, OP_EDITOR_BACKSPACE);
1065 
1066  /* generic menu keymap */
1068 
1069  km_bindkey("<home>", MENU_GENERIC, OP_FIRST_ENTRY);
1070  km_bindkey("<end>", MENU_GENERIC, OP_LAST_ENTRY);
1071  km_bindkey("<pagedown>", MENU_GENERIC, OP_NEXT_PAGE);
1072  km_bindkey("<pageup>", MENU_GENERIC, OP_PREV_PAGE);
1073  km_bindkey("<right>", MENU_GENERIC, OP_NEXT_PAGE);
1074  km_bindkey("<left>", MENU_GENERIC, OP_PREV_PAGE);
1075  km_bindkey("<up>", MENU_GENERIC, OP_PREV_ENTRY);
1076  km_bindkey("<down>", MENU_GENERIC, OP_NEXT_ENTRY);
1077  km_bindkey("1", MENU_GENERIC, OP_JUMP);
1078  km_bindkey("2", MENU_GENERIC, OP_JUMP);
1079  km_bindkey("3", MENU_GENERIC, OP_JUMP);
1080  km_bindkey("4", MENU_GENERIC, OP_JUMP);
1081  km_bindkey("5", MENU_GENERIC, OP_JUMP);
1082  km_bindkey("6", MENU_GENERIC, OP_JUMP);
1083  km_bindkey("7", MENU_GENERIC, OP_JUMP);
1084  km_bindkey("8", MENU_GENERIC, OP_JUMP);
1085  km_bindkey("9", MENU_GENERIC, OP_JUMP);
1086 
1087  km_bindkey("<return>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
1088  km_bindkey("<enter>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
1089 
1090  /* Miscellaneous extra bindings */
1091 
1092  km_bindkey(" ", MENU_MAIN, OP_DISPLAY_MESSAGE);
1093  km_bindkey("<up>", MENU_MAIN, OP_MAIN_PREV_UNDELETED);
1094  km_bindkey("<down>", MENU_MAIN, OP_MAIN_NEXT_UNDELETED);
1095  km_bindkey("J", MENU_MAIN, OP_NEXT_ENTRY);
1096  km_bindkey("K", MENU_MAIN, OP_PREV_ENTRY);
1097  km_bindkey("x", MENU_MAIN, OP_EXIT);
1098 
1099  km_bindkey("<return>", MENU_MAIN, OP_DISPLAY_MESSAGE);
1100  km_bindkey("<enter>", MENU_MAIN, OP_DISPLAY_MESSAGE);
1101 
1102  km_bindkey("x", MENU_PAGER, OP_EXIT);
1103  km_bindkey("i", MENU_PAGER, OP_EXIT);
1104  km_bindkey("<backspace>", MENU_PAGER, OP_PREV_LINE);
1105  km_bindkey("<pagedown>", MENU_PAGER, OP_NEXT_PAGE);
1106  km_bindkey("<pageup>", MENU_PAGER, OP_PREV_PAGE);
1107  km_bindkey("<up>", MENU_PAGER, OP_MAIN_PREV_UNDELETED);
1108  km_bindkey("<right>", MENU_PAGER, OP_MAIN_NEXT_UNDELETED);
1109  km_bindkey("<down>", MENU_PAGER, OP_MAIN_NEXT_UNDELETED);
1110  km_bindkey("<left>", MENU_PAGER, OP_MAIN_PREV_UNDELETED);
1111  km_bindkey("<home>", MENU_PAGER, OP_PAGER_TOP);
1112  km_bindkey("<end>", MENU_PAGER, OP_PAGER_BOTTOM);
1113  km_bindkey("1", MENU_PAGER, OP_JUMP);
1114  km_bindkey("2", MENU_PAGER, OP_JUMP);
1115  km_bindkey("3", MENU_PAGER, OP_JUMP);
1116  km_bindkey("4", MENU_PAGER, OP_JUMP);
1117  km_bindkey("5", MENU_PAGER, OP_JUMP);
1118  km_bindkey("6", MENU_PAGER, OP_JUMP);
1119  km_bindkey("7", MENU_PAGER, OP_JUMP);
1120  km_bindkey("8", MENU_PAGER, OP_JUMP);
1121  km_bindkey("9", MENU_PAGER, OP_JUMP);
1122 
1123  km_bindkey("<return>", MENU_PAGER, OP_NEXT_LINE);
1124  km_bindkey("<enter>", MENU_PAGER, OP_NEXT_LINE);
1125 
1126  km_bindkey("<return>", MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
1127  km_bindkey("<enter>", MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
1128  km_bindkey("<space>", MENU_ALIAS, OP_TAG);
1129 
1130  km_bindkey("<return>", MENU_ATTACH, OP_VIEW_ATTACH);
1131  km_bindkey("<enter>", MENU_ATTACH, OP_VIEW_ATTACH);
1132  km_bindkey("<return>", MENU_COMPOSE, OP_VIEW_ATTACH);
1133  km_bindkey("<enter>", MENU_COMPOSE, OP_VIEW_ATTACH);
1134 
1135  /* edit-to (default "t") hides generic tag-entry in Compose menu
1136  * This will bind tag-entry to "T" in the Compose menu */
1137  km_bindkey("T", MENU_COMPOSE, OP_TAG);
1138 }
1139 
1144 void km_error_key(enum MenuType mtype)
1145 {
1146  char buf[128];
1147  int p, op;
1148 
1149  struct Keymap *key = km_find_func(mtype, OP_HELP);
1150  if (!key && (mtype != MENU_EDITOR) && (mtype != MENU_PAGER))
1151  key = km_find_func(MENU_GENERIC, OP_HELP);
1152  if (!key)
1153  {
1154  mutt_error(_("Key is not bound"));
1155  return;
1156  }
1157 
1158  /* Make sure the key is really the help key in this menu.
1159  *
1160  * OP_END_COND is used as a barrier to ensure nothing extra
1161  * is left in the unget buffer.
1162  *
1163  * Note that km_expand_key() + tokenize_unget_string() should
1164  * not be used here: control sequences are expanded to a form
1165  * (e.g. "^H") not recognized by km_dokey(). */
1166  mutt_unget_event(0, OP_END_COND);
1167  p = key->len;
1168  while (p--)
1169  mutt_unget_event(key->keys[p], 0);
1170 
1171  /* Note, e.g. for the index menu:
1172  * bind generic ? noop
1173  * bind generic ,a help
1174  * bind index ,ab quit
1175  * The index keybinding shadows the generic binding.
1176  * OP_END_COND will be read and returned as the op.
1177  *
1178  * bind generic ? noop
1179  * bind generic dq help
1180  * bind index d delete-message
1181  * OP_DELETE will be returned as the op, leaving "q" + OP_END_COND
1182  * in the unget buffer.
1183  */
1184  op = km_dokey(mtype);
1185  if (op != OP_END_COND)
1187  if (op != OP_HELP)
1188  {
1189  mutt_error(_("Key is not bound"));
1190  return;
1191  }
1192 
1193  km_expand_key(buf, sizeof(buf), key);
1194  mutt_error(_("Key is not bound. Press '%s' for help."), buf);
1195 }
1196 
1200 enum CommandResult mutt_parse_push(struct Buffer *buf, struct Buffer *s,
1201  intptr_t data, struct Buffer *err)
1202 {
1204  if (MoreArgs(s))
1205  {
1206  mutt_buffer_printf(err, _("%s: too many arguments"), "push");
1207  return MUTT_CMD_ERROR;
1208  }
1209 
1211  return MUTT_CMD_SUCCESS;
1212 }
1213 
1228 static char *parse_keymap(enum MenuType *mtypes, struct Buffer *s, int max_menus,
1229  int *num_menus, struct Buffer *err, bool bind)
1230 {
1231  struct Buffer buf;
1232  int i = 0;
1233  char *q = NULL;
1234 
1235  mutt_buffer_init(&buf);
1236 
1237  /* menu name */
1239  char *p = buf.data;
1240  if (MoreArgs(s))
1241  {
1242  while (i < max_menus)
1243  {
1244  q = strchr(p, ',');
1245  if (q)
1246  *q = '\0';
1247 
1248  int val = mutt_map_get_value(p, MenuNames);
1249  if (val == -1)
1250  {
1251  mutt_buffer_printf(err, _("%s: no such menu"), p);
1252  goto error;
1253  }
1254  mtypes[i] = val;
1255  i++;
1256  if (q)
1257  p = q + 1;
1258  else
1259  break;
1260  }
1261  *num_menus = i;
1262  /* key sequence */
1264 
1265  if (buf.data[0] == '\0')
1266  {
1267  mutt_buffer_printf(err, _("%s: null key sequence"), bind ? "bind" : "macro");
1268  }
1269  else if (MoreArgs(s))
1270  return buf.data;
1271  }
1272  else
1273  {
1274  mutt_buffer_printf(err, _("%s: too few arguments"), bind ? "bind" : "macro");
1275  }
1276 error:
1277  FREE(&buf.data);
1278  return NULL;
1279 }
1280 
1290 static enum CommandResult try_bind(char *key, enum MenuType mtype, char *func,
1291  const struct Binding *bindings, struct Buffer *err)
1292 {
1293  for (int i = 0; bindings[i].name; i++)
1294  {
1295  if (mutt_str_equal(func, bindings[i].name))
1296  {
1297  return km_bindkey_err(key, mtype, bindings[i].op, err);
1298  }
1299  }
1300  if (err)
1301  {
1302  mutt_buffer_printf(err, _("Function '%s' not available for menu '%s'"),
1303  func, mutt_map_get_name(mtype, MenuNames));
1304  }
1305  return MUTT_CMD_ERROR; /* Couldn't find an existing function with this name */
1306 }
1307 
1313 const struct Binding *km_get_table(enum MenuType mtype)
1314 {
1315  switch (mtype)
1316  {
1317  case MENU_ALIAS:
1318  return OpAlias;
1319  case MENU_ATTACH:
1320  return OpAttach;
1321 #ifdef USE_AUTOCRYPT
1322  case MENU_AUTOCRYPT_ACCT:
1323  return OpAutocryptAcct;
1324 #endif
1325  case MENU_COMPOSE:
1326  return OpCompose;
1327  case MENU_EDITOR:
1328  return OpEditor;
1329  case MENU_FOLDER:
1330  return OpBrowser;
1331  case MENU_GENERIC:
1332  return OpGeneric;
1333 #ifdef CRYPT_BACKEND_GPGME
1334  case MENU_KEY_SELECT_PGP:
1335  return OpPgp;
1336  case MENU_KEY_SELECT_SMIME:
1337  return OpSmime;
1338 #endif
1339  case MENU_MAIN:
1340  return OpMain;
1341 #ifdef MIXMASTER
1342  case MENU_MIX:
1343  return OpMix;
1344 #endif
1345  case MENU_PAGER:
1346  return OpPager;
1347  case MENU_PGP:
1348  return (WithCrypto & APPLICATION_PGP) ? OpPgp : NULL;
1349  case MENU_POSTPONE:
1350  return OpPost;
1351  case MENU_QUERY:
1352  return OpQuery;
1353  default:
1354  return NULL;
1355  }
1356 }
1357 
1363 enum CommandResult mutt_parse_bind(struct Buffer *buf, struct Buffer *s,
1364  intptr_t data, struct Buffer *err)
1365 {
1366  const struct Binding *bindings = NULL;
1367  enum MenuType mtypes[MenuNamesLen];
1368  int num_menus = 0;
1369  enum CommandResult rc = MUTT_CMD_SUCCESS;
1370 
1371  char *key = parse_keymap(mtypes, s, mutt_array_size(mtypes), &num_menus, err, true);
1372  if (!key)
1373  return MUTT_CMD_ERROR;
1374 
1375  /* function to execute */
1377  if (MoreArgs(s))
1378  {
1379  mutt_buffer_printf(err, _("%s: too many arguments"), "bind");
1380  rc = MUTT_CMD_ERROR;
1381  }
1382  else if (mutt_istr_equal("noop", buf->data))
1383  {
1384  for (int i = 0; i < num_menus; i++)
1385  {
1386  km_bindkey(key, mtypes[i], OP_NULL); /* the 'unbind' command */
1387  bindings = km_get_table(mtypes[i]);
1388  if (bindings)
1389  {
1390  char keystr[32] = { 0 };
1391  km_expand_key_string(key, keystr, sizeof(keystr));
1392  const char *mname = mutt_map_get_name(mtypes[i], MenuNames);
1393  mutt_debug(LL_NOTIFY, "NT_BINDING_DELETE: %s %s\n", mname, keystr);
1394 
1395  int op = get_op(OpGeneric, buf->data, mutt_str_len(buf->data));
1396  struct EventBinding ev_b = { mtypes[i], key, op };
1398  }
1399  }
1400  }
1401  else
1402  {
1403  for (int i = 0; i < num_menus; i++)
1404  {
1405  /* The pager and editor menus don't use the generic map,
1406  * however for other menus try generic first. */
1407  if ((mtypes[i] != MENU_PAGER) && (mtypes[i] != MENU_EDITOR) && (mtypes[i] != MENU_GENERIC))
1408  {
1409  rc = try_bind(key, mtypes[i], buf->data, OpGeneric, err);
1410  if (rc == MUTT_CMD_SUCCESS)
1411  {
1412  char keystr[32] = { 0 };
1413  km_expand_key_string(key, keystr, sizeof(keystr));
1414  const char *mname = mutt_map_get_name(mtypes[i], MenuNames);
1415  mutt_debug(LL_NOTIFY, "NT_BINDING_NEW: %s %s\n", mname, keystr);
1416 
1417  int op = get_op(OpGeneric, buf->data, mutt_str_len(buf->data));
1418  struct EventBinding ev_b = { mtypes[i], key, op };
1420  continue;
1421  }
1422  if (rc == MUTT_CMD_WARNING)
1423  break;
1424  }
1425 
1426  /* Clear any error message, we're going to try again */
1427  err->data[0] = '\0';
1428  bindings = km_get_table(mtypes[i]);
1429  if (bindings)
1430  {
1431  rc = try_bind(key, mtypes[i], buf->data, bindings, err);
1432  if (rc == MUTT_CMD_SUCCESS)
1433  {
1434  char keystr[32] = { 0 };
1435  km_expand_key_string(key, keystr, sizeof(keystr));
1436  const char *mname = mutt_map_get_name(mtypes[i], MenuNames);
1437  mutt_debug(LL_NOTIFY, "NT_BINDING_NEW: %s %s\n", mname, keystr);
1438 
1439  int op = get_op(bindings, buf->data, mutt_str_len(buf->data));
1440  struct EventBinding ev_b = { mtypes[i], key, op };
1442  continue;
1443  }
1444  }
1445  }
1446  }
1447  FREE(&key);
1448  return rc;
1449 }
1450 
1459 static void *parse_menu(bool *menus, char *s, struct Buffer *err)
1460 {
1461  char *menu_names_dup = mutt_str_dup(s);
1462  char *marker = menu_names_dup;
1463  char *menu_name = NULL;
1464 
1465  while ((menu_name = strsep(&marker, ",")))
1466  {
1467  int value = mutt_map_get_value(menu_name, MenuNames);
1468  if (value == -1)
1469  {
1470  mutt_buffer_printf(err, _("%s: no such menu"), menu_name);
1471  break;
1472  }
1473  else
1474  menus[value] = true;
1475  }
1476 
1477  FREE(&menu_names_dup);
1478  return NULL;
1479 }
1480 
1488 static void km_unbind_all(struct KeymapList *km_list, unsigned long mode)
1489 {
1490  struct Keymap *np = NULL, *tmp = NULL;
1491 
1492  STAILQ_FOREACH_SAFE(np, km_list, entries, tmp)
1493  {
1494  if (((mode & MUTT_UNBIND) && !np->macro) || ((mode & MUTT_UNMACRO) && np->macro))
1495  {
1496  STAILQ_REMOVE(km_list, np, Keymap, entries);
1497  mutt_keymap_free(&np);
1498  }
1499  }
1500 }
1501 
1512 enum CommandResult mutt_parse_unbind(struct Buffer *buf, struct Buffer *s,
1513  intptr_t data, struct Buffer *err)
1514 {
1515  bool menu_matches[MENU_MAX] = { 0 };
1516  bool all_keys = false;
1517  char *key = NULL;
1518 
1520  if (mutt_str_equal(buf->data, "*"))
1521  {
1522  for (enum MenuType i = 0; i < MENU_MAX; i++)
1523  menu_matches[i] = true;
1524  }
1525  else
1526  parse_menu(menu_matches, buf->data, err);
1527 
1528  if (MoreArgs(s))
1529  {
1531  key = buf->data;
1532  }
1533  else
1534  all_keys = true;
1535 
1536  if (MoreArgs(s))
1537  {
1538  const char *cmd = (data & MUTT_UNMACRO) ? "unmacro" : "unbind";
1539 
1540  mutt_buffer_printf(err, _("%s: too many arguments"), cmd);
1541  return MUTT_CMD_ERROR;
1542  }
1543 
1544  for (enum MenuType i = 0; i < MENU_MAX; i++)
1545  {
1546  if (!menu_matches[i])
1547  continue;
1548  if (all_keys)
1549  {
1550  km_unbind_all(&Keymaps[i], data);
1551  km_bindkey("<enter>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
1552  km_bindkey("<return>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
1553  km_bindkey("<enter>", MENU_MAIN, OP_DISPLAY_MESSAGE);
1554  km_bindkey("<return>", MENU_MAIN, OP_DISPLAY_MESSAGE);
1555  km_bindkey("<backspace>", MENU_EDITOR, OP_EDITOR_BACKSPACE);
1556  km_bindkey("\177", MENU_EDITOR, OP_EDITOR_BACKSPACE);
1557  km_bindkey(":", MENU_GENERIC, OP_ENTER_COMMAND);
1558  km_bindkey(":", MENU_PAGER, OP_ENTER_COMMAND);
1559  if (i != MENU_EDITOR)
1560  {
1561  km_bindkey("?", i, OP_HELP);
1562  km_bindkey("q", i, OP_EXIT);
1563  }
1564 
1565  const char *mname = mutt_map_get_name(i, MenuNames);
1566  mutt_debug(LL_NOTIFY, "NT_MACRO_DELETE_ALL: %s\n", mname);
1567 
1568  struct EventBinding ev_b = { i, NULL, OP_NULL };
1571  &ev_b);
1572  }
1573  else
1574  {
1575  char keystr[32] = { 0 };
1576  km_expand_key_string(key, keystr, sizeof(keystr));
1577  const char *mname = mutt_map_get_name(i, MenuNames);
1578  mutt_debug(LL_NOTIFY, "NT_MACRO_DELETE: %s %s\n", mname, keystr);
1579 
1580  km_bindkey(key, i, OP_NULL);
1581  struct EventBinding ev_b = { i, key, OP_NULL };
1583  (data & MUTT_UNMACRO) ? NT_MACRO_DELETE : NT_BINDING_DELETE, &ev_b);
1584  }
1585  }
1586 
1587  return MUTT_CMD_SUCCESS;
1588 }
1589 
1595 enum CommandResult mutt_parse_macro(struct Buffer *buf, struct Buffer *s,
1596  intptr_t data, struct Buffer *err)
1597 {
1598  enum MenuType mtypes[MenuNamesLen];
1599  int num_menus = 0;
1600  enum CommandResult rc = MUTT_CMD_ERROR;
1601 
1602  char *key = parse_keymap(mtypes, s, mutt_array_size(mtypes), &num_menus, err, false);
1603  if (!key)
1604  return MUTT_CMD_ERROR;
1605 
1607  /* make sure the macro sequence is not an empty string */
1608  if (buf->data[0] == '\0')
1609  {
1610  mutt_buffer_strcpy(err, _("macro: empty key sequence"));
1611  }
1612  else
1613  {
1614  if (MoreArgs(s))
1615  {
1616  char *seq = mutt_str_dup(buf->data);
1618 
1619  if (MoreArgs(s))
1620  {
1621  mutt_buffer_printf(err, _("%s: too many arguments"), "macro");
1622  }
1623  else
1624  {
1625  for (int i = 0; i < num_menus; i++)
1626  {
1627  rc = km_bind(key, mtypes[i], OP_MACRO, seq, buf->data);
1628  if (rc == MUTT_CMD_SUCCESS)
1629  {
1630  char keystr[32] = { 0 };
1631  km_expand_key_string(key, keystr, sizeof(keystr));
1632  const char *mname = mutt_map_get_name(mtypes[i], MenuNames);
1633  mutt_debug(LL_NOTIFY, "NT_MACRO_NEW: %s %s\n", mname, keystr);
1634 
1635  struct EventBinding ev_b = { mtypes[i], key, OP_MACRO };
1637  continue;
1638  }
1639  }
1640  }
1641 
1642  FREE(&seq);
1643  }
1644  else
1645  {
1646  for (int i = 0; i < num_menus; i++)
1647  {
1648  rc = km_bind(key, mtypes[i], OP_MACRO, buf->data, NULL);
1649  if (rc == MUTT_CMD_SUCCESS)
1650  {
1651  char keystr[32] = { 0 };
1652  km_expand_key_string(key, keystr, sizeof(keystr));
1653  const char *mname = mutt_map_get_name(mtypes[i], MenuNames);
1654  mutt_debug(LL_NOTIFY, "NT_MACRO_NEW: %s %s\n", mname, keystr);
1655 
1656  struct EventBinding ev_b = { mtypes[i], key, OP_MACRO };
1658  continue;
1659  }
1660  }
1661  }
1662  }
1663  FREE(&key);
1664  return rc;
1665 }
1666 
1670 enum CommandResult mutt_parse_exec(struct Buffer *buf, struct Buffer *s,
1671  intptr_t data, struct Buffer *err)
1672 {
1673  int ops[128];
1674  int nops = 0;
1675  const struct Binding *bindings = NULL;
1676  char *function = NULL;
1677 
1678  if (!MoreArgs(s))
1679  {
1680  mutt_buffer_strcpy(err, _("exec: no arguments"));
1681  return MUTT_CMD_ERROR;
1682  }
1683 
1684  do
1685  {
1687  function = buf->data;
1688 
1689  const enum MenuType mtype = menu_get_current_type();
1690  bindings = km_get_table(mtype);
1691  if (!bindings && (mtype != MENU_PAGER))
1692  bindings = OpGeneric;
1693 
1694  ops[nops] = get_op(bindings, function, mutt_str_len(function));
1695  if ((ops[nops] == OP_NULL) && (mtype != MENU_PAGER))
1696  ops[nops] = get_op(OpGeneric, function, mutt_str_len(function));
1697 
1698  if (ops[nops] == OP_NULL)
1699  {
1700  mutt_flushinp();
1701  mutt_error(_("%s: no such function"), function);
1702  return MUTT_CMD_ERROR;
1703  }
1704  nops++;
1705  } while (MoreArgs(s) && nops < mutt_array_size(ops));
1706 
1707  while (nops)
1708  mutt_push_macro_event(0, ops[--nops]);
1709 
1710  return MUTT_CMD_SUCCESS;
1711 }
1712 
1718 void mutt_what_key(void)
1719 {
1720  int ch;
1721 
1722  struct MuttWindow *win = msgwin_get_window();
1723  if (!win)
1724  return;
1725 
1726  mutt_window_mvprintw(win, 0, 0, _("Enter keys (%s to abort): "), km_keyname(AbortKey));
1727  do
1728  {
1729  ch = getch();
1730  if ((ch != ERR) && (ch != AbortKey))
1731  {
1732  mutt_message(_("Char = %s, Octal = %o, Decimal = %d"), km_keyname(ch), ch, ch);
1733  }
1734  } while (ch != ERR && ch != AbortKey);
1735 
1736  mutt_flushinp();
1737  mutt_clear_error();
1738 }
1739 
1743 void mutt_keys_free(void)
1744 {
1745  for (int i = 0; i < MENU_MAX; i++)
1746  {
1748  }
1749 }
const struct Binding OpPager[]
Key bindings for the pager menu.
Definition: functions.c:263
short eq
number of leading keys equal to next entry
Definition: keymap.h:53
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
Convenience wrapper for the gui headers.
static const char * km_keyname(int c)
Get the human name for a key.
Definition: keymap.c:813
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function&#39;s mapping in a Menu.
Definition: keymap.c:946
Key macro has been added.
Definition: keymap.h:121
Manage keymappings.
static enum CommandResult km_bindkey_err(const char *s, enum MenuType mtype, int op, struct Buffer *err)
Bind a key in a Menu to an operation (with error message)
Definition: keymap.c:468
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
MenuType
Types of GUI selections.
Definition: type.h:35
#define WithCrypto
Definition: lib.h:113
IMAP network mailbox.
const struct Binding OpPgp[]
Key bindings for the pgp menu.
Definition: functions.c:647
const int MenuNamesLen
Definition: type.c:56
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:34
Config/command parsing.
Data passed to a notification function.
Definition: observer.h:39
struct KeymapList Keymaps[MENU_MAX]
Array of Keymap keybindings, one for each Menu.
Definition: keymap.c:126
Error: Can&#39;t help the user.
Definition: mutt_commands.h:36
Log of notifications.
Definition: logging.h:45
PGP encryption menu.
Definition: type.h:55
#define mutt_error(...)
Definition: logging.h:88
static void create_bindings(const struct Binding *map, enum MenuType mtype)
Attach a set of keybindings to a Menu.
Definition: keymap.c:797
Generic selection list.
Definition: type.h:45
void mutt_push_macro_event(int ch, int op)
Add the character/operation to the macro buffer.
Definition: curs_lib.c:620
int op
function id number
Definition: keymap.h:94
static int parse_keycode(const char *s)
Parse a numeric keycode.
Definition: keymap.c:253
void imap_keepalive(void)
poll the current folder to keep the connection alive
Definition: util.c:948
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:668
keycode_t * keys
key sequence
Definition: keymap.h:55
int op
Operation the key&#39;s bound to (for bind), e.g. OP_DELETE.
Definition: keymap.h:105
NeoMutt Logging.
A config-change event.
Definition: subset.h:69
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:621
static enum CommandResult try_bind(char *key, enum MenuType mtype, char *func, const struct Binding *bindings, struct Buffer *err)
Try to make a key binding.
Definition: keymap.c:1290
String manipulation buffer.
Definition: buffer.h:33
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:583
#define _(a)
Definition: message.h:28
void km_init(void)
Initialise all the menu keybindings.
Definition: keymap.c:1017
enum CommandResult mutt_parse_bind(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;bind&#39; command - Implements Command::parse() -bind menu-name <key_sequence> function-name...
Definition: keymap.c:1363
int op
function op
Definition: keymap.h:67
int ch
raw key pressed
Definition: keymap.h:66
WHERE bool OptIgnoreMacroEvents
(pseudo) don&#39;t process macro/push/exec events while set
Definition: options.h:37
bool MonitorFilesChanged
true after a monitored file has changed
Definition: monitor.c:51
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:389
Compose an email.
Definition: type.h:42
#define MUTT_UNMACRO
Definition: keymap.h:34
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define IsPrint(ch)
Definition: mbyte.h:38
int value
Definition: mapping.h:34
All user-callable functions.
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
enum CommandResult mutt_parse_macro(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;macro&#39; command - Implements Command::parse() -macro <menu> <key> <macro> <description> ...
Definition: keymap.c:1595
Convenience wrapper for the config headers.
const struct Binding OpCompose[]
Key bindings for the compose menu.
Definition: functions.c:457
All key bindings have been deleted.
Definition: keymap.h:119
const struct Binding OpSmime[]
Key bindings for the smime menu.
Definition: functions.c:656
const char * key
Key string being bound (for new bind/macro)
Definition: keymap.h:104
enum CommandResult mutt_parse_unbind(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unbind&#39; command - Implements Command::parse() -Command unbinds:
Definition: keymap.c:1512
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: keymap.c:988
#define mutt_array_size(x)
Definition: memory.h:33
Definition: type.h:59
Pager pager (email viewer)
Definition: type.h:54
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition: mapping.c:42
size_t dsize
Length of data.
Definition: buffer.h:37
#define MoreArgs(buf)
Definition: buffer.h:40
const char * mutt_get_func(const struct Binding *bindings, int op)
Get the name of a function.
Definition: keymap.c:516
int main_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: keymap.c:871
const struct Binding OpMix[]
Key bindings for the mixmaster menu.
Definition: functions.c:668
Many unsorted constants and some structs.
#define STAILQ_INIT(head)
Definition: queue.h:372
Text entry area.
Definition: type.h:43
static enum CommandResult km_bindkey(const char *s, enum MenuType mtype, int op)
Bind a key in a Menu to an operation.
Definition: keymap.c:481
struct MuttWindow * msgwin_get_window(void)
Get the Message Window pointer.
Definition: msgwin.c:253
const struct Binding OpAlias[]
Key bindings for the alias menu.
Definition: functions.c:536
void mutt_what_key(void)
Ask the user to press a key.
Definition: keymap.c:1718
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.c:53
int LastKey
contains the last key the user pressed
Definition: keymap.c:123
Convenience wrapper for the core headers.
void km_error_key(enum MenuType mtype)
Handle an unbound key sequence.
Definition: keymap.c:1144
static size_t parsekeys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition: keymap.c:276
const char * name
name of the function
Definition: keymap.h:93
short op
operation to perform
Definition: keymap.h:52
static char * parse_keymap(enum MenuType *mtypes, struct Buffer *s, int max_menus, int *num_menus, struct Buffer *err, bool bind)
Parse a user-config key binding.
Definition: keymap.c:1228
static void * parse_menu(bool *menus, char *s, struct Buffer *err)
Parse menu-names into an array.
Definition: keymap.c:1459
Key binding has changed, NotifyBinding, EventBinding.
Definition: notify_type.h:38
Select a PGP key.
Definition: type.h:47
#define ctrl(ch)
Definition: mutt_curses.h:66
Select an attachment.
Definition: type.h:38
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
#define mutt_warning(...)
Definition: logging.h:86
Key macro has been deleted.
Definition: keymap.h:122
All key macros have been deleted.
Definition: keymap.h:123
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
Select from results of external query.
Definition: type.h:57
const struct Binding OpPost[]
Key bindings for the postpone menu.
Definition: functions.c:527
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: keymap.c:849
Key binding has been added.
Definition: keymap.h:117
#define MUTT_TOKEN_CONDENSE
^(char) to control chars (macros)
Definition: mutt.h:68
static int parse_fkey(char *s)
Parse a function key string.
Definition: keymap.c:226
Select a postponed email.
Definition: type.h:56
static struct Keymap * alloc_keys(size_t len, keycode_t *keys)
Allocate space for a sequence of keys.
Definition: keymap.c:210
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1743
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:395
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:918
static int km_expand_key_string(char *str, char *buf, size_t buflen)
Get a human-readable key string.
Definition: keymap.c:893
char * macro
macro expansion (op == OP_MACRO)
Definition: keymap.h:50
enum CommandResult km_bind(char *s, enum MenuType mtype, int op, char *macro, char *desc)
Bind a key to a macro.
Definition: keymap.c:455
char * data
Pointer to data.
Definition: buffer.h:35
static void generic_tokenize_push_string(char *s, void(*generic_push)(int, int))
Parse and queue a &#39;push&#39; command.
Definition: keymap.c:536
enum CommandResult mutt_parse_exec(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;exec&#39; command - Implements Command::parse() -.
Definition: keymap.c:1670
Definitions of NeoMutt commands.
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
API for encryption/signing of emails.
#define STAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:383
Create/edit a Mixmaster chain.
Definition: type.h:52
static int retry_generic(enum MenuType mtype, keycode_t *keys, int keyslen, int lastkey)
Try to find the key in the generic menu bindings.
Definition: keymap.c:609
Index panel (list of emails)
Definition: type.h:50
An event such as a keypress.
Definition: keymap.h:64
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:196
short keycode_t
Type for key storage, the rest of neomutt works fine with int type.
Definition: keymap.h:39
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
char * desc
description of a macro for the help menu
Definition: keymap.h:51
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
const struct Binding * km_get_table(enum MenuType mtype)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1313
const struct Binding OpQuery[]
Key bindings for the external query menu.
Definition: functions.c:601
keycode_t AbortKey
code of key to abort prompts, normally Ctrl-G
Definition: keymap.c:124
Autocrypt Account menu.
Definition: type.h:40
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
A keyboard mapping.
Definition: keymap.h:48
void * event_data
Data from notify_send()
Definition: observer.h:44
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
General file/mailbox browser.
Definition: type.h:44
#define IS_SPACE(ch)
Definition: string2.h:38
short len
length of key sequence (unit: sizeof (keycode_t))
Definition: keymap.h:54
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
Success: Command worked.
Definition: mutt_commands.h:38
Definitions of user functions.
Warning: Help given to the user.
Definition: mutt_commands.h:37
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:749
Select a SMIME key.
Definition: type.h:48
enum CommandResult mutt_parse_push(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;push&#39; command - Implements Command::parse() -.
Definition: keymap.c:1200
void mutt_flush_unget_to_endcond(void)
Clear entries from UngetKeyEvents.
Definition: curs_lib.c:656
void mutt_getch_timeout(int delay)
Set the getch() timeout.
Definition: curs_lib.c:153
const struct Binding OpEditor[]
Key bindings for the editor menu.
Definition: functions.c:615
const char * seq
default key binding
Definition: keymap.h:95
const struct Mapping MenuNames[]
Menu name lookup table.
Definition: type.c:31
static void mutt_keymap_free(struct Keymap **km)
Free a Keymap.
Definition: keymap.c:179
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
static struct Keymap * km_compare_keys(struct Keymap *k1, struct Keymap *k2, size_t *pos)
Compare two keymaps&#39; keyscodes and return the bigger one.
Definition: keymap.c:335
Mapping between user-readable string and a constant.
Definition: mapping.h:31
#define MAX_SEQ
Definition: keymap.h:36
Monitor files for changes.
void mutt_unget_string(const char *s)
Return a string to the input buffer.
Definition: curs_lib.c:602
#define MUTT_UNBIND
Definition: keymap.h:33
int mutt_window_mvprintw(struct MuttWindow *win, int col, int row, const char *fmt,...)
Move the cursor and write a formatted string to a Window.
Definition: mutt_window.c:343
const struct Binding OpMain[]
Key bindings for the index menu.
Definition: functions.c:102
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
const char * name
Definition: mapping.h:33
SMIME encryption menu.
Definition: type.h:58
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
Select an email address by its alias.
Definition: type.h:37
int km_dokey(enum MenuType mtype)
Determine what a keypress should do.
Definition: keymap.c:635
Log at debug level 5.
Definition: logging.h:44
Convenience wrapper for the library headers.
static int get_op(const struct Binding *bindings, const char *start, size_t len)
Get the function by its name.
Definition: keymap.c:493
static void mutt_keymaplist_free(struct KeymapList *km_list)
Free a List of Keymaps.
Definition: keymap.c:194
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: mutt_globals.h:68
#define STAILQ_FIRST(head)
Definition: queue.h:350
const char * name
Name of config item that changed.
Definition: subset.h:72
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field)
Definition: queue.h:377
Mapping between a user key and a function.
Definition: keymap.h:91
const struct Binding OpAutocryptAcct[]
Key bindings for the autocrypt account.
Definition: functions.c:684
static enum CommandResult km_bind_err(const char *s, enum MenuType mtype, int op, char *macro, char *desc, struct Buffer *err)
Set up a key binding.
Definition: keymap.c:363
const struct Binding OpBrowser[]
Key bindings for the file browser menu.
Definition: functions.c:548
A key binding Event.
Definition: keymap.h:101
const struct Binding OpAttach[]
Key bindings for the attachment menu.
Definition: functions.c:420
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:66
static void km_unbind_all(struct KeymapList *km_list, unsigned long mode)
Free all the keys in the supplied Keymap.
Definition: keymap.c:1488
Key binding has been deleted.
Definition: keymap.h:118
int mutt_map_get_value(const char *name, const struct Mapping *map)
Lookup the constant for a string.
Definition: mapping.c:85
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171