fts-backend-solr.c revision adf8264ab1135c413bcede6af2e4248fd26a1ef9
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Copyright (c) 2006-2011 Dovecot authors, see the included COPYING file */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct solr_connection *solr_conn = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool is_valid_xml_char(unichar_t chr)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* Valid characters in XML:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce [#x10000-#x10FFFF]
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce This function gets called only for #x80 and higher */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherxml_encode_data(string_t *dest, const unsigned char *data, unsigned int len)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher unsigned int i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < len; i++) {
d3da1c165cdb4c1ec126a8f4b6b544ca415b9d20Pavel Březina /* exceptions to the following control char check */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* SOLR doesn't like control characters.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher replace them with spaces. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* make sure the character is valid for XML
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher so we don't get XML parser errors */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher uni_utf8_get_char_n(data + i, char_len, &chr) == 1 &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void xml_encode(string_t *dest, const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher xml_encode_data(dest, (const unsigned char *)str, strlen(str));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void solr_quote_http(string_t *dest, const char *str)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher solr_connection_http_escape(solr_conn, dest, str);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct fts_backend *fts_backend_solr_alloc(void)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher backend = i_new(struct solr_fts_backend, 1);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherfts_backend_solr_init(struct fts_backend *_backend,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher struct fts_solr_user *fuser = FTS_SOLR_USER_CONTEXT(_backend->ns->user);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher const struct fts_solr_settings *set = &fuser->set;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher solr_conn = solr_connection_init(set->url, set->debug);
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozekstatic void fts_backend_solr_deinit(struct fts_backend *_backend)
e6e26182d58c05d896f72f2925426658a6dc70b5Jakub Hrozek struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherget_last_uid_fallback(struct fts_backend *_backend, struct mailbox *box,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append(str, "fl=uid&rows=1&sort=uid+desc&q=");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (fts_mailbox_get_guid(box, &box_guid) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_printfa(str, "box:%s+user:", box_guid);
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek solr_quote_http(str, _backend->ns->owner->username);
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek pool = pool_alloconly_create("solr last uid lookup", 1024);
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek if (solr_connection_select(solr_conn, str_c(str),
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek /* no UIDs */
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek uidvals = array_get(&results[0]->uids, &count);
4d81fe27ced3d2e96866aeaf61661a925cb8edf1Jakub Hrozek if (count == 1 && uidvals[0].seq1 == uidvals[0].seq2) {
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher i_error("fts_solr: Last UID lookup returned multiple rows");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherfts_backend_solr_get_last_uid(struct fts_backend *_backend,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct mailbox *box, uint32_t *last_uid_r)
5352c9b3609bca63814f9f6f03dbbbadf6c6333aStephen Gallagher /* either nothing has been indexed, or the index was corrupted.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher do it the slow way. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (get_last_uid_fallback(_backend, box, last_uid_r) < 0)
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek (void)fts_index_set_last_uid(box, *last_uid_r);
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozekfts_backend_solr_update_init(struct fts_backend *_backend)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct solr_fts_backend_update_context *ctx;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx = i_new(struct solr_fts_backend_update_context, 1);
336879aabae137f9a81304f147fb0d43001654b0Simo Sorce ctx->cmd = str_new(default_pool, SOLR_CMDBUF_SIZE);
336879aabae137f9a81304f147fb0d43001654b0Simo Sorcestatic void xml_encode_id(struct solr_fts_backend_update_context *ctx,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher xml_encode(str, ctx->ctx.backend->ns->owner->username);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherfts_backend_solr_doc_open(struct solr_fts_backend_update_context *ctx,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "<field name=\"uid\">%u</field>"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "<field name=\"box\">%s</field>",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append(ctx->cmd, "<field name=\"user\">");
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher xml_encode(ctx->cmd, ctx->ctx.backend->ns->owner->username);
const char *str;
return ret;
const char *box_guid;
T_BEGIN {
} T_END;
i_unreached();
return TRUE;
return TRUE;
return FALSE;
case SEARCH_TEXT: {
case SEARCH_BODY:
case SEARCH_HEADER:
case SEARCH_HEADER_ADDRESS:
return FALSE;
return FALSE;
return TRUE;
bool and_args)
unsigned int last_len;
if (and_args)
return FALSE;
return TRUE;
case SEARCH_HEADER:
case SEARCH_HEADER_ADDRESS:
return FALSE;
return FALSE;
return FALSE;
return TRUE;
bool and_args)
unsigned int last_len;
if (and_args)
return FALSE;
return TRUE;
int ret;
return ret;
const char *box_guid;
unsigned int prefix_len;
const char *box_guid;
unsigned int i, len;
boxes[i]);
.flags = 0,
NULL,