From 51327f2489a4e0e615eb9f7d921473cf8512bb79 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sat, 1 Jan 2011 15:52:39 +0200 Subject: [PATCH] lib-storage: Moved some items from mailbox_get_status() to a new mailbox_get_metadata(). The idea is now that all status items are tracked all the time after mailbox is opened and they can always be looked up without failure. The metadata items are looked up lazily and the lookups may fail at any time. mailbox_get_status() can be used after mailbox_alloc() to indicate that the mailbox doesn't necessarily have to be opened, just that the status fields get returned. If mailbox is already known to be open, mailbox_get_open_status() can be used. It never fails. --- src/doveadm/doveadm-mail-fetch.c | 7 +- src/doveadm/doveadm-mail-mailbox-status.c | 110 ++++++++------- src/doveadm/doveadm-mail-search.c | 8 +- src/doveadm/doveadm-mail.c | 26 ++-- src/doveadm/doveadm-mail.h | 2 + src/dsync/dsync-worker-local.c | 28 ++-- src/imap/cmd-enable.c | 14 +- src/imap/cmd-select.c | 21 ++- src/imap/cmd-store.c | 4 +- src/imap/imap-client.c | 29 ++-- src/imap/imap-client.h | 2 +- src/imap/imap-commands-util.c | 9 +- src/imap/imap-fetch.c | 6 +- src/imap/imap-search.c | 2 +- src/imap/imap-status.c | 61 ++++---- src/imap/imap-status.h | 7 +- src/imap/imap-sync.c | 7 +- .../index/dbox-multi/mdbox-storage.c | 22 ++- .../index/dbox-single/sdbox-storage.c | 13 +- src/lib-storage/index/index-search.c | 9 +- src/lib-storage/index/index-status.c | 130 ++++++++++-------- src/lib-storage/index/index-storage.c | 16 ++- src/lib-storage/index/index-storage.h | 3 + .../index/maildir/maildir-storage.c | 13 +- src/lib-storage/index/mbox/mbox-storage.c | 25 +++- .../list/index-mailbox-list-sync.c | 2 +- src/lib-storage/mail-storage-private.h | 4 +- src/lib-storage/mail-storage.c | 22 +-- src/lib-storage/mail-storage.h | 33 +++-- src/plugins/fts-solr/fts-backend-solr.c | 10 +- src/plugins/fts-squat/fts-backend-squat.c | 2 +- src/plugins/fts/fts-storage.c | 15 +- src/plugins/virtual/virtual-save.c | 2 +- src/plugins/virtual/virtual-storage.c | 18 ++- src/plugins/virtual/virtual-sync.c | 6 +- src/pop3/pop3-client.c | 2 +- 36 files changed, 401 insertions(+), 289 deletions(-) diff --git a/src/doveadm/doveadm-mail-fetch.c b/src/doveadm/doveadm-mail-fetch.c index 4cb61d6e93..fd8fe171a2 100644 --- a/src/doveadm/doveadm-mail-fetch.c +++ b/src/doveadm/doveadm-mail-fetch.c @@ -63,11 +63,12 @@ static int fetch_mailbox(struct fetch_cmd_context *ctx) static int fetch_mailbox_guid(struct fetch_cmd_context *ctx) { - uint8_t guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; - if (mailbox_get_guid(ctx->mail->box, guid) < 0) + if (mailbox_get_metadata(ctx->mail->box, MAILBOX_METADATA_GUID, + &metadata) < 0) return -1; - doveadm_print(mail_guid_128_to_string(guid)); + doveadm_print(mail_guid_128_to_string(metadata.guid)); return 0; } diff --git a/src/doveadm/doveadm-mail-mailbox-status.c b/src/doveadm/doveadm-mail-mailbox-status.c index 86587f250c..8a5fa6b045 100644 --- a/src/doveadm/doveadm-mail-mailbox-status.c +++ b/src/doveadm/doveadm-mail-mailbox-status.c @@ -12,18 +12,24 @@ #define ALL_STATUS_ITEMS \ (STATUS_MESSAGES | STATUS_RECENT | \ STATUS_UIDNEXT | STATUS_UIDVALIDITY | \ - STATUS_UNSEEN | STATUS_HIGHESTMODSEQ | STATUS_VIRTUAL_SIZE) + STATUS_UNSEEN | STATUS_HIGHESTMODSEQ) +#define ALL_METADATA_ITEMS \ + (MAILBOX_METADATA_VIRTUAL_SIZE | MAILBOX_METADATA_GUID) #define TOTAL_STATUS_ITEMS \ - (STATUS_MESSAGES | STATUS_RECENT | STATUS_UNSEEN | STATUS_VIRTUAL_SIZE) + (STATUS_MESSAGES | STATUS_RECENT | STATUS_UNSEEN) +#define TOTAL_METADATA_ITEMS \ + (MAILBOX_METADATA_VIRTUAL_SIZE) struct status_cmd_context { struct doveadm_mail_cmd_context ctx; struct mail_search_args *search_args; - enum mailbox_status_items items; + + enum mailbox_status_items status_items; + enum mailbox_metadata_items metadata_items; struct mailbox_status total_status; + struct mailbox_metadata total_metadata; - unsigned int guid:1; unsigned int total_sum:1; }; @@ -37,40 +43,42 @@ static void status_parse_fields(struct status_cmd_context *ctx, const char *field = *fields; if (strcmp(field, "all") == 0) { - if (ctx->total_sum) - ctx->items |= TOTAL_STATUS_ITEMS; - else { - ctx->items |= ALL_STATUS_ITEMS; - ctx->guid = TRUE; + if (ctx->total_sum) { + ctx->status_items |= TOTAL_STATUS_ITEMS; + ctx->metadata_items |= TOTAL_METADATA_ITEMS; + } else { + ctx->status_items |= ALL_STATUS_ITEMS; + ctx->metadata_items |= ALL_METADATA_ITEMS; } } else if (strcmp(field, "messages") == 0) - ctx->items |= STATUS_MESSAGES; + ctx->status_items |= STATUS_MESSAGES; else if (strcmp(field, "recent") == 0) - ctx->items |= STATUS_RECENT; + ctx->status_items |= STATUS_RECENT; else if (strcmp(field, "uidnext") == 0) - ctx->items |= STATUS_UIDNEXT; + ctx->status_items |= STATUS_UIDNEXT; else if (strcmp(field, "uidvalidity") == 0) - ctx->items |= STATUS_UIDVALIDITY; + ctx->status_items |= STATUS_UIDVALIDITY; else if (strcmp(field, "unseen") == 0) - ctx->items |= STATUS_UNSEEN; + ctx->status_items |= STATUS_UNSEEN; else if (strcmp(field, "highestmodseq") == 0) - ctx->items |= STATUS_HIGHESTMODSEQ; + ctx->status_items |= STATUS_HIGHESTMODSEQ; else if (strcmp(field, "vsize") == 0) - ctx->items |= STATUS_VIRTUAL_SIZE; + ctx->metadata_items |= MAILBOX_METADATA_VIRTUAL_SIZE; else if (strcmp(field, "guid") == 0) - ctx->guid = TRUE; + ctx->metadata_items |= MAILBOX_METADATA_GUID; else i_fatal("Unknown status field: %s", field); if (ctx->total_sum && - ((ctx->items & ~TOTAL_STATUS_ITEMS) != 0 || ctx->guid)) + ((ctx->status_items & ~TOTAL_STATUS_ITEMS) != 0 || + (ctx->metadata_items & ~TOTAL_METADATA_ITEMS) != 0)) i_fatal("Status field %s can't be used with -t", field); } } static void status_output(struct status_cmd_context *ctx, struct mailbox *box, const struct mailbox_status *status, - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]) + const struct mailbox_metadata *metadata) { string_t *name; @@ -83,34 +91,35 @@ static void status_output(struct status_cmd_context *ctx, struct mailbox *box, doveadm_print(str_c(name)); } - if ((ctx->items & STATUS_MESSAGES) != 0) + if ((ctx->status_items & STATUS_MESSAGES) != 0) doveadm_print_num(status->messages); - if ((ctx->items & STATUS_RECENT) != 0) + if ((ctx->status_items & STATUS_RECENT) != 0) doveadm_print_num(status->recent); - if ((ctx->items & STATUS_UIDNEXT) != 0) + if ((ctx->status_items & STATUS_UIDNEXT) != 0) doveadm_print_num(status->uidnext); - if ((ctx->items & STATUS_UIDVALIDITY) != 0) + if ((ctx->status_items & STATUS_UIDVALIDITY) != 0) doveadm_print_num(status->uidvalidity); - if ((ctx->items & STATUS_UNSEEN) != 0) + if ((ctx->status_items & STATUS_UNSEEN) != 0) doveadm_print_num(status->unseen); - if ((ctx->items & STATUS_HIGHESTMODSEQ) != 0) + if ((ctx->status_items & STATUS_HIGHESTMODSEQ) != 0) doveadm_print_num(status->highest_modseq); - if ((ctx->items & STATUS_VIRTUAL_SIZE) != 0) - doveadm_print_num(status->virtual_size); - if (ctx->guid) - doveadm_print(mail_guid_128_to_string(mailbox_guid)); + if ((ctx->metadata_items & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) + doveadm_print_num(metadata->virtual_size); + if ((ctx->metadata_items & MAILBOX_METADATA_GUID) != 0) + doveadm_print(mail_guid_128_to_string(metadata->guid)); } static void status_sum(struct status_cmd_context *ctx, - const struct mailbox_status *status) + const struct mailbox_status *status, + const struct mailbox_metadata *metadata) { struct mailbox_status *dest = &ctx->total_status; dest->messages += status->messages; dest->recent += status->recent; dest->unseen += status->unseen; - dest->virtual_size += status->virtual_size; + ctx->total_metadata.virtual_size += metadata->virtual_size; } static void @@ -118,7 +127,7 @@ status_mailbox(struct status_cmd_context *ctx, const struct mailbox_info *info) { struct mailbox *box; struct mailbox_status status; - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; string_t *mailbox_name = t_str_new(128); if (imap_utf7_to_utf8(info->name, mailbox_name) < 0) { @@ -126,20 +135,17 @@ status_mailbox(struct status_cmd_context *ctx, const struct mailbox_info *info) str_append(mailbox_name, info->name); } - if (doveadm_mailbox_find_and_sync(ctx->ctx.cur_mail_user, - str_c(mailbox_name), &box) < 0 || - mailbox_get_status(box, ctx->items, &status) < 0) { + box = doveadm_mailbox_find(ctx->ctx.cur_mail_user, str_c(mailbox_name)); + if (mailbox_get_status(box, ctx->status_items, &status) < 0 || + mailbox_get_metadata(box, ctx->metadata_items, &metadata) < 0) { ctx->ctx.failed = TRUE; + mailbox_free(&box); return; } - if (ctx->guid) { - if (mailbox_get_guid(box, mailbox_guid) < 0) - memset(mailbox_guid, 0, sizeof(mailbox_guid)); - } if (!ctx->total_sum) - status_output(ctx, box, &status, mailbox_guid); + status_output(ctx, box, &status, &metadata); else - status_sum(ctx, &status); + status_sum(ctx, &status, &metadata); mailbox_free(&box); } @@ -165,8 +171,10 @@ cmd_mailbox_status_run(struct doveadm_mail_cmd_context *_ctx, } doveadm_mail_list_iter_deinit(&iter); - if (ctx->total_sum) - status_output(ctx, NULL, &ctx->total_status, NULL); + if (ctx->total_sum) { + status_output(ctx, NULL, &ctx->total_status, + &ctx->total_metadata); + } } static void cmd_mailbox_status_init(struct doveadm_mail_cmd_context *_ctx, @@ -185,21 +193,21 @@ static void cmd_mailbox_status_init(struct doveadm_mail_cmd_context *_ctx, doveadm_print_header("mailbox", "mailbox", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); } - if ((ctx->items & STATUS_MESSAGES) != 0) + if ((ctx->status_items & STATUS_MESSAGES) != 0) doveadm_print_header_simple("messages"); - if ((ctx->items & STATUS_RECENT) != 0) + if ((ctx->status_items & STATUS_RECENT) != 0) doveadm_print_header_simple("recent"); - if ((ctx->items & STATUS_UIDNEXT) != 0) + if ((ctx->status_items & STATUS_UIDNEXT) != 0) doveadm_print_header_simple("uidnext"); - if ((ctx->items & STATUS_UIDVALIDITY) != 0) + if ((ctx->status_items & STATUS_UIDVALIDITY) != 0) doveadm_print_header_simple("uidvalidity"); - if ((ctx->items & STATUS_UNSEEN) != 0) + if ((ctx->status_items & STATUS_UNSEEN) != 0) doveadm_print_header_simple("unseen"); - if ((ctx->items & STATUS_HIGHESTMODSEQ) != 0) + if ((ctx->status_items & STATUS_HIGHESTMODSEQ) != 0) doveadm_print_header_simple("highestmodseq"); - if ((ctx->items & STATUS_VIRTUAL_SIZE) != 0) + if ((ctx->metadata_items & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) doveadm_print_header_simple("vsize"); - if (ctx->guid) + if ((ctx->metadata_items & MAILBOX_METADATA_GUID) != 0) doveadm_print_header_simple("guid"); } diff --git a/src/doveadm/doveadm-mail-search.c b/src/doveadm/doveadm-mail-search.c index c9709c089c..0c77439178 100644 --- a/src/doveadm/doveadm-mail-search.c +++ b/src/doveadm/doveadm-mail-search.c @@ -16,7 +16,7 @@ cmd_search_box(struct doveadm_mail_cmd_context *ctx, struct doveadm_mail_iter *iter; struct mailbox_transaction_context *trans; struct mail *mail; - uint8_t guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; const char *guid_str; int ret = 0; @@ -24,10 +24,12 @@ cmd_search_box(struct doveadm_mail_cmd_context *ctx, return -1; mail = mail_alloc(trans, 0, NULL); - if (mailbox_get_guid(mail->box, guid) < 0) + + if (mailbox_get_metadata(mail->box, MAILBOX_METADATA_GUID, + &metadata) < 0) ret = -1; else { - guid_str = mail_guid_128_to_string(guid); + guid_str = mail_guid_128_to_string(metadata.guid); while (doveadm_mail_iter_next(iter, mail)) { doveadm_print(guid_str); T_BEGIN { diff --git a/src/doveadm/doveadm-mail.c b/src/doveadm/doveadm-mail.c index 3d51c50faf..53a6d442b7 100644 --- a/src/doveadm/doveadm-mail.c +++ b/src/doveadm/doveadm-mail.c @@ -71,13 +71,11 @@ static struct doveadm_mail_cmd_context *cmd_purge_alloc(void) return ctx; } -static int mailbox_find_and_open(struct mail_user *user, const char *mailbox, - struct mailbox **box_r) +struct mailbox * +doveadm_mailbox_find(struct mail_user *user, const char *mailbox) { struct mail_namespace *ns; - struct mailbox *box; string_t *str; - const char *orig_mailbox = mailbox; str = t_str_new(128); if (imap_utf8_to_utf7(mailbox, str) < 0) @@ -88,10 +86,19 @@ static int mailbox_find_and_open(struct mail_user *user, const char *mailbox, if (ns == NULL) i_fatal("Can't find namespace for mailbox %s", mailbox); - box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_KEEP_RECENT | - MAILBOX_FLAG_IGNORE_ACLS); + return mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_KEEP_RECENT | + MAILBOX_FLAG_IGNORE_ACLS); +} + +static int +doveadm_mailbox_find_and_open(struct mail_user *user, const char *mailbox, + struct mailbox **box_r) +{ + struct mailbox *box; + + box = doveadm_mailbox_find(user, mailbox); if (mailbox_open(box) < 0) { - i_error("Opening mailbox %s failed: %s", orig_mailbox, + i_error("Opening mailbox %s failed: %s", mailbox, mail_storage_get_last_error(mailbox_get_storage(box), NULL)); mailbox_free(&box); @@ -104,12 +111,13 @@ static int mailbox_find_and_open(struct mail_user *user, const char *mailbox, int doveadm_mailbox_find_and_sync(struct mail_user *user, const char *mailbox, struct mailbox **box_r) { - if (mailbox_find_and_open(user, mailbox, box_r) < 0) + if (doveadm_mailbox_find_and_open(user, mailbox, box_r) < 0) return -1; if (mailbox_sync(*box_r, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { i_error("Syncing mailbox %s failed: %s", mailbox, mail_storage_get_last_error(mailbox_get_storage(*box_r), NULL)); + mailbox_free(box_r); return -1; } return 0; @@ -143,7 +151,7 @@ static void cmd_force_resync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_storage *storage; struct mailbox *box; - if (mailbox_find_and_open(user, ctx->mailbox, &box) < 0) { + if (doveadm_mailbox_find_and_open(user, ctx->mailbox, &box) < 0) { _ctx->failed = TRUE; return; } diff --git a/src/doveadm/doveadm-mail.h b/src/doveadm/doveadm-mail.h index df113f41af..4a8d4a1a1c 100644 --- a/src/doveadm/doveadm-mail.h +++ b/src/doveadm/doveadm-mail.h @@ -89,6 +89,8 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx, const char **error_r); void doveadm_mail_server_flush(void); +struct mailbox * +doveadm_mailbox_find(struct mail_user *user, const char *mailbox); int doveadm_mailbox_find_and_sync(struct mail_user *user, const char *mailbox, struct mailbox **box_r); struct mail_search_args * diff --git a/src/dsync/dsync-worker-local.c b/src/dsync/dsync-worker-local.c index b01f47a4ff..a434156e48 100644 --- a/src/dsync/dsync-worker-local.c +++ b/src/dsync/dsync-worker-local.c @@ -514,12 +514,14 @@ local_worker_mailbox_iter_next(struct dsync_worker_mailbox_iter *_iter, MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT; const enum mailbox_status_items status_items = STATUS_UIDNEXT | STATUS_UIDVALIDITY | - STATUS_HIGHESTMODSEQ | STATUS_CACHE_FIELDS; + STATUS_HIGHESTMODSEQ; + const enum mailbox_metadata_items metadata_items = + MAILBOX_METADATA_CACHE_FIELDS | MAILBOX_METADATA_GUID; const struct mailbox_info *info; const char *storage_name; struct mailbox *box; struct mailbox_status status; - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; struct local_dsync_mailbox_change *change; struct local_dsync_dir_change *dir_change, change_lookup; struct local_dsync_mailbox *old_lbox; @@ -557,9 +559,8 @@ local_worker_mailbox_iter_next(struct dsync_worker_mailbox_iter *_iter, } box = mailbox_alloc(info->ns->list, storage_name, flags); - if (mailbox_sync(box, 0) < 0 || - mailbox_get_status(box, status_items, &status) < 0 || - mailbox_get_guid(box, mailbox_guid) < 0) { + if (mailbox_get_status(box, status_items, &status) < 0 || + mailbox_get_metadata(box, metadata_items, &metadata) < 0) { struct mail_storage *storage = mailbox_get_storage(box); i_error("Failed to sync mailbox %s: %s", info->name, @@ -569,13 +570,13 @@ local_worker_mailbox_iter_next(struct dsync_worker_mailbox_iter *_iter, return -1; } - change = hash_table_lookup(worker->mailbox_changes_hash, mailbox_guid); + change = hash_table_lookup(worker->mailbox_changes_hash, metadata.guid); if (change != NULL) { /* it shouldn't be marked as deleted, but drop it to be sure */ change->deleted_mailbox = FALSE; } - memcpy(dsync_box_r->mailbox_guid.guid, mailbox_guid, + memcpy(dsync_box_r->mailbox_guid.guid, metadata.guid, sizeof(dsync_box_r->mailbox_guid.guid)); dsync_box_r->uid_validity = status.uidvalidity; dsync_box_r->uid_next = status.uidnext; @@ -583,7 +584,7 @@ local_worker_mailbox_iter_next(struct dsync_worker_mailbox_iter *_iter, dsync_box_r->highest_modseq = status.highest_modseq; p_clear(iter->ret_pool); - fields = array_get(status.cache_fields, &field_count); + fields = array_get(metadata.cache_fields, &field_count); p_array_init(&dsync_box_r->cache_fields, iter->ret_pool, field_count); for (i = 0; i < field_count; i++) { const char *field_name = p_strdup(iter->ret_pool, fields[i]); @@ -788,7 +789,7 @@ static int local_mailbox_open(struct local_dsync_worker *worker, enum mailbox_flags flags = MAILBOX_FLAG_KEEP_RECENT; struct local_dsync_mailbox *lbox; struct mailbox *box; - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; lbox = hash_table_lookup(worker->mailbox_hash, guid); if (lbox == NULL) { @@ -799,7 +800,7 @@ static int local_mailbox_open(struct local_dsync_worker *worker, box = mailbox_alloc(lbox->ns->list, lbox->storage_name, flags); if (mailbox_sync(box, 0) < 0 || - mailbox_get_guid(box, mailbox_guid) < 0) { + mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) { struct mail_storage *storage = mailbox_get_storage(box); i_error("Failed to sync mailbox %s: %s", lbox->storage_name, @@ -808,10 +809,10 @@ static int local_mailbox_open(struct local_dsync_worker *worker, return -1; } - if (memcmp(mailbox_guid, guid->guid, sizeof(guid->guid)) != 0) { + if (memcmp(metadata.guid, guid->guid, sizeof(guid->guid)) != 0) { i_error("Mailbox %s changed its GUID (%s -> %s)", lbox->storage_name, dsync_guid_to_str(guid), - mail_guid_128_to_string(mailbox_guid)); + mail_guid_128_to_string(metadata.guid)); mailbox_free(&box); return -1; } @@ -936,8 +937,7 @@ iter_local_mailbox_next_expunge(struct local_dsync_worker_msg_iter *iter, array_clear(&iter->expunges); iter->expunges_set = TRUE; - if (mailbox_get_status(box, STATUS_UIDNEXT, &status) < 0) - i_unreached(); + mailbox_get_open_status(box, STATUS_UIDNEXT, &status); if (prev_uid + 1 >= status.uidnext) { /* no expunged messages at the end of mailbox */ return FALSE; diff --git a/src/imap/cmd-enable.c b/src/imap/cmd-enable.c index 778a6e96ce..dbe57bed50 100644 --- a/src/imap/cmd-enable.c +++ b/src/imap/cmd-enable.c @@ -21,13 +21,13 @@ bool cmd_enable(struct client_command_context *cmd) } str = t_str_ucase(str); if (strcmp(str, "CONDSTORE") == 0) { - client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE); - str_append(reply, " CONDSTORE"); - } - else if (strcmp(str, "QRESYNC") == 0) { - client_enable(cmd->client, MAILBOX_FEATURE_QRESYNC | - MAILBOX_FEATURE_CONDSTORE); - str_append(reply, " QRESYNC"); + if (client_enable(cmd->client, + MAILBOX_FEATURE_CONDSTORE) == 0) + str_append(reply, " CONDSTORE"); + } else if (strcmp(str, "QRESYNC") == 0) { + if (client_enable(cmd->client, MAILBOX_FEATURE_QRESYNC | + MAILBOX_FEATURE_CONDSTORE) == 0) + str_append(reply, " QRESYNC"); } } if (str_len(reply) > 9) diff --git a/src/imap/cmd-select.c b/src/imap/cmd-select.c index e588647a52..6294b21938 100644 --- a/src/imap/cmd-select.c +++ b/src/imap/cmd-select.c @@ -276,7 +276,7 @@ select_open(struct imap_select_context *ctx, const char *mailbox, bool readonly) struct client *client = ctx->cmd->client; struct mailbox_status status; enum mailbox_flags flags = 0; - int ret; + int ret = 0; if (readonly) flags |= MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT; @@ -289,20 +289,17 @@ select_open(struct imap_select_context *ctx, const char *mailbox, bool readonly) } if (client->enabled_features != 0) - mailbox_enable(ctx->box, client->enabled_features); - if (mailbox_sync(ctx->box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { - client_send_storage_error(ctx->cmd, - mailbox_get_storage(ctx->box)); - return -1; - } - if (mailbox_get_status(ctx->box, STATUS_MESSAGES | STATUS_RECENT | - STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY | - STATUS_UIDNEXT | STATUS_KEYWORDS | - STATUS_HIGHESTMODSEQ, &status) < 0) { + ret = mailbox_enable(ctx->box, client->enabled_features); + if (ret < 0 || + mailbox_sync(ctx->box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { client_send_storage_error(ctx->cmd, mailbox_get_storage(ctx->box)); return -1; } + mailbox_get_open_status(ctx->box, STATUS_MESSAGES | STATUS_RECENT | + STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY | + STATUS_UIDNEXT | STATUS_KEYWORDS | + STATUS_HIGHESTMODSEQ, &status); client->mailbox = ctx->box; client->select_counter++; @@ -413,7 +410,7 @@ bool cmd_select_full(struct client_command_context *cmd, bool readonly) if (ctx->condstore) { /* Enable while no mailbox is opened to avoid sending HIGHESTMODSEQ for previously opened mailbox */ - client_enable(client, MAILBOX_FEATURE_CONDSTORE); + (void)client_enable(client, MAILBOX_FEATURE_CONDSTORE); } ret = select_open(ctx, storage_name, readonly); diff --git a/src/imap/cmd-store.c b/src/imap/cmd-store.c index ff53ac400a..1bab792bda 100644 --- a/src/imap/cmd-store.c +++ b/src/imap/cmd-store.c @@ -62,8 +62,8 @@ store_parse_modifiers(struct imap_store_context *ctx, "Invalid modseq"); return FALSE; } - client_enable(ctx->cmd->client, - MAILBOX_FEATURE_CONDSTORE); + (void)client_enable(ctx->cmd->client, + MAILBOX_FEATURE_CONDSTORE); } else { client_send_command_error(ctx->cmd, "Unknown STORE modifier"); diff --git a/src/imap/imap-client.c b/src/imap/imap-client.c index 954b502675..5b32ad2367 100644 --- a/src/imap/imap-client.c +++ b/src/imap/imap-client.c @@ -911,28 +911,35 @@ bool client_handle_search_save_ambiguity(struct client_command_context *cmd) return TRUE; } -void client_enable(struct client *client, enum mailbox_feature features) +int client_enable(struct client *client, enum mailbox_feature features) { struct mailbox_status status; + int ret; if ((client->enabled_features & features) == features) - return; + return 0; client->enabled_features |= features; if (client->mailbox == NULL) - return; + return 0; - mailbox_enable(client->mailbox, features); - if ((features & MAILBOX_FEATURE_CONDSTORE) != 0) { + ret = mailbox_enable(client->mailbox, features); + if ((features & MAILBOX_FEATURE_CONDSTORE) != 0 && ret == 0) { /* CONDSTORE being enabled while mailbox is selected. Notify client of the latest HIGHESTMODSEQ. */ - if (mailbox_get_status(client->mailbox, - STATUS_HIGHESTMODSEQ, &status) < 0) - i_unreached(); - client_send_line(client, t_strdup_printf( - "* OK [HIGHESTMODSEQ %llu] Highest", - (unsigned long long)status.highest_modseq)); + ret = mailbox_get_status(client->mailbox, + STATUS_HIGHESTMODSEQ, &status); + if (ret == 0) { + client_send_line(client, t_strdup_printf( + "* OK [HIGHESTMODSEQ %llu] Highest", + (unsigned long long)status.highest_modseq)); + } + } + if (ret < 0) { + client_send_untagged_storage_error(client, + mailbox_get_storage(client->mailbox)); } + return ret; } struct imap_search_update * diff --git a/src/imap/imap-client.h b/src/imap/imap-client.h index 57fc747055..e6b44cc65d 100644 --- a/src/imap/imap-client.h +++ b/src/imap/imap-client.h @@ -192,7 +192,7 @@ bool client_read_string_args(struct client_command_context *cmd, have to wait for an existing SEARCH SAVE to finish. */ bool client_handle_search_save_ambiguity(struct client_command_context *cmd); -void client_enable(struct client *client, enum mailbox_feature features); +int client_enable(struct client *client, enum mailbox_feature features); struct imap_search_update * client_search_update_lookup(struct client *client, const char *tag, diff --git a/src/imap/imap-commands-util.c b/src/imap/imap-commands-util.c index 658ab66517..fd148e937e 100644 --- a/src/imap/imap-commands-util.c +++ b/src/imap/imap-commands-util.c @@ -102,8 +102,13 @@ int client_open_save_dest_box(struct client_command_context *cmd, mailbox_free(&box); return -1; } - if (cmd->client->enabled_features != 0) - mailbox_enable(box, cmd->client->enabled_features); + if (cmd->client->enabled_features != 0) { + if (mailbox_enable(box, cmd->client->enabled_features) < 0) { + client_send_storage_error(cmd, mailbox_get_storage(box)); + mailbox_free(&box); + return -1; + } + } *destbox_r = box; return 0; } diff --git a/src/imap/imap-fetch.c b/src/imap/imap-fetch.c index f20cd49a94..ded6969c5a 100644 --- a/src/imap/imap-fetch.c +++ b/src/imap/imap-fetch.c @@ -159,7 +159,7 @@ expunges_drop_known(struct imap_fetch_context *ctx, struct mail *mail, i_assert(array_count(ctx->qresync_sample_uidset) == count); i_assert(count > 0); - mailbox_get_status(ctx->box, STATUS_MESSAGES, &status); + mailbox_get_open_status(ctx->box, STATUS_MESSAGES, &status); /* FIXME: we could do removals from the middle as well */ for (i = 0; i < count && seqs[i] <= status.messages; i++) { @@ -245,7 +245,7 @@ static int get_expunges_fallback(struct imap_fetch_context *ctx, uid_filter[i].seq2); } - mailbox_get_status(ctx->box, STATUS_UIDNEXT, &status); + mailbox_get_open_status(ctx->box, STATUS_UIDNEXT, &status); seq_range_array_remove_range(expunged_uids, status.uidnext, (uint32_t)-1); @@ -751,7 +751,7 @@ static bool fetch_modseq_init(struct imap_fetch_context *ctx, const char *name, const struct imap_arg **args ATTR_UNUSED) { - client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE); + (void)client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE); imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL, fetch_modseq, NULL); return TRUE; diff --git a/src/imap/imap-search.c b/src/imap/imap-search.c index 6c6b842fe5..5f96e19f39 100644 --- a/src/imap/imap-search.c +++ b/src/imap/imap-search.c @@ -527,7 +527,7 @@ bool imap_search_start(struct imap_search_context *ctx, if (ctx->have_modseqs) { ctx->return_options |= SEARCH_RETURN_MODSEQ; - client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE); + (void)client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE); } ctx->box = cmd->client->mailbox; diff --git a/src/imap/imap-status.c b/src/imap/imap-status.c index b0c63bdb63..6f30372e70 100644 --- a/src/imap/imap-status.c +++ b/src/imap/imap-status.c @@ -11,7 +11,8 @@ int imap_status_parse_items(struct client_command_context *cmd, struct imap_status_items *items_r) { const char *item; - enum mailbox_status_items items; + enum mailbox_status_items status = 0; + enum mailbox_metadata_items metadata = 0; if (IMAP_ARG_IS_EOL(args)) { client_send_command_error(cmd, "Empty status list."); @@ -19,7 +20,6 @@ int imap_status_parse_items(struct client_command_context *cmd, } memset(items_r, 0, sizeof(*items_r)); - items = 0; for (; !IMAP_ARG_IS_EOL(args); args++) { if (!imap_arg_get_atom(args, &item)) { /* list may contain only atoms */ @@ -30,21 +30,21 @@ int imap_status_parse_items(struct client_command_context *cmd, item = t_str_ucase(item); if (strcmp(item, "MESSAGES") == 0) - items |= STATUS_MESSAGES; + status |= STATUS_MESSAGES; else if (strcmp(item, "RECENT") == 0) - items |= STATUS_RECENT; + status |= STATUS_RECENT; else if (strcmp(item, "UIDNEXT") == 0) - items |= STATUS_UIDNEXT; + status |= STATUS_UIDNEXT; else if (strcmp(item, "UIDVALIDITY") == 0) - items |= STATUS_UIDVALIDITY; + status |= STATUS_UIDVALIDITY; else if (strcmp(item, "UNSEEN") == 0) - items |= STATUS_UNSEEN; + status |= STATUS_UNSEEN; else if (strcmp(item, "HIGHESTMODSEQ") == 0) - items |= STATUS_HIGHESTMODSEQ; + status |= STATUS_HIGHESTMODSEQ; else if (strcmp(item, "X-SIZE") == 0) - items |= STATUS_VIRTUAL_SIZE; + metadata |= MAILBOX_METADATA_VIRTUAL_SIZE; else if (strcmp(item, "X-GUID") == 0) - items_r->guid = TRUE; + metadata |= MAILBOX_METADATA_GUID; else { client_send_tagline(cmd, t_strconcat( "BAD Invalid status item ", item, NULL)); @@ -52,7 +52,8 @@ int imap_status_parse_items(struct client_command_context *cmd, } } - items_r->mailbox_items = items; + items_r->status = status; + items_r->metadata = metadata; return 0; } @@ -75,16 +76,20 @@ int imap_status_get(struct client_command_context *cmd, box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT); - if (client->enabled_features != 0) - mailbox_enable(box, client->enabled_features); + if (client->enabled_features != 0) { + if (mailbox_enable(box, client->enabled_features) < 0) + ret = -1; + } } - if ((items->mailbox_items & STATUS_HIGHESTMODSEQ) != 0) - client_enable(client, MAILBOX_FEATURE_CONDSTORE); + if ((items->status & STATUS_HIGHESTMODSEQ) != 0) + (void)client_enable(client, MAILBOX_FEATURE_CONDSTORE); - ret = mailbox_get_status(box, items->mailbox_items, &result_r->status); - if (items->guid && ret == 0) - ret = mailbox_get_guid(box, result_r->mailbox_guid); + ret = mailbox_get_status(box, items->status, &result_r->status); + if (items->metadata != 0 && ret == 0) { + ret = mailbox_get_metadata(box, items->metadata, + &result_r->metadata); + } if (ret < 0) { struct mail_storage *storage = mailbox_get_storage(box); @@ -111,27 +116,27 @@ void imap_status_send(struct client *client, const char *mailbox, str_append(str, " ("); prefix_len = str_len(str); - if ((items->mailbox_items & STATUS_MESSAGES) != 0) + if ((items->status & STATUS_MESSAGES) != 0) str_printfa(str, "MESSAGES %u ", status->messages); - if ((items->mailbox_items & STATUS_RECENT) != 0) + if ((items->status & STATUS_RECENT) != 0) str_printfa(str, "RECENT %u ", status->recent); - if ((items->mailbox_items & STATUS_UIDNEXT) != 0) + if ((items->status & STATUS_UIDNEXT) != 0) str_printfa(str, "UIDNEXT %u ", status->uidnext); - if ((items->mailbox_items & STATUS_UIDVALIDITY) != 0) + if ((items->status & STATUS_UIDVALIDITY) != 0) str_printfa(str, "UIDVALIDITY %u ", status->uidvalidity); - if ((items->mailbox_items & STATUS_UNSEEN) != 0) + if ((items->status & STATUS_UNSEEN) != 0) str_printfa(str, "UNSEEN %u ", status->unseen); - if ((items->mailbox_items & STATUS_HIGHESTMODSEQ) != 0) { + if ((items->status & STATUS_HIGHESTMODSEQ) != 0) { str_printfa(str, "HIGHESTMODSEQ %llu ", (unsigned long long)status->highest_modseq); } - if ((items->mailbox_items & STATUS_VIRTUAL_SIZE) != 0) { + if ((items->metadata & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) { str_printfa(str, "X-SIZE %llu ", - (unsigned long long)status->virtual_size); + (unsigned long long)result->metadata.virtual_size); } - if (items->guid) { + if ((items->metadata & MAILBOX_METADATA_GUID) != 0) { str_printfa(str, "X-GUID %s ", - mail_guid_128_to_string(result->mailbox_guid)); + mail_guid_128_to_string(result->metadata.guid)); } if (str_len(str) != prefix_len) diff --git a/src/imap/imap-status.h b/src/imap/imap-status.h index 23a98b95af..3e038a79c4 100644 --- a/src/imap/imap-status.h +++ b/src/imap/imap-status.h @@ -2,14 +2,13 @@ #define IMAP_STATUS_H struct imap_status_items { - enum mailbox_status_items mailbox_items; - - unsigned int guid:1; + enum mailbox_status_items status; + enum mailbox_metadata_items metadata; }; struct imap_status_result { struct mailbox_status status; - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; }; int imap_status_parse_items(struct client_command_context *cmd, diff --git a/src/imap/imap-sync.c b/src/imap/imap-sync.c index 17a9091633..1c93ee4cc0 100644 --- a/src/imap/imap-sync.c +++ b/src/imap/imap-sync.c @@ -210,9 +210,6 @@ imap_sync_send_highestmodseq(struct imap_sync_context *ctx, int imap_sync_deinit(struct imap_sync_context *ctx, struct client_command_context *sync_cmd) { - const enum mailbox_status_items status_items = - STATUS_UIDVALIDITY | STATUS_MESSAGES | STATUS_RECENT | - STATUS_HIGHESTMODSEQ; struct client *client = ctx->client; struct mailbox_status status; struct mailbox_sync_status sync_status; @@ -223,13 +220,15 @@ int imap_sync_deinit(struct imap_sync_context *ctx, array_free(&ctx->expunges); if (mailbox_sync_deinit(&ctx->sync_ctx, &sync_status) < 0 || - mailbox_get_status(ctx->box, status_items, &status) < 0 || ctx->failed) { mailbox_transaction_rollback(&ctx->t); array_free(&ctx->tmp_keywords); i_free(ctx); return -1; } + mailbox_get_open_status(ctx->box, STATUS_UIDVALIDITY | + STATUS_MESSAGES | STATUS_RECENT | + STATUS_HIGHESTMODSEQ, &status); ret = mailbox_transaction_commit(&ctx->t); diff --git a/src/lib-storage/index/dbox-multi/mdbox-storage.c b/src/lib-storage/index/dbox-multi/mdbox-storage.c index 577b9b4534..1fc990da44 100644 --- a/src/lib-storage/index/dbox-multi/mdbox-storage.c +++ b/src/lib-storage/index/dbox-multi/mdbox-storage.c @@ -300,9 +300,9 @@ static void mdbox_set_file_corrupted(struct dbox_file *file) } static int -mdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +mdbox_mailbox_get_guid(struct mdbox_mailbox *mbox, + uint8_t guid[MAIL_GUID_128_SIZE]) { - struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)box; struct mdbox_index_header hdr; if (mdbox_read_header(mbox, &hdr) < 0) @@ -310,7 +310,7 @@ mdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) if (mail_guid_128_is_empty(hdr.mailbox_guid)) { /* regenerate it */ - if (mdbox_write_index_header(box, NULL, NULL) < 0 || + if (mdbox_write_index_header(&mbox->box, NULL, NULL) < 0 || mdbox_read_header(mbox, &hdr) < 0) return -1; } @@ -318,6 +318,20 @@ mdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) return 0; } +static int +mdbox_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) +{ + struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)box; + + if ((items & MAILBOX_METADATA_GUID) != 0) { + if (mdbox_mailbox_get_guid(mbox, metadata_r->guid) < 0) + return -1; + } + return index_mailbox_get_metadata(box, items, metadata_r); +} + static int mdbox_mailbox_update(struct mailbox *box, const struct mailbox_update *update) { @@ -403,7 +417,7 @@ struct mailbox mdbox_mailbox = { mdbox_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - mdbox_mailbox_get_guid, + mdbox_mailbox_get_metadata, NULL, NULL, mdbox_storage_sync_init, diff --git a/src/lib-storage/index/dbox-single/sdbox-storage.c b/src/lib-storage/index/dbox-single/sdbox-storage.c index aaf0fdff7b..1389522c3b 100644 --- a/src/lib-storage/index/dbox-single/sdbox-storage.c +++ b/src/lib-storage/index/dbox-single/sdbox-storage.c @@ -303,12 +303,17 @@ static int sdbox_mailbox_delete(struct mailbox *box) } static int -sdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +sdbox_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box; - memcpy(guid, mbox->mailbox_guid, MAIL_GUID_128_SIZE); - return 0; + if ((items & MAILBOX_METADATA_GUID) != 0) { + memcpy(metadata_r->guid, mbox->mailbox_guid, + MAIL_GUID_128_SIZE); + } + return index_mailbox_get_metadata(box, items, metadata_r); } static int @@ -370,7 +375,7 @@ struct mailbox sdbox_mailbox = { sdbox_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - sdbox_mailbox_get_guid, + sdbox_mailbox_get_metadata, NULL, NULL, sdbox_storage_sync_init, diff --git a/src/lib-storage/index/index-search.c b/src/lib-storage/index/index-search.c index 33b11735c3..f823b2fccf 100644 --- a/src/lib-storage/index/index-search.c +++ b/src/lib-storage/index/index-search.c @@ -88,7 +88,7 @@ static void search_parse_msgset_args(unsigned int messages_count, static void search_init_arg(struct mail_search_arg *arg, struct index_search_context *ctx) { - uint8_t guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; bool match; switch (arg->type) { @@ -105,12 +105,13 @@ static void search_init_arg(struct mail_search_arg *arg, ctx->have_index_args = TRUE; break; case SEARCH_MAILBOX_GUID: - if (mailbox_get_guid(ctx->box, guid) < 0) { + if (mailbox_get_metadata(ctx->box, MAILBOX_METADATA_GUID, + &metadata) < 0) { /* result will be unknown */ break; } - match = strcmp(mail_guid_128_to_string(guid), + match = strcmp(mail_guid_128_to_string(metadata.guid), arg->value.str) == 0; if (match != arg->not) arg->match_always = TRUE; @@ -1079,7 +1080,7 @@ index_storage_search_init(struct mailbox_transaction_context *t, if (gettimeofday(&ctx->last_nonblock_timeval, NULL) < 0) i_fatal("gettimeofday() failed: %m"); - mailbox_get_status(t->box, STATUS_MESSAGES, &status); + mailbox_get_open_status(t->box, STATUS_MESSAGES, &status); ctx->mail_ctx.progress_max = status.messages; i_array_init(&ctx->mail_ctx.results, 5); diff --git a/src/lib-storage/index/index-status.c b/src/lib-storage/index/index-status.c index ac219a5f5e..1e5aabd99e 100644 --- a/src/lib-storage/index/index-status.c +++ b/src/lib-storage/index/index-status.c @@ -7,9 +7,54 @@ #include "index-storage.h" #include "mail-index-modseq.h" +int index_storage_get_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r) +{ + const struct mail_index_header *hdr; + + memset(status_r, 0, sizeof(struct mailbox_status)); + + if (!box->opened) { + if (mailbox_open(box) < 0) + return -1; + if (mailbox_sync(box, 0) < 0) + return -1; + } + + /* we can get most of the status items without any trouble */ + hdr = mail_index_get_header(box->view); + status_r->messages = hdr->messages_count; + if ((items & STATUS_RECENT) != 0) { + status_r->recent = index_mailbox_get_recent_count(box); + i_assert(status_r->recent <= status_r->messages); + } + status_r->unseen = hdr->messages_count - hdr->seen_messages_count; + status_r->uidvalidity = hdr->uid_validity; + status_r->uidnext = hdr->next_uid; + status_r->nonpermanent_modseqs = mail_index_is_in_memory(box->index); + if ((items & STATUS_HIGHESTMODSEQ) != 0) { + status_r->highest_modseq = + mail_index_modseq_get_highest(box->view); + if (status_r->highest_modseq == 0) { + /* modseqs not enabled yet, but we can't return 0 */ + status_r->highest_modseq = 1; + } + } + + if ((items & STATUS_FIRST_UNSEEN_SEQ) != 0) { + mail_index_lookup_first(box->view, 0, MAIL_SEEN, + &status_r->first_unseen_seq); + } + + if ((items & STATUS_KEYWORDS) != 0) + status_r->keywords = mail_index_get_keywords(box->index); + return 0; +} + static void -index_storage_get_status_cache_fields(struct mailbox *box, - struct mailbox_status *status_r) +get_metadata_cache_fields(struct mailbox *box, + struct mailbox_metadata *metadata_r) { const struct mail_cache_field *fields; enum mail_cache_decision_type dec; @@ -26,12 +71,12 @@ index_storage_get_status_cache_fields(struct mailbox *box, if (dec != MAIL_CACHE_DECISION_NO) array_append(cache_fields, &fields[i].name, 1); } - status_r->cache_fields = cache_fields; + metadata_r->cache_fields = cache_fields; } static int -index_storage_virtual_size_add_new(struct mailbox *box, - struct index_vsize_header *vsize_hdr) +virtual_size_add_new(struct mailbox *box, + struct index_vsize_header *vsize_hdr) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); const struct mail_index_header *hdr; @@ -98,15 +143,17 @@ index_storage_virtual_size_add_new(struct mailbox *box, } static int -index_storage_get_status_virtual_size(struct mailbox *box, - struct mailbox_status *status_r) +get_metadata_virtual_size(struct mailbox *box, + struct mailbox_metadata *metadata_r) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box); struct index_vsize_header vsize_hdr; + struct mailbox_status status; const void *data; size_t size; int ret; + mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, &status); mail_index_get_header_ext(box->view, ibox->vsize_hdr_ext_id, &data, &size); if (size == sizeof(vsize_hdr)) @@ -120,71 +167,32 @@ index_storage_get_status_virtual_size(struct mailbox *box, memset(&vsize_hdr, 0, sizeof(vsize_hdr)); } - if (vsize_hdr.highest_uid + 1 == status_r->uidnext && - vsize_hdr.message_count == status_r->messages) { + if (vsize_hdr.highest_uid + 1 == status.uidnext && + vsize_hdr.message_count == status.messages) { /* up to date */ - status_r->virtual_size = vsize_hdr.vsize; + metadata_r->virtual_size = vsize_hdr.vsize; return 0; } - if (vsize_hdr.highest_uid >= status_r->uidnext) { + if (vsize_hdr.highest_uid >= status.uidnext) { mail_storage_set_critical(box->storage, "vsize-hdr has invalid highest-uid (%u >= %u)", - vsize_hdr.highest_uid, status_r->uidnext); + vsize_hdr.highest_uid, status.uidnext); memset(&vsize_hdr, 0, sizeof(vsize_hdr)); } - ret = index_storage_virtual_size_add_new(box, &vsize_hdr); - status_r->virtual_size = vsize_hdr.vsize; + ret = virtual_size_add_new(box, &vsize_hdr); + metadata_r->virtual_size = vsize_hdr.vsize; return ret; } -int index_storage_get_status(struct mailbox *box, - enum mailbox_status_items items, - struct mailbox_status *status_r) +int index_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { - const struct mail_index_header *hdr; - int ret = 0; - - memset(status_r, 0, sizeof(struct mailbox_status)); - - if (!box->opened) { - if (mailbox_open(box) < 0) - return -1; - if (mailbox_sync(box, 0) < 0) + if ((items & MAILBOX_METADATA_CACHE_FIELDS) != 0) + get_metadata_cache_fields(box, metadata_r); + if ((items & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) { + if (get_metadata_virtual_size(box, metadata_r) < 0) return -1; } - - /* we can get most of the status items without any trouble */ - hdr = mail_index_get_header(box->view); - status_r->messages = hdr->messages_count; - if ((items & STATUS_RECENT) != 0) { - status_r->recent = index_mailbox_get_recent_count(box); - i_assert(status_r->recent <= status_r->messages); - } - status_r->unseen = hdr->messages_count - hdr->seen_messages_count; - status_r->uidvalidity = hdr->uid_validity; - status_r->uidnext = hdr->next_uid; - status_r->nonpermanent_modseqs = mail_index_is_in_memory(box->index); - if ((items & STATUS_HIGHESTMODSEQ) != 0) { - status_r->highest_modseq = - mail_index_modseq_get_highest(box->view); - if (status_r->highest_modseq == 0) { - /* modseqs not enabled yet, but we can't return 0 */ - status_r->highest_modseq = 1; - } - } - - if ((items & STATUS_FIRST_UNSEEN_SEQ) != 0) { - mail_index_lookup_first(box->view, 0, MAIL_SEEN, - &status_r->first_unseen_seq); - } - - if ((items & STATUS_KEYWORDS) != 0) - status_r->keywords = mail_index_get_keywords(box->index); - if ((items & STATUS_CACHE_FIELDS) != 0) - index_storage_get_status_cache_fields(box, status_r); - if ((items & STATUS_VIRTUAL_SIZE) != 0) { - if (index_storage_get_status_virtual_size(box, status_r) < 0) - ret = -1; - } - return ret; + return 0; } diff --git a/src/lib-storage/index/index-storage.c b/src/lib-storage/index/index-storage.c index 609a29baeb..8c8907ec74 100644 --- a/src/lib-storage/index/index-storage.c +++ b/src/lib-storage/index/index-storage.c @@ -423,7 +423,7 @@ int index_storage_mailbox_delete_dir(struct mailbox *box, bool mailbox_deleted) int index_storage_mailbox_delete(struct mailbox *box) { - uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; + struct mailbox_metadata metadata; if (!box->opened) { /* \noselect mailbox, try deleting only the directory */ @@ -433,7 +433,7 @@ int index_storage_mailbox_delete(struct mailbox *box) if (mailbox_mark_index_deleted(box, TRUE) < 0) return -1; - if (mailbox_get_guid(box, mailbox_guid) < 0) + if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) return -1; /* Make sure the indexes are closed before trying to delete the @@ -449,7 +449,7 @@ int index_storage_mailbox_delete(struct mailbox *box) } mailbox_list_add_change(box->list, MAILBOX_LOG_RECORD_DELETE_MAILBOX, - mailbox_guid); + metadata.guid); return index_storage_mailbox_delete_dir(box, TRUE); } @@ -532,15 +532,17 @@ void index_copy_cache_fields(struct mail_save_context *ctx, struct mail *src_mail, uint32_t dest_seq) { T_BEGIN { - struct mailbox_status src_status; + struct mailbox_metadata src_metadata; const char *const *namep; buffer_t *buf; - index_storage_get_status(src_mail->box, STATUS_CACHE_FIELDS, - &src_status); + if (mailbox_get_metadata(src_mail->box, + MAILBOX_METADATA_CACHE_FIELDS, + &src_metadata) < 0) + i_unreached(); buf = buffer_create_dynamic(pool_datastack_create(), 1024); - array_foreach(src_status.cache_fields, namep) { + array_foreach(src_metadata.cache_fields, namep) { mail_copy_cache_field(ctx, src_mail, dest_seq, *namep, buf); } diff --git a/src/lib-storage/index/index-storage.h b/src/lib-storage/index/index-storage.h index d64311b553..09927ffedf 100644 --- a/src/lib-storage/index/index-storage.h +++ b/src/lib-storage/index/index-storage.h @@ -108,6 +108,9 @@ enum mailbox_sync_type index_sync_type_convert(enum mail_index_sync_type type); int index_storage_get_status(struct mailbox *box, enum mailbox_status_items items, struct mailbox_status *status_r); +int index_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r); struct mail_search_context * index_storage_search_init(struct mailbox_transaction_context *t, diff --git a/src/lib-storage/index/maildir/maildir-storage.c b/src/lib-storage/index/maildir/maildir-storage.c index 181d45a1dc..29648723ab 100644 --- a/src/lib-storage/index/maildir/maildir-storage.c +++ b/src/lib-storage/index/maildir/maildir-storage.c @@ -473,11 +473,18 @@ maildir_mailbox_create(struct mailbox *box, const struct mailbox_update *update, } static int -maildir_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +maildir_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { struct maildir_mailbox *mbox = (struct maildir_mailbox *)box; - return maildir_uidlist_get_mailbox_guid(mbox->uidlist, guid); + if ((items & MAILBOX_METADATA_GUID) != 0) { + if (maildir_uidlist_get_mailbox_guid(mbox->uidlist, + metadata_r->guid) < 0) + return -1; + } + return index_mailbox_get_metadata(box, items, metadata_r); } static void maildir_mailbox_close(struct mailbox *box) @@ -644,7 +651,7 @@ struct mailbox maildir_mailbox = { index_storage_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - maildir_mailbox_get_guid, + maildir_mailbox_get_metadata, maildir_list_index_has_changed, maildir_list_index_update_sync, maildir_storage_sync_init, diff --git a/src/lib-storage/index/mbox/mbox-storage.c b/src/lib-storage/index/mbox/mbox-storage.c index ef371d5347..ff70911138 100644 --- a/src/lib-storage/index/mbox/mbox-storage.c +++ b/src/lib-storage/index/mbox/mbox-storage.c @@ -593,12 +593,11 @@ static void mbox_mailbox_close(struct mailbox *box) } static int -mbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +mbox_mailbox_get_guid(struct mbox_mailbox *mbox, + uint8_t guid[MAIL_GUID_128_SIZE]) { - struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; - - if (mail_index_is_in_memory(box->index)) { - mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, + if (mail_index_is_in_memory(mbox->box.index)) { + mail_storage_set_error(mbox->box.storage, MAIL_ERROR_NOTPOSSIBLE, "Mailbox GUIDs are not permanent without index files"); return -1; } @@ -610,6 +609,20 @@ mbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) return 0; } +static int +mbox_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) +{ + struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; + + if ((items & MAILBOX_METADATA_GUID) != 0) { + if (mbox_mailbox_get_guid(mbox, metadata_r->guid) < 0) + return -1; + } + return index_mailbox_get_metadata(box, items, metadata_r); +} + static void mbox_notify_changes(struct mailbox *box) { struct mbox_mailbox *mbox = (struct mbox_mailbox *)box; @@ -748,7 +761,7 @@ struct mailbox mbox_mailbox = { index_storage_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - mbox_mailbox_get_guid, + mbox_mailbox_get_metadata, NULL, NULL, mbox_storage_sync_init, diff --git a/src/lib-storage/list/index-mailbox-list-sync.c b/src/lib-storage/list/index-mailbox-list-sync.c index 15d7a94c99..a58db9da8d 100644 --- a/src/lib-storage/list/index-mailbox-list-sync.c +++ b/src/lib-storage/list/index-mailbox-list-sync.c @@ -340,7 +340,7 @@ static int index_list_sync_deinit(struct mailbox_sync_context *ctx, view = mail_index_view_open(ilist->mail_index); if (mail_index_lookup_seq(view, uid, &seq)) { - mailbox_get_status(box, CACHED_STATUS_ITEMS, &status); + mailbox_get_open_status(box, CACHED_STATUS_ITEMS, &status); (void)index_list_update(ilist, box, view, seq, &status); } mail_index_view_close(&view); diff --git a/src/lib-storage/mail-storage-private.h b/src/lib-storage/mail-storage-private.h index 38488c46bb..85f87e1363 100644 --- a/src/lib-storage/mail-storage-private.h +++ b/src/lib-storage/mail-storage-private.h @@ -116,7 +116,9 @@ struct mailbox_vfuncs { int (*get_status)(struct mailbox *box, enum mailbox_status_items items, struct mailbox_status *status_r); - int (*get_guid)(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]); + int (*get_metadata)(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r); /* Lookup sync extension record and figure out if it mailbox has changed since. Returns 1 = yes, 0 = no, -1 = error. */ diff --git a/src/lib-storage/mail-storage.c b/src/lib-storage/mail-storage.c index f8f192f2fc..8c811d09d0 100644 --- a/src/lib-storage/mail-storage.c +++ b/src/lib-storage/mail-storage.c @@ -911,21 +911,27 @@ int mailbox_get_status(struct mailbox *box, return box->v.get_status(box, items, status_r); } -int mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]) +void mailbox_get_open_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r) +{ + i_assert(box->opened); + if (box->v.get_status(box, items, status_r) < 0) + i_unreached(); +} + +int mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { - if (box->v.get_guid == NULL) { - mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, - "Storage doesn't support mailbox GUIDs"); - return -1; - } if (!box->opened) { if (mailbox_open(box) < 0) return -1; } - if (box->v.get_guid(box, guid) < 0) + if (box->v.get_metadata(box, items, metadata_r) < 0) return -1; - i_assert(!mail_guid_128_is_empty(guid)); + i_assert((items & MAILBOX_METADATA_GUID) == 0 || + !mail_guid_128_is_empty(metadata_r->guid)); return 0; } diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index f5bcb70e27..9e8410190d 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -64,9 +64,13 @@ enum mailbox_status_items { STATUS_UNSEEN = 0x10, STATUS_FIRST_UNSEEN_SEQ = 0x20, STATUS_KEYWORDS = 0x40, - STATUS_HIGHESTMODSEQ = 0x80, - STATUS_CACHE_FIELDS = 0x100, - STATUS_VIRTUAL_SIZE = 0x200 + STATUS_HIGHESTMODSEQ = 0x80 +}; + +enum mailbox_metadata_items { + MAILBOX_METADATA_GUID = 0x01, + MAILBOX_METADATA_VIRTUAL_SIZE = 0x02, + MAILBOX_METADATA_CACHE_FIELDS = 0x04 }; enum mailbox_search_result_flags { @@ -185,17 +189,21 @@ struct mailbox_status { uint32_t first_unseen_seq; uint64_t highest_modseq; - /* sum of virtual size of all messages in mailbox */ - uint64_t virtual_size; const ARRAY_TYPE(keywords) *keywords; - /* Fields that have "temp" or "yes" caching decision. */ - const ARRAY_TYPE(const_string) *cache_fields; /* Modseqs aren't permanent (index is in memory) */ unsigned int nonpermanent_modseqs:1; }; +struct mailbox_metadata { + uint8_t guid[MAIL_GUID_128_SIZE]; + /* sum of virtual size of all messages in mailbox */ + uint64_t virtual_size; + /* Fields that have "temp" or "yes" caching decision. */ + const ARRAY_TYPE(const_string) *cache_fields; +}; + struct mailbox_update { /* All non-zero fields are changed. */ uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; @@ -393,11 +401,16 @@ bool mailbox_backends_equal(const struct mailbox *box1, do forced CLOSE. */ bool mailbox_is_inconsistent(struct mailbox *box); -/* Gets the mailbox status information. */ +/* Gets the mailbox status information, opening the mailbox if necessary. */ int mailbox_get_status(struct mailbox *box, enum mailbox_status_items items, struct mailbox_status *status_r); -/* Get mailbox GUID, creating it if necessary. */ -int mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]); +/* Gets the mailbox status, requires that mailbox is already opened. */ +void mailbox_get_open_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r); +/* Gets mailbox metadata */ +int mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r); /* Returns a mask of flags that are private to user in this mailbox (as opposed to flags shared between users). */ enum mail_flags mailbox_get_private_flags_mask(struct mailbox *box); diff --git a/src/plugins/fts-solr/fts-backend-solr.c b/src/plugins/fts-solr/fts-backend-solr.c index 29fc412203..d975839a75 100644 --- a/src/plugins/fts-solr/fts-backend-solr.c +++ b/src/plugins/fts-solr/fts-backend-solr.c @@ -298,7 +298,7 @@ static int fts_backend_solr_get_last_uid_fallback(struct fts_backend *backend, box_name = fts_box_get_root(box, &ns); - mailbox_get_status(box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status); str_printfa(str, "uidv:%u+box:", status.uidvalidity); solr_quote_http(str, box_name); solr_add_ns_query_http(str, backend, ns); @@ -340,7 +340,7 @@ static int fts_backend_solr_get_last_uid(struct fts_backend *backend, box_name = fts_box_get_root(box, &ns); - mailbox_get_status(box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status); str_printfa(str, "uidv:%u+box:", status.uidvalidity); solr_quote_http(str, box_name); solr_add_ns_query_http(str, backend, ns); @@ -539,7 +539,7 @@ fts_backend_solr_build_init(struct fts_backend *backend, uint32_t *last_uid_r, ctx->ctx.backend = backend; ctx->cmd = str_new(default_pool, SOLR_CMDBUF_SIZE); - mailbox_get_status(backend->box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(backend->box, STATUS_UIDVALIDITY, &status); ctx->uid_validity = status.uidvalidity; *ctx_r = &ctx->ctx; @@ -737,7 +737,7 @@ fts_backend_solr_expunge(struct fts_backend *backend, struct mail *mail) { struct mailbox_status status; - mailbox_get_status(mail->box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(mail->box, STATUS_UIDVALIDITY, &status); T_BEGIN { string_t *cmd; @@ -807,7 +807,7 @@ static int fts_backend_solr_lookup(struct fts_backend_lookup_context *ctx, bool virtual; virtual = strcmp(box->storage->name, "virtual") == 0; - mailbox_get_status(box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status); str = t_str_new(256); if (!virtual) { diff --git a/src/plugins/fts-squat/fts-backend-squat.c b/src/plugins/fts-squat/fts-backend-squat.c index b41b54715e..3da073b2d1 100644 --- a/src/plugins/fts-squat/fts-backend-squat.c +++ b/src/plugins/fts-squat/fts-backend-squat.c @@ -69,7 +69,7 @@ static struct fts_backend *fts_backend_squat_init(struct mailbox *box) return NULL; } - mailbox_get_status(box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status); if (storage->set->mmap_disable) flags |= SQUAT_INDEX_FLAG_MMAP_DISABLE; if (storage->set->mail_nfs_index) diff --git a/src/plugins/fts/fts-storage.c b/src/plugins/fts/fts-storage.c index 1fc50b1c52..dc1a51f041 100644 --- a/src/plugins/fts/fts-storage.c +++ b/src/plugins/fts/fts-storage.c @@ -396,8 +396,8 @@ static int fts_build_init_virtual_next(struct fts_search_context *fctx) ret = strcmp(vname, last_uids[uidi].mailbox); if (ret == 0) { /* match. check also that uidvalidity matches. */ - mailbox_get_status(boxes[boxi].box, STATUS_UIDVALIDITY, - &status); + mailbox_get_open_status(boxes[boxi].box, + STATUS_UIDVALIDITY, &status); if (status.uidvalidity != last_uids[uidi].uidvalidity) { uidi++; continue; @@ -501,8 +501,8 @@ static int fts_build_init(struct fts_search_context *fctx) struct mailbox_status status; int ret; - mailbox_get_status(fctx->t->box, STATUS_MESSAGES | STATUS_UIDNEXT, - &status); + mailbox_get_open_status(fctx->t->box, STATUS_MESSAGES | STATUS_UIDNEXT, + &status); if (status.messages == fctx->fbox->last_messages_count && status.uidnext == fctx->fbox->last_uidnext) { /* no new messages since last check */ @@ -540,8 +540,8 @@ static int fts_build_deinit(struct fts_storage_build_context **_ctx) ret = -1; if (ret == 0) { - mailbox_get_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, - &status); + mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, + &status); fbox->last_messages_count = status.messages; fbox->last_uidnext = status.uidnext; } @@ -778,7 +778,8 @@ static bool search_nonindexed(struct mail_search_context *ctx) struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box); struct mailbox_status status; - mailbox_get_status(ctx->transaction->box, STATUS_MESSAGES, &status); + mailbox_get_open_status(ctx->transaction->box, + STATUS_MESSAGES, &status); fctx->seqs_set = FALSE; ctx->seq = fctx->first_nonindexed_seq - 1; diff --git a/src/plugins/virtual/virtual-save.c b/src/plugins/virtual/virtual-save.c index e6321142d1..1b7da6e6f3 100644 --- a/src/plugins/virtual/virtual-save.c +++ b/src/plugins/virtual/virtual-save.c @@ -50,7 +50,7 @@ virtual_copy_keywords(struct mailbox *src_box, return NULL; t_array_init(&kw_strings, src_keywords->count + 1); - mailbox_get_status(src_box, STATUS_KEYWORDS, &status); + mailbox_get_open_status(src_box, STATUS_KEYWORDS, &status); for (i = 0; i < src_keywords->count; i++) { kwp = array_idx(status.keywords, src_keywords->idx[i]); diff --git a/src/plugins/virtual/virtual-storage.c b/src/plugins/virtual/virtual-storage.c index 60654b352d..f0cdf42874 100644 --- a/src/plugins/virtual/virtual-storage.c +++ b/src/plugins/virtual/virtual-storage.c @@ -335,12 +335,16 @@ virtual_mailbox_update(struct mailbox *box, } static int -virtual_mailbox_get_guid(struct mailbox *box, - uint8_t guid[MAIL_GUID_128_SIZE] ATTR_UNUSED) +virtual_mailbox_get_metadata(struct mailbox *box, + enum mailbox_metadata_items items, + struct mailbox_metadata *metadata_r) { - mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, - "Virtual mailboxes have no GUIDs"); - return -1; + if ((items & MAILBOX_METADATA_GUID) != 0) { + mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE, + "Virtual mailboxes have no GUIDs"); + return -1; + } + return index_mailbox_get_metadata(box, items, metadata_r); } static void @@ -437,7 +441,7 @@ virtual_get_virtual_uid(struct mailbox *box, const char *backend_mailbox, if (bbox == NULL) return FALSE; - mailbox_get_status(bbox->box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY, &status); if (status.uidvalidity != backend_uidvalidity) return FALSE; @@ -517,7 +521,7 @@ struct mailbox virtual_mailbox = { index_storage_mailbox_delete, index_storage_mailbox_rename, index_storage_get_status, - virtual_mailbox_get_guid, + virtual_mailbox_get_metadata, NULL, NULL, virtual_storage_sync_init, diff --git a/src/plugins/virtual/virtual-sync.c b/src/plugins/virtual/virtual-sync.c index ccd0d340a6..fdaf70ab90 100644 --- a/src/plugins/virtual/virtual-sync.c +++ b/src/plugins/virtual/virtual-sync.c @@ -986,8 +986,8 @@ static void virtual_sync_backend_ext_header(struct virtual_sync_context *ctx, unsigned int mailbox_offset; uint64_t wanted_ondisk_highest_modseq; - mailbox_get_status(bbox->box, STATUS_UIDVALIDITY | - STATUS_HIGHESTMODSEQ, &status); + mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY | + STATUS_HIGHESTMODSEQ, &status); wanted_ondisk_highest_modseq = array_count(&bbox->sync_pending_removes) > 0 ? 0 : status.highest_modseq; @@ -1053,7 +1053,7 @@ static int virtual_sync_backend_box(struct virtual_sync_context *ctx, if (mailbox_sync(bbox->box, sync_flags) < 0) return -1; - mailbox_get_status(bbox->box, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY, &status); virtual_backend_box_sync_mail_set(bbox); if (status.uidvalidity != bbox->sync_uid_validity) { /* UID validity changed since last sync (or this is diff --git a/src/pop3/pop3-client.c b/src/pop3/pop3-client.c index 693f86173f..11b703fbf3 100644 --- a/src/pop3/pop3-client.c +++ b/src/pop3/pop3-client.c @@ -116,7 +116,7 @@ static int read_mailbox(struct client *client, uint32_t *failed_uid_r) *failed_uid_r = 0; - mailbox_get_status(client->mailbox, STATUS_UIDVALIDITY, &status); + mailbox_get_open_status(client->mailbox, STATUS_UIDVALIDITY, &status); client->uid_validity = status.uidvalidity; client->messages_count = status.messages; -- 2.47.3