/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "net.h"
#include "str.h"
#include "strescape.h"
#include "write-full.h"
#include "wildcard-match.h"
#include "mail-search-build.h"
#include "mail-storage-private.h"
#include "mailbox-list-private.h"
#include "fts-api-private.h"
#include "fts-tokenizer.h"
#include "fts-indexer.h"
#include "fts-build-mail.h"
#include "fts-search-serialize.h"
#include "fts-plugin.h"
#include "fts-storage.h"
struct fts_mailbox_list {
const char *backend_name;
unsigned int update_ctx_refcount;
};
struct fts_mailbox {
bool fts_mailbox_excluded;
};
struct fts_transaction_context {
unsigned int precache_extra_count;
};
struct fts_mail {
};
{
return -1;
}
if (last_uid == 0)
*seq_r = 0;
else {
}
return 0;
}
static int
struct mailbox_status *status_r)
{
return -1;
if ((items & STATUS_LAST_CACHED_SEQ) != 0) {
return -1;
/* Always use the FTS's last_cached_seq. This is because we
don't want to reindex all mails to FTS if .cache file is
deleted. */
}
return 0;
}
{
}
}
struct fts_search_context *fctx)
{
int ret;
&fctx->indexer_ctx);
if (ret < 0)
return;
if (ret == 0) {
/* the index was up to date */
} else {
/* hide "searching" notifications while building index */
}
}
{
/* we want to update index only when searching from message body.
it's not worth the wait for searching only from headers, which
could be in cache file already */
case SEARCH_OR:
case SEARCH_SUB:
case SEARCH_INTHREAD:
return TRUE;
break;
case SEARCH_BODY:
case SEARCH_TEXT:
return TRUE;
break;
default:
break;
}
}
return FALSE;
}
{
return TRUE;
case SEARCH_OR:
case SEARCH_SUB:
case SEARCH_INTHREAD:
return TRUE;
break;
default:
break;
}
}
return FALSE;
}
static struct mail_search_context *
struct mail_search_args *args,
const enum mail_sort_type *sort_program,
struct mailbox_header_lookup_ctx *wanted_headers)
{
return ctx;
fctx->t = t;
"fts_enforced");
/* FIXME: we'll assume that all the args are fuzzy. not good,
but would require much more work to fix it. */
"fts_no_autofuzzy"))
/* transaction contains the last search's scores. they can be
queried later with mail_get_special() */
else
return ctx;
}
{
int ret;
if (ret == 0)
return FALSE;
/* indexing finished */
ret = -1;
if (ret > 0)
if (ret < 0) {
/* if indexing timed out, it probably means that
the mailbox is still being indexed, but it's a large
mailbox and it takes a while. in this situation
we'll simply abort the search.
if indexing failed for any other reason, just
fallback to searching the slow way. */
}
return TRUE;
}
static bool
{
/* precaching already failed - stop now instead of potentially
going through the same failure for all the mails */
return FALSE;
}
/* this command is still building the indexes */
if (!fts_mailbox_build_continue(ctx)) {
*tryagain_r = TRUE;
return FALSE;
}
if (fctx->indexing_timed_out) {
*tryagain_r = FALSE;
return FALSE;
}
}
return FALSE;
}
static void
{
continue;
*idx += 1;
}
}
{
unsigned int idx;
/* fts lookup not done for this search */
return FALSE;
}
/* restore original [non]matches */
return FALSE;
/* we've not indexed this far */
return TRUE;
}
/* apply [non]matches based on the FTS lookup results */
idx = 0;
return TRUE;
}
{
int ret = 0;
}
if (fctx->indexing_timed_out)
ret = -1;
/* FTS lookup failed and we didn't want to fallback to
opening all the mails and searching manually */
ret = -1;
}
} else {
ret = -1;
}
ret = -1;
return ret;
}
{
}
const char **value_r)
{
else {
}
return 0;
}
}
static int
struct fts_backend_update_context *update_ctx,
{
int ret = 0;
ret = -1;
break;
}
*extra_count += 1;
}
if (mailbox_search_deinit(&ctx) < 0)
ret = -1;
return ret;
}
{
return -1;
return 0;
}
{
return;
if (fts_mail_precache_init(_mail) < 0) {
return;
}
}
/* most likely a virtual mailbox. we'll first need to
index all mails up to the current one. */
&ft->precache_extra_count) < 0) {
return;
}
}
}
}
}
{
if (fmail->virtual_mail) {
} else T_BEGIN {
} T_END;
}
{
return;
v->precache = fts_mail_precache;
}
static struct mailbox_transaction_context *
const char *reason)
{
struct mailbox_transaction_context *t;
return t;
}
{
*error_r = "transaction context";
if (--flist->update_ctx_refcount == 0) {
ret = -1;
*error_r = "backend deinit";
}
}
} else if (ft->highest_virtual_uid > 0) {
ret = -1;
*error_r = "index last uid setting";
}
}
if (ft->precache_extra_count > 0) {
if (ret < 0) {
i_error("fts: Failed after indexing %u extra mails internally in %s: %s",
} else {
i_info("fts: Indexed %u extra mails internally in %s",
}
}
return ret;
}
{
const char *error;
(void)fts_transaction_end(t, &error);
}
{
unsigned int max_recent_msgs;
int fd;
if (fd == -1) {
return;
}
max_recent_msgs = 0;
i_close_fd(&fd);
}
static int
struct mail_transaction_commit_changes *changes_r)
{
bool autoindex;
int ret = 0;
const char *error;
"fts_autoindex");
if (fts_transaction_end(t, &error) < 0) {
t_strdup_printf("FTS transaction commit failed: %s",
error));
ret = -1;
}
ret = -1;
if (ret < 0)
return -1;
if (autoindex)
return 0;
}
enum mailbox_sync_type sync_type)
{
if (sync_type != MAILBOX_SYNC_TYPE_EXPUNGE) {
/* this sync is finished */
}
return;
}
/* FIXME: maildir workaround - we could get here
because we're building an index, which doesn't find
some mail and starts syncing the mailbox.. */
return;
}
}
}
struct mailbox_sync_status *status_r)
{
bool optimize;
int ret = 0;
MAILBOX_SYNC_FLAG_OPTIMIZE)) != 0;
return -1;
if (optimize) {
ret = -1;
}
}
return ret;
}
{
return -1;
return 0;
}
{
return -1;
return 0;
}
{
const char *str;
unsigned int i;
return NULL;
"fts_autoindex_exclude%u", i) < 0)
i_unreached();
}
}
{
const char *const *exclude_list;
unsigned int i;
const char *const *special_use;
if (exclude_list == NULL)
return FALSE;
for (i = 0; exclude_list[i] != NULL; i++) {
if (exclude_list[i][0] == '\\') {
/* \Special-use flag */
if (special_use != NULL &&
return TRUE;
} else {
/* mailbox name with wildcards */
return TRUE;
}
}
return FALSE;
}
{
return;
v->sync_deinit = fts_sync_deinit;
v->save_finish = fts_save_finish;
}
{
}
static int
const char **error_r)
{
return -1;
}
return 0;
}
{
const char *error;
i_error("fts: Failed to initialize backend '%s': %s",
}
}
}
void
{
const char *path;
i_debug("fts: No fts setting - plugin disabled");
return;
}
i_debug("fts: Indexes disabled for namespace '%s'",
}
return;
}
}
{
}
{
}