fts-backend-solr-old.c revision c051fa1a87d352295dbd522a7a90729ba8d6eacf
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2006-2015 Dovecot authors, see the included COPYING file */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "lib.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen#include "array.h"
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen#include "str.h"
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen#include "hash.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "strescape.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "unichar.h"
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen#include "http-url.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "imap-utf7.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "mail-storage-private.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "mailbox-list-private.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "mail-search.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "fts-api.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen#include "solr-connection.h"
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen#include "fts-solr-plugin.h"
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen#include <ctype.h>
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen#define SOLR_CMDBUF_SIZE (1024*64)
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen#define SOLR_MAX_MULTI_ROWS 100000
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainenstruct solr_fts_backend {
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen struct fts_backend backend;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen struct solr_connection *solr_conn;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen char *id_username, *id_namespace;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mail_namespace *default_ns;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen};
39e6fcc3e8b1ccb13087c232cb6bdea04d1a20a4Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstruct solr_fts_backend_update_context {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct fts_backend_update_context ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct mailbox *cur_box;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen char *id_box_name;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct solr_connection_post *post;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen uint32_t prev_uid, uid_validity;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen string_t *cmd, *hdr;
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen bool headers_open;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen bool body_open;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen bool documents_added;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen};
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenstatic const char *solr_escape_chars = "+-&|!(){}[]^\"~*?:\\/ ";
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstatic bool is_valid_xml_char(unichar_t chr)
150e64c376365becf1ec5c9d45912ecb840eea96Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* Valid characters in XML:
150e64c376365becf1ec5c9d45912ecb840eea96Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen [#x10000-#x10FFFF]
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen This function gets called only for #x80 and higher */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (chr > 0xd7ff && chr < 0xe000)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen return FALSE;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (chr > 0xfffd && chr < 0x10000)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen return FALSE;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen return chr < 0x10ffff;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainenstatic void
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainenxml_encode_data(string_t *dest, const unsigned char *data, unsigned int len)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen{
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen unichar_t chr;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen unsigned int i;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen for (i = 0; i < len; i++) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen switch (data[i]) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen case '&':
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen str_append(dest, "&amp;");
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen break;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen case '<':
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen str_append(dest, "&lt;");
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen break;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen case '>':
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen str_append(dest, "&gt;");
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen break;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen case '\t':
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen case '\n':
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen case '\r':
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* exceptions to the following control char check */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_c(dest, data[i]);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen default:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (data[i] < 32) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* SOLR doesn't like control characters.
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen replace them with spaces. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_c(dest, ' ');
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else if (data[i] >= 0x80) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* make sure the character is valid for XML
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen so we don't get XML parser errors */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen unsigned int char_len =
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen uni_utf8_get_char_n(data + i, len - i, &chr);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (char_len > 0 && is_valid_xml_char(chr))
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_n(dest, data + i, char_len);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_n(dest, utf8_replacement_char,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen UTF8_REPLACEMENT_CHAR_LEN);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i += char_len - 1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_c(dest, data[i]);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void xml_encode(string_t *dest, const char *str)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen xml_encode_data(dest, (const unsigned char *)str, strlen(str));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic const char *solr_escape_id_str(const char *str)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen string_t *tmp;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *p;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen for (p = str; *p != '\0'; p++) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (*p == '/' || *p == '!')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (*p == '\0')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return str;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen tmp = t_str_new(64);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen for (p = str; *p != '\0'; p++) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen switch (*p) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen case '/':
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen str_append(tmp, "!\\");
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen case '!':
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen str_append(tmp, "!!");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen default:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_c(tmp, *p);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return str_c(tmp);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic const char *solr_escape(const char *str)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen string_t *ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen unsigned int i;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (str[0] == '\0')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return "\"\"";
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen ret = t_str_new(strlen(str) + 16);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen for (i = 0; str[i] != '\0'; i++) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (strchr(solr_escape_chars, str[i]) != NULL)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen str_append_c(ret, '\\');
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen str_append_c(ret, str[i]);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen return str_c(ret);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenstatic void solr_quote(string_t *dest, const char *str)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen str_append(dest, solr_escape(str));
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainenstatic void solr_quote_http(string_t *dest, const char *str)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen http_url_escape_param(dest, solr_escape(str));
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainenstatic void fts_solr_set_default_ns(struct solr_fts_backend *backend)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen struct mail_namespace *ns = backend->backend.ns;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen struct fts_solr_user *fuser = FTS_SOLR_USER_CONTEXT(ns->user);
f2bd9e507b8befdd95a983f86664febf5c19bd95Timo Sirainen const struct fts_solr_settings *set = &fuser->set;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const char *str;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (backend->default_ns != NULL)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen return;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (set->default_ns_prefix != NULL) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen backend->default_ns =
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mail_namespace_find_prefix(ns->user->namespaces,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen set->default_ns_prefix);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (backend->default_ns == NULL) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_error("fts_solr: default_ns setting points to "
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen "nonexistent namespace");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (backend->default_ns == NULL) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen backend->default_ns =
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen mail_namespace_find_inbox(ns->user->namespaces);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen while (backend->default_ns->alias_for != NULL)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen backend->default_ns = backend->default_ns->alias_for;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ns != backend->default_ns) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str = solr_escape_id_str(ns->prefix);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen backend->id_namespace = i_strdup(str);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void fts_box_name_get_root(struct mail_namespace **ns, const char **name)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mail_namespace *orig_ns = *ns;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen while ((*ns)->alias_for != NULL)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen *ns = (*ns)->alias_for;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
39e6fcc3e8b1ccb13087c232cb6bdea04d1a20a4Timo Sirainen if (**name == '\0' && *ns != orig_ns &&
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ((*ns)->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* ugly workaround to allow selecting INBOX from a Maildir/
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen when it's not in the inbox=yes namespace. */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen *name = "INBOX";
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic const char *
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenfts_box_get_root(struct mailbox *box, struct mail_namespace **ns_r)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mail_namespace *ns = mailbox_get_namespace(box);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen const char *name;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
39e6fcc3e8b1ccb13087c232cb6bdea04d1a20a4Timo Sirainen if (t_imap_utf8_to_utf7(box->name, &name) < 0)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_unreached();
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen fts_box_name_get_root(&ns, &name);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen *ns_r = ns;
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen return name;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic struct fts_backend *fts_backend_solr_alloc(void)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen struct solr_fts_backend *backend;
bc3698b8892df8003b410daea6f5bbcd20433808Timo Sirainen
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen backend = i_new(struct solr_fts_backend, 1);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen backend->backend = fts_backend_solr_old;
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen return &backend->backend;
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen}
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic int
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainenfts_backend_solr_init(struct fts_backend *_backend, const char **error_r)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen struct fts_solr_user *fuser = FTS_SOLR_USER_CONTEXT(_backend->ns->user);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *str;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (fuser == NULL) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen *error_r = "Invalid fts_solr setting";
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return -1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (solr_connection_init(fuser->set.url, fuser->set.debug,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen &backend->solr_conn, error_r) < 0)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen return -1;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str = solr_escape_id_str(_backend->ns->user->username);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen backend->id_username = i_strdup(str);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainenstatic void fts_backend_solr_deinit(struct fts_backend *_backend)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen{
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen solr_connection_deinit(&backend->solr_conn);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_free(backend->id_namespace);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_free(backend->id_username);
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen i_free(backend);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen}
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainensolr_add_ns_query(string_t *str, struct solr_fts_backend *backend,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen struct mail_namespace *ns, bool neg)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen{
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen while (ns->alias_for != NULL)
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen ns = ns->alias_for;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen if (ns == backend->default_ns || *ns->prefix == '\0') {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (!neg)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append(str, " -ns:[* TO *]");
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen else
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append(str, " +ns:[* TO *]");
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen } else {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (!neg)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append(str, " +ns:");
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen else
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append(str, " -ns:");
2d9644d34a78b24dc7769cd96497e700a0fb1cf1Timo Sirainen solr_quote(str, ns->prefix);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen }
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen}
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainensolr_add_ns_query_http(string_t *str, struct solr_fts_backend *backend,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mail_namespace *ns)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen{
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen string_t *tmp;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen tmp = t_str_new(64);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen solr_add_ns_query(tmp, backend, ns, FALSE);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen http_url_escape_param(str, str_c(tmp));
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenfts_backend_solr_get_last_uid_fallback(struct solr_fts_backend *backend,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mailbox *box,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen uint32_t *last_uid_r)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct mail_namespace *ns;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct mailbox_status status;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct solr_result **results;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen const struct seq_range *uidvals;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *box_name;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen unsigned int count;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen string_t *str;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pool_t pool;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen int ret = 0;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen str = t_str_new(256);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen str_append(str, "fl=uid&rows=1&sort=uid+desc&q=");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen box_name = fts_box_get_root(box, &ns);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_printfa(str, "uidv:%u+AND+box:", status.uidvalidity);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen solr_quote_http(str, box_name);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen solr_add_ns_query_http(str, backend, ns);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append(str, "+AND+user:");
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen solr_quote_http(str, ns->user->username);
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen pool = pool_alloconly_create("solr last uid lookup", 1024);
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen if (solr_connection_select(backend->solr_conn, str_c(str),
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen pool, &results) < 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ret = -1;
c6ae908f6a2313573625d782bdd4e0ff3882c44aTimo Sirainen else if (results[0] == NULL) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* no UIDs */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *last_uid_r = 0;
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen } else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen uidvals = array_get(&results[0]->uids, &count);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_assert(count > 0);
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen if (count == 1 && uidvals[0].seq1 == uidvals[0].seq2) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *last_uid_r = uidvals[0].seq1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else {
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen i_error("fts_solr: Last UID lookup returned multiple rows");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ret = -1;
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pool_unref(&pool);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenfts_backend_solr_get_last_uid(struct fts_backend *_backend,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mailbox *box, uint32_t *last_uid_r)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct solr_fts_backend *backend =
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen (struct solr_fts_backend *)_backend;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct fts_index_header hdr;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (fts_index_get_header(box, &hdr)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *last_uid_r = hdr.last_indexed_uid;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* either nothing has been indexed, or the index was corrupted.
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen do it the slow way. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (fts_backend_solr_get_last_uid_fallback(backend, box, last_uid_r) < 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen fts_index_set_last_uid(box, *last_uid_r);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic struct fts_backend_update_context *
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenfts_backend_solr_update_init(struct fts_backend *_backend)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct solr_fts_backend *backend =
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen (struct solr_fts_backend *)_backend;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct solr_fts_backend_update_context *ctx;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx = i_new(struct solr_fts_backend_update_context, 1);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen ctx->ctx.backend = _backend;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen ctx->cmd = str_new(default_pool, SOLR_CMDBUF_SIZE);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen ctx->hdr = str_new(default_pool, 4096);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen fts_solr_set_default_ns(backend);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen return &ctx->ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstatic void xml_encode_id(struct solr_fts_backend_update_context *ctx,
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen string_t *str, uint32_t uid)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct solr_fts_backend *backend =
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen (struct solr_fts_backend *)ctx->ctx.backend;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (uid != 0)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_printfa(str, "%u/", uid);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen else
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append(str, "L/");
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
6384258c2f84e635d8ceffc3eeddad71f7538040Timo Sirainen if (backend->id_namespace != NULL) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen xml_encode(str, backend->id_namespace);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append_c(str, '/');
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen str_printfa(str, "%u/", ctx->uid_validity);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen xml_encode(str, backend->id_username);
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen str_append_c(str, '/');
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen xml_encode(str, ctx->id_box_name);
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen}
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainenstatic void
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainenfts_backend_solr_add_doc_prefix(struct solr_fts_backend_update_context *ctx,
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen uint32_t uid)
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen{
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen struct solr_fts_backend *backend =
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen (struct solr_fts_backend *)ctx->ctx.backend;
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen struct mailbox *box = ctx->cur_box;
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen struct mail_namespace *ns;
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen const char *box_name;
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen ctx->documents_added = TRUE;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_printfa(ctx->cmd, "<doc>"
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen "<field name=\"uid\">%u</field>"
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen "<field name=\"uidv\">%u</field>",
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen uid, ctx->uid_validity);
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen box_name = fts_box_get_root(box, &ns);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen if (ns != backend->default_ns) {
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen str_append(ctx->cmd, "<field name=\"ns\">");
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen xml_encode(ctx->cmd, ns->prefix);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_append(ctx->cmd, "</field>");
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen }
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_append(ctx->cmd, "<field name=\"box\">");
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen xml_encode(ctx->cmd, box_name);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_append(ctx->cmd, "</field><field name=\"user\">");
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen xml_encode(ctx->cmd, ns->user->username);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_append(ctx->cmd, "</field>");
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen}
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenstatic int
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainenfts_backed_solr_build_commit(struct solr_fts_backend_update_context *ctx)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (ctx->post == NULL)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return 0;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_append(ctx->cmd, "</doc></add>");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen solr_connection_post_more(ctx->post, str_data(ctx->cmd),
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_len(ctx->cmd));
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return solr_connection_post_end(&ctx->post);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic int
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenfts_backend_solr_update_deinit(struct fts_backend_update_context *_ctx)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct solr_fts_backend_update_context *ctx =
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen (struct solr_fts_backend_update_context *)_ctx;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct solr_fts_backend *backend =
c8625391da3ee51b31e69b88895708a3d149dd1bTimo Sirainen (struct solr_fts_backend *)_ctx->backend;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const char *str;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen int ret;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen ret = fts_backed_solr_build_commit(ctx);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* commit and wait until the documents we just indexed are
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen visible to the following search */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str = t_strdup_printf("<commit waitFlush=\"false\" "
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen "waitSearcher=\"%s\"/>",
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen ctx->documents_added ? "true" : "false");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (solr_connection_post(backend->solr_conn, str) < 0)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen ret = -1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_free(&ctx->cmd);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_free(&ctx->hdr);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_free(ctx->id_box_name);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_free(ctx);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return ret;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic void
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenfts_backend_solr_update_set_mailbox(struct fts_backend_update_context *_ctx,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct mailbox *box)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct solr_fts_backend_update_context *ctx =
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen (struct solr_fts_backend_update_context *)_ctx;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct mailbox_status status;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct mail_namespace *ns;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (ctx->prev_uid != 0) {
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen fts_index_set_last_uid(ctx->cur_box, ctx->prev_uid);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ctx->prev_uid = 0;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen }
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->cur_box = box;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->uid_validity = 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_free_and_null(ctx->id_box_name);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (box != NULL) {
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ctx->id_box_name = i_strdup(fts_box_get_root(box, &ns));
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ctx->uid_validity = status.uidvalidity;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen }
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen}
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainenstatic void
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainenfts_backend_solr_update_expunge(struct fts_backend_update_context *_ctx,
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen uint32_t uid)
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen{
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen struct solr_fts_backend_update_context *ctx =
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen (struct solr_fts_backend_update_context *)_ctx;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen struct solr_fts_backend *backend =
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen (struct solr_fts_backend *)_ctx->backend;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen T_BEGIN {
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen string_t *cmd;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen cmd = t_str_new(256);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen str_append(cmd, "<delete><id>");
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen xml_encode_id(ctx, cmd, uid);
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen str_append(cmd, "</id></delete>");
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen (void)solr_connection_post(backend->solr_conn, str_c(cmd));
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen } T_END;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic void
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenfts_backend_solr_uid_changed(struct solr_fts_backend_update_context *ctx,
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen uint32_t uid)
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen{
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen struct solr_fts_backend *backend =
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen (struct solr_fts_backend *)ctx->ctx.backend;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (ctx->post == NULL) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_assert(ctx->prev_uid == 0);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen ctx->post = solr_connection_post_begin(backend->solr_conn);
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen str_append(ctx->cmd, "<add>");
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen } else {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->headers_open = FALSE;
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen if (ctx->body_open) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->body_open = FALSE;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen str_append(ctx->cmd, "</field>");
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen }
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen str_append(ctx->cmd, "<field name=\"hdr\">");
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen str_append_str(ctx->cmd, ctx->hdr);
10cfe8a2bdc5ccfc05380689c71c27209327538fTimo Sirainen str_append(ctx->cmd, "</field>");
10cfe8a2bdc5ccfc05380689c71c27209327538fTimo Sirainen str_truncate(ctx->hdr, 0);
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen
10cfe8a2bdc5ccfc05380689c71c27209327538fTimo Sirainen str_append(ctx->cmd, "</doc>");
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen }
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen ctx->prev_uid = uid;
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen fts_backend_solr_add_doc_prefix(ctx, uid);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_printfa(ctx->cmd, "<field name=\"id\">");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen xml_encode_id(ctx, ctx->cmd, uid);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_append(ctx->cmd, "</field>");
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic bool
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenfts_backend_solr_update_set_build_key(struct fts_backend_update_context *_ctx,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct fts_backend_build_key *key)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct solr_fts_backend_update_context *ctx =
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen (struct solr_fts_backend_update_context *)_ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (key->uid != ctx->prev_uid)
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen fts_backend_solr_uid_changed(ctx, key->uid);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen switch (key->type) {
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen case FTS_BACKEND_BUILD_KEY_HDR:
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen case FTS_BACKEND_BUILD_KEY_MIME_HDR:
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen xml_encode(ctx->hdr, key->hdr_name);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen str_append(ctx->hdr, ": ");
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen ctx->headers_open = TRUE;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen break;
e30e068c8fac372ae217b3b31791a0c8c8046b7fTimo Sirainen case FTS_BACKEND_BUILD_KEY_BODY_PART:
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ctx->headers_open = FALSE;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen if (!ctx->body_open) {
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen ctx->body_open = TRUE;
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen str_append(ctx->cmd, "<field name=\"body\">");
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen }
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen break;
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen case FTS_BACKEND_BUILD_KEY_BODY_PART_BINARY:
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen i_unreached();
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen return TRUE;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen}
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainenstatic void
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainenfts_backend_solr_update_unset_build_key(struct fts_backend_update_context *_ctx)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct solr_fts_backend_update_context *ctx =
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen (struct solr_fts_backend_update_context *)_ctx;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->headers_open)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_c(ctx->hdr, '\n');
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen else {
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen i_assert(ctx->body_open);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_append_c(ctx->cmd, '\n');
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen }
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen}
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainenstatic int
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainenfts_backend_solr_update_build_more(struct fts_backend_update_context *_ctx,
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen const unsigned char *data, size_t size)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen{
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen struct solr_fts_backend_update_context *ctx =
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen (struct solr_fts_backend_update_context *)_ctx;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen xml_encode_data(ctx->cmd, data, size);
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen if (str_len(ctx->cmd) > SOLR_CMDBUF_SIZE-128) {
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen solr_connection_post_more(ctx->post, str_data(ctx->cmd),
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen str_len(ctx->cmd));
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen str_truncate(ctx->cmd, 0);
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return 0;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic int fts_backend_solr_refresh(struct fts_backend *backend ATTR_UNUSED)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int fts_backend_solr_optimize(struct fts_backend *backend ATTR_UNUSED)
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen{
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return 0;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen}
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainenstatic bool
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainensolr_add_definite_query(string_t *str, struct mail_search_arg *arg)
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen{
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen switch (arg->type) {
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen case SEARCH_TEXT: {
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen if (arg->match_not)
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen str_append_c(str, '-');
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen str_append(str, "(hdr:");
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen solr_quote_http(str, arg->value.str);
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen str_append(str, "+OR+body:");
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen solr_quote_http(str, arg->value.str);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen str_append(str, ")");
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen break;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen }
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen case SEARCH_BODY:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (arg->match_not)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_append_c(str, '-');
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen str_append(str, "body:");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen solr_quote_http(str, arg->value.str);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen break;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen default:
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return FALSE;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen return TRUE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen}
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainenstatic bool
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainensolr_add_definite_query_args(string_t *str, struct mail_search_arg *arg,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen bool and_args)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen unsigned int last_len;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen last_len = str_len(str);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen for (; arg != NULL; arg = arg->next) {
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen if (solr_add_definite_query(str, arg)) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen arg->match_always = TRUE;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen last_len = str_len(str);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (and_args)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_append(str, "+AND+");
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen else
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_append(str, "+OR+");
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen }
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen if (str_len(str) == last_len)
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen return FALSE;
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen str_truncate(str, last_len);
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen return TRUE;
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen}
3419b088ffe531799bdb47b3ff3fce85c8b7569aTimo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic int
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenfts_backend_solr_lookup(struct fts_backend *_backend, struct mailbox *box,
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen struct mail_search_arg *args,
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen enum fts_lookup_flags flags,
2d340205d897e23fbecb40c8e63a4ca49bd6739bTimo Sirainen struct fts_result *result)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen{
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct solr_fts_backend *backend =
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen (struct solr_fts_backend *)_backend;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen bool and_args = (flags & FTS_LOOKUP_FLAG_AND_ARGS) != 0;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mail_namespace *ns;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct mailbox_status status;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen string_t *str;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen const char *box_name;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen pool_t pool;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct solr_result **results;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen int ret;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen fts_solr_set_default_ns(backend);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen mailbox_get_open_status(box, STATUS_UIDVALIDITY | STATUS_UIDNEXT,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen &status);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen str = t_str_new(256);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen str_printfa(str, "fl=uid,score&rows=%u&sort=uid+asc&q=",
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen status.uidnext);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if (!solr_add_definite_query_args(str, args, and_args)) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* can't search this query */
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen return 0;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* use a separate filter query for selecting the mailbox. it shouldn't
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen affect the score and there could be some caching benefits too. */
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen str_append(str, "&fq=%2Buser:");
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen solr_quote_http(str, box->storage->user->username);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen box_name = fts_box_get_root(box, &ns);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_printfa(str, "+%%2Buidv:%u+%%2Bbox:", status.uidvalidity);
2372e16bfae0a245bfde6e908cde0919aa11ee0bTimo Sirainen solr_quote_http(str, box_name);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen solr_add_ns_query_http(str, backend, ns);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen pool = pool_alloconly_create("fts solr search", 1024);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen ret = solr_connection_select(backend->solr_conn, str_c(str),
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen pool, &results);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (ret == 0 && results[0] != NULL) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if ((flags & FTS_LOOKUP_FLAG_NO_AUTO_FUZZY) == 0)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen array_append_array(&result->definite_uids, &results[0]->uids);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen else
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen array_append_array(&result->maybe_uids, &results[0]->uids);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen array_append_array(&result->scores, &results[0]->scores);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen result->scores_sorted = TRUE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen pool_unref(&pool);
a8284e999d091cd29210fa75ecdc8076376a7345Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic char *
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenmailbox_get_id(struct solr_fts_backend *backend, struct mail_namespace *ns,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen const char *mailbox, uint32_t uidvalidity)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen{
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen string_t *str = t_str_new(64);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_printfa(str, "%u\001", uidvalidity);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_append(str, mailbox);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (ns != backend->default_ns)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_printfa(str, "\001%s", ns->prefix);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return str_c_modifiable(str);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen}
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic int
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainensolr_search_multi(struct solr_fts_backend *backend, string_t *str,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct mailbox *const boxes[],
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen enum fts_lookup_flags flags,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct fts_multi_result *result)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen{
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct solr_result **solr_results;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct fts_result *fts_result;
2d340205d897e23fbecb40c8e63a4ca49bd6739bTimo Sirainen ARRAY(struct fts_result) fts_results;
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen struct mail_namespace *ns;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox_status status;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen HASH_TABLE(char *, struct mailbox *) mailboxes;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct mailbox *box;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen const char *box_name;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen char *box_id;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen unsigned int i, len;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* use a separate filter query for selecting the mailbox. it shouldn't
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen affect the score and there could be some caching benefits too. */
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen str_append(str, "&fq=%2Buser:");
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen if (backend->backend.ns->owner != NULL)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen solr_quote_http(str, backend->backend.ns->owner->username);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen else
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_append(str, "%22%22");
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen hash_table_create(&mailboxes, default_pool, 0, str_hash, strcmp);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_append(str, "%2B(");
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen len = str_len(str);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen for (i = 0; boxes[i] != NULL; i++) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (str_len(str) != len)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen str_append(str, "+OR+");
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen box_name = fts_box_get_root(boxes[i], &ns);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen mailbox_get_open_status(boxes[i], STATUS_UIDVALIDITY, &status);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen str_printfa(str, "%%2B(%%2Buidv:%u+%%2Bbox:", status.uidvalidity);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen solr_quote_http(str, box_name);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen solr_add_ns_query_http(str, backend, ns);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen str_append_c(str, ')');
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen box_id = mailbox_get_id(backend, ns, box_name, status.uidvalidity);
294f1a51763015cda0e2d874c5027d6fe7a2cd54Timo Sirainen hash_table_insert(mailboxes, box_id, boxes[i]);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_append_c(str, ')');
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (solr_connection_select(backend->solr_conn, str_c(str),
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen result->pool, &solr_results) < 0) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen hash_table_destroy(&mailboxes);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return -1;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen p_array_init(&fts_results, result->pool, 32);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen for (i = 0; solr_results[i] != NULL; i++) {
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen box = hash_table_lookup(mailboxes, solr_results[i]->box_id);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if (box == NULL) {
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen i_warning("fts_solr: Lookup returned unexpected mailbox "
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen "with id=%s", solr_results[i]->box_id);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen continue;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen }
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen fts_result = array_append_space(&fts_results);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen fts_result->box = box;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if ((flags & FTS_LOOKUP_FLAG_NO_AUTO_FUZZY) == 0)
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen fts_result->definite_uids = solr_results[i]->uids;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen else
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen fts_result->maybe_uids = solr_results[i]->uids;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen fts_result->scores = solr_results[i]->scores;
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen fts_result->scores_sorted = TRUE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen array_append_zero(&fts_results);
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen result->box_results = array_idx_modifiable(&fts_results, 0);
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen hash_table_destroy(&mailboxes);
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen return 0;
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen}
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainenstatic int
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenfts_backend_solr_lookup_multi(struct fts_backend *_backend,
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen struct mailbox *const boxes[],
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen struct mail_search_arg *args,
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen enum fts_lookup_flags flags,
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen struct fts_multi_result *result)
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen{
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen bool and_args = (flags & FTS_LOOKUP_FLAG_AND_ARGS) != 0;
2d340205d897e23fbecb40c8e63a4ca49bd6739bTimo Sirainen struct solr_fts_backend *backend =
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen (struct solr_fts_backend *)_backend;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen string_t *str;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen fts_solr_set_default_ns(backend);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str = t_str_new(256);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen str_printfa(str, "fl=ns,box,uidv,uid,score&rows=%u&sort=box+asc,uid+asc&q=",
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen SOLR_MAX_MULTI_ROWS);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen if (solr_add_definite_query_args(str, args, and_args)) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (solr_search_multi(backend, str, boxes, flags, result) < 0)
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen return -1;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* FIXME: maybe_uids could be handled also with some more work.. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return 0;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen}
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstruct fts_backend fts_backend_solr_old = {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen .name = "solr_old",
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen .flags = 0,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_alloc,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen fts_backend_solr_init,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_deinit,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_get_last_uid,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_update_init,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_update_deinit,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_update_set_mailbox,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_update_expunge,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_update_set_build_key,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_update_unset_build_key,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_update_build_more,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_refresh,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen NULL,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_optimize,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_default_can_lookup,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_lookup,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen fts_backend_solr_lookup_multi,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen NULL
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen }
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen};
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen