]> granicus.if.org Git - neomutt/commitdiff
Create a separate macro/push/exec event buffer. (closes #3779)
authorKevin McCarthy <kevin@8t8.us>
Sun, 4 Oct 2015 02:08:49 +0000 (10:08 +0800)
committerKevin McCarthy <kevin@8t8.us>
Sun, 4 Oct 2015 02:08:49 +0000 (10:08 +0800)
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
commands.c
curs_lib.c
curs_main.c
keymap.c
menu.c
mutt.h
mutt_curses.h
mutt_ssl.c
mutt_ssl_gnutls.c

index cda4900a32d556c93a481213f92e24a1844216bd..c47aa7e81c2fcba870d444781a0314d6d72d5869 100644 (file)
--- 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:
index 5dbd10085ce7508ce4207052cccf88fb1d112a0a..b334c7b6e1c6ee0e807449941e62dc8334ac8f18 100644 (file)
@@ -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
index d8c62c360fac996d9af2f73e761da44c6426056f..d70c327f8d2170b33b5c29d3da57df98a8da3fad 100644 (file)
  * 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 ();
 }
 
index 425bd9aecbc1cb4a25f9ad68d70622db820b30f6..48fa6bbc19656932886729e67b2d529edd18a30f 100644 (file)
@@ -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])
index 1710b17d14fbf03bd8ca899f09918bf5c0c51663..40ea7455e3421327545b87d59bf4b158f86dabd3 100644 (file)
--- 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 <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;
 }
diff --git a/menu.c b/menu.c
index 578593ebc66b78fc8e689523c9f82185652df236..828df9c108482bad422402c4ffdc26ea140c081d 100644 (file)
--- 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 f8565fae86c270641e82c68c9c131dfb47b5729c..19d2680456100149ae15592a58a5baf0c77fa759 100644 (file)
--- 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
 };
index f8bc47cc440fde40aff115b56bd98f39af514f88..543639b3d1c0abe53da79065fba4de3d14b91bb2 100644 (file)
@@ -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);
 
 /* ----------------------------------------------------------------------------
index 9d1af09b17e7db0a1981d75ad1e26c6356ed967c..714b8c64b1f3c47cd0575e60319ad6e0dfe11cb7 100644 (file)
@@ -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);
index 6ea94fc289f25c1208ace0b123c53429f1f15c3a..e850fa340240c342d3979f6fec8b22c5da1d2a35 100644 (file)
@@ -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);