1
/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */
5
#include "mail-search.h"
6
#include "index-storage.h"
7
#include "virtual-storage.h"
11
enum virtual_search_state {
12
VIRTUAL_SEARCH_STATE_FAILED = -1,
13
VIRTUAL_SEARCH_STATE_BUILD,
14
VIRTUAL_SEARCH_STATE_RETURN,
15
VIRTUAL_SEARCH_STATE_SORT,
16
VIRTUAL_SEARCH_STATE_SORT_DONE
19
struct virtual_search_record {
25
struct virtual_search_context {
26
union mail_search_module_context module_ctx;
28
ARRAY_TYPE(seq_range) result;
29
struct seq_range_iter result_iter;
30
ARRAY_DEFINE(records, struct virtual_search_record);
32
enum virtual_search_state search_state;
33
unsigned int next_result_n;
34
unsigned int next_record_idx;
37
static int virtual_search_record_cmp(const void *p1, const void *p2)
39
const struct virtual_search_record *r1 = p1, *r2 = p2;
41
if (r1->mailbox_id < r2->mailbox_id)
43
if (r1->mailbox_id > r2->mailbox_id)
46
if (r1->real_uid < r2->real_uid)
48
if (r1->real_uid > r2->real_uid)
53
static int mail_search_get_result(struct mail_search_context *ctx)
55
const struct mail_search_arg *arg;
58
for (arg = ctx->args->args; arg != NULL; arg = arg->next) {
67
static int virtual_search_get_records(struct mail_search_context *ctx,
68
struct virtual_search_context *vctx)
70
struct virtual_mailbox *mbox =
71
(struct virtual_mailbox *)ctx->transaction->box;
72
const struct virtual_mail_index_record *vrec;
73
struct virtual_search_record srec, *srecs;
79
memset(&srec, 0, sizeof(srec));
80
while ((ret = index_storage_search_next_update_seq(ctx)) > 0) {
81
result = mail_search_get_result(ctx);
82
i_assert(result != 0);
84
/* full match, no need to check this any further */
85
seq_range_array_add(&vctx->result, 0, ctx->seq);
87
/* possible match, save and check later */
88
mail_index_lookup_ext(mbox->ibox.view, ctx->seq,
93
srec.mailbox_id = vrec->mailbox_id;
94
srec.real_uid = vrec->real_uid;
95
srec.virtual_seq = ctx->seq;
96
array_append(&vctx->records, &srec, 1);
98
mail_search_args_reset(ctx->args->args, FALSE);
100
srecs = array_get_modifiable(&vctx->records, &count);
101
qsort(srecs, count, sizeof(*srecs), virtual_search_record_cmp);
103
ctx->progress_max = count;
107
struct mail_search_context *
108
virtual_search_init(struct mailbox_transaction_context *t,
109
struct mail_search_args *args,
110
const enum mail_sort_type *sort_program)
112
struct mail_search_context *ctx;
113
struct virtual_search_context *vctx;
115
ctx = index_storage_search_init(t, args, sort_program);
117
vctx = i_new(struct virtual_search_context, 1);
118
vctx->search_state = VIRTUAL_SEARCH_STATE_BUILD;
119
i_array_init(&vctx->result, 64);
120
i_array_init(&vctx->records, 64);
121
MODULE_CONTEXT_SET(ctx, virtual_storage_module, vctx);
123
if (virtual_search_get_records(ctx, vctx) < 0)
124
vctx->search_state = VIRTUAL_SEARCH_STATE_FAILED;
126
seq_range_array_iter_init(&vctx->result_iter, &vctx->result);
130
int virtual_search_deinit(struct mail_search_context *ctx)
132
struct virtual_search_context *vctx = VIRTUAL_CONTEXT(ctx);
134
array_free(&vctx->result);
135
array_free(&vctx->records);
137
return index_storage_search_deinit(ctx);
140
int virtual_search_next_nonblock(struct mail_search_context *ctx,
141
struct mail *mail, bool *tryagain_r)
143
struct virtual_search_context *vctx = VIRTUAL_CONTEXT(ctx);
147
switch (vctx->search_state) {
148
case VIRTUAL_SEARCH_STATE_FAILED:
150
case VIRTUAL_SEARCH_STATE_BUILD:
151
if (ctx->sort_program == NULL)
152
vctx->search_state = VIRTUAL_SEARCH_STATE_SORT;
154
vctx->search_state = VIRTUAL_SEARCH_STATE_RETURN;
155
return virtual_search_next_nonblock(ctx, mail, tryagain_r);
156
case VIRTUAL_SEARCH_STATE_RETURN:
157
return index_storage_search_next_nonblock(ctx, mail, tryagain_r);
158
case VIRTUAL_SEARCH_STATE_SORT:
159
/* the messages won't be returned sorted, so we'll have to
161
while ((ret = index_storage_search_next_nonblock(ctx, mail,
163
seq_range_array_add(&vctx->result, 0, mail->seq);
164
if (ret < 0 || *tryagain_r)
167
vctx->next_result_n = 0;
168
vctx->search_state = VIRTUAL_SEARCH_STATE_SORT_DONE;
170
case VIRTUAL_SEARCH_STATE_SORT_DONE:
172
if (!seq_range_array_iter_nth(&vctx->result_iter,
173
vctx->next_result_n, &seq))
175
vctx->next_result_n++;
176
mail_set_seq(mail, seq);
182
static void search_args_set_full_match(struct mail_search_arg *args)
184
for (; args != NULL; args = args->next)
188
bool virtual_search_next_update_seq(struct mail_search_context *ctx)
190
struct virtual_search_context *vctx = VIRTUAL_CONTEXT(ctx);
191
const struct virtual_search_record *recs;
194
recs = array_get(&vctx->records, &count);
195
if (vctx->next_record_idx < count) {
196
/* go through potential results first */
197
ctx->seq = recs[vctx->next_record_idx++].virtual_seq - 1;
198
if (!index_storage_search_next_update_seq(ctx))
200
ctx->progress_cur = vctx->next_record_idx;
204
if (ctx->sort_program != NULL &&
205
seq_range_array_iter_nth(&vctx->result_iter,
206
vctx->next_result_n, &ctx->seq)) {
207
/* this is known to match fully */
208
search_args_set_full_match(ctx->args->args);
209
vctx->next_result_n++;