mailbox-list-subscriptions.c revision e7bdea8f7a7c87ba1974bb7a2e69a6b3d62bbdea
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenstruct subscriptions_mailbox_list_iterate_context {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenmailbox_list_subscription_fill_one(struct mailbox_list *list,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mail_namespace *ns, *default_ns = list->ns;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct mail_namespace *namespaces = default_ns->user->namespaces;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen unsigned int len;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* default_ns is whatever namespace we're currently listing.
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if we have e.g. prefix="" and prefix=pub/ namespaces with
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen pub/ namespace having subscriptions=no, we want to:
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen 1) when listing "" namespace we want to skip over any names
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen that begin with pub/. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ns = mail_namespace_find_unsubscribable(namespaces, name);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* 2) when listing pub/ namespace, skip over entries that don't
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen begin with pub/. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (default_ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* When listing shared namespace's subscriptions, we need to
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen autocreate all the visible child namespaces and use the
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen child namespace. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (ns != NULL && ns->type == NAMESPACE_SHARED &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* we'll need to get the namespace autocreated.
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen one easy way is to just ask if a mailbox name under
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen it is valid, and it gets created */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen (void)mailbox_list_is_valid_existing_name(list, name);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ns = mail_namespace_find_unsubscribable(namespaces, name);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (ns->flags & NAMESPACE_FLAG_AUTOCREATED) != 0);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* When listing pub/ namespace, skip over the namespace
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen prefix in the name. the rest of the name is storage_name. */
e7bdea8f7a7c87ba1974bb7a2e69a6b3d62bbdeaTimo Sirainen else if (strncmp(name, ns->prefix, ns->prefix_len) == 0)
e7bdea8f7a7c87ba1974bb7a2e69a6b3d62bbdeaTimo Sirainen /* "pub" entry - this shouldn't be possible normally, because
e7bdea8f7a7c87ba1974bb7a2e69a6b3d62bbdeaTimo Sirainen it should be saved as "pub/", but handle it anyway */
e7bdea8f7a7c87ba1974bb7a2e69a6b3d62bbdeaTimo Sirainen i_assert(strncmp(name, ns->prefix, ns->prefix_len-1) == 0 &&
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (len > 0 && name[len-1] == mail_namespace_get_sep(ns)) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* entry ends with hierarchy separator, remove it.
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen this exists mainly for backwards compatibility with old
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen Dovecot versions and non-Dovecot software that added them */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (!mailbox_list_is_valid_existing_name(list, name)) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* we'll only get into trouble if we show this */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node = mailbox_tree_get(list->subscriptions, vname, &created);
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainenint mailbox_list_subscriptions_refresh(struct mailbox_list *src_list,
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen i_assert((src_list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0);
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen dest_list->subscriptions = mailbox_tree_init(sep);
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen path = t_strconcat(src_list->set.control_dir != NULL ?
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen src_list->set.control_dir : src_list->set.root_dir,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* no subscriptions */
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen mailbox_list_set_critical(dest_list, "stat(%s) failed: %m",
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen if (st.st_mtime == dest_list->subscriptions_mtime &&
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen st.st_mtime < dest_list->subscriptions_read_time-1) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* we're up to date */
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen dest_list->subscriptions_read_time = ioloop_time;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen subsfile_ctx = subsfile_list_init(dest_list, path);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (subsfile_list_fstat(subsfile_ctx, &st) == 0)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen while ((name = subsfile_list_next(subsfile_ctx)) != NULL) T_BEGIN {
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen if (mailbox_list_subscription_fill_one(dest_list, name) < 0) {
737561538a2dcdcda948a1da2830a612d8263a23Timo Sirainen "Removing invalid entry: %s",
737561538a2dcdcda948a1da2830a612d8263a23Timo Sirainen (void)subsfile_set_subscribed(dest_list, path,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (subsfile_list_deinit(&subsfile_ctx) < 0) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenvoid mailbox_list_set_subscription_flags(struct mailbox_list *list,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen *flags &= ~(MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node = mailbox_tree_lookup(list->subscriptions, vname);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* the only reason why node might have a child is if one of
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen them is subscribed */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenvoid mailbox_list_subscriptions_fill(struct mailbox_list_iterate_context *ctx,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_list_iter_update_context update_ctx;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen update_ctx.parent_flags = MAILBOX_CHILD_SUBSCRIBED;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen (ctx->flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen iter = mailbox_tree_iterate_init(ctx->list->subscriptions, NULL,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen while ((node = mailbox_tree_iterate_next(iter, &name)) != NULL)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenmailbox_list_subscriptions_iter_init(struct mailbox_list *list,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen const char *const *patterns,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct subscriptions_mailbox_list_iterate_context *ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx = i_new(struct subscriptions_mailbox_list_iterate_context, 1);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->ctx.glob = imap_match_init_multiple(default_pool, patterns,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen array_create(&ctx->ctx.module_contexts, default_pool, sizeof(void *), 5);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen mailbox_list_subscriptions_fill(&ctx->ctx, ctx->tree);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->iter = mailbox_tree_iterate_init(ctx->tree, NULL, 0);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenmailbox_list_subscriptions_iter_next(struct mailbox_list_iterate_context *_ctx)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct subscriptions_mailbox_list_iterate_context *ctx =
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen (struct subscriptions_mailbox_list_iterate_context *)_ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node = mailbox_tree_iterate_next(ctx->iter, &vname);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen subs_flags = node->flags & (MAILBOX_SUBSCRIBED |
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if ((_ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) != 0 &&
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen (_ctx->flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) == 0) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* don't care about flags, just return it */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen storage_name = mailbox_list_get_storage_name(list, vname);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (!mailbox_list_is_valid_pattern(list, storage_name)) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* broken entry in subscriptions file */
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen } else if (mailbox_list_mailbox(list, storage_name,
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen } else if ((_ctx->flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) != 0 &&
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen ret = mailbox_has_children(list, storage_name);
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen else if (ret == 0)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->info.flags &= ~(MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node->flags & (MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenint mailbox_list_subscriptions_iter_deinit(struct mailbox_list_iterate_context *_ctx)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct subscriptions_mailbox_list_iterate_context *ctx =