index-thread-links.c revision 6ff05fc623dfad145a2bc65abc4536395ce5e561
/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "message-id.h"
#include "mail-storage.h"
#include "index-thread-private.h"
static struct mail_thread_node *
{
struct msgid_search_key key;
const char **msgidp;
/* not found, create */
/* make non-existing node uniquely identifiable */
"uid=0 found");
} else {
}
}
/* keep message-ids cached */
return node;
}
{
struct mail_thread_node *node;
struct mail_thread_node unode;
/* add UID to node */
} else {
/* duplicate, keep the original. if the original ever
gets expunged, rebuild. */
}
}
/* no valid message-id */
}
}
const struct mail_thread_node *node,
const struct mail_thread_node *ancestor)
{
if (node->parent_idx == 0)
return FALSE;
}
return TRUE;
}
{
child->link_refcount++;
/* loops to itself - ignore */
return;
}
/* child is an ancestor of parent. Adding child -> parent_node
would introduce a loop. If any messages referencing the path
between parent_node's parent and child_node get expunged, we
have to rebuild the tree because the loop might break.
For example:
#1: a -> b (a.ref=1, b.ref=1)
#2: b -> a (a.ref=2, b.ref=2)
#3: c -> a -> b (a.ref=3, b.ref=3, c.ref=1)
Expunging #3 wouldn't break the loop, but expunging #1
would. */
do {
if (idx == 0) {
/* earlier lookup_idx() failed */
break;
}
return;
/* The same link already exists */
return;
}
/* Set parent_node as child_node's parent */
if (child->parent_idx == 0)
else {
/* Conflicting parent already exists, keep the original */
/* If this message gets expunged,
the parent is changed. */
} else {
/* Message doesn't exist, so it was one of the node's
children that created the original reference. If
that reference gets dropped, the parent is changed.
We could catch this in one of several ways:
a) Link to parent node gets unreferenced
b) Link to this node gets unreferenced
c) Any of the child nodes gets expunged
b) is probably the least likely to happen,
so use it */
}
}
}
static void
const char **references)
{
const char *msgid, *last_msgid;
if (last_msgid == NULL)
return;
last_msgid = msgid;
}
/* link the last ID to us */
*references = last_msgid;
}
const char **value_r)
{
return -1;
/* Message is expunged. Instead of failing the entire THREAD
command, just treat the header as non-existing. */
}
return 0;
}
static bool references_are_crc32_unique(const char *references)
{
const char *msgid;
unsigned int i, count;
for (i = 0; i < count; i++) {
if (crc[i] == msgid_crc32)
return FALSE;
}
}
return TRUE;
}
{
struct mail_hash_header *hdr;
struct mail_thread_node *node;
hdr->message_count++;
return -1;
if (references != NULL)
else {
/* no valid IDs in References:, use In-Reply-To: instead */
&in_reply_to) < 0)
return -1;
}
if (old_parent != NULL &&
/* conflicting parent, remove it. */
node->parent_idx = 0;
/* If this message gets expunged, we have to revert back to
the original parent. */
}
return 0;
}
static bool
{
struct msgid_search_key key;
const char *msgids;
int ret;
return FALSE;
if (ret <= 0)
return FALSE;
return FALSE;
return FALSE;
/* duplicate Message-ID probably */
return FALSE;
}
return TRUE;
}
static bool
{
struct msgid_search_key key;
ctx->cmp_match_count = 0;
ctx->cmp_last_idx = 0;
/* couldn't find the message-id */
return FALSE;
}
/* there's only one key with this crc32 value, so it
must be what we're looking for */
}
if (parent->parent_unref_rebuilds)
return FALSE;
if (child->link_refcount == 0) {
"unexpected refcount=0");
return FALSE;
}
child->link_refcount--;
if (child->link_refcount == 0) {
/* we don't have a root anymore */
child->parent_idx = 0;
}
return TRUE;
}
static bool
const char *references, bool *valid_r)
{
const char *msgid;
/* tmp_mail may be changed below, so we have to duplicate the
references string */
return FALSE;
}
return TRUE;
}
{
struct mail_hash_header *hdr;
struct mail_thread_node *node;
const char *references, *in_reply_to;
bool have_refs;
return 0;
if (node->expunge_rebuilds)
return 0;
&references) < 0)
return -1;
return 0;
if (!have_refs) {
/* no valid IDs in References:, use In-Reply-To: instead */
&in_reply_to) < 0)
return -1;
if (in_reply_to != NULL) {
&parent_idx))
return 0;
}
}
/* get the node again, the pointer may have changed */
hdr->message_count--;
return 1;
}