mail-index-view.c revision 03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11a
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (C) 2003-2004 Timo Sirainen */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "lib.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "array.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "buffer.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "mail-index-view-private.h"
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen#include "mail-transaction-log.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
9511a40d933181045343110c8101b75887062aaeTimo Sirainenvoid mail_index_view_clone(struct mail_index_view *dest,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen const struct mail_index_view *src)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen memset(dest, 0, sizeof(dest));
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->refcount = 1;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->methods = src->methods;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->index = src->index;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->log_view = mail_transaction_log_view_open(src->index->log);
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->indexid = src->indexid;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->map = src->map;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->map->refcount++;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->hdr = src->hdr;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->broken_counters = src->broken_counters;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->log_file_seq = src->log_file_seq;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen dest->log_file_offset = src->log_file_offset;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenvoid mail_index_view_ref(struct mail_index_view *view)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen view->refcount++;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
3f8303bae0f70df6db9337ad1d1476d290f9b1a3Timo Sirainenstatic void _view_close(struct mail_index_view *view)
3f8303bae0f70df6db9337ad1d1476d290f9b1a3Timo Sirainen{
3f8303bae0f70df6db9337ad1d1476d290f9b1a3Timo Sirainen i_assert(view->refcount == 0);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen mail_index_view_unlock(view);
859cc94211b759825db5e15b0c88754da902ca14Timo Sirainen mail_transaction_log_view_close(&view->log_view);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
859cc94211b759825db5e15b0c88754da902ca14Timo Sirainen if (array_is_created(&view->syncs_done))
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen array_free(&view->syncs_done);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (array_is_created(&view->syncs_hidden))
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen array_free(&view->syncs_hidden);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen mail_index_unmap(view->index, &view->map);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (array_is_created(&view->map_refs)) {
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen mail_index_view_unref_maps(view);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen array_free(&view->map_refs);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen }
bcd286622779a93f809b11993db0550f8c7cc9b5Timo Sirainen i_free(view);
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen}
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainenint mail_index_view_lock_head(struct mail_index_view *view, bool update_index)
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen{
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen unsigned int lock_id;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(view->index->map))
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen return 0;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (!mail_index_is_locked(view->index, view->lock_id)) {
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (mail_index_lock_shared(view->index, update_index,
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen &view->lock_id) < 0)
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen return -1;
1117aa7adc2909c750031fd7551a58a486d100d8Timo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (mail_index_map(view->index, FALSE) <= 0) {
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen view->inconsistent = TRUE;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen return -1;
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen }
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen
8887a9bb6d2e3f664cf741b763643a0e5610fa4dTimo Sirainen if (view->index->indexid != view->indexid) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* index was rebuilt */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen view->inconsistent = TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen } else if (update_index) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mail_index_lock_shared(view->index, TRUE, &lock_id) < 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen mail_index_unlock(view->index, view->lock_id);
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen view->lock_id = lock_id;
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen }
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
2c0f1cb7a0564d48ec43c7315ea46ea38d2abd19Timo Sirainen i_assert(view->index->lock_type != F_UNLCK);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return 0;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenint mail_index_view_lock(struct mail_index_view *view)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mail_index_view_is_inconsistent(view))
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return -1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (view->map != view->index->map) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* not head mapping, no need to lock */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return 0;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen return mail_index_view_lock_head(view, FALSE);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen}
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenvoid mail_index_view_unlock(struct mail_index_view *view)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen{
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (view->lock_id != 0) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen mail_index_unlock(view->index, view->lock_id);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen view->lock_id = 0;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen}
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenbool mail_index_view_is_inconsistent(struct mail_index_view *view)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen{
10c96a244935de4add8213ba0b894178dfb889a5Timo Sirainen if (view->index->indexid != view->indexid)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen view->inconsistent = TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return view->inconsistent;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstruct mail_index *mail_index_view_get_index(struct mail_index_view *view)
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return view->index;
4aa7fe81503a20bc972ae625da4dd9e6996fbdbfTimo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenvoid mail_index_view_transaction_ref(struct mail_index_view *view)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen view->transactions++;
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen}
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainenvoid mail_index_view_transaction_unref(struct mail_index_view *view)
9511a40d933181045343110c8101b75887062aaeTimo Sirainen{
2974dca6be5120e49279f06c8aa952e5fac56048Timo Sirainen i_assert(view->transactions > 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen view->transactions--;
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen}
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainenstatic void mail_index_view_ref_map(struct mail_index_view *view,
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen struct mail_index_map *map)
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen{
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen struct mail_index_map *const *maps;
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen unsigned int i, count;
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen if (array_is_created(&view->map_refs)) {
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen maps = array_get(&view->map_refs, &count);
bdcb00145ad87765e3fd22d4ebc4d2c029a326b9Timo Sirainen
/* if map is already referenced, do nothing */
for (i = 0; i < count; i++) {
if (maps[i] == map)
return;
}
} else {
ARRAY_CREATE(&view->map_refs, default_pool,
struct mail_index_map *, 4);
}
/* reference the given mapping. the reference is dropped when the view
is synchronized or closed. */
map->refcount++;
array_append(&view->map_refs, &map, 1);
}
void mail_index_view_unref_maps(struct mail_index_view *view)
{
struct mail_index_map **maps;
unsigned int i, count;
if (!array_is_created(&view->map_refs))
return;
maps = array_get_modifyable(&view->map_refs, &count);
for (i = 0; i < count; i++)
mail_index_unmap(view->index, &maps[i]);
array_clear(&view->map_refs);
}
static uint32_t _view_get_messages_count(struct mail_index_view *view)
{
return view->hdr.messages_count;
}
static const struct mail_index_header *
_view_get_header(struct mail_index_view *view)
{
if (view->broken_counters)
mail_index_view_recalc_counters(view);
return &view->hdr;
}
static int _view_lookup_full(struct mail_index_view *view, uint32_t seq,
struct mail_index_map **map_r,
const struct mail_index_record **rec_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));
if (mail_index_view_lock(view) < 0)
return -1;
/* look up the record */
rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
if (view->map == view->index->map) {
/* view's mapping is latest. we can use it directly. */
*map_r = view->map;
*rec_r = rec;
return 1;
}
/* look up the record from head mapping. it may contain some changes. */
if (mail_index_view_lock_head(view, FALSE) < 0)
return -1;
/* 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->hdr->messages_count)
seq = view->index->hdr->messages_count;
if (seq == 0) {
/* everything is expunged from head. use the old record. */
*map_r = view->map;
*rec_r = rec;
return 0;
}
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;
*rec_r = head_rec;
return 1;
} else {
/* expuned from head. use the old record. */
*map_r = view->map;
*rec_r = rec;
return 0;
}
}
static int _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));
if (mail_index_view_lock(view) < 0)
return -1;
*uid_r = MAIL_INDEX_MAP_IDX(view->map, seq-1)->uid;
return 0;
}
static uint32_t mail_index_bsearch_uid(struct mail_index_view *view,
uint32_t uid, uint32_t *left_idx_p,
int nearest_side)
{
const struct mail_index_record *rec_base, *rec;
uint32_t idx, left_idx, right_idx, record_size;
i_assert(view->hdr.messages_count <= view->map->records_count);
rec_base = view->map->records;
record_size = view->map->hdr.record_size;
idx = left_idx = *left_idx_p;
right_idx = view->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;
}
if (idx == view->hdr.messages_count) {
/* no messages available */
return 0;
}
*left_idx_p = left_idx;
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->hdr.messages_count-1 ? 0 : idx+2;
} else {
/* we want uid or smaller */
return rec->uid < uid ? idx + 1 : idx;
}
}
return idx+1;
}
static int _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)
{
uint32_t left_idx;
i_assert(first_uid > 0);
i_assert(first_uid <= last_uid);
if (mail_index_view_lock(view) < 0)
return -1;
if (last_uid >= view->map->hdr.next_uid) {
last_uid = view->map->hdr.next_uid-1;
if (first_uid > last_uid) {
*first_seq_r = 0;
*last_seq_r = 0;
return 0;
}
}
left_idx = 0;
*first_seq_r = mail_index_bsearch_uid(view, first_uid, &left_idx, 1);
if (*first_seq_r == 0 ||
MAIL_INDEX_MAP_IDX(view->map, *first_seq_r-1)->uid > last_uid) {
*first_seq_r = 0;
*last_seq_r = 0;
return 0;
}
if (first_uid == last_uid) {
*last_seq_r = *first_seq_r;
return 0;
}
/* optimization - binary lookup only from right side: */
*last_seq_r = mail_index_bsearch_uid(view, last_uid, &left_idx, -1);
i_assert(*last_seq_r >= *first_seq_r);
return 0;
}
static int _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 (mail_index_view_lock(view) < 0)
return -1;
if ((flags_mask & MAIL_RECENT) != 0 && (flags & MAIL_RECENT) != 0)
LOW_UPDATE(view->map->hdr.first_recent_uid_lowwater);
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 {
if (mail_index_lookup_uid_range(view, low_uid, low_uid,
&seq, &seq) < 0)
return -1;
if (seq == 0)
return 0;
}
i_assert(view->hdr.messages_count <= view->map->records_count);
for (; seq <= view->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;
}
}
return 0;
}
static int _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)
{
const struct mail_index_ext *ext;
const struct mail_index_record *rec;
uint32_t idx, offset;
int ret;
if ((ret = mail_index_lookup_full(view, seq, map_r, &rec)) < 0)
return -1;
if (rec == NULL || !mail_index_map_get_ext_idx(*map_r, ext_id, &idx)) {
*data_r = NULL;
return ret;
}
ext = array_idx(&(*map_r)->extensions, idx);
offset = ext->record_offset;
*data_r = offset == 0 ? NULL : CONST_PTR_OFFSET(rec, offset);
return ret;
}
static int _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 we have a mapping, the view where it's from is already locked */
if (map == NULL) {
/* no mapping given, use head mapping */
if (mail_index_view_lock_head(view, FALSE) < 0)
return -1;
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 0;
}
ext = array_idx(&map->extensions, idx);
*data_r = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
*data_size_r = ext->hdr_size;
return 0;
}
void mail_index_view_close(struct mail_index_view **_view)
{
struct mail_index_view *view = *_view;
*_view = NULL;
if (--view->refcount > 0)
return;
view->methods.close(view);
}
uint32_t mail_index_view_get_messages_count(struct mail_index_view *view)
{
return view->methods.get_messages_count(view);
}
const struct mail_index_header *
mail_index_get_header(struct mail_index_view *view)
{
return view->methods.get_header(view);
}
int mail_index_lookup(struct mail_index_view *view, uint32_t seq,
const struct mail_index_record **rec_r)
{
struct mail_index_map *map;
return mail_index_lookup_full(view, seq, &map, rec_r);
}
int mail_index_lookup_full(struct mail_index_view *view, uint32_t seq,
struct mail_index_map **map_r,
const struct mail_index_record **rec_r)
{
return view->methods.lookup_full(view, seq, map_r, rec_r);
}
int mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
array_t *keyword_idx)
{
ARRAY_SET_TYPE(keyword_idx, unsigned int);
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;
int ret;
array_clear(keyword_idx);
/* get the keywords data. */
ext_id = view->index->keywords_ext_id;
ret = mail_index_lookup_ext_full(view, seq, ext_id, &map, &data);
if (ret < 0)
return -1;
if (data == NULL) {
/* no keywords at all in index */
return ret;
}
(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)) {
keyword_idx_map = NULL;
keyword_count = 0;
} else {
keyword_idx_map = array_get(&map->keyword_idx_map,
&keyword_count);
}
keyword_data = data;
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) {
/* keyword header was updated, parse it again
it so we know what this keyword is called */
if (mail_index_map_parse_keywords(view->index,
map) < 0)
return -1;
if (!array_is_created(&map->keyword_idx_map))
return ret;
/* pointer may have changed. update it. */
keyword_idx_map =
array_get(&map->keyword_idx_map,
&keyword_count);
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);
}
}
return ret;
}
int mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
uint32_t *uid_r)
{
return view->methods.lookup_uid(view, seq, uid_r);
}
int 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)
{
return view->methods.lookup_uid_range(view, first_uid, last_uid,
first_seq_r, last_seq_r);
}
int mail_index_lookup_first(struct mail_index_view *view, enum mail_flags flags,
uint8_t flags_mask, uint32_t *seq_r)
{
return view->methods.lookup_first(view, flags, flags_mask, seq_r);
}
int mail_index_lookup_ext(struct mail_index_view *view, uint32_t seq,
uint32_t ext_id, const void **data_r)
{
struct mail_index_map *map;
return view->methods.lookup_ext_full(view, seq, ext_id, &map, data_r);
}
int 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)
{
return view->methods.lookup_ext_full(view, seq, ext_id, map_r, data_r);
}
int mail_index_get_header_ext(struct mail_index_view *view, uint32_t ext_id,
const void **data_r, size_t *data_size_r)
{
return view->methods.get_header_ext(view, NULL, ext_id,
data_r, data_size_r);
}
int 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)
{
return view->methods.get_header_ext(view, map, ext_id,
data_r, data_size_r);
}
int 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 0;
}
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;
return 0;
}
static struct mail_index_view_methods view_methods = {
_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
};
struct mail_index_view *mail_index_view_open(struct mail_index *index)
{
struct mail_index_view *view;
i_assert(index->map != NULL);
view = i_new(struct mail_index_view, 1);
view->refcount = 1;
view->methods = view_methods;
view->index = index;
view->log_view = mail_transaction_log_view_open(index->log);
view->indexid = index->indexid;
view->map = index->map;
view->map->refcount++;
view->hdr = view->map->hdr;
view->log_file_seq = view->map->hdr.log_file_seq;
view->log_file_offset =
I_MIN(view->map->hdr.log_file_int_offset,
view->map->hdr.log_file_ext_offset);
return view;
}
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 0;
return array_idx(&view->map->extensions, idx);
}