bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
83b2368e64ca53712d80abcae9579bd22ef43c9eTimo Sirainen
83b2368e64ca53712d80abcae9579bd22ef43c9eTimo Sirainen#include "lib.h"
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen#include "ioloop.h"
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen#include "array.h"
382dde82f7646f850dc5b95d3c4505ef90e20f13Timo Sirainen#include "unichar.h"
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen#include "imap-match.h"
83b2368e64ca53712d80abcae9579bd22ef43c9eTimo Sirainen#include "subscription-file.h"
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen#include "mailbox-tree.h"
83b2368e64ca53712d80abcae9579bd22ef43c9eTimo Sirainen#include "mailbox-list-private.h"
83b2368e64ca53712d80abcae9579bd22ef43c9eTimo Sirainen#include "mailbox-list-subscriptions.h"
83b2368e64ca53712d80abcae9579bd22ef43c9eTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen#include <sys/stat.h>
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenstruct subscriptions_mailbox_list_iterate_context {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_list_iterate_context ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_tree_context *tree;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_tree_iterate_context *iter;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_info info;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen};
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenmailbox_list_subscription_fill_one(struct mailbox_list *list,
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen struct mailbox_list *src_list,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *name)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mail_namespace *ns, *default_ns = list->ns;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen struct mail_namespace *namespaces = default_ns->user->namespaces;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_node *node;
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen const char *vname, *ns_name, *error;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t len;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen bool created;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
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
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen 1) when listing "" namespace we want to skip over any names
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen that begin with pub/. */
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen if (src_list->ns->prefix_len == 0)
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen ns_name = name;
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen else {
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen /* we could have two-level namespace: ns/ns2/ */
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen ns_name = t_strconcat(src_list->ns->prefix, name, NULL);
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen }
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen ns = mail_namespace_find_unsubscribable(namespaces, ns_name);
a485cb14655f18bd890403c33f877dccdde27dc5Timo Sirainen if (ns != NULL && ns != default_ns) {
e27c711799aebc627f0089fe2216b874697f3b2cTimo Sirainen if (ns->prefix_len > 0)
a485cb14655f18bd890403c33f877dccdde27dc5Timo Sirainen return 0;
e27c711799aebc627f0089fe2216b874697f3b2cTimo Sirainen /* prefix="" namespace=no : catching this is basically the
e27c711799aebc627f0089fe2216b874697f3b2cTimo Sirainen same as not finding any namespace. */
e27c711799aebc627f0089fe2216b874697f3b2cTimo Sirainen ns = NULL;
a485cb14655f18bd890403c33f877dccdde27dc5Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* 2) when listing pub/ namespace, skip over entries that don't
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen begin with pub/. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (ns == NULL &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (default_ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* When listing shared namespace's subscriptions, we need to
34e4d771f71518a419342cf21508b64b20d2c416Timo Sirainen autocreate all the visible child namespaces. their subscriptions
34e4d771f71518a419342cf21508b64b20d2c416Timo Sirainen are listed later. */
14b551180cb4ac7acac8b048d8d6d7278541d1f6Timo Sirainen if (ns != NULL && mail_namespace_is_shared_user_root(ns)) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* we'll need to get the namespace autocreated.
753f22d1cec4b82c054856c29b5c65ab7275986dTimo Sirainen one easy way is to just ask to join a reference and
753f22d1cec4b82c054856c29b5c65ab7275986dTimo Sirainen pattern */
753f22d1cec4b82c054856c29b5c65ab7275986dTimo Sirainen (void)mailbox_list_join_refpattern(ns->list, ns_name, "");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
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 if (ns == NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ns = default_ns;
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen else if (strncmp(ns_name, ns->prefix, ns->prefix_len) == 0) {
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen ns_name += ns->prefix_len;
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen name = ns_name;
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen } else {
e7bdea8f7a7c87ba1974bb7a2e69a6b3d62bbdeaTimo Sirainen /* "pub" entry - this shouldn't be possible normally, because
e7bdea8f7a7c87ba1974bb7a2e69a6b3d62bbdeaTimo Sirainen it should be saved as "pub/", but handle it anyway */
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen i_assert(strncmp(ns_name, ns->prefix, ns->prefix_len-1) == 0 &&
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen ns_name[ns->prefix_len-1] == '\0');
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen name = ns_name = "";
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen len = strlen(name);
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 name = t_strndup(name, len-1);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen if (!mailbox_list_is_valid_name(list, name, &error)) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* we'll only get into trouble if we show this */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen vname = mailbox_list_get_vname(list, name);
382dde82f7646f850dc5b95d3c4505ef90e20f13Timo Sirainen if (!uni_utf8_str_is_valid(vname))
382dde82f7646f850dc5b95d3c4505ef90e20f13Timo Sirainen return -1;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node = mailbox_tree_get(list->subscriptions, vname, &created);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node->flags = MAILBOX_SUBSCRIBED;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainenint mailbox_list_subscriptions_refresh(struct mailbox_list *src_list,
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen struct mailbox_list *dest_list)
aef538e8e43f1aaf3d44c18de5c74afa08b960f8Timo Sirainen{
aef538e8e43f1aaf3d44c18de5c74afa08b960f8Timo Sirainen struct subsfile_list_context *subsfile_ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct stat st;
e3677df81bc31e3ce3188f71f3833f9bbda5fc0bTimo Sirainen enum mailbox_list_path_type type;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const char *path, *name;
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen char sep;
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen int ret;
83b2368e64ca53712d80abcae9579bd22ef43c9eTimo Sirainen
5a2b30ed0b51889535da764e12b42efefb25e278Timo Sirainen /* src_list is subscriptions=yes, dest_list is subscriptions=no
5a2b30ed0b51889535da764e12b42efefb25e278Timo Sirainen (or the same as src_list) */
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen i_assert((src_list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen if (dest_list->subscriptions == NULL) {
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen sep = mail_namespace_get_sep(src_list->ns);
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen dest_list->subscriptions = mailbox_tree_init(sep);
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen }
e3677df81bc31e3ce3188f71f3833f9bbda5fc0bTimo Sirainen
e3677df81bc31e3ce3188f71f3833f9bbda5fc0bTimo Sirainen type = src_list->set.control_dir != NULL ?
e3677df81bc31e3ce3188f71f3833f9bbda5fc0bTimo Sirainen MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_DIR;
3568ea090b5a072e498438e74db23b98103ff2deTimo Sirainen if (!mailbox_list_get_root_path(src_list, type, &path) ||
3568ea090b5a072e498438e74db23b98103ff2deTimo Sirainen src_list->set.subscription_fname == NULL) {
82af96bbd5222a787a91efb9f939b4a96905bed2Timo Sirainen /* no subscriptions (e.g. pop3c) */
82af96bbd5222a787a91efb9f939b4a96905bed2Timo Sirainen return 0;
82af96bbd5222a787a91efb9f939b4a96905bed2Timo Sirainen }
82af96bbd5222a787a91efb9f939b4a96905bed2Timo Sirainen path = t_strconcat(path, "/", src_list->set.subscription_fname, NULL);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (stat(path, &st) < 0) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (errno == ENOENT) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* no subscriptions */
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen mailbox_tree_clear(dest_list->subscriptions);
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen dest_list->subscriptions_mtime = 0;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return 0;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen mailbox_list_set_critical(dest_list, "stat(%s) failed: %m",
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen path);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return -1;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
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 */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return 0;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen mailbox_tree_clear(dest_list->subscriptions);
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen dest_list->subscriptions_read_time = ioloop_time;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen subsfile_ctx = subsfile_list_init(dest_list, path);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (subsfile_list_fstat(subsfile_ctx, &st) == 0)
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen dest_list->subscriptions_mtime = st.st_mtime;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen while ((name = subsfile_list_next(subsfile_ctx)) != NULL) T_BEGIN {
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen T_BEGIN {
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen ret = mailbox_list_subscription_fill_one(dest_list,
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen src_list, name);
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen } T_END;
f7b7a0516b2ffaa6effa7d932fb2ea51a8917e07Timo Sirainen if (ret < 0) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen i_warning("Subscriptions file %s: "
737561538a2dcdcda948a1da2830a612d8263a23Timo Sirainen "Removing invalid entry: %s",
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen path, name);
6c75379a3d918180b9dc297216245a5c86938c08Timo Sirainen (void)subsfile_set_subscribed(src_list, path,
5a2b30ed0b51889535da764e12b42efefb25e278Timo Sirainen mailbox_list_get_temp_prefix(src_list),
737561538a2dcdcda948a1da2830a612d8263a23Timo Sirainen name, FALSE);
737561538a2dcdcda948a1da2830a612d8263a23Timo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen } T_END;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (subsfile_list_deinit(&subsfile_ctx) < 0) {
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen dest_list->subscriptions_mtime = (time_t)-1;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return -1;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return 0;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen}
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenvoid mailbox_list_set_subscription_flags(struct mailbox_list *list,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen const char *vname,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen enum mailbox_info_flags *flags)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_node *node;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen *flags &= ~(MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node = mailbox_tree_lookup(list->subscriptions, vname);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (node != NULL) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen *flags |= node->flags & MAILBOX_SUBSCRIBED;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* the only reason why node might have a child is if one of
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen them is subscribed */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (node->children != NULL)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen *flags |= MAILBOX_CHILD_SUBSCRIBED;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen}
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenvoid mailbox_list_subscriptions_fill(struct mailbox_list_iterate_context *ctx,
a21537de6bebe0dafc8f28adf6b327358b0c3fdaTimo Sirainen struct mailbox_tree_context *tree,
a21537de6bebe0dafc8f28adf6b327358b0c3fdaTimo Sirainen bool default_nonexistent)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_list_iter_update_context update_ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_tree_iterate_context *iter;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen const char *name;
aef538e8e43f1aaf3d44c18de5c74afa08b960f8Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&update_ctx);
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen update_ctx.iter_ctx = ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen update_ctx.tree_ctx = tree;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen update_ctx.glob = ctx->glob;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen update_ctx.leaf_flags = MAILBOX_SUBSCRIBED;
a21537de6bebe0dafc8f28adf6b327358b0c3fdaTimo Sirainen if (default_nonexistent)
a21537de6bebe0dafc8f28adf6b327358b0c3fdaTimo Sirainen update_ctx.leaf_flags |= MAILBOX_NONEXISTENT;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen update_ctx.parent_flags = MAILBOX_CHILD_SUBSCRIBED;
4366a21968093172d9b757fe6894b1ee8916434eTimo Sirainen update_ctx.match_parents =
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen (ctx->flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0;
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen iter = mailbox_tree_iterate_init(ctx->list->subscriptions, NULL,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen MAILBOX_SUBSCRIBED);
c1dbcb60868c4e8e523fcf409b5b7539f58945d7Phil Carmody while (mailbox_tree_iterate_next(iter, &name) != NULL)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen mailbox_list_iter_update(&update_ctx, name);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen mailbox_tree_iterate_deinit(&iter);
83b2368e64ca53712d80abcae9579bd22ef43c9eTimo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenstruct mailbox_list_iterate_context *
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenmailbox_list_subscriptions_iter_init(struct mailbox_list *list,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen const char *const *patterns,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen enum mailbox_list_iter_flags flags)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct subscriptions_mailbox_list_iterate_context *ctx;
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen pool_t pool;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen char sep = mail_namespace_get_sep(list->ns);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen pool = pool_alloconly_create("mailbox list subscriptions iter", 1024);
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen ctx = p_new(pool, struct subscriptions_mailbox_list_iterate_context, 1);
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen ctx->ctx.pool = pool;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->ctx.list = list;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->ctx.flags = flags;
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen ctx->ctx.glob = imap_match_init_multiple(pool, patterns, TRUE, sep);
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen array_create(&ctx->ctx.module_contexts, pool, sizeof(void *), 5);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->tree = mailbox_tree_init(sep);
a21537de6bebe0dafc8f28adf6b327358b0c3fdaTimo Sirainen mailbox_list_subscriptions_fill(&ctx->ctx, ctx->tree, FALSE);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->info.ns = list->ns;
6e7954b94e1788c4d02799cf232ab675375bd640Timo Sirainen /* the tree usually has only those entries we want to iterate through,
6e7954b94e1788c4d02799cf232ab675375bd640Timo Sirainen but there are also non-matching root entries (e.g. "LSUB foo/%" will
6e7954b94e1788c4d02799cf232ab675375bd640Timo Sirainen include the "foo"), which we'll drop with MAILBOX_MATCHED. */
6e7954b94e1788c4d02799cf232ab675375bd640Timo Sirainen ctx->iter = mailbox_tree_iterate_init(ctx->tree, NULL, MAILBOX_MATCHED);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return &ctx->ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen}
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenconst struct mailbox_info *
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenmailbox_list_subscriptions_iter_next(struct mailbox_list_iterate_context *_ctx)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct subscriptions_mailbox_list_iterate_context *ctx =
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen (struct subscriptions_mailbox_list_iterate_context *)_ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_list *list = _ctx->list;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct mailbox_node *node;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen enum mailbox_info_flags subs_flags;
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen const char *vname, *storage_name, *error;
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen int ret;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node = mailbox_tree_iterate_next(ctx->iter, &vname);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (node == NULL)
34b724d1d7e50b1ab24267a3b6fc089b1147c1abAki Tuomi return mailbox_list_iter_default_next(_ctx);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
402e999a878e0cc41a0afb830fea0a93afc75f0dTimo Sirainen ctx->info.vname = vname;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen subs_flags = node->flags & (MAILBOX_SUBSCRIBED |
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen MAILBOX_CHILD_SUBSCRIBED);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
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 ctx->info.flags = subs_flags;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return &ctx->info;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen storage_name = mailbox_list_get_storage_name(list, vname);
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen if (!mailbox_list_is_valid_name(list, storage_name, &error)) {
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* broken entry in subscriptions file */
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->info.flags = MAILBOX_NONEXISTENT;
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen } else if (mailbox_list_mailbox(list, storage_name,
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen &ctx->info.flags) < 0) {
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen ctx->info.flags = 0;
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen _ctx->failed = TRUE;
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen } else if ((_ctx->flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) != 0 &&
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen (ctx->info.flags & (MAILBOX_CHILDREN |
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen MAILBOX_NOCHILDREN)) == 0) {
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen ret = mailbox_has_children(list, storage_name);
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen if (ret < 0)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen _ctx->failed = TRUE;
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen else if (ret == 0)
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen ctx->info.flags |= MAILBOX_NOCHILDREN;
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen else
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen ctx->info.flags |= MAILBOX_CHILDREN;
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->info.flags &= ~(MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen ctx->info.flags |=
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen node->flags & (MAILBOX_SUBSCRIBED | MAILBOX_CHILD_SUBSCRIBED);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen return &ctx->info;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen}
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainenint mailbox_list_subscriptions_iter_deinit(struct mailbox_list_iterate_context *_ctx)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen struct subscriptions_mailbox_list_iterate_context *ctx =
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen (struct subscriptions_mailbox_list_iterate_context *)_ctx;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen int ret = _ctx->failed ? -1 : 0;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen mailbox_tree_iterate_deinit(&ctx->iter);
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen mailbox_tree_deinit(&ctx->tree);
7ff6268cc35102675d73d44d680bed13d0709f7bTimo Sirainen pool_unref(&_ctx->pool);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return ret;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}