Hi,

I noticed that while mutt does support eg. IDLE for IMAP, it's not quite
as useful as it could be because recv() is not actually called on the
socket until timeout happens or terminal input is received. I made this
horribly ugly patch that uses select(2) instead of waiting on just stdin
-- it makes new mail/flag changes appear pretty much instantly if IDLE
is used. It's mostly just a proof of concept: a clean implementation
would require some more work around how input is handled.

-- 
Lauri Tirkkonen | lotheac @ IRCnet
diff -r 5904c6376f77 curs_lib.c
--- a/curs_lib.c        Sun May 21 18:45:09 2017 -0700
+++ b/curs_lib.c        Wed May 24 17:09:18 2017 +0300
@@ -59,7 +59,7 @@
 /* These are used in all other "normal" situations, and are not
  * ignored when setting OPTIGNOREMACROEVENTS
  */
-static size_t UngetCount = 0;
+size_t UngetCount = 0;
 static size_t UngetLen = 0;
 static event_t *UngetKeyEvents;
 
diff -r 5904c6376f77 curs_main.c
--- a/curs_main.c       Sun May 21 18:45:09 2017 -0700
+++ b/curs_main.c       Wed May 24 17:09:18 2017 +0300
@@ -664,7 +664,7 @@
        do_buffy_notify = 1;
     }
 
-    if (op != -1)
+    if (op >= 0)
       mutt_curs_set (0);
 
     if (menu->menu == MENU_MAIN)
@@ -705,8 +705,8 @@
 
       dprint(4, (debugfile, "mutt_index_menu[%d]: Got op %d\n", __LINE__, op));
 
-      if (op == -1)
-       continue; /* either user abort or timeout */
+      if (op < 0)
+       continue; /* user abort, timeout, socket event or error */
 
       mutt_curs_set (1);
 
@@ -731,7 +731,10 @@
        mutt_window_clrtoeol (MuttMessageWindow);
 
        /* get the real command */
-       if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX)
+       do
+         op = km_dokey (MENU_MAIN);
+       while (op == -2);
+       if (op == OP_TAG_PREFIX)
        {
          /* abort tag sequence */
           mutt_window_clearline (MuttMessageWindow, 0);
@@ -762,7 +765,10 @@
        mutt_window_clrtoeol (MuttMessageWindow);
 
        /* get the real command */
-       if ((op = km_dokey (MENU_MAIN)) == OP_TAG_PREFIX)
+       do
+         op = km_dokey (MENU_MAIN);
+       while (op == -2);
+       if (op == OP_TAG_PREFIX)
        {
          /* abort tag sequence */
          mutt_window_clearline (MuttMessageWindow, 0);
diff -r 5904c6376f77 enter.c
--- a/enter.c   Sun May 21 18:45:09 2017 -0700
+++ b/enter.c   Wed May 24 17:09:18 2017 +0300
@@ -315,7 +315,7 @@
     }
     mutt_refresh ();
 
-    if ((ch = km_dokey (MENU_EDITOR)) == -1)
+    if ((ch = km_dokey (MENU_EDITOR)) < 0)
     {
       rv = SigWinch ? 1 : -1;
       goto bye;
diff -r 5904c6376f77 keymap.c
--- a/keymap.c  Sun May 21 18:45:09 2017 -0700
+++ b/keymap.c  Wed May 24 17:09:18 2017 +0300
@@ -26,6 +26,8 @@
 #include "keymap.h"
 #include "mapping.h"
 #include "mutt_crypt.h"
+#include "mutt_socket.h"
+#include "lib.h"
 #ifdef USE_IMAP
 #include "imap/imap.h"
 #endif
@@ -128,6 +130,8 @@
 /* contains the last key the user pressed */
 int LastKey;
 
+extern size_t UngetCount;
+
 struct keymap_t *Keymaps[MENU_MAX];
 
 static struct keymap_t *allocKeys (int len, keycode_t *keys)
@@ -418,6 +422,7 @@
  *     >0              function to execute
  *     OP_NULL         no function bound to key sequence
  *     -1              error occurred while reading input
+ *     -2              timeout or event on a connection happened before input
  */
 int km_dokey (int menu)
 {
@@ -425,49 +430,70 @@
   struct keymap_t *map = Keymaps[menu];
   int pos = 0;
   int n = 0;
-  int i;
+  time_t remaining = 0;
 
   if (!map)
     return (retry_generic (menu, NULL, 0, 0));
 
+  remaining = Timeout > 0 ? Timeout : 60;
+
   FOREVER
   {
-    i = Timeout > 0 ? Timeout : 60;
+    int nfds;
+    fd_set rfds;
+    struct timespec before, after;
+    struct timespec wait = { 0 };
+
+    if (UngetCount == 0)
+    {
+      FD_ZERO (&rfds);
+      FD_SET (STDIN_FILENO, &rfds);
+      nfds = STDIN_FILENO + 1;
+      for (CONNECTION *c = mutt_socket_head (); c != NULL; c = c->next)
+      {
+       FD_SET (c->fd, &rfds);
+       if (nfds < c->fd + 1)
+           nfds = c->fd + 1;
+      }
+      wait.tv_sec = remaining;
 #ifdef USE_IMAP
-    /* keepalive may need to run more frequently than Timeout allows */
-    if (ImapKeepalive)
-    {
-      if (ImapKeepalive >= i)
-       imap_keepalive ();
-      else
-       while (ImapKeepalive && ImapKeepalive < i)
+      if (ImapKeepalive < wait.tv_sec)
+         wait.tv_sec = ImapKeepalive;
+#endif
+      clock_gettime (CLOCK_MONOTONIC, &before);
+      nfds = pselect (nfds, &rfds, NULL, NULL, &wait, NULL);
+      clock_gettime (CLOCK_MONOTONIC, &after);
+      remaining -= after.tv_sec - before.tv_sec;
+      if (nfds == 0 || (nfds < 0 && errno == EINTR))
+      {
+#ifdef USE_IMAP
+       if (ImapKeepalive && after.tv_sec - before.tv_sec > ImapKeepalive)
        {
-         timeout (ImapKeepalive * 1000);
-         tmp = mutt_getch ();
-         timeout (-1);
-         /* If a timeout was not received, or the window was resized, exit the
-          * loop now.  Otherwise, continue to loop until reaching a total of
-          * $timeout seconds.
-          */
-         if (tmp.ch != -2 || SigWinch)
-           goto gotkey;
-         i -= ImapKeepalive;
          imap_keepalive ();
+         continue;
        }
-    }
 #endif
+       /* hide timeouts, but not window resizes, from the line editor. */
+       if (menu == MENU_EDITOR && !SigWinch) {
+         remaining = Timeout > 0 ? Timeout: 60;
+         continue;
+       }
+       return -2;
+      }
+      else if (nfds < 0)
+      {
+       dprint (2, (debugfile, "km_dokey: select: %s\n", strerror(errno)));
+       return -1;
+      }
 
-    timeout (i * 1000);
-    tmp = mutt_getch();
+    if (!FD_ISSET(STDIN_FILENO, &rfds))
+      return -2;
+    }
+
+    timeout (0);
+    tmp = mutt_getch ();
     timeout (-1);
 
-#ifdef USE_IMAP
-  gotkey:
-#endif
-    /* hide timeouts, but not window resizes, from the line editor. */
-    if (menu == MENU_EDITOR && tmp.ch == -2 && !SigWinch)
-      continue;
-
     LastKey = tmp.ch;
     if (LastKey < 0)
       return -1;
@@ -496,7 +522,7 @@
 
       /* Sigh. Valid function but not in this context.
        * Find the literal string and push it back */
-      for (i = 0; Menus[i].name; i++)
+      for (int i = 0; Menus[i].name; i++)
       {
        bindings = km_get_table (Menus[i].value);
        if (bindings)
diff -r 5904c6376f77 pager.c
--- a/pager.c   Sun May 21 18:45:09 2017 -0700
+++ b/pager.c   Wed May 24 17:09:18 2017 +0300
@@ -2012,7 +2012,10 @@
     else
       OldHdr = NULL;
       
-    ch = km_dokey (MENU_PAGER);
+    do
+      ch = km_dokey (MENU_PAGER);
+    while(ch == -2);
+
     if (ch != -1)
       mutt_clear_error ();
     mutt_curs_set (1);

Reply via email to