shared-storage.c revision 1a5573ebc32fae2fe576ec544e1781323c1db609
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2008-2014 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen#include "array.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "str.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ioloop.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "var-expand.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "index-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-list-private.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "fail-mail-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "shared-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <stdlib.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <ctype.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenextern struct mail_storage shared_storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct mail_storage *shared_storage_alloc(void)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct shared_storage *storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen pool_t pool;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen pool = pool_alloconly_create("shared storage", 1024);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage = p_new(pool, struct shared_storage, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->storage = shared_storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->storage.pool = pool;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &storage->storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainenstatic int
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainenshared_storage_create(struct mail_storage *_storage, struct mail_namespace *ns,
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen const char **error_r)
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen{
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen struct shared_storage *storage = (struct shared_storage *)_storage;
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen struct mail_storage *storage_class;
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen const char *driver, *p;
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen char *wildcardp, key;
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen bool have_username;
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen /* location must begin with the actual mailbox driver */
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen p = strchr(ns->set->location, ':');
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen if (p == NULL) {
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen *error_r = "Shared mailbox location not prefixed with driver";
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen driver = t_strdup_until(ns->set->location, p);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->location = p_strdup(_storage->pool, ns->set->location);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->unexpanded_location =
d22301419109ed4a38351715e6760011421dadecTimo Sirainen p_strdup(_storage->pool, ns->unexpanded_set->location);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->storage_class_name = p_strdup(_storage->pool, driver);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage_class = mail_user_get_storage_class(_storage->user, driver);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (storage_class != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen _storage->class_flags = storage_class->class_flags;
3b32bc12710240f86465a00fbb2bd1ef030e6c40Timo Sirainen else if (strcmp(driver, "auto") != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = t_strconcat("Unknown shared storage driver: ",
d22301419109ed4a38351715e6760011421dadecTimo Sirainen driver, NULL);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return -1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen wildcardp = strchr(ns->prefix, '%');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (wildcardp == NULL) {
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen *error_r = "Shared namespace prefix doesn't contain %";
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->ns_prefix_pattern = p_strdup(_storage->pool, wildcardp);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen have_username = FALSE;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen for (p = storage->ns_prefix_pattern; *p != '\0'; p++) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (*p != '%')
d22301419109ed4a38351715e6760011421dadecTimo Sirainen continue;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen key = p[1];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (key == 'u' || key == 'n')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen have_username = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (key != '%' && key != 'd')
d22301419109ed4a38351715e6760011421dadecTimo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (*p != '\0') {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = "Shared namespace prefix contains unknown variables";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen if (!have_username) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = "Shared namespace prefix doesn't contain %u or %n";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (p[-1] != mail_namespace_get_sep(ns) &&
d22301419109ed4a38351715e6760011421dadecTimo Sirainen (ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen NAMESPACE_FLAG_LIST_CHILDREN)) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = "Shared namespace prefix doesn't end with hierarchy separator";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen }
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen /* truncate prefix after the above checks are done, so they can log
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen the full prefix in error conditions */
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen *wildcardp = '\0';
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen ns->prefix_len = strlen(ns->prefix);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenshared_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_list_settings *set)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set->layout = "shared";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenget_nonexistent_user_location(struct shared_storage *storage,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *username, string_t *location)
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* user wasn't found. we'll still need to create the storage
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen to avoid exposing which users exist and which don't. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(location, storage->storage_class_name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append_c(location, ':');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* use a reachable but nonexistent path as the mail root directory */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(location, storage->storage.user->set->base_dir);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(location, "/user-not-found/");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(location, username);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool shared_namespace_exists(struct mail_namespace *ns)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct stat st;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen path = mailbox_list_get_root_forced(ns->list, MAILBOX_LIST_PATH_TYPE_DIR);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (path == NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we can't know if this exists */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return stat(path, &st) == 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint shared_storage_get_namespace(struct mail_namespace **_ns,
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen const char **_name)
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_storage *_storage = (*_ns)->storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_list *list = (*_ns)->list;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct shared_storage *storage = (struct shared_storage *)_storage;
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen struct mail_user *user = _storage->user;
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen static struct var_expand_table static_tab[] = {
547e916f4e6f01af682f8b6e032c337f2a699364Timo Sirainen { 'u', NULL, "user" },
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen { 'n', NULL, "username" },
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen { 'd', NULL, "domain" },
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen { 'h', NULL, "home" },
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen { '\0', NULL, NULL }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen };
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen struct var_expand_table *tab;
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen struct mail_namespace *new_ns, *ns = *_ns;
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen struct mail_namespace_settings *ns_set, *unexpanded_ns_set;
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen struct mail_user *owner;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *domain = NULL, *username = NULL, *userdomain = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *name, *p, *next, **dest, *error;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *prefix, *location;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen char ns_sep = mail_namespace_get_sep(ns);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen p = storage->ns_prefix_pattern;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (name = *_name; *p != '\0';) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*p != '%') {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*p != *name)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen p++; name++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen continue;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen switch (*++p) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case 'd':
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dest = &domain;
46219292a55094fa49aae33eee681ed075d30e17Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case 'n':
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dest = &username;
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case 'u':
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dest = &userdomain;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen default:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we checked this already above */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_unreached();
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen p++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen next = strchr(name, *p != '\0' ? *p : ns_sep);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (next == NULL) {
888ab4e17f7441b4dcca4a01886d055b57f4586dTimo Sirainen *dest = name;
888ab4e17f7441b4dcca4a01886d055b57f4586dTimo Sirainen name = "";
888ab4e17f7441b4dcca4a01886d055b57f4586dTimo Sirainen break;
888ab4e17f7441b4dcca4a01886d055b57f4586dTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *dest = t_strdup_until(name, next);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen name = next;
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen }
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (*p != '\0') {
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (*name == '\0' ||
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen (name[1] == '\0' && *name == ns_sep)) {
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen /* trying to open <prefix>/<user> mailbox */
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen name = "INBOX";
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_list_set_critical(list,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Invalid namespace prefix %s vs %s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen storage->ns_prefix_pattern, *_name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* successfully matched the name. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (userdomain != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* user@domain given */
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen domain = strchr(userdomain, '@');
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen if (domain == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen username = userdomain;
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen else {
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen username = t_strdup_until(userdomain, domain);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen domain++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (username == NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* trying to open namespace "shared/domain"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen namespace prefix. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(*_name));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
5539418f448cd9bb38fc085e654861479dd1130bTimo Sirainen if (domain == NULL) {
5539418f448cd9bb38fc085e654861479dd1130bTimo Sirainen /* no domain given, use ours (if we have one) */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen domain = strchr(user->username, '@');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (domain != NULL) domain++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen userdomain = domain == NULL ? username :
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen t_strconcat(username, "@", domain, NULL);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*userdomain == '\0') {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Empty username doesn't exist");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
bca919b207e27d0d08b431bdb0f2ac099ef8b512Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen /* expand the namespace prefix and see if it already exists.
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen this should normally happen only when the mailbox is being opened */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen tab = t_malloc(sizeof(static_tab));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen memcpy(tab, static_tab, sizeof(static_tab));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen tab[0].value = userdomain;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen tab[1].value = username;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen tab[2].value = domain;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen prefix = t_str_new(128);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen str_append(prefix, ns->prefix);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen var_expand(prefix, storage->ns_prefix_pattern, tab);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *_ns = mail_namespace_find_prefix(user->namespaces, str_c(prefix));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*_ns != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *_name = mailbox_list_get_storage_name(ns->list,
438f12d7a776da695019114884b48188d94613efTimo Sirainen t_strconcat(ns->prefix, name, NULL));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen owner = mail_user_alloc(userdomain, user->set_info,
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen user->unexpanded_set);
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen owner->autocreated = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_user_init(owner, &error) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!owner->nonexistent) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_list_set_critical(list,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Couldn't create namespace '%s' for user %s: %s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ns->prefix, userdomain, error);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_user_unref(&owner);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (!var_has_key(storage->location, 'h', "home")) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we'll need to look up the user's home directory */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ret = mail_user_get_home(owner, &tab[3].value)) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_list_set_critical(list, "Namespace '%s': "
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "Could not lookup home for user %s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ns->prefix, userdomain);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_user_unref(&owner);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* create the new namespace */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns = i_new(struct mail_namespace, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns->refcount = 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns->type = MAIL_NAMESPACE_TYPE_SHARED;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns->user = user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns->prefix = i_strdup(str_c(prefix));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns->owner = owner;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns->flags = (NAMESPACE_FLAG_SUBSCRIPTIONS & ns->flags) |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen NAMESPACE_FLAG_AUTOCREATED | NAMESPACE_FLAG_INBOX_ANY;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns->mail_set = _storage->set;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_array_init(&new_ns->all_storages, 2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen location = t_str_new(256);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret > 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen var_expand(location, storage->location, tab);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen get_nonexistent_user_location(storage, userdomain, location);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_ns->flags |= NAMESPACE_FLAG_UNUSABLE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ns->user->mail_debug) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("shared: Tried to access mails of "
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen "nonexistent user %s", userdomain);
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
ns_set = p_new(user->pool, struct mail_namespace_settings, 1);
ns_set->type = "shared";
ns_set->separator = p_strdup_printf(user->pool, "%c", ns_sep);
ns_set->prefix = new_ns->prefix;
ns_set->location = p_strdup(user->pool, str_c(location));
ns_set->hidden = TRUE;
ns_set->list = "yes";
new_ns->set = ns_set;
unexpanded_ns_set =
p_new(user->pool, struct mail_namespace_settings, 1);
*unexpanded_ns_set = *ns_set;
unexpanded_ns_set->location =
p_strdup(user->pool, storage->unexpanded_location);
new_ns->unexpanded_set = unexpanded_ns_set;
/* We need to create a prefix="" namespace for the owner */
if (mail_namespaces_init_location(owner, str_c(location), &error) < 0) {
/* owner gets freed by namespace deinit */
mail_namespace_destroy(new_ns);
return -1;
}
if (mail_storage_create(new_ns, NULL, _storage->flags |
MAIL_STORAGE_FLAG_NO_AUTOVERIFY, &error) < 0) {
mailbox_list_set_critical(list, "Namespace '%s': %s",
new_ns->prefix, error);
/* owner gets freed by namespace deinit */
mail_namespace_destroy(new_ns);
return -1;
}
if ((new_ns->flags & NAMESPACE_FLAG_UNUSABLE) == 0 &&
!shared_namespace_exists(new_ns)) {
/* this user doesn't have a usable storage */
new_ns->flags |= NAMESPACE_FLAG_UNUSABLE;
}
/* mark the shared namespace root as usable, since it now has
child namespaces */
ns->flags |= NAMESPACE_FLAG_USABLE;
*_name = mailbox_list_get_storage_name(new_ns->list,
t_strconcat(new_ns->prefix, name, NULL));
*_ns = new_ns;
if (_storage->class_flags == 0) {
/* flags are unset if we were using "auto" storage */
_storage->class_flags =
mail_namespace_get_default_storage(new_ns)->class_flags;
}
mail_user_add_namespace(user, &new_ns);
return 0;
}
struct mail_storage shared_storage = {
.name = MAIL_SHARED_STORAGE_NAME,
.class_flags = 0, /* unknown at this point */
.v = {
NULL,
shared_storage_alloc,
shared_storage_create,
index_storage_destroy,
NULL,
shared_storage_get_list_settings,
NULL,
fail_mailbox_alloc,
NULL
}
};