From: Timo Sirainen Date: Sun, 30 Nov 2008 00:09:16 +0000 (+0200) Subject: Added alias_for setting for namespaces. Fixes namespace issues with fts. X-Git-Tag: 1.2.alpha5~56 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=af3f857bb3166ed99595e11a9d18e5b5cc670e1a;p=thirdparty%2Fdovecot%2Fcore.git Added alias_for setting for namespaces. Fixes namespace issues with fts. --HG-- branch : HEAD --- diff --git a/src/lib-storage/mail-namespace.c b/src/lib-storage/mail-namespace.c index f7e0cedaea..d8582bd156 100644 --- a/src/lib-storage/mail-namespace.c +++ b/src/lib-storage/mail-namespace.c @@ -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) diff --git a/src/lib-storage/mail-namespace.h b/src/lib-storage/mail-namespace.h index 0cd6b94c80..b4bc997dd3 100644 --- a/src/lib-storage/mail-namespace.h +++ b/src/lib-storage/mail-namespace.h @@ -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 */ diff --git a/src/master/mail-process.c b/src/master/mail-process.c index 7e4c8a5c24..30fedc98ee 100644 --- a/src/master/mail-process.c +++ b/src/master/mail-process.c @@ -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); diff --git a/src/master/master-settings.c b/src/master/master-settings.c index a7c592a92d..63141c370c 100644 --- a/src/master/master-settings.c +++ b/src/master/master-settings.c @@ -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; } } diff --git a/src/master/master-settings.h b/src/master/master-settings.h index fd76a7a76a..7ef74c32b1 100644 --- a/src/master/master-settings.h +++ b/src/master/master-settings.h @@ -240,6 +240,7 @@ struct namespace_settings { const char *separator; const char *prefix; const char *location; + const char *alias_for; bool inbox; bool hidden; diff --git a/src/plugins/fts-solr/fts-backend-solr.c b/src/plugins/fts-solr/fts-backend-solr.c index eed251ece6..095ba8e2f7 100644 --- a/src/plugins/fts-solr/fts-backend-solr.c +++ b/src/plugins/fts-solr/fts-backend-solr.c @@ -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, "" "%u" "%u", 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, ""); - xml_encode(ctx->cmd, box->storage->ns->prefix); + xml_encode(ctx->cmd, ns->prefix); str_append(ctx->cmd, ""); } str_append(ctx->cmd, ""); xml_encode(ctx->cmd, box->name); str_append(ctx->cmd, ""); - xml_encode(ctx->cmd, box->storage->ns->user->username); + xml_encode(ctx->cmd, ns->user->username); str_append(ctx->cmd, ""); } @@ -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, diff --git a/src/plugins/fts/fts-storage.c b/src/plugins/fts/fts-storage.c index 421848c039..ee703a2cf6 100644 --- a/src/plugins/fts/fts-storage.c +++ b/src/plugins/fts/fts-storage.c @@ -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)