Re: [Evolution-hackers] Camel interfaces





Groan.

On Tue, 2004-11-02 at 13:19 -0500, Jeffrey Stedfast wrote:
sounds cool, but where's the patch? :)

Jeff

On Tue, 2004-11-02 at 17:38 +0800, Not Zed wrote:
> 
> Well, work in progress patch below, as seen on the blog.
> 
> The idea is to add interfaces to camel objects, this would let us do
> some things we currently have to extend every class for.
> 
> It might make it easier to support e.g. public folders, and so on.  We
> can just add an IPublicFolder interface to the store class rather than
> having to put in dummy callbacks for all stores.  Interfaces fix a lot
> of the locking issues too, by forcing each implementation to do all
> the work rather than try to inherit some stuff which just interferes
> with it.
> 
> I have an example 'interface' in camel-store in the patch, for
> subscriptions, although nothing is hooked up (nor is any of it tested
> yet apart from compiling).
> 
> (another one of the 'big things' i'm trying to get out the way before
> the eventual shift to a separate camel, in eds or otherwise).
> 
> -- 
> 
> Michael Zucchi <notzed ximian com>
> "I'm stuck in a reality I can't
> imagine could be real."
> Novell's Evolution and Free
> Software Developer
--
Michael Zucchi <notzed ximian com>
"I'm stuck in a reality I can't imagine could be real."
Novell's Evolution and Free Software Developer
Index: camel/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/camel/ChangeLog,v
retrieving revision 1.2285
diff -u -3 -r1.2285 ChangeLog
--- camel/ChangeLog	28 Oct 2004 16:54:44 -0000	1.2285
+++ camel/ChangeLog	2 Nov 2004 09:28:40 -0000
@@ -1,3 +1,14 @@
+2004-11-02  Not Zed  <NotZed Ximian com>
+
+	* camel-object.c (camel_object_hook_event): check interfaces for
+	events too.
+	(camel_object_trigger_event): check interfaces for events too.
+	(camel_object_class_add_event): more checks for interfaces vs
+	normal object classes.
+	(camel_object_class_add_interface): add an interface to a class.
+	(camel_object_get_interface): query for interfaces on an object.
+	(camel_object_get_type): register the interface type.
+
 2004-10-28  Jeffrey Stedfast  <fejj ximian com>
 
 	* providers/imap4/camel-imap4-summary.c (envelope_decode_nstring):
Index: camel/camel-object.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-object.c,v
retrieving revision 1.49
diff -u -3 -r1.49 camel-object.c
--- camel/camel-object.c	20 Sep 2004 05:59:53 -0000	1.49
+++ camel/camel-object.c	2 Nov 2004 09:28:40 -0000
@@ -43,8 +43,10 @@
 /* I just mashed the keyboard for these... */
 #define CAMEL_OBJECT_MAGIC           	 0x77A344ED
 #define CAMEL_OBJECT_CLASS_MAGIC     	 0xEE26A997
+#define CAMEL_INTERFACE_MAGIC     	 0xBCE137A7
 #define CAMEL_OBJECT_FINALISED_MAGIC       0x84AC365F
 #define CAMEL_OBJECT_CLASS_FINALISED_MAGIC 0x7621ABCD
+#define CAMEL_INTERFACE_FINALISED_MAGIC    0x7CB2FE71
 
 /* ** Quickie type system ************************************************* */
 
@@ -113,6 +115,9 @@
 static const char *meta_name = "object:meta";
 #define CAMEL_OBJECT_STATE_FILE_MAGIC "CLMD"
 
+/* interface stuff */
+static const char *interface_name = "object:interface";
+
 /* ********************************************************************** */
 
 static CamelHookList *camel_object_get_hooks(CamelObject *o);
@@ -135,7 +140,9 @@
 static GHashTable *type_table;
 static EMemChunk *type_chunks;
 
+/* fundamental types are accessed via global */
 CamelType camel_object_type;
+CamelType camel_interface_type;
 
 #define P_LOCK(l) (pthread_mutex_lock(&l))
 #define P_UNLOCK(l) (pthread_mutex_unlock(&l))
@@ -144,7 +151,6 @@
 #define CLASS_LOCK(k) (g_mutex_lock((((CamelObjectClass *)k)->lock)))
 #define CLASS_UNLOCK(k) (g_mutex_unlock((((CamelObjectClass *)k)->lock)))
 
-
 static struct _CamelHookPair *
 pair_alloc(void)
 {
@@ -211,6 +217,8 @@
 
 /* ************************************************************************ */
 
+/* CamelObject base methods */
+
 /* Should this return the object to the caller? */
 static void
 cobject_init(CamelObject *o, CamelObjectClass *klass)
@@ -610,6 +618,59 @@
 	g_free(klass);
 }
 
+
+/* CamelInterface base methods */
+
+static void
+cinterface_init(CamelObject *o, CamelObjectClass *klass)
+{
+	g_error("Cannot instantiate interfaces, trying to instantiate '%s'", klass->name);
+	abort();
+}
+
+static int
+cinterface_getv(CamelObject *o, CamelException *ex, CamelArgGetV *args)
+{
+	return 0;
+}
+
+static int
+cinterface_setv(CamelObject *o, CamelException *ex, CamelArgV *args)
+{
+	return 0;
+}
+
+static void
+cinterface_free(CamelObject *o, guint32 tag, void *value)
+{
+	/* NOOP */
+}
+
+static void
+cinterface_class_init(CamelObjectClass *klass)
+{
+	klass->magic = CAMEL_INTERFACE_MAGIC;
+
+	/* just setup dummy callbacks, properties could be part of the interface but we support none */
+	klass->getv = cinterface_getv;
+	klass->setv = cinterface_setv;
+	klass->free = cinterface_free;
+
+	/* TODO: ok, these are cruft hanging around an interface, but it saves having to define two different class bases */
+	klass->meta_get = NULL;
+	klass->meta_set = NULL;
+	klass->state_read = NULL;
+	klass->state_write = NULL;
+}
+
+static void
+cinterface_class_finalise(CamelObjectClass * klass)
+{
+	klass->magic = CAMEL_INTERFACE_FINALISED_MAGIC;
+	g_free(klass);
+}
+
+/* this function must be called for any other in the object system */
 CamelType
 camel_object_get_type(void)
 {
@@ -620,6 +681,12 @@
 							sizeof(CamelObject), sizeof(CamelObjectClass),
 							cobject_class_init, cobject_class_finalise,
 							cobject_init, cobject_finalise);
+
+		camel_interface_type = camel_type_register(NULL, "CamelInterface",
+							   0, sizeof(CamelInterface),
+							   cinterface_class_init, cinterface_class_finalise,
+							   cinterface_init, NULL);
+							   
 	}
 
 	return camel_object_type;
@@ -635,24 +702,19 @@
 		type->klass_init(klass);
 }
 
-CamelType
-camel_type_register(CamelType parent, const char * name,
-		    /*unsigned int ver, unsigned int rev,*/
-		    size_t object_size, size_t klass_size,
-		    CamelObjectClassInitFunc class_init,
-		    CamelObjectClassFinalizeFunc class_finalise,
-		    CamelObjectInitFunc object_init,
-		    CamelObjectFinalizeFunc object_finalise)
+static CamelType
+co_type_register(CamelType parent, const char * name,
+		 /*unsigned int ver, unsigned int rev,*/
+		 size_t object_size, size_t klass_size,
+		 CamelObjectClassInitFunc class_init,
+		 CamelObjectClassFinalizeFunc class_finalise,
+		 CamelObjectInitFunc object_init,
+		 CamelObjectFinalizeFunc object_finalise)
 {
 	CamelObjectClass *klass;
 	/*int offset;
 	  size_t size;*/
 
-	if (parent != NULL && parent->magic != CAMEL_OBJECT_CLASS_MAGIC) {
-		g_warning("camel_type_register: invalid junk parent class for '%s'", name);
-		return NULL;
-	}
-
 	E_LOCK(type_lock);
 
 	/* Have to check creation, it might've happened in another thread before we got here */
@@ -724,6 +786,37 @@
 	return klass;
 }
 
+CamelType
+camel_type_register(CamelType parent, const char * name,
+		    /*unsigned int ver, unsigned int rev,*/
+		    size_t object_size, size_t klass_size,
+		    CamelObjectClassInitFunc class_init,
+		    CamelObjectClassFinalizeFunc class_finalise,
+		    CamelObjectInitFunc object_init,
+		    CamelObjectFinalizeFunc object_finalise)
+{
+	if (parent != NULL && parent->magic != CAMEL_OBJECT_CLASS_MAGIC) {
+		g_warning("camel_type_register: invalid junk parent class for '%s'", name);
+		return NULL;
+	}
+
+	return co_type_register(parent, name, object_size, klass_size, class_init, class_finalise, object_init, object_finalise);
+}
+
+CamelType
+camel_interface_register(CamelType parent, const char *name,
+			 size_t class_size,
+			 CamelObjectClassInitFunc class_init,
+			 CamelObjectClassFinalizeFunc class_finalise)
+{
+	if (parent != NULL && parent->magic != CAMEL_INTERFACE_MAGIC) {
+		g_warning("camel_interface_register: invalid junk parent class for '%s'", name);
+		return NULL;
+	}
+
+	return camel_type_register(parent, name, 0, class_size, class_init, class_finalise, NULL, NULL);
+}
+
 static void
 camel_object_init(CamelObject *o, CamelObjectClass *klass, CamelType type)
 {
@@ -852,6 +945,9 @@
 	if (type->magic == CAMEL_OBJECT_CLASS_MAGIC)
 		return type->name;
 
+	if (type->magic == CAMEL_INTERFACE_MAGIC)
+		return type->name;
+
 	return "(Junk class)";
 }
 
@@ -875,10 +971,14 @@
 		what = g_strdup_printf("CLASS '%s'", ((CamelObjectClass *)o)->name);
 	else if (o->magic == CAMEL_OBJECT_CLASS_MAGIC)
 		what = g_strdup_printf("CLASS '%s'", ((CamelObjectClass *)o)->name);
+	else if (o->magic == CAMEL_INTERFACE_MAGIC)
+		what = g_strdup_printf("INTERFACE '%s'", ((CamelObjectClass *)o)->name);
 	else if (o->magic == CAMEL_OBJECT_FINALISED_MAGIC)
 		what = g_strdup_printf("finalised OBJECT");
 	else if (o->magic == CAMEL_OBJECT_CLASS_FINALISED_MAGIC)
 		what = g_strdup_printf("finalised CLASS");
+	else if (o->magic == CAMEL_INTERFACE_FINALISED_MAGIC)
+		what = g_strdup_printf("finalised INTERFACE");
 	else 
 		what = g_strdup_printf("junk data");
 
@@ -948,6 +1048,20 @@
 	return FALSE;
 }
 
+gboolean
+camel_interface_is(CamelObjectClass *k, CamelType ctype)
+{
+	g_return_val_if_fail(check_magic(k, ctype, CAMEL_INTERFACE_MAGIC), FALSE);
+
+	while (k) {
+		if (k == ctype)
+			return TRUE;
+		k = k->parent;
+	}
+
+	return FALSE;
+}
+
 CamelObject *
 camel_object_cast(CamelObject *o, CamelType ctype)
 {
@@ -985,6 +1099,55 @@
 	return NULL;
 }
 
+CamelObjectClass *
+camel_interface_cast(CamelObjectClass *k, CamelType ctype)
+{
+	CamelObjectClass *r = k;
+
+	g_return_val_if_fail(check_magic(k, ctype, CAMEL_INTERFACE_MAGIC), NULL);
+
+	while (k) {
+		if (k == ctype)
+			return r;
+		k = k->parent;
+	}
+
+	g_warning("Interface '%s' doesn't have '%s' in its hierarchy", r->name, ctype->name);
+
+	return NULL;
+}
+
+static CamelHookPair *
+co_find_pair(CamelObjectClass *klass, const char *name)
+{
+	CamelHookPair *hook;
+
+	hook = klass->hooks;
+	while (hook) {
+		if (strcmp(hook->name, name) == 0)
+			return hook;
+		hook = hook->next;
+	}
+
+	return NULL;
+}
+
+static CamelHookPair *
+co_find_pair_ptr(CamelObjectClass *klass, const char *name)
+{
+	CamelHookPair *hook;
+
+	hook = klass->hooks;
+	while (hook) {
+		if (hook->name == name)
+			return hook;
+		hook = hook->next;
+	}
+
+	return NULL;
+}
+
+/* class functions */
 void
 camel_object_class_add_event(CamelObjectClass *klass, const char *name, CamelObjectEventPrepFunc prep)
 {
@@ -992,14 +1155,17 @@
 
 	g_return_if_fail (name);
 
-	pair = klass->hooks;
-	while (pair) {
-		if (strcmp(pair->name, name) == 0) {
-			g_warning("camel_object_class_add_event: `%s' is already declared for '%s'\n",
-				  name, klass->name);
-			return;
-		}
-		pair = pair->next;
+	pair = co_find_pair(klass, name);
+	if (pair) {
+		g_warning("camel_object_class_add_event: `%s' is already declared for '%s'",
+			  name, klass->name);
+		return;
+	}
+
+	if (klass->magic == CAMEL_INTERFACE_MAGIC && prep != NULL) {
+		g_warning("camel_object_class_add_event: `%s', CamelInterface '%s' may not have an event prep function - ignored",
+			  name, klass->name);
+		prep = NULL;
 	}
 
 	pair = pair_alloc();
@@ -1011,6 +1177,50 @@
 	klass->hooks = pair;
 }
 
+void
+camel_object_class_add_interface(CamelObjectClass *klass, CamelType itype)
+{
+	CamelHookPair *pair;
+	CamelType iscan;
+	GPtrArray *interfaces;
+	int i;
+
+	if (!camel_interface_is(itype, camel_interface_type)) {
+		g_warning("Cannot add an interface not derived from CamelInterface on class '%s'", klass->name);
+		return;
+	}
+
+	if (camel_object_class_is(klass, camel_interface_type)) {
+		g_warning("Cannot add an interface onto a class derived from CamelInterface");
+		return;
+	}
+
+	/* we store it on the class hooks so we don't have to add any extra space to the class */
+	pair = co_find_pair_ptr(klass, interface_name);
+	if (pair == NULL) {
+		pair = pair_alloc();
+		pair->data = g_ptr_array_new();
+		pair->next = klass->hooks;
+		klass->hooks = pair;
+	}
+
+	/* We just check that this type isn't added/derived anywhere else */
+	interfaces = pair->data;
+	iscan = itype;
+	while (iscan && iscan != camel_interface_type) {
+		for (i=0;i<interfaces->len;i++) {
+			if (camel_interface_is((CamelType)interfaces->pdata[i], iscan)) {
+				g_warning("Cannot add an interface twice '%s' on class '%s'\n", itype->name, klass->name);
+				return;
+			}
+		}
+		iscan = iscan->parent;
+	}
+
+	if (iscan == camel_interface_type)
+		g_ptr_array_add(interfaces, itype);
+}
+
 /* free hook data */
 static void
 camel_object_free_hooks(CamelObject *o)
@@ -1079,18 +1289,27 @@
 	g_return_val_if_fail(name != NULL, 0);
 	g_return_val_if_fail(func != NULL, 0);
 
-	hook = obj->klass->hooks;
-	while (hook) {
-		if (strcmp(hook->name, name) == 0)
-			goto setup;
-		hook = hook->next;
-	}
+	hook = co_find_pair(obj->klass, name);
 
-	g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.",
-		  name, obj->klass->name);
+	/* Check all interfaces on this object for events defined on them */
+	if (hook == NULL) {
+		pair = co_find_pair_ptr(obj->klass, interface_name);
+		if (pair) {
+			GPtrArray *interfaces = pair->data;
+			int i;
+
+			for (i=0;i<interfaces->len;i++) {
+				hook = co_find_pair(interfaces->pdata[i], name);
+				if (hook)
+					goto setup;
+			}
+		}
 
-	return 0;
+		g_warning("camel_object_hook_event: trying to hook event `%s' in class `%s' with no defined events.",
+			  name, obj->klass->name);
 
+		return 0;
+	}
 setup:
 	/* setup hook pair */
 	pair = pair_alloc();
@@ -1217,11 +1436,24 @@
 	g_return_if_fail (CAMEL_IS_OBJECT (obj));
 	g_return_if_fail (name);
 
-	hook = obj->klass->hooks;
-	while (hook) {
-		if (strcmp(hook->name, name) == 0)
-			goto trigger;
-		hook = hook->next;
+	hook = co_find_pair(obj->klass, name);
+	if (hook)
+		goto trigger;
+
+	if (obj->hooks == NULL)
+		return;
+
+	/* interface events can't have prep functions */
+	pair = co_find_pair_ptr(obj->klass, interface_name);
+	if (pair) {
+		GPtrArray *interfaces = pair->data;
+		int i;
+
+		for (i=0;i<interfaces->len;i++) {
+			hook = co_find_pair(interfaces->pdata[i], name);
+			if (hook)
+				goto trigger_interface;
+		}
 	}
 
 	g_warning("camel_object_trigger_event: trying to trigger unknown event `%s' in class `%s'",
@@ -1237,7 +1469,7 @@
 	/* also, no hooks, dont bother going further */
 	if (obj->hooks == NULL)
 		return;
-
+trigger_interface:
 	/* lock the object for hook emission */
 	camel_object_ref(obj);
 	hooks = camel_object_get_hooks(obj);
@@ -1283,6 +1515,31 @@
 
 	camel_object_unget_hooks(obj);
 	camel_object_unref(obj);
+}
+
+void *
+camel_object_get_interface(void *vo, CamelType itype)
+{
+	CamelObject *obj = vo;
+	CamelHookPair *pair;
+
+	g_return_val_if_fail(CAMEL_IS_OBJECT (obj), NULL);
+	g_return_val_if_fail(camel_interface_is(itype, camel_interface_type), NULL);
+
+	pair = co_find_pair_ptr(obj->klass, interface_name);
+	if (pair) {
+		GPtrArray *interfaces = pair->data;
+		int i;
+
+		for (i=0;i<interfaces->len;i++) {
+			if (camel_interface_is((CamelType)interfaces->pdata[i], itype))
+				return (CamelType)interfaces->pdata[i];
+		}
+	}
+
+	g_warning("Object %p class %s doesn't contain interface %s\n", vo, obj->klass->name, itype->name);
+
+	return NULL;
 }
 
 /* get/set arg methods */
Index: camel/camel-object.h
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-object.h,v
retrieving revision 1.31
diff -u -3 -r1.31 camel-object.h
--- camel/camel-object.h	20 Sep 2004 05:59:53 -0000	1.31
+++ camel/camel-object.h	2 Nov 2004 09:28:40 -0000
@@ -72,6 +72,10 @@
 typedef unsigned int CamelObjectHookID;
 typedef struct _CamelObjectMeta CamelObjectMeta;
 
+extern CamelType camel_interface_type;
+#define CAMEL_INTERFACE_TYPE (camel_interface_type)
+typedef struct _CamelInterface CamelInterface;
+
 typedef void (*CamelObjectClassInitFunc) (CamelObjectClass *);
 typedef void (*CamelObjectClassFinalizeFunc) (CamelObjectClass *);
 typedef void (*CamelObjectInitFunc) (CamelObject *, CamelObjectClass *);
@@ -165,6 +169,8 @@
 	void (*init)(struct _CamelObject *, struct _CamelObjectClass *);
 	void (*finalise)(struct _CamelObject *);
 
+	/* root-class fields follow, type system above */
+
 	/* get/set interface */
 	int (*setv)(struct _CamelObject *, struct _CamelException *ex, CamelArgV *args);
 	int (*getv)(struct _CamelObject *, struct _CamelException *ex, CamelArgGetV *args);
@@ -180,6 +186,11 @@
 	int (*state_write)(struct _CamelObject *, FILE *fp);
 };
 
+/* an interface is just a class with no instance data */
+struct _CamelInterface {
+	struct _CamelObjectClass type;
+};
+
 /* The type system .... it's pretty simple..... */
 void camel_type_init (void);
 CamelType camel_type_register(CamelType parent, const char * name, /*unsigned int ver, unsigned int rev,*/
@@ -190,6 +201,11 @@
 			      CamelObjectInitFunc instance_init,
 			      CamelObjectFinalizeFunc instance_finalize);
 
+CamelType camel_interface_register(CamelType parent, const char *name,
+				   size_t classfuncs_size,
+				   CamelObjectClassInitFunc class_init,
+				   CamelObjectClassFinalizeFunc class_finalize);
+
 /* deprecated interface */
 #define camel_type_get_global_classfuncs(x) ((CamelObjectClass *)(x))
 
@@ -197,6 +213,7 @@
 const char *camel_type_to_name (CamelType type);
 CamelType camel_name_to_type (const char *name);
 void camel_object_class_add_event (CamelObjectClass *klass, const char *name, CamelObjectEventPrepFunc prep);
+void camel_object_class_add_interface(CamelObjectClass *klass, CamelType itype);
 
 void camel_object_class_dump_tree (CamelType root);
 
@@ -207,6 +224,9 @@
 CamelObjectClass *camel_object_class_cast (CamelObjectClass *klass, CamelType ctype);
 gboolean camel_object_class_is (CamelObjectClass *klass, CamelType ctype);
 
+CamelObjectClass *camel_interface_cast(CamelObjectClass *klass, CamelType ctype);
+gboolean camel_interface_is(CamelObjectClass *k, CamelType ctype);
+
 CamelType camel_object_get_type (void);
 
 CamelObject *camel_object_new (CamelType type);
@@ -225,6 +245,9 @@
 void camel_object_remove_event(void *obj, CamelObjectHookID id);
 void camel_object_unhook_event(void *obj, const char *name, CamelObjectEventHookFunc hook, void *data);
 void camel_object_trigger_event(void *obj, const char *name, void *event_data);
+
+/* interfaces */
+void *camel_object_get_interface(void *vo, CamelType itype);
 
 /* get/set methods */
 int camel_object_set(void *obj, struct _CamelException *ex, ...);
Index: camel/camel-store.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-store.c,v
retrieving revision 1.154
diff -u -3 -r1.154 camel-store.c
--- camel/camel-store.c	20 Sep 2004 05:59:53 -0000	1.154
+++ camel/camel-store.c	2 Nov 2004 09:28:40 -0000
@@ -1204,3 +1204,58 @@
 	
 	return equal;
 }
+
+/* subscriptions interface */
+
+static void
+cis_interface_init (CamelISubscribe *cis)
+{
+	camel_object_class_add_event((CamelType)cis, "subscribed", NULL);
+	camel_object_class_add_event((CamelType)cis, "unsubscribed", NULL);
+}
+
+CamelType camel_isubscribe_get_type (void)
+{
+	static CamelType camel_isubscribe_type = CAMEL_INVALID_TYPE;
+
+	if (camel_isubscribe_type == CAMEL_INVALID_TYPE) {
+		camel_isubscribe_type = camel_interface_register (CAMEL_INTERFACE_TYPE, "CamelISubscribe",
+								  sizeof (CamelISubscribe),
+								  (CamelObjectClassInitFunc) cis_interface_init,
+								  NULL);
+	}
+
+	return camel_isubscribe_type;
+}
+
+gboolean camel_isubscribe_subscribed(CamelStore *store, const char *name)
+{
+	CamelISubscribe *iface = camel_object_get_interface(store, camel_isubscribe_get_type());
+
+	if (iface && iface->subscribed)
+		return iface->subscribed(store, name);
+
+	g_warning("Trying to invoke unimplemented subscribed method on a store");
+	return FALSE;
+}
+
+void camel_isubscribe_subscribe(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+	CamelISubscribe *iface = camel_object_get_interface(store, camel_isubscribe_get_type());
+
+	if (iface && iface->subscribe)
+		return iface->subscribe(store, folder_name, ex);
+
+	g_warning("Trying to invoke unimplemented subscribe method on a store");
+}
+
+void camel_isubscribe_unsubscribe(CamelStore *store, const char *folder_name, CamelException *ex)
+{
+	CamelISubscribe *iface = camel_object_get_interface(store, camel_isubscribe_get_type());
+
+	if (iface && iface->unsubscribe)
+		return iface->unsubscribe(store, folder_name, ex);
+
+	g_warning("Trying to invoke unimplemented unsubscribe method on a store");
+}
+
Index: camel/camel-store.h
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-store.h,v
retrieving revision 1.69
diff -u -3 -r1.69 camel-store.h
--- camel/camel-store.h	26 May 2004 04:24:01 -0000	1.69
+++ camel/camel-store.h	2 Nov 2004 09:28:40 -0000
@@ -164,7 +164,6 @@
 						     CamelException *ex);
 } CamelStoreClass;
 
-
 /* Standard Camel function */
 CamelType camel_store_get_type (void);
 
@@ -230,6 +229,20 @@
 int              camel_store_folder_uri_equal         (CamelStore *store,
 						       const char *uri0,
 						       const char *uri1);
+
+typedef struct _CamelISubscribe CamelISubscribe;
+struct _CamelISubscribe {
+	CamelInterface iface;
+
+	gboolean (*subscribed)(CamelStore *store, const char *folder_name);
+	void (*subscribe)(CamelStore *store, const char *folder_name, CamelException *ex);
+	void (*unsubscribe)(CamelStore *store, const char *folder_name, CamelException *ex);
+};
+
+CamelType camel_isubscribe_get_type (void);
+gboolean camel_isubscribe_subscribed(CamelStore *store, const char *name);
+void camel_isubscribe_subscribe(CamelStore *store, const char *folder_name, CamelException *ex);
+void camel_isubscribe_unsubscribe(CamelStore *store, const char *folder_name, CamelException *ex);
 
 #ifdef __cplusplus
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]