From: Timo Sirainen Date: Mon, 15 Jun 2009 21:37:15 +0000 (-0400) Subject: Added support for mailbox GUIDs. X-Git-Tag: 2.0.alpha1~581 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c0bfb67ba32064347bac3241f1aac9b8a809e2f1;p=thirdparty%2Fdovecot%2Fcore.git Added support for mailbox GUIDs. --HG-- branch : HEAD --- diff --git a/src/lib-storage/index/dbox/dbox-mail.c b/src/lib-storage/index/dbox/dbox-mail.c index 6eff26e9b7..71d0b5beff 100644 --- a/src/lib-storage/index/dbox/dbox-mail.c +++ b/src/lib-storage/index/dbox/dbox-mail.c @@ -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; diff --git a/src/lib-storage/index/dbox/dbox-save.c b/src/lib-storage/index/dbox/dbox-save.c index 06d5052292..842414b479 100644 --- a/src/lib-storage/index/dbox/dbox-save.c +++ b/src/lib-storage/index/dbox/dbox-save.c @@ -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; diff --git a/src/lib-storage/index/dbox/dbox-storage.c b/src/lib-storage/index/dbox/dbox-storage.c index 8cddab087d..ef05b3329f 100644 --- a/src/lib-storage/index/dbox/dbox-storage.c +++ b/src/lib-storage/index/dbox/dbox-storage.c @@ -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, diff --git a/src/lib-storage/index/dbox/dbox-storage.h b/src/lib-storage/index/dbox/dbox-storage.h index ad6eb0f1cc..bfb27dd4f0 100644 --- a/src/lib-storage/index/dbox/dbox-storage.h +++ b/src/lib-storage/index/dbox/dbox-storage.h @@ -30,9 +30,11 @@ /* 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); diff --git a/src/lib-storage/index/dbox/dbox-sync-rebuild.c b/src/lib-storage/index/dbox/dbox-sync-rebuild.c index 62942fe77b..a6d1e05eb2 100644 --- a/src/lib-storage/index/dbox/dbox-sync-rebuild.c +++ b/src/lib-storage/index/dbox/dbox-sync-rebuild.c @@ -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 * diff --git a/src/lib-storage/index/dbox/dbox-sync.c b/src/lib-storage/index/dbox/dbox-sync.c index c9687eeaf5..343d026256 100644 --- a/src/lib-storage/index/dbox/dbox-sync.c +++ b/src/lib-storage/index/dbox/dbox-sync.c @@ -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; } diff --git a/src/lib-storage/index/index-storage.c b/src/lib-storage/index/index-storage.c index 230de5a7d4..6564b96705 100644 --- a/src/lib-storage/index/index-storage.c +++ b/src/lib-storage/index/index-storage.c @@ -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; } diff --git a/src/lib-storage/index/maildir/maildir-storage.c b/src/lib-storage/index/maildir/maildir-storage.c index 60b3eb4a83..2da129f39d 100644 --- a/src/lib-storage/index/maildir/maildir-storage.c +++ b/src/lib-storage/index/maildir/maildir-storage.c @@ -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, diff --git a/src/lib-storage/index/maildir/maildir-uidlist.c b/src/lib-storage/index/maildir/maildir-uidlist.c index 6085ab5172..9a5838f4a8 100644 --- a/src/lib-storage/index/maildir/maildir-uidlist.c +++ b/src/lib-storage/index/maildir/maildir-uidlist.c @@ -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); } diff --git a/src/lib-storage/index/maildir/maildir-uidlist.h b/src/lib-storage/index/maildir/maildir-uidlist.h index 5f318ae45b..a4bf86446a 100644 --- a/src/lib-storage/index/maildir/maildir-uidlist.h +++ b/src/lib-storage/index/maildir/maildir-uidlist.h @@ -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); diff --git a/src/lib-storage/index/mbox/mbox-storage.c b/src/lib-storage/index/mbox/mbox-storage.c index 3e5a0b741e..00f3c59e8b 100644 --- a/src/lib-storage/index/mbox/mbox-storage.c +++ b/src/lib-storage/index/mbox/mbox-storage.c @@ -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, diff --git a/src/lib-storage/index/mbox/mbox-storage.h b/src/lib-storage/index/mbox/mbox-storage.h index fd6cb1ab62..51b5de421b 100644 --- a/src/lib-storage/index/mbox/mbox-storage.h +++ b/src/lib-storage/index/mbox/mbox-storage.h @@ -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; diff --git a/src/lib-storage/index/mbox/mbox-sync.c b/src/lib-storage/index/mbox/mbox-sync.c index 64dc6d3c94..70bf80588f 100644 --- a/src/lib-storage/index/mbox/mbox-sync.c +++ b/src/lib-storage/index/mbox/mbox-sync.c @@ -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 */ diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index c16532fb68..14c92961f0 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -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; diff --git a/src/util/idxview.c b/src/util/idxview.c index f9df97c0fc..4ddedcb41b 100644 --- a/src/util/idxview.c +++ b/src/util/idxview.c @@ -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;