bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen#include "lib.h"
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen#include "array.h"
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen#include "mail-search.h"
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen#include "index-search-private.h"
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen#include "virtual-storage.h"
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenenum virtual_search_state {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen VIRTUAL_SEARCH_STATE_BUILD,
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen VIRTUAL_SEARCH_STATE_RETURN,
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen VIRTUAL_SEARCH_STATE_SORT,
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen VIRTUAL_SEARCH_STATE_SORT_DONE
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen};
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenstruct virtual_search_record {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen uint32_t mailbox_id;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen uint32_t real_uid;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen uint32_t virtual_seq;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen};
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenstruct virtual_search_context {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen union mail_search_module_context module_ctx;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen ARRAY_TYPE(seq_range) result;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen struct seq_range_iter result_iter;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct virtual_search_record) records;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen enum virtual_search_state search_state;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen unsigned int next_result_n;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen unsigned int next_record_idx;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen};
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainenstatic int virtual_search_record_cmp(const struct virtual_search_record *r1,
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen const struct virtual_search_record *r2)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (r1->mailbox_id < r2->mailbox_id)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return -1;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (r1->mailbox_id > r2->mailbox_id)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return 1;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (r1->real_uid < r2->real_uid)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return -1;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (r1->real_uid > r2->real_uid)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return 1;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return 0;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenstatic int mail_search_get_result(struct mail_search_context *ctx)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen const struct mail_search_arg *arg;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen int ret = 1;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen for (arg = ctx->args->args; arg != NULL; arg = arg->next) {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (arg->result < 0)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return -1;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (arg->result == 0)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen ret = 0;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen }
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return ret;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainenstatic void virtual_search_get_records(struct mail_search_context *ctx,
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen struct virtual_search_context *vctx)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen struct virtual_mailbox *mbox =
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen (struct virtual_mailbox *)ctx->transaction->box;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen const struct virtual_mail_index_record *vrec;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen struct virtual_search_record srec;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen const void *data;
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen int result;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&srec);
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen while (index_storage_search_next_update_seq(ctx)) {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen result = mail_search_get_result(ctx);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen i_assert(result != 0);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (result > 0) {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen /* full match, no need to check this any further */
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&vctx->result, ctx->seq);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen } else {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen /* possible match, save and check later */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen mail_index_lookup_ext(mbox->box.view, ctx->seq,
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen mbox->virtual_ext_id,
03010dbaa74ec70f062994dfe3cd39bedc99a28bTimo Sirainen &data, NULL);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vrec = data;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen srec.mailbox_id = vrec->mailbox_id;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen srec.real_uid = vrec->real_uid;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen srec.virtual_seq = ctx->seq;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen array_append(&vctx->records, &srec, 1);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen }
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen mail_search_args_reset(ctx->args->args, FALSE);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen }
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&vctx->records, virtual_search_record_cmp);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen ctx->progress_max = array_count(&vctx->records);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenstruct mail_search_context *
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenvirtual_search_init(struct mailbox_transaction_context *t,
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen struct mail_search_args *args,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen const enum mail_sort_type *sort_program,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen enum mail_fetch_field wanted_fields,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen struct mail_search_context *ctx;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen struct virtual_search_context *vctx;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen ctx = index_storage_search_init(t, args, sort_program,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen wanted_fields, wanted_headers);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx = i_new(struct virtual_search_context, 1);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->search_state = VIRTUAL_SEARCH_STATE_BUILD;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen i_array_init(&vctx->result, 64);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen i_array_init(&vctx->records, 64);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen MODULE_CONTEXT_SET(ctx, virtual_storage_module, vctx);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen virtual_search_get_records(ctx, vctx);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen seq_range_array_iter_init(&vctx->result_iter, &vctx->result);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return ctx;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenint virtual_search_deinit(struct mail_search_context *ctx)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
109c39ab66c5aa85bf37d5bbf4ce91c6f966268bAki Tuomi struct virtual_search_context *vctx = VIRTUAL_CONTEXT_REQUIRE(ctx);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen array_free(&vctx->result);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen array_free(&vctx->records);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen i_free(vctx);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return index_storage_search_deinit(ctx);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainenbool virtual_search_next_nonblock(struct mail_search_context *ctx,
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct mail **mail_r, bool *tryagain_r)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
109c39ab66c5aa85bf37d5bbf4ce91c6f966268bAki Tuomi struct virtual_search_context *vctx = VIRTUAL_CONTEXT_REQUIRE(ctx);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen struct index_search_context *ictx = (struct index_search_context *)ctx;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen uint32_t seq;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen switch (vctx->search_state) {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen case VIRTUAL_SEARCH_STATE_BUILD:
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (ctx->sort_program == NULL)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->search_state = VIRTUAL_SEARCH_STATE_SORT;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen else
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->search_state = VIRTUAL_SEARCH_STATE_RETURN;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen return virtual_search_next_nonblock(ctx, mail_r, tryagain_r);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen case VIRTUAL_SEARCH_STATE_RETURN:
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen return index_storage_search_next_nonblock(ctx, mail_r, tryagain_r);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen case VIRTUAL_SEARCH_STATE_SORT:
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen /* the messages won't be returned sorted, so we'll have to
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen do it ourself */
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen while (index_storage_search_next_nonblock(ctx, mail_r, tryagain_r))
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&vctx->result, (*mail_r)->seq);
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen if (*tryagain_r)
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen return FALSE;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->next_result_n = 0;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->search_state = VIRTUAL_SEARCH_STATE_SORT_DONE;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen /* fall through */
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen case VIRTUAL_SEARCH_STATE_SORT_DONE:
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen *tryagain_r = FALSE;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (!seq_range_array_iter_nth(&vctx->result_iter,
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->next_result_n, &seq))
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen return FALSE;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->next_result_n++;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen *mail_r = index_search_get_mail(ictx);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_assert(*mail_r != NULL);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_set_seq(*mail_r, seq);
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen return TRUE;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen }
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen i_unreached();
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenstatic void search_args_set_full_match(struct mail_search_arg *args)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen for (; args != NULL; args = args->next)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen args->result = 1;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenbool virtual_search_next_update_seq(struct mail_search_context *ctx)
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen{
109c39ab66c5aa85bf37d5bbf4ce91c6f966268bAki Tuomi struct virtual_search_context *vctx = VIRTUAL_CONTEXT_REQUIRE(ctx);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen const struct virtual_search_record *recs;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen unsigned int count;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen recs = array_get(&vctx->records, &count);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (vctx->next_record_idx < count) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen /* go through potential results first */
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen ctx->seq = recs[vctx->next_record_idx++].virtual_seq - 1;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (!index_storage_search_next_update_seq(ctx))
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen i_unreached();
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen ctx->progress_cur = vctx->next_record_idx;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return TRUE;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen }
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen if (ctx->sort_program != NULL &&
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen seq_range_array_iter_nth(&vctx->result_iter,
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->next_result_n, &ctx->seq)) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen /* this is known to match fully */
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen search_args_set_full_match(ctx->args->args);
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen vctx->next_result_n++;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return TRUE;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen }
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen return FALSE;
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen}