fts-storage.c revision 437a8b0fe254057b0c1f1723d689bafa91cae2ab
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2006-2011 Dovecot authors, see the included COPYING file */
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen struct timeval search_start_time, last_notify;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union mailbox_transaction_module_context module_ctx;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_storage_module,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(fts_mail_module, &mail_module_register);
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainenstatic void fts_mailbox_free(struct mailbox *box)
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainenstatic int fts_build_mail_flush_headers(struct fts_storage_build_context *ctx)
ec02103893ae3748e5b593340995bb2489c4b741Timo Sirainen i_assert(uni_utf8_data_is_valid(ctx->headers->data, ctx->headers->used));
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen if (fts_backend_build_more(ctx->build, str_data(ctx->headers),
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainenstatic void fts_build_parse_content_type(struct fts_storage_build_context *ctx,
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen if (rfc822_parse_content_type(&parser, content_type) >= 0) {
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen ctx->content_type = i_strdup(str_c(content_type));
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainenfts_build_parse_content_disposition(struct fts_storage_build_context *ctx,
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen /* just pass it as-is to backend. */
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen i_strndup(hdr->full_value, hdr->full_value_len);
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainenstatic void fts_parse_mail_header(struct fts_storage_build_context *ctx,
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen const struct message_header_line *hdr = raw_block->hdr;
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen if (strcasecmp(hdr->name, "Content-Type") == 0)
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen else if (strcasecmp(hdr->name, "Content-Disposition") == 0)
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen fts_build_parse_content_disposition(ctx, hdr);
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainenstatic void fts_build_mail_header(struct fts_storage_build_context *ctx,
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen const struct message_header_line *hdr = block->hdr;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen /* hdr->full_value is always set because we get the block from
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen message_decoder */
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen str_append_n(ctx->headers, hdr->middle, hdr->middle_len);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen str_append_n(ctx->headers, hdr->full_value, hdr->full_value_len);
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainenfts_build_mail(struct fts_storage_build_context *ctx, struct mail *mail)
2116e38edb504e72eadaf5a51c3dd9b1a81039eaTimo Sirainen enum message_decoder_flags decoder_flags = MESSAGE_DECODER_FLAG_DTCASE;
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen if (mail_get_stream(mail, NULL, NULL, &input) < 0)
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen parser = message_parser_init(pool_datastack_create(), input,
2116e38edb504e72eadaf5a51c3dd9b1a81039eaTimo Sirainen if ((ctx->build->backend->flags & FTS_BACKEND_FLAG_BINARY_MIME_PARTS) != 0)
2116e38edb504e72eadaf5a51c3dd9b1a81039eaTimo Sirainen decoder_flags |= MESSAGE_DECODER_FLAG_RETURN_BINARY;
2116e38edb504e72eadaf5a51c3dd9b1a81039eaTimo Sirainen decoder = message_decoder_init(decoder_flags);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen ret = message_parser_parse_next_block(parser, &raw_block);
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen /* body part changed. we're now parsing the end of
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen boundary, possibly followed by message epilogue */
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen /* multipart. skip until beginning of next
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen part's headers */
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen /* always handle headers */
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen /* end of headers */
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen const char *content_type = ctx->content_type == NULL ?
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen skip_body = !fts_backend_build_body_begin(ctx->build,
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (!message_decoder_decode_next_block(decoder, &raw_block,
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen /* end of headers */
992118a50af940482b6cf884a89be56d7015580aTimo Sirainen if (message_parser_deinit(&parser, &parts) < 0)
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen mail_set_cache_corrupted(mail, MAIL_FETCH_MESSAGE_PARTS);
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen /* Index all headers at the end. This is required for Squat,
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen because it can handle only incremental UIDs. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic int fts_build_init_seq(struct fts_search_context *fctx,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen uint32_t seq1, uint32_t seq2, uint32_t last_uid)
e22b857e838fe118de3f78513aad6a3c6f4306b3Timo Sirainen fctx->best_arg->type == SEARCH_HEADER_COMPRESS_LWSP) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* we're not updating the index just for header lookups */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (fts_backend_build_init(backend, &last_uid_locked, &build) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (last_uid != last_uid_locked && last_uid_locked != (uint32_t)-1) {
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen /* changed, need to get again the sequences */
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen mailbox_get_seq_range(t->box, last_uid+1, (uint32_t)-1,
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen /* no new messages */
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen mail_search_build_add_seqset(search_args, seq1, seq2);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen ctx = i_new(struct fts_storage_build_context, 1);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx->search_ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic struct fts_backend *
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenfts_mailbox_get_backend(struct fts_search_context *fctx,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fctx->build_backend == fctx->fbox->backend_fast)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen i_assert(fctx->build_backend == fctx->fbox->backend_substr);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic int fts_build_init_trans(struct fts_search_context *fctx,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen backend = fts_mailbox_get_backend(fctx, t->box);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fts_backend_get_last_uid(backend, &last_uid) < 0)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen mailbox_get_seq_range(t->box, last_uid+1, (uint32_t)-1, &seq1, &seq2);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* no new messages */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ret = fts_build_init_seq(fctx, backend, t, seq1, seq2, last_uid);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenfts_build_init_box(struct fts_search_context *fctx, struct mailbox *box,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen mailbox_get_seq_range(box, last_uid + 1, (uint32_t)-1, &seq1, &seq2);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen fctx->virtual_ctx.trans = mailbox_transaction_begin(box, 0);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return fts_build_init_seq(fctx, backend, fctx->virtual_ctx.trans,
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenstatic int mailbox_name_cmp(const struct fts_orig_mailboxes *box1,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen vname1 = mailbox_list_get_vname(box1->ns->list, box1->name);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen vname2 = mailbox_list_get_vname(box2->ns->list, box2->name);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenfts_backend_uid_map_mailbox_cmp(const struct fts_backend_uid_map *map1,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic int fts_build_init_virtual_next(struct fts_search_context *fctx)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fts_search_virtual_context *vctx = &fctx->virtual_ctx;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen unsigned int boxi, uidi, box_count, last_uid_count;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen (void)mailbox_transaction_commit(&fctx->virtual_ctx.trans);
ff01c351d308504551048039304725d578978c2eTimo Sirainen boxes = array_get(&vctx->orig_mailboxes, &box_count);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen last_uids = array_get(&vctx->last_uids, &last_uid_count);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen while (vret == 0 && boxi < box_count && uidi < last_uid_count) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen vname = mailbox_list_get_vname(boxes[boxi].ns->list,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* match. check also that uidvalidity matches. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (status.uidvalidity != last_uids[uidi].uidvalidity) {
ff01c351d308504551048039304725d578978c2eTimo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen } else if (ret > 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* not part of this virtual mailbox */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* no messages indexed in the mailbox */
ff01c351d308504551048039304725d578978c2eTimo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box, 0);
ff01c351d308504551048039304725d578978c2eTimo Sirainen vret = fts_build_init_box(fctx, boxes[boxi].box, 0);
ff01c351d308504551048039304725d578978c2eTimo Sirainenstatic const char *
ff01c351d308504551048039304725d578978c2eTimo Sirainenfts_box_get_root(struct mailbox *box, struct mail_namespace **ns_r)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_namespace *ns = mailbox_get_namespace(box);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (*name == '\0' && ns != mailbox_get_namespace(box) &&
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
ff01c351d308504551048039304725d578978c2eTimo Sirainen /* ugly workaround to allow selecting INBOX from a Maildir/
ff01c351d308504551048039304725d578978c2eTimo Sirainen when it's not in the inbox=yes namespace. */
ff01c351d308504551048039304725d578978c2eTimo Sirainen return "INBOX";
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic int fts_build_init_virtual(struct fts_search_context *fctx)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct fts_search_virtual_context *vctx = &fctx->virtual_ctx;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen unsigned int i, box_count;
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainen fts_mailbox_get_virtual_backend_boxes(fctx->t->box, &mailboxes, TRUE);
ff01c351d308504551048039304725d578978c2eTimo Sirainen boxes = array_get_modifiable(&mailboxes, &box_count);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen vctx->pool = pool_alloconly_create("fts virtual build", 1024);
ff01c351d308504551048039304725d578978c2eTimo Sirainen p_array_init(&vctx->orig_mailboxes, vctx->pool, box_count);
ff01c351d308504551048039304725d578978c2eTimo Sirainen for (i = 0; i < box_count; i++) {
ff01c351d308504551048039304725d578978c2eTimo Sirainen orig_box.name = fts_box_get_root(boxes[i], &orig_box.ns);
ff01c351d308504551048039304725d578978c2eTimo Sirainen array_append(&vctx->orig_mailboxes, &orig_box, 1);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen orig_boxes = array_get(&vctx->orig_mailboxes, &box_count);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* empty virtual mailbox */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* virtual mailbox is built from only a single mailbox
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen (currently). check that directly. */
ff01c351d308504551048039304725d578978c2eTimo Sirainen mailbox_transaction_begin(orig_boxes[0].box, 0);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ret = fts_build_init_trans(fctx, fctx->virtual_ctx.trans);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* virtual mailbox is built from multiple mailboxes. figure out which
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ones need updating. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen p_array_init(&vctx->last_uids, vctx->pool, 64);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fts_backend_get_all_last_uids(fctx->build_backend, vctx->pool,
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&vctx->orig_mailboxes, mailbox_name_cmp);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&vctx->last_uids, fts_backend_uid_map_mailbox_cmp);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic int fts_build_init(struct fts_search_context *fctx)
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen mailbox_get_open_status(fctx->t->box, STATUS_MESSAGES | STATUS_UIDNEXT,
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen if (status.messages == fctx->fbox->last_messages_count &&
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen /* no new messages since last check */
b86dc9680d4a15312c5f0607c80402a19f659eb6Timo Sirainen (fctx->build_backend->flags & FTS_BACKEND_FLAG_VIRTUAL_LOOKUPS) != 0)
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen /* index was up-to-date */
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen fctx->fbox->last_messages_count = status.messages;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic int fts_build_deinit(struct fts_storage_build_context **_ctx)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct fts_storage_build_context *ctx = *_ctx;
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen struct mailbox *box = ctx->search_ctx->transaction->box;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (mailbox_search_deinit(&ctx->search_ctx) < 0)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (fts_backend_build_deinit(&ctx->build) < 0)
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_UIDNEXT,
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen if (ioloop_time - ctx->search_start_time.tv_sec >=
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen /* we notified at least once */
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainenfts_build_notify(struct fts_storage_build_context *ctx, uint32_t seq)
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen struct mailbox *box = ctx->search_ctx->transaction->box;
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen /* set the search time in here, in case a plugin
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen already spent some time indexing the mailbox */
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen } else if (box->storage->callbacks.notify_ok != NULL) {
c17099a136754ce37e346f6f98dfa1fe709ee772Timo Sirainen range = array_idx(&ctx->search_args->args->value.seqset, 0);
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen completed_frac = (double)(seq - range->seq1) / seq_diff;
c17099a136754ce37e346f6f98dfa1fe709ee772Timo Sirainen elapsed_msecs = timeval_diff_msecs(&ioloop_timeval,
c17099a136754ce37e346f6f98dfa1fe709ee772Timo Sirainen est_total_msecs = elapsed_msecs / completed_frac;
c17099a136754ce37e346f6f98dfa1fe709ee772Timo Sirainen eta_secs = (est_total_msecs - elapsed_msecs) / 1000;
c17099a136754ce37e346f6f98dfa1fe709ee772Timo Sirainen text = t_strdup_printf("Indexed %d%% of the mailbox, "
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenstatic int fts_build_more(struct fts_storage_build_context *ctx)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen unsigned int count = 0;
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen while (mailbox_search_next(ctx->search_ctx, &mail)) {
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen FTS_BUILD_NOTIFY_INTERVAL_SECS && mail != NULL)
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainenstatic void fts_search_init_lookup(struct mail_search_context *ctx,
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen strcmp(ctx->transaction->box->storage->name, "virtual") != 0) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen ctx->progress_max = array_count(&fctx->definite_seqs) +
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainenstatic bool fts_try_build_init(struct mail_search_context *ctx,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (fts_backend_is_building(fctx->build_backend)) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* this process is already building the indexes */
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen /* the index was up to date */
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen /* hide "searching" notifications */
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenfts_mailbox_search_init(struct mailbox_transaction_context *t,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(t);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(t->box);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx = fbox->module_ctx.super.search_init(t, args, sort_program,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET(ctx, fts_storage_module, fctx);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (fbox->backend_substr == NULL && fbox->backend_fast == NULL)
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainenstatic int fts_mailbox_search_build_more(struct mail_search_context *ctx)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* this command is still building the indexes */
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen /* finished / error */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* all finished */
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainenfts_mailbox_search_next_nonblock(struct mail_search_context *ctx,
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen /* we're still waiting for this process (but another command)
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen to finish building the indexes */
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen if (fts_mailbox_search_build_more(ctx) == 0) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* if we're here, the indexes are either built or they're not used */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen search_next_nonblock(ctx, mail_r, tryagain_r);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenfts_mailbox_search_args_definite_set(struct fts_search_context *fctx)
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen for (arg = fctx->args->args; arg != NULL; arg = arg->next) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen /* we're marking only fast args */
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainenstatic bool search_nonindexed(struct mail_search_context *ctx)
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen mailbox_get_open_status(ctx->transaction->box,
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen return fbox->module_ctx.super.search_next_update_seq(ctx);
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainenstatic bool fts_mailbox_search_next_update_seq(struct mail_search_context *ctx)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct seq_range *def_range, *maybe_range, *range;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return fbox->module_ctx.super.search_next_update_seq(ctx);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* fts_search_lookup() was called successfully */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen def_range = array_get_modifiable(&fctx->definite_seqs,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen maybe_range = array_get_modifiable(&fctx->maybe_seqs,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* if we're ahead of current positions, skip them */
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen wanted_seq > def_range[fctx->definite_idx].seq2)
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen wanted_seq > maybe_range[fctx->maybe_idx].seq2)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* use whichever is lower of definite/maybe */
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen /* look for the non-indexed mails */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (fctx->first_nonindexed_seq == (uint32_t)-1)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen use_maybe = maybe_range[fctx->maybe_idx].seq1 <
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* current sequence is already larger than where
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen range begins, so use the current sequence. */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* ctx->seq points to previous sequence we want */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ret = fbox->module_ctx.super.search_next_update_seq(ctx);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen mail_search_args_reset(ctx->args->args, FALSE);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* we have definite results, update args */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (ctx->seq + 1 >= fctx->first_nonindexed_seq) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* this is a virtual mailbox and we're searching headers.
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen some mailboxes had more messages indexed than others.
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen to avoid duplicates or jumping around, ignore the rest of
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen the search results and just go through the messages in
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen ctx->progress_cur = fctx->definite_idx + fctx->maybe_idx;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenfts_mailbox_search_next_update_seq_virtual(struct mail_search_context *ctx)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen while (fbox->module_ctx.super.search_next_update_seq(ctx)) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen /* virtual mailbox searches don't return sequences sorted.
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen just check if the suggested sequence exists. */
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (seq_range_exists(&fctx->definite_seqs, ctx->seq)) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (seq_range_exists(&fctx->maybe_seqs, ctx->seq))
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen mail_search_args_reset(ctx->args->args, FALSE);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic int fts_mailbox_search_deinit(struct mail_search_context *ctx)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(ctx->transaction);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(ctx->transaction->box);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct fts_search_context *fctx = FTS_CONTEXT(ctx);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen /* the search was cancelled */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen (void)mailbox_transaction_commit(&fctx->virtual_ctx.trans);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return fbox->module_ctx.super.search_deinit(ctx);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic void fts_mail_expunge(struct mail *_mail)
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen struct fts_mail *fmail = FTS_MAIL_CONTEXT(mail);
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(_mail->box);
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen fts_backend_expunge(fbox->backend_substr, _mail);
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen fts_backend_expunge(fbox->backend_fast, _mail);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenstatic int fts_score_cmp(const uint32_t *uid, const struct fts_score_map *score)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainenstatic int fts_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen const char **value_r)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen struct fts_mail *fmail = FTS_MAIL_CONTEXT(mail);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(_mail->transaction);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (field != MAIL_FETCH_SEARCH_SCORE || ft->score_map == NULL ||
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen scores = array_bsearch(ft->score_map, &_mail->uid,
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen i_snprintf(fmail->score, sizeof(fmail->score),
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen return fmail->module_ctx.super.get_special(_mail, field, value_r);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen struct fts_mailbox *fbox = FTS_CONTEXT(_mail->box);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen (fbox->backend_substr == NULL && fbox->backend_fast == NULL))
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen fmail = p_new(mail->pool, struct fts_mail, 1);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen MODULE_CONTEXT_SET(mail, fts_mail_module, fmail);
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainenstatic void fts_box_backends_init(struct mailbox *box)
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen const char *const *tmp;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen for (tmp = t_strsplit(fbox->env, ", "); *tmp != NULL; tmp++) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen i_fatal("fts: duplicate substring backend: %s",
14bb36cbb67b42e32105c3d843a8c974dc7ed436Timo Sirainen fbox->backend_substr == NULL && fbox->backend_fast == NULL)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("fts: No backends enabled by the fts setting");
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen ft = i_new(struct fts_transaction_context, 1);
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen /* the backend creation is delayed until the first transaction is
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen started. at that point the mailbox has been synced at least once. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen t = fbox->module_ctx.super.transaction_begin(box, flags);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET(t, fts_storage_module, ft);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenfts_storage_build_context_deinit(struct fts_storage_build_context *build_ctx)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen (void)fts_backend_build_deinit(&build_ctx->build);
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainenfts_transaction_finish(struct mailbox *box, struct fts_transaction_context *ft,
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen fts_backend_expunge_finish(fbox->backend_fast,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainenstatic void fts_transaction_rollback(struct mailbox_transaction_context *t)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(t);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen fts_storage_build_context_deinit(ft->build_ctx);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen fbox->module_ctx.super.transaction_rollback(t);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainenfts_transaction_commit(struct mailbox_transaction_context *t,
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen struct mail_transaction_commit_changes *changes_r)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen struct fts_transaction_context *ft = FTS_CONTEXT(t);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen fts_storage_build_context_deinit(ft->build_ctx);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen ret = fbox->module_ctx.super.transaction_commit(t, changes_r);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen arg = mail_search_build_add(search_args, SEARCH_BODY_FAST);
437a8b0fe254057b0c1f1723d689bafa91cae2abTimo Sirainen ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen while ((ret = fts_mailbox_search_build_more(ctx)) == 0) ;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainenstatic int fts_sync_deinit(struct mailbox_sync_context *ctx,
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen precache = (ctx->flags & MAILBOX_SYNC_FLAG_PRECACHE) != 0;
64b61cd24d630223478ccbe1934b9f60f0881f59Timo Sirainen if (fbox->module_ctx.super.sync_deinit(ctx, status_r) < 0)
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainenstatic void fts_mailbox_init(struct mailbox *box, const char *env)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen fbox->virtual = strcmp(box->storage->name, "virtual") == 0;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen v->search_next_nonblock = fts_mailbox_search_next_nonblock;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen v->transaction_rollback = fts_transaction_rollback;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen v->transaction_commit = fts_transaction_commit;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET(box, fts_storage_module, fbox);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenvoid fts_mailbox_allocated(struct mailbox *box)
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen const char *env;