Commit 30639b18 authored by Kevin J. McCarthy's avatar Kevin J. McCarthy

Add $imap_poll_timeout to allow mailbox polling to time out.

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.
parent 75e7e18d
......@@ -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 */
......
......@@ -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)
......
......@@ -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;
......
......@@ -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
......
......@@ -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
......
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