index-thread-links.c revision e9b6a9a490faf429900dd5f003152186910b0815
/* 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 */
if (ref_index <= MAIL_INDEX_NODE_REF_MAX_VALUE) {
} else {
msgid);
}
}
/* keep message-ids cached */
return node;
}
{
struct mail_thread_node *node;
struct mail_thread_node unode;
if (!MAIL_INDEX_NODE_EXISTS(node)) {
/* 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;
}
{
/* 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 (MAIL_INDEX_NODE_EXISTS(child)) {
/* 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 */
}
}
}
struct thread_message_id {
const char *str;
unsigned int collisions_after;
};
static const char *
const char *references)
{
struct thread_message_id *ids;
struct thread_message_id id;
/* put all message IDs to an array */
}
if (count <= 1)
/* count collisions */
for (i = 0; i < count; i++) {
for (j = i + 1; j < count; j++) {
ids[i].collisions_after++;
}
}
ids[0].collisions_after;
for (i = 1; i < count; i++) {
ids[i].collisions_after;
}
/* link the last ID to us */
}
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;
}
{
struct mail_hash_header *hdr;
struct mail_thread_node *node;
unsigned int ref_index;
hdr->message_count++;
return -1;
if (parent_msgid != 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 mail_thread_node **node_r)
{
struct mail_thread_node *node;
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 */
}
return TRUE;
}
static bool
{
if (parent->parent_unref_rebuilds)
return FALSE;
if (child->parent_link_refcount == 0) {
"unexpected refcount=0");
return FALSE;
}
if (child->parent_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 TRUE;
return FALSE;
return FALSE;
}
}
{
struct mail_hash_header *hdr;
struct mail_thread_node *node;
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 &&
in_reply_to, idx)))
return 0;
}
/* get the node again, the pointer may have changed */
hdr->message_count--;
return 1;
}