]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Code cleanups and fixes.
authorTimo Sirainen <tss@iki.fi>
Fri, 21 Jan 2011 15:39:24 +0000 (17:39 +0200)
committerTimo Sirainen <tss@iki.fi>
Fri, 21 Jan 2011 15:39:24 +0000 (17:39 +0200)
src/lib-storage/index/imapc/Makefile.am
src/lib-storage/index/imapc/imapc-client.h
src/lib-storage/index/imapc/imapc-connection.c
src/lib-storage/index/imapc/imapc-list.c
src/lib-storage/index/imapc/imapc-list.h
src/lib-storage/index/imapc/imapc-mailbox.c [new file with mode: 0644]
src/lib-storage/index/imapc/imapc-storage.c
src/lib-storage/index/imapc/imapc-storage.h

index 25bd450f7e68a969fef381e936dfa0b38c0ce2ff..7a08c0464dff3c1566c3a0bd8d930188584f0573 100644 (file)
@@ -14,6 +14,7 @@ libstorage_imapc_la_SOURCES = \
        imapc-connection.c \
        imapc-list.c \
        imapc-mail.c \
+       imapc-mailbox.c \
        imapc-save.c \
        imapc-search.c \
        imapc-seqmap.c \
index 5283a03c066a01ebe37fb8126c177740a4d24f24..ade9fe96dd1729281a8ff44bf05986ed1b5b0ac9 100644 (file)
@@ -34,10 +34,14 @@ struct imapc_client_settings {
 
 struct imapc_command_reply {
        enum imapc_command_state state;
-       /* "RESP TEXT" when the reply contains [RESP TEXT], otherwise NULL */
-       const char *resp_text;
+       /* "[RESP TEXT]" produces key=RESP, value=TEXT.
+          "[RESP]" produces key=RESP, value=NULL
+          otherwise both are NULL */
+       const char *resp_text_key, *resp_text_value;
        /* The full tagged reply, including [RESP TEXT]. */
-       const char *text;
+       const char *text_full;
+       /* Tagged reply text without [RESP TEXT] */
+       const char *text_without_resp;
 };
 
 struct imapc_untagged_reply {
@@ -49,8 +53,10 @@ struct imapc_untagged_reply {
        /* the rest of the reply can be read from these args. */
        const struct imap_arg *args;
 
-       /* "RESP TEXT" when the reply is "* OK [RESP TEXT]", otherwise NULL */
-       const char *resp_text;
+       /* "* OK [RESP TEXT]" produces key=RESP, value=TEXT.
+          "* OK [RESP]" produces key=RESP, value=NULL
+          otherwise both are NULL */
+       const char *resp_text_key, *resp_text_value;
 
        /* If this reply occurred while a mailbox was selected, this contains
           the mailbox's untagged_context. */
index bff14782abee14784edf4c305d5a48fe240e0e04..f701cc2b1495dc05dcec6033faaea27a10e2c015 100644 (file)
@@ -126,7 +126,8 @@ static void imapc_connection_set_state(struct imapc_connection *conn,
 
                memset(&reply, 0, sizeof(reply));
                reply.state = IMAPC_COMMAND_STATE_DISCONNECTED;
-               reply.text = "Disconnected from server";
+               reply.text_without_resp = reply.text_full =
+                       "Disconnected from server";
 
                while (array_count(&conn->cmd_wait_list) > 0) {
                        cmdp = array_idx(&conn->cmd_wait_list, 0);
@@ -241,17 +242,8 @@ imapc_connection_parse_capability(struct imapc_connection *conn,
 
 static int
 imapc_connection_handle_resp_text_code(struct imapc_connection *conn,
-                                      const char *text)
+                                      const char *key, const char *value)
 {
-       const char *key, *value;
-
-       value = strchr(text, ' ');
-       if (value != NULL)
-               key = t_strdup_until(text, value++);
-       else {
-               key = text;
-               value = "";
-       }
        if (strcasecmp(key, "CAPABILITY") == 0) {
                if (imapc_connection_parse_capability(conn, value) < 0)
                        return -1;
@@ -268,10 +260,36 @@ imapc_connection_handle_resp_text_code(struct imapc_connection *conn,
 
 static int
 imapc_connection_handle_resp_text(struct imapc_connection *conn,
-                                 const struct imap_arg *args,
-                                 const char **text_r)
+                                 const char *text,
+                                 const char **key_r, const char **value_r)
+{
+       const char *p, *value;
+
+       i_assert(text[0] == '[');
+
+       p = strchr(text, ']');
+       if (p == NULL) {
+               imapc_connection_input_error(conn, "Missing ']' in resp-text");
+               return -1;
+       }
+       text = t_strdup_until(text + 1, p);
+       value = strchr(text, ' ');
+       if (value != NULL) {
+               *key_r = t_strdup_until(text, value);
+               *value_r = value + 1;
+       } else {
+               *key_r = text;
+               *value_r = NULL;
+       }
+       return 0;
+}
+
+static int
+imapc_connection_handle_imap_resp_text(struct imapc_connection *conn,
+                                      const struct imap_arg *args,
+                                      const char **key_r, const char **value_r)
 {
-       const char *text, *p;
+       const char *text;
 
        if (args->type != IMAP_ARG_ATOM)
                return 0;
@@ -285,17 +303,10 @@ imapc_connection_handle_resp_text(struct imapc_connection *conn,
                }
                return 0;
        }
-       p = strchr(text, ']');
-       if (p == NULL) {
-               imapc_connection_input_error(conn, "Missing ']' in resp-text");
-               return -1;
-       }
-       if (p[1] == '\0' || p[1] != ' ' || p[2] == '\0') {
-               imapc_connection_input_error(conn, "Missing text in resp-text");
+       if (imapc_connection_handle_resp_text(conn, text, key_r, value_r) < 0)
                return -1;
-       }
-       *text_r = text = t_strdup_until(text + 1, p);
-       return imapc_connection_handle_resp_text_code(conn, text);
+
+       return imapc_connection_handle_resp_text_code(conn, *key_r, *value_r);
 }
 
 static bool need_literal(const char *str)
@@ -346,7 +357,7 @@ imapc_connection_capability_cb(const struct imapc_command_reply *reply,
 
        if (reply->state != IMAPC_COMMAND_STATE_OK) {
                imapc_connection_input_error(conn,
-                       "Failed to get capabilities: %s", reply->text);
+                       "Failed to get capabilities: %s", reply->text_full);
        } else if (conn->capabilities == 0) {
                imapc_connection_input_error(conn,
                        "Capabilities not returned by server");
@@ -363,7 +374,7 @@ static void imapc_connection_login_cb(const struct imapc_command_reply *reply,
 
        if (reply->state != IMAPC_COMMAND_STATE_OK) {
                imapc_connection_input_error(conn, "Authentication failed: %s",
-                                            reply->text);
+                                            reply->text_full);
                return;
        }
 
@@ -406,13 +417,14 @@ static int imapc_connection_input_banner(struct imapc_connection *conn)
 {
        const struct imapc_client_settings *set = &conn->client->set;
        const struct imap_arg *imap_args;
-       const char *cmd, *text;
+       const char *cmd, *key, *value;
        int ret;
 
        if ((ret = imapc_connection_read_line(conn, &imap_args)) <= 0)
                return ret;
 
-       if (imapc_connection_handle_resp_text(conn, imap_args, &text) < 0)
+       if (imapc_connection_handle_imap_resp_text(conn, imap_args,
+                                                  &key, &value) < 0)
                return -1;
        imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_AUTHENTICATING);
 
@@ -482,8 +494,9 @@ static int imapc_connection_input_untagged(struct imapc_connection *conn)
        memset(&reply, 0, sizeof(reply));
 
        if (strcasecmp(name, "OK") == 0) {
-               if (imapc_connection_handle_resp_text(conn, imap_args,
-                                                     &reply.resp_text) < 0)
+               if (imapc_connection_handle_imap_resp_text(conn, imap_args,
+                                               &reply.resp_text_key,
+                                               &reply.resp_text_value) < 0)
                        return -1;
        }
 
@@ -535,10 +548,10 @@ static int imapc_connection_input_tagged(struct imapc_connection *conn)
 
        linep = strchr(line, ' ');
        if (linep == NULL)
-               reply.text = "";
+               reply.text_full = "";
        else {
                *linep = '\0';
-               reply.text = linep + 1;
+               reply.text_full = linep + 1;
        }
 
        if (strcasecmp(line, "ok") == 0)
@@ -554,19 +567,20 @@ static int imapc_connection_input_tagged(struct imapc_connection *conn)
                return -1;
        }
 
-       if (reply.text[0] == '[') {
+       if (reply.text_full[0] == '[') {
                /* get resp-text */
-               p = strchr(reply.text, ']');
-               if (p == NULL) {
-                       imapc_connection_input_error(conn,
-                               "Missing ']' from resp-text: %u %s",
-                               conn->cur_tag, line);
-                       return -1;
-               }
-               reply.resp_text = t_strndup(reply.text + 1, p - reply.text - 1);
-               if (imapc_connection_handle_resp_text_code(conn,
-                                                          reply.resp_text) < 0)
+               if (imapc_connection_handle_resp_text(conn, reply.text_full,
+                                       &reply.resp_text_key,
+                                       &reply.resp_text_value) < 0)
                        return -1;
+
+               p = strchr(reply.text_full, ']');
+               i_assert(p != NULL);
+               reply.text_without_resp = p + 1;
+               if (reply.text_without_resp[0] == ' ')
+                       reply.text_without_resp++;
+       } else {
+               reply.text_without_resp = reply.text_full;
        }
 
        /* find the command. it's either the first command in send queue
index 1e3f85e0c15a76d36c2d5c264586f3fd50ed80dc..9ca531a9d5bb90d2ec18d6e88a8775bf2c9d7495 100644 (file)
@@ -77,9 +77,11 @@ imapc_list_update_tree(struct mailbox_tree_context *tree,
        return node;
 }
 
-void imapc_list_update_mailbox(struct imapc_mailbox_list *list,
-                              const struct imap_arg *args)
+static void imapc_untagged_list(const struct imapc_untagged_reply *reply,
+                               struct imapc_storage *storage)
 {
+       struct imapc_mailbox_list *list = storage->list;
+       const struct imap_arg *args = reply->args;
        const char *sep, *name;
 
        if (list->sep == '\0') {
@@ -99,9 +101,11 @@ void imapc_list_update_mailbox(struct imapc_mailbox_list *list,
        (void)imapc_list_update_tree(list->mailboxes, args);
 }
 
-void imapc_list_update_subscription(struct imapc_mailbox_list *list,
-                                   const struct imap_arg *args)
+static void imapc_untagged_lsub(const struct imapc_untagged_reply *reply,
+                               struct imapc_storage *storage)
 {
+       struct imapc_mailbox_list *list = storage->list;
+       const struct imap_arg *args = reply->args;
        struct mailbox_node *node;
 
        if (list->sep == '\0') {
@@ -115,6 +119,14 @@ void imapc_list_update_subscription(struct imapc_mailbox_list *list,
                node->flags |= MAILBOX_SUBSCRIBED;
 }
 
+void imapc_list_register_callbacks(struct imapc_mailbox_list *list)
+{
+       imapc_storage_register_untagged(list->storage, "LIST",
+                                       imapc_untagged_list);
+       imapc_storage_register_untagged(list->storage, "LSUB",
+                                       imapc_untagged_lsub);
+}
+
 static int imapc_list_refresh(struct imapc_mailbox_list *list,
                              enum mailbox_list_iter_flags flags)
 {
@@ -279,10 +291,13 @@ static int imapc_list_set_subscribed(struct mailbox_list *_list,
 }
 
 static int
-imapc_list_create_mailbox_dir(struct mailbox_list *list, const char *name,
-                             enum mailbox_dir_create_type type)
+imapc_list_create_mailbox_dir(struct mailbox_list *list ATTR_UNUSED,
+                             const char *name ATTR_UNUSED,
+                             enum mailbox_dir_create_type type ATTR_UNUSED)
 {
-       return -1;
+       /* this gets called just before mailbox.create().
+          we don't need to do anything. */
+       return 0;
 }
 
 static int
index 371b95c325d9109973fab1c69907ff52cd23b16d..b2f36e56fac3e9e28c5cc9249aa20be33f804def 100644 (file)
@@ -19,9 +19,6 @@ struct imapc_mailbox_list {
        unsigned int broken:1;
 };
 
-void imapc_list_update_mailbox(struct imapc_mailbox_list *list,
-                              const struct imap_arg *args);
-void imapc_list_update_subscription(struct imapc_mailbox_list *list,
-                                   const struct imap_arg *args);
+void imapc_list_register_callbacks(struct imapc_mailbox_list *list);
 
 #endif
diff --git a/src/lib-storage/index/imapc/imapc-mailbox.c b/src/lib-storage/index/imapc/imapc-mailbox.c
new file mode 100644 (file)
index 0000000..4f3d730
--- /dev/null
@@ -0,0 +1,176 @@
+/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "imap-arg.h"
+#include "imap-util.h"
+#include "imapc-client.h"
+#include "imapc-seqmap.h"
+#include "imapc-storage.h"
+
+static void imapc_untagged_exists(const struct imapc_untagged_reply *reply,
+                                 struct imapc_mailbox *mbox)
+{
+       uint32_t rcount = reply->num;
+       const struct mail_index_header *hdr;
+       struct imapc_seqmap *seqmap;
+       uint32_t next_lseq, next_rseq;
+
+       if (mbox == NULL)
+               return;
+
+       seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
+       next_lseq = mail_index_view_get_messages_count(mbox->box.view) + 1;
+       next_rseq = imapc_seqmap_lseq_to_rseq(seqmap, next_lseq);
+       if (next_rseq > rcount)
+               return;
+
+       hdr = mail_index_get_header(mbox->box.view);
+
+       mbox->new_msgs = TRUE;
+       imapc_client_mailbox_cmdf(mbox->client_box, imapc_async_stop_callback,
+                                 mbox->storage, "UID FETCH %u:* FLAGS",
+                                 hdr->next_uid);
+}
+
+
+static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply,
+                                struct imapc_mailbox *mbox)
+{
+       uint32_t seq = reply->num;
+       struct imapc_seqmap *seqmap;
+       const struct imap_arg *list, *flags_list;
+       const char *atom;
+       const struct mail_index_record *rec;
+       enum mail_flags flags;
+       uint32_t uid, old_count;
+       unsigned int i, j;
+       bool seen_flags = FALSE;
+
+       if (mbox == NULL || seq == 0 || !imap_arg_get_list(reply->args, &list))
+               return;
+
+       uid = 0; flags = 0;
+       for (i = 0; list[i].type != IMAP_ARG_EOL; i += 2) {
+               if (!imap_arg_get_atom(&list[i], &atom))
+                       return;
+
+               if (strcasecmp(atom, "UID") == 0) {
+                       if (!imap_arg_get_atom(&list[i+1], &atom) ||
+                           str_to_uint32(atom, &uid) < 0)
+                               return;
+               } else if (strcasecmp(atom, "FLAGS") == 0) {
+                       if (!imap_arg_get_list(&list[i+1], &flags_list))
+                               return;
+
+                       seen_flags = TRUE;
+                       for (j = 0; flags_list[j].type != IMAP_ARG_EOL; j++) {
+                               if (!imap_arg_get_atom(&flags_list[j], &atom))
+                                       return;
+                               if (atom[0] == '\\')
+                                       flags |= imap_parse_system_flag(atom);
+                       }
+               }
+       }
+
+       seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
+       seq = imapc_seqmap_rseq_to_lseq(seqmap, seq);
+
+       if (mbox->cur_fetch_mail != NULL && mbox->cur_fetch_mail->seq == seq) {
+               i_assert(uid == 0 || mbox->cur_fetch_mail->uid == uid);
+               imapc_fetch_mail_update(mbox->cur_fetch_mail, list);
+       }
+
+       old_count = mail_index_view_get_messages_count(mbox->delayed_sync_view);
+       if (seq > old_count) {
+               if (uid == 0)
+                       return;
+               i_assert(seq == old_count + 1);
+               mail_index_append(mbox->delayed_sync_trans, uid, &seq);
+       }
+       rec = mail_index_lookup(mbox->delayed_sync_view, seq);
+       if (seen_flags && rec->flags != flags) {
+               mail_index_update_flags(mbox->delayed_sync_trans, seq,
+                                       MODIFY_REPLACE, flags);
+       }
+}
+
+static void imapc_untagged_expunge(const struct imapc_untagged_reply *reply,
+                                  struct imapc_mailbox *mbox)
+{
+       struct imapc_seqmap *seqmap;
+       uint32_t lseq, rseq = reply->num;
+
+       if (mbox == NULL || rseq == 0)
+               return;
+
+       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);
+}
+
+static void
+imapc_resp_text_uidvalidity(const struct imapc_untagged_reply *reply,
+                           struct imapc_mailbox *mbox)
+{
+       uint32_t uid_validity;
+
+       if (mbox == NULL || reply->resp_text_value == NULL ||
+           str_to_uint32(reply->resp_text_value, &uid_validity) < 0)
+               return;
+
+       mail_index_update_header(mbox->delayed_sync_trans,
+               offsetof(struct mail_index_header, uid_validity),
+               &uid_validity, sizeof(uid_validity), TRUE);
+}
+
+static void
+imapc_resp_text_uidnext(const struct imapc_untagged_reply *reply,
+                       struct imapc_mailbox *mbox)
+{
+       uint32_t uid_next;
+
+       if (mbox == NULL || reply->resp_text_value == NULL ||
+           str_to_uint32(reply->resp_text_value, &uid_next) < 0)
+               return;
+
+       mail_index_update_header(mbox->delayed_sync_trans,
+                                offsetof(struct mail_index_header, next_uid),
+                                &uid_next, sizeof(uid_next), FALSE);
+}
+
+
+void imapc_mailbox_register_untagged(struct imapc_mailbox *mbox,
+                                    const char *key,
+                                    imapc_mailbox_callback_t *callback)
+{
+       struct imapc_mailbox_event_callback *cb;
+
+       cb = array_append_space(&mbox->untagged_callbacks);
+       cb->name = p_strdup(mbox->box.pool, key);
+       cb->callback = callback;
+}
+
+void imapc_mailbox_register_resp_text(struct imapc_mailbox *mbox,
+                                     const char *key,
+                                     imapc_mailbox_callback_t *callback)
+{
+       struct imapc_mailbox_event_callback *cb;
+
+       cb = array_append_space(&mbox->resp_text_callbacks);
+       cb->name = p_strdup(mbox->box.pool, key);
+       cb->callback = callback;
+}
+
+void imapc_mailbox_register_callbacks(struct imapc_mailbox *mbox)
+{
+       imapc_mailbox_register_untagged(mbox, "EXISTS",
+                                       imapc_untagged_exists);
+       imapc_mailbox_register_untagged(mbox, "FETCH",
+                                       imapc_untagged_fetch);
+       imapc_mailbox_register_untagged(mbox, "EXPUNGE",
+                                       imapc_untagged_expunge);
+       imapc_mailbox_register_resp_text(mbox, "UIDVALIDITY",
+                                        imapc_resp_text_uidvalidity);
+       imapc_mailbox_register_resp_text(mbox, "UIDNEXT",
+                                        imapc_resp_text_uidnext);
+}
index b0d7cfafeffa49cc190d7a37160fdcc67e4df4eb..7f995756192dba16812b7468d8cae7e0040a49cb 100644 (file)
@@ -2,20 +2,14 @@
 
 #include "lib.h"
 #include "str.h"
-#include "imap-util.h"
-#include "imap-arg.h"
 #include "imap-resp-code.h"
 #include "mail-copy.h"
 #include "index-mail.h"
-#include "mailbox-list-private.h"
 #include "imapc-client.h"
 #include "imapc-list.h"
-#include "imapc-seqmap.h"
 #include "imapc-sync.h"
 #include "imapc-storage.h"
 
-#include <sys/stat.h>
-
 #define DNS_CLIENT_SOCKET_NAME "dns-client"
 
 struct imapc_open_context {
@@ -92,15 +86,13 @@ imapc_copy_error_from_reply(struct imapc_storage *storage,
                            const struct imapc_command_reply *reply)
 {
        enum mail_error error;
-       const char *p;
 
-       if (imap_resp_text_code_parse(reply->resp_text, &error)) {
-               p = strchr(reply->text, ']');
-               i_assert(p != NULL);
-               mail_storage_set_error(&storage->storage, error, p + 1);
+       if (imap_resp_text_code_parse(reply->resp_text_key, &error)) {
+               mail_storage_set_error(&storage->storage, error,
+                                      reply->text_without_resp);
        } else {
                mail_storage_set_error(&storage->storage, default_error,
-                                      reply->text);
+                                      reply->text_without_resp);
        }
 }
 
@@ -116,7 +108,7 @@ void imapc_simple_callback(const struct imapc_command_reply *reply,
                ctx->ret = -1;
        } else {
                mail_storage_set_critical(&ctx->storage->storage,
-                       "imapc: Command failed: %s", reply->text);
+                       "imapc: Command failed: %s", reply->text_full);
                ctx->ret = -1;
        }
        imapc_client_stop(ctx->storage->client);
@@ -133,133 +125,37 @@ void imapc_async_stop_callback(const struct imapc_command_reply *reply,
                imapc_copy_error_from_reply(storage, MAIL_ERROR_PARAMS, reply);
        } else {
                mail_storage_set_critical(&storage->storage,
-                       "imapc: Command failed: %s", reply->text);
+                       "imapc: Command failed: %s", reply->text_full);
        }
        imapc_client_stop(storage->client);
 }
 
-static void
-imapc_mailbox_map_new_msgs(struct imapc_mailbox *mbox,
-                          struct imapc_seqmap *seqmap, uint32_t rcount)
-{
-       const struct mail_index_header *hdr;
-       uint32_t next_lseq, next_rseq;
-
-       next_lseq = mail_index_view_get_messages_count(mbox->box.view) + 1;
-       next_rseq = imapc_seqmap_lseq_to_rseq(seqmap, next_lseq);
-       if (next_rseq > rcount)
-               return;
-
-       hdr = mail_index_get_header(mbox->box.view);
-
-       mbox->new_msgs = TRUE;
-       imapc_client_mailbox_cmdf(mbox->client_box, imapc_async_stop_callback,
-                                 mbox->storage, "UID FETCH %u:* FLAGS",
-                                 hdr->next_uid);
-}
-
-static void
-imapc_mailbox_map_fetch_reply(struct imapc_mailbox *mbox,
-                             const struct imap_arg *args, uint32_t seq)
-{
-       struct imapc_seqmap *seqmap;
-       const struct imap_arg *list, *flags_list;
-       const char *atom;
-       const struct mail_index_record *rec;
-       enum mail_flags flags;
-       uint32_t uid, old_count;
-       unsigned int i, j;
-       bool seen_flags = FALSE;
-
-       if (seq == 0 || !imap_arg_get_list(args, &list))
-               return;
-
-       uid = 0; flags = 0;
-       for (i = 0; list[i].type != IMAP_ARG_EOL; i += 2) {
-               if (!imap_arg_get_atom(&list[i], &atom))
-                       return;
-
-               if (strcasecmp(atom, "UID") == 0) {
-                       if (!imap_arg_get_atom(&list[i+1], &atom) ||
-                           str_to_uint32(atom, &uid) < 0)
-                               return;
-               } else if (strcasecmp(atom, "FLAGS") == 0) {
-                       if (!imap_arg_get_list(&list[i+1], &flags_list))
-                               return;
-
-                       seen_flags = TRUE;
-                       for (j = 0; flags_list[j].type != IMAP_ARG_EOL; j++) {
-                               if (!imap_arg_get_atom(&flags_list[j], &atom))
-                                       return;
-                               if (atom[0] == '\\')
-                                       flags |= imap_parse_system_flag(atom);
-                       }
-               }
-       }
-
-       seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
-       seq = imapc_seqmap_rseq_to_lseq(seqmap, seq);
-
-       if (mbox->cur_fetch_mail != NULL && mbox->cur_fetch_mail->seq == seq) {
-               i_assert(uid == 0 || mbox->cur_fetch_mail->uid == uid);
-               imapc_fetch_mail_update(mbox->cur_fetch_mail, list);
-       }
-
-       old_count = mail_index_view_get_messages_count(mbox->delayed_sync_view);
-       if (seq > old_count) {
-               if (uid == 0)
-                       return;
-               i_assert(seq == old_count + 1);
-               mail_index_append(mbox->delayed_sync_trans, uid, &seq);
-       }
-       rec = mail_index_lookup(mbox->delayed_sync_view, seq);
-       if (seen_flags && rec->flags != flags) {
-               mail_index_update_flags(mbox->delayed_sync_trans, seq,
-                                       MODIFY_REPLACE, flags);
-       }
-}
-
 static void imapc_storage_untagged_cb(const struct imapc_untagged_reply *reply,
                                      void *context)
 {
        struct imapc_storage *storage = context;
        struct imapc_mailbox *mbox = reply->untagged_box_context;
-       struct imapc_seqmap *seqmap;
-       uint32_t lseq;
+       const struct imapc_storage_event_callback *cb;
+       const struct imapc_mailbox_event_callback *mcb;
 
-       if (strcasecmp(reply->name, "LIST") == 0)
-               imapc_list_update_mailbox(storage->list, reply->args);
-       else if (strcasecmp(reply->name, "LSUB") == 0)
-               imapc_list_update_subscription(storage->list, reply->args);
+       array_foreach(&storage->untagged_callbacks, cb) {
+               if (strcasecmp(reply->name, cb->name) == 0)
+                       cb->callback(reply, storage);
+       }
 
        if (mbox == NULL)
                return;
 
-       if (reply->resp_text != NULL) {
-               uint32_t uid_validity, uid_next;
-
-               if (strncasecmp(reply->resp_text, "UIDVALIDITY ", 12) == 0 &&
-                   str_to_uint32(reply->resp_text + 12, &uid_validity) == 0) {
-                       mail_index_update_header(mbox->delayed_sync_trans,
-                               offsetof(struct mail_index_header, uid_validity),
-                               &uid_validity, sizeof(uid_validity), TRUE);
-               }
-               if (strncasecmp(reply->resp_text, "UIDNEXT ", 8) == 0 &&
-                   str_to_uint32(reply->resp_text + 8, &uid_next) == 0) {
-                       mail_index_update_header(mbox->delayed_sync_trans,
-                               offsetof(struct mail_index_header, next_uid),
-                               &uid_next, sizeof(uid_next), FALSE);
-               }
+       array_foreach(&mbox->untagged_callbacks, mcb) {
+               if (strcasecmp(reply->name, mcb->name) == 0)
+                       mcb->callback(reply, mbox);
        }
 
-       seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
-       if (strcasecmp(reply->name, "EXISTS") == 0) {
-               imapc_mailbox_map_new_msgs(mbox, seqmap, reply->num);
-       } else if (strcasecmp(reply->name, "FETCH") == 0) {
-               imapc_mailbox_map_fetch_reply(mbox, reply->args, reply->num);
-       } else if (strcasecmp(reply->name, "EXPUNGE") == 0) {
-               lseq = imapc_seqmap_rseq_to_lseq(seqmap, reply->num);
-               mail_index_expunge(mbox->delayed_sync_trans, lseq);
+       if (reply->resp_text_key != NULL) {
+               array_foreach(&mbox->resp_text_callbacks, mcb) {
+                       if (strcasecmp(reply->resp_text_key, mcb->name) == 0)
+                               mcb->callback(reply, mbox);
+               }
        }
 }
 
@@ -283,11 +179,14 @@ imapc_storage_create(struct mail_storage *_storage,
        set.dns_client_socket_path =
                t_strconcat(_storage->user->set->base_dir, "/",
                            DNS_CLIENT_SOCKET_NAME, NULL);
-       storage->list = (struct imapc_list *)ns->list;
+       storage->list = (struct imapc_mailbox_list *)ns->list;
        storage->list->storage = storage;
        storage->client = imapc_client_init(&set);
+
+       p_array_init(&storage->untagged_callbacks, _storage->pool, 16);
        imapc_client_register_untagged(storage->client,
                                       imapc_storage_untagged_cb, storage);
+       imapc_list_register_callbacks(storage->list);
        return 0;
 }
 
@@ -298,6 +197,17 @@ static void imapc_storage_destroy(struct mail_storage *_storage)
        imapc_client_deinit(&storage->client);
 }
 
+void imapc_storage_register_untagged(struct imapc_storage *storage,
+                                    const char *name,
+                                    imapc_storage_callback_t *callback)
+{
+       struct imapc_storage_event_callback *cb;
+
+       cb = array_append_space(&storage->untagged_callbacks);
+       cb->name = p_strdup(storage->storage.pool, name);
+       cb->callback = callback;
+}
+
 static void
 imapc_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
                                struct mailbox_list_settings *set)
@@ -331,6 +241,10 @@ imapc_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
        ibox->save_rollback = imapc_transaction_save_rollback;
 
        mbox->storage = (struct imapc_storage *)storage;
+
+       p_array_init(&mbox->untagged_callbacks, pool, 16);
+       p_array_init(&mbox->resp_text_callbacks, pool, 16);
+       imapc_mailbox_register_callbacks(mbox);
        return &mbox->box;
 }
 
@@ -349,7 +263,7 @@ imapc_mailbox_open_callback(const struct imapc_command_reply *reply,
        } else {
                mail_storage_set_critical(ctx->mbox->box.storage,
                        "imapc: Opening mailbox '%s' failed: %s",
-                       ctx->mbox->box.name, reply->text);
+                       ctx->mbox->box.name, reply->text_full);
                ctx->ret = -1;
        }
        if (!ctx->mbox->new_msgs)
@@ -404,8 +318,8 @@ imapc_mailbox_create(struct mailbox *box,
        const char *name = box->name;
 
        if (directory) {
-               /* FIXME: hardcoded separator.. */
-               name = t_strconcat(name, "/", NULL);
+               name = t_strdup_printf("%s%c", name,
+                               mailbox_list_get_hierarchy_sep(box->list));
        }
        ctx.storage = mbox->storage;
        imapc_client_cmdf(mbox->storage->client, imapc_simple_callback, &ctx,
@@ -443,7 +357,7 @@ imapc_mailbox_status_callback(const struct imapc_command_reply *reply,
        } else {
                mail_storage_set_critical(ctx->mbox->box.storage,
                        "imapc: STATUS for mailbox '%s' failed: %s",
-                       ctx->mbox->box.name, reply->text);
+                       ctx->mbox->box.name, reply->text_full);
                ctx->ret = -1;
        }
        imapc_client_stop(ctx->mbox->storage->client);
index ad39d3473fd0e2a613120640b88a4ea219137f85..f51a3008c7721019b756b76a608fc663a0fc1480 100644 (file)
@@ -6,12 +6,32 @@
 #define IMAPC_STORAGE_NAME "imapc"
 
 struct imap_arg;
+struct imapc_untagged_reply;
 struct imapc_command_reply;
+struct imapc_mailbox;
+struct imapc_storage;
+
+typedef void imapc_storage_callback_t(const struct imapc_untagged_reply *reply,
+                                     struct imapc_storage *storage);
+typedef void imapc_mailbox_callback_t(const struct imapc_untagged_reply *reply,
+                                     struct imapc_mailbox *mbox);
+
+struct imapc_storage_event_callback {
+       const char *name;
+       imapc_storage_callback_t *callback;
+};
+
+struct imapc_mailbox_event_callback {
+       const char *name;
+       imapc_mailbox_callback_t *callback;
+};
 
 struct imapc_storage {
        struct mail_storage storage;
        struct imapc_mailbox_list *list;
        struct imapc_client *client;
+
+       ARRAY_DEFINE(untagged_callbacks, struct imapc_storage_event_callback);
 };
 
 struct imapc_mailbox {
@@ -24,6 +44,9 @@ struct imapc_mailbox {
 
        struct mail *cur_fetch_mail;
 
+       ARRAY_DEFINE(untagged_callbacks, struct imapc_mailbox_event_callback);
+       ARRAY_DEFINE(resp_text_callbacks, struct imapc_mailbox_event_callback);
+
        unsigned int new_msgs:1;
 };
 
@@ -59,4 +82,16 @@ void imapc_simple_callback(const struct imapc_command_reply *reply,
 void imapc_async_stop_callback(const struct imapc_command_reply *reply,
                               void *context);
 
+void imapc_storage_register_untagged(struct imapc_storage *storage,
+                                    const char *name,
+                                    imapc_storage_callback_t *callback);
+void imapc_mailbox_register_untagged(struct imapc_mailbox *mbox,
+                                    const char *name,
+                                    imapc_mailbox_callback_t *callback);
+void imapc_mailbox_register_resp_text(struct imapc_mailbox *mbox,
+                                     const char *key,
+                                     imapc_mailbox_callback_t *callback);
+
+void imapc_mailbox_register_callbacks(struct imapc_mailbox *mbox);
+
 #endif