struct mailbox_list_iterate_context * mailbox_list_subscriptions_iter_init(struct mailbox_list *list, const char *const *patterns, enum mailbox_list_iter_flags flags) { struct subscriptions_mailbox_list_iterate_context *ctx; pool_t pool; char sep = mail_namespace_get_sep(list->ns); pool = pool_alloconly_create("mailbox list subscriptions iter", 1024); ctx = p_new(pool, struct subscriptions_mailbox_list_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, sep); array_create(&ctx->ctx.module_contexts, pool, sizeof(void *), 5); ctx->tree = mailbox_tree_init(sep); mailbox_list_subscriptions_fill(&ctx->ctx, ctx->tree, FALSE); ctx->info.ns = list->ns; /* the tree usually has only those entries we want to iterate through, but there are also non-matching root entries (e.g. "LSUB foo/%" will include the "foo"), which we'll drop with MAILBOX_MATCHED. */ ctx->iter = mailbox_tree_iterate_init(ctx->tree, NULL, MAILBOX_MATCHED); return &ctx->ctx; }
static void acl_mailbox_try_list_fast(struct acl_mailbox_list_iterate_context *ctx) { struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ctx->ctx.list); struct acl_backend *backend = alist->rights.backend; const unsigned int *idxp; const struct acl_mask *acl_mask; struct acl_mailbox_list_context *nonowner_list_ctx; struct mail_namespace *ns = ctx->ctx.list->ns; struct mailbox_list_iter_update_context update_ctx; const char *name; int ret; if ((ctx->ctx.flags & (MAILBOX_LIST_ITER_RAW_LIST | MAILBOX_LIST_ITER_SELECT_SUBSCRIBED)) != 0) return; if (ns->type == MAIL_NAMESPACE_TYPE_PUBLIC) { /* mailboxes in public namespace should all be listable to someone. we don't benefit from fast listing. */ return; } /* if this namespace's default rights contain LOOKUP, we'll need to go through all mailboxes in any case. */ idxp = alist->rights.acl_storage_right_idx + ACL_STORAGE_RIGHT_LOOKUP; if (acl_backend_get_default_rights(backend, &acl_mask) < 0 || acl_cache_mask_isset(acl_mask, *idxp)) return; /* no LOOKUP right by default, we can optimize this */ memset(&update_ctx, 0, sizeof(update_ctx)); update_ctx.iter_ctx = &ctx->ctx; update_ctx.glob = imap_match_init(pool_datastack_create(), "*", (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0, ctx->sep); update_ctx.match_parents = TRUE; update_ctx.tree_ctx = mailbox_tree_init(ctx->sep); nonowner_list_ctx = acl_backend_nonowner_lookups_iter_init(backend); while ((ret = acl_backend_nonowner_lookups_iter_next(nonowner_list_ctx, &name)) > 0) { T_BEGIN { const char *vname = mailbox_list_get_vname(ns->list, name); mailbox_list_iter_update(&update_ctx, vname); } T_END; } acl_backend_nonowner_lookups_iter_deinit(&nonowner_list_ctx); if (ret == 0) ctx->lookup_boxes = update_ctx.tree_ctx; else mailbox_tree_deinit(&update_ctx.tree_ctx); }
struct mailbox_list_iterate_context * maildir_list_iter_init(struct mailbox_list *_list, const char *const *patterns, enum mailbox_list_iter_flags flags) { struct maildir_mailbox_list *list = (struct maildir_mailbox_list *)_list; struct maildir_list_iterate_context *ctx; pool_t pool; char ns_sep = mail_namespace_get_sep(_list->ns); int ret; pool = pool_alloconly_create("mailbox list maildir iter", 1024); ctx = p_new(pool, struct maildir_list_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->tree_ctx = mailbox_tree_init(ns_sep); ctx->info.ns = _list->ns; ctx->prefix_char = strcmp(_list->name, MAILBOX_LIST_NAME_IMAPDIR) == 0 ? '\0' : list->sep; ctx->dir = _list->set.root_dir; if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) { /* Listing only subscribed mailboxes. Flags are set later if needed. */ bool default_nonexistent = (flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0; mailbox_list_subscriptions_fill(&ctx->ctx, ctx->tree_ctx, default_nonexistent); } if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0 || (flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0) { /* Add/update mailbox list with flags */ bool update_only = (flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0; T_BEGIN { ret = maildir_fill_readdir(ctx, ctx->ctx.glob, update_only); } T_END; if (ret < 0) { ctx->ctx.failed = TRUE; return &ctx->ctx; } }
static struct mailbox_list *imapc_list_alloc(void) { struct imapc_mailbox_list *list; pool_t pool; pool = pool_alloconly_create("imapc mailbox list", 1024); list = p_new(pool, struct imapc_mailbox_list, 1); list->list = imapc_mailbox_list; list->list.pool = pool; /* separator is set lazily */ list->mailboxes = mailbox_tree_init('\0'); mailbox_tree_set_parents_nonexistent(list->mailboxes); return &list->list; }
int mailbox_list_subscriptions_refresh(struct mailbox_list *src_list, struct mailbox_list *dest_list) { struct subsfile_list_context *subsfile_ctx; struct stat st; enum mailbox_list_path_type type; const char *path, *name; char sep; int ret; /* src_list is subscriptions=yes, dest_list is subscriptions=no (or the same as src_list) */ i_assert((src_list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0); if (dest_list->subscriptions == NULL) { sep = mail_namespace_get_sep(src_list->ns); dest_list->subscriptions = mailbox_tree_init(sep); } type = src_list->set.control_dir != NULL ? MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_DIR; if (!mailbox_list_get_root_path(src_list, type, &path) || src_list->set.subscription_fname == NULL) { /* no subscriptions (e.g. pop3c) */ return 0; } path = t_strconcat(path, "/", src_list->set.subscription_fname, NULL); if (stat(path, &st) < 0) { if (errno == ENOENT) { /* no subscriptions */ mailbox_tree_clear(dest_list->subscriptions); dest_list->subscriptions_mtime = 0; return 0; } mailbox_list_set_critical(dest_list, "stat(%s) failed: %m", path); return -1; } if (st.st_mtime == dest_list->subscriptions_mtime && st.st_mtime < dest_list->subscriptions_read_time-1) { /* we're up to date */ return 0; } mailbox_tree_clear(dest_list->subscriptions); dest_list->subscriptions_read_time = ioloop_time; subsfile_ctx = subsfile_list_init(dest_list, path); if (subsfile_list_fstat(subsfile_ctx, &st) == 0) dest_list->subscriptions_mtime = st.st_mtime; while ((name = subsfile_list_next(subsfile_ctx)) != NULL) T_BEGIN { T_BEGIN { ret = mailbox_list_subscription_fill_one(dest_list, src_list, name); } T_END; if (ret < 0) { i_warning("Subscriptions file %s: " "Removing invalid entry: %s", path, name); (void)subsfile_set_subscribed(src_list, path, mailbox_list_get_temp_prefix(src_list), name, FALSE); } } T_END; if (subsfile_list_deinit(&subsfile_ctx) < 0) { dest_list->subscriptions_mtime = (time_t)-1; return -1; } return 0; }