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