index-thread-finish.c revision a7386efde8d89b85aa6ee8b56a34a4ddf85e84be
/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "hash.h"
#include "imap-base-subject.h"
#include "mail-storage-private.h"
#include "index-thread-private.h"
#include <stdlib.h>
struct mail_thread_shadow_node {
};
struct mail_thread_root_node {
/* node.idx usually points to indexes from mail hash. However
REFERENCES step (5) may add temporary dummy roots. They use larger
index numbers than exist in the hash. */
struct mail_thread_child_node node;
/* Used temporarily by (5)(B) base subject gathering.
root_idx1 is node's index in roots[] array + 1.
parent_root_idx points to root_idx1, or 0 for root. */
unsigned int root_idx1;
/* subject contained a Re: or Fwd: */
unsigned int reply_or_forward:1;
/* a dummy node */
unsigned int dummy:1;
/* ignore this node - it's a dummy without children */
unsigned int ignore:1;
};
struct thread_finish_context {
unsigned int refcount;
struct mail_thread_cache *cache;
unsigned int next_new_root_idx;
unsigned int use_sent_date:1;
unsigned int return_seqs:1;
};
struct mail_thread_iterate_context {
struct thread_finish_context *ctx;
unsigned int next_idx;
bool failed;
};
struct subject_gather_context {
struct thread_finish_context *ctx;
struct hash_table *subject_hash;
};
static void
struct mail_thread_root_node *node)
{
struct mail_thread_root_node *hash_node;
char *hash_subject;
bool is_reply_or_forward;
/* (ii) If the thread subject is empty, skip this message. */
if (*subject == '\0')
return;
/* (iii) Look up the message associated with the thread
subject in the subject table. */
/* (iv) If there is no message in the subject table with the
thread subject, add the current message and the thread
subject to the subject table. */
} else {
hash_subject = key;
/* Otherwise, if the message in the subject table is not a
dummy, AND either of the following criteria are true:
The current message is a dummy, OR
The message in the subject table is a reply or forward
and the current message is not.
then replace the message in the subject table with the
current message. */
} else {
}
}
}
{
return -1;
return 1;
return -1;
return 1;
return 0;
}
static uint32_t
{
const struct mail_thread_node *node;
}
static void
struct mail_thread_child_node *child)
{
int tz;
/* the UID should have existed. we would have rebuild
the thread tree otherwise. */
i_unreached();
}
/* get sent date if we want to use it and if it's valid */
if (!ctx->use_sent_date)
/* fallback to received date */
}
}
static void
{
const struct mail_thread_shadow_node *shadows;
unsigned int count;
/* add all child indexes to the array */
/* only child - don't bother setting sort date */
return;
}
}
/* sort the children */
}
{
struct subject_gather_context gather_ctx;
struct mail_thread_root_node *roots;
const char *subject;
unsigned int i, count;
const struct mail_thread_child_node *children;
if (count == 0)
return;
for (i = 0; i < count; i++) {
/* find the oldest child */
} else {
/* dummy without children */
continue;
}
/* the UID should have existed. we would have rebuild
the thread tree otherwise. */
i_unreached();
}
} T_END;
}
}
{
}
struct mail_thread_root_node *cur)
{
struct mail_thread_shadow_node *shadows;
unsigned int count;
/* The highest parent is the same as the current message in the
subject table. */
do {
} while (root->parent_root_idx1 != 0);
/* If both messages are dummies, append the current
message's children to the children of the message in
the subject table (the children of both messages
become siblings), and then delete the current message. */
while (idx != 0) {
}
!root->reply_or_forward)) {
/* a) If the message in the subject table is a dummy and the
current message is not, make the current message a
child of the message in the subject table (a sibling
of its children).
b) If the current message is a reply or forward and the
message in the subject table is not, make the current
message a child of the message in the subject table (a
sibling of its children). */
} else {
/* Otherwise, create a new dummy message and make both
the current message and the message in the subject
table children of the dummy. Then replace the message
in the subject table with the dummy message. */
/* append last, since it breaks root and cur pointers */
/* make sure all shadow indexes are accessible directly */
}
}
{
struct mail_thread_root_node *roots;
unsigned int i, count;
for (i = 0; i < count; i++) {
/* more roots may have been added */
}
}
return changed;
}
{
const struct mail_thread_child_node *children;
const struct mail_thread_shadow_node *shadows;
struct mail_thread_root_node *roots;
unsigned int i, count, child_count;
for (i = 0; i < count; i++) {
continue;
/* sort by the first child */
/* childless dummy node */
continue;
}
if (child_count == 1) {
/* only one child - deferred step (3).
promote the child to the root. */
} else {
}
} else {
}
}
}
{
}
{
const struct mail_thread_node *node;
struct mail_thread_child_node child;
const struct mail_thread_shadow_node *shadows;
unsigned int root_count;
/* drop childless dummy nodes */
}
if (!MAIL_THREAD_NODE_EXISTS(node))
continue;
parent_idx = idx;
while (node->parent_idx != 0) {
node->parent_idx);
}
}
}
{
struct mail_thread_root_node root;
struct mail_thread_child_node child;
/* We may see dummy messages without parents or children. We can't
free them since the nodes are in an array, but they may get reused
later so just leave them be. With the current algorithm when this
happens all the struct fields are always zero at that point, so
we don't even have to try to zero them. */
if (node->parent_idx == 0) {
/* root node - add to roots list */
if (!MAIL_THREAD_NODE_EXISTS(node)) {
} else {
}
continue;
}
if (!MAIL_THREAD_NODE_EXISTS(node)) {
/* dummy node */
continue;
}
/* Find the node's first non-dummy parent and add the
node as its child. If there are no non-dummy
parents, add it as the highest dummy's child. */
while (!MAIL_THREAD_NODE_EXISTS(parent) &&
parent->parent_idx != 0) {
}
}
}
enum mail_thread_type thread_type)
{
/* (2) save root nodes and (3) remove dummy messages */
/* make sure all shadow indexes are accessible directly. */
/* (4) */
switch (thread_type) {
case MAIL_THREAD_REFERENCES:
/* (5) Gather together messages under the root that have
the same base subject text. */
/* (5.C) Merge threads with the same thread subject. */
if (merge_subject_threads(ctx)) {
/* root ordering may have changed, sort them again. */
}
break;
case MAIL_THREAD_REFS:
break;
default:
i_unreached();
}
}
static void
{
struct mail_thread_child_node *children;
unsigned int i, count;
for (i = 0; i < count; i++) {
if (uid == 0) {
/* dummy root */
if (root)
continue;
i_unreached();
} else {
}
}
}
static void
{
struct mail_thread_root_node *roots;
unsigned int i, count;
for (i = 0; i < count; i++) {
}
}
}
static struct mail_thread_iterate_context *
{
struct mail_thread_iterate_context *child_iter;
&child_iter->children);
return child_iter;
}
struct mail_thread_iterate_context *
enum mail_thread_type thread_type,
bool return_seqs)
{
struct mail_thread_iterate_context *iter;
struct thread_finish_context *ctx;
if (return_seqs)
return iter;
}
const struct mail_thread_child_node *
struct mail_thread_iterate_context **child_iter_r)
{
const struct mail_thread_shadow_node *shadow;
unsigned int count;
return NULL;
if (child_iter_r != NULL) {
}
return child;
}
{
}
{
}
return 0;
}