]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added alias_for setting for namespaces. Fixes namespace issues with fts.
authorTimo Sirainen <tss@iki.fi>
Sun, 30 Nov 2008 00:09:16 +0000 (02:09 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 30 Nov 2008 00:09:16 +0000 (02:09 +0200)
--HG--
branch : HEAD

src/lib-storage/mail-namespace.c
src/lib-storage/mail-namespace.h
src/master/mail-process.c
src/master/master-settings.c
src/master/master-settings.h
src/plugins/fts-solr/fts-backend-solr.c
src/plugins/fts/fts-storage.c

index f7e0cedaea575288969a242c75941b4244715bce..d8582bd1560fd31e55dd65c4d08c43438af932c9 100644 (file)
@@ -38,10 +38,11 @@ static void mail_namespace_free(struct mail_namespace *ns)
 static struct mail_namespace *
 namespace_add_env(const char *data, unsigned int num,
                  struct mail_user *user, enum mail_storage_flags flags,
-                 enum file_lock_method lock_method)
+                 enum file_lock_method lock_method,
+                 struct mail_namespace *prev_namespaces)
 {
         struct mail_namespace *ns;
-       const char *sep, *type, *prefix, *driver, *error, *list;
+       const char *sep, *type, *prefix, *driver, *error, *list, *alias_for;
 
        ns = i_new(struct mail_namespace, 1);
 
@@ -49,6 +50,7 @@ namespace_add_env(const char *data, unsigned int num,
        type = getenv(t_strdup_printf("NAMESPACE_%u_TYPE", num));
        prefix = getenv(t_strdup_printf("NAMESPACE_%u_PREFIX", num));
        list = getenv(t_strdup_printf("NAMESPACE_%u_LIST", num));
+       alias_for = getenv(t_strdup_printf("NAMESPACE_%u_ALIAS", num));
        if (getenv(t_strdup_printf("NAMESPACE_%u_INBOX", num)) != NULL)
                ns->flags |= NAMESPACE_FLAG_INBOX;
        if (getenv(t_strdup_printf("NAMESPACE_%u_HIDDEN", num)) != NULL)
@@ -75,6 +77,23 @@ namespace_add_env(const char *data, unsigned int num,
                return NULL;
        }
 
+       if (alias_for != NULL) {
+               ns->alias_for = mail_namespace_find_prefix(prev_namespaces,
+                                                          alias_for);
+               if (ns->alias_for == NULL) {
+                       i_error("Invalid namespace alias_for: %s", alias_for);
+                       mail_namespace_free(ns);
+                       return NULL;
+               }
+               if (ns->alias_for->alias_for != NULL) {
+                       i_error("Chained namespace alias_for: %s", alias_for);
+                       mail_namespace_free(ns);
+                       return NULL;
+               }
+               ns->alias_chain_next = ns->alias_for->alias_chain_next;
+               ns->alias_for->alias_chain_next = ns;
+       }
+
        if (prefix == NULL)
                prefix = "";
 
@@ -207,7 +226,7 @@ int mail_namespaces_init(struct mail_user *user)
 
                T_BEGIN {
                        *ns_p = namespace_add_env(data, i, user, flags,
-                                                 lock_method);
+                                                 lock_method, namespaces);
                } T_END;
 
                if (*ns_p == NULL)
index 0cd6b94c8044fdd4683ff0802d19dd60959ad5a3..b4bc997dd3e94a3b1cb31b2361afa58e110ee74e 100644 (file)
@@ -41,6 +41,16 @@ struct mail_namespace {
        char *prefix;
        size_t prefix_len;
 
+       /* If non-NULL, this points to a namespace with identical mail location
+          and it should be considered as the primary way to access the
+          mailboxes. This allows for example FTS plugin to avoid duplicating
+          indexes for same mailboxes when they're accessed via different
+          namespaces. */
+       struct mail_namespace *alias_for;
+       /* alias_for->alias_chain_next starts each chain. The chain goes
+          through all namespaces that have the same alias_for. */
+       struct mail_namespace *alias_chain_next;
+
        struct mail_user *user, *owner;
        struct mailbox_list *list;
        /* FIXME: we should support multiple storages in one namespace */
index 7e4c8a5c242c02f1996a74fea75a8349b6ff2a77..30fedc98ee3e9a0dee5079bbbd91039ab1545610 100644 (file)
@@ -268,6 +268,10 @@ env_put_namespace(struct namespace_settings *ns, const char *default_location,
                        env_put(t_strdup_printf("NAMESPACE_%u_TYPE=%s",
                                                i, ns->type));
                }
+               if (ns->alias_for != NULL) {
+                       env_put(t_strdup_printf("NAMESPACE_%u_ALIAS=%s",
+                                               i, ns->alias_for));
+               }
                if (ns->prefix != NULL) {
                        /* expand variables, eg. ~%u/ can be useful */
                        str = t_str_new(256);
index a7c592a92dc6351929ee350babe9bb811edcde4f..63141c370c46a77c341352ebe0b798e4e54160ac 100644 (file)
@@ -158,6 +158,7 @@ static struct setting_def namespace_setting_defs[] = {
        DEF_STR(separator),
        DEF_STR(prefix),
        DEF_STR(location),
+       DEF_STR(alias_for),
        DEF_BOOL(inbox),
        DEF_BOOL(hidden),
        DEF_STR(list),
@@ -359,6 +360,7 @@ struct namespace_settings default_namespace_settings = {
        MEMBER(separator) "",
        MEMBER(prefix) "",
        MEMBER(location) "",
+       MEMBER(alias_for) NULL,
 
        MEMBER(inbox) FALSE,
        MEMBER(hidden) FALSE,
@@ -489,8 +491,10 @@ static bool auth_settings_verify(struct auth_settings *auth)
        return TRUE;
 }
 
-static bool namespace_settings_verify(struct namespace_settings *ns)
+static bool namespace_settings_verify(struct server_settings *server,
+                                     struct namespace_settings *ns)
 {
+       struct namespace_settings *n;
        const char *name;
 
        name = ns->prefix != NULL ? ns->prefix : "";
@@ -510,6 +514,24 @@ static bool namespace_settings_verify(struct namespace_settings *ns)
                return FALSE;
        }
 
+       if (ns->alias_for != NULL) {
+               for (n = server->namespaces; n != ns; n = n->next) {
+                       if (strcmp(n->prefix, ns->alias_for) == 0)
+                               break;
+               }
+               if (n == NULL) {
+                       i_error("Namespace '%s': alias_for points to "
+                               "unknown namespace: %s", name, ns->alias_for);
+                       return FALSE;
+               }
+               if (n->alias_for != NULL) {
+                       i_error("Namespace '%s': alias_for chaining isn't "
+                               "allowed: %s -> %s", name, ns->alias_for,
+                               n->alias_for);
+                       return FALSE;
+               }
+       }
+
        return TRUE;
 }
 
@@ -1559,7 +1581,7 @@ bool master_settings_read(const char *path, bool nochecks, bool nofixes)
                                }
                                ns = server->namespaces;
                                for (; ns != NULL; ns = ns->next) {
-                                       if (!namespace_settings_verify(ns))
+                                       if (!namespace_settings_verify(server, ns))
                                                return FALSE;
                                }
                        }
index fd76a7a76acb7b5dd2cd4792c006212f26a21d45..7ef74c32b1acfcf7253c289750640e92a10f4130 100644 (file)
@@ -240,6 +240,7 @@ struct namespace_settings {
        const char *separator;
        const char *prefix;
        const char *location;
+       const char *alias_for;
 
        bool inbox;
        bool hidden;
index eed251ece671ad3ed088de81e131b6920e060105..095ba8e2f77c5903623eee6db654c01e2affd545 100644 (file)
@@ -127,6 +127,9 @@ fts_backend_solr_init(struct mailbox *box)
        struct mail_namespace *ns = box->storage->ns;
        const char *str;
 
+       while (ns->alias_for != NULL)
+               ns = ns->alias_for;
+
        if (solr_conn == NULL)
                solr_conn = solr_connection_init(set->url, set->debug);
 
@@ -143,9 +146,12 @@ fts_backend_solr_init(struct mailbox *box)
                backend->default_ns =
                        mail_namespace_find_inbox(ns->user->namespaces);
        }
+       while (backend->default_ns->alias_for != NULL)
+               backend->default_ns = backend->default_ns->alias_for;
+
        str = solr_escape_id_str(ns->user->username);
        backend->id_username = i_strdup(str);
-       if (box->storage->ns != backend->default_ns) {
+       if (ns != backend->default_ns) {
                str = solr_escape_id_str(ns->prefix);
                backend->id_namespace = i_strdup(str);
        }
@@ -171,6 +177,9 @@ solr_add_ns_query(string_t *str, struct fts_backend *_backend,
 {
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
 
+       while (ns->alias_for != NULL)
+               ns = ns->alias_for;
+
        if (ns == backend->default_ns || *ns->prefix == '\0')
                str_append(str, " -ns:[* TO *]");
        else {
@@ -268,23 +277,17 @@ static int fts_backend_solr_get_last_uid(struct fts_backend *backend,
        return 0;
 }
 
-static const char *
-solr_get_vmailbox(struct fts_backend *_backend,
-                 struct mailbox *box, const char *ns_prefix,
-                 const char *mailbox, string_t *dest)
+static struct mail_namespace *
+solr_get_namespaces(struct fts_backend *_backend,
+                   struct mailbox *box, const char *ns_prefix)
 {
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
        struct mail_namespace *namespaces = box->storage->ns->user->namespaces;
-       struct mail_namespace *ns;
 
        if (ns_prefix == NULL)
-               ns = backend->default_ns;
-       else {
-               ns = mail_namespace_find_prefix(namespaces, ns_prefix);
-               if (ns == NULL)
-                       return FALSE;
-       }
-       return mail_namespace_get_vname(ns, dest, mailbox);
+               return backend->default_ns;
+       else
+               return mail_namespace_find_prefix(namespaces, ns_prefix);
 }
 
 static bool
@@ -293,15 +296,17 @@ solr_virtual_get_last_uids(const char *ns_prefix, const char *mailbox,
 {
        struct fts_backend_solr_get_last_uids_context *ctx = context;
        struct fts_backend_uid_map *map;
+       struct mail_namespace *ns;
        const char *vname;
 
-       vname = solr_get_vmailbox(ctx->backend, ctx->box, ns_prefix,
-                                 mailbox, ctx->vname);
-
-       map = array_append_space(ctx->last_uids);
-       map->mailbox = p_strdup(ctx->pool, vname);
-       map->uidvalidity = uidvalidity;
-       map->uid = *uid;
+       ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix);
+       for (; ns != NULL; ns = ns->alias_chain_next) {
+               vname = mail_namespace_get_vname(ns, ctx->vname, mailbox);
+               map = array_append_space(ctx->last_uids);
+               map->mailbox = p_strdup(ctx->pool, vname);
+               map->uidvalidity = uidvalidity;
+               map->uid = *uid;
+       }
        return FALSE;
 }
 
@@ -344,6 +349,7 @@ fts_backend_solr_filter_mailboxes(struct fts_backend *_backend,
 {
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
        ARRAY_TYPE(mailbox_virtual_patterns) includes_arr, excludes_arr;
+       struct mail_namespace *ns;
        const struct mailbox_virtual_pattern *includes, *excludes;
        unsigned int i, inc_count, exc_count, len;
        string_t *fq;
@@ -386,12 +392,15 @@ fts_backend_solr_filter_mailboxes(struct fts_backend *_backend,
                str_append_c(fq, '(');
                str_append(fq, "-box:");
                solr_add_pattern(fq, &excludes[i]);
-               if (excludes[i].ns == backend->default_ns) {
+
+               for (ns = excludes[i].ns; ns->alias_for != NULL; )
+                       ns = ns->alias_for;
+               if (ns == backend->default_ns) {
                        str_append(fq, " OR NOT");
-                       solr_add_ns_query(fq, _backend, excludes[i].ns);
-               } else if (*excludes[i].ns->prefix != '\0') {
+                       solr_add_ns_query(fq, _backend, ns);
+               } else if (*ns->prefix != '\0') {
                        str_append(fq, " OR -ns:");
-                       solr_quote(fq, excludes[i].ns->prefix);
+                       solr_quote(fq, ns->prefix);
                }
                str_append_c(fq, ')');
        }
@@ -453,21 +462,25 @@ fts_backend_solr_add_doc_prefix(struct solr_fts_backend_build_context *ctx,
        struct solr_fts_backend *backend =
                (struct solr_fts_backend *)ctx->ctx.backend;
        struct mailbox *box = ctx->ctx.backend->box;
+       struct mail_namespace *ns = box->storage->ns;
 
        str_printfa(ctx->cmd, "<doc>"
                    "<field name=\"uid\">%u</field>"
                    "<field name=\"uidv\">%u</field>",
                    uid, ctx->uid_validity);
 
-       if (box->storage->ns != backend->default_ns) {
+       while (ns->alias_for != NULL)
+               ns = ns->alias_for;
+
+       if (ns != backend->default_ns) {
                str_append(ctx->cmd, "<field name=\"ns\">");
-               xml_encode(ctx->cmd, box->storage->ns->prefix);
+               xml_encode(ctx->cmd, ns->prefix);
                str_append(ctx->cmd, "</field>");
        }
        str_append(ctx->cmd, "<field name=\"box\">");
        xml_encode(ctx->cmd, box->name);
        str_append(ctx->cmd, "</field><field name=\"user\">");
-       xml_encode(ctx->cmd, box->storage->ns->user->username);
+       xml_encode(ctx->cmd, ns->user->username);
        str_append(ctx->cmd, "</field>");
 }
 
@@ -629,11 +642,17 @@ static bool solr_virtual_uid_map(const char *ns_prefix, const char *mailbox,
                                 void *context)
 {
        struct solr_virtual_uid_map_context *ctx = context;
+       struct mail_namespace *ns;
        const char *vname;
 
-       vname = solr_get_vmailbox(ctx->backend, ctx->box, ns_prefix,
-                                 mailbox, ctx->vname);
-       return mailbox_get_virtual_uid(ctx->box, vname, uidvalidity, *uid, uid);
+       ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix);
+       for (; ns != NULL; ns = ns->alias_chain_next) {
+               vname = mail_namespace_get_vname(ns, ctx->vname, mailbox);
+               if (mailbox_get_virtual_uid(ctx->box, vname, uidvalidity,
+                                           *uid, uid))
+                       return TRUE;
+       }
+       return FALSE;
 }
 
 static int fts_backend_solr_lookup(struct fts_backend_lookup_context *ctx,
index 421848c039d39b2c2311580cc75bfa9eee63ec6b..ee703a2cf6c83cb9e3806c7b31abddf86c5ef946 100644 (file)
@@ -272,8 +272,21 @@ fts_build_init_box(struct fts_search_context *fctx, struct mailbox *box,
 static int mailbox_name_cmp(const void *p1, const void *p2)
 {
        struct mailbox *const *box1 = p1, *const *box2 = p2;
+       int ret;
 
-       return strcmp((*box1)->name, (*box2)->name);
+       T_BEGIN {
+               string_t *tmp1, *tmp2;
+               const char *vname1, *vname2;
+
+               tmp1 = t_str_new(128);
+               tmp2 = t_str_new(128);
+               vname1 = mail_namespace_get_vname((*box1)->storage->ns, tmp1,
+                                                 (*box1)->name);
+               vname2 = mail_namespace_get_vname((*box2)->storage->ns, tmp2,
+                                                 (*box2)->name);
+               ret = strcmp(vname1, vname2);
+       } T_END;
+       return ret;
 }
 
 static int fts_backend_uid_map_mailbox_cmp(const void *p1, const void *p2)