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;
};
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)
{
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);
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)
{
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);
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),
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),
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;
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\">");
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;
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
{
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 */
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;
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)
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),
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));
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;
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;
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);
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 {
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;
{
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;
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++;
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;
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) {
/* 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;
}
}
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);