diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/plugins/virtual/virtual-search.c | |
parent | Initial commit. (diff) | |
download | dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.tar.xz dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/plugins/virtual/virtual-search.c')
-rw-r--r-- | src/plugins/virtual/virtual-search.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/plugins/virtual/virtual-search.c b/src/plugins/virtual/virtual-search.c new file mode 100644 index 0000000..ee04a74 --- /dev/null +++ b/src/plugins/virtual/virtual-search.c @@ -0,0 +1,206 @@ +/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "mail-search.h" +#include "index-search-private.h" +#include "virtual-storage.h" + + +enum virtual_search_state { + VIRTUAL_SEARCH_STATE_BUILD, + VIRTUAL_SEARCH_STATE_RETURN, + VIRTUAL_SEARCH_STATE_SORT, + VIRTUAL_SEARCH_STATE_SORT_DONE +}; + +struct virtual_search_record { + uint32_t mailbox_id; + uint32_t real_uid; + uint32_t virtual_seq; +}; + +struct virtual_search_context { + union mail_search_module_context module_ctx; + + ARRAY_TYPE(seq_range) result; + struct seq_range_iter result_iter; + ARRAY(struct virtual_search_record) records; + + enum virtual_search_state search_state; + unsigned int next_result_n; + unsigned int next_record_idx; +}; + +static int virtual_search_record_cmp(const struct virtual_search_record *r1, + const struct virtual_search_record *r2) +{ + if (r1->mailbox_id < r2->mailbox_id) + return -1; + if (r1->mailbox_id > r2->mailbox_id) + return 1; + + if (r1->real_uid < r2->real_uid) + return -1; + if (r1->real_uid > r2->real_uid) + return 1; + return 0; +} + +static int mail_search_get_result(struct mail_search_context *ctx) +{ + const struct mail_search_arg *arg; + int ret = 1; + + for (arg = ctx->args->args; arg != NULL; arg = arg->next) { + if (arg->result < 0) + return -1; + if (arg->result == 0) + ret = 0; + } + return ret; +} + +static void virtual_search_get_records(struct mail_search_context *ctx, + struct virtual_search_context *vctx) +{ + struct virtual_mailbox *mbox = + (struct virtual_mailbox *)ctx->transaction->box; + const struct virtual_mail_index_record *vrec; + struct virtual_search_record srec; + const void *data; + int result; + + i_zero(&srec); + while (index_storage_search_next_update_seq(ctx)) { + result = mail_search_get_result(ctx); + i_assert(result != 0); + if (result > 0) { + /* full match, no need to check this any further */ + seq_range_array_add(&vctx->result, ctx->seq); + } else { + /* possible match, save and check later */ + mail_index_lookup_ext(mbox->box.view, ctx->seq, + mbox->virtual_ext_id, + &data, NULL); + vrec = data; + + srec.mailbox_id = vrec->mailbox_id; + srec.real_uid = vrec->real_uid; + srec.virtual_seq = ctx->seq; + array_push_back(&vctx->records, &srec); + } + mail_search_args_reset(ctx->args->args, FALSE); + } + array_sort(&vctx->records, virtual_search_record_cmp); + + ctx->progress_max = array_count(&vctx->records); +} + +struct mail_search_context * +virtual_search_init(struct mailbox_transaction_context *t, + struct mail_search_args *args, + const enum mail_sort_type *sort_program, + enum mail_fetch_field wanted_fields, + struct mailbox_header_lookup_ctx *wanted_headers) +{ + struct mail_search_context *ctx; + struct virtual_search_context *vctx; + + ctx = index_storage_search_init(t, args, sort_program, + wanted_fields, wanted_headers); + + vctx = i_new(struct virtual_search_context, 1); + vctx->search_state = VIRTUAL_SEARCH_STATE_BUILD; + i_array_init(&vctx->result, 64); + i_array_init(&vctx->records, 64); + MODULE_CONTEXT_SET(ctx, virtual_storage_module, vctx); + + virtual_search_get_records(ctx, vctx); + seq_range_array_iter_init(&vctx->result_iter, &vctx->result); + return ctx; +} + +int virtual_search_deinit(struct mail_search_context *ctx) +{ + struct virtual_search_context *vctx = VIRTUAL_CONTEXT_REQUIRE(ctx); + + array_free(&vctx->result); + array_free(&vctx->records); + i_free(vctx); + return index_storage_search_deinit(ctx); +} + +bool virtual_search_next_nonblock(struct mail_search_context *ctx, + struct mail **mail_r, bool *tryagain_r) +{ + struct virtual_search_context *vctx = VIRTUAL_CONTEXT_REQUIRE(ctx); + struct index_search_context *ictx = (struct index_search_context *)ctx; + uint32_t seq; + + switch (vctx->search_state) { + case VIRTUAL_SEARCH_STATE_BUILD: + if (ctx->sort_program == NULL) + vctx->search_state = VIRTUAL_SEARCH_STATE_SORT; + else + vctx->search_state = VIRTUAL_SEARCH_STATE_RETURN; + return virtual_search_next_nonblock(ctx, mail_r, tryagain_r); + case VIRTUAL_SEARCH_STATE_RETURN: + return index_storage_search_next_nonblock(ctx, mail_r, tryagain_r); + case VIRTUAL_SEARCH_STATE_SORT: + /* the messages won't be returned sorted, so we'll have to + do it ourself */ + while (index_storage_search_next_nonblock(ctx, mail_r, tryagain_r)) + seq_range_array_add(&vctx->result, (*mail_r)->seq); + if (*tryagain_r) + return FALSE; + + vctx->next_result_n = 0; + vctx->search_state = VIRTUAL_SEARCH_STATE_SORT_DONE; + /* fall through */ + case VIRTUAL_SEARCH_STATE_SORT_DONE: + *tryagain_r = FALSE; + if (!seq_range_array_iter_nth(&vctx->result_iter, + vctx->next_result_n, &seq)) + return FALSE; + vctx->next_result_n++; + *mail_r = index_search_get_mail(ictx); + i_assert(*mail_r != NULL); + mail_set_seq(*mail_r, seq); + return TRUE; + } + i_unreached(); +} + +static void search_args_set_full_match(struct mail_search_arg *args) +{ + for (; args != NULL; args = args->next) + args->result = 1; +} + +bool virtual_search_next_update_seq(struct mail_search_context *ctx) +{ + struct virtual_search_context *vctx = VIRTUAL_CONTEXT_REQUIRE(ctx); + const struct virtual_search_record *recs; + unsigned int count; + + recs = array_get(&vctx->records, &count); + if (vctx->next_record_idx < count) { + /* go through potential results first */ + ctx->seq = recs[vctx->next_record_idx++].virtual_seq - 1; + if (!index_storage_search_next_update_seq(ctx)) + i_unreached(); + ctx->progress_cur = vctx->next_record_idx; + return TRUE; + } + + if (ctx->sort_program != NULL && + seq_range_array_iter_nth(&vctx->result_iter, + vctx->next_result_n, &ctx->seq)) { + /* this is known to match fully */ + search_args_set_full_match(ctx->args->args); + vctx->next_result_n++; + return TRUE; + } + return FALSE; +} |