Mercurial > dovecot > core-2.2
changeset 12592:475050722f54
imapc: Handle properly mailbox changes while it's selected. Added support for IDLE.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 23 Jan 2011 22:57:01 +0200 |
parents | 868f2de3898b |
children | ad3abe06954b |
files | src/lib-storage/index/imapc/imapc-client.c src/lib-storage/index/imapc/imapc-client.h src/lib-storage/index/imapc/imapc-connection.c src/lib-storage/index/imapc/imapc-connection.h src/lib-storage/index/imapc/imapc-mailbox.c src/lib-storage/index/imapc/imapc-storage.c src/lib-storage/index/imapc/imapc-storage.h src/lib-storage/index/imapc/imapc-sync.c |
diffstat | 8 files changed, 119 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/imapc/imapc-client.c Sun Jan 23 20:26:02 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-client.c Sun Jan 23 22:57:01 2011 +0200 @@ -18,6 +18,7 @@ { "SASL-IR", IMAPC_CAPABILITY_SASL_IR }, { "LITERAL+", IMAPC_CAPABILITY_LITERALPLUS }, { "QRESYNC", IMAPC_CAPABILITY_QRESYNC }, + { "IDLE", IMAPC_CAPABILITY_IDLE }, { "IMAP4REV1", IMAPC_CAPABILITY_IMAP4REV1 }, { NULL, 0 } @@ -88,7 +89,8 @@ void imapc_client_stop(struct imapc_client *client) { - io_loop_stop(client->ioloop); + if (client->ioloop != NULL) + io_loop_stop(client->ioloop); } static void @@ -225,3 +227,17 @@ { return box->seqmap; } + +void imapc_client_mailbox_idle(struct imapc_client_mailbox *box) +{ + imapc_connection_idle(box->conn); +} + +enum imapc_capability +imapc_client_get_capabilities(struct imapc_client *client) +{ + struct imapc_client_connection *const *connp; + + connp = array_idx(&client->conns, 0); + return imapc_connection_get_capabilities((*connp)->conn); +}
--- a/src/lib-storage/index/imapc/imapc-client.h Sun Jan 23 20:26:02 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-client.h Sun Jan 23 22:57:01 2011 +0200 @@ -12,6 +12,7 @@ IMAPC_CAPABILITY_SASL_IR = 0x01, IMAPC_CAPABILITY_LITERALPLUS = 0x02, IMAPC_CAPABILITY_QRESYNC = 0x04, + IMAPC_CAPABILITY_IDLE = 0x08, IMAPC_CAPABILITY_IMAP4REV1 = 0x400000000 }; @@ -97,4 +98,9 @@ struct imapc_seqmap * imapc_client_mailbox_get_seqmap(struct imapc_client_mailbox *box); +void imapc_client_mailbox_idle(struct imapc_client_mailbox *box); + +enum imapc_capability +imapc_client_get_capabilities(struct imapc_client *client); + #endif
--- a/src/lib-storage/index/imapc/imapc-connection.c Sun Jan 23 20:26:02 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-connection.c Sun Jan 23 22:57:01 2011 +0200 @@ -67,6 +67,10 @@ unsigned int ips_count, prev_connect_idx; struct ip_addr *ips; + + unsigned int idling:1; + unsigned int idle_stopping:1; + unsigned int idle_plus_waiting:1; }; static void imapc_connection_disconnect(struct imapc_connection *conn); @@ -521,6 +525,13 @@ { struct imapc_command *const *cmd_p; + if (conn->idle_plus_waiting) { + /* "+ idling" reply for IDLE command */ + conn->idle_plus_waiting = FALSE; + conn->idling = TRUE; + return imapc_connection_skip_line(conn); + } + if (array_count(&conn->cmd_send_queue) == 0) { imapc_connection_input_error(conn, "Unexpected '+'"); return -1; @@ -558,9 +569,11 @@ reply.state = IMAPC_COMMAND_STATE_OK; else if (strcasecmp(line, "no") == 0) reply.state = IMAPC_COMMAND_STATE_NO; - else if (strcasecmp(line, "bad") == 0) + else if (strcasecmp(line, "bad") == 0) { + i_error("imapc(%s): Command failed with BAD: %u %s", + conn->name, conn->cur_tag, line); reply.state = IMAPC_COMMAND_STATE_BAD; - else if (strcasecmp(line, "bad") == 0) { + } else { imapc_connection_input_error(conn, "Invalid state in tagged reply: %u %s", conn->cur_tag, line); @@ -885,6 +898,10 @@ static void imapc_command_send(struct imapc_connection *conn, struct imapc_command *cmd) { + if ((conn->idling || conn->idle_plus_waiting) && !conn->idle_stopping) { + conn->idle_stopping = TRUE; + o_stream_send_str(conn->output, "DONE\r\n"); + } switch (conn->state) { case IMAPC_CONNECTION_STATE_AUTHENTICATING: array_insert(&conn->cmd_send_queue, 0, &cmd, 1); @@ -986,6 +1003,12 @@ return conn->state; } +enum imapc_capability +imapc_connection_get_capabilities(struct imapc_connection *conn) +{ + return conn->capabilities; +} + void imapc_connection_select(struct imapc_client_mailbox *box, const char *name, imapc_command_callback_t *callback, void *context) { @@ -1006,3 +1029,27 @@ imapc_connection_cmdf(conn, callback, context, "SELECT %s", name); } + +static void +imapc_connection_idle_callback(const struct imapc_command_reply *reply ATTR_UNUSED, + void *context) +{ + struct imapc_connection *conn = context; + + conn->idling = FALSE; + conn->idle_plus_waiting = FALSE; + conn->idle_stopping = FALSE; +} + +void imapc_connection_idle(struct imapc_connection *conn) +{ + if (array_count(&conn->cmd_send_queue) != 0 || + array_count(&conn->cmd_wait_list) != 0 || + conn->idling || conn->idle_plus_waiting || + (conn->capabilities & IMAPC_CAPABILITY_IDLE) == 0) + return; + + imapc_connection_cmd(conn, "IDLE", + imapc_connection_idle_callback, conn); + conn->idle_plus_waiting = TRUE; +}
--- a/src/lib-storage/index/imapc/imapc-connection.h Sun Jan 23 20:26:02 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-connection.h Sun Jan 23 22:57:01 2011 +0200 @@ -45,5 +45,9 @@ enum imapc_connection_state imapc_connection_get_state(struct imapc_connection *conn); +enum imapc_capability +imapc_connection_get_capabilities(struct imapc_connection *conn); + +void imapc_connection_idle(struct imapc_connection *conn); #endif
--- a/src/lib-storage/index/imapc/imapc-mailbox.c Sun Jan 23 20:26:02 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-mailbox.c Sun Jan 23 22:57:01 2011 +0200 @@ -1,12 +1,15 @@ /* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "ioloop.h" #include "imap-arg.h" #include "imap-util.h" #include "imapc-client.h" #include "imapc-seqmap.h" #include "imapc-storage.h" +#define NOTIFY_DELAY_MSECS 500 + static void imapc_untagged_exists(const struct imapc_untagged_reply *reply, struct imapc_mailbox *mbox) { @@ -32,6 +35,21 @@ hdr->next_uid); } +static void imapc_mailbox_idle_timeout(struct imapc_mailbox *mbox) +{ + timeout_remove(&mbox->to_idle); + if (mbox->box.notify_callback != NULL) + mbox->box.notify_callback(&mbox->box, mbox->box.notify_context); +} + +static void imapc_mailbox_idle_notify(struct imapc_mailbox *mbox) +{ + if (mbox->box.notify_callback != NULL && mbox->to_idle == NULL) { + mbox->to_idle = + timeout_add(NOTIFY_DELAY_MSECS, + imapc_mailbox_idle_timeout, mbox); + } +} static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply, struct imapc_mailbox *mbox) @@ -92,6 +110,7 @@ mail_index_update_flags(mbox->delayed_sync_trans, seq, MODIFY_REPLACE, flags); } + imapc_mailbox_idle_notify(mbox); } static void imapc_untagged_expunge(const struct imapc_untagged_reply *reply, @@ -106,6 +125,9 @@ seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box); lseq = imapc_seqmap_rseq_to_lseq(seqmap, rseq); mail_index_expunge(mbox->delayed_sync_trans, lseq); + imapc_seqmap_expunge(seqmap, rseq); + + imapc_mailbox_idle_notify(mbox); } static void
--- a/src/lib-storage/index/imapc/imapc-storage.c Sun Jan 23 20:26:02 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-storage.c Sun Jan 23 22:57:01 2011 +0200 @@ -1,6 +1,7 @@ /* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "ioloop.h" #include "str.h" #include "imap-resp-code.h" #include "mail-copy.h" @@ -302,9 +303,12 @@ { struct imapc_mailbox *mbox = (struct imapc_mailbox *)box; + imapc_client_mailbox_close(&mbox->client_box); mail_index_view_close(&mbox->delayed_sync_view); if (mail_index_transaction_commit(&mbox->delayed_sync_trans) < 0) mail_storage_set_index_error(&mbox->box); + if (mbox->to_idle != NULL) + timeout_remove(&mbox->to_idle); return index_storage_mailbox_close(box); } @@ -416,18 +420,17 @@ } static int imapc_mailbox_get_metadata(struct mailbox *box, - enum mailbox_metadata_items items, - struct mailbox_metadata *metadata_r) + enum mailbox_metadata_items items ATTR_UNUSED, + struct mailbox_metadata *metadata_r ATTR_UNUSED) { mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, "Not supported"); return -1; } -static void imapc_notify_changes(struct mailbox *box) +static void imapc_notify_changes(struct mailbox *box ATTR_UNUSED) { - struct imapc_mailbox *mbox = (struct imapc_mailbox *)box; - + /* we're doing IDLE all the time anyway - nothing to do here */ } struct mail_storage imapc_storage = {
--- a/src/lib-storage/index/imapc/imapc-storage.h Sun Jan 23 20:26:02 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-storage.h Sun Jan 23 22:57:01 2011 +0200 @@ -41,6 +41,7 @@ struct mail_index_transaction *delayed_sync_trans; struct mail_index_view *delayed_sync_view; + struct timeout *to_idle; struct mail *cur_fetch_mail;
--- a/src/lib-storage/index/imapc/imapc-sync.c Sun Jan 23 20:26:02 2011 +0200 +++ b/src/lib-storage/index/imapc/imapc-sync.c Sun Jan 23 22:57:01 2011 +0200 @@ -107,6 +107,7 @@ imapc_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags) { struct imapc_mailbox *mbox = (struct imapc_mailbox *)box; + enum imapc_capability capabilities; int ret = 0; if (!box->opened) { @@ -114,6 +115,16 @@ ret = -1; } + capabilities = imapc_client_get_capabilities(mbox->storage->client); + if ((capabilities & IMAPC_CAPABILITY_IDLE) == 0) { + /* IDLE not supported. do NOOP to get latest changes + before starting sync. */ + imapc_client_mailbox_cmdf(mbox->client_box, + imapc_async_stop_callback, + mbox->storage, "NOOP"); + imapc_client_run(mbox->storage->client); + } + mail_index_view_close(&mbox->delayed_sync_view); if (mail_index_transaction_commit(&mbox->delayed_sync_trans) < 0) { // FIXME: mark inconsistent @@ -148,5 +159,6 @@ seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box); imapc_seqmap_reset(seqmap); } + imapc_client_mailbox_idle(mbox->client_box); return ret; }