Mercurial > dovecot > original-hg > dovecot-1.2
changeset 8950:ec1ae90af21a HEAD
fts: Fixes to how virtual mailboxes are searched.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 15 Apr 2009 19:48:55 -0400 |
parents | 508bbbd4e6f6 |
children | 77fb2731830b |
files | src/plugins/fts-solr/fts-backend-solr.c src/plugins/fts/fts-storage.c src/plugins/fts/fts-storage.h |
diffstat | 3 files changed, 127 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- a/src/plugins/fts-solr/fts-backend-solr.c Wed Apr 15 19:48:17 2009 -0400 +++ b/src/plugins/fts-solr/fts-backend-solr.c Wed Apr 15 19:48:55 2009 -0400 @@ -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 @@ 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) { @@ -136,11 +162,12 @@ { const struct fts_solr_settings *set = &fts_solr_settings; 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); @@ -167,6 +194,7 @@ 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) @@ -178,6 +206,7 @@ { 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); @@ -221,21 +250,25 @@ 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), @@ -259,21 +292,25 @@ 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), @@ -331,12 +368,15 @@ 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; @@ -478,15 +518,15 @@ 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\">"); @@ -494,15 +534,14 @@ 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; @@ -517,7 +556,7 @@ 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 @@ -527,7 +566,6 @@ { 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 */ @@ -543,8 +581,7 @@ 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; @@ -571,7 +608,6 @@ 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) @@ -587,8 +623,7 @@ 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), @@ -627,8 +662,7 @@ 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)); @@ -660,10 +694,14 @@ 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; @@ -677,8 +715,10 @@ 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; @@ -727,9 +767,10 @@ 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);
--- a/src/plugins/fts/fts-storage.c Wed Apr 15 19:48:17 2009 -0400 +++ b/src/plugins/fts/fts-storage.c Wed Apr 15 19:48:55 2009 -0400 @@ -272,7 +272,7 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ } 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);
--- a/src/plugins/fts/fts-storage.h Wed Apr 15 19:48:17 2009 -0400 +++ b/src/plugins/fts/fts-storage.h Wed Apr 15 19:48:55 2009 -0400 @@ -13,11 +13,17 @@ 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;