mail-index-transaction.c revision ae6c13635a316a0c6069a462d5a52f249089785a
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen/* Inside transaction we keep messages stored in sequences in uid fields.
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen Before they're written to transaction log the sequences are changed to
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen UIDs. This is because we're able to compress sequence ranges better. */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenmail_index_transaction_begin(struct mail_index_view *view,
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen /* don't allow syncing view while there's ongoing transactions */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen /* transaction view cannot work if new records are being added
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen in two places. make sure it doesn't happen. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void mail_keyword_transaction_free(struct mail_keyword_transaction *kt)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen for (p = &kt->keywords->kt; *p != NULL; p = &(*p)->next) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (*p == kt) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* no transactions left, free mail_keywords */
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenstatic void mail_index_transaction_free(struct mail_index_transaction *t)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen recs = buffer_get_modifyable_data(t->ext_rec_updates, &size);
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen for (i = 0; i < size; i++) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen kt = buffer_get_modifyable_data(t->keyword_updates, &size);
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen for (i = 0; i < size; i++)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenvoid mail_index_transaction_ref(struct mail_index_transaction *t)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid mail_index_transaction_unref(struct mail_index_transaction *t)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if (--t->refcount == 0)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenmail_index_buffer_convert_to_uids(struct mail_index_transaction *t,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen unsigned char *data;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* @UNSAFE */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen data = buffer_get_modifyable_data(buf, &size);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainenmail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen extensions = buffer_get_data(index->extensions, NULL);
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen updates = buffer_get_modifyable_data(t->ext_rec_updates, &size);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen for (i = 0; i < size; i++) {
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen mail_index_buffer_convert_to_uids(t, updates[i],
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen kt = buffer_get_modifyable_data(t->keyword_updates, &size);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen for (i = 0; i < size; i++) {
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen mail_index_buffer_convert_to_uids(t, kt[i]->messages,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen mail_index_buffer_convert_to_uids(t, t->expunges,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen sizeof(struct mail_transaction_expunge), TRUE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_buffer_convert_to_uids(t, t->updates,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sizeof(struct mail_transaction_flag_update), TRUE);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenint mail_index_transaction_commit(struct mail_index_transaction *t,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (mail_index_view_is_inconsistent(t->view)) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mail_cache_transaction_commit(t->cache_trans_ctx);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (mail_index_transaction_convert_to_uids(t) < 0)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen ret = mail_transaction_log_append(t, log_file_seq_r,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenvoid mail_index_transaction_rollback(struct mail_index_transaction *t)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen mail_cache_transaction_rollback(t->cache_trans_ctx);
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainenmail_index_transaction_lookup(struct mail_index_transaction *t, uint32_t seq)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(seq >= t->first_new_seq && seq <= t->last_new_seq);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen pos = (seq - t->first_new_seq) * sizeof(struct mail_index_record);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return buffer_get_space_unsafe(t->appends, pos,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen sizeof(struct mail_index_record));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_index_append(struct mail_index_transaction *t, uint32_t uid,
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen t->appends = buffer_create_dynamic(default_pool, 4096);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen /* sequence number is visible only inside given view,
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen so let it generate it */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen rec = buffer_append_space_unsafe(t->appends, sizeof(*rec));
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenvoid mail_index_append_assign_uids(struct mail_index_transaction *t,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen rec = buffer_get_modifyable_data(t->appends, &size);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* find the first mail with uid = 0 */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic void mail_index_update_seq_range_buffer(buffer_t *buffer, uint32_t seq)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen data = buffer_get_modifyable_data(buffer, &size);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen /* quick checks */
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen /* grow last range */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* grow down first range */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen buffer_insert(buffer, 0, &value, sizeof(value));
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* somewhere in the middle, array is sorted so find it with
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen binary search */
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen /* it's already expunged */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* idx == size couldn't happen because we already handle it above */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_assert(idx < size && data[idx].seq1 >= seq);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_assert(data[idx].seq1 > seq || data[idx].seq2 < seq);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_assert(idx+1 < size); /* already handled above */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenvoid mail_index_expunge(struct mail_index_transaction *t, uint32_t seq)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(t->view));
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen /* expunges is a sorted array of {seq1, seq2, ..}, .. */
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen t->expunges = buffer_create_dynamic(default_pool, 1024);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen buffer_append(t->expunges, &seq, sizeof(seq));
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen buffer_append(t->expunges, &seq, sizeof(seq));
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen mail_index_update_seq_range_buffer(t->expunges, seq);
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainenmail_index_insert_flag_update(struct mail_index_transaction *t,
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen struct mail_transaction_flag_update *updates, tmp_update;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen updates = buffer_get_modifyable_data(t->updates, &size);
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen i_assert(left_idx <= right_idx && right_idx <= size);
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen /* find the first update with either overlapping range,
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen or the update which will come after our insert */
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen /* overlapping ranges, split/merge them */
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen for (; idx < size && u.uid2 >= updates[idx].uid1; idx++) {
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen updates[idx].remove_flags != u.remove_flags)) {
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen /* split existing update from beginning */
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen i_assert(updates[idx].uid1 <= updates[idx].uid2);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen buffer_insert(t->updates, idx * sizeof(tmp_update),
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen updates = buffer_get_modifyable_data(t->updates, NULL);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen updates[idx].remove_flags != u.remove_flags)) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* split existing update from end */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen i_assert(updates[idx].uid1 <= updates[idx].uid2);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen buffer_insert(t->updates, idx * sizeof(tmp_update),
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen updates = buffer_get_modifyable_data(t->updates, NULL);
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen (updates[idx].remove_flags | u.remove_flags) &
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* break here before idx++ so last_update_idx is set
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen i_assert(idx == size || updates[idx].uid1 > u.uid2);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen buffer_insert(t->updates, idx * sizeof(u), &u, sizeof(u));
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenstatic void mail_index_record_modify_flags(struct mail_index_record *rec,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid mail_index_update_flags_range(struct mail_index_transaction *t,
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen struct mail_transaction_flag_update u, *last_update;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* updates for appended messages, modify them directly */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (seq = I_MAX(t->first_new_seq, seq1); seq <= seq2; seq++) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_record_modify_flags(rec, modify_type, flags);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* range contains also existing messages. update them next. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(seq2 <= mail_index_view_get_messages_count(t->view));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen memset(&u, 0, sizeof(u));
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen u.remove_flags = ~flags & MAIL_INDEX_FLAGS_MASK;
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen t->updates = buffer_create_dynamic(default_pool, 4096);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen last_update = buffer_get_modifyable_data(t->updates, &size);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen /* fast path - hopefully we're updating the next message,
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen or a message that is to be appended as last update */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen u.remove_flags == last_update->remove_flags &&
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen /* we can just update the UID range */
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen /* hopefully we can just append it */
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen /* slow path */
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen /* added after this */
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen mail_index_insert_flag_update(t, u, t->last_update_idx + 1,
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* added before this or on top of this */
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen mail_index_insert_flag_update(t, u, 0, t->last_update_idx);
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainenvoid mail_index_update_flags(struct mail_index_transaction *t, uint32_t seq,
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen mail_index_update_flags_range(t, seq, seq, modify_type, flags);
14175321ddb88619015866978c05a27786ca4814Timo Sirainenint mail_index_seq_buffer_lookup(buffer_t *buffer, uint32_t seq,
14175321ddb88619015866978c05a27786ca4814Timo Sirainen data = buffer_get_modifyable_data(buffer, &size);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen /* we're probably appending it, check */
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen else if (*((uint32_t *)PTR_OFFSET(data, size-full_record_size)) < seq)
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen idx = 0; left_idx = 0; right_idx = size / full_record_size;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen seq_p = PTR_OFFSET(data, idx * full_record_size);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainenstatic int mail_index_update_seq_buffer(buffer_t **buffer, uint32_t seq,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen *buffer = buffer_create_dynamic(default_pool, 1024);
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen if (mail_index_seq_buffer_lookup(*buffer, seq, record_size, &pos)) {
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen /* already there, update */
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen p = buffer_get_space_unsafe(*buffer, pos + sizeof(seq),
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen buffer_copy(*buffer, pos + sizeof(seq) + record_size,
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen buffer_write(*buffer, pos, &seq, sizeof(seq));
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen buffer_write(*buffer, pos + sizeof(seq), record, record_size);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid mail_index_update_header(struct mail_index_transaction *t,
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen i_assert(size <= sizeof(t->hdr_change) - offset);
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainenvoid mail_index_ext_resize(struct mail_index_transaction *t, uint32_t ext_id,
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen if (!mail_index_map_get_ext_idx(t->view->map, ext_id, &intro.ext_id)) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* allow only header size changes if something was already written */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen t->ext_resizes = buffer_create_dynamic(default_pool, 128);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen buffer_write(t->ext_resizes, ext_id * sizeof(intro),
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainenvoid mail_index_ext_reset(struct mail_index_transaction *t, uint32_t ext_id,
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen ext_id < t->ext_rec_updates->used / sizeof(buffer_t *)) {
032964c7cc6788188b63ae6270fc26cbd4a3ca26Timo Sirainen buffer_t *const *buf = t->ext_rec_updates->data;
66d84e6f0ae34a3cf5b8fa8e009d6caf025b6a2aTimo Sirainen t->ext_resets = buffer_create_dynamic(default_pool,
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen buffer_write(t->ext_resets, pos, &reset_id, sizeof(reset_id));
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainenvoid mail_index_update_header_ext(struct mail_index_transaction *t,
73b9c241e7fb6abdccda88e88fbd32e844dbc185Timo Sirainenvoid mail_index_update_ext(struct mail_index_transaction *t, uint32_t seq,
73b9c241e7fb6abdccda88e88fbd32e844dbc185Timo Sirainen uint32_t ext_id, const void *data, void *old_data_r)
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen const struct mail_transaction_ext_intro *intro;
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen (seq <= mail_index_view_get_messages_count(t->view) ||
12a3540693ab69ec622e04d1b3b66962b8b2a3d9Timo Sirainen i_assert(ext_id < index->extensions->used / sizeof(*ext));
5df8396a7cbad0b38b83a86667fb3d4c223f6f7cTimo Sirainen intro = buffer_get_data(t->ext_resizes, &size);
5df8396a7cbad0b38b83a86667fb3d4c223f6f7cTimo Sirainen if (ext_id < size / sizeof(*intro) && intro[ext_id].name_size != 0) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen /* resized record */
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen t->ext_rec_updates = buffer_create_dynamic(default_pool, 128);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen buf = buffer_get_space_unsafe(t->ext_rec_updates,
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* @UNSAFE */
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen if (!mail_index_update_seq_buffer(buf, seq, data, record_size,
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainenmail_keyword_transaction_new(struct mail_index_transaction *t,
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen t->keyword_updates = buffer_create_dynamic(default_pool, 512);
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen kt = i_new(struct mail_keyword_transaction, 1);
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen buffer_append(t->keyword_updates, &kt, sizeof(kt));
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainenmail_index_keywords_build(struct mail_index *index,
5f3151744f3ffa73b57391d4a237884b75423f57Timo Sirainen const char *const keywords[], unsigned int count)
01e606cda5192c4254c090624a0b2ca92da6da8eTimo Sirainen unsigned int i, j, bitmask_offset, missing_count = 0;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* @UNSAFE */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen missing_keywords = t_new(const char *, count + 1);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen memset(&k, 0, sizeof(k));
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen /* keywords are sorted in index. look up the existing ones and add
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen new ones. build a bitmap pointing to them. keywords are never
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen removed from index's keyword list. */
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen bitmask_offset = sizeof(k) - sizeof(k.bitmask);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen keyword_buf = buffer_create_dynamic(default_pool, bitmask_offset +
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen for (i = 0; i < count; i++) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen for (j = 0; index->keywords[j] != NULL; j++) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (strcasecmp(keywords[i], index->keywords[j]) == 0)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen /* first one */
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen } else if (j < k.start) {
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen /* arrays are sorted, can't match anymore */
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen missing_keywords[missing_count++] = keywords[i];
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen /* add missing keywords. first drop the trailing NULL. */
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen size = index->keywords_buf->used - sizeof(const char *);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen buffer_set_used_size(index->keywords_buf, size);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen j = size / sizeof(const char *);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen for (; *missing_keywords != NULL; missing_keywords++, j++) {
k.end = j;
k.count++;
t_pop();
struct mail_keywords *
const char *const keywords[])
struct mail_keywords *k;
(void)mail_keyword_transaction_new(t, k);