This site has been retired. For up to date information, see handbook.gnome.org or gitlab.gnome.org.


[Home] [TitleIndex] [WordIndex

Camel.Store

CamelStore is the base object of any backends which support storage and retrival of mail. It is one of the more complicated objects that any plugin Evolution/Camel.Provider must implement, and it manages the connection and collections of folders.

Base class

The base class derives from Evolution/Camel.Service, and adds some state information.

 struct _CamelStore {
        CamelService parent_object;
        struct _CamelStorePrivate *priv;
        
        CamelObjectBag *folders;
 
        guint32 flags;
        guint32 mode;
 };

Flag bits, these are initialised by the implementation as appropriate. The default flags value is CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK.

Mode bits, by default they are both set.

These mode bits are very coarse grained. Perhaps per-folder mode bits which match IMAP ACL permissions could also be added. (RFC-2086)

The class structure itself consists of a large number of virtual methods; most are explained in the following sections.

 typedef struct {
        CamelServiceClass parent_class;
 
        GHashFunc       hash_folder_name;
        GCompareFunc    compare_folder_name;
 
        ...
 } CamelStoreClass;

But these are not, and must be set by the implementation to something appropriate. By default a case-sensitive string hash and compare is used.

Hooks

 typedef struct _CamelRenameInfo {
        char *old_base;
        struct _CamelFolderInfo *new;
 } CamelRenameInfo;

Camel.FolderInfo

The CamelFolderInfo is an important core object which is used to comminicate lists and trees of folders between the store and client code.

One of the basic uses of the CamelFolderInfo structure is to display a list of folders to the user to choose from. As such, it includes enough information for a basic folder display, that can be used to present this list without having to open every folder present. The idea being that to open a new object for every folder would be time and memory consuming.

In practice, this doesn't really turn out to be that great an idea; the interfaces which create and use CamelFolderInfo's are some of the hardest to implement. Since only a subset of static information is provided, it isn't as flexible as it might be. And it just adds another layer of indirection required to access the Evolution/Camel.Folder objects themsevles.

 typedef struct _CamelFolderInfo {
        struct _CamelFolderInfo *next;
        struct _CamelFolderInfo *parent;
        struct _CamelFolderInfo *child;
 
        char *uri;
        char *name;
        char *full_name;
 
        guint32 flags;
        guint32 unread;
        guint32 total;
 } CamelFolderInfo;

Then we have the flags. Note that these are all obviously, abstractions. They may not map DIRECTLY to a given implementation. They're not supposed to. Each implementation should just implement as much as it can, and choose appropriate defaults when it doesn't otherwise make sense.

Then there are additional bits which describe the basic folder type, in addition to the options above. They are just used to provide appropriate icons currently, although they could be used to help auto-configure things like Drafts and Sent folders with some more work.

Folder retrival functions

Now onto the methods in CamelStore. First, the folder retrival functions.

 #define CAMEL_STORE_FOLDER_CREATE (1<<0)
 #define CAMEL_STORE_FOLDER_EXCL (1<<1)
 #define CAMEL_STORE_FOLDER_BODY_INDEX (1<<2)
 #define CAMEL_STORE_FOLDER_PRIVATE (1<<3)
 
 CamelFolder *camel_store_get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex);

This is the basic folder opening function. folder_name corresponds to the full_name from the CamelFolderInfo structure.

The code entry point will manage the Evolution/Camel.Object#Camel.ObjectBag holding the folder names, and will this only ever call the virtual get_folder method on unopened folders. Implementation code therefore needn't worry about creating unique folder objects. A folder_opened event will automatically be created for any newly opened folders.

In the virtaul method, the implementation should create a Evolution/Camel.Folder corresponding to the folder and return it. Or set an exception in ex appropriately, and return NULL.

The flags are as follows:

The flags field is basically redundant now, only CREATE needs to be implemented. BODY_INDEX and other similar state information is handled by the Evolution/Camel.Object persistent state mechanisms now, and not by opening flags.

If the folder must be created, then a folder_created event must be emitted to broadcast this fact. In addition, if the store is running in a subscriptions mode, a folder_subscribed event must follow.

Then there are some helper functions to get specific folders. These are used by client code so they can access these folders directly, without having to scan CamelFolderInfo lists.

 CamelFolder *camel_store_get_inbox(CamelStore *store, CamelException *ex);
 CamelFolder *camel_store_get_trash(CamelStore *store, CamelException *ex);
 CamelFolder *camel_store_get_junk(CamelStore *store, CamelException *ex);

If a VTRASH or VJUNK folder is supported, then the entry points will just call camel_store_get_folder with a folder name of CAMEL_VTRASH_NAME and CAMEL_VJUNK_NAME respectively.

The default inbox name is inbox.

Folder manipulation functions

Then we have the folder manipulation functions. These work on folder name values, and not folder objects. In some cases, the entry point will manage the folders Evolution/Camel.Object#Camel.ObjectBag, and emit events as required. This should really be cleaned up to be consistent.

 CamelFolderInfo *camel_store_create_folder(CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex);

Creates a folder under parent_name. This is (almost) identical to calling open_folder with a path name of parent_name/folder_name with the CREATE flag, except it does not open the folder object itself. A {{{parent_name{{{ of "" is used to create a top-level folder.

A CamelFolderInfo is retunred describing all folders that were created. This includes any parent folders that were created that didn't exist.

It is up to the implementation to emit a folder_created event. If the store is running in a subscription mode, then it should also subscribe the folder and follow with a folder_subscribed event.

The function will automatically prevent a clash with a junk or trash folder name if VJUNK or VTRASH is enabled for the store.

 void camel_store_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex);

This will delete folder_name. The implementation should only allow empty folders with no subfolders to be deleted; but it is up to them. If the folder is deleted successfully and it is already open, the Evolution/Camel.Folder.folder_delete() method will be called on the open folder and it will be removed from the folders Evolution/Camel.Object#Camel.ObjectBag.

It is up to the implementation to emit a folder_deleted event for the deleted folder. It is also up to the implementation to unsubscribe from the folder and emit a folder_unsubscribed event if it is subscribed, before deleting it.

The function will automatically prevent a delete of a junk or trash folder name if VJUNK or VTRASH is enabled for the store.

 void camel_store_rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex);

This will rename a folder to a new location. Any subfolders of old_name must also be renamed.

This function will automatically emit appropriate folder_renamed events. It does this by using get_folder_info after the folder is renamed to find out what folder tree exists under new_name.

The function will automatically prevent a clash with a junk or trash folder name if VJUNK or VTRASH is enabled for the store.

Folder listing functions

Now we come to the functions which list the folders on a store.

 #define CAMEL_STORE_FOLDER_INFO_FAST       (1 << 0)
 #define CAMEL_STORE_FOLDER_INFO_RECURSIVE  (1 << 1)
 #define CAMEL_STORE_FOLDER_INFO_SUBSCRIBED (1 << 2)
 #define CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL (1 << 3)
 
 CamelFolderInfo *camel_store_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex);

It is absolutely vital that any implementation of get_folder_info is correct and properly implements the interface. Failing to do so could result in the UI code wrongfully deleting whole folder trees. You have been warned!

This will list folders starting at top, depending on the supplied flags.

It is vitally important that any listing from top start exactly at top and then proceed to list any siblings and children from that point. This is because this interface is used by the client to query the folder lists when deleting and renaming folder trees.

 void camel_store_free_folder_info(CamelStore *store, CamelFolderInfo *fi);
 void camel_store_free_folder_info_full(CamelStore *store, CamelFolderInfo *fi);
 void camel_store_free_folder_info_nop(CamelStore *store, CamelFolderInfo *fi);

These are just helper function used to fill out the virtual methods in CamelStoreClass. Some implementations may store static information in various fields of CamelFolderInfo, etc. Only free_folder_info_full is very useful.

 void camel_folder_info_free(CamelFolderInfo *fi);
 CamelFolderInfo *camel_folder_info_clone(CamelFolderInfo *fi);

These functions work on 'full' CamelFolderInfos. That is, where all strings are allocated using g_malloc.

 CamelFolderInfo *camel_folder_info_build(GPtrArray *folders, const char *namespace, char separator, gboolean short_names);

This function can be used to convert a flag array of CamelFolderInfo pointers into a tree structure. Do not use this in new code, do it yourself.

Subscription functions

CamelStore interfaces manage subscriptions.

First, an accessor which just checks the SUBSCRIPTIONS flag:

 gboolean camel_store_supports_subscriptions(CamelStore *store);

Then a query function for a specific folder name:

 gboolean camel_store_folder_subscribed(CamelStore *store, const char *folder_name);

And control functions to manage them:

 void camel_store_subscribe_folder(CamelStore *store, const char *folder_name, CamelException *ex);
 void camel_store_unsubscribe_folder(CamelStore *store, const char *folder_name, CamelException *ex);

It is up to each implementation to provide appropriate folder_subscribed and folder_unsubscribed events.

Control &amp; other functions

All folders in a store may be synchronised to the backing store using a convenience function:

 void camel_store_sync(CamelStore *store, int expunge, CamelException *ex);

This includes an optional expunge. Note that the default implementation will only expunge open folders.

The noop function is a mighty hack, to get around the problem of providing a timeout callback to a synchronous api. It may be called periodically to ping the server to keep a connection alive.

 void camel_store_noop(CamelStore *store, CamelException *ex);

folder_uri_equal is a function that can compare two URI's to see if they refer to the same physical folder. You must use this, rather than say strcmp since it takes into account various per-provider rules for comparing store URI's and folder names. It uses the store virtual method compare_folder_name to implement it.

 int camel_store_folder_uri_equal(CamelStore *store, const char *uri0,  const char *uri1);

Notes

camel_store_get_folder_info is hard to implement and hard to use. It should probably be changed to take a file-globbing like pattern instead, and take no flags. It should also be changed to return a simple flat-list of matching folders, rather than a tree.

The whole CamelFolderInfo thing could probably be removed. Instead, just return Evolution/Camel.Folder objects directly. If this was done, then there would also be no requirement for most of the folder manipulation functions; they could just be virtual methods on Evolution/Camel.Folder, which would now contain folders or messages rather than just messages.

CAMEL_STORE_FOLDER_INFO_FAST is messy. It should always be fast. Infact in Evolution 2.4 this isn't really used anymore - Evolution/Camel.Folder.refresh_info() is used instead to update folder counts.

Locking??


2024-10-23 10:58