mail-index-sync-keywords.c revision 7ded22760598b78ee29f9418eacc0abe3fb51055
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (C) 2004 Timo Sirainen */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "lib.h"
5ab2ee0b9b7ad3867fcfd2a31fda0790370fbbbdTimo Sirainen#include "array.h"
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen#include "buffer.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "mail-index-view-private.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "mail-index-sync-private.h"
0371406d952fe51367c7be91703e5634b7d9d225Timo Sirainen#include "mail-transaction-log.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
06b0c3be9905099038964b068216bbed155701deTimo Sirainenstatic int
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenkeyword_lookup(struct mail_index_sync_map_ctx *ctx,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const char *keyword_name, unsigned int *idx_r)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mail_index_map *map = ctx->view->map;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const unsigned int *idx_map;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int i, count, keyword_idx;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!map->keywords_read) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (mail_index_map_parse_keywords(map) < 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (array_is_created(&map->keyword_idx_map) &&
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen mail_index_keyword_lookup(ctx->view->index, keyword_name,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen &keyword_idx)) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* FIXME: slow. maybe create index -> file mapping as well */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen idx_map = array_get(&map->keyword_idx_map, &count);
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen for (i = 0; i < count; i++) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (idx_map[i] == keyword_idx) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen *idx_r = i;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
b3f46fa8a890527996fd0288cf964b7f3567cd22Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen *idx_r = (unsigned int)-1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return 0;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainenstatic buffer_t *
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenkeywords_get_header_buf(struct mail_index_map *map,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const struct mail_index_ext *ext,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen unsigned int new_count, unsigned int *keywords_count_r,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen size_t *rec_offset_r, size_t *name_offset_root_r,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen size_t *name_offset_r)
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen{
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen buffer_t *buf;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen const struct mail_index_keyword_header *kw_hdr;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen const struct mail_index_keyword_header_rec *kw_rec;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen const char *name;
7d075009a641d88a45940238676883a8eaf1507bTimo Sirainen struct mail_index_keyword_header new_kw_hdr;
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen uint32_t offset;
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen
0db5b158a00c08955bdacc99b1e2cd1ec07f4311Timo Sirainen kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen kw_rec = (const void *)(kw_hdr + 1);
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen name = (const char *)(kw_rec + kw_hdr->keywords_count);
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen if (kw_hdr->keywords_count == 0)
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen return NULL;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert((size_t)(name - (const char *)kw_hdr) < ext->hdr_size);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen new_kw_hdr = *kw_hdr;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen new_kw_hdr.keywords_count += new_count;
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen *keywords_count_r = new_kw_hdr.keywords_count;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen offset = kw_rec[kw_hdr->keywords_count-1].name_offset;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen offset += strlen(name + offset) + 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
b57cd9928909b51fa473c3eea81442e296006438Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 512);
b57cd9928909b51fa473c3eea81442e296006438Timo Sirainen buffer_append(buf, &new_kw_hdr, sizeof(new_kw_hdr));
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen buffer_append(buf, kw_rec, sizeof(*kw_rec) * kw_hdr->keywords_count);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *rec_offset_r = buf->used;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buffer_write(buf, buf->used + sizeof(*kw_rec) * new_count,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name, offset);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen *name_offset_root_r = buf->used;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *name_offset_r = offset;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen return buf;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen}
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic int keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen uint32_t ext_map_idx, uint32_t reset_id,
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen uint32_t hdr_size, uint32_t keywords_count)
c87d1e148ae76cf20f3adc7fc84fd54219dc62d5Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen buffer_t *ext_intro_buf;
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen struct mail_transaction_ext_intro *u;
c87d1e148ae76cf20f3adc7fc84fd54219dc62d5Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ext_intro_buf =
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen buffer_create_static_hard(pool_datastack_create(),
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sizeof(*u) + sizeof("keywords")-1);
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen u = buffer_append_space_unsafe(ext_intro_buf, sizeof(*u));
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen u->ext_id = ext_map_idx;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen u->reset_id = reset_id;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen u->hdr_size = hdr_size;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen if ((u->record_size % 4) != 0) {
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen /* since we aren't properly aligned anyway,
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen reserve one extra byte for future */
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen u->record_size++;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen u->record_align = 1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen if (ext_map_idx == (uint32_t)-1) {
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen u->name_size = strlen("keywords");
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen buffer_append(ext_intro_buf, "keywords", u->name_size);
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
06b0c3be9905099038964b068216bbed155701deTimo Sirainen return mail_index_sync_ext_intro(ctx, u);
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen}
06b0c3be9905099038964b068216bbed155701deTimo Sirainen
06b0c3be9905099038964b068216bbed155701deTimo Sirainenstatic int
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenkeywords_header_add(struct mail_index_sync_map_ctx *ctx,
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen const char *keyword_name, unsigned int *keyword_idx_r)
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen{
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen struct mail_index_map *map = ctx->view->map;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct mail_index_ext *ext = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct mail_index_keyword_header *kw_hdr;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mail_index_keyword_header_rec kw_rec;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen uint32_t ext_map_idx;
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen buffer_t *buf = NULL;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen size_t keyword_len, rec_offset, name_offset, name_offset_root;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int keywords_count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen int ret;
a0b89f3b1df99b3a32f44623f13ad1893118825bTimo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen /* if we crash in the middle of writing the header, the
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen keywords are more or less corrupted. avoid that by
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen making sure the header is updated atomically. */
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen map = mail_index_sync_get_atomic_map(ctx);
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen if (!mail_index_map_lookup_ext(map, "keywords", &ext_map_idx))
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ext_map_idx = (uint32_t)-1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen else {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* update existing header */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buf = keywords_get_header_buf(map, ext, 1, &keywords_count,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen &rec_offset, &name_offset_root,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen &name_offset);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (buf == NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* create new / replace broken header */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 512);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen kw_hdr = buffer_append_space_unsafe(buf, sizeof(*kw_hdr));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen kw_hdr->keywords_count = 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen keywords_count = kw_hdr->keywords_count;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen rec_offset = buf->used;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name_offset_root = rec_offset +
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen kw_hdr->keywords_count * sizeof(kw_rec);
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen name_offset = 0;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* add the keyword */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen memset(&kw_rec, 0, sizeof(kw_rec));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen kw_rec.name_offset = name_offset;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen keyword_len = strlen(keyword_name) + 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buffer_write(buf, name_offset_root, keyword_name, keyword_len);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen rec_offset += sizeof(kw_rec);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen kw_rec.name_offset += keyword_len;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen name_offset_root += keyword_len;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if ((buf->used % 4) != 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buffer_append_zero(buf, 4 - (buf->used % 4));
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (ext == NULL || buf->used > ext->hdr_size ||
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen (uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* if we need to grow the buffer, add some padding */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buffer_append_zero(buf, 128);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen ret = keywords_ext_register(ctx, ext_map_idx,
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen ext == NULL ? 0 : ext->reset_id,
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen buf->used, keywords_count);
57ca8cc86193103127066c724815e7e7a24926dbTimo Sirainen if (ret <= 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return ret;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* map may have changed */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map = ctx->view->map;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!mail_index_map_lookup_ext(map, "keywords", &ext_map_idx))
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen i_unreached();
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(ext->hdr_size == buf->used);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen buffer_copy(map->hdr_copy_buf, ext->hdr_offset,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen buf, 0, buf->used);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen *keyword_idx_r = keywords_count - 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen map->keywords_read = FALSE;
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen return 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
bc27fcd011f86208feaf73da9778a66ac7d7d3abTimo Sirainen
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainenstatic int
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainenkeywords_update_records(struct mail_index_sync_map_ctx *ctx,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen const struct mail_index_ext *ext,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int keyword_idx, enum modify_type type,
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen uint32_t uid1, uint32_t uid2)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen struct mail_index_view *view = ctx->view;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct mail_index_record *rec;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned char *data, data_mask;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen unsigned int data_offset;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen uint32_t seq1, seq2;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(keyword_idx != (unsigned int)-1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
4c9c55e15f35474f53f11659e796c63b1c34e884Timo Sirainen mail_index_lookup_uid_range(view, uid1, uid2, &seq1, &seq2);
9222c96ab9f42b25d5d5260f9e7a42c694715b0aTimo Sirainen if (seq1 == 0)
9222c96ab9f42b25d5d5260f9e7a42c694715b0aTimo Sirainen return 1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
3e28b527dd6048a40684afd29cff0ee008fc0014Timo Sirainen mail_index_sync_write_seq_update(ctx, seq1, seq2);
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen data_offset = keyword_idx / CHAR_BIT;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen data_mask = 1 << (keyword_idx % CHAR_BIT);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_assert(data_offset < ext->record_size);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen data_offset += ext->record_offset;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen i_assert(data_offset >= sizeof(struct mail_index_record));
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen switch (type) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen case MODIFY_ADD:
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (seq1--; seq1 < seq2; seq1++) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen data = PTR_OFFSET(rec, data_offset);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *data |= data_mask;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen }
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen break;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen case MODIFY_REMOVE:
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen data_mask = ~data_mask;
6bca3405636e3ec95724350c3a10d6fcb737782aTimo Sirainen for (seq1--; seq1 < seq2; seq1++) {
13a8c553f293349248b161ff851743498916e26eTimo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen data = PTR_OFFSET(rec, data_offset);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen *data &= data_mask;
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen }
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen break;
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen default:
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen i_unreached();
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return 1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
c95fc202215d2451372599db7092b16459f360a3Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenint mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct mail_transaction_header *hdr,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct mail_transaction_keyword_update *rec)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const char *keyword_name;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct mail_index_ext *ext;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const uint32_t *uid, *end;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen uint32_t seqset_offset, ext_map_idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int keyword_idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen int ret;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
c95fc202215d2451372599db7092b16459f360a3Timo Sirainen if ((seqset_offset % 4) != 0)
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen seqset_offset += 4 - (seqset_offset % 4);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen i_assert(seqset_offset < hdr->size);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen uid = CONST_PTR_OFFSET(rec, seqset_offset);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen end = CONST_PTR_OFFSET(rec, hdr->size);
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen
24ce0c343cefe54af841871fa39dbc3464028b06Timo Sirainen keyword_name = t_strndup(rec + 1, rec->name_size);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (*keyword_name == '\0') {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen mail_index_sync_set_corrupted(ctx,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen "Trying to use empty keyword");
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return -1;
3db8062598ce08e9320c84f77c267b9c70cb0809Timo Sirainen }
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen if (keyword_lookup(ctx, keyword_name, &keyword_idx) < 0)
5fbf8719b9ef072295c16bc4492f9f0ece92117dTimo Sirainen return -1;
3db8062598ce08e9320c84f77c267b9c70cb0809Timo Sirainen if (keyword_idx == (unsigned int)-1) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen ret = keywords_header_add(ctx, keyword_name, &keyword_idx);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (ret <= 0)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return ret;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (!mail_index_map_lookup_ext(ctx->view->map, "keywords",
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen &ext_map_idx))
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ext = NULL;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen else
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ext = array_idx(&ctx->view->map->extensions, ext_map_idx);
eeea0a402bcd9533e9e359f2a2518e3216162151Timo Sirainen if (ext == NULL || ext->record_size == 0) {
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen /* nothing to do */
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (rec->modify_type != MODIFY_REMOVE) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen mail_index_sync_set_corrupted(ctx,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen "Keyword ext record missing for added keyword");
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen if (!ctx->view->map->keywords_read) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (mail_index_map_parse_keywords(ctx->view->map) < 0)
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen return -1;
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen while (uid+2 <= end) {
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen ret = keywords_update_records(ctx, ext, keyword_idx,
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen rec->modify_type,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen uid[0], uid[1]);
f1ea65eb88b4f67e572c4640882bdf00fe3a2186Timo Sirainen if (ret <= 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return ret;
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen uid += 2;
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen }
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return 1;
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen}
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainen
4e9070b89501c0ce7ad6aaf4f5e49aba1ee56decTimo Sirainenint
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainenmail_index_sync_keywords_reset(struct mail_index_sync_map_ctx *ctx,
e8fd206cf9dca263278efba21864606126fc29b8Timo Sirainen const struct mail_transaction_header *hdr,
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen const struct mail_transaction_keyword_reset *r)
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen{
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen struct mail_index_map *map = ctx->view->map;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen struct mail_index_record *rec;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen const struct mail_index_ext *ext;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen const struct mail_transaction_keyword_reset *end;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen uint32_t ext_map_idx, seq1, seq2;
a5be5a0d074ed0f3e4106612a2792e143a43efc6Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (!mail_index_map_lookup_ext(map, "keywords", &ext_map_idx)) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen /* nothing to do */
a74e4a66db99a69cca71d7c5ac1feae46d92138fTimo Sirainen return 1;
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen }
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen ext = array_idx(&map->extensions, ext_map_idx);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen end = CONST_PTR_OFFSET(r, hdr->size);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen for (; r != end; r++) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen mail_index_lookup_uid_range(ctx->view, r->uid1, r->uid2,
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen &seq1, &seq2);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen if (seq1 == 0)
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen continue;
3656c91dcb8336814bebd4500e81c3dde25233e6Timo Sirainen
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen mail_index_sync_write_seq_update(ctx, seq1, seq2);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen for (seq1--; seq1 < seq2; seq1++) {
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen rec = MAIL_INDEX_MAP_IDX(map, seq1);
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen memset(PTR_OFFSET(rec, ext->record_offset),
dc9de21d4375faeedbe5b7e941502ac578650da9Timo Sirainen 0, ext->record_size);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen