]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added support for mailbox GUIDs.
authorTimo Sirainen <tss@iki.fi>
Mon, 15 Jun 2009 21:37:15 +0000 (17:37 -0400)
committerTimo Sirainen <tss@iki.fi>
Mon, 15 Jun 2009 21:37:15 +0000 (17:37 -0400)
--HG--
branch : HEAD

15 files changed:
src/lib-storage/index/dbox/dbox-mail.c
src/lib-storage/index/dbox/dbox-save.c
src/lib-storage/index/dbox/dbox-storage.c
src/lib-storage/index/dbox/dbox-storage.h
src/lib-storage/index/dbox/dbox-sync-rebuild.c
src/lib-storage/index/dbox/dbox-sync.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/maildir/maildir-uidlist.c
src/lib-storage/index/maildir/maildir-uidlist.h
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/index/mbox/mbox-storage.h
src/lib-storage/index/mbox/mbox-sync.c
src/lib-storage/mail-storage.h
src/util/idxview.c

index 6eff26e9b7aad5d133ead73699e854bb7de6458b..71d0b5beff4c741f8fcc536ed2e3b1af33abb92a 100644 (file)
@@ -49,9 +49,8 @@ int dbox_mail_lookup(struct dbox_mailbox *mbox, struct mail_index_view *view,
                     uint32_t seq, uint32_t *map_uid_r)
 {
        const struct dbox_mail_index_record *dbox_rec;
-       const struct dbox_index_header *hdr;
+       struct dbox_index_header hdr;
        const void *data;
-       size_t data_size;
        uint32_t cur_map_uid_validity;
        bool expunged;
 
@@ -63,18 +62,11 @@ int dbox_mail_lookup(struct dbox_mailbox *mbox, struct mail_index_view *view,
        }
 
        if (mbox->map_uid_validity == 0) {
-               mail_index_get_header_ext(mbox->ibox.view,
-                                         mbox->dbox_hdr_ext_id,
-                                         &data, &data_size);
-               if (data_size != sizeof(*hdr)) {
-                       mail_storage_set_critical(&mbox->storage->storage,
-                               "dbox %s: Invalid dbox header size",
-                               mbox->ibox.box.path);
+               if (dbox_read_header(mbox, &hdr) < 0) {
                        mbox->storage->sync_rebuild = TRUE;
                        return -1;
                }
-               hdr = data;
-               mbox->map_uid_validity = hdr->map_uid_validity;
+               mbox->map_uid_validity = hdr.map_uid_validity;
        }
        if (dbox_map_open(mbox->storage->map, TRUE) < 0)
                return -1;
index 06d50522925237481288a49bd3c62e9df46ebfeb..842414b47992793ac5d338eef774ca71fd298df1 100644 (file)
@@ -319,30 +319,6 @@ void dbox_save_cancel(struct mail_save_context *_ctx)
        (void)dbox_save_finish(_ctx);
 }
 
-static void dbox_add_missing_map_uidvalidity(struct dbox_save_context *ctx)
-{
-       const struct dbox_index_header *hdr;
-       struct dbox_index_header new_hdr;
-       const void *data;
-       size_t data_size;
-
-       mail_index_get_header_ext(ctx->mbox->ibox.view,
-                                 ctx->mbox->dbox_hdr_ext_id,
-                                 &data, &data_size);
-       if (data_size == sizeof(*hdr)) {
-               hdr = data;
-               if (hdr->map_uid_validity != 0)
-                       return;
-               new_hdr = *hdr;
-       } else {
-               memset(&new_hdr, 0, sizeof(new_hdr));
-       }
-       new_hdr.map_uid_validity =
-               dbox_map_get_uid_validity(ctx->mbox->storage->map);
-       mail_index_update_header_ext(ctx->trans, ctx->mbox->dbox_hdr_ext_id, 0,
-                                    &new_hdr, sizeof(new_hdr));
-}
-
 int dbox_transaction_save_commit_pre(struct dbox_save_context *ctx)
 {
        struct dbox_transaction_context *t =
@@ -392,7 +368,7 @@ int dbox_transaction_save_commit_pre(struct dbox_save_context *ctx)
                unsigned int i, count;
                uint32_t next_map_uid = first_map_uid;
 
-               dbox_add_missing_map_uidvalidity(ctx);
+               dbox_update_header(ctx->mbox, ctx->trans);
 
                memset(&rec, 0, sizeof(rec));
                rec.save_date = ioloop_time;
index 8cddab087df2476b7500487734fb3f27c741579f..ef05b3329fef6ac14f204186229accc05bff25e7 100644 (file)
@@ -191,23 +191,72 @@ uint32_t dbox_get_uidvalidity_next(struct mailbox_list *list)
        return mailbox_uidvalidity_next(path);
 }
 
+static bool
+dbox_index_header_has_mailbox_guid(const struct dbox_index_header *hdr)
+{
+       unsigned int i;
+
+       for (i = 0; i < sizeof(hdr->mailbox_guid); i++) {
+               if (hdr->mailbox_guid[i] != 0)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+void dbox_set_mailbox_guid(struct dbox_index_header *hdr)
+{
+       if (!dbox_index_header_has_mailbox_guid(hdr))
+               mail_generate_guid_128(hdr->mailbox_guid);
+}
+
+int dbox_read_header(struct dbox_mailbox *mbox, struct dbox_index_header *hdr)
+{
+       const void *data;
+       size_t data_size;
+
+       mail_index_get_header_ext(mbox->ibox.view, mbox->dbox_hdr_ext_id,
+                                 &data, &data_size);
+       if (data_size < DBOX_INDEX_HEADER_MIN_SIZE &&
+           (!mbox->creating || data_size != 0)) {
+               mail_storage_set_critical(&mbox->storage->storage,
+                       "dbox %s: Invalid dbox header size",
+                       mbox->ibox.box.path);
+               return -1;
+       }
+       memset(hdr, 0, sizeof(*hdr));
+       memcpy(hdr, data, I_MIN(data_size, sizeof(*hdr)));
+       return 0;
+}
+
+void dbox_update_header(struct dbox_mailbox *mbox,
+                       struct mail_index_transaction *trans)
+{
+       struct dbox_index_header hdr, new_hdr;
+
+       if (dbox_read_header(mbox, &hdr) < 0)
+               memset(&hdr, 0, sizeof(hdr));
+
+       new_hdr = hdr;
+       dbox_set_mailbox_guid(&new_hdr);
+       new_hdr.map_uid_validity =
+               dbox_map_get_uid_validity(mbox->storage->map);
+       if (memcmp(&hdr, &new_hdr, sizeof(hdr)) != 0) {
+               mail_index_update_header_ext(trans, mbox->dbox_hdr_ext_id, 0,
+                                            &new_hdr, sizeof(new_hdr));
+       }
+}
+
 static int dbox_write_index_header(struct mailbox *box)
 {
        struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
        struct mail_index_transaction *trans;
-       struct dbox_index_header hdr;
        uint32_t uid_validity;
 
        if (dbox_map_open(mbox->storage->map, TRUE) < 0)
                return -1;
 
        trans = mail_index_transaction_begin(mbox->ibox.view, 0);
-
-       /* set dbox header */
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.map_uid_validity = dbox_map_get_uid_validity(mbox->storage->map);
-       mail_index_update_header_ext(trans, mbox->dbox_hdr_ext_id, 0,
-                                    &hdr, sizeof(hdr));
+       dbox_update_header(mbox, trans);
 
        /* set uidvalidity */
        uid_validity = dbox_get_uidvalidity_next(box->list);
@@ -215,20 +264,30 @@ static int dbox_write_index_header(struct mailbox *box)
                offsetof(struct mail_index_header, uid_validity),
                &uid_validity, sizeof(uid_validity), TRUE);
 
-       return mail_index_transaction_commit(&trans);
+       if (mail_index_transaction_commit(&trans) < 0) {
+               mail_storage_set_internal_error(box->storage);
+               mail_index_reset_error(mbox->ibox.index);
+               return -1;
+       }
+       return 0;
 }
 
 static int create_dbox(struct mailbox *box)
 {
+       struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
        mode_t mode;
        gid_t gid;
+       int ret;
 
        mailbox_list_get_dir_permissions(box->list, NULL, &mode, &gid);
        if (mkdir_parents_chown(box->path, mode, (uid_t)-1, gid) == 0) {
                /* create indexes immediately with the dbox header */
                if (index_storage_mailbox_open(box) < 0)
                        return -1;
-               if (dbox_write_index_header(box) < 0)
+               mbox->creating = TRUE;
+               ret = dbox_write_index_header(box);
+               mbox->creating = FALSE;
+               if (ret < 0)
                        return -1;
        } else if (errno != EEXIST) {
                if (!mail_storage_set_error_from_errno(box->storage)) {
@@ -305,6 +364,35 @@ static void dbox_mailbox_close(struct mailbox *box)
        index_storage_mailbox_close(box);
 }
 
+static void dbox_storage_get_status_guid(struct mailbox *box,
+                                        struct mailbox_status *status_r)
+{
+       struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
+       struct dbox_index_header hdr;
+
+       if (dbox_read_header(mbox, &hdr) < 0)
+               memset(&hdr, 0, sizeof(hdr));
+
+       if (!dbox_index_header_has_mailbox_guid(&hdr)) {
+               /* regenerate it */
+               if (dbox_write_index_header(box) < 0 ||
+                   dbox_read_header(mbox, &hdr) < 0)
+                       return;
+       }
+       memcpy(status_r->mailbox_guid, hdr.mailbox_guid,
+              sizeof(status_r->mailbox_guid));
+}
+
+static void
+dbox_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
+                       struct mailbox_status *status_r)
+{
+       index_storage_get_status(box, items, status_r);
+
+       if ((items & STATUS_GUID) != 0)
+               dbox_storage_get_status_guid(box, status_r);
+}
+
 static int
 dbox_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
                    const char *name, bool directory)
@@ -776,7 +864,7 @@ struct mailbox dbox_mailbox = {
                index_storage_mailbox_enable,
                dbox_mailbox_open,
                dbox_mailbox_close,
-               index_storage_get_status,
+               dbox_storage_get_status,
                NULL,
                NULL,
                dbox_storage_sync_init,
index ad6eb0f1cc0199914e6e6252d23e27ae403e6e3d..bfb27dd4f005999dab84645a4c567635bdfc328a 100644 (file)
 /* Flag specifies if the message should be in primary or alternative storage */
 #define DBOX_INDEX_FLAG_ALT MAIL_INDEX_MAIL_FLAG_BACKEND
 
+#define DBOX_INDEX_HEADER_MIN_SIZE (sizeof(uint32_t))
 struct dbox_index_header {
        uint32_t map_uid_validity;
        uint32_t highest_maildir_uid;
+       uint8_t mailbox_guid[MAILBOX_GUID_SIZE];
 };
 
 struct dbox_storage {
@@ -74,6 +76,8 @@ struct dbox_mailbox {
        uint32_t dbox_ext_id, dbox_hdr_ext_id, guid_ext_id;
 
        const char *alt_path;
+
+       unsigned int creating:1;
 };
 
 struct dbox_transaction_context {
@@ -104,6 +108,10 @@ dbox_mail_alloc(struct mailbox_transaction_context *t,
 int dbox_mail_lookup(struct dbox_mailbox *mbox, struct mail_index_view *view,
                     uint32_t seq, uint32_t *map_uid_r);
 uint32_t dbox_get_uidvalidity_next(struct mailbox_list *list);
+void dbox_set_mailbox_guid(struct dbox_index_header *hdr);
+int dbox_read_header(struct dbox_mailbox *mbox, struct dbox_index_header *hdr);
+void dbox_update_header(struct dbox_mailbox *mbox,
+                       struct mail_index_transaction *trans);
 
 struct mail_save_context *
 dbox_save_alloc(struct mailbox_transaction_context *_t);
index 62942fe77b56587c9015599182e4b44965c3e0c2..a6d1e05eb24df277576437b2a74d6cbe33cb9b6c 100644 (file)
@@ -348,25 +348,17 @@ static int dbox_sync_maildir_finish(struct dbox_sync_rebuild_context *ctx)
 
 static void dbox_sync_update_header(struct dbox_sync_rebuild_context *ctx)
 {
-       const struct dbox_index_header *hdr;
-       struct dbox_index_header new_hdr;
-       const void *data;
-       size_t data_size;
-
-       mail_index_get_header_ext(ctx->mbox->ibox.view,
-                                 ctx->mbox->dbox_hdr_ext_id,
-                                 &data, &data_size);
-       hdr = data;
-       if (data_size == sizeof(*hdr))
-               new_hdr = *hdr;
-       else
-               memset(&new_hdr, 0, sizeof(new_hdr));
-       if (new_hdr.highest_maildir_uid < ctx->mbox->highest_maildir_uid)
-               new_hdr.highest_maildir_uid = ctx->mbox->highest_maildir_uid;
-       new_hdr.map_uid_validity = !ctx->storage_rebuild ? 0 :
+       struct dbox_index_header hdr;
+
+       if (dbox_read_header(ctx->mbox, &hdr) < 0)
+               memset(&hdr, 0, sizeof(hdr));
+       dbox_set_mailbox_guid(&hdr);
+       if (hdr.highest_maildir_uid < ctx->mbox->highest_maildir_uid)
+               hdr.highest_maildir_uid = ctx->mbox->highest_maildir_uid;
+       hdr.map_uid_validity = !ctx->storage_rebuild ? 0 :
                dbox_map_get_uid_validity(ctx->mbox->storage->map);
        mail_index_update_header_ext(ctx->trans, ctx->mbox->dbox_hdr_ext_id, 0,
-                                    &new_hdr, sizeof(new_hdr));
+                                    &hdr, sizeof(hdr));
 }
 
 struct dbox_sync_rebuild_context *
index c9687eeaf55b77bb2e0fb151769e3135062ec701..343d026256f93b19b98d433f74a4a103307cb92a 100644 (file)
@@ -202,35 +202,20 @@ static int dbox_sync_index(struct dbox_sync_context *ctx)
 static int dbox_refresh_header(struct dbox_mailbox *mbox, bool retry)
 {
        struct mail_index_view *view;
-       const struct dbox_index_header *hdr;
-       const void *data;
-       size_t data_size;
+       struct dbox_index_header hdr;
        int ret;
 
        view = mail_index_view_open(mbox->ibox.index);
-       mail_index_get_header_ext(view, mbox->dbox_hdr_ext_id,
-                                 &data, &data_size);
-       if (data_size != sizeof(*hdr)) {
-               if (retry) {
-                       mail_index_view_close(&view);
-                       (void)mail_index_refresh(mbox->ibox.index);
-                       return dbox_refresh_header(mbox, FALSE);
-               }
-
-               /* data_size=0 means it's never been synced as dbox.
-                  data_size=4 is for backwards compatibility */
-               if (data_size != 0 && data_size != 4) {
-                       i_warning("dbox %s: Invalid dbox header size",
-                                 mbox->ibox.box.path);
-               }
-               ret = -1;
-       } else {
-               hdr = data;
+       ret = dbox_read_header(mbox, &hdr);
+       mail_index_view_close(&view);
 
-               mbox->highest_maildir_uid = hdr->highest_maildir_uid;
+       if (ret == 0) {
+               mbox->highest_maildir_uid = hdr.highest_maildir_uid;
                ret = mbox->storage->sync_rebuild ? -1 : 0;
+       } else if (retry) {
+               (void)mail_index_refresh(mbox->ibox.index);
+               return dbox_refresh_header(mbox, FALSE);
        }
-       mail_index_view_close(&view);
        return ret;
 }
 
index 230de5a7d46169d28c262b6e5d2da03f4d0cbdeb..6564b96705725efaa25ec03eda617050e60b7d56 100644 (file)
@@ -206,6 +206,7 @@ index_storage_alloc(struct mailbox_list *list, const char *name,
        } else {
                match->refcount++;
        }
+       i_assert(match->index != NULL);
        return match->index;
 }
 
index 60b3eb4a833e967f2d92e024128998277795f1d6..2da129f39d50707072a903f352779dd6d6c0a29a 100644 (file)
@@ -528,6 +528,19 @@ maildir_mailbox_create(struct mail_storage *storage, struct mailbox_list *list,
        return 0;
 }
 
+static void
+maildir_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
+                          struct mailbox_status *status_r)
+{
+       struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
+
+       index_storage_get_status(box, items, status_r);
+       if ((items & STATUS_GUID) != 0) {
+               (void)maildir_uidlist_get_mailbox_guid(mbox->uidlist,
+                                                      status_r->mailbox_guid);
+       }
+}
+
 static const char *
 maildir_get_unlink_dest(struct mailbox_list *list, const char *name)
 {
@@ -1029,7 +1042,7 @@ struct mailbox maildir_mailbox = {
                index_storage_mailbox_enable,
                maildir_mailbox_open,
                maildir_mailbox_close,
-               index_storage_get_status,
+               maildir_storage_get_status,
                maildir_list_index_has_changed,
                maildir_list_index_update_sync,
                maildir_storage_sync_init,
index 6085ab5172ed8e20b447ee7ce4ee3e0e1c6a86ae..9a5838f4a82c2ea725472b57b412295a58415516 100644 (file)
@@ -30,6 +30,7 @@
 #include "istream.h"
 #include "ostream.h"
 #include "str.h"
+#include "hex-binary.h"
 #include "file-dotlock.h"
 #include "close-keep-errno.h"
 #include "nfs-workarounds.h"
@@ -88,12 +89,15 @@ struct maildir_uidlist {
        uoff_t last_read_offset;
        string_t *hdr_extensions;
 
+       uint8_t mailbox_guid[MAILBOX_GUID_SIZE];
+
        unsigned int recreate:1;
        unsigned int initial_read:1;
        unsigned int initial_hdr_read:1;
        unsigned int retry_rewind:1;
        unsigned int locked_refresh:1;
        unsigned int unsorted:1;
+       unsigned int have_mailbox_guid:1;
 };
 
 struct maildir_uidlist_sync_ctx {
@@ -549,13 +553,63 @@ static bool maildir_uidlist_next(struct maildir_uidlist *uidlist,
        return TRUE;
 }
 
+static int
+maildir_uidlist_read_v3_header(struct maildir_uidlist *uidlist,
+                              const char *line,
+                              unsigned int *uid_validity_r,
+                              unsigned int *next_uid_r)
+{
+       buffer_t *buf;
+       char key;
+
+       str_truncate(uidlist->hdr_extensions, 0);
+       while (*line != '\0') {
+               const char *value;
+
+               key = *line;
+               value = ++line;
+               while (*line != '\0' && *line != ' ') line++;
+               value = t_strdup_until(value, line);
+
+               switch (key) {
+               case MAILDIR_UIDLIST_HDR_EXT_UID_VALIDITY:
+                       *uid_validity_r = strtoul(value, NULL, 10);
+                       break;
+               case MAILDIR_UIDLIST_HDR_EXT_NEXT_UID:
+                       *next_uid_r = strtoul(value, NULL, 10);
+                       break;
+               case MAILDIR_UIDLIST_HDR_EXT_GUID:
+                       buf = buffer_create_dynamic(pool_datastack_create(),
+                                                   MAILBOX_GUID_SIZE);
+                       if (hex_to_binary(value, buf) < 0 ||
+                           buf->used != MAILBOX_GUID_SIZE) {
+                               maildir_uidlist_set_corrupted(uidlist,
+                                       "Invalid mailbox GUID: %s", value);
+                               return -1;
+                       }
+                       memcpy(uidlist->mailbox_guid, buf->data,
+                              sizeof(uidlist->mailbox_guid));
+                       uidlist->have_mailbox_guid = TRUE;
+                       break;
+               default:
+                       if (str_len(uidlist->hdr_extensions) > 0)
+                               str_append_c(uidlist->hdr_extensions, ' ');
+                       str_printfa(uidlist->hdr_extensions,
+                                   "%c%s", key, value);
+                       break;
+               }
+
+               while (*line == ' ') line++;
+       }
+       return 0;
+}
+
 static int maildir_uidlist_read_header(struct maildir_uidlist *uidlist,
                                       struct istream *input)
 {
        unsigned int uid_validity, next_uid;
-       string_t *ext_hdr;
        const char *line;
-       char key;
+       int ret;
 
        line = i_stream_read_next_line(input);
         if (line == NULL) {
@@ -589,32 +643,13 @@ static int maildir_uidlist_read_header(struct maildir_uidlist *uidlist,
                }
                break;
        case UIDLIST_VERSION:
-               ext_hdr = uidlist->hdr_extensions;
-               str_truncate(ext_hdr, 0);
-               while (*line != '\0') T_BEGIN {
-                       const char *value;
-
-                       key = *line;
-                       value = ++line;
-                       while (*line != '\0' && *line != ' ') line++;
-                       value = t_strdup_until(value, line);
-
-                       switch (key) {
-                       case MAILDIR_UIDLIST_HDR_EXT_UID_VALIDITY:
-                               uid_validity = strtoul(value, NULL, 10);
-                               break;
-                       case MAILDIR_UIDLIST_HDR_EXT_NEXT_UID:
-                               next_uid = strtoul(value, NULL, 10);
-                               break;
-                       default:
-                               if (str_len(ext_hdr) > 0)
-                                       str_append_c(ext_hdr, ' ');
-                               str_printfa(ext_hdr, "%c%s", key, value);
-                               break;
-                       }
-
-                       while (*line == ' ') line++;
+               T_BEGIN {
+                       ret = maildir_uidlist_read_v3_header(uidlist, line,
+                                                            &uid_validity,
+                                                            &next_uid);
                } T_END;
+               if (ret < 0)
+                       return 0;
                break;
        default:
                maildir_uidlist_set_corrupted(uidlist, "Unsupported version %u",
@@ -880,6 +915,10 @@ int maildir_uidlist_refresh(struct maildir_uidlist *uidlist)
                uidlist->initial_hdr_read = TRUE;
                if (UIDLIST_IS_LOCKED(uidlist))
                        uidlist->locked_refresh = TRUE;
+               if (!uidlist->have_mailbox_guid) {
+                       uidlist->recreate = TRUE;
+                       (void)maildir_uidlist_update(uidlist);
+               }
        }
         return ret;
 }
@@ -1034,6 +1073,18 @@ uint32_t maildir_uidlist_get_next_uid(struct maildir_uidlist *uidlist)
        return !uidlist->initial_hdr_read ? 0 : uidlist->next_uid;
 }
 
+int maildir_uidlist_get_mailbox_guid(struct maildir_uidlist *uidlist,
+                                    uint8_t mailbox_guid[MAILBOX_GUID_SIZE])
+{
+       if (!uidlist->have_mailbox_guid) {
+               uidlist->recreate = TRUE;
+               if (maildir_uidlist_update(uidlist) < 0)
+                       return -1;
+       }
+       memcpy(mailbox_guid, uidlist->mailbox_guid, MAILBOX_GUID_SIZE);
+       return 0;
+}
+
 void maildir_uidlist_set_uid_validity(struct maildir_uidlist *uidlist,
                                      uint32_t uid_validity)
 {
@@ -1135,10 +1186,15 @@ static int maildir_uidlist_write_fd(struct maildir_uidlist *uidlist, int fd,
                i_assert(first_idx == 0);
                uidlist->version = UIDLIST_VERSION;
 
+               if (!uidlist->have_mailbox_guid)
+                       mail_generate_guid_128(uidlist->mailbox_guid);
+
                i_assert(uidlist->uid_validity != 0);
                i_assert(uidlist->next_uid > 0);
-               str_printfa(str, "%u V%u N%u", uidlist->version,
-                           uidlist->uid_validity, uidlist->next_uid);
+               str_printfa(str, "%u V%u N%u G%s", uidlist->version,
+                           uidlist->uid_validity, uidlist->next_uid,
+                           binary_to_hex(uidlist->mailbox_guid,
+                                         sizeof(uidlist->mailbox_guid)));
                if (str_len(uidlist->hdr_extensions) > 0) {
                        str_append_c(str, ' ');
                        str_append_str(str, uidlist->hdr_extensions);
@@ -1266,6 +1322,7 @@ static int maildir_uidlist_recreate(struct maildir_uidlist *uidlist)
                uidlist->fd_size = st.st_size;
                uidlist->last_read_offset = st.st_size;
                uidlist->recreate = FALSE;
+               uidlist->have_mailbox_guid = TRUE;
                maildir_uidlist_update_hdr(uidlist, &st);
        }
        if (ret < 0)
@@ -1311,7 +1368,8 @@ static bool maildir_uidlist_want_recreate(struct maildir_uidlist_sync_ctx *ctx)
 
        if (ctx->finish_change_counter != uidlist->change_counter)
                return TRUE;
-       if (uidlist->fd == -1 || uidlist->version != UIDLIST_VERSION)
+       if (uidlist->fd == -1 || uidlist->version != UIDLIST_VERSION ||
+           !uidlist->have_mailbox_guid)
                return TRUE;
        return maildir_uidlist_want_compress(ctx);
 }
index 5f318ae45bbb887d50c5fda7e4f94800ce002d3c..a4bf86446ab035ce8e282f106a150c68664ea854 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MAILDIR_UIDLIST_H
 #define MAILDIR_UIDLIST_H
 
+#include "mail-storage.h"
+
 #define MAILDIR_UIDLIST_NAME "dovecot-uidlist"
 /* how many seconds to wait before overriding uidlist.lock */
 #define MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT (60*2)
@@ -30,6 +32,7 @@ enum maildir_uidlist_rec_flag {
 enum maildir_uidlist_hdr_ext_key {
        MAILDIR_UIDLIST_HDR_EXT_UID_VALIDITY            = 'V',
        MAILDIR_UIDLIST_HDR_EXT_NEXT_UID                = 'N',
+       MAILDIR_UIDLIST_HDR_EXT_GUID                    = 'G',
        /* POP3 UIDL format unless overridden by records */
        MAILDIR_UIDLIST_HDR_EXT_POP3_UIDL_FORMAT        = 'P'
 };
@@ -79,6 +82,8 @@ maildir_uidlist_lookup_ext(struct maildir_uidlist *uidlist, uint32_t uid,
 
 uint32_t maildir_uidlist_get_uid_validity(struct maildir_uidlist *uidlist);
 uint32_t maildir_uidlist_get_next_uid(struct maildir_uidlist *uidlist);
+int maildir_uidlist_get_mailbox_guid(struct maildir_uidlist *uidlist,
+                                    uint8_t mailbox_guid[MAILBOX_GUID_SIZE]);
 
 void maildir_uidlist_set_uid_validity(struct maildir_uidlist *uidlist,
                                      uint32_t uid_validity);
index 3e5a0b741e419bd1af3bfaffa160230c8825a308..00f3c59e8bafafdefd918d416cc2cb55e8a1c33a 100644 (file)
@@ -590,6 +590,19 @@ static void mbox_mailbox_close(struct mailbox *box)
        index_storage_mailbox_close(box);
 }
 
+static void
+mbox_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
+                       struct mailbox_status *status_r)
+{
+       struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
+
+       index_storage_get_status(box, items, status_r);
+       if ((items & STATUS_GUID) != 0) {
+               memcpy(status_r->mailbox_guid, mbox->mbox_hdr.mailbox_guid,
+                      sizeof(status_r->mailbox_guid));
+       }
+}
+
 static void mbox_notify_changes(struct mailbox *box)
 {
        struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
@@ -845,7 +858,7 @@ struct mailbox mbox_mailbox = {
                index_storage_mailbox_enable,
                mbox_mailbox_open,
                mbox_mailbox_close,
-               index_storage_get_status,
+               mbox_storage_get_status,
                NULL,
                NULL,
                mbox_storage_sync_init,
index fd6cb1ab625750867a5a9518ccd199a615b06ab5..51b5de421b029fcc72f9a72c65eaafa29ff9f298 100644 (file)
@@ -20,6 +20,7 @@ struct mbox_index_header {
        uint32_t sync_mtime;
        uint8_t dirty_flag;
        uint8_t unused[3];
+       uint8_t mailbox_guid[MAILBOX_GUID_SIZE];
 };
 struct mbox_storage {
        struct mail_storage storage;
index 64dc6d3c942e2c7931a43fb60ad00b709baf6264..70bf80588f653a1aaddb19660c9537043edd01ce 100644 (file)
@@ -1332,6 +1332,17 @@ static int mbox_sync_handle_eof_updates(struct mbox_sync_context *sync_ctx,
        return 0;
 }
 
+static bool mbox_has_mailbox_guid(struct mbox_mailbox *mbox)
+{
+       unsigned int i;
+
+       for (i = 0; i < sizeof(mbox->mbox_hdr.mailbox_guid); i++) {
+               if (mbox->mbox_hdr.mailbox_guid[i] != 0)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
 static void
 mbox_sync_index_update_ext_header(struct mbox_sync_context *sync_ctx)
 {
@@ -1339,6 +1350,9 @@ mbox_sync_index_update_ext_header(struct mbox_sync_context *sync_ctx)
        const void *data;
        size_t data_size;
 
+       if (!mbox_has_mailbox_guid(mbox))
+               mail_generate_guid_128(mbox->mbox_hdr.mailbox_guid);
+
        mail_index_get_header_ext(mbox->ibox.view, mbox->mbox_ext_idx,
                                  &data, &data_size);
        if (data_size != sizeof(mbox->mbox_hdr) ||
@@ -1641,6 +1655,11 @@ int mbox_sync_has_changed_full(struct mbox_mailbox *mbox, bool leave_dirty,
        if (mbox_sync_header_refresh(mbox) < 0)
                return -1;
 
+       if (!mbox_has_mailbox_guid(mbox)) {
+               /* need to assign mailbox GUID */
+               return 1;
+       }
+
        if ((uint32_t)st->st_mtime == mbox->mbox_hdr.sync_mtime &&
            (uint64_t)st->st_size == mbox->mbox_hdr.sync_size) {
                /* fully synced */
index c16532fb6874e79ed0a4a0685e405e1798c50f8d..14c92961f0851d66a60c8ea29dd79542d8063a08 100644 (file)
@@ -59,7 +59,8 @@ enum mailbox_status_items {
        STATUS_UNSEEN           = 0x10,
        STATUS_FIRST_UNSEEN_SEQ = 0x20,
        STATUS_KEYWORDS         = 0x40,
-       STATUS_HIGHESTMODSEQ    = 0x80
+       STATUS_HIGHESTMODSEQ    = 0x80,
+       STATUS_GUID             = 0x100
 };
 
 enum mailbox_search_result_flags {
@@ -169,6 +170,7 @@ struct mail_save_context;
 struct mailbox;
 struct mailbox_transaction_context;
 
+#define MAILBOX_GUID_SIZE 16
 struct mailbox_status {
        uint32_t messages;
        uint32_t recent;
@@ -179,6 +181,7 @@ struct mailbox_status {
 
        uint32_t first_unseen_seq;
        uint64_t highest_modseq;
+       uint8_t mailbox_guid[MAILBOX_GUID_SIZE];
 
        const ARRAY_TYPE(keywords) *keywords;
 
index f9df97c0fcae3b821c9b808617dab3309e38034c..4ddedcb41b357e927c6236f1cffb6e04b4880da5 100644 (file)
@@ -24,10 +24,12 @@ struct mbox_index_header {
        uint32_t sync_mtime;
        uint8_t dirty_flag;
        uint8_t unused[3];
+       uint8_t mailbox_guid[16];
 };
 struct dbox_index_header {
        uint32_t map_uid_validity;
        uint32_t highest_maildir_uid;
+       uint8_t mailbox_guid[16];
 };
 struct dbox_mail_index_record {
        uint32_t map_uid;
@@ -116,16 +118,22 @@ static void dump_extension_header(struct mail_index *index,
                const struct mbox_index_header *hdr = data;
 
                printf("header\n");
-               printf(" - sync_mtime = %s\n", unixdate2str(hdr->sync_mtime));
-               printf(" - sync_size = %llu\n",
+               printf(" - sync_mtime = %s\n", unixdate2str(hdr->sync_mtime));
+               printf(" - sync_size .. = %llu\n",
                       (unsigned long long)hdr->sync_size);
-               printf(" - dirty_flag = %d\n", hdr->dirty_flag);
+               printf(" - dirty_flag . = %d\n", hdr->dirty_flag);
+               printf(" - mailbox_guid = %s\n",
+                      binary_to_hex(hdr->mailbox_guid,
+                                    sizeof(hdr->mailbox_guid)));
        } else if (strcmp(ext->name, "dbox-hdr") == 0) {
                const struct dbox_index_header *hdr = data;
 
                printf("header\n");
-               printf(" - map_uid_validity = %u\n", hdr->map_uid_validity);
+               printf(" - map_uid_validity .. = %u\n", hdr->map_uid_validity);
                printf(" - highest_maildir_uid = %u\n", hdr->highest_maildir_uid);
+               printf(" - mailbox_guid ...... = %s\n",
+                      binary_to_hex(hdr->mailbox_guid,
+                                    sizeof(hdr->mailbox_guid)));
        } else if (strcmp(ext->name, "modseq") == 0) {
                const struct mail_index_modseq_header *hdr = data;