index-thread.c revision 5fa6399cfdf74f19851fb28bd654b944a62c0b0c
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen/* doc/thread-refs.txt describes the incremental algorithm we use here. */
87a6b7df39d6822a5a8289a62f32deabff9b75e4Timo Sirainen MODULE_CONTEXT(obj, mail_thread_storage_module)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen struct mail_index_strmap_view_sync *strmap_sync;
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainen /* sorted by UID, ref_index */
09801f106cd531a28b4e03ec665e44c421264560Timo Sirainen const ARRAY_TYPE(mail_index_strmap_rec) *msgid_map;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* set only temporarily while needed */
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmodystatic MODULE_CONTEXT_DEFINE_INIT(mail_thread_storage_module,
212a34c06ff45952c008ae9eec387ced783de6cfPhil Carmodystatic void mail_thread_clear(struct mail_thread_context *ctx);
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch const char **msgid_r)
a9a928e40e3b691924c8e5e444e3e1a4320aa3bdStephan Bosch unsigned int n = 0;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen /* Message-ID: header */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = mail_get_first_header(mail, HDR_MESSAGE_ID, &msgids);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen /* In-Reply-To: header */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen ret = mail_get_first_header(mail, HDR_IN_REPLY_TO, &msgids);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen /* References: header */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen ret = mail_get_first_header(mail, HDR_REFERENCES, &msgids);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen n = rec->ref_index - MAIL_THREAD_NODE_REF_REFERENCES1;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* treat it as if it didn't exist. trying to add it
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen again will result in failure. */
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen /* get the nth message-id */
46ce4d9273e6df12ef1912bbdb1c8b84b104f394Timo Sirainen /* shouldn't have happened */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen "Threading lost Message ID");
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen /* either a match or a collision, need to look closer */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen ret = mail_strmap_rec_get_msgid(ctx->tmp_mail, rec, &msgid);
0b6924ad1943fe5c6917fc49f675d8f316b0d939Timo Sirainenmail_thread_hash_rec_cmp(const struct mail_index_strmap_rec *rec1,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen ret = mail_strmap_rec_get_msgid(ctx->tmp_mail, rec1, &msgid1);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen ret = mail_strmap_rec_get_msgid(ctx->tmp_mail, rec2,
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenstatic void mail_thread_strmap_remap(const uint32_t *idx_map,
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen struct mail_thread_cache *cache = tbox->cache;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen unsigned int i, nodes_count, max, new_first_invalid, invalid_count;
6a170d6d781094bdc75f027b6456dde160fbde39Timo Sirainen /* strmap was reset, we'll need to rebuild thread */
6a170d6d781094bdc75f027b6456dde160fbde39Timo Sirainen mailbox_search_result_free(&cache->search_result);
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen invalid_count = cache->next_invalid_msgid_str_idx -
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen old_nodes = array_get(&cache->thread_nodes, &nodes_count);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen i_array_init(&new_nodes, new_count + invalid_count + 32);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* optimization: allocate all nodes initially */
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen (void)array_idx_modifiable(&new_nodes, new_count-1);
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen /* renumber existing valid nodes. all existing records in old_nodes
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen should also exist in idx_map since we've removed expunged messages
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen from the cache before committing the sync. */
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen for (i = 0; i < max; i++) {
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen /* expunged record. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen node = array_idx_modifiable(&new_nodes, idx_map[i]);
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody /* copy invalid nodes, if any. no other messages point to them,
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody so this is safe. we still need to update their parent_idx
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody pointers though. */
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody for (i = 0; i < invalid_count; i++) {
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody node = array_idx_modifiable(&new_nodes, new_first_invalid + i);
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody *node = old_nodes[cache->first_invalid_msgid_str_idx + i];
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody cache->first_invalid_msgid_str_idx = new_first_invalid;
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody cache->next_invalid_msgid_str_idx = new_first_invalid + invalid_count;
09142ea11662746ea07475b1a4f69a6a406fb996Phil Carmody /* replace the old nodes with the renumbered ones */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int thread_get_mail_header(struct mail *mail, const char *name,
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen const char **value_r)
282a436a74d8835edb45cc019b1c916013013fd3Timo Sirainen if (mail_get_first_header(mail, name, value_r) < 0) {
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen /* Message is expunged. Instead of failing the entire THREAD
4c096615cb86a826fda377b87df22c579bfe5525Timo Sirainen command, just treat the header as nonexistent. */
msgid);
ref_index++;
&in_reply_to) < 0)
msgid);
static const char *wanted_headers[] = {
int ret = 0;
&last_uid);
if (seq1 == 0) {
if (ret < 0)
return ret;
return FALSE;
for (i = j = 0; i < uid_count; i++) {
j += idx;
if (j == map_count) {
if (j == map_count) {
return FALSE;
return TRUE;
if (uid_count == 0)
msgid_map_cmp, &j);
for (i = 0; i < uid_count; i++) {
if (count == 0) {
unsigned int i, count;
int ret;
if (ret == 0)
if (ret < 0) {
struct mail_thread_iterate_context *