]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
fts: Fixes to how virtual mailboxes are searched.
authorTimo Sirainen <tss@iki.fi>
Wed, 15 Apr 2009 23:48:55 +0000 (19:48 -0400)
committerTimo Sirainen <tss@iki.fi>
Wed, 15 Apr 2009 23:48:55 +0000 (19:48 -0400)
--HG--
branch : HEAD

src/plugins/fts-solr/fts-backend-solr.c
src/plugins/fts/fts-storage.c
src/plugins/fts/fts-storage.h

index 40ccedbde75e3f83a244fc3206e1c3a4e2fcc474..28142f61283f8f3440630832bb7e3388969db81a 100644 (file)
@@ -18,7 +18,7 @@
 
 struct solr_fts_backend {
        struct fts_backend backend;
-       char *id_username, *id_namespace;
+       char *id_username, *id_namespace, *id_box_name;
        struct mail_namespace *default_ns;
 };
 
@@ -48,6 +48,32 @@ struct fts_backend_solr_get_last_uids_context {
 
 static struct solr_connection *solr_conn = NULL;
 
+static void fts_box_name_get_root(struct mail_namespace **ns, const char **name)
+{
+       struct mail_namespace *orig_ns = *ns;
+
+       while ((*ns)->alias_for != NULL)
+               *ns = (*ns)->alias_for;
+
+       if (**name == '\0' && *ns != orig_ns &&
+           ((*ns)->flags & NAMESPACE_FLAG_INBOX) != 0) {
+               /* ugly workaround to allow selecting INBOX from a Maildir/
+                  when it's not in the inbox=yes namespace. */
+               *name = "INBOX";
+       }
+}
+
+static const char *
+fts_box_get_root(struct mailbox *box, struct mail_namespace **ns_r)
+{
+       struct mail_namespace *ns = box->storage->ns;
+       const char *name = box->name;
+
+       fts_box_name_get_root(&ns, &name);
+       *ns_r = ns;
+       return name;
+}
+
 static void
 xml_encode_data(string_t *dest, const unsigned char *data, unsigned int len)
 {
@@ -138,11 +164,12 @@ fts_backend_solr_init(struct mailbox *box)
                FTS_SOLR_USER_CONTEXT(box->storage->ns->user);
        const struct fts_solr_settings *set = &fuser->set;
        struct solr_fts_backend *backend;
-       struct mail_namespace *ns = box->storage->ns;
-       const char *str;
+       struct mail_namespace *ns;
+       const char *str, *box_name;
 
-       while (ns->alias_for != NULL)
-               ns = ns->alias_for;
+
+       box_name = fts_box_get_root(box, &ns);
+       i_assert(*box_name != '\0');
 
        if (solr_conn == NULL)
                solr_conn = solr_connection_init(set->url, set->debug);
@@ -169,6 +196,7 @@ fts_backend_solr_init(struct mailbox *box)
                str = solr_escape_id_str(ns->prefix);
                backend->id_namespace = i_strdup(str);
        }
+       backend->id_box_name = i_strdup(box_name);
        backend->backend = fts_backend_solr;
 
        if (set->substring_search)
@@ -180,6 +208,7 @@ static void fts_backend_solr_deinit(struct fts_backend *_backend)
 {
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
 
+       i_free(backend->id_box_name);
        i_free(backend->id_namespace);
        i_free(backend->id_username);
        i_free(backend);
@@ -223,21 +252,25 @@ static int fts_backend_solr_get_last_uid_fallback(struct fts_backend *backend,
                                                  uint32_t *last_uid_r)
 {
        struct mailbox *box = backend->box;
+       struct mail_namespace *ns;
        struct mailbox_status status;
        ARRAY_TYPE(seq_range) uids;
        const struct seq_range *uidvals;
+       const char *box_name;
        unsigned int count;
        string_t *str;
 
        str = t_str_new(256);
        str_append(str, "fl=uid&rows=1&sort=uid+desc&q=");
 
+       box_name = fts_box_get_root(box, &ns);
+
        mailbox_get_status(box, STATUS_UIDVALIDITY, &status);
        str_printfa(str, "uidv:%u+box:", status.uidvalidity);
-       solr_quote_http(str, box->name);
-       solr_add_ns_query_http(str, backend, box->storage->ns);
+       solr_quote_http(str, box_name);
+       solr_add_ns_query_http(str, backend, ns);
        str_append(str, "+user:");
-       solr_quote_http(str, box->storage->ns->user->username);
+       solr_quote_http(str, ns->user->username);
 
        t_array_init(&uids, 1);
        if (solr_connection_select(solr_conn, str_c(str),
@@ -261,21 +294,25 @@ static int fts_backend_solr_get_last_uid(struct fts_backend *backend,
                                         uint32_t *last_uid_r)
 {
        struct mailbox *box = backend->box;
+       struct mail_namespace *ns;
        struct mailbox_status status;
        ARRAY_TYPE(seq_range) uids;
        const struct seq_range *uidvals;
+       const char *box_name;
        unsigned int count;
        string_t *str;
 
        str = t_str_new(256);
        str_append(str, "fl=uid&rows=1&q=last_uid:TRUE+");
 
+       box_name = fts_box_get_root(box, &ns);
+
        mailbox_get_status(box, STATUS_UIDVALIDITY, &status);
        str_printfa(str, "uidv:%u+box:", status.uidvalidity);
-       solr_quote_http(str, box->name);
-       solr_add_ns_query_http(str, backend, box->storage->ns);
+       solr_quote_http(str, box_name);
+       solr_add_ns_query_http(str, backend, ns);
        str_append(str, "+user:");
-       solr_quote_http(str, box->storage->ns->user->username);
+       solr_quote_http(str, ns->user->username);
 
        t_array_init(&uids, 1);
        if (solr_connection_select(solr_conn, str_c(str),
@@ -333,12 +370,15 @@ solr_virtual_get_last_uids(const char *ns_prefix, const char *mailbox,
 static void
 solr_add_pattern(string_t *str, const struct mailbox_virtual_pattern *pattern)
 {
+       struct mail_namespace *ns = pattern->ns;
        const char *name, *p;
 
        name = pattern->pattern;
        if (!mail_namespace_update_name(pattern->ns, &name))
                name = mail_namespace_fix_sep(pattern->ns, name);
 
+       fts_box_name_get_root(&ns, &name);
+
        if (strcmp(name, "*") == 0) {
                str_append(str, "[* TO *]");
                return;
@@ -480,15 +520,15 @@ 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;
+       struct mail_namespace *ns;
+       const char *box_name;
 
        str_printfa(ctx->cmd, "<doc>"
                    "<field name=\"uid\">%u</field>"
                    "<field name=\"uidv\">%u</field>",
                    uid, ctx->uid_validity);
 
-       while (ns->alias_for != NULL)
-               ns = ns->alias_for;
+       box_name = fts_box_get_root(box, &ns);
 
        if (ns != backend->default_ns) {
                str_append(ctx->cmd, "<field name=\"ns\">");
@@ -496,15 +536,14 @@ fts_backend_solr_add_doc_prefix(struct solr_fts_backend_build_context *ctx,
                str_append(ctx->cmd, "</field>");
        }
        str_append(ctx->cmd, "<field name=\"box\">");
-       xml_encode(ctx->cmd, box->name);
+       xml_encode(ctx->cmd, box_name);
        str_append(ctx->cmd, "</field><field name=\"user\">");
        xml_encode(ctx->cmd, ns->user->username);
        str_append(ctx->cmd, "</field>");
 }
 
 static void xml_encode_id(string_t *str, struct fts_backend *_backend,
-                         uint32_t uid, uint32_t uid_validity,
-                         const char *mailbox)
+                         uint32_t uid, uint32_t uid_validity)
 {
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
 
@@ -519,7 +558,7 @@ static void xml_encode_id(string_t *str, struct fts_backend *_backend,
        str_printfa(str, "%u/", uid_validity);
        xml_encode(str, backend->id_username);
        str_append_c(str, '/');
-       xml_encode(str, mailbox);
+       xml_encode(str, backend->id_box_name);
 }
 
 static int
@@ -529,7 +568,6 @@ fts_backend_solr_build_more(struct fts_backend_build_context *_ctx,
 {
        struct solr_fts_backend_build_context *ctx =
                (struct solr_fts_backend_build_context *)_ctx;
-       struct mailbox *box = _ctx->backend->box;
        string_t *cmd = ctx->cmd;
 
        /* body comes first, then headers */
@@ -545,8 +583,7 @@ fts_backend_solr_build_more(struct fts_backend_build_context *_ctx,
 
                fts_backend_solr_add_doc_prefix(ctx, uid);
                str_printfa(cmd, "<field name=\"id\">");
-               xml_encode_id(cmd, _ctx->backend, uid, ctx->uid_validity,
-                             box->name);
+               xml_encode_id(cmd, _ctx->backend, uid, ctx->uid_validity);
                str_append(cmd, "</field>");
 
                ctx->headers = headers;
@@ -573,7 +610,6 @@ fts_backend_solr_build_more(struct fts_backend_build_context *_ctx,
 static int
 fts_backed_solr_build_commit(struct solr_fts_backend_build_context *ctx)
 {
-       struct mailbox *box = ctx->ctx.backend->box;
        int ret;
 
        if (ctx->post == NULL)
@@ -589,8 +625,7 @@ fts_backed_solr_build_commit(struct solr_fts_backend_build_context *ctx)
        fts_backend_solr_add_doc_prefix(ctx, ctx->prev_uid);
        str_printfa(ctx->cmd, "<field name=\"last_uid\">TRUE</field>"
                    "<field name=\"id\">");
-       xml_encode_id(ctx->cmd, ctx->ctx.backend, 0, ctx->uid_validity,
-                     box->name);
+       xml_encode_id(ctx->cmd, ctx->ctx.backend, 0, ctx->uid_validity);
        str_append(ctx->cmd, "</field></doc></add>");
 
        solr_connection_post_more(ctx->post, str_data(ctx->cmd),
@@ -629,8 +664,7 @@ fts_backend_solr_expunge(struct fts_backend *backend, struct mail *mail)
 
                cmd = t_str_new(256);
                str_append(cmd, "<delete><id>");
-               xml_encode_id(cmd, backend, mail->uid, status.uidvalidity,
-                             mail->box->name);
+               xml_encode_id(cmd, backend, mail->uid, status.uidvalidity);
                str_append(cmd, "</id></delete>");
 
                (void)solr_connection_post(solr_conn, str_c(cmd));
@@ -662,10 +696,14 @@ static bool solr_virtual_uid_map(const char *ns_prefix, const char *mailbox,
        struct solr_virtual_uid_map_context *ctx = context;
        struct mail_namespace *ns;
        const char *vname;
+       bool convert_inbox;
 
        ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix);
+       convert_inbox = (ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
+               strcmp(mailbox, "INBOX") == 0;
        for (; ns != NULL; ns = ns->alias_chain_next) {
-               vname = mail_namespace_get_vname(ns, ctx->vname, mailbox);
+               vname = convert_inbox ? ns->prefix :
+                       mail_namespace_get_vname(ns, ctx->vname, mailbox);
                if (mailbox_get_virtual_uid(ctx->box, vname, uidvalidity,
                                            *uid, uid))
                        return TRUE;
@@ -679,8 +717,10 @@ static int fts_backend_solr_lookup(struct fts_backend_lookup_context *ctx,
                                   ARRAY_TYPE(fts_score_map) *scores)
 {
        struct mailbox *box = ctx->backend->box;
+       struct mail_namespace *ns;
        struct solr_virtual_uid_map_context uid_map_ctx;
        const struct fts_backend_lookup_field *fields;
+       const char *box_name;
        unsigned int i, count;
        struct mailbox_status status;
        string_t *str;
@@ -729,9 +769,10 @@ static int fts_backend_solr_lookup(struct fts_backend_lookup_context *ctx,
        if (virtual)
                fts_backend_solr_filter_mailboxes(ctx->backend, str, box);
        else {
+               box_name = fts_box_get_root(box, &ns);
                str_printfa(str, "+%%2Buidv:%u+%%2Bbox:", status.uidvalidity);
-               solr_quote_http(str, box->name);
-               solr_add_ns_query_http(str, ctx->backend, box->storage->ns);
+               solr_quote_http(str, box_name);
+               solr_add_ns_query_http(str, ctx->backend, ns);
        }
 
        array_clear(maybe_uids);
index 23d80d11f9a3d0084e7f40e4d2f865471b6d92d4..a0253a6cfce4d9694cb83c7f20b8f771ad57f5be 100644 (file)
@@ -272,7 +272,7 @@ 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;
+       const struct fts_orig_mailboxes *box1 = p1, *box2 = p2;
        int ret;
 
        T_BEGIN {
@@ -281,10 +281,8 @@ static int mailbox_name_cmp(const void *p1, const void *p2)
 
                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);
+               vname1 = mail_namespace_get_vname(box1->ns, tmp1, box1->name);
+               vname2 = mail_namespace_get_vname(box2->ns, tmp2, box2->name);
                ret = strcmp(vname1, vname2);
        } T_END;
        return ret;
@@ -301,7 +299,7 @@ static int fts_build_init_virtual_next(struct fts_search_context *fctx)
 {
        struct fts_search_virtual_context *vctx = &fctx->virtual_ctx;
        struct mailbox_status status;
-       struct mailbox *const *boxes;
+       const struct fts_orig_mailboxes *boxes;
        const struct fts_backend_uid_map *last_uids;
        unsigned int boxi, uidi, box_count, last_uid_count;
        const char *vname;
@@ -314,25 +312,25 @@ static int fts_build_init_virtual_next(struct fts_search_context *fctx)
        if (fctx->virtual_ctx.trans != NULL)
                (void)mailbox_transaction_commit(&fctx->virtual_ctx.trans);
 
-       boxes = array_get(&vctx->mailboxes, &box_count);
+       boxes = array_get(&vctx->orig_mailboxes, &box_count);
        last_uids = array_get(&vctx->last_uids, &last_uid_count);
 
        tmp = t_str_new(256);
        boxi = vctx->boxi;
        uidi = vctx->uidi;
        while (vret == 0 && boxi < box_count && uidi < last_uid_count) {
-               vname = mail_namespace_get_vname(boxes[boxi]->storage->ns, tmp,
-                                                boxes[boxi]->name);
+               vname = mail_namespace_get_vname(boxes[boxi].ns, tmp,
+                                                boxes[boxi].name);
                ret = strcmp(vname, last_uids[uidi].mailbox);
                if (ret == 0) {
                        /* match. check also that uidvalidity matches. */
-                       mailbox_get_status(boxes[boxi], STATUS_UIDVALIDITY,
+                       mailbox_get_status(boxes[boxi].box, STATUS_UIDVALIDITY,
                                           &status);
                        if (status.uidvalidity != last_uids[uidi].uidvalidity) {
                                uidi++;
                                continue;
                        }
-                       vret = fts_build_init_box(fctx, boxes[boxi],
+                       vret = fts_build_init_box(fctx, boxes[boxi].box,
                                                  last_uids[uidi].uid);
                        boxi++;
                        uidi++;
@@ -341,12 +339,12 @@ static int fts_build_init_virtual_next(struct fts_search_context *fctx)
                        uidi++;
                } else {
                        /* no messages indexed in the mailbox */
-                       vret = fts_build_init_box(fctx, boxes[boxi], 0);
+                       vret = fts_build_init_box(fctx, boxes[boxi].box, 0);
                        boxi++;
                }
        }
        while (vret == 0 && boxi < box_count) {
-               vret = fts_build_init_box(fctx, boxes[boxi], 0);
+               vret = fts_build_init_box(fctx, boxes[boxi].box, 0);
                boxi++;
        }
        vctx->boxi = boxi;
@@ -354,18 +352,50 @@ static int fts_build_init_virtual_next(struct fts_search_context *fctx)
        return vret;
 }
 
+static const char *
+fts_box_get_root(struct mailbox *box, struct mail_namespace **ns_r)
+{
+       struct mail_namespace *ns = box->storage->ns;
+       const char *name = box->name;
+
+       while (ns->alias_for != NULL)
+               ns = ns->alias_for;
+       *ns_r = ns;
+
+       if (*name == '\0' && ns != box->storage->ns &&
+           (ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+               /* ugly workaround to allow selecting INBOX from a Maildir/
+                  when it's not in the inbox=yes namespace. */
+               return "INBOX";
+       }
+       return name;
+}
+
 static int fts_build_init_virtual(struct fts_search_context *fctx)
 {
        struct fts_search_virtual_context *vctx = &fctx->virtual_ctx;
        struct fts_backend_uid_map *last_uids;
-       struct mailbox **boxes;
-       unsigned int box_count, last_uid_count;
+       ARRAY_TYPE(mailboxes) mailboxes;
+       struct mailbox *const *boxes;
+       struct fts_orig_mailboxes *orig_boxes;
+       struct fts_orig_mailboxes orig_box;
+       unsigned int i, box_count, last_uid_count;
        int ret;
 
+       t_array_init(&mailboxes, 64);
+       mailbox_get_virtual_backend_boxes(fctx->t->box, &mailboxes, TRUE);
+       boxes = array_get_modifiable(&mailboxes, &box_count);
+
        vctx->pool = pool_alloconly_create("fts virtual build", 1024);
-       p_array_init(&vctx->mailboxes, vctx->pool, 64);
-       mailbox_get_virtual_backend_boxes(fctx->t->box, &vctx->mailboxes, TRUE);
-       boxes = array_get_modifiable(&vctx->mailboxes, &box_count);
+       p_array_init(&vctx->orig_mailboxes, vctx->pool, box_count);
+       memset(&orig_box, 0, sizeof(orig_box));
+       for (i = 0; i < box_count; i++) {
+               orig_box.box = boxes[i];
+               orig_box.name = fts_box_get_root(boxes[i], &orig_box.ns);
+               array_append(&vctx->orig_mailboxes, &orig_box, 1);
+       }
+
+       orig_boxes = array_get_modifiable(&vctx->orig_mailboxes, &box_count);
 
        if (box_count <= 0) {
                if (box_count == 0) {
@@ -375,7 +405,7 @@ static int fts_build_init_virtual(struct fts_search_context *fctx)
                /* virtual mailbox is built from only a single mailbox
                   (currently). check that directly. */
                fctx->virtual_ctx.trans =
-                       mailbox_transaction_begin(boxes[0], 0);
+                       mailbox_transaction_begin(orig_boxes[0].box, 0);
                ret = fts_build_init_trans(fctx, fctx->virtual_ctx.trans);
                return ret;
        }
@@ -390,7 +420,7 @@ static int fts_build_init_virtual(struct fts_search_context *fctx)
        }
        last_uids = array_get_modifiable(&vctx->last_uids, &last_uid_count);
 
-       qsort(boxes, box_count, sizeof(*boxes), mailbox_name_cmp);
+       qsort(orig_boxes, box_count, sizeof(*orig_boxes), mailbox_name_cmp);
        qsort(last_uids, last_uid_count, sizeof(*last_uids),
              fts_backend_uid_map_mailbox_cmp);
 
index 5b553bc1e9ff0a197a53ddb801f617120147120c..27018e238d90bc98ee9c9a1950418b31a5d0184a 100644 (file)
@@ -13,11 +13,17 @@ struct fts_mailbox {
        unsigned int backend_set:1;
 };
 
+struct fts_orig_mailboxes {
+       const char *name;
+       struct mail_namespace *ns;
+       struct mailbox *box;
+};
+
 struct fts_search_virtual_context {
        pool_t pool;
 
        struct mailbox_transaction_context *trans;
-       ARRAY_TYPE(mailboxes) mailboxes;
+       ARRAY_DEFINE(orig_mailboxes, struct fts_orig_mailboxes);
        ARRAY_TYPE(fts_backend_uid_map) last_uids;
 
        unsigned int boxi, uidi;