]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Initial support for local index files.
authorTimo Sirainen <tss@iki.fi>
Thu, 10 Mar 2011 16:32:08 +0000 (18:32 +0200)
committerTimo Sirainen <tss@iki.fi>
Thu, 10 Mar 2011 16:32:08 +0000 (18:32 +0200)
src/lib-storage/index/imapc/imapc-list.c
src/lib-storage/index/imapc/imapc-list.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
src/lib-storage/index/imapc/imapc-sync.h

index 72ba525b4f9ec2d1d1f2e4f160eee3e77abfbb30..7217ed525d13e16850ef3137e6db73cfb0c0b453 100644 (file)
@@ -182,22 +182,84 @@ static char imapc_list_get_hierarchy_sep(struct mailbox_list *_list)
        return list->sep;
 }
 
+static struct mailbox_list *imapc_list_get_fs(struct imapc_mailbox_list *list)
+{
+       struct mailbox_list_settings list_set;
+       const char *error, *dir;
+
+       dir = list->list.set.index_dir;
+       if (dir == NULL)
+               dir = list->list.set.root_dir;
+
+       if (dir == NULL) {
+               /* indexes disabled */
+       } else if (list->index_list == NULL && !list->index_list_failed) {
+               memset(&list_set, 0, sizeof(list_set));
+               list_set.layout = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS;
+               /* the root dir shouldn't actually ever be used. we just need
+                  it to be different from index_dir so the index directories
+                  get autocreated */
+               list_set.root_dir = t_strconcat(dir, "/", NULL);
+               list_set.index_dir = dir;
+               list_set.escape_char = '%';
+
+               if (mailbox_list_create(list_set.layout, list->list.ns,
+                                       &list_set, MAILBOX_LIST_FLAG_SECONDARY,
+                                       &list->index_list, &error) < 0) {
+                       i_error("imapc: Couldn't create %s mailbox list: %s",
+                               list_set.layout, error);
+                       list->index_list_failed = TRUE;
+               }
+       }
+       return list->index_list;
+}
+
 static const char *
-imapc_list_get_path(struct mailbox_list *list ATTR_UNUSED,
-                   const char *name ATTR_UNUSED,
+imapc_list_get_fs_name(struct imapc_mailbox_list *list, const char *name)
+{
+       struct mailbox_list *fs_list = imapc_list_get_fs(list);
+       const char *vname;
+
+       if (name == NULL)
+               return name;
+
+       vname = mailbox_list_get_vname(&list->list, name);
+       return mailbox_list_get_storage_name(fs_list, vname);
+}
+
+static const char *
+imapc_list_get_path(struct mailbox_list *_list, const char *name,
                    enum mailbox_list_path_type type)
 {
-       if (type == MAILBOX_LIST_PATH_TYPE_INDEX)
-               return "";
-       return NULL;
+       struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list;
+       struct mailbox_list *fs_list = imapc_list_get_fs(list);
+       const char *fs_name;
+
+       if (fs_list != NULL) {
+               fs_name = imapc_list_get_fs_name(list, name);
+               return mailbox_list_get_path(fs_list, fs_name, type);
+       } else {
+               if (type == MAILBOX_LIST_PATH_TYPE_INDEX)
+                       return "";
+               return NULL;
+       }
 }
 
 static const char *
-imapc_list_get_temp_prefix(struct mailbox_list *list, bool global ATTR_UNUSED)
+imapc_list_get_temp_prefix(struct mailbox_list *_list, bool global)
 {
-       i_panic("imapc: Can't return a temp prefix for '%s'",
-               list->ns->prefix);
-       return NULL;
+       struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list;
+       struct mailbox_list *fs_list = imapc_list_get_fs(list);
+
+       if (fs_list != NULL) {
+               return global ?
+                       mailbox_list_get_global_temp_prefix(fs_list) :
+                       mailbox_list_get_temp_prefix(fs_list);
+       } else {
+               i_panic("imapc: Can't return a temp prefix for '%s'",
+                       _list->ns->prefix);
+               return NULL;
+       }
 }
 
 static const char *
@@ -422,9 +484,15 @@ imapc_list_delete_mailbox(struct mailbox_list *_list, const char *name)
 }
 
 static int
-imapc_list_delete_dir(struct mailbox_list *list ATTR_UNUSED,
-                     const char *name ATTR_UNUSED)
+imapc_list_delete_dir(struct mailbox_list *_list, const char *name)
 {
+       struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list;
+       struct mailbox_list *fs_list = imapc_list_get_fs(list);
+
+       if (fs_list != NULL) {
+               name = imapc_list_get_fs_name(list, name);
+               (void)mailbox_list_delete_dir(fs_list, name);
+       }
        return 0;
 }
 
@@ -434,6 +502,7 @@ imapc_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
                          bool rename_children)
 {
        struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)oldlist;
+       struct mailbox_list *fs_list = imapc_list_get_fs(list);
        struct imapc_simple_context ctx;
 
        if (!rename_children) {
@@ -453,6 +522,13 @@ imapc_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname,
                          imapc_list_simple_callback, &ctx,
                          "RENAME %s %s", oldname, newname);
        imapc_simple_run(&ctx);
+       if (ctx.ret == 0 && fs_list != NULL && oldlist == newlist) {
+               oldname = imapc_list_get_fs_name(list, oldname);
+               newname = imapc_list_get_fs_name(list, newname);
+               (void)fs_list->v.rename_mailbox(fs_list, oldname,
+                                               fs_list, newname,
+                                               rename_children);
+       }
        return ctx.ret;
 }
 
index 73c48c4913469b740d92ac03f362466fa1dfe26c..90cc35beeb04f53102e30da77c1d44c3117ac158 100644 (file)
@@ -10,6 +10,7 @@ struct imap_arg;
 struct imapc_mailbox_list {
        struct mailbox_list list;
        struct imapc_storage *storage;
+       struct mailbox_list *index_list;
 
        struct mailbox_tree_context *mailboxes, *tmp_subscriptions;
        char sep;
@@ -21,6 +22,7 @@ struct imapc_mailbox_list {
        unsigned int broken:1;
        unsigned int refreshed_subscriptions:1;
        unsigned int refreshed_mailboxes:1;
+       unsigned int index_list_failed:1;
 };
 
 void imapc_list_register_callbacks(struct imapc_mailbox_list *list);
index 53d23f4ff090e9b37929f4408462c3f314d89057..6677535c467d1f2cfd3a1ff3f64f9ea7276ed1f2 100644 (file)
@@ -6,6 +6,7 @@
 #include "imap-util.h"
 #include "imapc-client.h"
 #include "imapc-seqmap.h"
+#include "imapc-sync.h"
 #include "imapc-storage.h"
 
 #define NOTIFY_DELAY_MSECS 500
@@ -37,6 +38,27 @@ static void imapc_mailbox_init_delayed_trans(struct imapc_mailbox *mbox)
                mail_index_transaction_open_updated_view(mbox->delayed_sync_trans);
 }
 
+int imapc_mailbox_commit_delayed_trans(struct imapc_mailbox *mbox,
+                                      bool *changes_r)
+{
+       int ret = 0;
+
+       *changes_r = FALSE;
+
+       if (mbox->delayed_sync_view != NULL)
+               mail_index_view_close(&mbox->delayed_sync_view);
+       if (mbox->delayed_sync_trans != NULL) {
+               if (mail_index_transaction_commit(&mbox->delayed_sync_trans) < 0) {
+                       mail_storage_set_index_error(&mbox->box);
+                       ret = -1;
+               }
+               *changes_r = TRUE;
+       }
+       if (mbox->sync_view != NULL)
+               mail_index_view_close(&mbox->sync_view);
+       return ret;
+}
+
 static void
 imapc_newmsgs_callback(const struct imapc_command_reply *reply,
                       void *context)
@@ -63,7 +85,7 @@ static void imapc_untagged_exists(const struct imapc_untagged_reply *reply,
        uint32_t rcount = reply->num;
        const struct mail_index_header *hdr;
        struct imapc_seqmap *seqmap;
-       uint32_t next_lseq, next_rseq;
+       uint32_t first_uid, next_lseq, next_rseq;
 
        if (mbox == NULL)
                return;
@@ -74,14 +96,19 @@ static void imapc_untagged_exists(const struct imapc_untagged_reply *reply,
        seqmap = imapc_client_mailbox_get_seqmap(mbox->client_box);
        next_lseq = mail_index_view_get_messages_count(view) + 1;
        next_rseq = imapc_seqmap_lseq_to_rseq(seqmap, next_lseq);
-       if (next_rseq > rcount)
-               return;
-
-       hdr = mail_index_get_header(view);
+       if (next_rseq > rcount) {
+               if (rcount == 0 || !mbox->opening)
+                       return;
+               /* initial SELECT. we don't know what the flags are. */
+               first_uid = 1;
+       } else {
+               hdr = mail_index_get_header(view);
+               first_uid = hdr->next_uid;
+       }
 
        mbox->new_msgs = TRUE;
        imapc_client_mailbox_cmdf(mbox->client_box, imapc_newmsgs_callback,
-                                 mbox, "UID FETCH %u:* FLAGS", hdr->next_uid);
+                                 mbox, "UID FETCH %u:* FLAGS", first_uid);
 }
 
 static void imapc_mailbox_idle_timeout(struct imapc_mailbox *mbox)
@@ -101,6 +128,28 @@ static void imapc_mailbox_idle_notify(struct imapc_mailbox *mbox)
        }
 }
 
+static bool keywords_are_equal(struct mail_keywords *kw,
+                              const ARRAY_TYPE(keyword_indexes) *kw_arr)
+{
+       const unsigned int *kw_idx;
+       unsigned int i, j, count;
+
+       kw_idx = array_get(kw_arr, &count);
+       if (count != kw->count)
+               return FALSE;
+
+       /* there are normally only a few keywords, so O(n^2) is fine */
+       for (i = 0; i < count; i++) {
+               for (j = 0; j < count; j++) {
+                       if (kw->idx[i] == kw_idx[j])
+                               break;
+               }
+               if (j == count)
+                       return FALSE;
+       }
+       return TRUE;
+}
+
 static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply,
                                 struct imapc_mailbox *mbox)
 {
@@ -158,32 +207,49 @@ static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply,
 
        imapc_mailbox_init_delayed_trans(mbox);
        old_count = mail_index_view_get_messages_count(mbox->delayed_sync_view);
+       while (lseq <= old_count) {
+               rec = mail_index_lookup(mbox->delayed_sync_view, lseq);
+               if (rec->uid == uid || uid == 0)
+                       break;
+
+               if (!mbox->opening || uid < rec->uid) {
+                       imapc_mailbox_set_corrupted(mbox,
+                               "Message UID changed %u -> %u", rec->uid, uid);
+                       return;
+               }
+               /* we're opening the mailbox. this message was expunged
+                  externally, so expunge it ourself too. */
+               imapc_seqmap_expunge(seqmap, rseq);
+               mail_index_expunge(mbox->delayed_sync_trans, lseq);
+               lseq++;
+       }
        if (lseq > old_count) {
                if (uid == 0 || lseq != old_count + 1)
                        return;
                i_assert(lseq == old_count + 1);
                mail_index_append(mbox->delayed_sync_trans, uid, &lseq);
        }
-       rec = mail_index_lookup(mbox->delayed_sync_view, lseq);
-       if (rec->uid != uid && uid != 0) {
-               imapc_mailbox_set_corrupted(mbox, "Message UID changed %u -> %u",
-                                           rec->uid, uid);
-               return;
-       }
        if (seen_flags && rec->flags != flags) {
                mail_index_update_flags(mbox->delayed_sync_trans, lseq,
                                        MODIFY_REPLACE, flags);
        }
-       if (seen_flags) {
+       if (seen_flags) T_BEGIN {
+               ARRAY_TYPE(keyword_indexes) old_kws;
                struct mail_keywords *kw;
 
+               t_array_init(&old_kws, 8);
+               mail_index_lookup_keywords(mbox->delayed_sync_view, lseq,
+                                          &old_kws);
+
                (void)array_append_space(&keywords);
                kw = mail_index_keywords_create(mbox->box.index,
                                                array_idx(&keywords, 0));
-               mail_index_update_keywords(mbox->delayed_sync_trans, lseq,
-                                          MODIFY_REPLACE, kw);
+               if (!keywords_are_equal(kw, &old_kws)) {
+                       mail_index_update_keywords(mbox->delayed_sync_trans,
+                                                  lseq, MODIFY_REPLACE, kw);
+               }
                mail_index_keywords_unref(&kw);
-       }
+       } T_END;
        imapc_mailbox_idle_notify(mbox);
 }
 
@@ -222,32 +288,47 @@ static void
 imapc_resp_text_uidvalidity(const struct imapc_untagged_reply *reply,
                            struct imapc_mailbox *mbox)
 {
+       const struct mail_index_header *hdr;
        uint32_t uid_validity;
+       bool changes;
 
        if (mbox == NULL || reply->resp_text_value == NULL ||
            str_to_uint32(reply->resp_text_value, &uid_validity) < 0)
                return;
 
-       imapc_mailbox_init_delayed_trans(mbox);
-       mail_index_update_header(mbox->delayed_sync_trans,
-               offsetof(struct mail_index_header, uid_validity),
-               &uid_validity, sizeof(uid_validity), TRUE);
+       hdr = mail_index_get_header(mbox->box.view);
+       if (hdr->uid_validity != uid_validity) {
+               imapc_mailbox_init_delayed_trans(mbox);
+               if (hdr->uid_validity != 0) {
+                       /* uidvalidity changed, reset the entire mailbox */
+                       mail_index_reset(mbox->delayed_sync_trans);
+                       (void)imapc_mailbox_commit_delayed_trans(mbox, &changes);
+                       imapc_mailbox_init_delayed_trans(mbox);
+               }
+               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)
 {
+       const struct mail_index_header *hdr;
        uint32_t uid_next;
 
        if (mbox == NULL || reply->resp_text_value == NULL ||
            str_to_uint32(reply->resp_text_value, &uid_next) < 0)
                return;
 
-       imapc_mailbox_init_delayed_trans(mbox);
-       mail_index_update_header(mbox->delayed_sync_trans,
-                                offsetof(struct mail_index_header, next_uid),
-                                &uid_next, sizeof(uid_next), FALSE);
+       hdr = mail_index_get_header(mbox->box.view);
+       if (hdr->next_uid != uid_next) {
+               imapc_mailbox_init_delayed_trans(mbox);
+               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,
index d9edb3927848ae2ff1f534d178f660ae3c28f9a1..23697393035e9d5dd6944b7ef0963e4aa0fadf77 100644 (file)
@@ -267,8 +267,6 @@ imapc_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
        struct index_mailbox_context *ibox;
        pool_t pool;
 
-       flags |= MAILBOX_FLAG_NO_INDEX_FILES;
-
        pool = pool_alloconly_create("imapc mailbox", 1024*3);
        mbox = p_new(pool, struct imapc_mailbox, 1);
        mbox->box = imapc_mailbox;
@@ -277,7 +275,8 @@ imapc_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
        mbox->box.list = list;
        mbox->box.mail_vfuncs = &imapc_mail_vfuncs;
 
-       index_storage_mailbox_alloc(&mbox->box, vname, flags, NULL);
+       index_storage_mailbox_alloc(&mbox->box, vname, flags,
+                                   IMAPC_INDEX_PREFIX);
 
        ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
        ibox->save_commit_pre = imapc_transaction_save_commit_pre;
index f1b8f0ba70444d98eff1e6469214a8fedb6c8448..27fedaa268c8b136464492ce99b5ef91b8163309 100644 (file)
@@ -4,6 +4,7 @@
 #include "index-storage.h"
 
 #define IMAPC_STORAGE_NAME "imapc"
+#define IMAPC_INDEX_PREFIX "dovecot.index"
 
 struct imap_arg;
 struct imapc_untagged_reply;
@@ -102,6 +103,8 @@ void imapc_async_stop_callback(const struct imapc_command_reply *reply,
                               void *context);
 int imapc_mailbox_get_client_box(struct imapc_mailbox *mbox,
                                 struct imapc_client_mailbox **client_box_r);
+int imapc_mailbox_commit_delayed_trans(struct imapc_mailbox *mbox,
+                                      bool *changes_r);
 
 void imapc_storage_register_untagged(struct imapc_storage *storage,
                                     const char *name,
index 45e312657f4798df6fcb195ef6b814f08fa80282..0fa1cdd2778110cf371d6992067ce97dd2ea1e9e 100644 (file)
@@ -309,7 +309,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;
-       bool changes = FALSE;
+       bool changes;
        int ret = 0;
 
        if (!box->opened) {
@@ -327,18 +327,8 @@ imapc_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
                imapc_client_run(mbox->storage->client);
        }
 
-       if (mbox->delayed_sync_view != NULL)
-               mail_index_view_close(&mbox->delayed_sync_view);
-       if (mbox->delayed_sync_trans != NULL) {
-               if (mail_index_transaction_commit(&mbox->delayed_sync_trans) < 0) {
-                       mail_storage_set_index_error(&mbox->box);
-                       ret = -1;
-               }
-               changes = TRUE;
-       }
-       if (mbox->sync_view != NULL)
-               mail_index_view_close(&mbox->sync_view);
-
+       if (imapc_mailbox_commit_delayed_trans(mbox, &changes) < 0)
+               ret = -1;
        if ((changes || index_mailbox_want_full_sync(&mbox->box, flags)) &&
            ret == 0)
                ret = imapc_sync(mbox);
index d83b240a058ca8b413a4f5708de611e8efd6d886..de0da627a6f67b8da77109a2237d042fa6bafe9c 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef CYDIR_SYNC_H
 #define CYDIR_SYNC_H
 
+enum mailbox_sync_flags;
 struct mailbox;
+struct mailbox_sync_status;
 
 struct imapc_sync_context {
        struct imapc_mailbox *mbox;