fts-storage.c revision 499fec3443374cc89fb8c83b8027c1614097d7a3
/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "str.h"
#include "istream.h"
#include "time-util.h"
#include "rfc822-parser.h"
#include "message-parser.h"
#include "message-decoder.h"
#include "mail-namespace.h"
#include "mail-search-build.h"
#include "mail-storage-private.h"
#include "fts-api-private.h"
#include "fts-mailbox.h"
#include "fts-storage.h"
#include "fts-plugin.h"
#include <stdlib.h>
#define FTS_CONTEXT(obj) \
#define FTS_MAIL_CONTEXT(obj) \
#define FTS_SEARCH_NONBLOCK_COUNT 50
#define FTS_BUILD_NOTIFY_INTERVAL_SECS 10
struct fts_mail {
union mail_module_context module_ctx;
char score[30];
};
struct fts_storage_build_context {
struct mail_search_context *search_ctx;
struct mail_search_args *search_args;
struct fts_backend_build_context *build;
char *content_type, *content_disposition;
};
struct fts_transaction_context {
struct fts_storage_build_context *build_ctx;
unsigned int free_mail:1;
unsigned int expunges:1;
};
{
}
{
return 0;
return -1;
return 0;
}
const struct message_header_line *hdr)
{
struct rfc822_parser_context parser;
(void)rfc822_skip_lwsp(&parser);
T_BEGIN {
}
} T_END;
}
static void
const struct message_header_line *hdr)
{
/* just pass it as-is to backend. */
}
const struct message_block *raw_block)
{
}
const struct message_block *block)
{
/* hdr->full_value is always set because we get the block from
message_decoder */
if (!hdr->no_newline)
}
{
struct message_parser_ctx *parser;
struct message_decoder_context *decoder;
int ret;
return -1;
0);
for (;;) {
if (ret < 0) {
if (input->stream_errno == 0)
ret = 0;
break;
}
/* body part changed. we're now parsing the end of
boundary, possibly followed by message epilogue */
}
/* multipart. skip until beginning of next
part's headers */
}
}
/* always handle headers */
/* end of headers */
} else {
if (skip_body)
continue;
}
&block))
continue;
/* end of headers */
} else {
ret = -1;
break;
}
}
}
if (ret == 0) {
/* Index all headers at the end. This is required for Squat,
because it can handle only incremental UIDs. */
}
return ret;
}
struct fts_backend *backend,
struct mailbox_transaction_context *t,
{
struct mail_search_args *search_args;
struct fts_storage_build_context *ctx;
struct fts_backend_build_context *build;
/* we're not updating the index just for header lookups */
return 0;
}
return -1;
/* changed, need to get again the sequences */
if (seq1 == 0) {
/* no new messages */
(void)fts_backend_build_deinit(&build);
return 0;
}
}
return 1;
}
static struct fts_backend *
{
return fbox->backend_fast;
else {
return fbox->backend_substr;
}
}
struct mailbox_transaction_context *t)
{
struct fts_backend *backend;
int ret;
return -1;
if (seq1 == 0) {
/* no new messages */
return 0;
}
return ret < 0 ? -1 : 0;
}
static int
{
struct fts_backend *backend;
if (seq1 == 0)
return 0;
}
const struct fts_orig_mailboxes *box2)
{
int ret;
T_BEGIN {
} T_END;
return ret;
}
static int
const struct fts_backend_uid_map *map2)
{
}
{
struct mailbox_status status;
const struct fts_orig_mailboxes *boxes;
const struct fts_backend_uid_map *last_uids;
const char *vname;
return 0;
if (ret == 0) {
/* match. check also that uidvalidity matches. */
&status);
uidi++;
continue;
}
boxi++;
uidi++;
} else if (ret > 0) {
/* not part of this virtual mailbox */
uidi++;
} else {
/* no messages indexed in the mailbox */
boxi++;
}
}
boxi++;
}
return vret;
}
static const char *
{
/* ugly workaround to allow selecting INBOX from a Maildir/
when it's not in the inbox=yes namespace. */
return "INBOX";
}
return name;
}
{
const struct fts_orig_mailboxes *orig_boxes;
struct fts_orig_mailboxes orig_box;
unsigned int i, box_count;
int ret;
for (i = 0; i < box_count; i++) {
}
if (box_count <= 0) {
if (box_count == 0) {
/* empty virtual mailbox */
return 0;
}
/* virtual mailbox is built from only a single mailbox
(currently). check that directly. */
return ret;
}
/* virtual mailbox is built from multiple mailboxes. figure out which
ones need updating. */
return -1;
}
return ret < 0 ? -1 : 0;
}
{
struct mailbox_status status;
int ret;
&status);
/* no new messages since last check */
return 0;
}
else
/* index was up-to-date */
}
return ret;
}
{
struct mailbox_status status;
int ret = 0;
ret = -1;
ret = -1;
if (ret == 0) {
&status);
}
/* we notified at least once */
}
return ret;
}
{
/* set the search time in here, in case a plugin
already spent some time indexing the mailbox */
double completed_frac;
unsigned int eta_secs;
if (seq_diff != 0) {
if (completed_frac >= 0.000001) {
unsigned int elapsed_msecs, est_total_msecs;
&ctx->search_start_time);
} else {
eta_secs = 0;
}
} else {
completed_frac = 0.0;
eta_secs = 0;
}
T_BEGIN {
const char *text;
} T_END;
}
}
{
unsigned int count = 0;
int ret;
T_BEGIN {
} T_END;
if (ret < 0)
return -1;
if (++count == FTS_SEARCH_NONBLOCK_COUNT)
return 0;
}
return 1;
}
struct fts_search_context *fctx)
{
}
ctx->progress_cur = 0;
}
struct fts_search_context *fctx)
{
return TRUE;
}
/* this process is already building the indexes */
return FALSE;
}
if (fts_build_init(fctx) < 0) {
return TRUE;
}
/* the index was up to date */
} else {
/* hide "searching" notifications */
}
return TRUE;
}
static struct mail_search_context *
struct mail_search_args *args,
const enum mail_sort_type *sort_program)
{
struct mail_search_context *ctx;
struct fts_search_context *fctx;
fctx->t = t;
return ctx;
return ctx;
}
static bool
{
int ret;
if (!fctx->build_initialized) {
/* we're still waiting for this process (but another command)
to finish building the indexes */
*tryagain_r = TRUE;
return FALSE;
}
}
/* this command is still building the indexes */
if (ret == 0) {
*tryagain_r = TRUE;
return FALSE;
}
/* finished / error */
ret = -1;
if (ret > 0) {
if (fts_build_init_virtual_next(fctx) == 0) {
/* all finished */
}
}
}
/* if we're here, the indexes are either built or they're not used */
}
static void
{
struct mail_search_arg *arg;
case SEARCH_TEXT:
case SEARCH_BODY:
/* we're marking only fast args */
break;
}
case SEARCH_BODY_FAST:
case SEARCH_TEXT_FAST:
break;
default:
break;
}
}
}
{
struct mailbox_status status;
}
{
unsigned int def_count, maybe_count;
/* fts_search_lookup() was called successfully */
for (;;) {
&def_count);
&maybe_count);
/* if we're ahead of current positions, skip them */
fctx->definite_idx++;
/* look for the non-indexed mails */
return FALSE;
return search_nonindexed(ctx);
}
} else {
}
if (use_maybe)
else
/* current sequence is already larger than where
range begins, so use the current sequence. */
} else {
}
/* ctx->seq points to previous sequence we want */
break;
}
if (!use_maybe) {
/* we have definite results, update args */
}
/* this is a virtual mailbox and we're searching headers.
some mailboxes had more messages indexed than others.
to avoid duplicates or jumping around, ignore the rest of
the search results and just go through the messages in
order. */
return search_nonindexed(ctx);
}
return ret;
}
static bool
{
return TRUE;
/* virtual mailbox searches don't return sequences sorted.
just check if the suggested sequence exists. */
return TRUE;
}
return TRUE;
}
return FALSE;
}
{
/* the search was cancelled */
}
}
{
}
{
}
const char **value_r)
{
const struct fts_score_map *scores;
else {
}
return 0;
}
}
{
return;
v->expunge = fts_mail_expunge;
}
{
struct fts_backend *backend;
const char *const *tmp;
continue;
FTS_BACKEND_FLAG_SUBSTRING_LOOKUPS) != 0) {
i_fatal("fts: duplicate substring backend: %s",
*tmp);
}
} else {
i_fatal("fts: duplicate fast backend: %s",
*tmp);
}
}
}
i_debug("fts: No backends enabled by the fts setting");
}
static struct mailbox_transaction_context *
{
struct mailbox_transaction_context *t;
struct fts_transaction_context *ft;
/* the backend creation is delayed until the first transaction is
started. at that point the mailbox has been synced at least once. */
if (!fbox->backend_set) {
}
return t;
}
static void
{
}
static void
bool committed)
{
}
}
}
static void fts_transaction_rollback(struct mailbox_transaction_context *t)
{
}
}
static int
struct mail_transaction_commit_changes *changes_r)
{
int ret;
}
return ret;
}
{
struct fts_mailbox *fbox;
v->free = fts_mailbox_free;
}
{
const char *env;
}