Camel.Service

CamelService is an abstract class which is the parent class of Evolution/Camel.Store and Evolution/Camel.Transport used to define common operations associated with a given mail service.

Services are resolved by URI using Evolution/Camel.Session.get_service().

Base class

Class instances will always be instantiated by Evolution/Camel.Session.get_service. It uses the class types in the Evolution/Camel.Provider#struct CamelProvider to determine which type to create.

 typedef enum {
        CAMEL_SERVICE_DISCONNECTED,
        CAMEL_SERVICE_CONNECTING,
        CAMEL_SERVICE_CONNECTED,
        CAMEL_SERVICE_DISCONNECTING
 } CamelServiceConnectionStatus;
 
 struct _CamelService {
        CamelObject parent_object;
        struct _CamelServicePrivate *priv;
 
        CamelSession *session;
        CamelProvider *provider;
        CamelServiceConnectionStatus status;
        CamelOperation *connect_op;
        CamelURL *url;
 };

Implementations can override this virtual construct method, but should always chain the call up to the parent class. The url parameter is the most important, it will contain all of the settings not only to uniquely identify this service, but also any options on it. It will be built using the information defined in the Evolution/Camel.Provider module for this service. The construct method may parse the url parameters to define service options, or leave it until connect time.

 void camel_service_construct(CamelService *service,
                              CamelSession *session,
                              CamelProvider *provider,
                              CamelURL *url, 
                              CamelException *ex);

Connection state

Although services may not necessarily deal with remote resources, CamelService contains a set of connection oriented functions. As a rule, services will always be connected to before they are used in a way which may imply the requirement to be connected. Functions requiring a connected state should just fail if they are not. Any local services should just use the default implementations of these virtual methods.

 gboolean camel_service_connect(CamelService *service, CamelException *ex);

This is the time when a service should setup any remote resources, connect to sockets or servers, and so on, based on the url set in the base CamelService object.

The connect function will also setup a Evolution/Camel.Operation for the current thread, that can be used to cancel the connection; since connections may take some time, failure or not.

Then there is a disconnect function. After this is called all remote resources should be closed down. If clean is false then any connections must just be dropped, regardless of any failures involved. Otherwise the disconnect may fail, if for example, it cannot synchronise local changes to the remote resource. Note that if clean is false then this function must not fail.

 gboolean camel_service_disconnect(CamelService *service, gboolean clean, CamelException *ex);

And finally a cancellation command. The default implementation for this will send a cancellation request to the connect_op which will be registered appropriately. This will normally need to be called from another thread.

 void camel_service_cancel_connect(CamelService *service);

Although the above scenario lists how the API expects things to work, it is up to the backend to implement this whichever way it sees fit.

For example, instead of the connect function actually allocating the resources for the connection, it could merely switch the state of the service into a connected state. The service, via another thread or process, could then connect at will as required, silently failing if the server cannot be reached. It must just ensure that a disconnect invocation closes down the remote connections and stops any more from occuring while in the disconnected state.

Note this will interact (often badly) with the online state of the Evolution/Camel.Session and the Camel.DiscoStore. i.e. if you are onffline, then even a connect must not access remote resources. Note that if the later implementation idea above is used, this additional offline state is easier to integrate.

This is complicated by the additional states of CONNECTING and DISCONNECTING. This has been the source of innumerable bugs; the states are probably not required, and the whole connect and disconnect interface is the entire cause of these bugs.

Accessors

Most of these are pointless accessors which access public structure fields, or they should be accessed using the object #Properties instead.

 char *camel_service_get_url(CamelService *service);
 char *camel_service_get_name(CamelService *service, gboolean brief);
 char *camel_service_get_path(CamelService *service);
 CamelSession *camel_service_get_session(CamelService *service);
 CamelProvider *camel_service_get_provider(CamelService *service);

Auth types

The auth types complement the Evolution/Camel.Provider.authtype list, in that they will always be a sub-set of the provider authtypes. But unlike the provider authtypes, these will be the actual authentication types supported by the resource identified by the url for this service.

 typedef struct {
        char *name;
        char *description;
        char *authproto;
        gboolean need_password;
 } CamelServiceAuthType;
  • name: Is the short name of the authentication type. e.g. "Password". This will be translated based on the translation domain supplied in the Evolution/Camel.Provider structure for this service.

  • description: Is a longer description of the authentication type. Might be used as a tool-tip or status bar help message, etc.
  • authproto: The string used to select this authentication type. It will be added as an 'authmech' option to the Evolution/Camel.URL.

  • need_password: This authenication method uses and requires a password to be set. This is normally just used to fine-tune any configuration UI.

And to find the auth-types implemented by this service instance:

 GList *camel_service_query_auth_types(CamelService *service, CamelException *ex);

Since this may need to make an implicit connection to the service it may fail, and set the Evolution/Camel.Exception appropriately. It must also act appropriately if the Evolution/Camel.Session is offline.

The caller must free the GList, but not its content.

Properties

In addition to the basic [[Evolution/Camel.Object#CamelObject tags|Camel.Object properties]], CamelService provides additional properties accessors:

Note that these just access members of the url. This is in preparation for the possibility that services will not be defined by a URI but by other means.

  • CAMEL_SERVICE_USERNAME: Get the username from the url for this service.

  • CAMEL_SERVICE_AUTH: Retrieve the auth mechanism for this service.
  • CAMEL_SERVICE_HOSTNAME: Hostname.
  • CAMEL_SERVICE_PORT: Port.
  • CAMEL_SERVICE_PATH: Path.

Other properties should be added to replace the accessors above.

Notes

It is debatable whether Evolution/Camel.Store and Evolution/Camel.Transport really need to exist as separate object instances from Evolution/Camel.Service. Infact it makes integrated providers like Exchange and Groupwise rather messy to implement since you must access the same resource using two independent objects.

What would be a cleaner approach is for each of Evolution/Camel.Store and Evolution/Camel.Transport to be changed into interfaces, say, CamelIStore and CamelITransport, which would optionally be present on any given CamelService class.

The connect and disconnect state machine is far too complex. With 4 states for that, 2 online states for the session and 3 states for the Evolution/Camel.Store#Camel.DiscoStore that makes 24 potential states, most of which are invalid!! However it needs to properly handle concurrent threads trying to connect and disconnect simultaneously. Locking is used, but that is also complex. See also Evolution/Camel.Store#Notes.

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