aboutsummaryrefslogtreecommitdiffstats
path: root/mail/message-thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/message-thread.c')
-rw-r--r--mail/message-thread.c368
1 files changed, 55 insertions, 313 deletions
diff --git a/mail/message-thread.c b/mail/message-thread.c
index 05cd4d43c4..4e976b4984 100644
--- a/mail/message-thread.c
+++ b/mail/message-thread.c
@@ -35,218 +35,12 @@
#include "mail-threads.h"
#define d(x)
-/*#define LEAKDEBUG*/
-
-/* **************************************** */
-/* mem leak debug stuff */
-
-#ifdef LEAKDEBUG
-
-static GHashTable *allocedht = NULL;
-
-#define EXISTS (1 << 0)
-#define WALKED (1 << 1)
-#define FREED (1 << 2)
-#define AL_401 (1 << 3)
-#define AL_541 (1 << 4)
-#define AL_546 (1 << 5)
-#define AL_569 (1 << 6)
-#define LINKED (1 << 7)
-#define EXCUSED (1 << 8)
-
-#define GITP(x) GINT_TO_POINTER(x)
-#define GPTI(x) GPOINTER_TO_INT(x)
-
-static struct _container *
-alloc_container (int where)
-{
- struct _container *c;
-
- c = g_new0 (struct _container, 1);
-
- if (!allocedht)
- allocedht = g_hash_table_new (g_direct_hash, g_direct_equal);
-
- g_hash_table_insert (allocedht, c, GITP(EXISTS|where));
- return c;
-}
-
-static void
-free_container (struct _container **c)
-{
- gpointer flags;
-
- memset ((*c), 0, sizeof (struct _container));
- if ((flags = g_hash_table_lookup (allocedht, (*c))) == NULL)
- printf ("** threading mem debug: freeing unalloced entry %p?\n", (*c));
- d(printf("** Freeing container %p\n", (*c)));
- g_hash_table_insert (allocedht, (*c), GITP(GPTI(flags)|FREED));
- g_free ((*c));
- (*c) = NULL;
-}
-
-static void
-cont_print (gpointer key, gpointer value, gpointer user)
-{
- struct _container *c = (struct _container *) key;
- char *line;
-
- if (GPTI(value) & FREED)
- return;
-
- if (GPTI(value) & AL_401)
- line = "401";
- else if (GPTI(value) & AL_541)
- line = "541";
- else if (GPTI(value) & AL_546)
- line = "546";
- else if (GPTI(value) & AL_569)
- line = "569";
- else
- line = "???";
-
- printf (" %p : %s %s %s %s %s",
- c,
- GPTI(value) & FREED ? "freed" : "unfrd",
- GPTI(value) & WALKED ? "walked" : "unwlkd",
- line,
- GPTI(value) & LINKED ? "linked" : "unlnkd",
- GPTI(value) & EXCUSED ? "excused" : "unexcsd");
-
- if ((GPTI(value) & FREED) == 0) {
- gpointer oth_flags;
-
- printf (" : %p %p %p : \"%s\" \"%s\" %d %d",
- c->next, c->parent, c->child,
- c->message ? c->message->subject : "(null message)",
- c->root_subject ? c->root_subject : "(null root-subject)",
- c->re, c->order);
-
- if (c->next) {
- oth_flags = g_hash_table_lookup (allocedht, c->next);
-
- printf ("\n next : %p : %s %s %s",
- c->next,
- GPTI(oth_flags) & WALKED ? "walked" : "unwlkd",
- GPTI(oth_flags) & LINKED ? "linked" : "unlnkd",
- GPTI(oth_flags) & EXCUSED ? "excused" : "unexcsd");
- }
-
- if (c->parent) {
- oth_flags = g_hash_table_lookup (allocedht, c->parent);
-
- printf ("\n prnt : %p : %s %s %s",
- c->parent,
- GPTI(oth_flags) & WALKED ? "walked" : "unwlkd",
- GPTI(oth_flags) & LINKED ? "linked" : "unlnkd",
- GPTI(oth_flags) & EXCUSED ? "excused" : "unexcsd");
- }
-
- if (c->child) {
- oth_flags = g_hash_table_lookup (allocedht, c->child);
-
- printf ("\n chld : %p : %s %s %s",
- c->child,
- GPTI(oth_flags) & WALKED ? "walked" : "unwlkd",
- GPTI(oth_flags) & LINKED ? "linked" : "unlnkd",
- GPTI(oth_flags) & EXCUSED ? "excused" : "unexcsd");
- }
-
- }
-
- printf ("\n");
-
-}
-
-static void
-make_excuses (gpointer key, gpointer value, gpointer user)
-{
- struct _container *c;
- gpointer chldflags;
- gpointer nextflags;
-
- if (GPTI(value) & FREED)
- return;
-
- c = (struct _container *) key;
-
- if (c->next) {
- nextflags = g_hash_table_lookup (allocedht, c->next);
-
- if ((GPTI(nextflags) & EXCUSED) == 0) {
- g_hash_table_insert (allocedht, c->next, GITP(GPTI(nextflags)|EXCUSED));
- ((gint *)user) = 1;
- }
- }
-
- if (c->child) {
- chldflags = g_hash_table_lookup (allocedht, c->child);
-
- if ((GPTI(chldflags) & EXCUSED) == 0) {
- g_hash_table_insert (allocedht, c->child, GITP(GPTI(chldflags)|EXCUSED));
- ((gint *)user) = 1;
- }
- }
-}
-
-static void
-print_containers (void)
-{
- gint hit;
-
- do {
- hit = 0;
- g_hash_table_foreach (allocedht, make_excuses, &hit);
- } while (hit);
-
- printf ("List of container stats:\n");
- g_hash_table_foreach (allocedht, cont_print, NULL);
- printf ("End of list.\n");
-}
-
-static void
-walk_containers (struct _container *head)
-{
- gpointer flags;
-
- while (head) {
- if (head->child)
- walk_containers (head->child);
- if ((flags = g_hash_table_lookup (allocedht, head)) == NULL) {
- printf ("*** walk_containers : bad pointer %p\n", head);
- } else {
- g_hash_table_insert (allocedht, head, GITP(GPTI(flags)|WALKED));
- }
-
- head = head->next;
- }
-}
-
-static void
-link_container (struct _container *c)
-{
- gpointer flags;
-
- if ((flags = g_hash_table_lookup (allocedht, c)) == NULL)
- printf ("** threading mem debug: linking unalloced entry %p?\n", c);
- g_hash_table_insert (allocedht, c, GITP(GPTI(flags)|LINKED));
-}
-
-#else
-#define alloc_container(w) (g_new0 (struct _container, 1))
-#define free_container(c) g_free (*(c))
-#define print_containers()
-#define walk_containers(c)
-#define link_container(c)
-#endif
-
-/* **************************************** */
static struct _container *thread_messages(CamelFolder *folder, GPtrArray *uids);
static void thread_messages_free(struct _container *);
/* for debug only */
-int dump_tree(struct _container *c, int depth);
+int dump_tree(struct _container *c);
static void
container_add_child(struct _container *node, struct _container *child)
@@ -257,14 +51,18 @@ container_add_child(struct _container *node, struct _container *child)
child->parent = node;
}
-#if 0
static void
-container_unparent_child(struct _container *child)
+container_parent_child(struct _container *parent, struct _container *child)
{
struct _container *c, *node;
+ /* are we already the right parent? */
+ if (child->parent == parent)
+ return;
+
/* are we unparented? */
if (child->parent == NULL) {
+ container_add_child(parent, child);
return;
}
@@ -278,6 +76,7 @@ container_unparent_child(struct _container *child)
d(printf("found node %p\n", child));
c->next = c->next->next;
child->parent = NULL;
+ container_add_child(parent, child);
return;
}
c = c->next;
@@ -285,70 +84,6 @@ container_unparent_child(struct _container *child)
printf("DAMN, we shouldn't be here!\n");
}
-#endif
-
-static void
-container_parent_child(struct _container *parent, struct _container *child)
-{
- struct _container *c, *node, **prev;
-
- /* are we already the right parent? */
- if (child->parent == parent)
- return;
-
- /* are we unparented? */
- if (child->parent == NULL) {
- container_add_child(parent, child);
- return;
- }
-
- /* check for trying to make my child my parent */
- for (c = parent; c; c = c->parent) {
- if (c == child) {
- d(printf("AIIE: trying to lop off hunk of nodes!\n"));
- return;
- }
- }
-
- /* else remove child from its existing parent, and reparent */
- node = child->parent;
-
- /* c = (struct _container *)&node->child;
- *d(printf("scanning children:\n"));
- *while (c->next) {
- * d(printf(" %p\n", c));
- * if (c->next==child) {
- * d(printf("found node %p\n", child));
- * c->next = c->next->next;
- * child->parent = NULL;
- * container_add_child(parent, child);
- * return;
- * }
- * c = c->next;
- *}
- */
-
- d(printf("PKGW deparent child"));
- c = node->child;
- prev = &(node->child);
- while (c) {
- d(printf (" %p\n", c));
-
- if (c == child) {
- d(printf (" hit child %p\n", child));
- (*prev) = c->next;
- c->next = NULL;
- c->parent = NULL;
- container_add_child (parent, child);
- return;
- }
-
- prev = &(c->next);
- c = c->next;
- }
-
- printf("DAMN, we shouldn't be here!\n");
-}
static void
prune_empty(struct _container **cp)
@@ -366,7 +101,6 @@ prune_empty(struct _container **cp)
if (c->child == NULL) {
d(printf("removing empty node\n"));
lastc->next = c->next;
- free_container (&c);
continue;
}
if (c->parent || c->child->next==0) {
@@ -382,7 +116,6 @@ prune_empty(struct _container **cp)
child = next;
}
- free_container (&c);
continue;
}
}
@@ -400,7 +133,6 @@ hashloop(void *key, void *value, void *data)
if (c->parent == NULL) {
c->next = tail->next;
tail->next = c;
- link_container(c);
}
}
@@ -450,39 +182,32 @@ get_root_subject(struct _container *c, int *re)
return NULL;
}
-/* this is pretty slow, but not used often */
+/* this can be pretty slow, but not used often */
+/* clast cannot be null */
static void
remove_node(struct _container **list, struct _container *node, struct _container **clast)
{
struct _container *c;
/* this is intentional, even if it looks funny */
- c = (struct _container *)list;
+ /* if we have a parent, then we should remove it from the parent list,
+ otherwise we remove it from the root list */
+ if (node->parent) {
+ c = (struct _container *)&node->parent->child;
+ } else {
+ c = (struct _container *)list;
+ }
while (c->next) {
- /* we do this to catch cases where the container in the
- * subject table is not toplevel. */
- if (c->next->message == NULL) {
- /* yeah, this pointer casting trick is evil */
- c = (struct _container *) &(c->next->child);
- }
-
if (c->next == node) {
- if (clast && *clast == c->next)
+ if (*clast == c->next)
*clast = c;
c->next = c->next->next;
- break;
+ return;
}
-
- /* this could theoretically cause a problem when c = &(head)
- * and c->next->next == NULL, because then c->parent wouldn't be
- * valid. But that would only happen in a one-message mailbox,
- * in which case remove_node() wouldn't be called anyway.
- */
- if (c->next->next == NULL && c->parent)
- c = c->parent->next;
- else
- c = c->next;
+ c = c->next;
}
+
+ printf("ERROR: removing node %p failed\n", node);
}
static void
@@ -525,6 +250,7 @@ group_root_set(struct _container **cp)
scan = scan->next;
scan->next = c->child;
clast->next = c->next;
+ g_free(c);
continue;
} if (c->message == NULL && container->message != NULL) {
d(printf("container is non-empty parent\n"));
@@ -550,7 +276,7 @@ group_root_set(struct _container **cp)
remove_node(cp, container, &clast);
remove_node(cp, c, &clast);
- scan = alloc_container(AL_401);
+ scan = g_malloc0(sizeof(*scan));
scan->root_subject = c->root_subject;
scan->re = c->re && container->re;
scan->next = c->next;
@@ -567,8 +293,12 @@ group_root_set(struct _container **cp)
g_hash_table_destroy(subject_table);
}
-int
-dump_tree(struct _container *c, int depth)
+struct _tree_info {
+ GHashTable *visited;
+};
+
+static int
+dump_tree_rec(struct _tree_info *info, struct _container *c, int depth)
{
char *p;
int count=0;
@@ -578,6 +308,11 @@ dump_tree(struct _container *c, int depth)
p[depth*2] = 0;
while (c) {
+ if (g_hash_table_lookup(info->visited, c)) {
+ printf("WARNING: NODE REVISITED: %p\n", c);
+ } else {
+ g_hash_table_insert(info->visited, c, c);
+ }
if (c->message) {
printf("%s %p Subject: %s <%s>\n", p, c, c->message->subject, c->message->message_id);
count += 1;
@@ -585,24 +320,34 @@ dump_tree(struct _container *c, int depth)
printf("%s %p <empty>\n", p, c);
}
if (c->child)
- count += dump_tree(c->child, depth+1);
+ count += dump_tree_rec(info, c->child, depth+1);
c = c->next;
}
return count;
}
+int
+dump_tree(struct _container *c)
+{
+ char *p;
+ int count;
+ struct _tree_info info;
+
+ info.visited = g_hash_table_new(g_direct_hash, g_direct_equal);
+ count = dump_tree_rec(&info, c, 0);
+ g_hash_table_destroy(info.visited);
+ return count;
+}
+
static void thread_messages_free(struct _container *c)
{
struct _container *n;
- d(printf("** thread_messages_free: %p\n", c));
- /* FIXME: ok, for some reason this doesn't work .. investigate later ... */
-
while (c) {
n = c->next;
if (c->child)
thread_messages_free(c->child); /* free's children first */
- free_container (&c);
+ g_free(c);
c = n;
}
}
@@ -691,12 +436,12 @@ thread_messages(CamelFolder *folder, GPtrArray *uids)
d(printf("doing : %s\n", mi->message_id));
c = g_hash_table_lookup(id_table, mi->message_id);
if (!c) {
- c = alloc_container(AL_541);
+ c = g_malloc0(sizeof(*c));
g_hash_table_insert(id_table, mi->message_id, c);
}
} else {
d(printf("doing : (no message id)\n"));
- c = alloc_container(AL_546);
+ c = g_malloc0(sizeof(*c));
g_hash_table_insert(no_id_table, (void *)mi, c);
}
@@ -719,7 +464,7 @@ thread_messages(CamelFolder *folder, GPtrArray *uids)
c = g_hash_table_lookup(id_table, ref->id);
if (c == NULL) {
d(printf("not found\n"));
- c = alloc_container(AL_569);
+ c = g_malloc0(sizeof(*c));
g_hash_table_insert(id_table, ref->id, c);
}
if (c!=child)
@@ -748,7 +493,7 @@ thread_messages(CamelFolder *folder, GPtrArray *uids)
#if 0
printf("finished\n");
- i = dump_tree(head, 0);
+ i = dump_tree(head);
printf("%d count, %d items in tree\n", uids->len, i);
#endif
@@ -821,17 +566,14 @@ static void cleanup_thread_messages (gpointer in_data, gpointer op_data, CamelEx
thread_messages_data_t *data = (thread_messages_data_t *) op_data;
(input->build) (input->ml, data->container);
- walk_containers (data->container);
thread_messages_free (data->container);
- print_containers();
-
if (input->use_camel_uidfree) {
mail_tool_camel_lock_up ();
camel_folder_free_uids (input->ml->folder, input->uids);
mail_tool_camel_lock_down ();
} else {
- g_ptr_array_add (input->uids, NULL);
+ g_ptr_array_add(input->uids, 0);
g_strfreev ((char **)input->uids->pdata);
g_ptr_array_free (input->uids, FALSE);
}