/src/dovecot/src/lib-index/mail-index-view.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "array.h" |
5 | | #include "buffer.h" |
6 | | #include "llist.h" |
7 | | #include "mail-index-view-private.h" |
8 | | #include "mail-transaction-log.h" |
9 | | |
10 | | #undef mail_index_view_clone |
11 | | #undef mail_index_view_dup_private |
12 | | |
13 | | struct mail_index_view * |
14 | | mail_index_view_dup_private(const struct mail_index_view *src, |
15 | | const char *source_filename, |
16 | | unsigned int source_linenum) |
17 | 0 | { |
18 | 0 | struct mail_index_view *view; |
19 | 0 | struct mail_index_map *map; |
20 | |
|
21 | 0 | view = i_new(struct mail_index_view, 1); |
22 | 0 | mail_index_view_clone(view, src, source_filename, source_linenum); |
23 | |
|
24 | 0 | map = mail_index_map_clone(view->map); |
25 | 0 | mail_index_unmap(&view->map); |
26 | 0 | view->map = map; |
27 | 0 | return view; |
28 | 0 | } |
29 | | |
30 | | void mail_index_view_clone(struct mail_index_view *dest, |
31 | | const struct mail_index_view *src, |
32 | | const char *source_filename, |
33 | | unsigned int source_linenum) |
34 | 0 | { |
35 | 0 | i_zero(dest); |
36 | 0 | dest->refcount = 1; |
37 | 0 | dest->v = src->v; |
38 | 0 | dest->index = src->index; |
39 | 0 | if (src->log_view != NULL) { |
40 | 0 | dest->log_view = |
41 | 0 | mail_transaction_log_view_open(src->index->log); |
42 | 0 | } |
43 | |
|
44 | 0 | dest->indexid = src->indexid; |
45 | 0 | dest->inconsistency_id = src->inconsistency_id; |
46 | 0 | dest->map = src->map; |
47 | 0 | if (dest->map != NULL) |
48 | 0 | dest->map->refcount++; |
49 | |
|
50 | 0 | dest->log_file_expunge_seq = src->log_file_expunge_seq; |
51 | 0 | dest->log_file_expunge_offset = src->log_file_expunge_offset; |
52 | 0 | dest->log_file_head_seq = src->log_file_head_seq; |
53 | 0 | dest->log_file_head_offset = src->log_file_head_offset; |
54 | |
|
55 | 0 | i_array_init(&dest->module_contexts, |
56 | 0 | I_MIN(5, mail_index_module_register.id)); |
57 | |
|
58 | 0 | dest->source_filename = source_filename; |
59 | 0 | dest->source_linenum = source_linenum; |
60 | |
|
61 | 0 | DLLIST_PREPEND(&dest->index->views, dest); |
62 | 0 | } |
63 | | |
64 | | void mail_index_view_ref(struct mail_index_view *view) |
65 | 0 | { |
66 | 0 | view->refcount++; |
67 | 0 | } |
68 | | |
69 | | static void view_close(struct mail_index_view *view) |
70 | 0 | { |
71 | 0 | i_assert(view->refcount == 0); |
72 | 0 | i_assert(view->index->views != NULL); |
73 | | |
74 | 0 | DLLIST_REMOVE(&view->index->views, view); |
75 | |
|
76 | 0 | mail_transaction_log_view_close(&view->log_view); |
77 | |
|
78 | 0 | if (array_is_created(&view->syncs_hidden)) |
79 | 0 | array_free(&view->syncs_hidden); |
80 | 0 | mail_index_unmap(&view->map); |
81 | 0 | if (array_is_created(&view->map_refs)) { |
82 | 0 | mail_index_view_unref_maps(view); |
83 | 0 | array_free(&view->map_refs); |
84 | 0 | } |
85 | 0 | array_free(&view->module_contexts); |
86 | 0 | i_free(view); |
87 | 0 | } |
88 | | |
89 | | bool mail_index_view_is_inconsistent(struct mail_index_view *view) |
90 | 0 | { |
91 | 0 | if (view->index->indexid != view->indexid || |
92 | 0 | view->index->inconsistency_id != view->inconsistency_id) |
93 | 0 | view->inconsistent = TRUE; |
94 | 0 | return view->inconsistent; |
95 | 0 | } |
96 | | |
97 | | struct mail_index *mail_index_view_get_index(struct mail_index_view *view) |
98 | 0 | { |
99 | 0 | return view->index; |
100 | 0 | } |
101 | | |
102 | | bool mail_index_view_have_transactions(struct mail_index_view *view) |
103 | 0 | { |
104 | 0 | return view->transactions_list != NULL; |
105 | 0 | } |
106 | | |
107 | | static void mail_index_view_ref_map(struct mail_index_view *view, |
108 | | struct mail_index_map *map) |
109 | 0 | { |
110 | 0 | struct mail_index_map *const *maps; |
111 | 0 | unsigned int i, count; |
112 | |
|
113 | 0 | if (array_is_created(&view->map_refs)) { |
114 | 0 | maps = array_get(&view->map_refs, &count); |
115 | | |
116 | | /* if map is already referenced, do nothing */ |
117 | 0 | for (i = 0; i < count; i++) { |
118 | 0 | if (maps[i] == map) |
119 | 0 | return; |
120 | 0 | } |
121 | 0 | } else { |
122 | 0 | i_array_init(&view->map_refs, 4); |
123 | 0 | } |
124 | | |
125 | | /* reference the given mapping. the reference is dropped when the view |
126 | | is synchronized or closed. */ |
127 | 0 | map->refcount++; |
128 | 0 | array_push_back(&view->map_refs, &map); |
129 | 0 | } |
130 | | |
131 | | void mail_index_view_unref_maps(struct mail_index_view *view) |
132 | 0 | { |
133 | 0 | struct mail_index_map **maps; |
134 | 0 | unsigned int i, count; |
135 | |
|
136 | 0 | if (!array_is_created(&view->map_refs)) |
137 | 0 | return; |
138 | | |
139 | 0 | maps = array_get_modifiable(&view->map_refs, &count); |
140 | 0 | for (i = 0; i < count; i++) |
141 | 0 | mail_index_unmap(&maps[i]); |
142 | |
|
143 | 0 | array_clear(&view->map_refs); |
144 | 0 | } |
145 | | |
146 | | static uint32_t view_get_messages_count(struct mail_index_view *view) |
147 | 0 | { |
148 | 0 | return view->map->hdr.messages_count; |
149 | 0 | } |
150 | | |
151 | | static const struct mail_index_header * |
152 | | view_get_header(struct mail_index_view *view) |
153 | 0 | { |
154 | 0 | return &view->map->hdr; |
155 | 0 | } |
156 | | |
157 | | static const struct mail_index_record * |
158 | | view_lookup_full(struct mail_index_view *view, uint32_t seq, |
159 | | struct mail_index_map **map_r, bool *expunged_r) |
160 | 0 | { |
161 | 0 | static struct mail_index_record broken_rec; |
162 | 0 | struct mail_index_map *map; |
163 | 0 | const struct mail_index_record *rec, *head_rec; |
164 | |
|
165 | 0 | i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view)); |
166 | | |
167 | | /* look up the record */ |
168 | 0 | rec = MAIL_INDEX_REC_AT_SEQ(view->map, seq); |
169 | 0 | if (unlikely(rec->uid == 0)) { |
170 | 0 | if (!view->inconsistent) { |
171 | 0 | mail_index_set_error(view->index, |
172 | 0 | "Corrupted Index file %s: Record [%u].uid=0", |
173 | 0 | view->index->filepath, seq); |
174 | 0 | (void)mail_index_fsck(view->index); |
175 | 0 | view->inconsistent = TRUE; |
176 | 0 | } |
177 | | |
178 | | /* we'll need to return something so the caller doesn't crash */ |
179 | 0 | *map_r = view->map; |
180 | 0 | if (expunged_r != NULL) |
181 | 0 | *expunged_r = TRUE; |
182 | 0 | return &broken_rec; |
183 | 0 | } |
184 | 0 | if (view->map == view->index->map) { |
185 | | /* view's mapping is latest. we can use it directly. */ |
186 | 0 | *map_r = view->map; |
187 | 0 | if (expunged_r != NULL) |
188 | 0 | *expunged_r = FALSE; |
189 | 0 | return rec; |
190 | 0 | } |
191 | | |
192 | | /* look up the record from head mapping. it may contain some changes. |
193 | | |
194 | | start looking up from the same sequence as in the old view. |
195 | | if there are no expunges, it's there. otherwise it's somewhere |
196 | | before (since records can't be inserted). |
197 | | |
198 | | usually there are only a few expunges, so just going downwards from |
199 | | our initial sequence position is probably faster than binary |
200 | | search. */ |
201 | 0 | if (seq > view->index->map->hdr.messages_count) |
202 | 0 | seq = view->index->map->hdr.messages_count; |
203 | 0 | if (seq == 0) { |
204 | | /* everything is expunged from head. use the old record. */ |
205 | 0 | *map_r = view->map; |
206 | 0 | if (expunged_r != NULL) |
207 | 0 | *expunged_r = TRUE; |
208 | 0 | return rec; |
209 | 0 | } |
210 | | |
211 | 0 | map = view->index->map; |
212 | 0 | do { |
213 | 0 | head_rec = MAIL_INDEX_REC_AT_SEQ(map, seq); |
214 | 0 | if (head_rec->uid <= rec->uid) |
215 | 0 | break; |
216 | 0 | } while (--seq > 0); |
217 | |
|
218 | 0 | if (head_rec->uid == rec->uid) { |
219 | | /* found it. use it. reference the index mapping so that the |
220 | | returned record doesn't get invalidated after next sync. */ |
221 | 0 | mail_index_view_ref_map(view, view->index->map); |
222 | 0 | *map_r = view->index->map; |
223 | 0 | if (expunged_r != NULL) |
224 | 0 | *expunged_r = FALSE; |
225 | 0 | return head_rec; |
226 | 0 | } else { |
227 | | /* expunged from head. use the old record. */ |
228 | 0 | *map_r = view->map; |
229 | 0 | if (expunged_r != NULL) |
230 | 0 | *expunged_r = TRUE; |
231 | 0 | return rec; |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | static void view_lookup_uid(struct mail_index_view *view, uint32_t seq, |
236 | | uint32_t *uid_r) |
237 | 0 | { |
238 | 0 | i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view)); |
239 | | |
240 | 0 | *uid_r = MAIL_INDEX_REC_AT_SEQ(view->map, seq)->uid; |
241 | 0 | } |
242 | | |
243 | | static void view_lookup_seq_range(struct mail_index_view *view, |
244 | | uint32_t first_uid, uint32_t last_uid, |
245 | | uint32_t *first_seq_r, uint32_t *last_seq_r) |
246 | 0 | { |
247 | 0 | mail_index_map_lookup_seq_range(view->map, first_uid, last_uid, |
248 | 0 | first_seq_r, last_seq_r); |
249 | 0 | } |
250 | | |
251 | | static void view_lookup_first(struct mail_index_view *view, |
252 | | enum mail_flags flags, uint8_t flags_mask, |
253 | | uint32_t *seq_r) |
254 | 0 | { |
255 | 0 | #define LOW_UPDATE(x) \ |
256 | 0 | STMT_START { if ((x) > low_uid) low_uid = x; } STMT_END |
257 | 0 | const struct mail_index_header *hdr = &view->map->hdr; |
258 | 0 | const struct mail_index_record *rec; |
259 | 0 | uint32_t seq, seq2, low_uid = 1; |
260 | |
|
261 | 0 | *seq_r = 0; |
262 | |
|
263 | 0 | if ((flags_mask & MAIL_SEEN) != 0 && (flags & MAIL_SEEN) == 0) |
264 | 0 | LOW_UPDATE(hdr->first_unseen_uid_lowwater); |
265 | 0 | if ((flags_mask & MAIL_DELETED) != 0 && (flags & MAIL_DELETED) != 0) |
266 | 0 | LOW_UPDATE(hdr->first_deleted_uid_lowwater); |
267 | |
|
268 | 0 | if (low_uid == 1) |
269 | 0 | seq = 1; |
270 | 0 | else { |
271 | 0 | if (!mail_index_lookup_seq_range(view, low_uid, hdr->next_uid, |
272 | 0 | &seq, &seq2)) |
273 | 0 | return; |
274 | 0 | } |
275 | | |
276 | 0 | i_assert(hdr->messages_count <= view->map->rec_map->records_count); |
277 | 0 | for (; seq <= hdr->messages_count; seq++) { |
278 | 0 | rec = MAIL_INDEX_REC_AT_SEQ(view->map, seq); |
279 | 0 | if ((rec->flags & flags_mask) == (uint8_t)flags) { |
280 | 0 | *seq_r = seq; |
281 | 0 | break; |
282 | 0 | } |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | static void |
287 | | mail_index_data_lookup_keywords(struct mail_index_map *map, |
288 | | const unsigned char *data, |
289 | | ARRAY_TYPE(keyword_indexes) *keyword_idx) |
290 | 0 | { |
291 | 0 | const unsigned int *keyword_idx_map; |
292 | 0 | unsigned int i, j, keyword_count, index_idx; |
293 | 0 | uint32_t idx, hdr_size; |
294 | 0 | uint16_t record_size, record_align; |
295 | |
|
296 | 0 | array_clear(keyword_idx); |
297 | 0 | if (data == NULL) { |
298 | | /* no keywords at all in index */ |
299 | 0 | return; |
300 | 0 | } |
301 | 0 | (void)mail_index_ext_get_size(map, map->index->keywords_ext_id, |
302 | 0 | &hdr_size, &record_size, |
303 | 0 | &record_align); |
304 | | |
305 | | /* keyword_idx_map[] contains file => index keyword mapping */ |
306 | 0 | if (!array_is_created(&map->keyword_idx_map)) |
307 | 0 | return; |
308 | | |
309 | 0 | keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count); |
310 | 0 | for (i = 0; i < record_size; i++) { |
311 | | /* first do the quick check to see if there's keywords at all */ |
312 | 0 | if (data[i] == 0) |
313 | 0 | continue; |
314 | | |
315 | 0 | idx = i * CHAR_BIT; |
316 | 0 | for (j = 0; j < CHAR_BIT; j++, idx++) { |
317 | 0 | if ((data[i] & (1 << j)) == 0) |
318 | 0 | continue; |
319 | | |
320 | 0 | if (idx >= keyword_count) { |
321 | | /* extra bits set in keyword bytes. |
322 | | shouldn't happen, but just ignore. */ |
323 | 0 | break; |
324 | 0 | } |
325 | | |
326 | 0 | index_idx = keyword_idx_map[idx]; |
327 | 0 | array_push_back(keyword_idx, &index_idx); |
328 | 0 | } |
329 | 0 | } |
330 | 0 | } |
331 | | |
332 | | static void view_lookup_keywords(struct mail_index_view *view, uint32_t seq, |
333 | | ARRAY_TYPE(keyword_indexes) *keyword_idx) |
334 | 0 | { |
335 | 0 | struct mail_index_map *map; |
336 | 0 | const void *data; |
337 | |
|
338 | 0 | mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id, |
339 | 0 | &map, &data, NULL); |
340 | 0 | mail_index_data_lookup_keywords(map, data, keyword_idx); |
341 | 0 | } |
342 | | |
343 | | static const void * |
344 | | view_map_lookup_ext_full(struct mail_index_map *map, |
345 | | const struct mail_index_record *rec, uint32_t ext_id) |
346 | 0 | { |
347 | 0 | const struct mail_index_ext *ext; |
348 | 0 | uint32_t idx; |
349 | |
|
350 | 0 | if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) |
351 | 0 | return NULL; |
352 | | |
353 | 0 | ext = array_idx(&map->extensions, idx); |
354 | 0 | return ext->record_offset == 0 ? NULL : |
355 | 0 | CONST_PTR_OFFSET(rec, ext->record_offset); |
356 | 0 | } |
357 | | |
358 | | static void |
359 | | view_lookup_ext_full(struct mail_index_view *view, uint32_t seq, |
360 | | uint32_t ext_id, struct mail_index_map **map_r, |
361 | | const void **data_r, bool *expunged_r) |
362 | 0 | { |
363 | 0 | const struct mail_index_record *rec; |
364 | |
|
365 | 0 | rec = view->v.lookup_full(view, seq, map_r, expunged_r); |
366 | 0 | *data_r = view_map_lookup_ext_full(*map_r, rec, ext_id); |
367 | 0 | } |
368 | | |
369 | | static void view_get_header_ext(struct mail_index_view *view, |
370 | | struct mail_index_map *map, uint32_t ext_id, |
371 | | const void **data_r, size_t *data_size_r) |
372 | 0 | { |
373 | 0 | const struct mail_index_ext *ext; |
374 | 0 | uint32_t idx; |
375 | |
|
376 | 0 | if (map == NULL) { |
377 | | /* no mapping given, use head mapping */ |
378 | 0 | map = view->index->map; |
379 | 0 | } |
380 | |
|
381 | 0 | if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) { |
382 | | /* extension doesn't exist in this index file */ |
383 | 0 | *data_r = NULL; |
384 | 0 | *data_size_r = 0; |
385 | 0 | return; |
386 | 0 | } |
387 | | |
388 | 0 | ext = array_idx(&map->extensions, idx); |
389 | 0 | *data_r = MAIL_INDEX_MAP_HDR_OFFSET(map, ext->hdr_offset); |
390 | 0 | *data_size_r = ext->hdr_size; |
391 | 0 | } |
392 | | |
393 | | static bool view_ext_get_reset_id(struct mail_index_view *view ATTR_UNUSED, |
394 | | struct mail_index_map *map, |
395 | | uint32_t ext_id, uint32_t *reset_id_r) |
396 | 0 | { |
397 | 0 | const struct mail_index_ext *ext; |
398 | 0 | uint32_t idx; |
399 | |
|
400 | 0 | if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) |
401 | 0 | return FALSE; |
402 | | |
403 | 0 | ext = array_idx(&map->extensions, idx); |
404 | 0 | *reset_id_r = ext->reset_id; |
405 | 0 | return TRUE; |
406 | 0 | } |
407 | | |
408 | | void mail_index_view_close(struct mail_index_view **_view) |
409 | 0 | { |
410 | 0 | struct mail_index_view *view = *_view; |
411 | |
|
412 | 0 | if (view == NULL) |
413 | 0 | return; |
414 | | |
415 | 0 | *_view = NULL; |
416 | 0 | if (--view->refcount > 0) |
417 | 0 | return; |
418 | | |
419 | 0 | i_assert(view->transactions_list == NULL); |
420 | | |
421 | 0 | view->v.close(view); |
422 | 0 | } |
423 | | |
424 | | uint32_t mail_index_view_get_messages_count(struct mail_index_view *view) |
425 | 0 | { |
426 | 0 | return view->v.get_messages_count(view); |
427 | 0 | } |
428 | | |
429 | | const struct mail_index_header * |
430 | | mail_index_get_header(struct mail_index_view *view) |
431 | 0 | { |
432 | 0 | return view->v.get_header(view); |
433 | 0 | } |
434 | | |
435 | | const struct mail_index_record * |
436 | | mail_index_lookup(struct mail_index_view *view, uint32_t seq) |
437 | 0 | { |
438 | 0 | struct mail_index_map *map; |
439 | |
|
440 | 0 | return mail_index_lookup_full(view, seq, &map, NULL); |
441 | 0 | } |
442 | | |
443 | | const struct mail_index_record * |
444 | | mail_index_lookup_full(struct mail_index_view *view, uint32_t seq, |
445 | | struct mail_index_map **map_r, bool *expunged_r) |
446 | 0 | { |
447 | 0 | return view->v.lookup_full(view, seq, map_r, expunged_r); |
448 | 0 | } |
449 | | |
450 | | bool mail_index_is_expunged(struct mail_index_view *view, uint32_t seq) |
451 | 0 | { |
452 | 0 | struct mail_index_map *map; |
453 | 0 | bool expunged; |
454 | |
|
455 | 0 | (void)view->v.lookup_full(view, seq, &map, &expunged); |
456 | 0 | return expunged; |
457 | 0 | } |
458 | | |
459 | | void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq, |
460 | | ARRAY_TYPE(keyword_indexes) *keyword_idx) |
461 | 0 | { |
462 | 0 | const struct mail_index_ext *ext; |
463 | 0 | const struct mail_index_record *rec; |
464 | 0 | const void *data; |
465 | 0 | uint32_t idx; |
466 | |
|
467 | 0 | if (!mail_index_map_get_ext_idx(map, map->index->keywords_ext_id, &idx)) |
468 | 0 | data = NULL; |
469 | 0 | else { |
470 | 0 | rec = MAIL_INDEX_REC_AT_SEQ(map, seq); |
471 | 0 | ext = array_idx(&map->extensions, idx); |
472 | 0 | data = ext->record_offset == 0 ? NULL : |
473 | 0 | CONST_PTR_OFFSET(rec, ext->record_offset); |
474 | 0 | } |
475 | 0 | mail_index_data_lookup_keywords(map, data, keyword_idx); |
476 | 0 | } |
477 | | |
478 | | void mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq, |
479 | | ARRAY_TYPE(keyword_indexes) *keyword_idx) |
480 | 0 | { |
481 | 0 | view->v.lookup_keywords(view, seq, keyword_idx); |
482 | 0 | } |
483 | | |
484 | | void mail_index_lookup_view_flags(struct mail_index_view *view, uint32_t seq, |
485 | | enum mail_flags *flags_r, |
486 | | ARRAY_TYPE(keyword_indexes) *keyword_idx) |
487 | 0 | { |
488 | 0 | const struct mail_index_record *rec; |
489 | 0 | const unsigned char *keyword_data; |
490 | |
|
491 | 0 | i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view)); |
492 | | |
493 | 0 | rec = MAIL_INDEX_REC_AT_SEQ(view->map, seq); |
494 | 0 | *flags_r = rec->flags; |
495 | |
|
496 | 0 | keyword_data = view_map_lookup_ext_full(view->map, rec, |
497 | 0 | view->index->keywords_ext_id); |
498 | 0 | mail_index_data_lookup_keywords(view->map, keyword_data, keyword_idx); |
499 | 0 | } |
500 | | |
501 | | void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq, |
502 | | uint32_t *uid_r) |
503 | 0 | { |
504 | 0 | view->v.lookup_uid(view, seq, uid_r); |
505 | 0 | } |
506 | | |
507 | | bool mail_index_lookup_seq_range(struct mail_index_view *view, |
508 | | uint32_t first_uid, uint32_t last_uid, |
509 | | uint32_t *first_seq_r, uint32_t *last_seq_r) |
510 | 0 | { |
511 | 0 | view->v.lookup_seq_range(view, first_uid, last_uid, |
512 | 0 | first_seq_r, last_seq_r); |
513 | 0 | return *first_seq_r != 0; |
514 | 0 | } |
515 | | |
516 | | bool mail_index_lookup_seq(struct mail_index_view *view, |
517 | | uint32_t uid, uint32_t *seq_r) |
518 | 0 | { |
519 | 0 | view->v.lookup_seq_range(view, uid, uid, seq_r, seq_r); |
520 | 0 | return *seq_r != 0; |
521 | 0 | } |
522 | | |
523 | | void mail_index_lookup_first(struct mail_index_view *view, |
524 | | enum mail_flags flags, uint8_t flags_mask, |
525 | | uint32_t *seq_r) |
526 | 0 | { |
527 | 0 | view->v.lookup_first(view, flags, flags_mask, seq_r); |
528 | 0 | } |
529 | | |
530 | | void mail_index_lookup_ext(struct mail_index_view *view, uint32_t seq, |
531 | | uint32_t ext_id, const void **data_r, |
532 | | bool *expunged_r) |
533 | 0 | { |
534 | 0 | struct mail_index_map *map; |
535 | |
|
536 | 0 | mail_index_lookup_ext_full(view, seq, ext_id, &map, data_r, expunged_r); |
537 | 0 | } |
538 | | |
539 | | void mail_index_lookup_ext_full(struct mail_index_view *view, uint32_t seq, |
540 | | uint32_t ext_id, struct mail_index_map **map_r, |
541 | | const void **data_r, bool *expunged_r) |
542 | 0 | { |
543 | 0 | view->v.lookup_ext_full(view, seq, ext_id, map_r, data_r, expunged_r); |
544 | 0 | } |
545 | | |
546 | | void mail_index_get_header_ext(struct mail_index_view *view, uint32_t ext_id, |
547 | | const void **data_r, size_t *data_size_r) |
548 | 0 | { |
549 | 0 | view->v.get_header_ext(view, NULL, ext_id, data_r, data_size_r); |
550 | 0 | } |
551 | | |
552 | | void mail_index_map_get_header_ext(struct mail_index_view *view, |
553 | | struct mail_index_map *map, uint32_t ext_id, |
554 | | const void **data_r, size_t *data_size_r) |
555 | 0 | { |
556 | 0 | view->v.get_header_ext(view, map, ext_id, data_r, data_size_r); |
557 | 0 | } |
558 | | |
559 | | bool mail_index_ext_get_reset_id(struct mail_index_view *view, |
560 | | struct mail_index_map *map, |
561 | | uint32_t ext_id, uint32_t *reset_id_r) |
562 | 0 | { |
563 | 0 | return view->v.ext_get_reset_id(view, map, ext_id, reset_id_r); |
564 | 0 | } |
565 | | |
566 | | void mail_index_ext_get_size(struct mail_index_map *map, uint32_t ext_id, |
567 | | uint32_t *hdr_size_r, uint16_t *record_size_r, |
568 | | uint16_t *record_align_r) |
569 | 0 | { |
570 | 0 | const struct mail_index_ext *ext; |
571 | 0 | uint32_t idx; |
572 | |
|
573 | 0 | i_assert(map != NULL); |
574 | | |
575 | 0 | if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) { |
576 | | /* extension doesn't exist in this index file */ |
577 | 0 | *hdr_size_r = 0; |
578 | 0 | *record_size_r = 0; |
579 | 0 | *record_align_r = 0; |
580 | 0 | return; |
581 | 0 | } |
582 | | |
583 | 0 | ext = array_idx(&map->extensions, idx); |
584 | 0 | *hdr_size_r = ext->hdr_size; |
585 | 0 | *record_size_r = ext->record_size; |
586 | 0 | *record_align_r = ext->record_align; |
587 | 0 | } |
588 | | |
589 | | static struct mail_index_view_vfuncs view_vfuncs = { |
590 | | view_close, |
591 | | view_get_messages_count, |
592 | | view_get_header, |
593 | | view_lookup_full, |
594 | | view_lookup_uid, |
595 | | view_lookup_seq_range, |
596 | | view_lookup_first, |
597 | | view_lookup_keywords, |
598 | | view_lookup_ext_full, |
599 | | view_get_header_ext, |
600 | | view_ext_get_reset_id |
601 | | }; |
602 | | |
603 | | struct mail_index_view * |
604 | | mail_index_view_open_with_map(struct mail_index *index, |
605 | | struct mail_index_map *map) |
606 | 0 | { |
607 | 0 | struct mail_index_view *view; |
608 | |
|
609 | 0 | view = i_new(struct mail_index_view, 1); |
610 | 0 | view->refcount = 1; |
611 | 0 | view->v = view_vfuncs; |
612 | 0 | view->index = index; |
613 | 0 | view->log_view = mail_transaction_log_view_open(index->log); |
614 | |
|
615 | 0 | view->indexid = index->indexid; |
616 | 0 | view->inconsistency_id = index->inconsistency_id; |
617 | 0 | view->map = map; |
618 | 0 | view->map->refcount++; |
619 | |
|
620 | 0 | view->log_file_expunge_seq = view->log_file_head_seq = |
621 | 0 | view->map->hdr.log_file_seq; |
622 | 0 | view->log_file_expunge_offset = view->log_file_head_offset = |
623 | 0 | view->map->hdr.log_file_head_offset; |
624 | |
|
625 | 0 | i_array_init(&view->module_contexts, |
626 | 0 | I_MIN(5, mail_index_module_register.id)); |
627 | 0 | DLLIST_PREPEND(&index->views, view); |
628 | 0 | return view; |
629 | 0 | } |
630 | | |
631 | | #undef mail_index_view_open |
632 | | struct mail_index_view * |
633 | | mail_index_view_open(struct mail_index *index, |
634 | | const char *source_filename, unsigned int source_linenum) |
635 | 0 | { |
636 | 0 | struct mail_index_view *view; |
637 | |
|
638 | 0 | view = mail_index_view_open_with_map(index, index->map); |
639 | | /* these can be used to debug mail_index_view_close() leaks */ |
640 | 0 | view->source_filename = source_filename; |
641 | 0 | view->source_linenum = source_linenum; |
642 | 0 | return view; |
643 | 0 | } |
644 | | |
645 | | const struct mail_index_ext * |
646 | | mail_index_view_get_ext(struct mail_index_view *view, uint32_t ext_id) |
647 | 0 | { |
648 | 0 | uint32_t idx; |
649 | |
|
650 | 0 | if (!mail_index_map_get_ext_idx(view->map, ext_id, &idx)) |
651 | 0 | return NULL; |
652 | | |
653 | 0 | return array_idx(&view->map->extensions, idx); |
654 | 0 | } |