CamelFolderThread is a helper processing object that can take a list of messages from a folder, and calculate the conversations contained in the messages, based on the NNTP and RFC822 headers, In-Reply-To and References.

The algorithm is based on one from Jamie Zawinksi, a developer on Netscape 3 Mail. The threading is quite robust and reliable (despite what some Mutt users have claimed over the years). Because it is also based on pre-calculated hashes from the CamelMessageInfo, it is also very fast.

Base object

The base object contains some internal working data and the tree pointer which points to a tree of nodes representing the conversation threads.

 typedef struct _CamelFolderThread {
        guint32 refcount  : 31;
        guint32 subject   : 1;
        struct _CamelFolderThreadNode *tree;
        struct _EMemChunk *node_chunks;
        CamelFolder *folder;
        GPtrArray *summary;
 } CamelFolderThread;
 typedef struct _CamelFolderThreadNode {
        struct _CamelFolderThreadNode *next, *parent, *child;
        const CamelMessageInfo *message;
        char *root_subject;
        guint32 order:31;
        guint32 re:1;
 } CamelFolderThreadNode;

CamelFolderThreadNode is the important bit, where a description of the structure of the conversation is created. This can be used to directly build a model for use in a tree-view widget, or even used directly as a read-only model.


The new function creates the base object, threading all messages appropriately. the thread_subject option enables an additional algorithm which will fall-back to using "Re: " before subject lines to try to find conversation parts, when there are no other headers present.

 CamelFolderThread *camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids, gboolean thread_subject);

The apply function can be used to re-calculate the thread tree. It is a bit more efficient than re-building a full tree, and it changes the algorithm slightly. If nodes with children are removed, those children are not re-sorted to their proper ordered location in the tree, they just remain where they are. This can prevent strange jumping as messages are deleted.

 void camel_folder_thread_messages_apply(CamelFolderThread *thread, GPtrArray *uids);

Some reference counting:

 void camel_folder_thread_messages_ref(CamelFolderThread *threads);
 void camel_folder_thread_messages_unref(CamelFolderThread *threads);

And a debug function which dumps the tree structure generated.

 int camel_folder_threaded_messages_dump(CamelFolderThreadNode *c);


The disksummary branch code has its own independent implementation of these algorithms, one which works incrementally much more efficiently than these are.

Should reference the algorithm, from JWZ's site.

Apps/Evolution/Camel.FolderThread (last edited 2013-08-08 22:50:10 by WilliamJonMcCann)