Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-index/mail-index-transaction-view.c @ 5228:3bccf203fa91 HEAD
When adding mails to index in non-sorted UID order and then using
mail_index_get_header(), the next_uid field could have been wrong.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 06 Mar 2007 22:19:08 +0200 |
parents | 0ffb6fa11744 |
children | fd6ff4d9cab1 |
line wrap: on
line source
/* Copyright (C) 2004-2006 Timo Sirainen */ #include "lib.h" #include "array.h" #include "buffer.h" #include "seq-range-array.h" #include "mail-index-private.h" #include "mail-index-view-private.h" #include "mail-index-transaction-private.h" struct mail_index_view_transaction { struct mail_index_view view; struct mail_index_view_vfuncs *super; struct mail_index_transaction *t; struct mail_index_header hdr; }; static void _tview_close(struct mail_index_view *view) { struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; struct mail_index_transaction *t = tview->t; tview->super->close(view); mail_index_transaction_unref(&t); } static uint32_t _tview_get_message_count(struct mail_index_view *view) { struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; return view->hdr.messages_count + (tview->t->last_new_seq == 0 ? 0 : tview->t->last_new_seq - tview->t->first_new_seq); } static const struct mail_index_header * _tview_get_header(struct mail_index_view *view) { struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; const struct mail_index_header *hdr; const struct mail_index_record *recs; unsigned int count; /* FIXME: header counters may not be correct */ hdr = tview->super->get_header(view); if (array_is_created(&tview->t->appends)) { /* update next_uid from appends, if UIDs have been given yet */ mail_index_transaction_sort_appends(tview->t); recs = array_get(&tview->t->appends, &count); if (count > 0 && recs[count-1].uid != 0) { i_assert(recs[count-1].uid >= hdr->next_uid); tview->hdr = *hdr; tview->hdr.next_uid = recs[count-1].uid + 1; hdr = &tview->hdr; } } return hdr; } static int _tview_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_view_transaction *tview = (struct mail_index_view_transaction *)view; int ret; if (seq >= tview->t->first_new_seq) { /* FIXME: is this right to return index map..? it's not there yet. */ *map_r = view->index->map; *rec_r = mail_index_transaction_lookup(tview->t, seq); return 1; } ret = tview->super->lookup_full(view, seq, map_r, rec_r); if (ret <= 0) return ret; /* if we're expunged within this transaction, return 0 */ return array_is_created(&tview->t->expunges) && seq_range_exists(&tview->t->expunges, seq) ? 0 : 1; } static int _tview_lookup_uid(struct mail_index_view *view, uint32_t seq, uint32_t *uid_r) { struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; if (seq >= tview->t->first_new_seq) { *uid_r = mail_index_transaction_lookup(tview->t, seq)->uid; return 0; } else { return tview->super->lookup_uid(view, seq, uid_r); } } static int _tview_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) { struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; if (tview->super->lookup_uid_range(view, first_uid, last_uid, first_seq_r, last_seq_r) < 0) return -1; /* FIXME: we don't need this function yet.. new UIDs might be 0 as well.. */ if (*first_seq_r == 0) { /* nothing found, either doesn't exist or it's completely newly appended. */ } else if (*last_seq_r + 1 == tview->t->first_new_seq) { /* last_seq_r may be growed from transactions */ } return 0; } static int _tview_lookup_first(struct mail_index_view *view, enum mail_flags flags, uint8_t flags_mask, uint32_t *seq_r) { struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; const struct mail_index_record *rec; unsigned int append_count; uint32_t seq, message_count; if (tview->super->lookup_first(view, flags, flags_mask, seq_r) < 0) return -1; if (*seq_r != 0) return 0; rec = array_get(&tview->t->appends, &append_count); seq = tview->t->first_new_seq; message_count = tview->t->last_new_seq; i_assert(append_count == message_count - seq + 1); for (; seq <= message_count; seq++, rec++) { if ((rec->flags & flags_mask) == (uint8_t)flags) { *seq_r = seq; break; } } return 0; } static int _tview_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) { struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; const ARRAY_TYPE(seq_array) *ext_buf; const void *data; unsigned int idx; i_assert(ext_id < array_count(&view->index->extensions)); *map_r = view->index->map; if (array_is_created(&tview->t->ext_rec_updates) && ext_id < array_count(&tview->t->ext_rec_updates)) { /* there are some ext updates in transaction. see if there's any for this sequence. */ ext_buf = array_idx(&tview->t->ext_rec_updates, ext_id); if (array_is_created(ext_buf) && mail_index_seq_array_lookup(ext_buf, seq, &idx)) { data = array_idx(ext_buf, idx); *data_r = CONST_PTR_OFFSET(data, sizeof(uint32_t)); return 1; } } /* not updated, return the existing value */ if (seq < tview->t->first_new_seq) { return tview->super->lookup_ext_full(view, seq, ext_id, map_r, data_r); } *data_r = NULL; return 1; } static int _tview_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) { struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; /* FIXME: check updates */ return tview->super->get_header_ext(view, map, ext_id, data_r, data_size_r); } static struct mail_index_view_vfuncs trans_view_vfuncs = { _tview_close, _tview_get_message_count, _tview_get_header, _tview_lookup_full, _tview_lookup_uid, _tview_lookup_uid_range, _tview_lookup_first, _tview_lookup_ext_full, _tview_get_header_ext }; struct mail_index_view * mail_index_transaction_open_updated_view(struct mail_index_transaction *t) { struct mail_index_view_transaction *tview; if (t->view->syncing) { /* transaction view is being synced. while it's done, it's not possible to add new messages, but the view itself might change. so we can't make a copy of the view. */ mail_index_view_ref(t->view); return t->view; } tview = i_new(struct mail_index_view_transaction, 1); mail_index_view_clone(&tview->view, t->view); tview->view.v = trans_view_vfuncs; tview->super = &t->view->v; tview->t = t; mail_index_transaction_ref(t); return &tview->view; }