mail-namespace.c revision 2c067d5cd0088123e59ff45bee9b059fa9c1ffb1
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "lib.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "array.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "str.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "file-lock.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "settings-parser.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "mailbox-list-private.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "mail-storage-private.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "mail-storage-settings.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "mail-namespace.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic struct mail_namespace_settings prefixless_ns_unexpanded_set = {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen .name = "",
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen .type = "private",
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen .separator = "",
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen .prefix = "0",
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen .location = "0fail::LAYOUT=none",
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen .alias_for = NULL,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen .inbox = FALSE,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen .hidden = TRUE,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen .list = "no",
0327191888a058542f065526e82bce30319579a4Phil Carmody .subscriptions = FALSE,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen .ignore_on_failure = FALSE,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen .disabled = FALSE,
948b838c8e9896132e3a2d802fb5dad37e8dc716Timo Sirainen
948b838c8e9896132e3a2d802fb5dad37e8dc716Timo Sirainen .mailboxes = ARRAY_INIT
948b838c8e9896132e3a2d802fb5dad37e8dc716Timo Sirainen};
948b838c8e9896132e3a2d802fb5dad37e8dc716Timo Sirainenstatic struct mail_namespace_settings prefixless_ns_set;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenvoid mail_namespace_add_storage(struct mail_namespace *ns,
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen struct mail_storage *storage)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if (ns->storage == NULL)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->storage = storage;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_append(&ns->all_storages, &storage, 1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (storage->v.add_list != NULL)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen storage->v.add_list(storage, ns->list);
0327191888a058542f065526e82bce30319579a4Phil Carmody hook_mail_namespace_storage_added(ns);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainenvoid mail_namespace_finish_list_init(struct mail_namespace *ns,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct mailbox_list *list)
5a0ac2e5ef482016e00575a7dce83f52c1704732Timo Sirainen{
5a0ac2e5ef482016e00575a7dce83f52c1704732Timo Sirainen ns->list = list;
54bd0fec0be357266e299466a582f3c9269884e9Timo Sirainen ns->prefix_len = strlen(ns->prefix);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic void mail_namespace_free(struct mail_namespace *ns)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct mail_storage **storagep;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (array_is_created(&ns->all_storages)) {
0327191888a058542f065526e82bce30319579a4Phil Carmody array_foreach_modifiable(&ns->all_storages, storagep)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen mail_storage_unref(storagep);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_free(&ns->all_storages);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen if (ns->list != NULL)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen mailbox_list_destroy(&ns->list);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ns->owner != ns->user && ns->owner != NULL)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen mail_user_unref(&ns->owner);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_free(ns->prefix);
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen i_free(ns);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic bool
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainennamespace_has_special_use_mailboxes(struct mail_namespace_settings *ns_set)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen struct mailbox_settings *const *box_set;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen if (!array_is_created(&ns_set->mailboxes))
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen return FALSE;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen array_foreach(&ns_set->mailboxes, box_set) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if ((*box_set)->special_use[0] != '\0')
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return TRUE;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen}
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainenint mail_namespace_alloc(struct mail_user *user,
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen struct mail_namespace_settings *ns_set,
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen struct mail_namespace_settings *unexpanded_set,
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen struct mail_namespace **ns_r,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char **error_r)
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen{
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen struct mail_namespace *ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns = i_new(struct mail_namespace, 1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->refcount = 1;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen ns->user = user;
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen ns->prefix = i_strdup(ns_set->prefix);
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen ns->set = ns_set;
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen ns->unexpanded_set = unexpanded_set;
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen ns->mail_set = mail_user_set_get_storage_set(user);
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen i_array_init(&ns->all_storages, 2);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (strcmp(ns_set->type, "private") == 0) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->owner = user;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen ns->type = MAIL_NAMESPACE_TYPE_PRIVATE;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen } else if (strcmp(ns_set->type, "shared") == 0)
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen ns->type = MAIL_NAMESPACE_TYPE_SHARED;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen else if (strcmp(ns_set->type, "public") == 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->type = MAIL_NAMESPACE_TYPE_PUBLIC;
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen else {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = t_strdup_printf("Unknown namespace type: %s",
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen ns_set->type);
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen mail_namespace_free(ns);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen }
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (strcmp(ns_set->list, "children") == 0)
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen ns->flags |= NAMESPACE_FLAG_LIST_CHILDREN;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen else if (strcmp(ns_set->list, "yes") == 0)
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen ns->flags |= NAMESPACE_FLAG_LIST_PREFIX;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen else if (strcmp(ns_set->list, "no") != 0) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen *error_r = t_strdup_printf("Invalid list setting value: %s",
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen ns_set->list);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen mail_namespace_free(ns);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen return -1;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen }
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen if (ns_set->inbox) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen ns->flags |= NAMESPACE_FLAG_INBOX_USER |
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen NAMESPACE_FLAG_INBOX_ANY;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen }
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (ns_set->hidden)
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen ns->flags |= NAMESPACE_FLAG_HIDDEN;
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen if (ns_set->subscriptions)
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen ns->flags |= NAMESPACE_FLAG_SUBSCRIPTIONS;
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen *ns_r = ns;
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen return 0;
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen}
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen
0327191888a058542f065526e82bce30319579a4Phil Carmodyint mail_namespaces_init_add(struct mail_user *user,
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen struct mail_namespace_settings *ns_set,
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen struct mail_namespace_settings *unexpanded_ns_set,
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen struct mail_namespace **ns_p, const char **error_r)
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen{
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen const struct mail_storage_settings *mail_set =
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen mail_user_set_get_storage_set(user);
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen struct mail_namespace *ns;
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen const char *driver, *error;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen int ret;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen if (*ns_set->location == '\0')
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ns_set->location = mail_set->mail_location;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
548d8f62722578f076b4944e30013675f2605206Timo Sirainen if (mail_set->mail_debug) {
98950c9167dc2fab6c13d6d4c968e1963ecd73d7Timo Sirainen i_debug("Namespace %s: type=%s, prefix=%s, sep=%s, "
98950c9167dc2fab6c13d6d4c968e1963ecd73d7Timo Sirainen "inbox=%s, hidden=%s, list=%s, subscriptions=%s "
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen "location=%s",
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen ns_set->name, ns_set->type, ns_set->prefix,
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen ns_set->separator == NULL ? "" : ns_set->separator,
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ns_set->inbox ? "yes" : "no",
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns_set->hidden ? "yes" : "no",
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns_set->list,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns_set->subscriptions ? "yes" : "no", ns_set->location);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
64c48ffb71f1cf99acf375768fde4cff9b512648Timo Sirainen
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen if ((ret = mail_namespace_alloc(user, ns_set, unexpanded_ns_set,
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen &ns, error_r)) < 0)
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen return ret;
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ns_set == &prefixless_ns_set) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* autocreated prefix="" namespace */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->flags |= NAMESPACE_FLAG_UNUSABLE |
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen NAMESPACE_FLAG_AUTOCREATED;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen ns->special_use_mailboxes = namespace_has_special_use_mailboxes(ns_set);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen if (ns->type == MAIL_NAMESPACE_TYPE_SHARED &&
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen (strchr(ns->prefix, '%') != NULL ||
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen strchr(ns->set->location, '%') != NULL)) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* dynamic shared namespace. the above check catches wrong
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen mixed %% usage, but still allows for specifying a shared
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen namespace to an explicit location without any %% */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->flags |= NAMESPACE_FLAG_NOQUOTA | NAMESPACE_FLAG_NOACL;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen driver = MAIL_SHARED_STORAGE_NAME;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen } else {
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen driver = NULL;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (mail_storage_create(ns, driver, 0, &error) < 0) {
59a63791d4ec70a134cb0dcbad1255d952075efeTimo Sirainen *error_r = t_strdup_printf("Namespace '%s': %s",
59a63791d4ec70a134cb0dcbad1255d952075efeTimo Sirainen ns->prefix, error);
59a63791d4ec70a134cb0dcbad1255d952075efeTimo Sirainen mail_namespace_free(ns);
59a63791d4ec70a134cb0dcbad1255d952075efeTimo Sirainen return -1;
59a63791d4ec70a134cb0dcbad1255d952075efeTimo Sirainen }
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen *ns_p = ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainenstatic bool namespace_is_valid_alias_storage(struct mail_namespace *ns,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char **error_r)
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen{
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen if (strcmp(ns->storage->name, ns->alias_for->storage->name) != 0) {
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen *error_r = t_strdup_printf(
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen "Namespace %s can't have alias_for=%s "
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen "to a different storage type (%s vs %s)",
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen ns->prefix, ns->alias_for->prefix,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->storage->name, ns->alias_for->storage->name);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen return FALSE;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen }
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen if ((ns->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen ns->storage != ns->alias_for->storage) {
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen *error_r = t_strdup_printf(
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen "Namespace %s can't have alias_for=%s "
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen "to a different storage (different root dirs)",
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen ns->prefix, ns->alias_for->prefix);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen return FALSE;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return TRUE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
59a63791d4ec70a134cb0dcbad1255d952075efeTimo Sirainen
59a63791d4ec70a134cb0dcbad1255d952075efeTimo Sirainenstatic int
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainennamespace_set_alias_for(struct mail_namespace *ns,
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen struct mail_namespace *all_namespaces,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char **error_r)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ns->set->alias_for != NULL) {
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen ns->alias_for = mail_namespace_find_prefix(all_namespaces,
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen ns->set->alias_for);
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen if (ns->alias_for == NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = t_strdup_printf("Invalid namespace alias_for: %s",
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->set->alias_for);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen if (ns->alias_for->alias_for != NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = t_strdup_printf("Chained namespace alias_for: %s",
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->set->alias_for);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (!namespace_is_valid_alias_storage(ns, error_r))
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen if ((ns->alias_for->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen /* copy inbox=yes */
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen ns->flags |= NAMESPACE_FLAG_INBOX_USER;
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen }
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen ns->alias_chain_next = ns->alias_for->alias_chain_next;
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen ns->alias_for->alias_chain_next = ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return 0;
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstatic bool
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainennamespaces_check(struct mail_namespace *namespaces, const char **error_r)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct mail_namespace *ns, *inbox_ns = NULL;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen unsigned int subscriptions_count = 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen bool visible_namespaces = FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen char ns_sep, list_sep = '\0';
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (ns = namespaces; ns != NULL; ns = ns->next) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns_sep = mail_namespace_get_sep(ns);
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen if (mail_namespace_find_prefix(ns->next, ns->prefix) != NULL) {
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen *error_r = t_strdup_printf(
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen "Duplicate namespace prefix: \"%s\"",
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->prefix);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if ((ns->flags & NAMESPACE_FLAG_HIDDEN) == 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen visible_namespaces = TRUE;
0327191888a058542f065526e82bce30319579a4Phil Carmody /* check the inbox=yes status before alias_for changes it */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (inbox_ns != NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = "There can be only one namespace with "
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen "inbox=yes";
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen return FALSE;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen inbox_ns = ns;
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen }
6cc5a850bb6c1769f4113009c2067e5a719175a0Timo Sirainen if (namespace_set_alias_for(ns, namespaces, error_r) < 0)
6cc5a850bb6c1769f4113009c2067e5a719175a0Timo Sirainen return FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (*ns->prefix != '\0' &&
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen (ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) != 0 &&
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen ns->prefix[strlen(ns->prefix)-1] != ns_sep) {
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen *error_r = t_strdup_printf(
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen "list=yes requires prefix=%s "
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen "to end with separator", ns->prefix);
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen return FALSE;
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen }
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen if (*ns->prefix != '\0' &&
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen (ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) != 0 &&
13fc4d6d28f05076ffe6f5a925e8f6269e4b548ePhil Carmody ns->prefix[0] == ns_sep) {
13fc4d6d28f05076ffe6f5a925e8f6269e4b548ePhil Carmody *error_r = t_strdup_printf(
13fc4d6d28f05076ffe6f5a925e8f6269e4b548ePhil Carmody "list=yes requires prefix=%s "
13fc4d6d28f05076ffe6f5a925e8f6269e4b548ePhil Carmody "not to start with separator", ns->prefix);
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen return FALSE;
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) != 0) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (list_sep == '\0')
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen list_sep = ns_sep;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen else if (list_sep != ns_sep) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = "All list=yes namespaces must use "
0327191888a058542f065526e82bce30319579a4Phil Carmody "the same separator";
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen subscriptions_count++;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (inbox_ns == NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = "inbox=yes namespace missing";
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (list_sep == '\0') {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = "list=yes namespace missing";
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (!visible_namespaces) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = "hidden=no namespace missing";
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (subscriptions_count == 0) {
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen *error_r = "subscriptions=yes namespace missing";
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen return FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen return TRUE;
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenint mail_namespaces_init_finish(struct mail_namespace *namespaces,
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen const char **error_r)
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen{
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen struct mail_namespace *ns;
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen bool prefixless_found = FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(namespaces != NULL);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (ns = namespaces; ns != NULL; ns = ns->next) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ns->prefix_len == 0)
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen prefixless_found = TRUE;
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen }
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen if (!prefixless_found) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen prefixless_ns_set = prefixless_ns_unexpanded_set;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* a pretty evil way to expand the values */
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen prefixless_ns_set.prefix++;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen prefixless_ns_set.location++;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (mail_namespaces_init_add(namespaces->user,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen &prefixless_ns_set,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen &prefixless_ns_unexpanded_set,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen &ns, error_r) < 0)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_unreached();
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns->next = namespaces;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen namespaces = ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (namespaces->user->autocreated) {
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen /* e.g. raw user - don't check namespaces' validity */
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen } else if (!namespaces_check(namespaces, error_r)) {
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen *error_r = t_strconcat("namespace configuration error: ",
25c833d3cff7047f5c383892c379f59d116ff218Timo Sirainen *error_r, NULL);
25c833d3cff7047f5c383892c379f59d116ff218Timo Sirainen while (namespaces != NULL) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns = namespaces;
namespaces = ns->next;
mail_namespace_free(ns);
}
return -1;
}
mail_user_add_namespace(namespaces->user, &namespaces);
T_BEGIN {
hook_mail_namespaces_created(namespaces);
} T_END;
return 0;
}
int mail_namespaces_init(struct mail_user *user, const char **error_r)
{
const struct mail_storage_settings *mail_set;
struct mail_namespace_settings *const *ns_set;
struct mail_namespace_settings *const *unexpanded_ns_set;
struct mail_namespace *namespaces, **ns_p;
unsigned int i, count, count2;
i_assert(user->initialized);
namespaces = NULL; ns_p = &namespaces;
mail_set = mail_user_set_get_storage_set(user);
if (array_is_created(&user->set->namespaces)) {
ns_set = array_get(&user->set->namespaces, &count);
unexpanded_ns_set =
array_get(&user->unexpanded_set->namespaces, &count2);
i_assert(count == count2);
} else {
ns_set = unexpanded_ns_set = NULL;
count = 0;
}
for (i = 0; i < count; i++) {
if (ns_set[i]->disabled)
continue;
if (mail_namespaces_init_add(user, ns_set[i],
unexpanded_ns_set[i],
ns_p, error_r) < 0) {
if (!ns_set[i]->ignore_on_failure) {
mail_namespaces_deinit(&namespaces);
return -1;
}
if (mail_set->mail_debug) {
i_debug("Skipping namespace %s: %s",
ns_set[i]->prefix, *error_r);
}
} else {
ns_p = &(*ns_p)->next;
}
}
if (namespaces == NULL) {
/* no namespaces defined, create a default one */
return mail_namespaces_init_location(user, NULL, error_r);
}
return mail_namespaces_init_finish(namespaces, error_r);
}
int mail_namespaces_init_location(struct mail_user *user, const char *location,
const char **error_r)
{
struct mail_namespace_settings *inbox_set, *unexpanded_inbox_set;
struct mail_namespace *ns;
const struct mail_storage_settings *mail_set;
const char *error, *driver, *location_source;
bool default_location = FALSE;
int ret;
i_assert(location == NULL || *location != '\0');
inbox_set = p_new(user->pool, struct mail_namespace_settings, 1);
*inbox_set = mail_namespace_default_settings;
inbox_set->inbox = TRUE;
/* enums must be changed */
inbox_set->type = "private";
inbox_set->list = "yes";
unexpanded_inbox_set = p_new(user->pool, struct mail_namespace_settings, 1);
*unexpanded_inbox_set = *inbox_set;
driver = NULL;
mail_set = mail_user_set_get_storage_set(user);
if (location != NULL) {
inbox_set->location = p_strdup(user->pool, location);
location_source = "mail_location parameter";
} else if (*mail_set->mail_location != '\0') {
location_source = "mail_location setting";
inbox_set->location = mail_set->mail_location;
default_location = TRUE;
} else {
location_source = "environment MAIL";
inbox_set->location = getenv("MAIL");
}
if (inbox_set->location == NULL) {
/* support also maildir-specific environment */
inbox_set->location = getenv("MAILDIR");
if (inbox_set->location == NULL)
inbox_set->location = "";
else {
driver = "maildir";
location_source = "environment MAILDIR";
}
}
if (default_location) {
/* treat this the same as if a namespace was created with
default settings. dsync relies on finding a namespace
without explicit location setting. */
unexpanded_inbox_set->location = SETTING_STRVAR_UNEXPANDED;
} else {
unexpanded_inbox_set->location =
p_strconcat(user->pool, SETTING_STRVAR_EXPANDED,
inbox_set->location, NULL);
}
if ((ret = mail_namespace_alloc(user, inbox_set, unexpanded_inbox_set,
&ns, error_r)) < 0)
return ret;
if (mail_storage_create(ns, driver, 0, &error) < 0) {
if (*inbox_set->location != '\0') {
*error_r = t_strdup_printf(
"Initializing mail storage from %s "
"failed: %s", location_source, error);
} else {
*error_r = t_strdup_printf("mail_location not set and "
"autodetection failed: %s", error);
}
mail_namespace_free(ns);
return -1;
}
return mail_namespaces_init_finish(ns, error_r);
}
struct mail_namespace *mail_namespaces_init_empty(struct mail_user *user)
{
struct mail_namespace *ns;
ns = i_new(struct mail_namespace, 1);
ns->refcount = 1;
ns->user = user;
ns->owner = user;
ns->prefix = i_strdup("");
ns->flags = NAMESPACE_FLAG_INBOX_USER | NAMESPACE_FLAG_INBOX_ANY |
NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_SUBSCRIPTIONS;
ns->mail_set = mail_user_set_get_storage_set(user);
i_array_init(&ns->all_storages, 2);
return ns;
}
void mail_namespaces_deinit(struct mail_namespace **_namespaces)
{
struct mail_namespace *ns, *next;
/* update *_namespaces as needed, instead of immediately setting it
to NULL. for example mdbox_storage.destroy() wants to go through
user's namespaces. */
while (*_namespaces != NULL) {
ns = *_namespaces;
next = ns->next;
mail_namespace_free(ns);
*_namespaces = next;
}
}
void mail_namespaces_set_storage_callbacks(struct mail_namespace *namespaces,
struct mail_storage_callbacks *callbacks,
void *context)
{
struct mail_namespace *ns;
struct mail_storage *const *storagep;
for (ns = namespaces; ns != NULL; ns = ns->next) {
array_foreach(&ns->all_storages, storagep)
mail_storage_set_callbacks(*storagep, callbacks, context);
}
}
void mail_namespace_ref(struct mail_namespace *ns)
{
i_assert(ns->refcount > 0);
ns->refcount++;
}
void mail_namespace_unref(struct mail_namespace **_ns)
{
struct mail_namespace *ns = *_ns;
i_assert(ns->refcount > 0);
*_ns = NULL;
if (--ns->refcount > 0)
return;
i_assert(ns->destroyed);
mail_namespace_free(ns);
}
void mail_namespace_destroy(struct mail_namespace *ns)
{
struct mail_namespace **nsp;
i_assert(!ns->destroyed);
/* remove from user's namespaces list */
for (nsp = &ns->user->namespaces; *nsp != NULL; nsp = &(*nsp)->next) {
if (*nsp == ns) {
*nsp = ns->next;
break;
}
}
ns->destroyed = TRUE;
mail_namespace_unref(&ns);
}
struct mail_storage *
mail_namespace_get_default_storage(struct mail_namespace *ns)
{
return ns->storage;
}
char mail_namespace_get_sep(struct mail_namespace *ns)
{
return *ns->set->separator != '\0' ? *ns->set->separator :
mailbox_list_get_hierarchy_sep(ns->list);
}
char mail_namespaces_get_root_sep(struct mail_namespace *namespaces)
{
while ((namespaces->flags & NAMESPACE_FLAG_LIST_PREFIX) == 0)
namespaces = namespaces->next;
return mail_namespace_get_sep(namespaces);
}
static bool mail_namespace_is_usable_prefix(struct mail_namespace *ns,
const char *mailbox, bool inbox)
{
if (strncmp(ns->prefix, mailbox, ns->prefix_len) == 0) {
/* true exact prefix match */
return TRUE;
}
if (inbox && strncmp(ns->prefix, "INBOX", 5) == 0 &&
strncmp(ns->prefix+5, mailbox+5, ns->prefix_len-5) == 0) {
/* we already checked that mailbox begins with case-insensitive
INBOX. this namespace also begins with INBOX and the rest
of the prefix matches too. */
return TRUE;
}
if (strncmp(ns->prefix, mailbox, ns->prefix_len-1) == 0 &&
mailbox[ns->prefix_len-1] == '\0' &&
ns->prefix[ns->prefix_len-1] == mail_namespace_get_sep(ns)) {
/* we're trying to access the namespace prefix itself */
return TRUE;
}
return FALSE;
}
static struct mail_namespace *
mail_namespace_find_mask(struct mail_namespace *namespaces, const char *box,
enum namespace_flags flags,
enum namespace_flags mask)
{
struct mail_namespace *ns = namespaces;
struct mail_namespace *best = NULL;
unsigned int best_len = 0;
bool inbox;
inbox = strncasecmp(box, "INBOX", 5) == 0;
if (inbox && box[5] == '\0') {
/* find the INBOX namespace */
while (ns != NULL) {
if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
(ns->flags & mask) == flags)
return ns;
if (*ns->prefix == '\0')
best = ns;
ns = ns->next;
}
return best;
}
for (; ns != NULL; ns = ns->next) {
if (ns->prefix_len >= best_len && (ns->flags & mask) == flags &&
mail_namespace_is_usable_prefix(ns, box, inbox)) {
best = ns;
best_len = ns->prefix_len;
}
}
return best;
}
static struct mail_namespace *
mail_namespace_find_shared(struct mail_namespace *ns, const char *mailbox)
{
struct mailbox_list *list = ns->list;
struct mail_storage *storage;
if (mailbox_list_get_storage(&list, mailbox, &storage) < 0)
return ns;
return mailbox_list_get_namespace(list);
}
struct mail_namespace *
mail_namespace_find(struct mail_namespace *namespaces, const char *mailbox)
{
struct mail_namespace *ns;
ns = mail_namespace_find_mask(namespaces, mailbox, 0, 0);
i_assert(ns != NULL);
if (mail_namespace_is_shared_user_root(ns)) {
/* see if we need to autocreate a namespace for shared user */
if (strchr(mailbox, mail_namespace_get_sep(ns)) != NULL)
return mail_namespace_find_shared(ns, mailbox);
}
return ns;
}
struct mail_namespace *
mail_namespace_find_unalias(struct mail_namespace *namespaces,
const char **mailbox)
{
struct mail_namespace *ns;
const char *storage_name;
ns = mail_namespace_find(namespaces, *mailbox);
if (ns->alias_for != NULL) {
storage_name =
mailbox_list_get_storage_name(ns->list, *mailbox);
ns = ns->alias_for;
*mailbox = mailbox_list_get_vname(ns->list, storage_name);
}
return ns;
}
struct mail_namespace *
mail_namespace_find_visible(struct mail_namespace *namespaces,
const char *mailbox)
{
return mail_namespace_find_mask(namespaces, mailbox, 0,
NAMESPACE_FLAG_HIDDEN);
}
struct mail_namespace *
mail_namespace_find_subscribable(struct mail_namespace *namespaces,
const char *mailbox)
{
return mail_namespace_find_mask(namespaces, mailbox,
NAMESPACE_FLAG_SUBSCRIPTIONS,
NAMESPACE_FLAG_SUBSCRIPTIONS);
}
struct mail_namespace *
mail_namespace_find_unsubscribable(struct mail_namespace *namespaces,
const char *mailbox)
{
return mail_namespace_find_mask(namespaces, mailbox,
0, NAMESPACE_FLAG_SUBSCRIPTIONS);
}
struct mail_namespace *
mail_namespace_find_inbox(struct mail_namespace *namespaces)
{
i_assert(namespaces != NULL);
/* there should always be an INBOX */
while ((namespaces->flags & NAMESPACE_FLAG_INBOX_USER) == 0) {
namespaces = namespaces->next;
i_assert(namespaces != NULL);
}
return namespaces;
}
struct mail_namespace *
mail_namespace_find_prefix(struct mail_namespace *namespaces,
const char *prefix)
{
struct mail_namespace *ns;
unsigned int len = strlen(prefix);
for (ns = namespaces; ns != NULL; ns = ns->next) {
if (ns->prefix_len == len &&
strcmp(ns->prefix, prefix) == 0)
return ns;
}
return NULL;
}
struct mail_namespace *
mail_namespace_find_prefix_nosep(struct mail_namespace *namespaces,
const char *prefix)
{
struct mail_namespace *ns;
unsigned int len = strlen(prefix);
for (ns = namespaces; ns != NULL; ns = ns->next) {
if (ns->prefix_len == len + 1 &&
strncmp(ns->prefix, prefix, len) == 0 &&
ns->prefix[len] == mail_namespace_get_sep(ns))
return ns;
}
return NULL;
}
bool mail_namespace_is_shared_user_root(struct mail_namespace *ns)
{
struct mail_storage *const *storagep;
if (ns->type != MAIL_NAMESPACE_TYPE_SHARED)
return FALSE;
if ((ns->flags & NAMESPACE_FLAG_AUTOCREATED) != 0) {
/* child of the shared root */
return FALSE;
}
/* if we have driver=shared storage, we're a real shared root */
array_foreach(&ns->all_storages, storagep) {
if (strcmp((*storagep)->name, MAIL_SHARED_STORAGE_NAME) == 0)
return TRUE;
}
return FALSE;
}