]> granicus.if.org Git - mutt/commitdiff
Add $imap_poll_timeout to allow mailbox polling to time out.
authorKevin McCarthy <kevin@8t8.us>
Sun, 23 Jul 2017 02:48:50 +0000 (19:48 -0700)
committerKevin McCarthy <kevin@8t8.us>
Sun, 23 Jul 2017 02:48:50 +0000 (19:48 -0700)
Enable the polling flag for the NOOP in imap_check_mailbox(), the
STATUS command in imap_buffy_check(), and the LOGOUT command.

This is not intended to handle all blocking-IO related issues.
However, the periodic NOOP and STATUS are the most frequent places for
mutt to freeze up, especially after a laptop is sleep/woken.

Since these are quick operations with little data, this is a good place
to check if the connection is still working before hanging on a read.

globals.h
imap/command.c
imap/imap.c
imap/imap_private.h
init.h

index 90c2c19587e55cb24589a9600950610ea31e3c04..5654f28cefa1af2eed91b9bc2a341522ddcf9df9 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -233,6 +233,7 @@ WHERE LIST *SidebarWhitelist INITVAL(0);
 #ifdef USE_IMAP
 WHERE short ImapKeepalive;
 WHERE short ImapPipelineDepth;
+WHERE short ImapPollTimeout;
 #endif
 
 /* flags for received signals */
index ad322892e8f495ca91c6990a2de26cd8d925b913..496154e8e5db8ffdcec581d42d2704f14cbffcfb 100644 (file)
@@ -39,7 +39,7 @@
 /* forward declarations */
 static int cmd_start (IMAP_DATA* idata, const char* cmdstr, int flags);
 static int cmd_queue_full (IMAP_DATA* idata);
-static int cmd_queue (IMAP_DATA* idata, const char* cmdstr);
+static int cmd_queue (IMAP_DATA* idata, const char* cmdstr, int flags);
 static IMAP_COMMAND* cmd_new (IMAP_DATA* idata);
 static int cmd_status (const char *s);
 static void cmd_handle_fatal (IMAP_DATA* idata);
@@ -237,6 +237,7 @@ const char* imap_cmd_trailer (IMAP_DATA* idata)
  *     for checking for a mailbox on append and login
  *   IMAP_CMD_PASS: command contains a password. Suppress logging.
  *   IMAP_CMD_QUEUE: only queue command, do not execute.
+ *   IMAP_CMD_POLL: poll the socket for a response before running imap_cmd_step.
  * Return 0 on success, -1 on Failure, -2 on OK Failure
  */
 int imap_exec (IMAP_DATA* idata, const char* cmdstr, int flags)
@@ -252,6 +253,16 @@ int imap_exec (IMAP_DATA* idata, const char* cmdstr, int flags)
   if (flags & IMAP_CMD_QUEUE)
     return 0;
 
+  if ((flags & IMAP_CMD_POLL) &&
+      (ImapPollTimeout > 0) &&
+      (mutt_socket_poll (idata->conn, ImapPollTimeout)) == 0)
+  {
+    mutt_error (_("Connection to %s timed out"), idata->conn->account.host);
+    mutt_sleep (2);
+    cmd_handle_fatal (idata);
+    return -1;
+  }
+
   do
     rc = imap_cmd_step (idata);
   while (rc == IMAP_CMD_CONTINUE);
@@ -377,7 +388,7 @@ static IMAP_COMMAND* cmd_new (IMAP_DATA* idata)
 }
 
 /* queues command. If the queue is full, attempts to drain it. */
-static int cmd_queue (IMAP_DATA* idata, const char* cmdstr)
+static int cmd_queue (IMAP_DATA* idata, const char* cmdstr, int flags)
 {
   IMAP_COMMAND* cmd;
   int rc;
@@ -386,7 +397,7 @@ static int cmd_queue (IMAP_DATA* idata, const char* cmdstr)
   {
     dprint (3, (debugfile, "Draining IMAP command pipeline\n"));
 
-    rc = imap_exec (idata, NULL, IMAP_CMD_FAIL_OK);
+    rc = imap_exec (idata, NULL, IMAP_CMD_FAIL_OK | (flags & IMAP_CMD_POLL));
 
     if (rc < 0 && rc != -2)
       return rc;
@@ -411,7 +422,7 @@ static int cmd_start (IMAP_DATA* idata, const char* cmdstr, int flags)
     return -1;
   }
 
-  if (cmdstr && ((rc = cmd_queue (idata, cmdstr)) < 0))
+  if (cmdstr && ((rc = cmd_queue (idata, cmdstr, flags)) < 0))
     return rc;
 
   if (flags & IMAP_CMD_QUEUE)
index 0260a730e138de1cd7e1372bbabd84c00df7565a..6e0021a6bee9343289d1d378bfd70235e39037e2 100644 (file)
@@ -832,8 +832,12 @@ void imap_logout (IMAP_DATA** idata)
    * receive a bye response (so it doesn't freak out and close the conn) */
   (*idata)->status = IMAP_BYE;
   imap_cmd_start (*idata, "LOGOUT");
-  while (imap_cmd_step (*idata) == IMAP_CMD_CONTINUE)
-    ;
+  if (ImapPollTimeout <= 0 ||
+      mutt_socket_poll ((*idata)->conn, ImapPollTimeout) != 0)
+  {
+    while (imap_cmd_step (*idata) == IMAP_CMD_CONTINUE)
+      ;
+  }
 
   mutt_socket_close ((*idata)->conn);
   imap_free_idata (idata);
@@ -1476,7 +1480,7 @@ int imap_check_mailbox (CONTEXT *ctx, int *index_hint, int force)
 
   if ((force ||
        (idata->state != IMAP_IDLE && time(NULL) >= idata->lastread + Timeout))
-      && imap_exec (idata, "NOOP", 0) != 0)
+      && imap_exec (idata, "NOOP", IMAP_CMD_POLL) != 0)
     return -1;
 
   /* We call this even when we haven't run NOOP in case we have pending
@@ -1600,14 +1604,14 @@ int imap_buffy_check (int force, int check_stats)
       snprintf (command, sizeof (command),
              "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
 
-    if (imap_exec (idata, command, IMAP_CMD_QUEUE) < 0)
+    if (imap_exec (idata, command, IMAP_CMD_QUEUE | IMAP_CMD_POLL) < 0)
     {
       dprint (1, (debugfile, "Error queueing command\n"));
       return 0;
     }
   }
 
-  if (lastdata && (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK) == -1))
+  if (lastdata && (imap_exec (lastdata, NULL, IMAP_CMD_FAIL_OK | IMAP_CMD_POLL) == -1))
   {
     dprint (1, (debugfile, "Error polling mailboxes\n"));
     return 0;
index ff28da2f1a1bf0ade97b8b2401350543d9286e8a..b85c128030edf89c7ed5696b18454c1ddac948db 100644 (file)
@@ -70,6 +70,7 @@
 #define IMAP_CMD_FAIL_OK (1<<0)
 #define IMAP_CMD_PASS    (1<<1)
 #define IMAP_CMD_QUEUE   (1<<2)
+#define IMAP_CMD_POLL    (1<<3)
 
 /* length of "DD-MMM-YYYY HH:MM:SS +ZZzz" (null-terminated) */
 #define IMAP_DATELEN 27
diff --git a/init.h b/init.h
index 3e22b114f0163d99160aa447a473e53f1db5bd3d..d7bb5e7fc45034b8c578655bb45221dc25c02e37 100644 (file)
--- a/init.h
+++ b/init.h
@@ -1310,6 +1310,14 @@ struct option_t MuttVars[] = {
   ** .pp
   ** \fBNote:\fP Changes to this variable have no effect on open connections.
   */
+  { "imap_poll_timeout", DT_NUM,  R_NONE, UL &ImapPollTimeout, 15 },
+  /*
+  ** .pp
+  ** This variable specifies the maximum amount of time in seconds
+  ** that mutt will wait for a response when polling IMAP connections
+  ** for new mail, before timing out and closing the connection.  Set
+  ** to 0 to disable timing out.
+  */
   { "imap_servernoise",                DT_BOOL, R_NONE, OPTIMAPSERVERNOISE, 1 },
   /*
   ** .pp