Camel Virtual Folders

Another important feature of Camel is the virtual folder concept. These are like searches performed over a set of folders, but are automatically updated, and otherwise act and behave just like normal folders.


CamelVeeStore implements the basic Evolution/Camel.Store interfaces required to manage a separate list of virtual folders. It handles renaming and deleting and the like. Basically it is just a model implementation which can be used by a front-end to manage the list of virtual folders.

The list is only generated at run-time, and is not stored anywhere persistently - it is up to the driving application to create and initalise the virtual folders within the store. It does this by opening each folder in turn, and then setting it's search expression and folder sets.

Base class

The base class implements a new folder opening mode flag:


This means that the folder will automatically update as soon as changes occur, otherwise it will wait for a sync, update_info, or expunge call before it will update. This is required for most user-created virtual folders, otherwise for example, a virtual folder of unread messages would lose messages as they were read, which would be an unpleasant side-effect.

It will also automatically include the UNMATCHED virtual folder in the folder listings, as a system folder.


This is a Evolution/Camel.Folder subclass which implements virtual folders. Although they should normally live off a CamelVeeStore, there are some special cases where they might be parented to another store - e.g. a trash or junk folder.

Base class

The base VeeFolder object tracks the expression for this folder, and internally it tracks the list of folders it is searching against. It also uses the #Camel.VeeSummary to store and manage the list of messages matching the folder.

In addition, there is a special folder, called UNMATCHED:


This folder represents all messages from folders which are part of all virtual folders - which are not matched by any of those virtual folders. If all of the vfolders represent the working folders for a given user, then effectively UNMATCHED becomes the inbox.

Folder management

A few functions let you control which folders are searched.

 void camel_vee_folder_add_folder(CamelVeeFolder *vf, CamelFolder *sub);
 void camel_vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *sub);
 void camel_vee_folder_set_folders(CamelVeeFolder *vf, GList *folders);

And there is a function to set (or change) the expression. It uses a normal CamelFolderSearch search expression.

 void camel_vee_folder_set_expression(CamelVeeFolder *vf, const char *expr);

Other functions

 int camel_vee_folder_rebuild_folder(CamelVeeFolder *vf, CamelFolder *sub, CamelException *ex);

This is an internal function used to force a specific folder to be re-calculated.

 void camel_vee_folder_hash_folder(CamelFolder *folder, char buffer[8]);

UIDs should be as static as possible, so the virtual folder UIDs all consist of an 8 character hash code, followed by the original folder's UID. This allows the virtual folder implementation to easily convert from virtual folder UID to real UID, and also helps keep the UID static. This function generates the hash based on the (real) folder. Note that virtual folders of virtual folders still use a one-level UID conversion, since it is based on the physical folder's hash, not the virtual folder one.

 CamelFolder *camel_vee_folder_get_location(CamelVeeFolder *vf, const struct _CamelVeeMessageInfo *vinfo, char **realuid);

This is a helper function which gets the physical folder location of the message, including the original UID.


The CamelVeeSummary is a purely-memory-based Evolution/Camel.FolderSummary object which manages the list of matches for the current folder. Actually #Camel.Veefolder manages it, but this keeps track of them.


The CamelVeeMessageInfo is a stripped down version of a message-id. It only contains the virtual UID, a refcount, and a pointer to the real CamelMessageInfo from the source folder.

 struct _CamelVeeMessageInfo {
        CamelMessageInfo info;
        CamelMessageInfo *real;

It is implemented this way for a couple of reasons:

# Obviously the best way to do it. # Saves memory, the virtual messageid is much smaller. # Saves data duplication, all changes are sent directly to the destination message.

It used to maintain its own copy of everything because not all of the accessors were virtualised.


This is another special subclass of CamelVeeFolder which implements a much more optimised search function for simple search types. Those based on a simple bit comparison of the system flags. It implements a deleted messages and junked messages folder, although it could be extended for the other types too.

It is used internally by Evolution/Camel.Store to implement virtual trash or junk folders.

 #define CAMEL_VTRASH_NAME ".#evolution/Trash"
 #define CAMEL_VJUNK_NAME ".#evolution/Junk"

These are the hard-coded path-names of a trash and junk folder on a given store. They are stored in the ".#evolution" namespace.

  typedef enum _camel_vtrash_folder_t {
 } camel_vtrash_folder_t;
 struct _CamelVTrashFolder {
        CamelVeeFolder parent;
        enum _camel_vtrash_folder_t type;
        guint32 bit;
 CamelFolder *camel_vtrash_folder_new(CamelStore *parent_store, camel_vtrash_folder_t type);

The parent_store can be any type of store.


Even with the smaller CamelMessageInfo, virtual folders can be a massive overhead. They are also expensive to setup since search results are discarded between sessions.

Virtual folders work very differently in the disk summary branch. Instead of separate searches, they are view indices maintained on a per-folder basis. This means that no separate MessageInfo is required at all - saving all the memory required for it. Because the folder itself manages the indices, the results of searches can be made persistent in a reliable and consistent with no wasted overhead.

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