if test "$need_socket" = "yes"
then
+ AC_CHECK_HEADERS([sys/select.h])
AC_MSG_CHECKING([for socklen_t])
AC_EGREP_HEADER(socklen_t, sys/socket.h, AC_MSG_RESULT([yes]),
AC_MSG_RESULT([no])
"AUTH=ANONYMOUS",
"STARTTLS",
"LOGINDISABLED",
+ "IDLE",
NULL
};
/* seq, space, cmd, \r\n\0 */
cmdlen = strlen (cmd->seq) + strlen (cmdstr) + 4;
+ if (idata->state == IMAP_IDLE)
+ cmdlen += 6; /* DONE\r\n */
if (idata->cmdbuflen < cmdlen + (idata->cmdtail - idata->cmdbuf))
{
unsigned int tailoff = idata->cmdtail - idata->cmdbuf;
idata->cmdbuflen = tailoff + cmdlen;
idata->cmdtail = idata->cmdbuf + tailoff;
}
- snprintf (idata->cmdtail, cmdlen, "%s %s\r\n", cmd->seq, cmdstr);
+ snprintf (idata->cmdtail, cmdlen, "%s%s %s\r\n",
+ idata->state == IMAP_IDLE ? "DONE\r\n" : "", cmd->seq, cmdstr);
idata->cmdtail += cmdlen - 1;
+ if (idata->state == IMAP_IDLE)
+ idata->state = IMAP_SELECTED;
+
return 0;
}
return;
}
- if (!(idata->state == IMAP_SELECTED) || idata->ctx->closing)
+ if (!(idata->state >= IMAP_SELECTED) || idata->ctx->closing)
return;
if (idata->reopen & IMAP_REOPEN_ALLOW)
{
idata->status = IMAP_FATAL;
- if ((idata->state == IMAP_SELECTED) &&
+ if ((idata->state >= IMAP_SELECTED) &&
(idata->reopen & IMAP_REOPEN_ALLOW))
{
mx_fastclose_mailbox (idata->ctx);
idata->state = IMAP_DISCONNECTED;
}
- if (idata->state != IMAP_SELECTED)
+ if (idata->state < IMAP_SELECTED)
{
idata->state = IMAP_DISCONNECTED;
mutt_socket_close (idata->conn);
s = imap_next_word (idata->buf);
- if ((idata->state == IMAP_SELECTED) && isdigit ((unsigned char) *s))
+ if ((idata->state >= IMAP_SELECTED) && isdigit ((unsigned char) *s))
{
pn = s;
s = imap_next_word (s);
/* make sure this connection is not in SELECTED state, if neccessary */
if (flags & M_IMAP_CONN_NOSELECT)
- while (conn->data && ((IMAP_DATA*) conn->data)->state == IMAP_SELECTED)
+ while (conn->data && ((IMAP_DATA*) conn->data)->state >= IMAP_SELECTED)
{
if (!(conn = mutt_conn_find (conn, account)))
return NULL;
idata = (IMAP_DATA*) ctx->data;
- if (idata->state != IMAP_SELECTED)
+ if (idata->state < IMAP_SELECTED)
{
dprint (2, (debugfile, "imap_sync_mailbox: no mailbox selected\n"));
return -1;
if (ctx == idata->ctx)
{
- if (idata->status != IMAP_FATAL && idata->state == IMAP_SELECTED)
+ if (idata->status != IMAP_FATAL && idata->state >= IMAP_SELECTED)
{
/* mx_close_mailbox won't sync if there are no deleted messages
* and the mailbox is unchanged, so we may have to close here */
}
}
-/* use the NOOP command to poll for new mail
+/* use the NOOP or IDLE command to poll for new mail
*
* return values:
* M_REOPENED mailbox has been externally modified
idata = (IMAP_DATA*) ctx->data;
- if ((force || time(NULL) >= idata->lastread + Timeout)
+ /* try IDLE first */
+ if (mutt_bit_isset (idata->capabilities, IDLE)
+ && (idata->state != IMAP_IDLE
+ || time(NULL) >= idata->lastread + ImapKeepalive))
+ {
+ imap_cmd_start (idata, "IDLE");
+ if (imap_cmd_step (idata) != IMAP_CMD_RESPOND)
+ {
+ dprint (1, (debugfile, "Error starting IDLE\n"));
+ return -1;
+ }
+ idata->state = IMAP_IDLE;
+ }
+ if (idata->state == IMAP_IDLE)
+ {
+ while (mutt_socket_poll (idata->conn) > 0)
+ {
+ if (imap_cmd_step (idata) != IMAP_CMD_CONTINUE)
+ {
+ dprint (1, (debugfile, "Error reading IDLE response\n"));
+ return -1;
+ }
+ }
+ }
+ else if ((force || time(NULL) >= idata->lastread + Timeout)
&& imap_exec (idata, "NOOP", 0) != 0)
return -1;
char command[LONG_STRING];
char munged[LONG_STRING];
int buffies = 0;
- int rc;
for (mailbox = Incoming; mailbox; mailbox = mailbox->next)
{
IMAP_DISCONNECTED = 0,
IMAP_CONNECTED,
IMAP_AUTHENTICATED,
- IMAP_SELECTED
+ IMAP_SELECTED,
+
+ /* and pseudo-states */
+ IMAP_IDLE
};
enum
AUTH_ANON, /* AUTH=ANONYMOUS */
STARTTLS, /* RFC 2595: STARTTLS */
LOGINDISABLED, /* LOGINDISABLED */
+ IDLE, /* RFC 2177: IDLE */
CAPMAX
};
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
#include <string.h>
#include <errno.h>
return rc;
}
+/* poll whether reads would block.
+ * Returns: >0 if there is data to read,
+ * 0 if a read would block,
+ * -1 if this connection doesn't support polling */
+int mutt_socket_poll (CONNECTION* conn)
+{
+ if (conn->bufpos < conn->available)
+ return conn->available - conn->bufpos;
+
+ if (conn->conn_poll)
+ return conn->conn_poll (conn);
+
+ return -1;
+}
+
/* simple read buffering to speed things up. */
int mutt_socket_readchar (CONNECTION *conn, char *c)
{
conn->conn_write = raw_socket_write;
conn->conn_open = raw_socket_open;
conn->conn_close = raw_socket_close;
+ conn->conn_poll = raw_socket_poll;
}
return conn;
return rc;
}
+int raw_socket_poll (CONNECTION* conn)
+{
+ fd_set rfds;
+ struct timeval tv = { 0, 0 };
+
+ if (conn->fd < 0)
+ return -1;
+
+ FD_ZERO (&rfds);
+ FD_SET (conn->fd, &rfds);
+
+ return select (conn->fd + 1, &rfds, NULL, NULL, &tv);
+}
+
int raw_socket_open (CONNECTION* conn)
{
int rc;
int (*conn_write) (struct _connection *conn, const char *buf, size_t count);
int (*conn_open) (struct _connection *conn);
int (*conn_close) (struct _connection *conn);
+ int (*conn_poll) (struct _connection *conn);
} CONNECTION;
int mutt_socket_open (CONNECTION* conn);
int mutt_socket_close (CONNECTION* conn);
int mutt_socket_read (CONNECTION* conn, char* buf, size_t len);
+int mutt_socket_poll (CONNECTION* conn);
int mutt_socket_readchar (CONNECTION *conn, char *c);
#define mutt_socket_readln(A,B,C) mutt_socket_readln_d(A,B,C,M_SOCK_LOG_CMD)
int mutt_socket_readln_d (char *buf, size_t buflen, CONNECTION *conn, int dbg);
int raw_socket_write (CONNECTION* conn, const char* buf, size_t count);
int raw_socket_open (CONNECTION *conn);
int raw_socket_close (CONNECTION *conn);
+int raw_socket_poll (CONNECTION* conn);
#endif /* _MUTT_SOCKET_H_ */
static int tunnel_socket_close (CONNECTION*);
static int tunnel_socket_read (CONNECTION* conn, char* buf, size_t len);
static int tunnel_socket_write (CONNECTION* conn, const char* buf, size_t len);
+static int tunnel_socket_poll (CONNECTION* conn);
/* -- public functions -- */
int mutt_tunnel_socket_setup (CONNECTION *conn)
conn->conn_close = tunnel_socket_close;
conn->conn_read = tunnel_socket_read;
conn->conn_write = tunnel_socket_write;
+ conn->conn_poll = tunnel_socket_poll;
return 0;
}
return rc;
}
+
+static int tunnel_socket_poll (CONNECTION* conn)
+{
+ TUNNEL_DATA* tunnel = (TUNNEL_DATA*) conn->sockdata;
+ int ofd;
+ int rc;
+
+ ofd = conn->fd;
+ conn->fd = tunnel->readfd;
+ rc = raw_socket_poll (conn);
+ conn->fd = ofd;
+
+ return rc;
+}