Mercurial > dovecot > core-2.2
view src/lib-storage/list/index-mailbox-list.c @ 12645:d3d5f104ca40
lib-storage: Mailbox list indexes now refresh the index on create/delete/rename.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 08 Feb 2011 22:54:14 +0200 |
parents | ad002fdc6a6c |
children | 0cadba9597cb |
line wrap: on
line source
/* Copyright (c) 2006-2011 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "ioloop.h" #include "str.h" #include "hash.h" #include "imap-match.h" #include "mail-index.h" #include "mail-storage-hooks.h" #include "mailbox-list-subscriptions.h" #include "index-mailbox-list.h" struct index_mailbox_list_sync_context { struct index_mailbox_list *ilist; char sep[2]; uint32_t next_uid; struct mail_index_sync_ctx *sync_ctx; struct mail_index_view *view; struct mail_index_transaction *trans; }; struct index_mailbox_list_module index_mailbox_list_module = MODULE_CONTEXT_INIT(&mailbox_list_module_register); static int index_mailbox_list_read(struct index_mailbox_list *ilist, struct mail_index_view *view, bool force); static void index_mailbox_list_reset(struct index_mailbox_list *ilist) { hash_table_clear(ilist->mailbox_names, FALSE); hash_table_clear(ilist->mailbox_hash, FALSE); p_clear(ilist->mailbox_pool); ilist->mailbox_tree = NULL; ilist->highest_name_id = 0; ilist->sync_log_file_seq = 0; ilist->sync_log_file_offset = 0; } static struct index_mailbox_node * index_mailbox_node_find_sibling(struct index_mailbox_node *node, const char *name) { while (node != NULL) { if (strcmp(node->name, name) == 0) return node; node = node->next; } return NULL; } static void index_mailbox_node_add_to_index(struct index_mailbox_list_sync_context *ctx, struct index_mailbox_node *node, uint32_t *name_id_r, uint32_t *seq_r) { struct mailbox_list_index_record irec; uint32_t seq; memset(&irec, 0, sizeof(irec)); irec.name_id = node->name_id; if (node->parent != NULL) irec.parent_uid = node->parent->uid; mail_index_append(ctx->trans, node->uid, &seq); mail_index_update_flags(ctx->trans, seq, MODIFY_REPLACE, (enum mail_flags)MAILBOX_LIST_INDEX_FLAG_NONEXISTENT); mail_index_update_ext(ctx->trans, seq, ctx->ilist->ext_id, &irec, NULL); *name_id_r = irec.name_id; *seq_r = seq; } static struct index_mailbox_node * index_mailbox_node_add(struct index_mailbox_list_sync_context *ctx, struct index_mailbox_node *parent, const char *name, uint32_t *seq_r) { struct index_mailbox_node *node; uint32_t name_id; char *dup_name; node = p_new(ctx->ilist->mailbox_pool, struct index_mailbox_node, 1); node->flags = MAILBOX_LIST_INDEX_FLAG_NONEXISTENT | MAILBOX_LIST_INDEX_FLAG_MARKED; node->name = dup_name = p_strdup(ctx->ilist->mailbox_pool, name); node->name_id = ++ctx->ilist->highest_name_id; node->uid = ctx->next_uid++; if (parent != NULL) { node->parent = parent; node->next = parent->children; parent->children = node; } else { node->next = ctx->ilist->mailbox_tree; ctx->ilist->mailbox_tree = node; } index_mailbox_node_add_to_index(ctx, node, &name_id, seq_r); hash_table_insert(ctx->ilist->mailbox_hash, POINTER_CAST(node->uid), node); hash_table_insert(ctx->ilist->mailbox_names, POINTER_CAST(name_id), dup_name); return node; } struct index_mailbox_node * index_mailbox_list_lookup(struct mailbox_list *list, const char *vname) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); struct index_mailbox_node *node; T_BEGIN { const char *const *path; unsigned int i; char sep[2]; sep[0] = mail_namespace_get_sep(list->ns); sep[1] = '\0'; path = t_strsplit(vname, sep); node = ilist->mailbox_tree; for (i = 0;; i++) { node = index_mailbox_node_find_sibling(node, path[i]); if (node == NULL || path[i+1] == NULL) break; node = node->children; } } T_END; return node; } static uint32_t index_mailbox_list_sync_name(struct index_mailbox_list_sync_context *ctx, const char *name, enum mailbox_list_index_flags flags) { const char *const *path; struct index_mailbox_node *node, *parent; unsigned int i; uint32_t seq = 0; path = t_strsplit(name, ctx->sep); node = ctx->ilist->mailbox_tree; parent = NULL; for (i = 0; path[i] != NULL; i++) { node = index_mailbox_node_find_sibling(node, path[i]); if (node == NULL) break; node->flags |= MAILBOX_LIST_INDEX_FLAG_MARKED; parent = node; node = node->children; } node = parent; if (path[i] == NULL) { if (!mail_index_lookup_seq(ctx->view, node->uid, &seq)) i_panic("mailbox list index: lost uid=%u", node->uid); } else { for (; path[i] != NULL; i++) node = index_mailbox_node_add(ctx, node, path[i], &seq); } node->flags = flags | MAILBOX_LIST_INDEX_FLAG_MARKED; return seq; } static void get_existing_name_ids(ARRAY_TYPE(uint32_t) *ids, const struct index_mailbox_node *node) { for (; node != NULL; node = node->next) { if ((node->flags & MAILBOX_LIST_INDEX_FLAG_MARKED) != 0) { if (node->children != NULL) get_existing_name_ids(ids, node->children); array_append(ids, &node->name_id, 1); } } } static int uint32_cmp(const uint32_t *p1, const uint32_t *p2) { return *p1 < *p2 ? -1 : (*p1 > *p2 ? 1 : 0); } static void index_mailbox_list_sync_names(struct index_mailbox_list_sync_context *ctx) { struct index_mailbox_list *ilist = ctx->ilist; ARRAY_TYPE(uint32_t) existing_name_ids; buffer_t *buf; struct mailbox_list_index_header *hdr; const void *ext_data; size_t ext_size; const char *name; const uint32_t *id_p; uint32_t prev_id = 0; t_array_init(&existing_name_ids, 64); get_existing_name_ids(&existing_name_ids, ilist->mailbox_tree); array_sort(&existing_name_ids, uint32_cmp); buf = buffer_create_dynamic(pool_datastack_create(), 1024); hdr = buffer_append_space_unsafe(buf, sizeof(*hdr)); array_foreach(&existing_name_ids, id_p) { if (*id_p != prev_id) { buffer_append(buf, id_p, sizeof(*id_p)); name = hash_table_lookup(ilist->mailbox_names, POINTER_CAST(*id_p)); buffer_append(buf, name, strlen(name) + 1); prev_id = *id_p; } } buffer_append_zero(buf, sizeof(*id_p)); mail_index_get_header_ext(ctx->view, ilist->ext_id, &ext_data, &ext_size); if (nearest_power(ext_size) != nearest_power(buf->used)) { mail_index_ext_resize(ctx->trans, ilist->ext_id, nearest_power(buf->used), sizeof(struct mailbox_list_index_record), sizeof(uint32_t)); } mail_index_update_header_ext(ctx->trans, ilist->ext_id, 0, buf->data, buf->used); } static void index_mailbox_list_node_unmark_recursive(struct index_mailbox_node *node) { while (node != NULL) { if (node->children != NULL) index_mailbox_list_node_unmark_recursive(node->children); node->flags &= ~MAILBOX_LIST_INDEX_FLAG_MARKED; node = node->next; } } static void index_mailbox_node_unlink(struct index_mailbox_list_sync_context *sync_ctx, struct index_mailbox_node *node) { struct index_mailbox_node **prev; prev = node->parent == NULL ? &sync_ctx->ilist->mailbox_tree : &node->parent; while (*prev != node) prev = &(*prev)->next; *prev = node->next; } static void index_mailbox_nodes_expunge(struct index_mailbox_list_sync_context *sync_ctx, struct index_mailbox_node *node) { uint32_t seq; while (node != NULL) { if (node->children != NULL) index_mailbox_nodes_expunge(sync_ctx, node->children); if ((node->flags & MAILBOX_LIST_INDEX_FLAG_MARKED) == 0) { if (mail_index_lookup_seq(sync_ctx->view, node->uid, &seq)) mail_index_expunge(sync_ctx->trans, seq); index_mailbox_node_unlink(sync_ctx, node); } node = node->next; } } static int index_mailbox_list_sync(struct mailbox_list *list) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); struct index_mailbox_list_sync_context sync_ctx; struct mailbox_list_iterate_context *iter; const struct mail_index_header *hdr; const struct mailbox_info *info; const char *patterns[2]; enum mailbox_list_index_flags flags; uint32_t seq, orig_highest_name_id; int ret = 0; index_mailbox_list_reset(ilist); memset(&sync_ctx, 0, sizeof(sync_ctx)); sync_ctx.ilist = ilist; sync_ctx.sep[0] = mail_namespace_get_sep(list->ns); if (mail_index_sync_begin(ilist->index, &sync_ctx.sync_ctx, &sync_ctx.view, &sync_ctx.trans, MAIL_INDEX_SYNC_FLAG_AVOID_FLAG_UPDATES) < 0) return -1; if (index_mailbox_list_read(ilist, sync_ctx.view, TRUE) < 0) { mail_index_sync_rollback(&sync_ctx.sync_ctx); return -1; } orig_highest_name_id = ilist->highest_name_id; hdr = mail_index_get_header(sync_ctx.view); sync_ctx.next_uid = hdr->next_uid; if (hdr->uid_validity == 0) { uint32_t uid_validity = ioloop_time; mail_index_update_header(sync_ctx.trans, offsetof(struct mail_index_header, uid_validity), &uid_validity, sizeof(uid_validity), TRUE); } index_mailbox_list_node_unmark_recursive(ilist->mailbox_tree); patterns[0] = "*"; patterns[1] = NULL; iter = ilist->module_ctx.super.iter_init(list, patterns, 0); while ((info = ilist->module_ctx.super.iter_next(iter)) != NULL) { flags = 0; if ((info->flags & MAILBOX_NONEXISTENT) != 0) flags |= MAILBOX_LIST_INDEX_FLAG_NONEXISTENT; if ((info->flags & MAILBOX_NOSELECT) != 0) flags |= MAILBOX_LIST_INDEX_FLAG_NOSELECT; if ((info->flags & MAILBOX_NOINFERIORS) != 0) flags |= MAILBOX_LIST_INDEX_FLAG_NOINFERIORS; T_BEGIN { seq = index_mailbox_list_sync_name(&sync_ctx, info->name, (enum mail_flags)flags); } T_END; mail_index_update_flags(sync_ctx.trans, seq, MODIFY_REPLACE, flags); } if (ilist->module_ctx.super.iter_deinit(iter) < 0) ret = -1; if (ret < 0) { mail_index_sync_rollback(&sync_ctx.sync_ctx); return -1; } index_mailbox_nodes_expunge(&sync_ctx, ilist->mailbox_tree); if (orig_highest_name_id != ilist->highest_name_id) { /* new names added */ T_BEGIN { index_mailbox_list_sync_names(&sync_ctx); } T_END; } else { struct mailbox_list_index_header new_hdr; new_hdr.refresh_flag = 0; mail_index_update_header_ext(sync_ctx.trans, ilist->ext_id, offsetof(struct mailbox_list_index_header, refresh_flag), &new_hdr.refresh_flag, sizeof(new_hdr.refresh_flag)); } return mail_index_sync_commit(&sync_ctx.sync_ctx); } static int index_mailbox_list_parse_header(struct index_mailbox_list *ilist, struct mail_index_view *view) { const struct mailbox_list_index_header *hdr; const void *data, *p; size_t i, len, size; uint32_t id, prev_id = 0; char *name; mail_index_get_header_ext(view, ilist->ext_id, &data, &size); if (size == 0) return 0; hdr = data; for (i = sizeof(*hdr); i < size; ) { /* get id */ if (i + sizeof(id) > size) return -1; memcpy(&id, CONST_PTR_OFFSET(data, i), sizeof(id)); i += sizeof(id); if (id <= prev_id) { /* allow extra space in the end as long as last id=0 */ return id == 0 ? 0 : -1; } /* get name */ p = memchr(CONST_PTR_OFFSET(data, i), '\0', size-i); if (p == NULL) return -1; len = (const char *)p - (const char *)(CONST_PTR_OFFSET(data, i)); name = p_strndup(ilist->mailbox_pool, CONST_PTR_OFFSET(data, i), len); i += len + 1; /* add id => name to hash table */ hash_table_insert(ilist->mailbox_names, POINTER_CAST(id), name); ilist->highest_name_id = id; } i_assert(i == size); return 0; } static int index_mailbox_list_parse_records(struct index_mailbox_list *ilist, struct mail_index_view *view) { struct index_mailbox_node *node; const struct mail_index_record *rec; const struct mailbox_list_index_record *irec; const void *data; bool expunged; uint32_t seq, count; count = mail_index_view_get_messages_count(view); for (seq = 1; seq <= count; seq++) { node = p_new(ilist->mailbox_pool, struct index_mailbox_node, 1); rec = mail_index_lookup(view, seq); node->uid = rec->uid; node->flags = rec->flags; mail_index_lookup_ext(view, seq, ilist->ext_id, &data, &expunged); if (data == NULL) return -1; irec = data; node->name_id = irec->name_id; node->name = hash_table_lookup(ilist->mailbox_names, POINTER_CAST(irec->name_id)); if (node->name == NULL) return -1; if (irec->parent_uid != 0) { node->parent = hash_table_lookup(ilist->mailbox_hash, POINTER_CAST(irec->parent_uid)); if (node->parent == NULL) return -1; node->next = node->parent->children; node->parent->children = node; } else { node->next = ilist->mailbox_tree; ilist->mailbox_tree = node; } hash_table_insert(ilist->mailbox_hash, POINTER_CAST(node->uid), node); } return 0; } static int index_mailbox_list_read(struct index_mailbox_list *ilist, struct mail_index_view *view, bool force) { const struct mail_index_header *hdr; int ret; hdr = mail_index_get_header(view); if (!force && hdr->log_file_seq == ilist->sync_log_file_seq && hdr->log_file_head_offset == ilist->sync_log_file_offset) { /* nothing changed */ return 0; } index_mailbox_list_reset(ilist); ilist->sync_log_file_seq = hdr->log_file_seq; ilist->sync_log_file_offset = hdr->log_file_head_offset; ret = index_mailbox_list_parse_header(ilist, view); if (ret == 0) ret = index_mailbox_list_parse_records(ilist, view); if (ret < 0) { i_error("Corrupted mailbox list index %s", ilist->path); mail_index_mark_corrupted(ilist->index); return -1; } return 0; } static bool index_mailbox_list_need_refresh(struct index_mailbox_list *ilist, struct mail_index_view *view) { const struct mailbox_list_index_header *hdr; const void *data; size_t size; mail_index_get_header_ext(view, ilist->ext_id, &data, &size); hdr = data; return hdr != NULL && hdr->refresh_flag != 0; } int index_mailbox_list_refresh(struct mailbox_list *list) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); struct mail_index_view *view; int ret; if (ilist->iter_refcount > 0) { /* someone's already iterating. don't break them. */ return 0; } if (mail_index_refresh(ilist->index) < 0) return -1; view = mail_index_view_open(ilist->index); if (ilist->mailbox_tree == NULL || index_mailbox_list_need_refresh(ilist, view)) { /* refresh list of mailboxes */ ret = index_mailbox_list_sync(list); } else { ret = index_mailbox_list_read(ilist, view, FALSE); } mail_index_view_close(&view); return ret; } void index_mailbox_list_refresh_later(struct mailbox_list *list) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); struct mailbox_list_index_header new_hdr; struct mail_index_view *view; struct mail_index_transaction *trans; view = mail_index_view_open(ilist->index); if (!index_mailbox_list_need_refresh(ilist, view)) { new_hdr.refresh_flag = 1; trans = mail_index_transaction_begin(view, MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); mail_index_update_header_ext(trans, ilist->ext_id, offsetof(struct mailbox_list_index_header, refresh_flag), &new_hdr.refresh_flag, sizeof(new_hdr.refresh_flag)); if (mail_index_transaction_commit(&trans) < 0) mail_index_mark_corrupted(ilist->index); } mail_index_view_close(&view); } static struct mailbox_list_iterate_context * index_mailbox_list_iter_init(struct mailbox_list *list, const char *const *patterns, enum mailbox_list_iter_flags flags) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); struct index_mailbox_list_iterate_context *ctx; char ns_sep = mail_namespace_get_sep(list->ns); ctx = i_new(struct index_mailbox_list_iterate_context, 1); ctx->ctx.list = list; ctx->ctx.flags = flags; ctx->ctx.glob = imap_match_init_multiple(default_pool, patterns, TRUE, ns_sep); array_create(&ctx->ctx.module_contexts, default_pool, sizeof(void *), 5); ctx->sep = ns_sep; if (index_mailbox_list_refresh(ctx->ctx.list) < 0) { /* no indexing */ mail_index_mark_corrupted(ilist->index); ctx->backend_ctx = ilist->module_ctx.super. iter_init(list, patterns, flags); } else { /* listing mailboxes from index */ ctx->info.ns = list->ns; ctx->path = str_new(default_pool, 128); ctx->next_node = ilist->mailbox_tree; ilist->iter_refcount++; } return &ctx->ctx; } static void index_mailbox_list_update_info(struct index_mailbox_list_iterate_context *ctx) { struct index_mailbox_node *node = ctx->next_node; str_truncate(ctx->path, ctx->parent_len); if (str_len(ctx->path) > 0) str_append_c(ctx->path, ctx->sep); str_append(ctx->path, node->name); ctx->info.name = str_c(ctx->path); ctx->info.flags = 0; if ((node->flags & MAILBOX_LIST_INDEX_FLAG_NONEXISTENT) != 0) ctx->info.flags |= MAILBOX_NONEXISTENT; else if ((node->flags & MAILBOX_LIST_INDEX_FLAG_NOSELECT) != 0) ctx->info.flags |= MAILBOX_NOSELECT; if ((node->flags & MAILBOX_LIST_INDEX_FLAG_NOINFERIORS) != 0) ctx->info.flags |= MAILBOX_NOINFERIORS; ctx->info.flags |= node->children != NULL ? MAILBOX_CHILDREN : MAILBOX_NOCHILDREN; if ((ctx->ctx.flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED | MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) { mailbox_list_set_subscription_flags(ctx->ctx.list, ctx->info.name, &ctx->info.flags); } /* FIXME: set marked, unmarked flags based on recent counter */ } static void index_mailbox_list_update_next(struct index_mailbox_list_iterate_context *ctx, bool follow_children) { struct index_mailbox_node *node = ctx->next_node; if (node->children != NULL && follow_children) { ctx->parent_len = str_len(ctx->path); ctx->next_node = node->children; } else { while (node->next == NULL) { node = node->parent; if (node != NULL) { ctx->parent_len -= strlen(node->name); if (node->parent != NULL) ctx->parent_len--; } if (node == NULL) { /* last one */ ctx->next_node = NULL; return; } } ctx->next_node = node->next; } } static bool iter_subscriptions_ok(struct index_mailbox_list_iterate_context *ctx) { if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) return TRUE; if ((ctx->info.flags & MAILBOX_SUBSCRIBED) != 0) return TRUE; if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0 && (ctx->info.flags & MAILBOX_CHILD_SUBSCRIBED) != 0) return TRUE; return FALSE; } static const struct mailbox_info * index_mailbox_list_iter_next(struct mailbox_list_iterate_context *_ctx) { struct index_mailbox_list_iterate_context *ctx = (struct index_mailbox_list_iterate_context *)_ctx; struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(_ctx->list); bool follow_children; enum imap_match_result match; if (ctx->backend_ctx != NULL) { /* index isn't being used */ return ilist->module_ctx.super.iter_next(ctx->backend_ctx); } /* listing mailboxes from index */ while (ctx->next_node != NULL) { index_mailbox_list_update_info(ctx); match = imap_match(_ctx->glob, ctx->info.name); follow_children = (match & (IMAP_MATCH_YES | IMAP_MATCH_CHILDREN)) != 0; if (match == IMAP_MATCH_YES && iter_subscriptions_ok(ctx)) { index_mailbox_list_update_next(ctx, TRUE); return &ctx->info; } else if ((_ctx->flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0 && (ctx->info.flags & MAILBOX_CHILD_SUBSCRIBED) == 0) { /* listing only subscriptions, but there are no subscribed children. */ follow_children = FALSE; } index_mailbox_list_update_next(ctx, follow_children); } return NULL; } static int index_mailbox_list_iter_deinit(struct mailbox_list_iterate_context *_ctx) { struct index_mailbox_list_iterate_context *ctx = (struct index_mailbox_list_iterate_context *)_ctx; struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(_ctx->list); int ret = ctx->failed ? -1 : 0; if (ctx->backend_ctx != NULL) ret = ilist->module_ctx.super.iter_deinit(ctx->backend_ctx); else { i_assert(ilist->iter_refcount > 0); ilist->iter_refcount--; str_free(&ctx->path); } imap_match_deinit(&ctx->ctx.glob); array_free(&ctx->ctx.module_contexts); i_free(ctx); return ret; } static void index_mailbox_list_deinit(struct mailbox_list *list) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); hash_table_destroy(&ilist->mailbox_hash); hash_table_destroy(&ilist->mailbox_names); pool_unref(&ilist->mailbox_pool); mail_index_close(ilist->index); mail_index_free(&ilist->index); ilist->module_ctx.super.deinit(list); } static int index_mailbox_list_index_open(struct mailbox_list *list) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); const struct mail_storage_settings *set = list->mail_set; enum mail_index_open_flags index_flags; unsigned int lock_timeout; index_flags = mail_storage_settings_to_index_flags(set); lock_timeout = set->mail_max_lock_timeout == 0 ? -1U : set->mail_max_lock_timeout; mail_index_set_lock_method(ilist->index, set->parsed_lock_method, lock_timeout); if (mail_index_open_or_create(ilist->index, index_flags) < 0) { if (mail_index_move_to_memory(ilist->index) < 0) { /* try opening once more. it should be created directly into memory now. */ if (mail_index_open_or_create(ilist->index, index_flags) < 0) i_panic("in-memory index creation failed"); } } return 0; } static int index_mailbox_list_create_mailbox_dir(struct mailbox_list *list, const char *name, enum mailbox_dir_create_type type) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); index_mailbox_list_refresh_later(list); return ilist->module_ctx.super.create_mailbox_dir(list, name, type); } static int index_mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); index_mailbox_list_refresh_later(list); return ilist->module_ctx.super.delete_mailbox(list, name); } static int index_mailbox_list_delete_dir(struct mailbox_list *list, const char *name) { struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list); index_mailbox_list_refresh_later(list); return ilist->module_ctx.super.delete_dir(list, name); } static int index_mailbox_list_rename_mailbox(struct mailbox_list *oldlist, const char *oldname, struct mailbox_list *newlist, const char *newname, bool rename_children) { struct index_mailbox_list *oldilist = INDEX_LIST_CONTEXT(oldlist); index_mailbox_list_refresh_later(oldlist); if (oldlist != newlist) index_mailbox_list_refresh_later(newlist); return oldilist->module_ctx.super. rename_mailbox(oldlist, oldname, newlist, newname, rename_children); } static void index_mailbox_list_created(struct mailbox_list *list) { struct index_mailbox_list *ilist; const char *dir; dir = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_INDEX); if (*dir == '\0' || list->mail_set->mailbox_list_index) { /* reserve the module context anyway, so syncing code knows that the index is disabled */ ilist = NULL; MODULE_CONTEXT_SET(list, index_mailbox_list_module, ilist); return; } ilist = p_new(list->pool, struct index_mailbox_list, 1); ilist->module_ctx.super = list->v; list->v.deinit = index_mailbox_list_deinit; list->v.iter_init = index_mailbox_list_iter_init; list->v.iter_deinit = index_mailbox_list_iter_deinit; list->v.iter_next = index_mailbox_list_iter_next; list->v.create_mailbox_dir = index_mailbox_list_create_mailbox_dir; list->v.delete_mailbox = index_mailbox_list_delete_mailbox; list->v.delete_dir = index_mailbox_list_delete_dir; list->v.rename_mailbox = index_mailbox_list_rename_mailbox; MODULE_CONTEXT_SET(list, index_mailbox_list_module, ilist); ilist->path = p_strdup_printf(list->pool, "%s/"MAILBOX_LIST_INDEX_PREFIX, dir); ilist->index = mail_index_alloc(dir, MAILBOX_LIST_INDEX_PREFIX); ilist->ext_id = mail_index_ext_register(ilist->index, "list", sizeof(struct mailbox_list_index_header), sizeof(struct mailbox_list_index_record), sizeof(uint32_t)); ilist->mailbox_pool = pool_alloconly_create("mailbox list index", 4096); ilist->mailbox_names = hash_table_create(default_pool, ilist->mailbox_pool, 0, NULL, NULL); ilist->mailbox_hash = hash_table_create(default_pool, ilist->mailbox_pool, 0, NULL, NULL); if (index_mailbox_list_index_open(list) < 0) { list->v = ilist->module_ctx.super; mail_index_free(&ilist->index); MODULE_CONTEXT_UNSET(list, index_mailbox_list_module); } index_mailbox_list_status_init_list(list); } static struct mail_storage_hooks index_mailbox_list_hooks = { .mailbox_list_created = index_mailbox_list_created }; void index_mailbox_list_init(void); /* called in mailbox-list-register.c */ void index_mailbox_list_init(void) { mail_storage_hooks_add_internal(&index_mailbox_list_hooks); index_mailbox_list_status_init(); }