bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "lib.h"
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen#include "array.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "hash.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "str.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "strescape.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "ioloop.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "istream.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "http-url.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "http-client.h"
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen#include "fts-solr-plugin.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "solr-connection.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <expat.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenenum solr_xml_response_state {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen SOLR_XML_RESPONSE_STATE_ROOT,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen SOLR_XML_RESPONSE_STATE_RESPONSE,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen SOLR_XML_RESPONSE_STATE_RESULT,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen SOLR_XML_RESPONSE_STATE_DOC,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen SOLR_XML_RESPONSE_STATE_CONTENT
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenenum solr_xml_content_state {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen SOLR_XML_CONTENT_STATE_NONE = 0,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen SOLR_XML_CONTENT_STATE_UID,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen SOLR_XML_CONTENT_STATE_SCORE,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen SOLR_XML_CONTENT_STATE_MAILBOX,
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen SOLR_XML_CONTENT_STATE_NAMESPACE,
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen SOLR_XML_CONTENT_STATE_UIDVALIDITY,
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen SOLR_XML_CONTENT_STATE_ERROR
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct solr_lookup_xml_context {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen enum solr_xml_response_state state;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen enum solr_xml_content_state content_state;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int depth;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen uint32_t uid, uidvalidity;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen float score;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen char *mailbox, *ns;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen pool_t result_pool;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* box_id -> solr_result */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE(char *, struct solr_result *) mailboxes;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct solr_result *) results;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct solr_connection_post {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct solr_connection *conn;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct http_client_request *http_req;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool failed:1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct solr_connection {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen XML_Parser xml_parser;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch char *http_host;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch in_port_t http_port;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch char *http_base_url;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen char *http_failure;
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston char *http_user;
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston char *http_password;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch int request_status;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct istream *payload;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct io *io;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool debug:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool posting:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool xml_failed:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool http_ssl:1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int solr_xml_parse(struct solr_connection *conn,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const void *data, size_t size, bool done)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen enum XML_Error err;
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen int line, col;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (conn->xml_failed)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen if (XML_Parse(conn->xml_parser, data, size, done ? 1 : 0) != 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen err = XML_GetErrorCode(conn->xml_parser);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (err != XML_ERROR_FINISHED) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen line = XML_GetCurrentLineNumber(conn->xml_parser);
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen col = XML_GetCurrentColumnNumber(conn->xml_parser);
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen i_error("fts_solr: Invalid XML input at %d:%d: %s "
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen "(near: %.*s)", line, col, XML_ErrorString(err),
cd2fc7dd28c3a2e3f82e8480eaf3ba7c4abc3614Timo Sirainen (int)I_MIN(size, 128), (const char *)data);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->xml_failed = TRUE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
526631052ca3175357302af8fa7dcbf763b40c53Stephan Boschint solr_connection_init(const char *url,
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch const struct ssl_iostream_settings *ssl_client_set,
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch bool debug, struct solr_connection **conn_r,
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch const char **error_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct http_client_settings http_set;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct solr_connection *conn;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct http_url *http_url;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch const char *error;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston if (http_url_parse(url, NULL, HTTP_URL_ALLOW_USERINFO_PART, pool_datastack_create(),
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch &http_url, &error) < 0) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch *error_r = t_strdup_printf(
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch "fts_solr: Failed to parse HTTP url: %s", error);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return -1;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn = i_new(struct solr_connection, 1);
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch conn->http_host = i_strdup(http_url->host.name);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->http_port = http_url->port;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->http_base_url = i_strconcat(http_url->path, http_url->enc_query, NULL);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->http_ssl = http_url->have_ssl;
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston if (http_url->user != NULL) {
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston conn->http_user = i_strdup(http_url->user);
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston /* allow empty password */
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston conn->http_password = i_strdup(http_url->password != NULL ? http_url->password : "");
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston }
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston
53ec1ff2231d477db3103c51987fa9cb6033bc16Timo Sirainen conn->debug = debug;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen if (solr_http_client == NULL) {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&http_set);
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_set.max_idle_time_msecs = 5*1000;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_set.max_parallel_connections = 1;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_set.max_pipelined_requests = 1;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_set.max_redirects = 1;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_set.max_attempts = 3;
88b90ce9dfe1056d1ec5497b95592d30a849e5f1Timo Sirainen http_set.connect_timeout_msecs = 5*1000;
88b90ce9dfe1056d1ec5497b95592d30a849e5f1Timo Sirainen http_set.request_timeout_msecs = 60*1000;
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch http_set.ssl = ssl_client_set;
526631052ca3175357302af8fa7dcbf763b40c53Stephan Bosch http_set.debug = debug;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen solr_http_client = http_client_init(&http_set);
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->xml_parser = XML_ParserCreate("UTF-8");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (conn->xml_parser == NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_fatal_status(FATAL_OUTOFMEM,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "fts_solr: Failed to allocate XML parser");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch *conn_r = conn;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainenvoid solr_connection_deinit(struct solr_connection **_conn)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen struct solr_connection *conn = *_conn;
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen *_conn = NULL;
dafbec2c6b4275233a78cb137f41dd8041aa1c46Timo Sirainen XML_ParserFree(conn->xml_parser);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_free(conn->http_host);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_free(conn->http_base_url);
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston i_free(conn->http_user);
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston i_free(conn->http_password);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_free(conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic const char *attrs_get_name(const char **attrs)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen for (; *attrs != NULL; attrs += 2) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (strcmp(attrs[0], "name") == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return attrs[1];
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return "";
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainensolr_lookup_xml_start(void *context, const char *name, const char **attrs)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct solr_lookup_xml_context *ctx = context;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *name_attr;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(ctx->depth >= (int)ctx->state);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->depth++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ctx->depth - 1 > (int)ctx->state) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* skipping over unwanted elements */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* response -> result -> doc */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen switch (ctx->state) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case SOLR_XML_RESPONSE_STATE_ROOT:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (strcmp(name, "response") == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->state++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case SOLR_XML_RESPONSE_STATE_RESPONSE:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (strcmp(name, "result") == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->state++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case SOLR_XML_RESPONSE_STATE_RESULT:
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (strcmp(name, "doc") == 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->state++;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen ctx->uid = 0;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen ctx->score = 0;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_free_and_null(ctx->mailbox);
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen i_free_and_null(ctx->ns);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen ctx->uidvalidity = 0;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case SOLR_XML_RESPONSE_STATE_DOC:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen name_attr = attrs_get_name(attrs);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (strcmp(name_attr, "uid") == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_UID;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen else if (strcmp(name_attr, "score") == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_SCORE;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen else if (strcmp(name_attr, "box") == 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_MAILBOX;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen else if (strcmp(name_attr, "ns") == 0)
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_NAMESPACE;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen else if (strcmp(name_attr, "uidv") == 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_UIDVALIDITY;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen else
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->state++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case SOLR_XML_RESPONSE_STATE_CONTENT:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic struct solr_result *
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainensolr_result_get(struct solr_lookup_xml_context *ctx, const char *box_id)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct solr_result *result;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen char *box_id_dup;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen result = hash_table_lookup(ctx->mailboxes, box_id);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (result != NULL)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return result;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen box_id_dup = p_strdup(ctx->result_pool, box_id);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen result = p_new(ctx->result_pool, struct solr_result, 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen result->box_id = box_id_dup;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(&result->uids, ctx->result_pool, 32);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(&result->scores, ctx->result_pool, 32);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen hash_table_insert(ctx->mailboxes, box_id_dup, result);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen array_append(&ctx->results, &result, 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return result;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainenstatic int solr_lookup_add_doc(struct solr_lookup_xml_context *ctx)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen{
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen struct fts_score_map *score;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct solr_result *result;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *box_id;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (ctx->uid == 0) {
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen i_error("fts_solr: uid missing from inside doc");
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen return -1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ctx->mailbox == NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* looking up from a single mailbox only */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen box_id = "";
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else if (ctx->uidvalidity != 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* old style lookup */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen string_t *str = t_str_new(64);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen str_printfa(str, "%u\001", ctx->uidvalidity);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen str_append(str, ctx->mailbox);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ctx->ns != NULL)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen str_printfa(str, "\001%s", ctx->ns);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen box_id = str_c(str);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* new style lookup */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen box_id = ctx->mailbox;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen result = solr_result_get(ctx, box_id);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
91c58af8e992d028eb325707904debb58ae80438Timo Sirainen if (seq_range_array_add(&result->uids, ctx->uid)) {
91c58af8e992d028eb325707904debb58ae80438Timo Sirainen /* duplicate result */
91c58af8e992d028eb325707904debb58ae80438Timo Sirainen } else if (ctx->score != 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen score = array_append_space(&result->scores);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen score->uid = ctx->uid;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen score->score = ctx->score;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen return 0;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen}
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void solr_lookup_xml_end(void *context, const char *name ATTR_UNUSED)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct solr_lookup_xml_context *ctx = context;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen int ret;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen if (ctx->content_state == SOLR_XML_CONTENT_STATE_ERROR)
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(ctx->depth >= (int)ctx->state);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ctx->state == SOLR_XML_RESPONSE_STATE_CONTENT &&
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ctx->content_state == SOLR_XML_CONTENT_STATE_MAILBOX &&
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ctx->mailbox == NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* mailbox is namespace prefix */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ctx->mailbox = i_strdup("");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ctx->depth == (int)ctx->state) {
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen ret = 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (ctx->state == SOLR_XML_RESPONSE_STATE_DOC) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen T_BEGIN {
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen ret = solr_lookup_add_doc(ctx);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } T_END;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->state--;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen if (ret < 0)
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_ERROR;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen else
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_NONE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->depth--;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenstatic int uint32_parse(const char *str, int len, uint32_t *value_r)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen{
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen uint32_t value = 0;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen int i;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen for (i = 0; i < len; i++) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (str[i] < '0' || str[i] > '9')
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen break;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen value = value*10 + str[i]-'0';
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (i != len)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return -1;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen *value_r = value;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return 0;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen}
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void solr_lookup_xml_data(void *context, const char *str, int len)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct solr_lookup_xml_context *ctx = context;
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen char *new_name;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen switch (ctx->content_state) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case SOLR_XML_CONTENT_STATE_NONE:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case SOLR_XML_CONTENT_STATE_UID:
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen if (uint32_parse(str, len, &ctx->uid) < 0 || ctx->uid == 0) {
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen i_error("fts_solr: received invalid uid '%s'",
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen t_strndup(str, len));
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_ERROR;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case SOLR_XML_CONTENT_STATE_SCORE:
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen T_BEGIN {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen ctx->score = strtod(t_strndup(str, len), NULL);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen } T_END;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen case SOLR_XML_CONTENT_STATE_MAILBOX:
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen /* this may be called multiple times, for example if input
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen contains '&' characters */
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen new_name = ctx->mailbox == NULL ? i_strndup(str, len) :
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen i_strconcat(ctx->mailbox, t_strndup(str, len), NULL);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_free(ctx->mailbox);
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen ctx->mailbox = new_name;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen break;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen case SOLR_XML_CONTENT_STATE_NAMESPACE:
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen new_name = ctx->ns == NULL ? i_strndup(str, len) :
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen i_strconcat(ctx->ns, t_strndup(str, len), NULL);
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen i_free(ctx->ns);
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen ctx->ns = new_name;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen break;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen case SOLR_XML_CONTENT_STATE_UIDVALIDITY:
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (uint32_parse(str, len, &ctx->uidvalidity) < 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_error("fts_solr: received invalid uidvalidity");
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen break;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen case SOLR_XML_CONTENT_STATE_ERROR:
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschstatic void solr_connection_payload_input(struct solr_connection *conn)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch const unsigned char *data;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch size_t size;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch int ret;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch /* read payload */
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody while ((ret = i_stream_read_more(conn->payload, &data, &size)) > 0) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch (void)solr_xml_parse(conn, data, size, FALSE);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_stream_skip(conn->payload, size);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (ret == 0) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch /* we will be called again for more data */
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch } else {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (conn->payload->stream_errno != 0) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_error("fts_solr: failed to read payload from HTTP server: %m");
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->request_status = -1;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch io_remove(&conn->io);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_stream_unref(&conn->payload);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschstatic void
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschsolr_connection_select_response(const struct http_response *response,
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct solr_connection *conn)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (response->status / 100 != 2) {
ce3fc9190e82d8d9e9604afd4ebbee1d61957764Stephan Bosch i_error("fts_solr: Lookup failed: %s",
ce3fc9190e82d8d9e9604afd4ebbee1d61957764Stephan Bosch http_response_get_message(response));
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->request_status = -1;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (response->payload == NULL) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_error("fts_solr: Lookup failed: Empty response payload");
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->request_status = -1;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_stream_ref(response->payload);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->payload = response->payload;
9937dfc157dc64ed781b7aa264aa893d1d50c5c4Timo Sirainen conn->io = io_add_istream(response->payload,
9937dfc157dc64ed781b7aa264aa893d1d50c5c4Timo Sirainen solr_connection_payload_input, conn);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch solr_connection_payload_input(conn);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenint solr_connection_select(struct solr_connection *conn, const char *query,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen pool_t pool, struct solr_result ***box_results_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct solr_lookup_xml_context solr_lookup_context;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct http_client_request *http_req;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch const char *url;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen int parse_ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&solr_lookup_context);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen solr_lookup_context.result_pool = pool;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&solr_lookup_context.mailboxes, default_pool, 0,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen str_hash, strcmp);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen p_array_init(&solr_lookup_context.results, pool, 32);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen i_free_and_null(conn->http_failure);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->xml_failed = FALSE;
6b09a3b269f4b10364c9a77f6614dbe3d306b79dTimo Sirainen XML_ParserReset(conn->xml_parser, "UTF-8");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen XML_SetElementHandler(conn->xml_parser,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen solr_lookup_xml_start, solr_lookup_xml_end);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen XML_SetCharacterDataHandler(conn->xml_parser, solr_lookup_xml_data);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen XML_SetUserData(conn->xml_parser, &solr_lookup_context);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch url = t_strconcat(conn->http_base_url, "select?", query, NULL);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_req = http_client_request(solr_http_client, "GET",
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->http_host, url,
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch solr_connection_select_response, conn);
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston if (conn->http_user != NULL) {
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston http_client_request_set_auth_simple(http_req, conn->http_user, conn->http_password);
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_set_port(http_req, conn->http_port);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_set_ssl(http_req, conn->http_ssl);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_submit(http_req);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->request_status = 0;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_client_wait(solr_http_client);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen if (conn->request_status < 0 ||
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen solr_lookup_context.content_state == SOLR_XML_CONTENT_STATE_ERROR)
428d63767dc20aeb87695b82fb01cd0a06d7769cTimo Sirainen return -1;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen parse_ret = solr_xml_parse(conn, "", 0, TRUE);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen hash_table_destroy(&solr_lookup_context.mailboxes);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&solr_lookup_context.results);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen *box_results_r = array_idx_modifiable(&solr_lookup_context.results, 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return parse_ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschstatic void
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschsolr_connection_update_response(const struct http_response *response,
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct solr_connection *conn)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (response->status / 100 != 2) {
ce3fc9190e82d8d9e9604afd4ebbee1d61957764Stephan Bosch i_error("fts_solr: Indexing failed: %s",
ce3fc9190e82d8d9e9604afd4ebbee1d61957764Stephan Bosch http_response_get_message(response));
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->request_status = -1;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschstatic struct http_client_request *
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschsolr_connection_post_request(struct solr_connection *conn)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct http_client_request *http_req;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch const char *url;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch url = t_strconcat(conn->http_base_url, "update", NULL);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_req = http_client_request(solr_http_client, "POST",
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->http_host, url,
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch solr_connection_update_response, conn);
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston if (conn->http_user != NULL) {
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston http_client_request_set_auth_simple(http_req, conn->http_user, conn->http_password);
f817e98f79893a17b09214081f51834c3d733919J. Nick Koston }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_set_port(http_req, conn->http_port);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_set_ssl(http_req, conn->http_ssl);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_add_header(http_req, "Content-Type", "text/xml");
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return http_req;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct solr_connection_post *
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainensolr_connection_post_begin(struct solr_connection *conn)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct solr_connection_post *post;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(!conn->posting);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->posting = TRUE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch post = i_new(struct solr_connection_post, 1);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch post->conn = conn;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch post->http_req = solr_connection_post_request(conn);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch XML_ParserReset(conn->xml_parser, "UTF-8");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return post;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenvoid solr_connection_post_more(struct solr_connection_post *post,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const unsigned char *data, size_t size)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct solr_connection *conn = post->conn;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(post->conn->posting);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (post->failed)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c9445d17bfb97440cf47c5363993518a943f7010Timo Sirainen if (conn->request_status == 0)
c9445d17bfb97440cf47c5363993518a943f7010Timo Sirainen (void)http_client_request_send_payload(&post->http_req, data, size);
c9445d17bfb97440cf47c5363993518a943f7010Timo Sirainen if (conn->request_status < 0)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch post->failed = TRUE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c9445d17bfb97440cf47c5363993518a943f7010Timo Sirainenint solr_connection_post_end(struct solr_connection_post **_post)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
c9445d17bfb97440cf47c5363993518a943f7010Timo Sirainen struct solr_connection_post *post = *_post;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct solr_connection *conn = post->conn;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int ret = post->failed ? -1 : 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(conn->posting);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c9445d17bfb97440cf47c5363993518a943f7010Timo Sirainen *_post = NULL;
c9445d17bfb97440cf47c5363993518a943f7010Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (!post->failed) {
c3a4c931e95737a52e1cebeeb109a2e1cc4d47d6Timo Sirainen if (http_client_request_finish_payload(&post->http_req) < 0 ||
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->request_status < 0) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch ret = -1;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch } else {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (post->http_req != NULL)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_abort(&post->http_req);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_free(post);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->posting = FALSE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenint solr_connection_post(struct solr_connection *conn, const char *cmd)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct http_client_request *http_req;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct istream *post_payload;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_assert(!conn->posting);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_req = solr_connection_post_request(conn);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch post_payload = i_stream_create_from_data(cmd, strlen(cmd));
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_set_payload(http_req, post_payload, TRUE);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_stream_unref(&post_payload);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch http_client_request_submit(http_req);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch XML_ParserReset(conn->xml_parser, "UTF-8");
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->request_status = 0;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen http_client_wait(solr_http_client);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return conn->request_status;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}