aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-folder-thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-folder-thread.c')
-rw-r--r--camel/camel-folder-thread.c159
1 files changed, 157 insertions, 2 deletions
diff --git a/camel/camel-folder-thread.c b/camel/camel-folder-thread.c
index 3a1c4addde..53d381bead 100644
--- a/camel/camel-folder-thread.c
+++ b/camel/camel-folder-thread.c
@@ -432,6 +432,8 @@ static gint id_equal(void *a, void *b)
* Thread a (subset) of the messages in a folder. And sort the result
* in summary order.
*
+ * This function is probably to be removed soon.
+ *
* Return value: A CamelFolderThread contianing a tree of CamelFolderThreadNode's
* which represent the threaded structure of the messages.
**/
@@ -591,6 +593,157 @@ camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids)
}
/**
+ * camel_folder_thread_messages_new_summary:
+ * @summary: Array of CamelMessageInfo's to thread.
+ *
+ * Thread a list of MessageInfo's. The summary must remain valid for the
+ * life of the CamelFolderThread created by this function, and it is upto the
+ * caller to ensure this.
+ *
+ * Return value: A CamelFolderThread contianing a tree of CamelFolderThreadNode's
+ * which represent the threaded structure of the messages.
+ **/
+CamelFolderThread *
+camel_folder_thread_messages_new_summary(GPtrArray *summary)
+{
+ GHashTable *id_table, *no_id_table;
+ int i;
+ CamelFolderThreadNode *c, *child, *head;
+ CamelFolderThread *thread;
+
+#ifdef TIMEIT
+ struct timeval start, end;
+ unsigned long diff;
+
+ gettimeofday(&start, NULL);
+#endif
+
+ thread = g_malloc(sizeof(*thread));
+ thread->tree = NULL;
+ thread->node_chunks = e_memchunk_new(32, sizeof(CamelFolderThreadNode));
+ thread->folder = NULL;
+ thread->summary = NULL;
+
+ id_table = g_hash_table_new((GHashFunc)id_hash, (GCompareFunc)id_equal);
+ no_id_table = g_hash_table_new(NULL, NULL);
+ for (i=0;i<summary->len;i++) {
+ CamelMessageInfo *mi = summary->pdata[i];
+
+ if (mi->message_id.id.id) {
+ c = g_hash_table_lookup(id_table, &mi->message_id);
+ /* check for duplicate messages */
+ if (c) {
+ /* if duplicate, just make out it is a no-id message, but try and insert it
+ into the right spot in the tree */
+ d(printf("doing: (duplicate message id)\n"));
+ c = e_memchunk_alloc0(thread->node_chunks);
+ g_hash_table_insert(no_id_table, (void *)mi, c);
+ } else {
+ d(printf("doing : %08x%08x (%s)\n", mi->message_id.id.part.hi, mi->message_id.id.part.lo, camel_message_info_subject(mi)));
+ c = e_memchunk_alloc0(thread->node_chunks);
+ g_hash_table_insert(id_table, (void *)&mi->message_id, c);
+ }
+ } else {
+ d(printf("doing : (no message id)\n"));
+ c = e_memchunk_alloc0(thread->node_chunks);
+ g_hash_table_insert(no_id_table, (void *)mi, c);
+ }
+
+ c->message = mi;
+ c->order = i;
+ child = c;
+ if (mi->references) {
+ int j;
+
+ d(printf("references:\n"));
+ for (j=0;j<mi->references->size;j++) {
+ /* should never be empty, but just incase */
+ if (mi->references->references[j].id.id == 0)
+ continue;
+
+ c = g_hash_table_lookup(id_table, &mi->references->references[j]);
+ if (c == NULL) {
+ d(printf("not found\n"));
+ c = e_memchunk_alloc0(thread->node_chunks);
+ g_hash_table_insert(id_table, &mi->references->references[j], c);
+ }
+ if (c!=child)
+ container_parent_child(c, child);
+ child = c;
+ }
+ }
+ }
+
+ d(printf("\n\n"));
+ /* build a list of root messages (no parent) */
+ head = NULL;
+ g_hash_table_foreach(id_table, hashloop, &head);
+ g_hash_table_foreach(no_id_table, hashloop, &head);
+
+ g_hash_table_destroy(id_table);
+ g_hash_table_destroy(no_id_table);
+
+ /* remove empty parent nodes */
+ prune_empty(thread, &head);
+
+ /* find any siblings which missed out */
+ group_root_set(thread, &head);
+
+#if 0
+ printf("finished\n");
+ i = camel_folder_thread_messages_dump(head);
+ printf("%d count, %d items in tree\n", uids->len, i);
+#endif
+
+ sort_thread(&head);
+
+ /* remove any phantom nodes, this could possibly be put in group_root_set()? */
+ c = (CamelFolderThreadNode *)&head;
+ while (c && c->next) {
+ CamelFolderThreadNode *scan, *newtop;
+
+ child = c->next;
+ if (child->message == NULL) {
+ newtop = child->child;
+ /* unlink pseudo node */
+ c->next = newtop;
+
+ /* link its siblings onto the end of its children */
+ scan = (CamelFolderThreadNode *)&newtop->child;
+ while (scan->next)
+ scan = scan->next;
+ scan->next = newtop->next;
+ /* and link the now 'real' node into the list */
+ newtop->next = child->next;
+ c = newtop;
+ e_memchunk_free(thread->node_chunks, child);
+ } else {
+ c = child;
+ }
+ }
+
+ /* this is only debug assertion stuff */
+ c = (CamelFolderThreadNode *)&head;
+ while (c->next) {
+ c = c->next;
+ if (c->message == NULL)
+ g_warning("threading missed removing a pseudo node: %s\n", c->root_subject);
+ }
+
+ thread->tree = head;
+
+#ifdef TIMEIT
+ gettimeofday(&end, NULL);
+ diff = end.tv_sec * 1000 + end.tv_usec/1000;
+ diff -= start.tv_sec * 1000 + start.tv_usec/1000;
+ printf("Message threading %d messages took %ld.%03ld seconds\n",
+ summary->len, diff / 1000, diff % 1000);
+#endif
+
+ return thread;
+}
+
+/**
* camel_folder_thread_messages_destroy:
* @thread:
*
@@ -599,8 +752,10 @@ camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids)
void
camel_folder_thread_messages_destroy(CamelFolderThread *thread)
{
- camel_folder_free_summary(thread->folder, thread->summary);
- camel_object_unref((CamelObject *)thread->folder);
+ if (thread->folder) {
+ camel_folder_free_summary(thread->folder, thread->summary);
+ camel_object_unref((CamelObject *)thread->folder);
+ }
e_memchunk_destroy(thread->node_chunks);
g_free(thread);
}