fts-storage.c revision 96308127e006bb3b1108093bcf4cc1fd9481cb7a
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "ioloop.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "array.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "str.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "istream.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "message-parser.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "message-decoder.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mail-namespace.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mail-search-build.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "mail-storage-private.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "fts-api-private.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "fts-storage.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "fts-plugin.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include <stdlib.h>
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#define FTS_CONTEXT(obj) \
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen MODULE_CONTEXT(obj, fts_storage_module)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define FTS_MAIL_CONTEXT(obj) \
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen MODULE_CONTEXT(obj, fts_mail_module)
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen#define FTS_SEARCH_NONBLOCK_COUNT 50
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen#define FTS_BUILD_NOTIFY_INTERVAL_SECS 10
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainenstruct fts_mail {
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen union mail_module_context module_ctx;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen char score[30];
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen};
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenstruct fts_storage_build_context {
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen struct mail_search_context *search_ctx;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mail_search_args *search_args;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail *mail;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct fts_backend_build_context *build;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct timeval search_start_time, last_notify;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t uid;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen string_t *headers;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen};
571fd6ff94570ee11a72a20b649acfdac2495919Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstruct fts_transaction_context {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen union mailbox_transaction_module_context module_ctx;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct fts_storage_build_context *build_ctx;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen ARRAY_TYPE(fts_score_map) *score_map;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct mail *mail;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen uint32_t last_uid;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int free_mail:1;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen unsigned int expunges:1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_storage_module,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen &mail_storage_module_register);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_mail_module, &mail_module_register);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void fts_mailbox_close(struct mailbox *box)
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen{
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(box);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (fbox->backend_substr != NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen fts_backend_deinit(&fbox->backend_substr);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (fbox->backend_fast != NULL)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen fts_backend_deinit(&fbox->backend_fast);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen fbox->module_ctx.super.close(box);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen i_free(fbox);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen}
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic int fts_build_mail_flush_headers(struct fts_storage_build_context *ctx)
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen{
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen if (str_len(ctx->headers) == 0)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (fts_backend_build_more(ctx->build, ctx->uid, str_data(ctx->headers),
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str_len(ctx->headers), TRUE) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str_truncate(ctx->headers, 0);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic bool fts_build_want_index_part(const struct message_block *block)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* we'll index only text/xxx and message/rfc822 parts for now */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return (block->part->flags &
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (MESSAGE_PART_FLAG_TEXT |
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void fts_build_mail_header(struct fts_storage_build_context *ctx,
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen const struct message_block *block)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct message_header_line *hdr = block->hdr;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* hdr->full_value is always set because we get the block from
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen message_decoder */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen str_append(ctx->headers, hdr->name);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str_append_n(ctx->headers, hdr->middle, hdr->middle_len);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen str_append_n(ctx->headers, hdr->full_value, hdr->full_value_len);
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen if (!hdr->no_newline)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str_append_c(ctx->headers, '\n');
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen}
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int fts_build_mail(struct fts_storage_build_context *ctx, uint32_t uid)
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct istream *input;
53cd46dd843c22f21f7e6efcc52a3e0f76cd1e52Timo Sirainen struct message_parser_ctx *parser;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct message_decoder_context *decoder;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct message_block raw_block, block;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct message_part *prev_part, *parts;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen int ret;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen ctx->uid = uid;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_get_stream(ctx->mail, NULL, NULL, &input) < 0)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen return -1;
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen prev_part = NULL;
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen parser = message_parser_init(pool_datastack_create(), input,
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE,
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen 0);
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen decoder = message_decoder_init(MESSAGE_DECODER_FLAG_DTCASE);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen for (;;) {
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen ret = message_parser_parse_next_block(parser, &raw_block);
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen i_assert(ret != 0);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if (ret < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (input->stream_errno == 0)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen ret = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (raw_block.hdr == NULL && raw_block.size != 0 &&
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen !fts_build_want_index_part(&raw_block)) {
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen /* skipping this body */
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen continue;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen }
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen if (!message_decoder_decode_next_block(decoder, &raw_block,
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen &block))
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen continue;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (block.hdr != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fts_build_mail_header(ctx, &block);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen else if (block.size == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* end of headers */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen str_append_c(ctx->headers, '\n');
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fts_backend_build_more(ctx->build, ctx->uid,
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen block.data, block.size,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen FALSE) < 0) {
53cd46dd843c22f21f7e6efcc52a3e0f76cd1e52Timo Sirainen ret = -1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen break;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen }
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen if (message_parser_deinit(&parser, &parts) < 0)
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen mail_set_cache_corrupted(ctx->mail, MAIL_FETCH_MESSAGE_PARTS);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen message_decoder_deinit(&decoder);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret == 0) {
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen /* Index all headers at the end. This is required for Squat,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen because it can handle only incremental UIDs. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ret = fts_build_mail_flush_headers(ctx);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen return ret;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int fts_build_init_seq(struct fts_search_context *fctx,
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen struct fts_backend *backend,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct mailbox_transaction_context *t,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen uint32_t seq1, uint32_t seq2, uint32_t last_uid)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen struct mail_search_args *search_args;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct fts_storage_build_context *ctx;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct fts_backend_build_context *build;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen uint32_t last_uid_locked;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (fctx->best_arg->type == SEARCH_HEADER ||
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fctx->best_arg->type == SEARCH_HEADER_COMPRESS_LWSP) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* we're not updating the index just for header lookups */
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (seq1 < fctx->first_nonindexed_seq)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fctx->first_nonindexed_seq = seq1;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
53cd46dd843c22f21f7e6efcc52a3e0f76cd1e52Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (fts_backend_build_init(backend, &last_uid_locked, &build) < 0)
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen return -1;
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen if (last_uid != last_uid_locked && last_uid_locked != (uint32_t)-1) {
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen /* changed, need to get again the sequences */
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen last_uid = last_uid_locked;
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen mailbox_get_seq_range(t->box, last_uid+1, (uint32_t)-1,
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen &seq1, &seq2);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen if (seq1 == 0) {
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen /* no new messages */
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen (void)fts_backend_build_deinit(&build);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen return 0;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen search_args = mail_search_build_init();
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen mail_search_build_add_seqset(search_args, seq1, seq2);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ctx = i_new(struct fts_storage_build_context, 1);
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen ctx->build = build;
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen ctx->headers = str_new(default_pool, 512);
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen ctx->mail = mail_alloc(t, 0, NULL);
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen ctx->search_ctx = mailbox_search_init(t, search_args, NULL);
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen ctx->search_ctx->progress_hidden = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen ctx->search_args = search_args;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen fctx->build_ctx = ctx;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return 1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic struct fts_backend *
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenfts_mailbox_get_backend(struct fts_search_context *fctx,
4e8d6d03c2ff85448df79b181a2ea850fb5d4199Timo Sirainen struct mailbox *box)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(box);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (fctx->build_backend == fctx->fbox->backend_fast)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return fbox->backend_fast;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen else {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(fctx->build_backend == fctx->fbox->backend_substr);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return fbox->backend_substr;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic int fts_build_init_trans(struct fts_search_context *fctx,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct mailbox_transaction_context *t)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct fts_backend *backend;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen uint32_t last_uid, seq1, seq2;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen int ret;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen backend = fts_mailbox_get_backend(fctx, t->box);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (fts_backend_get_last_uid(backend, &last_uid) < 0)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return -1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mailbox_get_seq_range(t->box, last_uid+1, (uint32_t)-1, &seq1, &seq2);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (seq1 == 0) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen /* no new messages */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return 0;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen ret = fts_build_init_seq(fctx, backend, t, seq1, seq2, last_uid);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return ret < 0 ? -1 : 0;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic int
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenfts_build_init_box(struct fts_search_context *fctx, struct mailbox *box,
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen uint32_t last_uid)
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen{
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen struct fts_backend *backend;
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen uint32_t seq1, seq2;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen mailbox_get_seq_range(box, last_uid + 1, (uint32_t)-1, &seq1, &seq2);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (seq1 == 0)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return 0;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen backend = fts_mailbox_get_backend(fctx, box);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen fctx->virtual_ctx.trans = mailbox_transaction_begin(box, 0);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return fts_build_init_seq(fctx, backend, fctx->virtual_ctx.trans,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen seq1, seq2, last_uid);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
989cafb9d84d8c98d6441fc1ab45b4c37762a98aTimo Sirainenstatic int mailbox_name_cmp(const struct fts_orig_mailboxes *box1,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct fts_orig_mailboxes *box2)
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen{
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen int ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen T_BEGIN {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen string_t *tmp1, *tmp2;
53cd46dd843c22f21f7e6efcc52a3e0f76cd1e52Timo Sirainen const char *vname1, *vname2;
989cafb9d84d8c98d6441fc1ab45b4c37762a98aTimo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen tmp1 = t_str_new(128);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen tmp2 = t_str_new(128);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen vname1 = mail_namespace_get_vname(box1->ns, tmp1, box1->name);
989cafb9d84d8c98d6441fc1ab45b4c37762a98aTimo Sirainen vname2 = mail_namespace_get_vname(box2->ns, tmp2, box2->name);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen ret = strcmp(vname1, vname2);
989cafb9d84d8c98d6441fc1ab45b4c37762a98aTimo Sirainen } T_END;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainenstatic int
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainenfts_backend_uid_map_mailbox_cmp(const struct fts_backend_uid_map *map1,
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen const struct fts_backend_uid_map *map2)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen{
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen return strcmp(map1->mailbox, map2->mailbox);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen}
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainenstatic int fts_build_init_virtual_next(struct fts_search_context *fctx)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen{
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen struct fts_search_virtual_context *vctx = &fctx->virtual_ctx;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen struct mailbox_status status;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen const struct fts_orig_mailboxes *boxes;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen const struct fts_backend_uid_map *last_uids;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen unsigned int boxi, uidi, box_count, last_uid_count;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen const char *vname;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen string_t *tmp;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen int ret, vret = 0;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen if (vctx->pool == NULL)
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen return 0;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen if (fctx->virtual_ctx.trans != NULL)
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen (void)mailbox_transaction_commit(&fctx->virtual_ctx.trans);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen boxes = array_get(&vctx->orig_mailboxes, &box_count);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen last_uids = array_get(&vctx->last_uids, &last_uid_count);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen tmp = t_str_new(256);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen boxi = vctx->boxi;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen uidi = vctx->uidi;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen while (vret == 0 && boxi < box_count && uidi < last_uid_count) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen vname = mail_namespace_get_vname(boxes[boxi].ns, tmp,
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen boxes[boxi].name);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen ret = strcmp(vname, last_uids[uidi].mailbox);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen if (ret == 0) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen /* match. check also that uidvalidity matches. */
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen mailbox_get_status(boxes[boxi].box, STATUS_UIDVALIDITY,
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen &status);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen if (status.uidvalidity != last_uids[uidi].uidvalidity) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen uidi++;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen continue;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen }
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box,
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen last_uids[uidi].uid);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen boxi++;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen uidi++;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen } else if (ret > 0) {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen /* not part of this virtual mailbox */
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen uidi++;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen } else {
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen /* no messages indexed in the mailbox */
71da447014454c84828d9dface77219875554d7dTimo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box, 0);
71da447014454c84828d9dface77219875554d7dTimo Sirainen boxi++;
71da447014454c84828d9dface77219875554d7dTimo Sirainen }
71da447014454c84828d9dface77219875554d7dTimo Sirainen }
71da447014454c84828d9dface77219875554d7dTimo Sirainen while (vret == 0 && boxi < box_count) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box, 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen boxi++;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen vctx->boxi = boxi;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen vctx->uidi = uidi;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return vret;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic const char *
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenfts_box_get_root(struct mailbox *box, struct mail_namespace **ns_r)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mail_namespace *ns = mailbox_get_namespace(box);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const char *name = box->name;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen while (ns->alias_for != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ns = ns->alias_for;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen *ns_r = ns;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (*name == '\0' && ns != mailbox_get_namespace(box) &&
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* ugly workaround to allow selecting INBOX from a Maildir/
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen when it's not in the inbox=yes namespace. */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return "INBOX";
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return name;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int fts_build_init_virtual(struct fts_search_context *fctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct fts_search_virtual_context *vctx = &fctx->virtual_ctx;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ARRAY_TYPE(mailboxes) mailboxes;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox *const *boxes;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const struct fts_orig_mailboxes *orig_boxes;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct fts_orig_mailboxes orig_box;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen unsigned int i, box_count;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen int ret;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen t_array_init(&mailboxes, 64);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_get_virtual_backend_boxes(fctx->t->box, &mailboxes, TRUE);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen boxes = array_get_modifiable(&mailboxes, &box_count);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen vctx->pool = pool_alloconly_create("fts virtual build", 1024);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen p_array_init(&vctx->orig_mailboxes, vctx->pool, box_count);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen memset(&orig_box, 0, sizeof(orig_box));
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen for (i = 0; i < box_count; i++) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen orig_box.box = boxes[i];
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen orig_box.name = fts_box_get_root(boxes[i], &orig_box.ns);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen array_append(&vctx->orig_mailboxes, &orig_box, 1);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen orig_boxes = array_get(&vctx->orig_mailboxes, &box_count);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (box_count <= 0) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (box_count == 0) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* empty virtual mailbox */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return 0;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* virtual mailbox is built from only a single mailbox
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (currently). check that directly. */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen fctx->virtual_ctx.trans =
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_transaction_begin(orig_boxes[0].box, 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = fts_build_init_trans(fctx, fctx->virtual_ctx.trans);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return ret;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* virtual mailbox is built from multiple mailboxes. figure out which
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ones need updating. */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen p_array_init(&vctx->last_uids, vctx->pool, 64);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (fts_backend_get_all_last_uids(fctx->build_backend, vctx->pool,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen &vctx->last_uids) < 0) {
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen pool_unref(&vctx->pool);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return -1;
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen }
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen array_sort(&vctx->orig_mailboxes, mailbox_name_cmp);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen array_sort(&vctx->last_uids, fts_backend_uid_map_mailbox_cmp);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = fts_build_init_virtual_next(fctx);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return ret < 0 ? -1 : 0;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int fts_build_init(struct fts_search_context *fctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox_status status;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen int ret;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_get_status(fctx->t->box, STATUS_MESSAGES | STATUS_UIDNEXT,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen &status);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (status.messages == fctx->fbox->last_messages_count &&
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen status.uidnext == fctx->fbox->last_uidnext) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* no new messages since last check */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return 0;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (fctx->fbox->virtual)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = fts_build_init_virtual(fctx);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen else
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = fts_build_init_trans(fctx, fctx->t);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (ret == 0 && fctx->build_ctx == NULL) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* index was up-to-date */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen fctx->fbox->last_messages_count = status.messages;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen fctx->fbox->last_uidnext = status.uidnext;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return ret;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic int fts_build_deinit(struct fts_storage_build_context **_ctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct fts_storage_build_context *ctx = *_ctx;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox *box = ctx->mail->transaction->box;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(box);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox_status status;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen int ret = 0;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen *_ctx = NULL;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = -1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_free(&ctx->mail);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (fts_backend_build_deinit(&ctx->build) < 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = -1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen if (ret == 0) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mailbox_get_status(box, STATUS_MESSAGES | STATUS_UIDNEXT,
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen &status);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen fbox->last_messages_count = status.messages;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen fbox->last_uidnext = status.uidnext;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen if (ioloop_time - ctx->search_start_time.tv_sec >=
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen FTS_BUILD_NOTIFY_INTERVAL_SECS) {
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen /* we notified at least once */
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen box->storage->callbacks.
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen notify_ok(box, "Mailbox indexing finished",
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen box->storage->callback_context);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen str_free(&ctx->headers);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen mail_search_args_unref(&ctx->search_args);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_free(ctx);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return ret;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void fts_build_notify(struct fts_storage_build_context *ctx)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct mailbox *box = ctx->mail->transaction->box;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const struct seq_range *range;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen float percentage;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen unsigned int msecs, secs;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (ctx->last_notify.tv_sec == 0) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* set the search time in here, in case a plugin
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen already spent some time indexing the mailbox */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ctx->search_start_time = ioloop_timeval;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen } else if (box->storage->callbacks.notify_ok != NULL) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen range = array_idx(&ctx->search_args->args->value.seqset, 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen percentage = (ctx->mail->seq - range->seq1) * 100.0 /
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (range->seq2 - range->seq1);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen msecs = (ioloop_timeval.tv_sec -
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ctx->search_start_time.tv_sec) * 1000 +
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen (ioloop_timeval.tv_usec -
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ctx->search_start_time.tv_usec) / 1000;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen secs = (msecs / (percentage / 100.0) - msecs) / 1000;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen T_BEGIN {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen const char *text;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen text = t_strdup_printf("Indexed %d%% of the mailbox, "
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen "ETA %d:%02d", (int)percentage,
71da447014454c84828d9dface77219875554d7dTimo Sirainen secs/60, secs%60);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen box->storage->callbacks.
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen notify_ok(box, text,
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen box->storage->callback_context);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen } T_END;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen }
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen ctx->last_notify = ioloop_timeval;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen}
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainenstatic int fts_build_more(struct fts_storage_build_context *ctx)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen{
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen unsigned int count = 0;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen int ret;
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen if (ioloop_time - ctx->last_notify.tv_sec >=
FTS_BUILD_NOTIFY_INTERVAL_SECS)
fts_build_notify(ctx);
while (mailbox_search_next(ctx->search_ctx, ctx->mail) > 0) {
T_BEGIN {
ret = fts_build_mail(ctx, ctx->mail->uid);
} T_END;
if (ret < 0)
return -1;
if (++count == FTS_SEARCH_NONBLOCK_COUNT)
return 0;
}
return 1;
}
static void fts_search_init_lookup(struct mail_search_context *ctx,
struct fts_search_context *fctx)
{
fts_search_lookup(fctx);
if (fctx->seqs_set &&
strcmp(ctx->transaction->box->storage->name, "virtual") != 0) {
ctx->progress_max = array_count(&fctx->definite_seqs) +
array_count(&fctx->maybe_seqs);
}
ctx->progress_cur = 0;
}
static bool fts_try_build_init(struct mail_search_context *ctx,
struct fts_search_context *fctx)
{
if (fctx->build_backend == NULL) {
fctx->build_initialized = TRUE;
return TRUE;
}
if (fts_backend_is_building(fctx->build_backend)) {
/* this process is already building the indexes */
return FALSE;
}
fctx->build_initialized = TRUE;
if (fts_build_init(fctx) < 0) {
fctx->build_backend = NULL;
return TRUE;
}
if (fctx->build_ctx == NULL) {
/* the index was up to date */
fts_search_init_lookup(ctx, fctx);
} else {
/* hide "searching" notifications */
ctx->progress_hidden = TRUE;
}
return TRUE;
}
static struct mail_search_context *
fts_mailbox_search_init(struct mailbox_transaction_context *t,
struct mail_search_args *args,
const enum mail_sort_type *sort_program)
{
struct fts_transaction_context *ft = FTS_CONTEXT(t);
struct fts_mailbox *fbox = FTS_CONTEXT(t->box);
struct mail_search_context *ctx;
struct fts_search_context *fctx;
ctx = fbox->module_ctx.super.search_init(t, args, sort_program);
fctx = i_new(struct fts_search_context, 1);
fctx->fbox = fbox;
fctx->t = t;
fctx->args = args;
fctx->first_nonindexed_seq = (uint32_t)-1;
MODULE_CONTEXT_SET(ctx, fts_storage_module, fctx);
if (fbox->backend_substr == NULL && fbox->backend_fast == NULL)
return ctx;
ft->score_map = &fctx->score_map;
fts_search_analyze(fctx);
(void)fts_try_build_init(ctx, fctx);
return ctx;
}
static int fts_mailbox_search_next_nonblock(struct mail_search_context *ctx,
struct mail *mail, bool *tryagain_r)
{
struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
struct fts_search_context *fctx = FTS_CONTEXT(ctx);
int ret;
if (!fctx->build_initialized) {
/* we're still waiting for this process (but another command)
to finish building the indexes */
if (!fts_try_build_init(ctx, fctx)) {
*tryagain_r = TRUE;
return 0;
}
}
while (fctx->build_ctx != NULL) {
/* this command is still building the indexes */
ret = fts_build_more(fctx->build_ctx);
if (ret == 0) {
*tryagain_r = TRUE;
return 0;
}
/* finished / error */
ctx->progress_hidden = FALSE;
if (fts_build_deinit(&fctx->build_ctx) < 0)
ret = -1;
if (ret > 0) {
if (fts_build_init_virtual_next(fctx) == 0) {
/* all finished */
fts_search_init_lookup(ctx, fctx);
}
}
}
/* if we're here, the indexes are either built or they're not used */
return fbox->module_ctx.super.
search_next_nonblock(ctx, mail, tryagain_r);
}
static void
fts_mailbox_search_args_definite_set(struct fts_search_context *fctx)
{
struct mail_search_arg *arg;
for (arg = fctx->args->args; arg != NULL; arg = arg->next) {
switch (arg->type) {
case SEARCH_TEXT:
case SEARCH_BODY:
if (fctx->fbox->backend_substr == NULL) {
/* we're marking only fast args */
break;
}
case SEARCH_BODY_FAST:
case SEARCH_TEXT_FAST:
arg->result = 1;
break;
default:
break;
}
}
}
static bool search_nonindexed(struct mail_search_context *ctx)
{
struct fts_search_context *fctx = FTS_CONTEXT(ctx);
struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
struct mailbox_status status;
mailbox_get_status(ctx->transaction->box, STATUS_MESSAGES, &status);
fctx->seqs_set = FALSE;
ctx->seq = fctx->first_nonindexed_seq - 1;
ctx->progress_cur = ctx->seq;
ctx->progress_max = status.messages;
return fbox->module_ctx.super.search_next_update_seq(ctx);
}
static bool fts_mailbox_search_next_update_seq(struct mail_search_context *ctx)
{
struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
struct fts_search_context *fctx = FTS_CONTEXT(ctx);
struct seq_range *def_range, *maybe_range, *range;
unsigned int def_count, maybe_count;
uint32_t wanted_seq;
bool use_maybe, ret;
if (!fctx->seqs_set)
return fbox->module_ctx.super.search_next_update_seq(ctx);
wanted_seq = ctx->seq + 1;
/* fts_search_lookup() was called successfully */
for (;;) {
def_range = array_get_modifiable(&fctx->definite_seqs,
&def_count);
maybe_range = array_get_modifiable(&fctx->maybe_seqs,
&maybe_count);
/* if we're ahead of current positions, skip them */
while (fctx->definite_idx < def_count &&
wanted_seq > def_range[fctx->definite_idx].seq2)
fctx->definite_idx++;
while (fctx->maybe_idx < maybe_count &&
wanted_seq > maybe_range[fctx->maybe_idx].seq2)
fctx->maybe_idx++;
/* use whichever is lower of definite/maybe */
if (fctx->definite_idx == def_count) {
if (fctx->maybe_idx == maybe_count) {
/* look for the non-indexed mails */
if (fctx->first_nonindexed_seq == (uint32_t)-1)
return FALSE;
return search_nonindexed(ctx);
}
use_maybe = TRUE;
} else if (fctx->maybe_idx == maybe_count) {
use_maybe = FALSE;
} else {
use_maybe = maybe_range[fctx->maybe_idx].seq1 <
def_range[fctx->definite_idx].seq2;
}
if (use_maybe)
range = maybe_range + fctx->maybe_idx;
else
range = def_range + fctx->definite_idx;
i_assert(range->seq1 <= range->seq2);
if (wanted_seq > range->seq1) {
/* current sequence is already larger than where
range begins, so use the current sequence. */
range->seq1 = wanted_seq+1;
} else {
wanted_seq = range->seq1;
range->seq1++;
}
if (range->seq1 > range->seq2)
range->seq2 = 0;
/* ctx->seq points to previous sequence we want */
ctx->seq = wanted_seq - 1;
ret = fbox->module_ctx.super.search_next_update_seq(ctx);
if (!ret || wanted_seq == ctx->seq)
break;
wanted_seq = ctx->seq;
mail_search_args_reset(ctx->args->args, FALSE);
}
if (!use_maybe) {
/* we have definite results, update args */
fts_mailbox_search_args_definite_set(fctx);
}
if (ctx->seq + 1 >= fctx->first_nonindexed_seq) {
/* 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);
}
ctx->progress_cur = fctx->definite_idx + fctx->maybe_idx;
return ret;
}
static bool
fts_mailbox_search_next_update_seq_virtual(struct mail_search_context *ctx)
{
struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
struct fts_search_context *fctx = FTS_CONTEXT(ctx);
while (fbox->module_ctx.super.search_next_update_seq(ctx)) {
if (!fctx->seqs_set)
return TRUE;
/* virtual mailbox searches don't return sequences sorted.
just check if the suggested sequence exists. */
if (seq_range_exists(&fctx->definite_seqs, ctx->seq)) {
fts_mailbox_search_args_definite_set(fctx);
return TRUE;
}
if (seq_range_exists(&fctx->maybe_seqs, ctx->seq))
return TRUE;
mail_search_args_reset(ctx->args->args, FALSE);
}
return FALSE;
}
static int fts_mailbox_search_deinit(struct mail_search_context *ctx)
{
struct fts_transaction_context *ft = FTS_CONTEXT(ctx->transaction);
struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
struct fts_search_context *fctx = FTS_CONTEXT(ctx);
if (ft->score_map == &fctx->score_map)
ft->score_map = NULL;
if (fctx->build_ctx != NULL) {
/* the search was cancelled */
(void)fts_build_deinit(&fctx->build_ctx);
}
if (array_is_created(&fctx->definite_seqs))
array_free(&fctx->definite_seqs);
if (array_is_created(&fctx->maybe_seqs))
array_free(&fctx->maybe_seqs);
if (array_is_created(&fctx->score_map))
array_free(&fctx->score_map);
if (fctx->virtual_ctx.trans != NULL)
(void)mailbox_transaction_commit(&fctx->virtual_ctx.trans);
if (fctx->virtual_ctx.pool != NULL)
pool_unref(&fctx->virtual_ctx.pool);
i_free(fctx);
return fbox->module_ctx.super.search_deinit(ctx);
}
static void fts_mail_expunge(struct mail *_mail)
{
struct mail_private *mail = (struct mail_private *)_mail;
struct fts_mail *fmail = FTS_MAIL_CONTEXT(mail);
struct fts_mailbox *fbox = FTS_CONTEXT(_mail->box);
struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction);
ft->expunges = TRUE;
if (fbox->backend_substr != NULL)
fts_backend_expunge(fbox->backend_substr, _mail);
if (fbox->backend_fast != NULL)
fts_backend_expunge(fbox->backend_fast, _mail);
fmail->module_ctx.super.expunge(_mail);
}
static int fts_score_cmp(const uint32_t *uid, const struct fts_score_map *score)
{
return *uid < score->uid ? -1 :
(*uid > score->uid ? 1 : 0);
}
static int fts_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
const char **value_r)
{
struct mail_private *mail = (struct mail_private *)_mail;
struct fts_mail *fmail = FTS_MAIL_CONTEXT(mail);
struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction);
const struct fts_score_map *scores;
if (field != MAIL_FETCH_SEARCH_SCORE || ft->score_map == NULL ||
!array_is_created(ft->score_map))
scores = NULL;
else {
scores = array_bsearch(ft->score_map, &_mail->uid,
fts_score_cmp);
}
if (scores != NULL) {
i_assert(scores->uid == _mail->uid);
i_snprintf(fmail->score, sizeof(fmail->score),
"%f", scores->score);
*value_r = fmail->score;
return 0;
}
return fmail->module_ctx.super.get_special(_mail, field, value_r);
}
static struct mail *
fts_mail_alloc(struct mailbox_transaction_context *t,
enum mail_fetch_field wanted_fields,
struct mailbox_header_lookup_ctx *wanted_headers)
{
struct fts_mailbox *fbox = FTS_CONTEXT(t->box);
struct fts_mail *fmail;
struct mail *_mail;
struct mail_private *mail;
_mail = fbox->module_ctx.super.
mail_alloc(t, wanted_fields, wanted_headers);
if (fbox->backend_substr != NULL || fbox->backend_fast != NULL) {
mail = (struct mail_private *)_mail;
fmail = p_new(mail->pool, struct fts_mail, 1);
fmail->module_ctx.super = mail->v;
mail->v.expunge = fts_mail_expunge;
mail->v.get_special = fts_mail_get_special;
MODULE_CONTEXT_SET(mail, fts_mail_module, fmail);
}
return _mail;
}
static void fts_box_backends_init(struct mailbox *box)
{
struct fts_mailbox *fbox = FTS_CONTEXT(box);
struct fts_backend *backend;
const char *const *tmp;
for (tmp = t_strsplit(fbox->env, ", "); *tmp != NULL; tmp++) {
backend = fts_backend_init(*tmp, box);
if (backend == NULL)
continue;
if ((backend->flags &
FTS_BACKEND_FLAG_SUBSTRING_LOOKUPS) != 0) {
if (fbox->backend_substr != NULL) {
i_fatal("fts: duplicate substring backend: %s",
*tmp);
}
fbox->backend_substr = backend;
} else {
if (fbox->backend_fast != NULL) {
i_fatal("fts: duplicate fast backend: %s",
*tmp);
}
fbox->backend_fast = backend;
}
}
if (box->storage->set->mail_debug &&
fbox->backend_substr == NULL && fbox->backend_fast == NULL)
i_info("fts: No backends enabled by the fts setting");
}
static struct mailbox_transaction_context *
fts_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags)
{
struct fts_mailbox *fbox = FTS_CONTEXT(box);
struct mailbox_transaction_context *t;
struct fts_transaction_context *ft;
ft = i_new(struct fts_transaction_context, 1);
/* 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) {
fts_box_backends_init(box);
fbox->backend_set = TRUE;
}
t = fbox->module_ctx.super.transaction_begin(box, flags);
MODULE_CONTEXT_SET(t, fts_storage_module, ft);
return t;
}
static void
fts_storage_build_context_deinit(struct fts_storage_build_context *build_ctx)
{
(void)fts_backend_build_deinit(&build_ctx->build);
str_free(&build_ctx->headers);
i_free(build_ctx);
}
static void
fts_transaction_finish(struct mailbox *box, struct fts_transaction_context *ft,
bool committed)
{
struct fts_mailbox *fbox = FTS_CONTEXT(box);
if (ft->expunges) {
if (fbox->backend_fast != NULL) {
fts_backend_expunge_finish(fbox->backend_fast,
box, committed);
}
}
i_free(ft);
}
static void fts_transaction_rollback(struct mailbox_transaction_context *t)
{
struct mailbox *box = t->box;
struct fts_mailbox *fbox = FTS_CONTEXT(box);
struct fts_transaction_context *ft = FTS_CONTEXT(t);
if (ft->build_ctx != NULL) {
fts_storage_build_context_deinit(ft->build_ctx);
ft->build_ctx = NULL;
}
if (ft->free_mail)
mail_free(&ft->mail);
fbox->module_ctx.super.transaction_rollback(t);
fts_transaction_finish(box, ft, FALSE);
}
static int
fts_transaction_commit(struct mailbox_transaction_context *t,
struct mail_transaction_commit_changes *changes_r)
{
struct mailbox *box = t->box;
struct fts_mailbox *fbox = FTS_CONTEXT(box);
struct fts_transaction_context *ft = FTS_CONTEXT(t);
int ret;
if (ft->build_ctx != NULL) {
fts_storage_build_context_deinit(ft->build_ctx);
ft->build_ctx = NULL;
}
if (ft->free_mail)
mail_free(&ft->mail);
ret = fbox->module_ctx.super.transaction_commit(t, changes_r);
fts_transaction_finish(box, ft, ret == 0);
return ret;
}
static void fts_mailbox_init(struct mailbox *box, const char *env)
{
struct fts_mailbox *fbox;
fbox = i_new(struct fts_mailbox, 1);
fbox->virtual = strcmp(box->storage->name, "virtual") == 0;
fbox->env = env;
fbox->module_ctx.super = box->v;
box->v.close = fts_mailbox_close;
box->v.search_init = fts_mailbox_search_init;
box->v.search_next_nonblock = fts_mailbox_search_next_nonblock;
box->v.search_next_update_seq = fbox->virtual ?
fts_mailbox_search_next_update_seq_virtual :
fts_mailbox_search_next_update_seq;
box->v.search_deinit = fts_mailbox_search_deinit;
box->v.mail_alloc = fts_mail_alloc;
box->v.transaction_begin = fts_transaction_begin;
box->v.transaction_rollback = fts_transaction_rollback;
box->v.transaction_commit = fts_transaction_commit;
MODULE_CONTEXT_SET(box, fts_storage_module, fbox);
}
void fts_mailbox_allocated(struct mailbox *box)
{
const char *env;
env = mail_user_plugin_getenv(box->storage->user, "fts");
if (env != NULL)
fts_mailbox_init(box, env);
if (fts_next_hook_mailbox_allocated != NULL)
fts_next_hook_mailbox_allocated(box);
}