From a570bb037f3fd6b15e1e3d16a04827b6243ff85f Mon Sep 17 00:00:00 2001 From: Not Zed Date: Sat, 17 Mar 2001 04:51:21 +0000 Subject: Implemented. (ref_message_info): And default implementation. 2001-03-17 Not Zed * camel-folder.c (camel_folder_ref_message_info): Implemented. (ref_message_info): And default implementation. * camel-folder.h: Added ref_message_info virtual method. 2001-03-16 Not Zed * camel-folder-thread.c (camel_folder_thread_messages_new_summary): New function to create a thread tree from a supplied summary array. (camel_folder_thread_messages_destroy): Handle thread trees generated by the above function properly. svn path=/trunk/; revision=8774 --- camel/ChangeLog | 15 +++++ camel/camel-folder-thread.c | 159 +++++++++++++++++++++++++++++++++++++++++++- camel/camel-folder-thread.h | 3 + camel/camel-folder.c | 28 +++++++- camel/camel-folder.h | 2 + 5 files changed, 204 insertions(+), 3 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 65b72eb4de..5ba27929be 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,18 @@ +2001-03-17 Not Zed + + * camel-folder.c (camel_folder_ref_message_info): Implemented. + (ref_message_info): And default implementation. + + * camel-folder.h: Added ref_message_info virtual method. + +2001-03-16 Not Zed + + * camel-folder-thread.c + (camel_folder_thread_messages_new_summary): New function to create + a thread tree from a supplied summary array. + (camel_folder_thread_messages_destroy): Handle thread trees + generated by the above function properly. + 2001-03-16 Jeffrey Stedfast * camel-private.h: Same. 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. **/ @@ -590,6 +592,157 @@ camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids) return thread; } +/** + * 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;ilen;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;jreferences->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); } diff --git a/camel/camel-folder-thread.h b/camel/camel-folder-thread.h index 843ade0b56..d75fc35c54 100644 --- a/camel/camel-folder-thread.h +++ b/camel/camel-folder-thread.h @@ -43,6 +43,9 @@ typedef struct CamelFolderThread { } CamelFolderThread; CamelFolderThread *camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids); + +/* new improved interface (believe it or not!) */ +CamelFolderThread *camel_folder_thread_messages_new_summary(GPtrArray *summary); /* void camel_folder_thread_messages_add(CamelFolderThread *threads, CamelFolder *folder, GPtrArray *uids); void camel_folder_thread_messages_remove(CamelFolderThread *threads, CamelFolder *folder, GPtrArray *uids); diff --git a/camel/camel-folder.c b/camel/camel-folder.c index b3d50e893d..b3a86c0f4f 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -35,7 +35,7 @@ #include "camel-private.h" -#define d(x) x +#define d(x) static CamelObjectClass *parent_class = NULL; @@ -87,6 +87,7 @@ static CamelMimeMessage *get_message (CamelFolder *folder, static CamelMessageInfo *get_message_info (CamelFolder *folder, const char *uid); static void free_message_info (CamelFolder *folder, CamelMessageInfo *info); +static void ref_message_info (CamelFolder *folder, CamelMessageInfo *info); static GPtrArray *search_by_expression (CamelFolder *folder, const char *exp, @@ -145,6 +146,7 @@ camel_folder_class_init (CamelFolderClass *camel_folder_class) camel_folder_class->search_by_expression = search_by_expression; camel_folder_class->search_free = search_free; camel_folder_class->get_message_info = get_message_info; + camel_folder_class->ref_message_info = ref_message_info; camel_folder_class->free_message_info = free_message_info; camel_folder_class->copy_message_to = copy_message_to; camel_folder_class->move_message_to = move_message_to; @@ -801,6 +803,30 @@ camel_folder_free_message_info(CamelFolder *folder, CamelMessageInfo *info) CF_CLASS (folder)->free_message_info(folder, info); } +static void +ref_message_info (CamelFolder *folder, CamelMessageInfo *info) +{ + g_return_if_fail(folder->summary != NULL); + + camel_folder_summary_info_ref(folder->summary, info); +} + +/** + * camel_folder_ref_message_info: + * @folder: + * @info: + * + * Ref a CamelMessageInfo, previously obtained with get_message_info(). + **/ +void +camel_folder_ref_message_info(CamelFolder *folder, CamelMessageInfo *info) +{ + g_return_if_fail(CAMEL_IS_FOLDER (folder)); + g_return_if_fail(info != NULL); + + CF_CLASS (folder)->ref_message_info(folder, info); +} + /* TODO: is this function required anyway? */ gboolean camel_folder_has_summary_capability (CamelFolder *folder) diff --git a/camel/camel-folder.h b/camel/camel-folder.h index 53fa626e85..ab3483d1da 100644 --- a/camel/camel-folder.h +++ b/camel/camel-folder.h @@ -137,6 +137,7 @@ typedef struct { void (*search_free) (CamelFolder *folder, GPtrArray *result); CamelMessageInfo * (*get_message_info) (CamelFolder *, const char *uid); + void (*ref_message_info) (CamelFolder *, CamelMessageInfo *); void (*free_message_info) (CamelFolder *, CamelMessageInfo *); void (*copy_message_to) (CamelFolder *source, @@ -252,6 +253,7 @@ void camel_folder_search_free (CamelFolder *folder, GPtrArray *); /* summary info */ CamelMessageInfo *camel_folder_get_message_info (CamelFolder *folder, const char *uid); void camel_folder_free_message_info (CamelFolder *folder, CamelMessageInfo *info); +void camel_folder_ref_message_info (CamelFolder *folder, CamelMessageInfo *info); void camel_folder_copy_message_to (CamelFolder *source, const char *uid, -- cgit v1.2.3