mail-index-transaction-view.c revision 48a1d109563d54542797e317a1d9efab22c5b1a1
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "array.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "buffer.h"
9c6a09aa16095ff72837799a37e0e3b3e93bb3d8Timo Sirainen#include "seq-range-array.h"
31a9637b38d37451b649c86301b2c12e53a7810eTimo Sirainen#include "mail-index-private.h"
9c6a09aa16095ff72837799a37e0e3b3e93bb3d8Timo Sirainen#include "mail-index-view-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-index-transaction-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mail_index_view_transaction {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_index_view view;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen struct mail_index_view_vfuncs *super;
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen struct mail_index_transaction *t;
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen struct mail_index_map *lookup_map;
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen struct mail_index_header hdr;
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen buffer_t *lookup_return_data;
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen uint32_t lookup_prev_seq;
1f9d1bedae25d86f26c239055c5487499dfeeb58Timo Sirainen
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen unsigned int record_size;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen unsigned int recs_count;
f37ecd72aad9b806aae83f71bacafdce32146945Timo Sirainen void *recs;
f37ecd72aad9b806aae83f71bacafdce32146945Timo Sirainen};
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainenstatic void tview_close(struct mail_index_view *view)
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen{
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen struct mail_index_view_transaction *tview =
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen (struct mail_index_view_transaction *)view;
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen struct mail_index_transaction *t = tview->t;
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainen if (tview->lookup_map != NULL)
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainen mail_index_unmap(&tview->lookup_map);
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen if (tview->lookup_return_data != NULL)
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen buffer_free(&tview->lookup_return_data);
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen i_free(tview->recs);
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen
b63e20ea9bc84f1aa90a551f217d01385e070b73Timo Sirainen tview->super->close(view);
b63e20ea9bc84f1aa90a551f217d01385e070b73Timo Sirainen mail_index_transaction_unref(&t);
b63e20ea9bc84f1aa90a551f217d01385e070b73Timo Sirainen}
b63e20ea9bc84f1aa90a551f217d01385e070b73Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic uint32_t tview_get_message_count(struct mail_index_view *view)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi struct mail_index_view_transaction *tview =
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi (struct mail_index_view_transaction *)view;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return view->map->hdr.messages_count +
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi (tview->t->last_new_seq == 0 ? 0 :
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi tview->t->last_new_seq - tview->t->first_new_seq + 1);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi}
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistatic const struct mail_index_header *
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomitview_get_header(struct mail_index_view *view)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_view_transaction *tview =
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen (struct mail_index_view_transaction *)view;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct mail_index_header *hdr;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen uint32_t next_uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen /* FIXME: header counters may not be correct */
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen hdr = tview->super->get_header(view);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen next_uid = mail_index_transaction_get_next_uid(tview->t);
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen if (next_uid != hdr->next_uid) {
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch tview->hdr = *hdr;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch tview->hdr.next_uid = next_uid;
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch hdr = &tview->hdr;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen }
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch return hdr;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch}
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistatic const struct mail_index_record *
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomitview_apply_flag_updates(struct mail_index_view_transaction *tview,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi struct mail_index_map *map,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi const struct mail_index_record *rec, uint32_t seq)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi{
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi struct mail_index_transaction *t = tview->t;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen const struct mail_transaction_flag_update *updates;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen struct mail_index_record *trec;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen unsigned int idx, count;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen /* see if there are any flag updates */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq ||
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen !array_is_created(&t->updates))
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen return rec;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen updates = array_get(&t->updates, &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen idx = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (seq < updates[idx].uid1 || seq > updates[idx].uid2)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return rec;
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* yes, we have flag updates. since we can't modify rec directly and
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen we want to be able to handle multiple mail_index_lookup() calls
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen without the second one overriding the first one's data, we'll
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen create a records array and return data from there */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (tview->recs == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen tview->recs_count = t->first_new_seq;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen tview->record_size = I_MAX(map->hdr.record_size,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen tview->view.map->hdr.record_size);
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen tview->recs = i_malloc(tview->record_size *
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen tview->recs_count);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen }
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen i_assert(tview->recs_count == t->first_new_seq);
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen i_assert(seq > 0 && seq <= tview->recs_count);
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen i_assert(map->hdr.record_size <= tview->record_size);
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen trec = PTR_OFFSET(tview->recs, (seq-1) * tview->record_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen memcpy(trec, rec, map->hdr.record_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen trec->flags |= updates[idx].add_flags;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen trec->flags &= ~updates[idx].remove_flags;
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen return trec;
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen}
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainenstatic const struct mail_index_record *
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainentview_lookup_full(struct mail_index_view *view, uint32_t seq,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_index_map **map_r, bool *expunged_r)
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen{
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen struct mail_index_view_transaction *tview =
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen (struct mail_index_view_transaction *)view;
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen const struct mail_index_record *rec;
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen if (seq >= tview->t->first_new_seq) {
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen /* FIXME: is this right to return index map..?
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen it's not there yet. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *map_r = view->index->map;
719abeb2088987f213a33a7dd1fe78958beaef03Timo Sirainen *expunged_r = FALSE;
719abeb2088987f213a33a7dd1fe78958beaef03Timo Sirainen return mail_index_transaction_lookup(tview->t, seq);
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen }
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen rec = tview->super->lookup_full(view, seq, map_r, expunged_r);
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen rec = tview_apply_flag_updates(tview, *map_r, rec, seq);
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen if (mail_index_transaction_is_expunged(tview->t, seq))
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen *expunged_r = TRUE;
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen return rec;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenstatic void
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainentview_lookup_uid(struct mail_index_view *view, uint32_t seq, uint32_t *uid_r)
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen{
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen struct mail_index_view_transaction *tview =
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen (struct mail_index_view_transaction *)view;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (seq >= tview->t->first_new_seq)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen *uid_r = mail_index_transaction_lookup(tview->t, seq)->uid;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen else
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen tview->super->lookup_uid(view, seq, uid_r);
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen}
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainenstatic void tview_lookup_seq_range(struct mail_index_view *view,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen uint32_t first_uid, uint32_t last_uid,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen uint32_t *first_seq_r, uint32_t *last_seq_r)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen{
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen struct mail_index_view_transaction *tview =
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen (struct mail_index_view_transaction *)view;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen const struct mail_index_record *rec;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t seq;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!tview->t->reset) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen tview->super->lookup_seq_range(view, first_uid, last_uid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen first_seq_r, last_seq_r);
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen } else {
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen /* index is being reset. we never want to return old
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen sequences. */
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen *first_seq_r = *last_seq_r = 0;
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen }
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen if (tview->t->last_new_seq == 0) {
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen /* no new messages, the results are final. */
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen return;
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rec = mail_index_transaction_lookup(tview->t, tview->t->first_new_seq);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (rec->uid == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* new messages don't have UIDs */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (last_uid < rec->uid) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* all wanted messages were existing */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen /* at least some of the wanted messages are newly created */
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen if (*first_seq_r == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen seq = tview->t->first_new_seq;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (; seq <= tview->t->last_new_seq; seq++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen rec = mail_index_transaction_lookup(tview->t, seq);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (first_uid <= rec->uid)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen if (seq > tview->t->last_new_seq) {
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen /* no messages in range */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *first_seq_r = seq;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen seq = tview->t->last_new_seq;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (; seq >= tview->t->first_new_seq; seq--) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen rec = mail_index_transaction_lookup(tview->t, seq);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (rec->uid <= last_uid) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen *last_seq_r = seq;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen break;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen }
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen }
03baa1c4c51f7b08fb285e82b528fcb00ac09ebfTimo Sirainen i_assert(seq >= tview->t->first_new_seq);
03baa1c4c51f7b08fb285e82b528fcb00ac09ebfTimo Sirainen}
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void tview_lookup_first(struct mail_index_view *view,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen enum mail_flags flags, uint8_t flags_mask,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen uint32_t *seq_r)
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen{
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen struct mail_index_view_transaction *tview =
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen (struct mail_index_view_transaction *)view;
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen const struct mail_index_record *rec;
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen unsigned int append_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t seq, message_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!tview->t->reset) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen tview->super->lookup_first(view, flags, flags_mask, seq_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (*seq_r != 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen } else {
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen *seq_r = 0;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen }
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen rec = array_get(&tview->t->appends, &append_count);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen seq = tview->t->first_new_seq;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen message_count = tview->t->last_new_seq;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen i_assert(append_count == message_count - seq + 1);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen for (; seq <= message_count; seq++, rec++) {
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi if ((rec->flags & flags_mask) == (uint8_t)flags) {
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi *seq_r = seq;
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
}
}
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)
{
if (tview->lookup_map == NULL) {
tview->lookup_map =
mail_index_map_clone(tview->view.index->map);
}
return tview->lookup_map;
}
static const void *
tview_return_updated_ext(struct mail_index_view_transaction *tview,
uint32_t seq, const void *data, uint32_t ext_id)
{
const struct mail_index_ext *ext;
const struct mail_index_registered_ext *rext;
const struct mail_transaction_ext_intro *intro;
unsigned int record_align, record_size;
uint32_t ext_idx;
size_t pos;
/* data begins with a 32bit sequence, followed by the actual
extension data */
data = CONST_PTR_OFFSET(data, sizeof(uint32_t));
if (!mail_index_map_get_ext_idx(tview->lookup_map, ext_id, &ext_idx)) {
/* we're adding the extension now. */
rext = array_idx(&tview->view.index->extensions, ext_id);
record_align = rext->record_align;
record_size = rext->record_size;
} else {
ext = array_idx(&tview->lookup_map->extensions, ext_idx);
record_align = ext->record_align;
record_size = ext->record_size;
}
/* see if the extension has been resized within this transaction */
if (array_is_created(&tview->t->ext_resizes) &&
ext_id < array_count(&tview->t->ext_resizes)) {
intro = array_idx(&tview->t->ext_resizes, ext_id);
if (intro[ext_id].name_size != 0) {
record_align = intro->record_align;
record_size = intro->record_size;
}
}
if (record_align <= sizeof(uint32_t)) {
/* data is 32bit aligned already */
return data;
} else {
/* assume we want 64bit alignment - copy the data to
temporary buffer and return it */
if (tview->lookup_return_data == NULL) {
tview->lookup_return_data =
buffer_create_dynamic(default_pool,
record_size + 64);
} else if (seq != tview->lookup_prev_seq) {
/* clear the buffer between lookups for different
messages */
buffer_set_used_size(tview->lookup_return_data, 0);
}
tview->lookup_prev_seq = seq;
pos = tview->lookup_return_data->used;
buffer_append(tview->lookup_return_data, data, record_size);
return CONST_PTR_OFFSET(tview->lookup_return_data->data, pos);
}
}
static void
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, bool *expunged_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));
*expunged_r = FALSE;
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);
*map_r = tview_get_lookup_map(tview);
*data_r = tview_return_updated_ext(tview, seq, data,
ext_id);
return;
}
}
/* not updated, return the existing value */
if (seq < tview->t->first_new_seq) {
tview->super->lookup_ext_full(view, seq, ext_id,
map_r, data_r, expunged_r);
} else {
*map_r = view->index->map;
*data_r = NULL;
}
}
static void 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 */
tview->super->get_header_ext(view, map, ext_id, data_r, data_size_r);
}
static bool tview_ext_get_reset_id(struct mail_index_view *view,
struct mail_index_map *map,
uint32_t ext_id, uint32_t *reset_id_r)
{
struct mail_index_view_transaction *tview =
(struct mail_index_view_transaction *)view;
const uint32_t *reset_id_p;
if (array_is_created(&tview->t->ext_reset_ids) &&
ext_id < array_count(&tview->t->ext_reset_ids) &&
map == tview->lookup_map) {
reset_id_p = array_idx(&tview->t->ext_reset_ids, ext_id);
*reset_id_r = *reset_id_p;
return TRUE;
}
return tview->super->ext_get_reset_id(view, map, ext_id, reset_id_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_seq_range,
tview_lookup_first,
tview_lookup_keywords,
tview_lookup_ext_full,
tview_get_header_ext,
tview_ext_get_reset_id
};
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;
}