bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen#include "lib.h"
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen#include "array.h"
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen#include "message-id.h"
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen#include "mail-storage.h"
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen#include "index-thread-private.h"
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic uint32_t thread_msg_add(struct mail_thread_cache *cache,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen uint32_t uid, uint32_t msgid_idx)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen struct mail_thread_node *node;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(msgid_idx != 0);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(msgid_idx < cache->first_invalid_msgid_str_idx);
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
139143f1b798472438b813343a48601f1c564060Sergey Kitov node = array_idx_get_space(&cache->thread_nodes, msgid_idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (node->uid == 0)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node->uid = uid;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen else {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* duplicate message-id, keep the original.
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if the original ever gets expunged, rebuild. */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node->expunge_rebuilds = TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen msgid_idx = cache->next_invalid_msgid_str_idx++;
139143f1b798472438b813343a48601f1c564060Sergey Kitov node = array_idx_get_space(&cache->thread_nodes, msgid_idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node->uid = uid;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return msgid_idx;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen}
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic bool thread_node_has_ancestor(struct mail_thread_cache *cache,
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen const struct mail_thread_node *node,
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen const struct mail_thread_node *ancestor)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen{
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen while (node != ancestor) {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen if (node->parent_idx == 0)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen return FALSE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node = array_idx(&cache->thread_nodes, node->parent_idx);
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen return TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen}
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic void thread_link_reference(struct mail_thread_cache *cache,
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen uint32_t parent_idx, uint32_t child_idx)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen{
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen struct mail_thread_node *node, *parent, *child;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen uint32_t idx;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(parent_idx < cache->first_invalid_msgid_str_idx);
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a68752dd4de71537a8f7d120aa299044727f125aTimo Sirainen /* either child_idx or parent_idx may cause thread_nodes array to
a68752dd4de71537a8f7d120aa299044727f125aTimo Sirainen grow. in such situation the other pointer may become invalid if
a68752dd4de71537a8f7d120aa299044727f125aTimo Sirainen we don't get the pointers in correct order. */
a68752dd4de71537a8f7d120aa299044727f125aTimo Sirainen if (child_idx < parent_idx) {
139143f1b798472438b813343a48601f1c564060Sergey Kitov parent = array_idx_get_space(&cache->thread_nodes, parent_idx);
a68752dd4de71537a8f7d120aa299044727f125aTimo Sirainen child = array_idx_modifiable(&cache->thread_nodes, child_idx);
a68752dd4de71537a8f7d120aa299044727f125aTimo Sirainen } else {
139143f1b798472438b813343a48601f1c564060Sergey Kitov child = array_idx_get_space(&cache->thread_nodes, child_idx);
a68752dd4de71537a8f7d120aa299044727f125aTimo Sirainen parent = array_idx_modifiable(&cache->thread_nodes, parent_idx);
a68752dd4de71537a8f7d120aa299044727f125aTimo Sirainen }
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen child->parent_link_refcount++;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (thread_node_has_ancestor(cache, parent, child)) {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen if (parent == child) {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* loops to itself - ignore */
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen return;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* child is an ancestor of parent. Adding child -> parent_node
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen would introduce a loop. If any messages referencing the path
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen between parent_node's parent and child_node get expunged, we
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen have to rebuild the tree because the loop might break.
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen For example:
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen #1: a -> b (a.ref=1, b.ref=1)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen #2: b -> a (a.ref=2, b.ref=2)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen #3: c -> a -> b (a.ref=3, b.ref=3, c.ref=1)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen Expunging #3 wouldn't break the loop, but expunging #1
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen would. */
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen node = parent;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen do {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen idx = node->parent_idx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(idx != 0);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node = array_idx_modifiable(&cache->thread_nodes, idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node->child_unref_rebuilds = TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen } while (node != child);
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen return;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen } else if (child->parent_idx == parent_idx) {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* The same link already exists */
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen return;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* Set parent_node as child_node's parent */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (child->parent_idx == 0) {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen child->parent_idx = parent_idx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen } else {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* Conflicting parent already exists, keep the original */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (MAIL_THREAD_NODE_EXISTS(child)) {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* If this message gets expunged,
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen the parent is changed. */
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen child->expunge_rebuilds = TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen } else {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* Message doesn't exist, so it was one of the node's
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen children that created the original reference. If
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen that reference gets dropped, the parent is changed.
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen We could catch this in one of several ways:
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen a) Link to parent node gets unreferenced
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen b) Link to this node gets unreferenced
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen c) Any of the child nodes gets expunged
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen b) is probably the least likely to happen,
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen so use it */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen child->child_unref_rebuilds = TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen}
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenstatic uint32_t
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenthread_link_references(struct mail_thread_cache *cache, uint32_t uid,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen const struct mail_index_strmap_rec *msgid_map,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unsigned int *msgid_map_idx)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen{
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen uint32_t parent_idx;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (msgid_map->uid != uid)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return 0;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen parent_idx = msgid_map->str_idx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen msgid_map++;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *msgid_map_idx += 1;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen for (; msgid_map->uid == uid; msgid_map++) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen thread_link_reference(cache, parent_idx, msgid_map->str_idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen parent_idx = msgid_map->str_idx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *msgid_map_idx += 1;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(parent_idx < cache->first_invalid_msgid_str_idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return parent_idx;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen}
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenvoid mail_thread_add(struct mail_thread_cache *cache,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen const struct mail_index_strmap_rec *msgid_map,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unsigned int *msgid_map_idx)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen{
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen struct mail_thread_node *node;
e9b6a9a490faf429900dd5f003152186910b0815Timo Sirainen uint32_t idx, parent_idx;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(msgid_map->ref_index == MAIL_THREAD_NODE_REF_MSGID);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(cache->last_uid <= msgid_map->uid);
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen cache->last_uid = msgid_map->uid;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen idx = thread_msg_add(cache, msgid_map->uid, msgid_map->str_idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen parent_idx = thread_link_references(cache, msgid_map->uid,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen msgid_map + 1, msgid_map_idx);
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node = array_idx_modifiable(&cache->thread_nodes, idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (node->parent_idx != parent_idx && node->parent_idx != 0) {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* conflicting parent, remove it. */
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen node->parent_idx = 0;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* If this message gets expunged, we have to revert back to
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen the original parent. */
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen node->expunge_rebuilds = TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (parent_idx != 0)
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen thread_link_reference(cache, parent_idx, idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *msgid_map_idx += 1;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen}
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainenstatic bool
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenmail_thread_unref_link(struct mail_thread_cache *cache,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen uint32_t parent_idx, uint32_t child_idx)
afb00cdb7ceb2ebe754d9c6b229c663a6de3b736Timo Sirainen{
afb00cdb7ceb2ebe754d9c6b229c663a6de3b736Timo Sirainen struct mail_thread_node *parent, *child;
afb00cdb7ceb2ebe754d9c6b229c663a6de3b736Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen parent = array_idx_modifiable(&cache->thread_nodes, parent_idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (parent->child_unref_rebuilds)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen return FALSE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen child = array_idx_modifiable(&cache->thread_nodes, child_idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(child->parent_link_refcount > 0);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
e9b6a9a490faf429900dd5f003152186910b0815Timo Sirainen child->parent_link_refcount--;
e9b6a9a490faf429900dd5f003152186910b0815Timo Sirainen if (child->parent_link_refcount == 0) {
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen /* we don't have a root anymore */
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen child->parent_idx = 0;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen return TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen}
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainenbool mail_thread_remove(struct mail_thread_cache *cache,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen const struct mail_index_strmap_rec *msgid_map,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unsigned int *msgid_map_idx)
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen{
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen struct mail_thread_node *node;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen uint32_t idx, parent_idx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen unsigned int count = 1;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen idx = msgid_map->str_idx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(idx != 0);
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (msgid_map->uid > cache->last_uid) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* this message was never added to the cache, skip */
838f57f389d5f4e97d9313ff86625bf1ee3517c6Timo Sirainen while (msgid_map[count].uid == msgid_map->uid)
838f57f389d5f4e97d9313ff86625bf1ee3517c6Timo Sirainen count++;
838f57f389d5f4e97d9313ff86625bf1ee3517c6Timo Sirainen *msgid_map_idx += count;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen }
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node = array_idx_modifiable(&cache->thread_nodes, idx);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (node->expunge_rebuilds) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* this catches the duplicate message-id case */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return FALSE;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen i_assert(node->uid == msgid_map->uid);
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* update link refcounts */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (msgid_map[count].uid == node->uid) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen parent_idx = msgid_map[count].str_idx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen count++;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen while (msgid_map[count].uid == node->uid) {
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!mail_thread_unref_link(cache, parent_idx,
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen msgid_map[count].str_idx))
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return FALSE;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen parent_idx = msgid_map[count].str_idx;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen count++;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen if (!mail_thread_unref_link(cache, parent_idx, idx))
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return FALSE;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen }
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* mark this message as expunged */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen node->uid = 0;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen /* we don't know (and don't want to waste time figuring out) if other
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen messages point to this removed message, so don't delete the node */
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen *msgid_map_idx += count;
a914bff43644dd9b3977244203839ca74161e40cTimo Sirainen return TRUE;
6ff05fc623dfad145a2bc65abc4536395ce5e561Timo Sirainen}