/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "hash.h"
#include "strescape.h"
#include "unichar.h"
#include "iostream-ssl.h"
#include "http-url.h"
#include "imap-utf7.h"
#include "mail-storage-private.h"
#include "mailbox-list-private.h"
#include "mail-search.h"
#include "fts-api.h"
#include "solr-connection.h"
#include "fts-solr-plugin.h"
#include <ctype.h>
struct solr_fts_backend {
};
struct solr_fts_backend_update_context {
char *id_box_name;
bool headers_open;
bool body_open;
bool documents_added;
};
{
/* Valid characters in XML:
#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
[#x10000-#x10FFFF]
This function gets called only for #x80 and higher */
return FALSE;
return FALSE;
return chr < 0x10ffff;
}
static void
{
size_t i;
for (i = 0; i < len; i++) {
switch (data[i]) {
case '&':
break;
case '<':
break;
case '>':
break;
case '\t':
case '\n':
case '\r':
/* exceptions to the following control char check */
break;
default:
if (data[i] < 32) {
/* SOLR doesn't like control characters.
replace them with spaces. */
} else if (data[i] >= 0x80) {
/* make sure the character is valid for XML
so we don't get XML parser errors */
unsigned int char_len =
else {
}
i += char_len - 1;
} else {
}
break;
}
}
}
{
}
{
const char *p;
for (p = str; *p != '\0'; p++) {
if (*p == '/' || *p == '!')
break;
}
if (*p == '\0')
return str;
for (p = str; *p != '\0'; p++) {
switch (*p) {
case '/':
break;
case '!':
break;
default:
str_append_c(tmp, *p);
break;
}
}
}
{
unsigned int i;
if (str[0] == '\0')
return "\"\"";
for (i = 0; str[i] != '\0'; i++) {
}
}
{
}
{
}
{
const char *str;
return;
i_error("fts_solr: default_ns setting points to "
"nonexistent namespace");
}
}
}
}
}
{
/* ugly workaround to allow selecting INBOX from a Maildir/
when it's not in the inbox=yes namespace. */
*name = "INBOX";
}
}
static const char *
{
const char *name;
i_unreached();
return name;
}
{
}
static int
{
const char *str;
*error_r = "Invalid fts_solr setting";
return -1;
}
error_r) < 0)
return -1;
return 0;
}
{
}
static void
{
if (!neg)
else
} else {
if (!neg)
else
}
}
static void
struct mail_namespace *ns)
{
}
static int
{
const char *box_name;
unsigned int count;
int ret = 0;
ret = -1;
/* no UIDs */
*last_uid_r = 0;
} else {
} else {
i_error("fts_solr: Last UID lookup returned multiple rows");
ret = -1;
}
}
pool_unref(&pool);
return ret;
}
static int
{
(struct solr_fts_backend *)_backend;
return 0;
}
/* either nothing has been indexed, or the index was corrupted.
do it the slow way. */
return -1;
return 0;
}
static struct fts_backend_update_context *
{
(struct solr_fts_backend *)_backend;
}
{
if (uid != 0)
else
}
}
static void
{
const char *box_name;
"<field name=\"uid\">%u</field>"
"<field name=\"uidv\">%u</field>",
}
}
static int
{
return 0;
}
static int
{
(struct solr_fts_backend_update_context *)_ctx;
const char *str;
int ret;
/* commit and wait until the documents we just indexed are
visible to the following search */
"waitSearcher=\"%s\"/>",
ret = -1;
return ret;
}
static void
{
(struct solr_fts_backend_update_context *)_ctx;
}
ctx->uid_validity = 0;
}
}
static void
{
(struct solr_fts_backend_update_context *)_ctx;
T_BEGIN {
} T_END;
}
static void
{
} else {
}
}
}
static bool
const struct fts_backend_build_key *key)
{
(struct solr_fts_backend_update_context *)_ctx;
break;
}
break;
i_unreached();
}
return TRUE;
}
static void
{
(struct solr_fts_backend_update_context *)_ctx;
if (ctx->headers_open)
else {
}
}
static int
{
(struct solr_fts_backend_update_context *)_ctx;
}
return 0;
}
{
return 0;
}
{
return 0;
}
static bool
{
return FALSE;
case SEARCH_TEXT: {
break;
}
case SEARCH_BODY:
break;
default:
return FALSE;
}
return TRUE;
}
static bool
bool and_args)
{
if (and_args)
else
}
}
return FALSE;
return TRUE;
}
static int
struct mail_search_arg *args,
enum fts_lookup_flags flags,
struct fts_result *result)
{
(struct solr_fts_backend *)_backend;
const char *box_name;
int ret;
&status);
/* can't search this query */
return 0;
}
/* use a separate filter query for selecting the mailbox. it shouldn't
affect the score and there could be some caching benefits too. */
if ((flags & FTS_LOOKUP_FLAG_NO_AUTO_FUZZY) == 0)
else
}
pool_unref(&pool);
return ret;
}
static char *
{
return str_c_modifiable(str);
}
static int
enum fts_lookup_flags flags,
struct fts_multi_result *result)
{
const char *box_name;
char *box_id;
unsigned int i;
/* use a separate filter query for selecting the mailbox. it shouldn't
affect the score and there could be some caching benefits too. */
else
}
return -1;
}
for (i = 0; solr_results[i] != NULL; i++) {
i_warning("fts_solr: Lookup returned unexpected mailbox "
continue;
}
if ((flags & FTS_LOOKUP_FLAG_NO_AUTO_FUZZY) == 0)
else
}
return 0;
}
static int
struct mail_search_arg *args,
enum fts_lookup_flags flags,
struct fts_multi_result *result)
{
(struct solr_fts_backend *)_backend;
str_printfa(str, "fl=ns,box,uidv,uid,score&rows=%u&sort=box+asc,uid+asc&q=%%7b!lucene+q.op%%3dAND%%7d",
return -1;
}
/* FIXME: maybe_uids could be handled also with some more work.. */
return 0;
}
.name = "solr_old",
.flags = 0,
{
NULL,
}
};