mail-index-sync-keywords.c revision faed8babca9914257f34fb2e603d74016d563b2d
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "buffer.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "mail-index-view-private.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#include "mail-index-sync-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo 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 unsigned int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!ctx->keywords_read) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_map_read_keywords(ctx->view->index, map) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->keywords_read = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < map->keywords_count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(map->keywords[i], keyword_name) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *idx_r = i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *idx_r = (unsigned int)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainenstatic buffer_t *
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainenkeywords_get_header_buf(struct mail_index_map *map,
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen const struct mail_index_ext *ext,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int new_count, unsigned int *keywords_count_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t *rec_offset_r, size_t *name_offset_root_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t *name_offset_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo 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;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *name;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_keyword_header new_kw_hdr;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo 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);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (kw_hdr->keywords_count == 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return NULL;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen new_kw_hdr = *kw_hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_kw_hdr.keywords_count += new_count;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen *keywords_count_r = new_kw_hdr.keywords_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen offset = kw_rec[kw_hdr->keywords_count-1].name_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen offset += strlen(name + offset) + 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo 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);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen *name_offset_root_r = buf->used;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *name_offset_r = offset;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return buf;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenstatic int keywords_ext_register(struct mail_index_sync_map_ctx *ctx,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen uint32_t ext_id, uint32_t reset_id,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen uint32_t hdr_size, uint32_t keywords_count)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t *ext_intro_buf;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen struct mail_transaction_ext_intro *u;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ext_intro_buf =
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen buffer_create_static_hard(pool_datastack_create(),
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen sizeof(*u) + sizeof("keywords")-1);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen u = buffer_append_space_unsafe(ext_intro_buf, sizeof(*u));
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen u->ext_id = ext_id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen u->reset_id = reset_id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen u->hdr_size = hdr_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen u->record_size = (keywords_count + CHAR_BIT - 1) / CHAR_BIT;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if ((u->record_size % 4) != 0) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* since we aren't properly aligned anyway,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen reserve one extra byte for future */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen u->record_size++;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen u->record_align = 1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (ext_id == (uint32_t)-1) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen u->name_size = strlen("keywords");
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen buffer_append(ext_intro_buf, "keywords", u->name_size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return mail_index_sync_ext_intro(ctx, u);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen}
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenstatic int
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenkeywords_header_add(struct mail_index_sync_map_ctx *ctx,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const char *keyword_name, unsigned int *keyword_idx_r)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen{
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen struct mail_index_map *map = ctx->view->map;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen const struct mail_index_ext *ext = NULL;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct mail_index_keyword_header *kw_hdr;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen struct mail_index_keyword_header_rec kw_rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t ext_id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t *buf = NULL;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen size_t keyword_len, rec_offset, name_offset, name_offset_root;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int keywords_count;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext_id = mail_index_map_lookup_ext(map, "keywords");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ext_id != (uint32_t)-1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* update existing header */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ext = map->extensions->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext += ext_id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen buf = keywords_get_header_buf(map, ext, 1, &keywords_count,
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen &rec_offset, &name_offset_root,
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen &name_offset);
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen }
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (buf == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* create new / replace broken header */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo 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;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen keywords_count = kw_hdr->keywords_count;
37e6cf44d61a81c6839e3ab76234b54309d8d292Timo Sirainen rec_offset = buf->used;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen name_offset_root = rec_offset +
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kw_hdr->keywords_count * sizeof(kw_rec);
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen name_offset = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* add the keyword */
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen memset(&kw_rec, 0, sizeof(kw_rec));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kw_rec.name_offset = name_offset;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen keyword_len = strlen(keyword_name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_write(buf, rec_offset, &kw_rec, sizeof(kw_rec));
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen buffer_write(buf, name_offset_root, keyword_name, keyword_len);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen rec_offset += sizeof(kw_rec);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen kw_rec.name_offset += keyword_len;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen name_offset_root += keyword_len;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((buf->used % 4) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append_zero(buf, 4 - (buf->used % 4));
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ext == NULL || buf->used > ext->hdr_size ||
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen (uint32_t)ext->record_size * CHAR_BIT < keywords_count) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* if we need to grow the buffer, add some padding */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen buffer_append_zero(buf, 128);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = keywords_ext_register(ctx, ext_id,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ext == NULL ? 0 : ext->reset_id,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen buf->used, keywords_count);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ret <= 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return ret;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* map may have changed */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen map = ctx->view->map;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (ext == NULL) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ext_id = mail_index_map_lookup_ext(map, "keywords");
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_assert(ext_id != (uint32_t)-1);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ext = map->extensions->data;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ext += ext_id;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_assert(ext->hdr_size == buf->used);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen buffer_copy(map->hdr_copy_buf, ext->hdr_offset,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen buf, 0, buf->used);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen map->hdr_base = map->hdr_copy_buf->data;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *keyword_idx_r = keywords_count - 1;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen ctx->keywords_read = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenkeywords_update_records(struct mail_index_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_ext *ext,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int keyword_idx,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen enum modify_type type,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen uint32_t uid1, uint32_t uid2)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen{
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen struct mail_index_record *rec;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen unsigned char *data, data_mask;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen unsigned int data_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq1, seq2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(keyword_idx != (unsigned int)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_lookup_uid_range(view, uid1, uid2, &seq1, &seq2) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (seq1 == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data_offset = keyword_idx / CHAR_BIT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data_mask = 1 << (keyword_idx % CHAR_BIT);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_assert(data_offset < ext->record_size);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen data_offset += ext->record_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen switch (type) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen case MODIFY_ADD:
d565eaa943f29a49b97230ced57eec40ee65b4f9Timo Sirainen for (seq1--; seq1 < seq2; seq1++) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data = PTR_OFFSET(rec, data_offset);
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen *data |= data_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen case MODIFY_REMOVE:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data_mask = ~data_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (seq1--; seq1 < seq2; seq1++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, seq1);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen data = PTR_OFFSET(rec, data_offset);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen *data &= data_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen default:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenint mail_index_sync_keywords(struct mail_index_sync_map_ctx *ctx,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const struct mail_transaction_header *hdr,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct mail_transaction_keyword_update *rec)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const char *keyword_name;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct mail_index_ext *ext;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const uint32_t *uid, *end;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seqset_offset, ext_id;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen unsigned int keyword_idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seqset_offset = sizeof(*rec) + rec->name_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((seqset_offset % 4) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seqset_offset += 4 - (seqset_offset % 4);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen if (seqset_offset > hdr->size) {
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen mail_transaction_log_view_set_corrupted(ctx->view->log_view,
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen "Keyword header ended unexpectedly");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return -1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uid = CONST_PTR_OFFSET(rec, seqset_offset);
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen end = CONST_PTR_OFFSET(rec, hdr->size);
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen if (uid == end) {
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen mail_transaction_log_view_set_corrupted(ctx->view->log_view,
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen "Keyword sequence list empty");
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen return -1;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen keyword_name = t_strndup(rec + 1, rec->name_size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (keyword_lookup(ctx, keyword_name, &keyword_idx) < 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return -1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (keyword_idx == (unsigned int)-1) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ret = keywords_header_add(ctx, keyword_name, &keyword_idx);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (ret <= 0)
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen return ret;
69bd816e46fdee6182d0cb2e4c6be32399a555c8Timo Sirainen }
69bd816e46fdee6182d0cb2e4c6be32399a555c8Timo Sirainen
69bd816e46fdee6182d0cb2e4c6be32399a555c8Timo Sirainen ext_id = mail_index_map_lookup_ext(ctx->view->map, "keywords");
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen if (ext_id == (uint32_t)-1) {
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen /* nothing to do */
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen i_assert(rec->modify_type == MODIFY_REMOVE);
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen return 1;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen }
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext = ctx->view->map->extensions->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext += ext_id;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen if (ext->record_size == 0) {
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen /* nothing to do */
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen i_assert(rec->modify_type == MODIFY_REMOVE);
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen return 1;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen }
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen if (!ctx->keywords_read) {
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen if (mail_index_map_read_keywords(ctx->view->index,
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen ctx->view->map) < 0)
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen return -1;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen ctx->keywords_read = TRUE;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen }
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen while (uid+2 <= end) {
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen if (uid[0] > uid[1] || uid[0] == 0) {
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen mail_transaction_log_view_set_corrupted(
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen ctx->view->log_view,
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen "Keyword record UIDs are broken");
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen return -1;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen }
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = keywords_update_records(ctx->view, ext, keyword_idx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec->modify_type,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen uid[0], uid[1]);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (ret <= 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return ret;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen uid += 2;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return 1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_index_sync_keywords_reset(struct mail_index_sync_map_ctx *ctx,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct mail_transaction_header *hdr,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct mail_transaction_keyword_reset *r)
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct mail_index_map *map = ctx->view->map;
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen struct mail_index_record *rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_ext *ext;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_transaction_keyword_reset *end;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t ext_id, seq1, seq2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen ext_id = mail_index_map_lookup_ext(map, "keywords");
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen if (ext_id == (uint32_t)-1) {
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen /* nothing to do */
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen return 1;
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen }
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen ext = map->extensions->data;
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen ext += ext_id;
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen end = CONST_PTR_OFFSET(r, hdr->size);
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen for (; r != end; r++) {
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen if (mail_index_lookup_uid_range(ctx->view, r->uid1, r->uid2,
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen &seq1, &seq2) < 0)
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen return -1;
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen if (seq1 == 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen for (seq1--; seq1 < seq2; seq1++) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen rec = MAIL_INDEX_MAP_IDX(map, seq1);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen memset(PTR_OFFSET(rec, ext->record_offset),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen 0, ext->record_size);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return 1;
ba482d3624ca4f1b3d638e6e8470ba5134f21493Timo Sirainen}
ba482d3624ca4f1b3d638e6e8470ba5134f21493Timo Sirainen