mail-index-sync-keywords.c revision 6825360d446542046757b06064282301c4c6b27c
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "buffer.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "mail-index-view-private.h"
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen#include "mail-index-sync-private.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#include "mail-transaction-log.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenkeyword_lookup(struct mail_index_sync_map_ctx *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *keyword_name, unsigned int *idx_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_map *map = ctx->view->map;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const unsigned int *idx_map;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i, count, keyword_idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!map->keywords_read) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_map_parse_keywords(map) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (array_is_created(&map->keyword_idx_map) &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_keyword_lookup(ctx->view->index, keyword_name,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &keyword_idx)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* FIXME: slow. maybe create index -> file mapping as well */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen idx_map = array_get(&map->keyword_idx_map, &count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (idx_map[i] == keyword_idx) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *idx_r = i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen *idx_r = (unsigned int)-1;
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen return 0;
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic buffer_t *
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenkeywords_get_header_buf(struct mail_index_map *map,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const struct mail_index_ext *ext,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen unsigned int new_count, unsigned int *keywords_count_r,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen size_t *rec_offset_r, size_t *name_offset_root_r,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen size_t *name_offset_r)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t *buf;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_keyword_header *kw_hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen const char *name;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_keyword_header new_kw_hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kw_rec = (const void *)(kw_hdr + 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (kw_hdr->keywords_count == 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_assert((size_t)(name - (const char *)kw_hdr) < ext->hdr_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_kw_hdr = *kw_hdr;
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen new_kw_hdr.keywords_count += new_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *keywords_count_r = new_kw_hdr.keywords_count;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen offset = kw_rec[kw_hdr->keywords_count-1].name_offset;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen offset += strlen(name + offset) + 1;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 512);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(buf, &new_kw_hdr, sizeof(new_kw_hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(buf, kw_rec, sizeof(*kw_rec) * kw_hdr->keywords_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *rec_offset_r = buf->used;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_write(buf, buf->used + sizeof(*kw_rec) * new_count,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen name, offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *name_offset_root_r = buf->used;
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen *name_offset_r = offset;
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen return buf;
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen}
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainenstatic int keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen uint32_t ext_id, uint32_t reset_id,
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen uint32_t hdr_size, uint32_t keywords_count)
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen{
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen buffer_t *ext_intro_buf;
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen struct mail_transaction_ext_intro *u;
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen ext_intro_buf =
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen buffer_create_static_hard(pool_datastack_create(),
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen sizeof(*u) + sizeof("keywords")-1);
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen u = buffer_append_space_unsafe(ext_intro_buf, sizeof(*u));
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen u->ext_id = ext_id;
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen u->reset_id = reset_id;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen u->hdr_size = hdr_size;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen if ((u->record_size % 4) != 0) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen /* since we aren't properly aligned anyway,
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen reserve one extra byte for future */
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen u->record_size++;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen }
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen u->record_align = 1;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (ext_id == (uint32_t)-1) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen u->name_size = strlen("keywords");
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen buffer_append(ext_intro_buf, "keywords", u->name_size);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen }
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen return mail_index_sync_ext_intro(ctx, u);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen}
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainenstatic int
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainenkeywords_header_add(struct mail_index_sync_map_ctx *ctx,
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen const char *keyword_name, unsigned int *keyword_idx_r)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen{
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen struct mail_index_map *map = ctx->view->map;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen const struct mail_index_ext *ext = NULL;
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen struct mail_index_keyword_header *kw_hdr;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen struct mail_index_keyword_header_rec kw_rec;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen uint32_t ext_id;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen buffer_t *buf = NULL;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen size_t keyword_len, rec_offset, name_offset, name_offset_root;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen unsigned int keywords_count;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen int ret;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen /* if we crash in the middle of writing the header, the
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen keywords are more or less corrupted. avoid that by
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen making sure the header is updated atomically. */
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen map = mail_index_sync_get_atomic_map(ctx);
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen ext_id = mail_index_map_lookup_ext(map, "keywords");
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (ext_id != (uint32_t)-1) {
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen /* update existing header */
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen ext = array_idx(&map->extensions, ext_id);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen buf = keywords_get_header_buf(map, ext, 1, &keywords_count,
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen &rec_offset, &name_offset_root,
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen &name_offset);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen }
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (buf == NULL) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen /* create new / replace broken header */
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 512);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen kw_hdr = buffer_append_space_unsafe(buf, sizeof(*kw_hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kw_hdr->keywords_count = 1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen keywords_count = kw_hdr->keywords_count;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen rec_offset = buf->used;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen name_offset_root = rec_offset +
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen kw_hdr->keywords_count * sizeof(kw_rec);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen name_offset = 0;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* add the keyword */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(&kw_rec, 0, sizeof(kw_rec));
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen kw_rec.name_offset = name_offset;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen keyword_len = strlen(keyword_name) + 1;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen buffer_write(buf, name_offset_root, keyword_name, keyword_len);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen rec_offset += sizeof(kw_rec);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen kw_rec.name_offset += keyword_len;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen name_offset_root += keyword_len;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((buf->used % 4) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append_zero(buf, 4 - (buf->used % 4));
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ext == NULL || buf->used > ext->hdr_size ||
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen (uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* if we need to grow the buffer, add some padding */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append_zero(buf, 128);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ret = keywords_ext_register(ctx, ext_id,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen ext == NULL ? 0 : ext->reset_id,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen buf->used, keywords_count);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (ret <= 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return ret;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* map may have changed */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen map = ctx->view->map;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen if (ext == NULL) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen ext_id = mail_index_map_lookup_ext(map, "keywords");
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen i_assert(ext_id != (uint32_t)-1);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ext = array_idx(&map->extensions, ext_id);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen i_assert(ext->hdr_size == buf->used);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_copy(map->hdr_copy_buf, ext->hdr_offset,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen buf, 0, buf->used);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *keyword_idx_r = keywords_count - 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen map->keywords_read = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenkeywords_update_records(struct mail_index_sync_map_ctx *ctx,
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen const struct mail_index_ext *ext,
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen unsigned int keyword_idx, enum modify_type type,
85ebd164b748fbd808fcfc17c8fd2af4cd9289d5Timo Sirainen uint32_t uid1, uint32_t uid2)
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen{
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_view *view = ctx->view;
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen struct mail_index_record *rec;
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen unsigned char *data, data_mask;
85ebd164b748fbd808fcfc17c8fd2af4cd9289d5Timo Sirainen unsigned int data_offset;
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen uint32_t seq1, seq2;
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen i_assert(keyword_idx != (unsigned int)-1);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
c4877db8b6559846f4b58be8e42422dc734c193fTimo Sirainen mail_index_lookup_uid_range(view, uid1, uid2, &seq1, &seq2);
85ebd164b748fbd808fcfc17c8fd2af4cd9289d5Timo Sirainen if (seq1 == 0)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen mail_index_sync_write_seq_update(ctx, seq1, seq2);
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen data_offset = keyword_idx / CHAR_BIT;
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen data_mask = 1 << (keyword_idx % CHAR_BIT);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(data_offset < ext->record_size);
37e6cf44d61a81c6839e3ab76234b54309d8d292Timo Sirainen data_offset += ext->record_offset;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(data_offset >= sizeof(struct mail_index_record));
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (type) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen case MODIFY_ADD:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (seq1--; seq1 < seq2; seq1++) {
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = PTR_OFFSET(rec, data_offset);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen *data |= data_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen case MODIFY_REMOVE:
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen data_mask = ~data_mask;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen for (seq1--; seq1 < seq2; seq1++) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = PTR_OFFSET(rec, data_offset);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen *data &= data_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen default:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return 1;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen}
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenint mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen const struct mail_transaction_header *hdr,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_keyword_update *rec)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const char *keyword_name;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const struct mail_index_ext *ext;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const uint32_t *uid, *end;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen uint32_t seqset_offset, ext_id;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen unsigned int keyword_idx;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen int ret;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen if ((seqset_offset % 4) != 0)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen seqset_offset += 4 - (seqset_offset % 4);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen i_assert(seqset_offset < hdr->size);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen uid = CONST_PTR_OFFSET(rec, seqset_offset);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen end = CONST_PTR_OFFSET(rec, hdr->size);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen keyword_name = t_strndup(rec + 1, rec->name_size);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (*keyword_name == '\0') {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mail_index_sync_set_corrupted(ctx,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen "Trying to use empty keyword");
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen return -1;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen }
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen if (keyword_lookup(ctx, keyword_name, &keyword_idx) < 0)
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen return -1;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen if (keyword_idx == (unsigned int)-1) {
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen ret = keywords_header_add(ctx, keyword_name, &keyword_idx);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen if (ret <= 0)
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen return ret;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen }
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen ext_id = mail_index_map_lookup_ext(ctx->view->map, "keywords");
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ext = ext_id == (uint32_t)-1 ? NULL :
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen array_idx(&ctx->view->map->extensions, ext_id);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ext == NULL || ext->record_size == 0) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* nothing to do */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (rec->modify_type != MODIFY_REMOVE) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_sync_set_corrupted(ctx,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen "Keyword ext record missing for added keyword");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!ctx->view->map->keywords_read) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_map_parse_keywords(ctx->view->map) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen while (uid+2 <= end) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen ret = keywords_update_records(ctx, ext, keyword_idx,
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen rec->modify_type,
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen uid[0], uid[1]);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (ret <= 0)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uid += 2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_index_sync_keywords_reset(struct mail_index_sync_map_ctx *ctx,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const struct mail_transaction_header *hdr,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_keyword_reset *r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_map *map = ctx->view->map;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen struct mail_index_record *rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_ext *ext;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const struct mail_transaction_keyword_reset *end;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen uint32_t ext_id, seq1, seq2;
f519e4c2ad4ef826f1b08f3e0138b9b287a52c80Timo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen ext_id = mail_index_map_lookup_ext(map, "keywords");
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen if (ext_id == (uint32_t)-1) {
d565eaa943f29a49b97230ced57eec40ee65b4f9Timo Sirainen /* nothing to do */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen ext = array_idx(&map->extensions, ext_id);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end = CONST_PTR_OFFSET(r, hdr->size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (; r != end; r++) {
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen mail_index_lookup_uid_range(ctx->view, r->uid1, r->uid2,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &seq1, &seq2);
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen if (seq1 == 0)
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen continue;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen mail_index_sync_write_seq_update(ctx, seq1, seq2);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen for (seq1--; seq1 < seq2; seq1++) {
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen rec = MAIL_INDEX_MAP_IDX(map, seq1);
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen memset(PTR_OFFSET(rec, ext->record_offset),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen 0, ext->record_size);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen