Camel.Offline

This page discusses the various interfaces designed to support offline operation.

Camel.OfflineStore

CamelOfflineStore is the 'new' interface that any remote backends should support. They do this by sub-classing CamelOfflineStore rather than CamelStore.

There is also Evolution/#Camel.DiscoStore, which is only used by older backends - it should not be used in new code.

Basically, this just adds a new state to a Evolution/#Camel.Store, and a new public interface so that client code can control it. This interface is used by Evolution to switch to and from offline state through the ui. The reason a synchronous call is used rather than a simple notification is that the code may want to do some processing before it actually goes offline.

Any backend implementing this should also provide Evolution/#Camel.OfflineFolder based folders, for any folders which constitute remote data.

Base class

There is a single virtual method which sets the new state. The member variable state can be read to determine the current state.

 enum {
        CAMEL_OFFLINE_STORE_NETWORK_AVAIL,
        CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL,
 };
 
 void camel_offline_store_set_network_state(CamelOfflineStore *store, int state, CamelException *ex);

The default implementation will just synchronise all of the Evolution/Camel.OfflineFolders present in the stores active folder table, so will rarely need to be overriden.

Actually, it isn't a virtual method afterall, despite appearances, it just talks to the Evolution/Camel.OfflineFolder interfaces only. This looks like a bug to me.

Camel.OfflineFolder

Each offlineable folder in an offlineable store should subclass this object. It provides a couple of interfaces:

  • A persistent property to indicate if the folder should be kept in sync always.
  • A virtual method to sync specific messages.

Base class

 enum {
        CAMEL_OFFLINE_FOLDER_SYNC_OFFLINE = CAMEL_OFFLINE_FOLDER_ARG_SYNC_OFFLINE | CAMEL_ARG_BOO,
 };
 
 struct _CamelOfflineFolder {
        CamelFolder parent_object;
        
        unsigned int sync_offline:1;
 };
 
 void camel_offline_folder_downsync(CamelOfflineFolder *folder, const char *expression, CamelException *ex);

The expression passed to downsync is a search expression, used to match messages to ensure are synced. Note that if the sync_offline property is TRUE, then the backend should normally just synchronise everything automatically, all the time.

Camel.OfflineJournal

CamelOfflineJournal is a helper class which can be used to implement a changelog journal for an offline folder. Note that this is purely an abstract helper object, it is up to the backend implementation to use it appropriately.

Since it doesn't even have record-writing interface, I don't actually see what the point of it is? It isn't useful for client code, and doesn't seem to help backend code much in their tasks.

It seems that an implementation needs to define it's own record format, and add each record manually to the linked list in the base class. Then it has to implement its own record reading and writing functions which use its record format to read and write those records.

It would be nice if at least it provided some transactional interfaces to ensure changes are replayed properly and only once.

Camel.Disco

The diconnected interface is the older interface set used to implement offline mode. It is still used for IMAP, but should not be used in new code, due to it's complexity.

Camel.DiscoStore

CamelDiscoStore is the original 'disconnected mode' backend. It is only used by some existing storage backends and should not be used in new code. This is somewhat over-engineered and over-complex, it tries to simplify implementations by handling all of the state information internally and mapping to different virtual methods appropriately. In reality this just makes things more complicated for implementing code, leading to many complex state problems.

Worse, it adds another state, 'resyncing' apart from the basic 'online' and 'offline' states, just to confuse the matter. (there is really no practical reason why internal inter-states should ever be exposed to client code).

Because it shouldn't be used in new code, it wont be described further here, see the source code.

Camel.DiscoFolder

This is wildly over-engineered. It tries to hide the offline-state from the implementation by providing an exploded list of methods they must implement, for operations in each of the given states. In reality this just makes the code much more complex to write and maintain. Just say no.

It will try to automatically run a re-sync process when you go back online using the journal.

Camel.DiscoDiary

This is used by CamelDiscoFolder to record changes that happen to folders when they are in offline mode. When the folder is placed back in online mode, the journal is replayed, hopefully synchronising all changes from the client to the backend appropriately.

Notes

The additional state together with the Evolution/Camel.Service connection state, just makes this pretty messy to use and to implement. Perhaps there should be an ICamelStoreOffline interface instead of having to subclass the store object. This might simplify some of the state too.

The linkage with the online state in Evolution/Camel.Session is indirect. Services must query CamelSession for the online state independently; this is a bit of a mess. Ideally the online state should only need to be set on the Evolution/Camel.Session and it could then cascade this atomically to all services.

There is also some argument for removing this synchronous online-offline state change anyway - e.g. for desktop notification of a removed network facility. Where no synchronisation can occur, it is pointless to try to. It is possible to do this in any given backend anyway, without needing to change apis.

CamelDiscoStore's functions generally have more obvious names than the OfflineStore ones, despite its otherwise difficult design.

The journal code isn't very reliable in the face of failures. Normally the rest of the journal is simply discarded if any one step fails. There is no internal mechanisms to manage transactional changes either.

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