mail-index-view.c revision d051664df497582e1eb75a9f238d04b65e858db8
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina/* Copyright (C) 2003-2004 Timo Sirainen */
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina#include "lib.h"
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina#include "array.h"
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina#include "buffer.h"
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina#include "mail-index-view-private.h"
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina#include "mail-transaction-log.h"
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březinavoid mail_index_view_clone(struct mail_index_view *dest,
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina const struct mail_index_view *src)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina{
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina memset(dest, 0, sizeof(dest));
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->refcount = 1;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->v = src->v;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->index = src->index;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina if (src->log_view != NULL) {
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->log_view =
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina mail_transaction_log_view_open(src->index->log);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina }
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->indexid = src->indexid;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->map = src->map;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina if (dest->map != NULL)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->map->refcount++;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->log_file_expunge_seq = src->log_file_expunge_seq;
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina dest->log_file_expunge_offset = src->log_file_expunge_offset;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina dest->log_file_head_seq = src->log_file_head_seq;
beeef7f627a5ed9264de25ee4c76eb9620c1c984Pavel Březina dest->log_file_head_offset = src->log_file_head_offset;
beeef7f627a5ed9264de25ee4c76eb9620c1c984Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina i_array_init(&dest->module_contexts,
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina I_MIN(5, mail_index_module_register.id));
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina}
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březinavoid mail_index_view_ref(struct mail_index_view *view)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina{
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina view->refcount++;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina}
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březinastatic void _view_close(struct mail_index_view *view)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina{
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina i_assert(view->refcount == 0);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina mail_transaction_log_view_close(&view->log_view);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina if (array_is_created(&view->syncs_hidden))
beeef7f627a5ed9264de25ee4c76eb9620c1c984Pavel Březina array_free(&view->syncs_hidden);
beeef7f627a5ed9264de25ee4c76eb9620c1c984Pavel Březina mail_index_unmap(&view->map);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina if (array_is_created(&view->map_refs)) {
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina mail_index_view_unref_maps(view);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina array_free(&view->map_refs);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina }
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina array_free(&view->module_contexts);
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina i_free(view);
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina}
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březinabool mail_index_view_is_inconsistent(struct mail_index_view *view)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina{
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina if (view->index->indexid != view->indexid)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina view->inconsistent = TRUE;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina return view->inconsistent;
beeef7f627a5ed9264de25ee4c76eb9620c1c984Pavel Březina}
beeef7f627a5ed9264de25ee4c76eb9620c1c984Pavel Březina
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březinastruct mail_index *mail_index_view_get_index(struct mail_index_view *view)
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina{
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina return view->index;
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina}
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březinavoid mail_index_view_transaction_ref(struct mail_index_view *view)
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina{
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina view->transactions++;
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina}
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březinavoid mail_index_view_transaction_unref(struct mail_index_view *view)
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina{
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina i_assert(view->transactions > 0);
4e5d19f659d8c545c4ed3c307c95cfe4f2ca33cbPavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina view->transactions--;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina}
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březinastatic void mail_index_view_ref_map(struct mail_index_view *view,
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina struct mail_index_map *map)
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina{
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina struct mail_index_map *const *maps;
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina unsigned int i, count;
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina if (array_is_created(&view->map_refs)) {
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina maps = array_get(&view->map_refs, &count);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina /* if map is already referenced, do nothing */
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina for (i = 0; i < count; i++) {
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina if (maps[i] == map)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina return;
62ebed8582285bd24efba92b9a06366511507946Pavel Březina }
62ebed8582285bd24efba92b9a06366511507946Pavel Březina } else {
62ebed8582285bd24efba92b9a06366511507946Pavel Březina i_array_init(&view->map_refs, 4);
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březina }
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina /* reference the given mapping. the reference is dropped when the view
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina is synchronized or closed. */
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina map->refcount++;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina array_append(&view->map_refs, &map, 1);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina}
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březinavoid mail_index_view_unref_maps(struct mail_index_view *view)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina{
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina struct mail_index_map **maps;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina unsigned int i, count;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina if (!array_is_created(&view->map_refs))
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina return;
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina maps = array_get_modifiable(&view->map_refs, &count);
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina for (i = 0; i < count; i++)
772199031f0ec687fa1fefd939206858c440e5a1Pavel Březina mail_index_unmap(&maps[i]);
array_clear(&view->map_refs);
}
static uint32_t _view_get_messages_count(struct mail_index_view *view)
{
return view->map->hdr.messages_count;
}
static const struct mail_index_header *
_view_get_header(struct mail_index_view *view)
{
return &view->map->hdr;
}
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)
{
struct mail_index_map *map;
const struct mail_index_record *rec, *head_rec;
i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
/* look up the record */
rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
if (rec->uid == 0) {
mail_index_set_error(view->index, "Corrupted Index file %s: "
"Record [%u].uid=0", view->index->filepath, seq);
mail_index_mark_corrupted(view->index);
*map_r = view->map;
*expunged_r = TRUE;
return rec;
}
if (view->map == view->index->map) {
/* view's mapping is latest. we can use it directly. */
*map_r = view->map;
*expunged_r = FALSE;
return rec;
}
/* look up the record from head mapping. it may contain some changes.
start looking up from the same sequence as in the old view.
if there are no expunges, it's there. otherwise it's somewhere
before (since records can't be inserted).
usually there are only a few expunges, so just going downwards from
our initial sequence position is probably faster than binary
search. */
if (seq > view->index->map->hdr.messages_count)
seq = view->index->map->hdr.messages_count;
if (seq == 0) {
/* everything is expunged from head. use the old record. */
*map_r = view->map;
*expunged_r = TRUE;
return rec;
}
map = view->index->map;
do {
seq--;
head_rec = MAIL_INDEX_MAP_IDX(map, seq);
if (head_rec->uid <= rec->uid)
break;
} while (seq > 0);
if (head_rec->uid == rec->uid) {
/* found it. use it. reference the index mapping so that the
returned record doesn't get invalidated after next sync. */
mail_index_view_ref_map(view, view->index->map);
*map_r = view->index->map;
*expunged_r = FALSE;
return head_rec;
} else {
/* expuned from head. use the old record. */
*map_r = view->map;
*expunged_r = TRUE;
return rec;
}
}
static void _view_lookup_uid(struct mail_index_view *view, uint32_t seq,
uint32_t *uid_r)
{
i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
*uid_r = MAIL_INDEX_MAP_IDX(view->map, seq-1)->uid;
}
static uint32_t mail_index_bsearch_uid(struct mail_index_view *view,
uint32_t uid, uint32_t left_idx,
int nearest_side)
{
const struct mail_index_record *rec_base, *rec;
uint32_t idx, right_idx, record_size;
i_assert(view->map->hdr.messages_count <=
view->map->rec_map->records_count);
if (uid == 1) {
/* optimization: the message can be only the first one */
return 1;
}
rec_base = view->map->rec_map->records;
record_size = view->map->hdr.record_size;
idx = left_idx;
right_idx = view->map->hdr.messages_count;
while (left_idx < right_idx) {
idx = (left_idx + right_idx) / 2;
rec = CONST_PTR_OFFSET(rec_base, idx * record_size);
if (rec->uid < uid)
left_idx = idx+1;
else if (rec->uid > uid)
right_idx = idx;
else
break;
}
i_assert(idx < view->map->hdr.messages_count);
rec = CONST_PTR_OFFSET(rec_base, idx * record_size);
if (rec->uid != uid) {
if (nearest_side > 0) {
/* we want uid or larger */
return rec->uid > uid ? idx+1 :
(idx == view->map->hdr.messages_count-1 ?
0 : idx+2);
} else {
/* we want uid or smaller */
return rec->uid < uid ? idx + 1 : idx;
}
}
return idx+1;
}
static void _view_lookup_uid_range(struct mail_index_view *view,
uint32_t first_uid, uint32_t last_uid,
uint32_t *first_seq_r, uint32_t *last_seq_r)
{
i_assert(first_uid > 0);
i_assert(first_uid <= last_uid);
if (view->map->hdr.messages_count == 0) {
*first_seq_r = *last_seq_r = 0;
return;
}
*first_seq_r = mail_index_bsearch_uid(view, first_uid, 0, 1);
if (*first_seq_r == 0 ||
MAIL_INDEX_MAP_IDX(view->map, *first_seq_r-1)->uid > last_uid) {
*first_seq_r = *last_seq_r = 0;
return;
}
if (last_uid >= view->map->hdr.next_uid-1) {
/* we want the last message */
last_uid = view->map->hdr.next_uid-1;
if (first_uid > last_uid) {
*first_seq_r = *last_seq_r = 0;
return;
}
*last_seq_r = view->map->hdr.messages_count;
return;
}
if (first_uid == last_uid)
*last_seq_r = *first_seq_r;
else {
/* optimization - binary lookup only from right side: */
*last_seq_r = mail_index_bsearch_uid(view, last_uid,
*first_seq_r - 1, -1);
}
i_assert(*last_seq_r >= *first_seq_r);
}
static void _view_lookup_first(struct mail_index_view *view,
enum mail_flags flags, uint8_t flags_mask,
uint32_t *seq_r)
{
#define LOW_UPDATE(x) \
STMT_START { if ((x) > low_uid) low_uid = x; } STMT_END
const struct mail_index_record *rec;
uint32_t seq, low_uid = 1;
*seq_r = 0;
if ((flags_mask & MAIL_SEEN) != 0 && (flags & MAIL_SEEN) == 0)
LOW_UPDATE(view->map->hdr.first_unseen_uid_lowwater);
if ((flags_mask & MAIL_DELETED) != 0 && (flags & MAIL_DELETED) != 0)
LOW_UPDATE(view->map->hdr.first_deleted_uid_lowwater);
if (low_uid == 1)
seq = 1;
else {
mail_index_lookup_uid_range(view, low_uid, low_uid,
&seq, &seq);
if (seq == 0)
return;
}
i_assert(view->map->hdr.messages_count <=
view->map->rec_map->records_count);
for (; seq <= view->map->hdr.messages_count; seq++) {
rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
if ((rec->flags & flags_mask) == (uint8_t)flags) {
*seq_r = seq;
break;
}
}
}
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)
{
const struct mail_index_ext *ext;
const struct mail_index_record *rec;
uint32_t idx, offset;
rec = view->v.lookup_full(view, seq, map_r, expunged_r);
if (!mail_index_map_get_ext_idx(*map_r, ext_id, &idx)) {
*data_r = NULL;
return;
}
ext = array_idx(&(*map_r)->extensions, idx);
offset = ext->record_offset;
*data_r = offset == 0 ? NULL : CONST_PTR_OFFSET(rec, offset);
}
static void _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)
{
const struct mail_index_ext *ext;
uint32_t idx;
if (map == NULL) {
/* no mapping given, use head mapping */
map = view->index->map;
}
if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
/* extension doesn't exist in this index file */
*data_r = NULL;
*data_size_r = 0;
return;
}
ext = array_idx(&map->extensions, idx);
*data_r = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
*data_size_r = ext->hdr_size;
}
static bool _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)
{
const struct mail_index_ext *ext;
uint32_t idx;
if (!mail_index_map_get_ext_idx(map, ext_id, &idx))
return FALSE;
ext = array_idx(&map->extensions, idx);
*reset_id_r = ext->reset_id;
return TRUE;
}
void mail_index_view_close(struct mail_index_view **_view)
{
struct mail_index_view *view = *_view;
*_view = NULL;
if (--view->refcount > 0)
return;
i_assert(view->transactions == 0);
view->v.close(view);
}
uint32_t mail_index_view_get_messages_count(struct mail_index_view *view)
{
return view->v.get_messages_count(view);
}
const struct mail_index_header *
mail_index_get_header(struct mail_index_view *view)
{
return view->v.get_header(view);
}
const struct mail_index_record *
mail_index_lookup(struct mail_index_view *view, uint32_t seq)
{
struct mail_index_map *map;
return mail_index_lookup_full(view, seq, &map);
}
const struct mail_index_record *
mail_index_lookup_full(struct mail_index_view *view, uint32_t seq,
struct mail_index_map **map_r)
{
bool expunged;
return view->v.lookup_full(view, seq, map_r, &expunged);
}
bool mail_index_is_expunged(struct mail_index_view *view, uint32_t seq)
{
struct mail_index_map *map;
bool expunged;
(void)view->v.lookup_full(view, seq, &map, &expunged);
return expunged;
}
void mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
ARRAY_TYPE(keyword_indexes) *keyword_idx)
{
struct mail_index_map *map;
const void *data;
const unsigned char *keyword_data;
const unsigned int *keyword_idx_map;
unsigned int i, j, keyword_count, index_idx;
uint32_t ext_id, idx;
uint16_t record_size;
array_clear(keyword_idx);
/* get the keywords data. */
ext_id = view->index->keywords_ext_id;
mail_index_lookup_ext_full(view, seq, ext_id, &map, &data, NULL);
if (data == NULL) {
/* no keywords at all in index */
return;
}
keyword_data = data;
(void)mail_index_ext_get_size(view, ext_id, map, NULL,
&record_size, NULL);
/* keyword_idx_map[] contains file => index keyword mapping */
if (!array_is_created(&map->keyword_idx_map))
return;
keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count);
for (i = 0, idx = 0; i < record_size; i++) {
/* first do the quick check to see if there's keywords at all */
if (keyword_data[i] == 0)
continue;
idx = i * CHAR_BIT;
for (j = 0; j < CHAR_BIT; j++, idx++) {
if ((keyword_data[i] & (1 << j)) == 0)
continue;
if (idx >= keyword_count) {
/* extra bits set in keyword bytes.
shouldn't happen, but just ignore. */
break;
}
index_idx = keyword_idx_map[idx];
array_append(keyword_idx, &index_idx, 1);
}
}
}
void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
uint32_t *uid_r)
{
view->v.lookup_uid(view, seq, uid_r);
}
void mail_index_lookup_uid_range(struct mail_index_view *view,
uint32_t first_uid, uint32_t last_uid,
uint32_t *first_seq_r, uint32_t *last_seq_r)
{
view->v.lookup_uid_range(view, first_uid, last_uid,
first_seq_r, last_seq_r);
}
void mail_index_lookup_first(struct mail_index_view *view,
enum mail_flags flags, uint8_t flags_mask,
uint32_t *seq_r)
{
view->v.lookup_first(view, flags, flags_mask, seq_r);
}
void mail_index_lookup_ext(struct mail_index_view *view, uint32_t seq,
uint32_t ext_id, const void **data_r,
bool *expunged_r)
{
struct mail_index_map *map;
mail_index_lookup_ext_full(view, seq, ext_id, &map, data_r, expunged_r);
}
void 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)
{
bool expunged;
if (expunged_r == NULL)
expunged_r = &expunged;
view->v.lookup_ext_full(view, seq, ext_id, map_r, data_r, expunged_r);
}
void mail_index_get_header_ext(struct mail_index_view *view, uint32_t ext_id,
const void **data_r, size_t *data_size_r)
{
view->v.get_header_ext(view, NULL, ext_id, data_r, data_size_r);
}
void 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)
{
view->v.get_header_ext(view, map, ext_id, data_r, data_size_r);
}
bool 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)
{
return view->v.ext_get_reset_id(view, map, ext_id, reset_id_r);
}
void mail_index_ext_get_size(struct mail_index_view *view __attr_unused__,
uint32_t ext_id, struct mail_index_map *map,
uint32_t *hdr_size_r, uint16_t *record_size_r,
uint16_t *record_align_r)
{
const struct mail_index_ext *ext;
uint32_t idx;
i_assert(map != NULL);
if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
/* extension doesn't exist in this index file */
if (hdr_size_r != NULL)
*hdr_size_r = 0;
if (record_size_r != NULL)
*record_size_r = 0;
if (record_align_r != NULL)
*record_align_r = 0;
return;
}
ext = array_idx(&map->extensions, idx);
if (hdr_size_r != NULL)
*hdr_size_r = ext->hdr_size;
if (record_size_r != NULL)
*record_size_r = ext->record_size;
if (record_align_r != NULL)
*record_align_r = ext->record_align;
}
static struct mail_index_view_vfuncs view_vfuncs = {
_view_close,
_view_get_messages_count,
_view_get_header,
_view_lookup_full,
_view_lookup_uid,
_view_lookup_uid_range,
_view_lookup_first,
_view_lookup_ext_full,
_view_get_header_ext,
_view_ext_get_reset_id
};
struct mail_index_view *
mail_index_view_open_with_map(struct mail_index *index,
struct mail_index_map *map)
{
struct mail_index_view *view;
view = i_new(struct mail_index_view, 1);
view->refcount = 1;
view->v = view_vfuncs;
view->index = index;
view->log_view = mail_transaction_log_view_open(index->log);
view->indexid = index->indexid;
view->map = map;
view->map->refcount++;
view->log_file_expunge_seq = view->log_file_head_seq =
view->map->hdr.log_file_seq;
view->log_file_expunge_offset = view->log_file_head_offset =
view->map->hdr.log_file_head_offset;
i_array_init(&view->module_contexts,
I_MIN(5, mail_index_module_register.id));
return view;
}
struct mail_index_view *mail_index_view_open(struct mail_index *index)
{
return mail_index_view_open_with_map(index, index->map);
}
const struct mail_index_ext *
mail_index_view_get_ext(struct mail_index_view *view, uint32_t ext_id)
{
uint32_t idx;
if (!mail_index_map_get_ext_idx(view->map, ext_id, &idx))
return NULL;
return array_idx(&view->map->extensions, idx);
}