Commit 53900afa authored by Kevin J. McCarthy's avatar Kevin J. McCarthy

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.
parent f358cf9a
......@@ -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:
......
......@@ -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
......
......@@ -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 ();
}
......
......@@ -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])
......
......@@ -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 <function> 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;
}
......
......@@ -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;
}
......
......@@ -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
};
......
......@@ -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);
/* ----------------------------------------------------------------------------
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment