From f8f27f06c65cf6eaf2c5366d50054d9b8d70e8fa Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Sun, 4 Oct 2015 10:08:49 +0800 Subject: [PATCH] Create a separate macro/push/exec event buffer. (closes #3779) Currently, the SSL and TLS certficate prompts turn on OPTUNBUFFEREDINPUT, (to prevent macros and such from running right through the dialog). Unfortunately, the menu dialog processing in menu_dialog_dokey() is using mutt_ungetch() to forward non-dialog keys on to standard menu processing. With OPTUNBUFFEREDINPUT set, those keys never make it to the menu and are buffered until after the menu dialog. This patch creates a new event buffer, separate from the standard "unget" buffer, for use by macros, exec, and push events. These events can be temporarily ignored by setting OPTIGNOREMACROEVENTS (renamed from OPTUNBUFFEREDINPUT), while continuing to allow unget events to be processed. Since the "push" and "unget" functions now go to different buffers, function names were slightly renamed, to make it less easy to unintentionally use the wrong function at the wrong time. --- browser.c | 2 +- commands.c | 2 +- curs_lib.c | 78 +++++++++++++++++++++++++++++++++++++++-------- curs_main.c | 11 ++----- keymap.c | 41 +++++++++++++++---------- menu.c | 13 ++------ mutt.h | 5 +-- mutt_curses.h | 5 ++- mutt_ssl.c | 4 +-- mutt_ssl_gnutls.c | 4 +-- 10 files changed, 106 insertions(+), 59 deletions(-) diff --git a/browser.c b/browser.c index cda4900a3..c47aa7e81 100644 --- a/browser.c +++ b/browser.c @@ -896,7 +896,7 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num else set_option (OPTIMAPLSUB); - mutt_ungetch (0, OP_CHECK_NEW); + mutt_unget_event (0, OP_CHECK_NEW); break; case OP_CREATE_MAILBOX: diff --git a/commands.c b/commands.c index 5dbd10085..b334c7b6e 100644 --- a/commands.c +++ b/commands.c @@ -228,7 +228,7 @@ int mutt_display_message (HEADER *cur) mutt_set_flag (Context, cur, M_READ, 1); if (r != -1 && option (OPTPROMPTAFTER)) { - mutt_ungetch (mutt_any_key_to_continue _("Command: "), 0); + mutt_unget_event (mutt_any_key_to_continue _("Command: "), 0); rc = km_dokey (MENU_PAGER); } else diff --git a/curs_lib.c b/curs_lib.c index d8c62c360..d70c327f8 100644 --- a/curs_lib.c +++ b/curs_lib.c @@ -48,9 +48,20 @@ * is impossible to unget function keys in SLang, so roll our own input * buffering routines. */ -size_t UngetCount = 0; -static size_t UngetBufLen = 0; -static event_t *KeyEvent; + +/* These are used for macros and exec/push commands. + * They can be temporarily ignored by setting OPTIGNOREMACROEVENTS + */ +static size_t MacroBufferCount = 0; +static size_t MacroBufferLen = 0; +static event_t *MacroEvents; + +/* These are used in all other "normal" situations, and are not + * ignored when setting OPTIGNOREMACROEVENTS + */ +static size_t UngetCount = 0; +static size_t UngetLen = 0; +static event_t *UngetKeyEvents; void mutt_refresh (void) { @@ -83,8 +94,11 @@ event_t mutt_getch (void) event_t err = {-1, OP_NULL }, ret; event_t timeout = {-2, OP_NULL}; - if (!option(OPTUNBUFFEREDINPUT) && UngetCount) - return (KeyEvent[--UngetCount]); + if (UngetCount) + return (UngetKeyEvents[--UngetCount]); + + if (!option(OPTIGNOREMACROEVENTS) && MacroBufferCount) + return (MacroEvents[--MacroBufferCount]); SigInt = 0; @@ -118,7 +132,7 @@ event_t mutt_getch (void) { /* send ALT-x as ESC-x */ ch &= ~0x80; - mutt_ungetch (ch, 0); + mutt_unget_event (ch, 0); ret.ch = '\033'; ret.op = 0; return ret; @@ -157,9 +171,9 @@ int mutt_get_field_unbuffered (char *msg, char *buf, size_t buflen, int flags) { int rc; - set_option (OPTUNBUFFEREDINPUT); + set_option (OPTIGNOREMACROEVENTS); rc = mutt_get_field (msg, buf, buflen, flags); - unset_option (OPTUNBUFFEREDINPUT); + unset_option (OPTIGNOREMACROEVENTS); return (rc); } @@ -595,7 +609,7 @@ int _mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, char *pc = safe_malloc (mutt_strlen (prompt) + 3); sprintf (pc, "%s: ", prompt); /* __SPRINTF_CHECKED__ */ - mutt_ungetch (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0); + mutt_unget_event (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0); if (_mutt_get_field (pc, buf, blen, (buffy ? M_EFILE : M_FILE) | M_CLEAR, multiple, files, numfiles) != 0) buf[0] = 0; @@ -606,22 +620,60 @@ int _mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, return 0; } -void mutt_ungetch (int ch, int op) +void mutt_unget_event (int ch, int op) +{ + event_t tmp; + + tmp.ch = ch; + tmp.op = op; + + if (UngetCount >= UngetLen) + safe_realloc (&UngetKeyEvents, (UngetLen += 16) * sizeof(event_t)); + + UngetKeyEvents[UngetCount++] = tmp; +} + +void mutt_unget_string (char *s) +{ + char *p = s + mutt_strlen (s) - 1; + + while (p >= s) + { + mutt_unget_event ((unsigned char)*p--, 0); + } +} + +/* + * Adds the ch/op to the macro buffer. + * This should be used for macros, push, and exec commands only. + */ +void mutt_push_macro_event (int ch, int op) { event_t tmp; tmp.ch = ch; tmp.op = op; - if (UngetCount >= UngetBufLen) - safe_realloc (&KeyEvent, (UngetBufLen += 128) * sizeof(event_t)); + if (MacroBufferCount >= MacroBufferLen) + safe_realloc (&MacroEvents, (MacroBufferLen += 128) * sizeof(event_t)); + + MacroEvents[MacroBufferCount++] = tmp; +} - KeyEvent[UngetCount++] = tmp; +void mutt_flush_macro_to_endcond (void) +{ + UngetCount = 0; + while (MacroBufferCount > 0) + { + if (MacroEvents[--MacroBufferCount].op == OP_END_COND) + return; + } } void mutt_flushinp (void) { UngetCount = 0; + MacroBufferCount = 0; flushinp (); } diff --git a/curs_main.c b/curs_main.c index 425bd9aec..48fa6bbc1 100644 --- a/curs_main.c +++ b/curs_main.c @@ -109,8 +109,6 @@ static const char *No_visible = N_("No visible messages."); #define OLDHDR Context->hdrs[Context->v2r[menu->oldcurrent]] #define UNREAD(h) mutt_thread_contains_unread (Context, h) -extern size_t UngetCount; - /* de facto standard escapes for tsl/fsl */ static char *tsl = "\033]0;"; static char *fsl = "\007"; @@ -729,12 +727,7 @@ int mutt_index_menu (void) if (!Context->tagged) { - event_t tmp; - while(UngetCount>0) - { - tmp=mutt_getch(); - if(tmp.op==OP_END_COND)break; - } + mutt_flush_macro_to_endcond (); mutt_message _("Nothing to do."); continue; } @@ -819,7 +812,7 @@ int mutt_index_menu (void) CHECK_MSGCOUNT; CHECK_VISIBLE; - if (isdigit (LastKey)) mutt_ungetch (LastKey, 0); + if (isdigit (LastKey)) mutt_unget_event (LastKey, 0); buf[0] = 0; if (mutt_get_field (_("Jump to message: "), buf, sizeof (buf), 0) != 0 || !buf[0]) diff --git a/keymap.c b/keymap.c index 1710b17d1..40ea7455e 100644 --- a/keymap.c +++ b/keymap.c @@ -325,7 +325,12 @@ static char *get_func (const struct binding_t *bindings, int op) return NULL; } -static void push_string (char *s) +/* Parses s for syntax and adds the whole sequence to + * the macro buffer. + * + * This should be used for macros, push, and exec commands only. + */ +static void tokenize_push_macro_string (char *s) { char *pp, *p = s + mutt_strlen (s) - 1; size_t l; @@ -343,7 +348,7 @@ static void push_string (char *s) { if ((i = parse_fkey (pp)) > 0) { - mutt_ungetch (KEY_F (i), 0); + mutt_push_macro_event (KEY_F (i), 0); p = pp - 1; continue; } @@ -357,7 +362,7 @@ static void push_string (char *s) if (KeyNames[i].name) { /* found a match */ - mutt_ungetch (KeyNames[i].value, 0); + mutt_push_macro_event (KeyNames[i].value, 0); p = pp - 1; continue; } @@ -377,13 +382,13 @@ static void push_string (char *s) if (op != OP_NULL) { - mutt_ungetch (0, op); + mutt_push_macro_event (0, op); p = pp - 1; continue; } } } - mutt_ungetch ((unsigned char)*p--, 0); /* independent 8 bits chars */ + mutt_push_macro_event ((unsigned char)*p--, 0); /* independent 8 bits chars */ } } @@ -392,9 +397,9 @@ static int retry_generic (int menu, keycode_t *keys, int keyslen, int lastkey) if (menu != MENU_EDITOR && menu != MENU_GENERIC && menu != MENU_PAGER) { if (lastkey) - mutt_ungetch (lastkey, 0); + mutt_unget_event (lastkey, 0); for (; keyslen; keyslen--) - mutt_ungetch (keys[keyslen - 1], 0); + mutt_unget_event (keys[keyslen - 1], 0); return (km_dokey (MENU_GENERIC)); } if (menu != MENU_EDITOR) @@ -495,11 +500,9 @@ int km_dokey (int menu) func = get_func (bindings, tmp.op); if (func) { - /* careful not to feed the <..> as one token. otherwise - * push_string() will push the bogus op right back! */ - mutt_ungetch ('>', 0); - push_string (func); - mutt_ungetch ('<', 0); + mutt_unget_event ('>', 0); + mutt_unget_string (func); + mutt_unget_event ('<', 0); break; } } @@ -526,6 +529,12 @@ int km_dokey (int menu) if (map->op != OP_MACRO) return map->op; + if (option (OPTIGNOREMACROEVENTS)) + { + mutt_error _("Macros are currently disabled."); + return -1; + } + if (n++ == 10) { mutt_flushinp (); @@ -533,7 +542,7 @@ int km_dokey (int menu) return -1; } - push_string (map->macro); + tokenize_push_macro_string (map->macro); map = Keymaps[menu]; pos = 0; } @@ -835,7 +844,7 @@ void km_error_key (int menu) } /* make sure the key is really the help key in this menu */ - push_string (buf); + mutt_unget_string (buf); if (km_dokey (menu) != OP_HELP) { mutt_error _("Key is not bound."); @@ -857,7 +866,7 @@ int mutt_parse_push (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) r = -1; } else - push_string (buf->data); + tokenize_push_macro_string (buf->data); return (r); } @@ -1107,7 +1116,7 @@ int mutt_parse_exec (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) while(MoreArgs(s) && nops < sizeof(ops)/sizeof(ops[0])); while(nops) - mutt_ungetch(0, ops[--nops]); + mutt_push_macro_event (0, ops[--nops]); return 0; } diff --git a/menu.c b/menu.c index 578593ebc..828df9c10 100644 --- a/menu.c +++ b/menu.c @@ -25,8 +25,6 @@ #include "mutt_menu.h" #include "mbyte.h" -extern size_t UngetCount; - char* SearchBuffers[MENU_MAX]; static void print_enriched_string (int attr, unsigned char *s, int do_color) @@ -415,7 +413,7 @@ void menu_jump (MUTTMENU *menu) if (menu->max) { - mutt_ungetch (LastKey, 0); + mutt_unget_event (LastKey, 0); buf[0] = 0; if (mutt_get_field (_("Jump to: "), buf, sizeof (buf), 0) == 0 && buf[0]) { @@ -817,7 +815,7 @@ static int menu_dialog_dokey (MUTTMENU *menu, int *ip) } else { - mutt_ungetch (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0); + mutt_unget_event (ch.op ? 0 : ch.ch, ch.op ? ch.op : 0); return -1; } } @@ -905,12 +903,7 @@ int mutt_menuLoop (MUTTMENU *menu) } else /* None tagged, OP_TAG_PREFIX_COND */ { - event_t tmp; - while(UngetCount>0) - { - tmp=mutt_getch(); - if(tmp.op==OP_END_COND)break; - } + mutt_flush_macro_to_endcond (); mutt_message _("Nothing to do."); i = -1; } diff --git a/mutt.h b/mutt.h index f8565fae8..19d268045 100644 --- a/mutt.h +++ b/mutt.h @@ -98,9 +98,6 @@ #define M_TOKEN_COMMENT (1<<5) /* don't reap comments */ #define M_TOKEN_SEMICOLON (1<<6) /* don't treat ; as special */ -/* flags for km_dokey() */ -#define M_KM_UNBUFFERED 1 /* don't read from the key buffer */ - typedef struct { char *data; /* pointer to data */ @@ -513,7 +510,7 @@ enum OPTREDRAWTREE, /* (pseudo) redraw the thread tree */ OPTPGPCHECKTRUST, /* (pseudo) used by pgp_select_key () */ OPTDONTHANDLEPGPKEYS, /* (pseudo) used to extract PGP keys */ - OPTUNBUFFEREDINPUT, /* (pseudo) don't use key buffer */ + OPTIGNOREMACROEVENTS, /* (pseudo) don't process macro/push/exec events while set */ OPTMAX }; diff --git a/mutt_curses.h b/mutt_curses.h index f8bc47cc4..543639b3d 100644 --- a/mutt_curses.h +++ b/mutt_curses.h @@ -93,7 +93,10 @@ void mutt_endwin (const char *); void mutt_flushinp (void); void mutt_refresh (void); void mutt_resize_screen (void); -void mutt_ungetch (int, int); +void mutt_unget_event (int, int); +void mutt_unget_string (char *); +void mutt_push_macro_event (int, int); +void mutt_flush_macro_to_endcond (void); void mutt_need_hard_redraw (void); /* ---------------------------------------------------------------------------- diff --git a/mutt_ssl.c b/mutt_ssl.c index 9d1af09b1..714b8c64b 100644 --- a/mutt_ssl.c +++ b/mutt_ssl.c @@ -1051,7 +1051,7 @@ static int interactive_check_cert (X509 *cert, int idx, int len) menu->help = helpstr; done = 0; - set_option(OPTUNBUFFEREDINPUT); + set_option(OPTIGNOREMACROEVENTS); while (!done) { switch (mutt_menuLoop (menu)) @@ -1086,7 +1086,7 @@ static int interactive_check_cert (X509 *cert, int idx, int len) break; } } - unset_option(OPTUNBUFFEREDINPUT); + unset_option(OPTIGNOREMACROEVENTS); mutt_menuDestroy (&menu); dprint (2, (debugfile, "ssl interactive_check_cert: done=%d\n", done)); return (done == 2); diff --git a/mutt_ssl_gnutls.c b/mutt_ssl_gnutls.c index 6ea94fc28..e850fa340 100644 --- a/mutt_ssl_gnutls.c +++ b/mutt_ssl_gnutls.c @@ -1005,7 +1005,7 @@ static int tls_check_one_certificate (const gnutls_datum_t *certdata, menu->help = helpstr; done = 0; - set_option (OPTUNBUFFEREDINPUT); + set_option (OPTIGNOREMACROEVENTS); while (!done) { switch (mutt_menuLoop (menu)) @@ -1057,7 +1057,7 @@ static int tls_check_one_certificate (const gnutls_datum_t *certdata, break; } } - unset_option (OPTUNBUFFEREDINPUT); + unset_option (OPTIGNOREMACROEVENTS); mutt_menuDestroy (&menu); gnutls_x509_crt_deinit (cert); -- 2.40.0