1 /* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "mail-storage-private.h"
6 #include "mail-search.h"
7 #include "mailbox-search-result-private.h"
8 
9 static void
mailbox_search_result_analyze_args(struct mail_search_result * result,struct mail_search_arg * arg)10 mailbox_search_result_analyze_args(struct mail_search_result *result,
11 				   struct mail_search_arg *arg)
12 {
13 	for (; arg != NULL; arg = arg->next) {
14 		switch (arg->type) {
15 		case SEARCH_OR:
16 		case SEARCH_SUB:
17 			mailbox_search_result_analyze_args(result,
18 							   arg->value.subargs);
19 			break;
20 		case SEARCH_FLAGS:
21 			result->args_have_flags = TRUE;
22 			break;
23 		case SEARCH_KEYWORDS:
24 			result->args_have_keywords = TRUE;
25 			break;
26 		case SEARCH_MODSEQ:
27 			result->args_have_modseq = TRUE;
28 			break;
29 		default:
30 			break;
31 		}
32 	}
33 }
34 
35 struct mail_search_result *
mailbox_search_result_alloc(struct mailbox * box,struct mail_search_args * args,enum mailbox_search_result_flags flags)36 mailbox_search_result_alloc(struct mailbox *box, struct mail_search_args *args,
37 			    enum mailbox_search_result_flags flags)
38 {
39 	struct mail_search_result *result;
40 
41 	result = i_new(struct mail_search_result, 1);
42 	result->box = box;
43 	result->flags = flags;
44 	i_array_init(&result->uids, 32);
45 	i_array_init(&result->never_uids, 128);
46 
47 	if ((result->flags & MAILBOX_SEARCH_RESULT_FLAG_UPDATE) != 0) {
48 		result->search_args = args;
49 		mail_search_args_ref(result->search_args);
50 		mailbox_search_result_analyze_args(result, args->args);
51 	}
52 
53 	array_push_back(&result->box->search_results, &result);
54 	return result;
55 }
56 
mailbox_search_result_free(struct mail_search_result ** _result)57 void mailbox_search_result_free(struct mail_search_result **_result)
58 {
59 	struct mail_search_result *result = *_result;
60 	struct mail_search_result *const *results;
61 	unsigned int i, count;
62 
63 	*_result = NULL;
64 
65 	results = array_get(&result->box->search_results, &count);
66 	for (i = 0; i < count; i++) {
67 		if (results[i] == result) {
68 			array_delete(&result->box->search_results, i, 1);
69 			break;
70 		}
71 	}
72 	i_assert(i != count);
73 
74 	if (result->search_args != NULL)
75 		mail_search_args_unref(&result->search_args);
76 
77 	array_free(&result->uids);
78 	array_free(&result->never_uids);
79 	if (array_is_created(&result->removed_uids)) {
80 		array_free(&result->removed_uids);
81 		array_free(&result->added_uids);
82 	}
83 	i_free(result);
84 }
85 
86 struct mail_search_result *
mailbox_search_result_save(struct mail_search_context * ctx,enum mailbox_search_result_flags flags)87 mailbox_search_result_save(struct mail_search_context *ctx,
88 			   enum mailbox_search_result_flags flags)
89 {
90 	struct mail_search_result *result;
91 
92 	result = mailbox_search_result_alloc(ctx->transaction->box,
93 					     ctx->args, flags);
94 	array_push_back(&ctx->results, &result);
95 	return result;
96 }
97 
mailbox_search_result_initial_done(struct mail_search_result * result)98 void mailbox_search_result_initial_done(struct mail_search_result *result)
99 {
100 	if ((result->flags & MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC) != 0) {
101 		i_array_init(&result->removed_uids, 32);
102 		i_array_init(&result->added_uids, 32);
103 	}
104 	mail_search_args_seq2uid(result->search_args);
105 }
106 
mailbox_search_results_initial_done(struct mail_search_context * ctx)107 void mailbox_search_results_initial_done(struct mail_search_context *ctx)
108 {
109 	struct mail_search_result *const *results;
110 	unsigned int i, count;
111 
112 	results = array_get(&ctx->results, &count);
113 	for (i = 0; i < count; i++)
114 		mailbox_search_result_initial_done(results[i]);
115 }
116 
mailbox_search_result_add(struct mail_search_result * result,uint32_t uid)117 void mailbox_search_result_add(struct mail_search_result *result, uint32_t uid)
118 {
119 	i_assert(uid > 0);
120 
121 	if (seq_range_exists(&result->uids, uid))
122 		return;
123 
124 	seq_range_array_add(&result->uids, uid);
125 	if (array_is_created(&result->added_uids)) {
126 		seq_range_array_add(&result->added_uids, uid);
127 		seq_range_array_remove(&result->removed_uids, uid);
128 	}
129 }
130 
mailbox_search_result_remove(struct mail_search_result * result,uint32_t uid)131 void mailbox_search_result_remove(struct mail_search_result *result,
132 				  uint32_t uid)
133 {
134 	if (seq_range_array_remove(&result->uids, uid)) {
135 		if (array_is_created(&result->removed_uids)) {
136 			seq_range_array_add(&result->removed_uids, uid);
137 			seq_range_array_remove(&result->added_uids, uid);
138 		}
139 	}
140 }
141 
mailbox_search_results_add(struct mail_search_context * ctx,uint32_t uid)142 void mailbox_search_results_add(struct mail_search_context *ctx, uint32_t uid)
143 {
144 	struct mail_search_result *const *results;
145 	unsigned int i, count;
146 
147 	results = array_get(&ctx->results, &count);
148 	for (i = 0; i < count; i++)
149 		mailbox_search_result_add(results[i], uid);
150 }
151 
mailbox_search_results_remove(struct mailbox * box,uint32_t uid)152 void mailbox_search_results_remove(struct mailbox *box, uint32_t uid)
153 {
154 	struct mail_search_result *const *results;
155 	unsigned int i, count;
156 
157 	results = array_get(&box->search_results, &count);
158 	for (i = 0; i < count; i++)
159 		mailbox_search_result_remove(results[i], uid);
160 }
161 
mailbox_search_result_never(struct mail_search_result * result,uint32_t uid)162 void mailbox_search_result_never(struct mail_search_result *result,
163 				 uint32_t uid)
164 {
165 	seq_range_array_add(&result->never_uids, uid);
166 }
167 
mailbox_search_results_never(struct mail_search_context * ctx,uint32_t uid)168 void mailbox_search_results_never(struct mail_search_context *ctx,
169 				  uint32_t uid)
170 {
171 	struct mail_search_result *const *results;
172 	unsigned int i, count;
173 
174 	if (ctx->update_result != NULL)
175 		mailbox_search_result_never(ctx->update_result, uid);
176 
177 	results = array_get(&ctx->results, &count);
178 	for (i = 0; i < count; i++)
179 		mailbox_search_result_never(results[i], uid);
180 }
181 
ARRAY_TYPE(seq_range)182 const ARRAY_TYPE(seq_range) *
183 mailbox_search_result_get(struct mail_search_result *result)
184 {
185 	return &result->uids;
186 }
187 
mailbox_search_result_sync(struct mail_search_result * result,ARRAY_TYPE (seq_range)* removed_uids,ARRAY_TYPE (seq_range)* added_uids)188 void mailbox_search_result_sync(struct mail_search_result *result,
189 				ARRAY_TYPE(seq_range) *removed_uids,
190 				ARRAY_TYPE(seq_range) *added_uids)
191 {
192 	array_clear(removed_uids);
193 	array_clear(added_uids);
194 
195 	array_append_array(removed_uids, &result->removed_uids);
196 	array_append_array(added_uids, &result->added_uids);
197 
198 	array_clear(&result->removed_uids);
199 	array_clear(&result->added_uids);
200 }
201