void mailbox_list_index_refresh_later(struct mailbox_list *list) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); struct mailbox_list_index_header new_hdr; struct mail_index_view *view; struct mail_index_transaction *trans; if (!ilist->has_backing_store) return; (void)mailbox_list_index_index_open(list); view = mail_index_view_open(ilist->index); if (!mailbox_list_index_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); }
int mailbox_list_index_refresh(struct mailbox_list *list) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); struct mail_index_view *view; int ret; if (ilist->syncing) return 0; if (mailbox_list_index_index_open(list) < 0) return -1; if (mail_index_refresh(ilist->index) < 0) { mailbox_list_index_set_index_error(list); return -1; } view = mail_index_view_open(ilist->index); if (ilist->mailbox_tree == NULL || mailbox_list_index_need_refresh(ilist, view)) { /* refresh list of mailboxes */ ret = mailbox_list_index_sync(list); } else { ret = mailbox_list_index_parse(list, view, FALSE); } mail_index_view_close(&view); return ret; }
static void mailbox_list_index_refresh_timeout(struct mailbox_list *list) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); timeout_remove(&ilist->to_refresh); (void)mailbox_list_index_refresh(list); }
void mailbox_list_index_set_index_error(struct mailbox_list *list) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); mailbox_list_set_internal_error(list); mail_index_reset_error(ilist->index); }
struct mailbox_list_iterate_context * mailbox_list_index_iter_init(struct mailbox_list *list, const char *const *patterns, enum mailbox_list_iter_flags flags) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); struct mailbox_list_index_iterate_context *ctx; pool_t pool; char ns_sep = mail_namespace_get_sep(list->ns); pool = pool_alloconly_create("mailbox list index iter", 2048); ctx = p_new(pool, struct mailbox_list_index_iterate_context, 1); ctx->ctx.pool = pool; ctx->ctx.list = list; ctx->ctx.flags = flags; ctx->ctx.glob = imap_match_init_multiple(pool, patterns, TRUE, ns_sep); array_create(&ctx->ctx.module_contexts, pool, sizeof(void *), 5); ctx->info_pool = pool_alloconly_create("mailbox list index iter info", 128); if (!iter_use_index(ctx)) { /* no indexing */ 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(pool, 128); ctx->next_node = ilist->mailbox_tree; ctx->mailbox_pool = ilist->mailbox_pool; pool_ref(ctx->mailbox_pool); } return &ctx->ctx; }
const struct mailbox_info * mailbox_list_index_iter_next(struct mailbox_list_iterate_context *_ctx) { struct mailbox_list_index_iterate_context *ctx = (struct mailbox_list_index_iterate_context *)_ctx; struct mailbox_list_index *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) { mailbox_list_index_update_info(ctx); match = imap_match(_ctx->glob, ctx->info.vname); follow_children = (match & (IMAP_MATCH_YES | IMAP_MATCH_CHILDREN)) != 0; if (match == IMAP_MATCH_YES && iter_subscriptions_ok(ctx)) { mailbox_list_index_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; } mailbox_list_index_update_next(ctx, follow_children); } return NULL; }
static int index_list_get_cached_status(struct mailbox *box, struct mailbox_status *status) { struct index_mailbox_list *ilist; struct mail_index_view *view; const void *data; uint32_t seq, *ext_id_p, *counter_p; unsigned int i; bool expunged; int ret; memset(status, 0, sizeof(*status)); ret = index_list_mailbox_open_unchanged_view(box, &view, &seq); if (ret <= 0) return ret; ilist = INDEX_LIST_CONTEXT(box->list); for (i = 0; index_list_map[i].name != NULL; i++) { ext_id_p = PTR_OFFSET(ilist, index_list_map[i].eid_offset); mail_index_lookup_ext(view, seq, *ext_id_p, &data, &expunged); if (expunged || data == NULL) { ret = 0; break; } counter_p = PTR_OFFSET(status, index_list_map[i].status_offset); *counter_p = *(const uint32_t *)data; } mail_index_view_close(&view); return ret; }
int mailbox_list_index_iter_deinit(struct mailbox_list_iterate_context *_ctx) { struct mailbox_list_index_iterate_context *ctx = (struct mailbox_list_index_iterate_context *)_ctx; struct mailbox_list_index *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 pool_unref(&ctx->mailbox_pool); pool_unref(&ctx->info_pool); pool_unref(&_ctx->pool); return ret; }
static int mailbox_list_index_index_open(struct mailbox_list *list) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); const struct mail_storage_settings *set = list->mail_set; struct mailbox_permissions perm; enum mail_index_open_flags index_flags; unsigned int lock_timeout; if (ilist->opened) return 0; if (mailbox_list_mkdir_missing_index_root(list) < 0) return -1; index_flags = mail_storage_settings_to_index_flags(set); if (strcmp(list->name, MAILBOX_LIST_NAME_INDEX) == 0) { /* LAYOUT=index. this is the only location for the mailbox data, so we must never move it into memory. */ index_flags |= MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY; } lock_timeout = set->mail_max_lock_timeout == 0 ? UINT_MAX : set->mail_max_lock_timeout; mailbox_list_get_root_permissions(list, &perm); mail_index_set_permissions(ilist->index, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin); 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, except if it fails with LAYOUT=index backend. */ if (mail_index_open_or_create(ilist->index, index_flags) < 0) { mailbox_list_set_internal_error(list); return -1; } } } ilist->opened = TRUE; return 0; }
static int index_list_mailbox_open_unchanged_view(struct mailbox *box, struct mail_index_view **view_r, uint32_t *seq_r) { struct index_mailbox_list *ilist; struct mail_index_view *view; uint32_t uid, seq; int ret; ilist = INDEX_LIST_CONTEXT(box->list); if (ilist == NULL) { /* indexing disabled */ return 0; } ret = mailbox_list_index_lookup(ilist->list_sync_view, box->name, &uid); if (ret <= 0) return ret; /* make sure we're synced */ if (index_list_update_mail_index(ilist, box) < 0) return -1; /* found from list index. lookup the mail index record for it */ view = mail_index_view_open(ilist->mail_index); if (!mail_index_lookup_seq(view, uid, &seq)) { mail_index_view_close(&view); return 0; } T_BEGIN { ret = box->v.list_index_has_changed(box, view, seq); } T_END; if (ret != 0) { /* error / mailbox has changed. we'll need to sync it. */ mail_index_view_close(&view); return ret < 0 ? -1 : 0; } *view_r = view; *seq_r = seq; return 1; }
int mailbox_list_index_parse(struct mailbox_list *list, struct mail_index_view *view, bool force) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); const struct mail_index_header *hdr; const char *error; 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; } mailbox_list_index_reset(ilist); ilist->sync_log_file_seq = hdr->log_file_seq; ilist->sync_log_file_offset = hdr->log_file_head_offset; if (mailbox_list_index_parse_header(ilist, view) < 0) { mailbox_list_set_critical(list, "Corrupted mailbox list index header %s", ilist->path); if (ilist->has_backing_store) { mail_index_mark_corrupted(ilist->index); return -1; } } if (mailbox_list_index_parse_records(ilist, view, &error) < 0) { mailbox_list_set_critical(list, "Corrupted mailbox list index %s: %s", ilist->path, error); if (ilist->has_backing_store) { mail_index_mark_corrupted(ilist->index); return -1; } /* FIXME: find any missing mailboxes, add them and write the index back. */ } return 0; }
static struct mailbox_list_index_node * mailbox_list_index_lookup_real(struct mailbox_list *list, const char *name) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); struct mailbox_list_index_node *node = ilist->mailbox_tree; const char *const *path; unsigned int i; char sep[2]; if (*name == '\0') return mailbox_list_index_node_find_sibling(node, ""); sep[0] = mailbox_list_get_hierarchy_sep(list); sep[1] = '\0'; path = t_strsplit(name, sep); for (i = 0;; i++) { node = mailbox_list_index_node_find_sibling(node, path[i]); if (node == NULL || path[i+1] == NULL) break; node = node->children; } return node; }
static bool iter_use_index(struct mailbox_list_index_iterate_context *ctx) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(ctx->ctx.list); if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) { /* for now we don't use indexes when listing subscriptions, because it needs to list also the nonexistent subscribed mailboxes, which don't exist in the index. */ return FALSE; } if ((ctx->ctx.flags & MAILBOX_LIST_ITER_RAW_LIST) != 0 && ilist->has_backing_store) { /* no indexing wanted with raw lists */ return FALSE; } if (mailbox_list_index_refresh(ctx->ctx.list) < 0 && ilist->has_backing_store) { /* refresh failed */ return FALSE; } return TRUE; }