]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added initial support for shared mailboxes. Listing isn't supported yet.
authorTimo Sirainen <tss@iki.fi>
Sun, 7 Sep 2008 19:34:11 +0000 (22:34 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 7 Sep 2008 19:34:11 +0000 (22:34 +0300)
Each user gets their own hidden namespace created automatically when they're
accessed the first time.

--HG--
branch : HEAD

12 files changed:
configure.in
src/lib-storage/index/Makefile.am
src/lib-storage/index/shared/Makefile.am [new file with mode: 0644]
src/lib-storage/index/shared/shared-list.c [new file with mode: 0644]
src/lib-storage/index/shared/shared-storage.c [new file with mode: 0644]
src/lib-storage/index/shared/shared-storage.h [new file with mode: 0644]
src/lib-storage/mail-namespace.c
src/lib-storage/mail-storage.c
src/lib-storage/mail-storage.h
src/lib-storage/mail-user.c
src/lib-storage/mail-user.h
src/lib-storage/register/Makefile.am

index a636ad3f14069a773e104877da6f4d4b46d506b9..79fec87e238259313e3d36df0af6db184915bb26 100644 (file)
@@ -362,12 +362,12 @@ AM_CONDITIONAL(BUILD_DELIVER, test "$want_deliver" = "yes")
 
 AC_ARG_WITH(storages,
 [  --with-storages         Build with specified mail storage formats
-                          (maildir mbox dbox cydir raw)], [
+                          (maildir mbox dbox cydir shared raw)], [
        if test "$withval" = "yes" -o "$withval" = "no"; then
                AC_MSG_ERROR([--with-storages needs storage list as parameter])
        fi
        mail_storages=`echo "$withval"|sed 's/,/ /g'` ],
-       mail_storages="maildir mbox dbox cydir raw")
+       mail_storages="maildir mbox dbox cydir shared raw")
 AC_SUBST(mail_storages)
 
 AC_ARG_WITH(sql-drivers,
@@ -2238,6 +2238,7 @@ mbox_libs='$(top_builddir)/src/lib-storage/index/mbox/libstorage_mbox.a'
 dbox_libs='$(top_builddir)/src/lib-storage/index/dbox/libstorage_dbox.a'
 cydir_libs='$(top_builddir)/src/lib-storage/index/cydir/libstorage_cydir.a'
 raw_libs='$(top_builddir)/src/lib-storage/index/raw/libstorage_raw.a'
+shared_libs='$(top_builddir)/src/lib-storage/index/shared/libstorage_shared.a'
 CORE_LIBS='$(top_builddir)/src/lib-storage/index/libstorage_index.a $(top_builddir)/src/lib-storage/libstorage.a $(top_builddir)/src/lib-index/libindex.a'
 
 deliver_storage="raw"
@@ -2404,6 +2405,7 @@ src/lib-storage/index/mbox/Makefile
 src/lib-storage/index/dbox/Makefile
 src/lib-storage/index/cydir/Makefile
 src/lib-storage/index/raw/Makefile
+src/lib-storage/index/shared/Makefile
 src/lib-storage/register/Makefile
 src/auth/Makefile
 src/deliver/Makefile
index 06e85554a7476f1459f24880e0ad3bdeb8823349..67cd3a61a0ab4a99d333b59252382d56698174e4 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = maildir mbox dbox cydir raw
+SUBDIRS = maildir mbox dbox cydir raw shared
 
 noinst_LIBRARIES = libstorage_index.a
 
diff --git a/src/lib-storage/index/shared/Makefile.am b/src/lib-storage/index/shared/Makefile.am
new file mode 100644 (file)
index 0000000..708821a
--- /dev/null
@@ -0,0 +1,23 @@
+noinst_LIBRARIES = libstorage_shared.a
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-mail \
+       -I$(top_srcdir)/src/lib-imap \
+       -I$(top_srcdir)/src/lib-index \
+       -I$(top_srcdir)/src/lib-storage \
+       -I$(top_srcdir)/src/lib-storage/index
+
+libstorage_shared_a_SOURCES = \
+       shared-list.c \
+       shared-storage.c
+
+headers = \
+       shared-storage.h
+
+if INSTALL_HEADERS
+  pkginc_libdir=$(pkgincludedir)/src/lib-storage/index/shared
+  pkginc_lib_HEADERS = $(headers)
+else
+  noinst_HEADERS = $(headers)
+endif
diff --git a/src/lib-storage/index/shared/shared-list.c b/src/lib-storage/index/shared/shared-list.c
new file mode 100644 (file)
index 0000000..b918ec9
--- /dev/null
@@ -0,0 +1,269 @@
+/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "mailbox-list-private.h"
+#include "shared-storage.h"
+
+struct shared_mailbox_list_iterate_context {
+       struct mailbox_list_iterate_context ctx;
+};
+
+extern struct mailbox_list shared_mailbox_list;
+
+static struct mailbox_list *shared_list_alloc(void)
+{
+       struct mailbox_list *list;
+       pool_t pool;
+
+       pool = pool_alloconly_create("shared list", 256);
+       list = p_new(pool, struct mailbox_list, 1);
+       *list = shared_mailbox_list;
+       list->pool = pool;
+       return list;
+}
+
+static void shared_list_deinit(struct mailbox_list *list)
+{
+       pool_unref(&list->pool);
+}
+
+static void shared_list_copy_error(struct mailbox_list *shared_list,
+                                  struct mail_namespace *backend_ns)
+{
+       const char *str;
+       enum mail_error error;
+
+       str = mailbox_list_get_last_error(backend_ns->list, &error);
+       mailbox_list_set_error(shared_list, error, str);
+}
+
+static bool
+shared_is_valid_pattern(struct mailbox_list *list, const char *pattern)
+{
+       struct mail_namespace *ns;
+
+       if (shared_storage_get_namespace(list->ns->storage, &pattern, &ns) < 0)
+               return FALSE;
+       return mailbox_list_is_valid_pattern(ns->list, pattern);
+}
+
+static bool
+shared_is_valid_existing_name(struct mailbox_list *list, const char *name)
+{
+       struct mail_namespace *ns;
+
+       if (shared_storage_get_namespace(list->ns->storage, &name, &ns) < 0)
+               return FALSE;
+       return mailbox_list_is_valid_existing_name(ns->list, name);
+}
+
+static bool
+shared_is_valid_create_name(struct mailbox_list *list, const char *name)
+{
+       struct mail_namespace *ns;
+
+       if (shared_storage_get_namespace(list->ns->storage, &name, &ns) < 0)
+               return FALSE;
+       return mailbox_list_is_valid_create_name(ns->list, name);
+}
+
+static const char *
+shared_list_get_path(struct mailbox_list *list, const char *name,
+                    enum mailbox_list_path_type type)
+{
+       struct mail_namespace *ns;
+
+       if (list->ns->storage == NULL ||
+           shared_storage_get_namespace(list->ns->storage, &name, &ns) < 0) {
+               switch (type) {
+               case MAILBOX_LIST_PATH_TYPE_DIR:
+               case MAILBOX_LIST_PATH_TYPE_MAILBOX:
+               case MAILBOX_LIST_PATH_TYPE_CONTROL:
+                       break;
+               case MAILBOX_LIST_PATH_TYPE_INDEX:
+                       /* we can safely say we don't use indexes */
+                       return "";
+               }
+               i_panic("shared mailbox list: Can't return path for '%s'",
+                       list->ns->prefix);
+       }
+       return mailbox_list_get_path(ns->list, name, type);
+}
+
+static int
+shared_list_get_mailbox_name_status(struct mailbox_list *list, const char *name,
+                                   enum mailbox_name_status *status_r)
+{
+       struct mail_namespace *ns;
+       int ret;
+
+       if (shared_storage_get_namespace(list->ns->storage, &name, &ns) < 0)
+               return -1;
+       ret = mailbox_list_get_mailbox_name_status(ns->list, name, status_r);
+       if (ret < 0)
+               shared_list_copy_error(list, ns);
+       return ret;
+}
+
+static const char *
+shared_list_get_temp_prefix(struct mailbox_list *list, bool global ATTR_UNUSED)
+{
+       i_panic("shared mailbox list: Can't return a temp prefix for '%s'",
+               list->ns->prefix);
+       return NULL;
+}
+
+static const char *
+shared_list_join_refpattern(struct mailbox_list *list,
+                           const char *ref, const char *pattern)
+{
+       struct mail_namespace *ns;
+
+       if (*ref != '\0' &&
+           shared_storage_get_namespace(list->ns->storage, &ref, &ns) == 0)
+               return mailbox_list_join_refpattern(ns->list, ref, pattern);
+
+       if (*ref == '\0' &&
+           shared_storage_get_namespace(list->ns->storage, &pattern, &ns) == 0)
+               return mailbox_list_join_refpattern(ns->list, "", pattern);
+
+       /* fallback to default behavior */
+       if (*ref != '\0')
+               pattern = t_strconcat(ref, pattern, NULL);
+       return pattern;
+}
+
+static struct mailbox_list_iterate_context *
+shared_list_iter_init(struct mailbox_list *list, const char *const *patterns,
+                     enum mailbox_list_iter_flags flags)
+{
+       struct shared_mailbox_list_iterate_context *ctx;
+
+       ctx = i_new(struct shared_mailbox_list_iterate_context, 1);
+       ctx->ctx.list = list;
+       ctx->ctx.flags = flags;
+
+       /* FIXME */
+       return &ctx->ctx;
+}
+
+static const struct mailbox_info *
+shared_list_iter_next(struct mailbox_list_iterate_context *_ctx)
+{
+       struct shared_mailbox_list_iterate_context *ctx =
+               (struct shared_mailbox_list_iterate_context *)_ctx;
+
+       return NULL;
+}
+
+static int shared_list_iter_deinit(struct mailbox_list_iterate_context *_ctx)
+{
+       struct shared_mailbox_list_iterate_context *ctx =
+               (struct shared_mailbox_list_iterate_context *)_ctx;
+
+       i_free(ctx);
+       return -1;
+}
+
+static int shared_list_set_subscribed(struct mailbox_list *list,
+                                     const char *name, bool set)
+{
+       struct mail_namespace *ns;
+       int ret;
+
+       if (shared_storage_get_namespace(list->ns->storage, &name, &ns) < 0)
+               return -1;
+       ret = mailbox_list_set_subscribed(ns->list, name, set);
+       if (ret < 0)
+               shared_list_copy_error(list, ns);
+       return ret;
+}
+
+static int
+shared_list_delete_mailbox(struct mailbox_list *list, const char *name)
+{
+       struct mail_namespace *ns;
+       int ret;
+
+       if (shared_storage_get_namespace(list->ns->storage, &name, &ns) < 0)
+               return -1;
+       ret = mailbox_list_delete_mailbox(ns->list, name);
+       if (ret < 0)
+               shared_list_copy_error(list, ns);
+       return ret;
+}
+
+static int shared_list_rename_get_ns(struct mailbox_list *list,
+                                    const char **oldname, const char **newname,
+                                    struct mail_namespace **ns_r)
+{
+       struct mail_namespace *old_ns, *new_ns;
+
+       if (shared_storage_get_namespace(list->ns->storage,
+                                        oldname, &old_ns) < 0 ||
+           shared_storage_get_namespace(list->ns->storage,
+                                        newname, &new_ns) < 0)
+               return -1;
+       if (old_ns != new_ns) {
+               mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+                       "Can't rename mailboxes across storages");
+               return -1;
+       }
+       *ns_r = old_ns;
+       return 0;
+}
+
+static int shared_list_rename_mailbox(struct mailbox_list *list,
+                                     const char *oldname, const char *newname)
+{
+       struct mail_namespace *ns;
+       int ret;
+
+       if (shared_list_rename_get_ns(list, &oldname, &newname, &ns) < 0)
+               return -1;
+       ret = mailbox_list_rename_mailbox(ns->list, oldname, newname);
+       if (ret < 0)
+               shared_list_copy_error(list, ns);
+       return ret;
+}
+
+static int
+shared_list_rename_mailbox_pre(struct mailbox_list *list,
+                              const char *oldname, const char *newname)
+{
+       struct mail_namespace *ns;
+       int ret;
+
+       if (shared_list_rename_get_ns(list, &oldname, &newname, &ns) < 0)
+               return -1;
+       ret = ns->list->v.rename_mailbox_pre(ns->list, oldname, newname);
+       if (ret < 0)
+               shared_list_copy_error(list, ns);
+       return ret;
+}
+
+struct mailbox_list shared_mailbox_list = {
+       MEMBER(name) "shared",
+       MEMBER(hierarchy_sep) '/',
+       MEMBER(mailbox_name_max_length) PATH_MAX,
+
+       {
+               shared_list_alloc,
+               shared_list_deinit,
+               shared_is_valid_pattern,
+               shared_is_valid_existing_name,
+               shared_is_valid_create_name,
+               shared_list_get_path,
+               shared_list_get_mailbox_name_status,
+               shared_list_get_temp_prefix,
+               shared_list_join_refpattern,
+               shared_list_iter_init,
+               shared_list_iter_next,
+               shared_list_iter_deinit,
+               NULL,
+               shared_list_set_subscribed,
+               shared_list_delete_mailbox,
+               shared_list_rename_mailbox,
+               shared_list_rename_mailbox_pre
+       }
+};
diff --git a/src/lib-storage/index/shared/shared-storage.c b/src/lib-storage/index/shared/shared-storage.c
new file mode 100644 (file)
index 0000000..49bdc74
--- /dev/null
@@ -0,0 +1,262 @@
+/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "var-expand.h"
+#include "shared-storage.h"
+
+#define SHARED_LIST_CONTEXT(obj) \
+       MODULE_CONTEXT(obj, shared_mailbox_list_module)
+
+extern struct mail_storage shared_storage;
+extern struct mailbox shared_mailbox;
+
+static MODULE_CONTEXT_DEFINE_INIT(shared_mailbox_list_module,
+                                 &mailbox_list_module_register);
+
+static struct mail_storage *shared_alloc(void)
+{
+       struct shared_storage *storage;
+       pool_t pool;
+
+       pool = pool_alloconly_create("shared storage", 256);
+       storage = p_new(pool, struct shared_storage, 1);
+       storage->storage = shared_storage;
+       storage->storage.pool = pool;
+
+       return &storage->storage;
+}
+
+static int shared_create(struct mail_storage *_storage, const char *data,
+                        const char **error_r)
+{
+       struct shared_storage *storage = (struct shared_storage *)_storage;
+       struct mailbox_list_settings list_set;
+       const char *driver, *p;
+       bool have_username;
+
+       /* data must begin with the actual mailbox driver */
+       p = strchr(data, ':');
+       if (p == NULL) {
+               *error_r = "Shared mailbox location not prefixed with driver";
+               return -1;
+       }
+       driver = t_strdup_until(data, p);
+       storage->location = p_strdup(_storage->pool, data);
+       storage->storage_class = mail_storage_find_class(driver);
+       if (storage->storage_class == NULL) {
+               *error_r = t_strconcat("Unknown shared storage driver: ",
+                                      driver, NULL);
+               return -1;
+       }
+       _storage->mailbox_is_file = storage->storage_class->mailbox_is_file;
+
+       p = strchr(_storage->ns->prefix, '%');
+       if (p == NULL) {
+               *error_r = "Shared namespace prefix doesn't contain %";
+               return -1;
+       }
+       storage->ns_prefix_pattern = p_strdup(_storage->pool, p);
+       _storage->ns->prefix = p_strdup_until(_storage->ns->user->pool,
+                                             _storage->ns->prefix, p);
+
+       have_username = FALSE;
+       for (p = storage->ns_prefix_pattern; *p != '\0'; p++) {
+               if (*p != '%')
+                       continue;
+               if (*++p == '\0')
+                       break;
+               if (*p == 'u' || *p == 'n')
+                       have_username = TRUE;
+               else if (*p != 'd')
+                       break;
+       }
+       if (*p != '\0') {
+               *error_r = "Shared namespace prefix contains unknown variables";
+               return -1;
+       }
+       if (!have_username) {
+               *error_r = "Shared namespace prefix doesn't contain %u or %n";
+               return -1;
+       }
+
+       if (mailbox_list_alloc("shared", &_storage->list, error_r) < 0)
+               return -1;
+       MODULE_CONTEXT_SET_FULL(_storage->list, shared_mailbox_list_module,
+                               storage, &storage->list_module_ctx);
+
+       memset(&list_set, 0, sizeof(list_set));
+       list_set.mail_storage_flags = &_storage->flags;
+       list_set.lock_method = &_storage->lock_method;
+       mailbox_list_init(_storage->list, _storage->ns, &list_set,
+                         mail_storage_get_list_flags(_storage->flags));
+       return 0;
+}
+
+int shared_storage_get_namespace(struct mail_storage *_storage,
+                                const char **_name,
+                                struct mail_namespace **ns_r)
+{
+       struct shared_storage *storage = (struct shared_storage *)_storage;
+       struct mail_user *user = _storage->ns->user;
+       static struct var_expand_table static_tab[] = {
+               { 'u', NULL },
+               { 'n', NULL },
+               { 'd', NULL },
+               { '\0', NULL }
+       };
+       struct var_expand_table *tab;
+       struct mail_namespace *ns;
+       const char *domain = NULL, *username = NULL, *userdomain = NULL;
+       const char *name, *p, *next, **dest, *error;
+       string_t *prefix, *location;
+
+       p = storage->ns_prefix_pattern;
+       for (name = *_name; *p != '\0';) {
+               if (*p != '%') {
+                       if (*p != *name)
+                               return -1;
+                       p++; name++;
+                       continue;
+               }
+               switch (*++p) {
+               case 'd':
+                       dest = &domain;
+                       break;
+               case 'n':
+                       dest = &username;
+                       break;
+               case 'u':
+                       dest = &userdomain;
+                       break;
+               default:
+                       /* we checked this already above */
+                       i_unreached();
+               }
+               p++;
+
+               next = strchr(name, *p != '\0' ? *p : _storage->ns->sep);
+               if (next == NULL)
+                       return -1;
+
+               *dest = t_strdup_until(name, next);
+               name = next;
+       }
+       /* successfully matched the name. */
+       if (userdomain == NULL) {
+               i_assert(username != NULL);
+               userdomain = domain == NULL ? username :
+                       t_strconcat(username, "@", domain, NULL);
+       } else {
+               domain = strchr(userdomain, '@');
+               if (domain == NULL)
+                       username = userdomain;
+               else {
+                       username = t_strdup_until(userdomain, domain);
+                       domain++;
+               }
+       }
+
+       /* expand the namespace prefix and see if it already exists.
+          this should normally happen only when the mailbox is being opened */
+       tab = t_malloc(sizeof(static_tab));
+       memcpy(tab, static_tab, sizeof(static_tab));
+       tab[0].value = userdomain;
+       tab[1].value = username;
+       tab[2].value = domain;
+       prefix = t_str_new(128);
+       str_append(prefix, _storage->ns->prefix);
+       var_expand(prefix, storage->ns_prefix_pattern, tab);
+
+       ns = mail_namespace_find_prefix(user->namespaces, str_c(prefix));
+       if (ns != NULL) {
+               *_name = name;
+               *ns_r = ns;
+               return 0;
+       }
+
+       /* create the new namespace */
+       ns = p_new(user->pool, struct mail_namespace, 1);
+       ns->type = NAMESPACE_SHARED;
+       ns->user = user;
+       ns->prefix = p_strdup(user->pool, str_c(prefix));
+       ns->flags = NAMESPACE_FLAG_LIST | NAMESPACE_FLAG_HIDDEN;
+
+       location = t_str_new(256);
+       var_expand(location, storage->location, tab);
+       if (mail_storage_create(ns, NULL, str_c(location), _storage->flags,
+                               _storage->lock_method, &error) < 0) {
+               i_error("Namespace '%s': %s", ns->prefix, error);
+               return -1;
+       }
+       /* FIXME: we could remove namespaces here that don't have usable
+          mailboxes. otherwise the memory usage could just keep growing. */
+       mail_user_add_namespace(user, ns);
+
+       *_name = name;
+       *ns_r = ns;
+       return 0;
+}
+
+static void shared_mailbox_copy_error(struct mail_storage *shared_storage,
+                                     struct mail_namespace *backend_ns)
+{
+       const char *str;
+       enum mail_error error;
+
+       str = mail_storage_get_last_error(backend_ns->storage, &error);
+       mail_storage_set_error(shared_storage, error, str);
+}
+
+static struct mailbox *
+shared_mailbox_open(struct mail_storage *storage, const char *name,
+                   struct istream *input, enum mailbox_open_flags flags)
+{
+       struct mail_namespace *ns;
+       struct mailbox *box;
+
+       if (input != NULL) {
+               mail_storage_set_critical(storage,
+                       "Shared storage doesn't support streamed mailboxes");
+               return NULL;
+       }
+
+       if (shared_storage_get_namespace(storage, &name, &ns) < 0)
+               return NULL;
+
+       box = mailbox_open(ns->storage, name, NULL, flags);
+       if (box == NULL)
+               shared_mailbox_copy_error(storage, ns);
+       return box;
+}
+
+static int shared_mailbox_create(struct mail_storage *storage,
+                                const char *name, bool directory)
+{
+       struct mail_namespace *ns;
+       int ret;
+
+       if (shared_storage_get_namespace(storage, &name, &ns) < 0)
+               return -1;
+       ret = mail_storage_mailbox_create(ns->storage, name, directory);
+       if (ret < 0)
+               shared_mailbox_copy_error(storage, ns);
+       return ret;
+}
+
+struct mail_storage shared_storage = {
+       MEMBER(name) SHARED_STORAGE_NAME,
+       MEMBER(mailbox_is_file) FALSE, /* unknown at this point */
+
+       {
+               NULL,
+               NULL,
+               shared_alloc,
+               shared_create,
+               index_storage_destroy,
+               NULL,
+               shared_mailbox_open,
+               shared_mailbox_create
+       }
+};
diff --git a/src/lib-storage/index/shared/shared-storage.h b/src/lib-storage/index/shared/shared-storage.h
new file mode 100644 (file)
index 0000000..e16886f
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SHARED_STORAGE_H
+#define SHARED_STORAGE_H
+
+#include "index-storage.h"
+#include "mailbox-list-private.h"
+
+#define SHARED_STORAGE_NAME "shared"
+
+struct shared_storage {
+       struct mail_storage storage;
+       union mailbox_list_module_context list_module_ctx;
+
+       const char *ns_prefix_pattern;
+       const char *location;
+
+       struct mail_storage *storage_class;
+};
+
+struct mailbox_list *shared_mailbox_list_alloc(void);
+
+int shared_storage_get_namespace(struct mail_storage *storage,
+                                const char **name,
+                                struct mail_namespace **ns_r);
+
+#endif
index 893f70df299c0d0e40109df8b0ff10dad9d5aee2..7e856d80bb665b923623f887d08fd16f798ce5be 100644 (file)
@@ -33,7 +33,7 @@ namespace_add_env(const char *data, unsigned int num,
                  enum file_lock_method lock_method)
 {
         struct mail_namespace *ns;
-       const char *sep, *type, *prefix, *error;
+       const char *sep, *type, *prefix, *driver, *error;
 
        ns = p_new(user->pool, struct mail_namespace, 1);
 
@@ -79,7 +79,14 @@ namespace_add_env(const char *data, unsigned int num,
        ns->prefix = p_strdup(user->pool, prefix);
        ns->user = user;
 
-       if (mail_storage_create(ns, NULL, data, flags, lock_method,
+       if (ns->type == NAMESPACE_SHARED && strchr(ns->prefix, '%') != NULL) {
+               /* dynamic shared namespace */
+               driver = "shared";
+       } else {
+               driver = NULL;
+       }
+
+       if (mail_storage_create(ns, driver, data, flags, lock_method,
                                &error) < 0) {
                i_error("Namespace '%s': %s", ns->prefix, error);
                return NULL;
@@ -160,24 +167,6 @@ static bool namespaces_check(struct mail_namespace *namespaces)
        return TRUE;
 }
 
-static struct mail_namespace *
-namespaces_sort(struct mail_namespace *src)
-{
-       struct mail_namespace **tmp, *next, *dest = NULL;
-
-       for (; src != NULL; src = next) {
-               next = src->next;
-
-               for (tmp = &dest; *tmp != NULL; tmp = &(*tmp)->next) {
-                       if (strlen(src->prefix) < strlen((*tmp)->prefix))
-                               break;
-               }
-               src->next = *tmp;
-               *tmp = src;
-       }
-       return dest;
-}
-
 int mail_namespaces_init(struct mail_user *user)
 {
        struct mail_namespace *namespaces, *ns, **ns_p;
@@ -212,8 +201,7 @@ int mail_namespaces_init(struct mail_user *user)
        if (namespaces != NULL) {
                if (!namespaces_check(namespaces))
                        return -1;
-               namespaces = namespaces_sort(namespaces);
-               user->namespaces = namespaces;
+               mail_user_add_namespace(user, namespaces);
 
                if (hook_mail_namespaces_created != NULL) {
                        T_BEGIN {
index 41cce6c42e071d4fda2bb688742b272dbe0afee5..867fb5001bccb41b9a62f1638338bfc0235f917c 100644 (file)
@@ -119,7 +119,7 @@ void mail_storage_parse_env(enum mail_storage_flags *flags_r,
                i_fatal("Unknown lock_method: %s", str);
 }
 
-static struct mail_storage *mail_storage_find(const char *name)
+struct mail_storage *mail_storage_find_class(const char *name)
 {
        struct mail_storage *const *classes;
        unsigned int i, count;
@@ -199,7 +199,7 @@ int mail_storage_create(struct mail_namespace *ns, const char *driver,
                classes = &storage_class;
                count = 1;
        } else {
-               storage_class = mail_storage_find(driver);
+               storage_class = mail_storage_find_class(driver);
                if (storage_class == NULL) {
                        *error_r = t_strdup_printf(
                                "Unknown mail storage driver %s", driver);
index 176808b7985ce1ea7e40ad18ba404808d94a4a06..cf851e527df621421c65928d44f09db9b134b918 100644 (file)
@@ -238,6 +238,8 @@ void mail_storage_register_all(void);
    are set to default methods */
 void mail_storage_class_register(struct mail_storage *storage_class);
 void mail_storage_class_unregister(struct mail_storage *storage_class);
+/* Find mail storage class by name */
+struct mail_storage *mail_storage_find_class(const char *name);
 
 /* Returns flags and lock_method based on environment settings. */
 void mail_storage_parse_env(enum mail_storage_flags *flags_r,
index c92e6c3e05dd3040fc7e56a543f0cbcb85f31ae0..1a15caca6390f45a21813f66eda47b79ed1db5cf 100644 (file)
@@ -42,6 +42,23 @@ void mail_user_deinit(struct mail_user **_user)
        user->v.deinit(user);
 }
 
+void mail_user_add_namespace(struct mail_user *user, struct mail_namespace *ns)
+{
+       struct mail_namespace **tmp, *next;
+
+       for (; ns != NULL; ns = next) {
+               next = ns->next;
+
+               tmp = &user->namespaces;
+               for (; *tmp != NULL; tmp = &(*tmp)->next) {
+                       if (strlen(ns->prefix) < strlen((*tmp)->prefix))
+                               break;
+               }
+               ns->next = *tmp;
+               *tmp = ns;
+       }
+}
+
 const char *mail_user_home_expand(struct mail_user *user, const char *path)
 {
        (void)mail_user_try_home_expand(user, &path);
index 9d711af9ea3fb7e7d98114227e93a2a8dc5c5251..56760ed5d959ec1ab1a3c19a61f6e78d4b00e0bd 100644 (file)
@@ -36,6 +36,9 @@ extern void (*hook_mail_user_created)(struct mail_user *user);
 struct mail_user *mail_user_init(const char *username, const char *home);
 void mail_user_deinit(struct mail_user **user);
 
+/* Add a new namespace to user's namespaces. */
+void mail_user_add_namespace(struct mail_user *user, struct mail_namespace *ns);
+
 /* Replace ~/ at the beginning of the path with the user's home directory. */
 const char *mail_user_home_expand(struct mail_user *user, const char *path);
 /* Returns 0 if ok, -1 if home directory isn't set. */
index b5ae1637e06c40cfdbf96be2417401efa8906595..55699aed91911f8d33bb5dd6a733e4f32b0ad7d4 100644 (file)
@@ -3,7 +3,7 @@ noinst_LIBRARIES = libstorage-register.a
 BUILT_SOURCES = mail-storage-register.c
 mail_storages = @mail_storages@
 
-mailbox_list_drivers = maildir imapdir fs
+mailbox_list_drivers = maildir imapdir fs shared
 
 mail-storage-register.c: Makefile
        rm -f $@