NULL,
NULL,
NULL,
+ NULL,
NULL
};
void mail_index_transaction_convert_to_uids(struct mail_index_transaction *t);
void mail_index_transaction_check_conflicts(struct mail_index_transaction *t);
+unsigned int
+mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t,
+ unsigned int left_idx,
+ unsigned int right_idx,
+ uint32_t seq);
+
bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
uint32_t seq, unsigned int *idx_r);
struct mail_index_map *lookup_map;
struct mail_index_header hdr;
+
buffer_t *lookup_return_data;
uint32_t lookup_prev_seq;
+
+ unsigned int recs_count;
+ struct mail_index_record *recs;
};
static void tview_close(struct mail_index_view *view)
mail_index_unmap(&tview->lookup_map);
if (tview->lookup_return_data != NULL)
buffer_free(&tview->lookup_return_data);
+ i_free(tview->recs);
tview->super->close(view);
mail_index_transaction_unref(&t);
return hdr;
}
+static const struct mail_index_record *
+tview_apply_flag_updates(struct mail_index_view_transaction *tview,
+ const struct mail_index_record *rec, uint32_t seq)
+{
+ struct mail_index_transaction *t = tview->t;
+ const struct mail_transaction_flag_update *updates;
+ unsigned int idx, count;
+
+ /* see if there are any flag updates */
+ if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq ||
+ !array_is_created(&t->updates))
+ return rec;
+
+ updates = array_get(&t->updates, &count);
+ idx = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
+ if (seq < updates[idx].uid1 || seq > updates[idx].uid2)
+ return rec;
+
+ /* yes, we have flag updates. since we can't modify rec directly and
+ we want to be able to handle multiple mail_index_lookup() calls
+ without the second one overriding the first one's data, we'll
+ create a records array and return data from there */
+ if (tview->recs == NULL) {
+ tview->recs_count = t->first_new_seq;
+ tview->recs = i_new(struct mail_index_record,
+ tview->recs_count);
+ }
+ i_assert(tview->recs_count == t->first_new_seq);
+ i_assert(seq > 0 && seq <= tview->recs_count);
+
+ tview->recs[seq-1] = *rec;
+ tview->recs[seq-1].flags |= updates[idx].add_flags;
+ tview->recs[seq-1].flags &= ~updates[idx].remove_flags;
+ return &tview->recs[seq-1];
+}
+
static const struct mail_index_record *
tview_lookup_full(struct mail_index_view *view, uint32_t seq,
struct mail_index_map **map_r, bool *expunged_r)
}
rec = tview->super->lookup_full(view, seq, map_r, expunged_r);
+ rec = tview_apply_flag_updates(tview, rec, seq);
- /* if we're expunged within this transaction, return 0 */
if (array_is_created(&tview->t->expunges) &&
seq_range_exists(&tview->t->expunges, seq))
*expunged_r = TRUE;
}
}
+static void keyword_index_add(ARRAY_TYPE(keyword_indexes) *keywords,
+ unsigned int idx)
+{
+ const unsigned int *indexes;
+ unsigned int i, count;
+
+ indexes = array_get(keywords, &count);
+ for (i = 0; i < count; i++) {
+ if (indexes[i] == idx)
+ return;
+ }
+ array_append(keywords, &idx, 1);
+}
+
+static void keyword_index_remove(ARRAY_TYPE(keyword_indexes) *keywords,
+ unsigned int idx)
+{
+ const unsigned int *indexes;
+ unsigned int i, count;
+
+ indexes = array_get(keywords, &count);
+ for (i = 0; i < count; i++) {
+ if (indexes[i] == idx) {
+ array_delete(keywords, i, 1);
+ break;
+ }
+ }
+}
+
+static void tview_lookup_keywords(struct mail_index_view *view, uint32_t seq,
+ ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+ struct mail_index_view_transaction *tview =
+ (struct mail_index_view_transaction *)view;
+ struct mail_index_transaction *t = tview->t;
+ const struct mail_index_transaction_keyword_update *updates;
+ unsigned int i, count;
+
+ tview->super->lookup_keywords(view, seq, keyword_idx);
+
+ if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq) {
+ /* no keyword updates for this sequence */
+ return;
+ }
+
+ /* apply any keyword updates in this transaction */
+ if (array_is_created(&t->keyword_resets)) {
+ if (seq_range_exists(&t->keyword_resets, seq))
+ array_clear(keyword_idx);
+ }
+
+ if (array_is_created(&t->keyword_updates))
+ updates = array_get(&t->keyword_updates, &count);
+ else {
+ updates = NULL;
+ count = 0;
+ }
+ for (i = 0; i < count; i++) {
+ if (array_is_created(&updates[i].add_seq) &&
+ seq_range_exists(&updates[i].add_seq, seq))
+ keyword_index_add(keyword_idx, i);
+ else if (array_is_created(&updates[i].remove_seq) &&
+ seq_range_exists(&updates[i].remove_seq, seq))
+ keyword_index_remove(keyword_idx, i);
+ }
+}
+
static struct mail_index_map *
tview_get_lookup_map(struct mail_index_view_transaction *tview)
{
tview_lookup_uid,
tview_lookup_seq_range,
tview_lookup_first,
+ tview_lookup_keywords,
tview_lookup_ext_full,
tview_get_header_ext,
tview_ext_get_reset_id
return FALSE;
}
-static uint32_t
-mail_index_find_update_insert_pos(struct mail_index_transaction *t,
- unsigned int left_idx, unsigned int right_idx,
- uint32_t seq)
+unsigned int
+mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t,
+ unsigned int left_idx,
+ unsigned int right_idx,
+ uint32_t seq)
{
const struct mail_transaction_flag_update *updates;
unsigned int idx, count;
first_idx = 0;
count = t->last_update_idx + 1;
}
- idx = mail_index_find_update_insert_pos(t, first_idx, count,
- u.uid1);
+ idx = mail_index_transaction_get_flag_update_pos(t, first_idx,
+ count, u.uid1);
mail_index_insert_flag_update(t, u, idx);
}
}
return ret;
updates = array_get_modifiable(&t->updates, &count);
- i = mail_index_find_update_insert_pos(t, 0, count, seq);
+ i = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
if (i < count && updates[i].uid1 <= seq && updates[i].uid2 >= seq) {
/* exists */
ret = TRUE;
void (*lookup_first)(struct mail_index_view *view,
enum mail_flags flags, uint8_t flags_mask,
uint32_t *seq_r);
+ void (*lookup_keywords)(struct mail_index_view *view, uint32_t seq,
+ ARRAY_TYPE(keyword_indexes) *keyword_idx);
void (*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);
}
}
+static void
+mail_index_data_lookup_keywords(struct mail_index_map *map,
+ const unsigned char *data,
+ ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+ const unsigned int *keyword_idx_map;
+ unsigned int i, j, keyword_count, index_idx;
+ uint32_t idx;
+ uint16_t record_size;
+
+ array_clear(keyword_idx);
+ if (data == NULL) {
+ /* no keywords at all in index */
+ return;
+ }
+ (void)mail_index_ext_get_size(NULL, map->index->keywords_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 (data[i] == 0)
+ continue;
+
+ idx = i * CHAR_BIT;
+ for (j = 0; j < CHAR_BIT; j++, idx++) {
+ if ((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);
+ }
+ }
+}
+
+static void view_lookup_keywords(struct mail_index_view *view, uint32_t seq,
+ ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+ struct mail_index_map *map;
+ const void *data;
+
+ mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id,
+ &map, &data, NULL);
+ mail_index_data_lookup_keywords(map, data, keyword_idx);
+}
+
static void
view_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
uint32_t ext_id, struct mail_index_map **map_r,
return expunged;
}
-static void
-mail_index_data_lookup_keywords(struct mail_index_map *map,
- const unsigned char *data,
- ARRAY_TYPE(keyword_indexes) *keyword_idx)
-{
- const unsigned int *keyword_idx_map;
- unsigned int i, j, keyword_count, index_idx;
- uint32_t idx;
- uint16_t record_size;
-
- array_clear(keyword_idx);
- if (data == NULL) {
- /* no keywords at all in index */
- return;
- }
- (void)mail_index_ext_get_size(NULL, map->index->keywords_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 (data[i] == 0)
- continue;
-
- idx = i * CHAR_BIT;
- for (j = 0; j < CHAR_BIT; j++, idx++) {
- if ((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_map_lookup_keywords(struct mail_index_map *map, uint32_t seq,
ARRAY_TYPE(keyword_indexes) *keyword_idx)
{
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;
-
- mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id,
- &map, &data, NULL);
- mail_index_data_lookup_keywords(map, data, keyword_idx);
+ view->v.lookup_keywords(view, seq, keyword_idx);
}
void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
view_lookup_uid,
view_lookup_seq_range,
view_lookup_first,
+ view_lookup_keywords,
view_lookup_ext_full,
view_get_header_ext,
view_ext_get_reset_id
enum mail_flags index_mail_get_flags(struct mail *_mail)
{
struct index_mail *mail = (struct index_mail *)_mail;
- struct index_mail_data *data = &mail->data;
+ const struct mail_index_record *rec;
+ enum mail_flags flags;
+
+ rec = mail_index_lookup(mail->trans->trans_view, _mail->seq);
+ flags = rec->flags & (MAIL_FLAGS_NONRECENT |
+ MAIL_INDEX_MAIL_FLAG_BACKEND);
if (index_mailbox_is_recent(mail->ibox, _mail->uid))
- data->flags |= MAIL_RECENT;
+ flags |= MAIL_RECENT;
- return data->flags;
+ return flags;
}
uint64_t index_mail_get_modseq(struct mail *_mail)
if (!array_is_created(&data->keyword_indexes)) {
p_array_init(&data->keyword_indexes, mail->data_pool, 32);
- mail_index_lookup_keywords(mail->ibox->view, mail->data.seq,
+ mail_index_lookup_keywords(mail->trans->trans_view,
+ mail->data.seq,
&data->keyword_indexes);
}
return &data->keyword_indexes;
struct index_mail_data *data = &mail->data;
struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
struct mail_cache_view *cache_view = mail->trans->cache_view;
- const struct mail_index_record *rec;
struct istream *input;
if (data->seq == seq)
index_mail_reset(mail);
- rec = mail_index_lookup(mail->trans->trans_view, seq);
data->seq = seq;
- data->flags = rec->flags & (MAIL_FLAGS_NONRECENT |
- MAIL_INDEX_MAIL_FLAG_BACKEND);
mail->mail.mail.seq = seq;
- mail->mail.mail.uid = rec->uid;
+ mail_index_lookup_uid(mail->trans->trans_view, seq,
+ &mail->mail.mail.uid);
if (mail_index_view_is_inconsistent(mail->trans->trans_view)) {
mail_set_expunged(&mail->mail.mail);
{
struct index_mail *imail = (struct index_mail *)mail;
+ if (array_is_created(&imail->data.keyword_indexes))
+ array_free(&imail->data.keyword_indexes);
+ if (array_is_created(&imail->data.keywords)) {
+ /* clear the keywords array so the next mail_get_keywords()
+ returns the updated keywords. don't free the array, because
+ then any existing mail_get_keywords() return values would
+ point to broken data. this won't leak memory because the
+ array is allocated from mail's memory pool. */
+ memset(&imail->data.keywords, 0,
+ sizeof(imail->data.keywords));
+ }
+
mail_index_update_keywords(imail->trans->trans, mail->seq, modify_type,
keywords);
}
struct message_header_line;
struct index_mail_data {
- enum mail_flags flags;
time_t date, received_date, save_date;
uoff_t virtual_size, physical_size;
struct mailbox_transaction_context *backend_trans;
struct mailbox_header_lookup_ctx *backend_headers;
const struct virtual_mail_index_record *vrec;
- const struct mail_index_record *rec;
const void *data;
bool expunged;
memset(&vmail->imail.data, 0, sizeof(vmail->imail.data));
p_clear(vmail->imail.data_pool);
- rec = mail_index_lookup(mbox->ibox.view, seq);
vmail->imail.data.seq = seq;
- vmail->imail.data.flags = rec->flags & MAIL_FLAGS_NONRECENT;
-
mail->seq = seq;
- mail->uid = rec->uid;
+ mail_index_lookup_uid(mbox->ibox.view, seq, &mail->uid);
mail->expunged = vmail->backend_mail->expunged;
mail->has_nuls = vmail->backend_mail->has_nuls;