static bool keyword_lookup(struct mail_index_sync_map_ctx *ctx, const char *keyword_name, unsigned int *idx_r) { struct mail_index_map *map = ctx->view->map; const unsigned int *idx_map; unsigned int i, count, keyword_idx; if (array_is_created(&map->keyword_idx_map) && mail_index_keyword_lookup(ctx->view->index, keyword_name, &keyword_idx)) { /* FIXME: slow. maybe create index -> file mapping as well */ idx_map = array_get(&map->keyword_idx_map, &count); for (i = 0; i < count; i++) { if (idx_map[i] == keyword_idx) { *idx_r = i; return TRUE; } } } return FALSE; }
static bool parse_x_keywords_real(struct mbox_sync_mail_context *ctx, struct message_header_line *hdr) { struct mailbox *box = &ctx->sync_ctx->mbox->box; ARRAY_TYPE(keyword_indexes) keyword_list; const unsigned int *list; string_t *keyword; size_t keyword_start; unsigned int i, idx, count; size_t pos; if (array_is_created(&ctx->mail.keywords)) return FALSE; /* duplicate header, delete */ /* read keyword indexes to temporary array first */ keyword = t_str_new(128); t_array_init(&keyword_list, 16); for (pos = 0; pos < hdr->full_value_len; ) { if (IS_LWSP_LF(hdr->full_value[pos])) { pos++; continue; } /* read the keyword string */ keyword_start = pos; for (; pos < hdr->full_value_len; pos++) { if (IS_LWSP_LF(hdr->full_value[pos])) break; } str_truncate(keyword, 0); str_append_n(keyword, hdr->full_value + keyword_start, pos - keyword_start); if (!mail_index_keyword_lookup(box->index, str_c(keyword), &idx)) { /* keyword wasn't found. that means the sent mail originally contained X-Keywords header. Delete it. */ return FALSE; } /* check that the keyword isn't already added there. we don't want duplicates. */ list = array_get(&keyword_list, &count); for (i = 0; i < count; i++) { if (list[i] == idx) break; } if (i == count) array_append(&keyword_list, &idx, 1); } /* once we know how many keywords there are, we can allocate the array from mail_keyword_pool without wasting memory. */ if (array_count(&keyword_list) > 0) { p_array_init(&ctx->mail.keywords, ctx->sync_ctx->mail_keyword_pool, array_count(&keyword_list)); array_append_array(&ctx->mail.keywords, &keyword_list); } ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = str_len(ctx->header); parse_trailing_whitespace(ctx, hdr); return TRUE; }
int mail_index_map_parse_keywords(struct mail_index_map *map) { struct mail_index *index = map->index; const struct mail_index_ext *ext; const struct mail_index_keyword_header *kw_hdr; const struct mail_index_keyword_header_rec *kw_rec; const char *name; unsigned int i, name_area_end_offset, old_count; uint32_t idx; if (!mail_index_map_lookup_ext(map, MAIL_INDEX_EXT_KEYWORDS, &idx)) { if (array_is_created(&map->keyword_idx_map)) array_clear(&map->keyword_idx_map); return 0; } ext = array_idx(&map->extensions, idx); /* Extension header contains: - struct mail_index_keyword_header - struct mail_index_keyword_header_rec * keywords_count - const char names[] * keywords_count */ i_assert(ext->hdr_offset < map->hdr.header_size); kw_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset); kw_rec = (const void *)(kw_hdr + 1); name = (const char *)(kw_rec + kw_hdr->keywords_count); old_count = !array_is_created(&map->keyword_idx_map) ? 0 : array_count(&map->keyword_idx_map); /* Keywords can only be added into same mapping. Removing requires a new mapping (recreating the index file) */ if (kw_hdr->keywords_count == old_count) { /* nothing changed */ return 0; } /* make sure the header is valid */ if (kw_hdr->keywords_count < old_count) { mail_index_set_error(index, "Corrupted index file %s: " "Keywords removed unexpectedly", index->filepath); return -1; } if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) { mail_index_set_error(index, "Corrupted index file %s: " "keywords_count larger than header size", index->filepath); return -1; } name_area_end_offset = (const char *)kw_hdr + ext->hdr_size - name; for (i = 0; i < kw_hdr->keywords_count; i++) { if (kw_rec[i].name_offset > name_area_end_offset) { mail_index_set_error(index, "Corrupted index file %s: " "name_offset points outside allocated header", index->filepath); return -1; } } if (name[name_area_end_offset-1] != '\0') { mail_index_set_error(index, "Corrupted index file %s: " "Keyword header doesn't end with NUL", index->filepath); return -1; } /* create file -> index mapping */ if (!array_is_created(&map->keyword_idx_map)) i_array_init(&map->keyword_idx_map, kw_hdr->keywords_count); #ifdef DEBUG /* Check that existing headers are still the same. It's behind DEBUG since it's pretty useless waste of CPU normally. */ for (i = 0; i < array_count(&map->keyword_idx_map); i++) { const char *keyword = name + kw_rec[i].name_offset; const unsigned int *old_idx; unsigned int kw_idx; old_idx = array_idx(&map->keyword_idx_map, i); if (!mail_index_keyword_lookup(index, keyword, &kw_idx) || kw_idx != *old_idx) { mail_index_set_error(index, "Corrupted index file %s: " "Keywords changed unexpectedly", index->filepath); return -1; } } #endif /* Register the newly seen keywords */ i = array_count(&map->keyword_idx_map); for (; i < kw_hdr->keywords_count; i++) { const char *keyword = name + kw_rec[i].name_offset; unsigned int kw_idx; if (*keyword == '\0') { mail_index_set_error(index, "Corrupted index file %s: " "Empty keyword name in header", index->filepath); return -1; } mail_index_keyword_lookup_or_create(index, keyword, &kw_idx); array_append(&map->keyword_idx_map, &kw_idx, 1); } return 0; }