[evolution-data-server] EServerSideSource: Support creating/deleting remote resources.



commit 945ef632647208496e0077f55d67d40e7e86fa08
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu Aug 2 13:51:41 2012 -0400

    EServerSideSource: Support creating/deleting remote resources.
    
    Add "remote-creatable" and "remote-deletable" properties which work the
    same as the "removable" and "writable" properties in terms of exporting
    and unexporting D-Bus interfaces.
    
    Add handlers for Create() and Delete() D-Bus method invocations, which
    call e_source_remote_create() and e_source_remote_delete() respectively.
    
    Override the remote_create_sync() and remote_delete_sync() methods to
    ferry the request to an associated ECollectionBackend (or set an error
    if there is no associated ECollectionBackend).

 .../reference/libebackend/libebackend-sections.txt |    2 +
 libebackend/e-server-side-source.c                 |  446 +++++++++++++++++++-
 libebackend/e-server-side-source.h                 |    6 +
 3 files changed, 442 insertions(+), 12 deletions(-)
---
diff --git a/docs/reference/libebackend/libebackend-sections.txt b/docs/reference/libebackend/libebackend-sections.txt
index ce41548..42bcb9d 100644
--- a/docs/reference/libebackend/libebackend-sections.txt
+++ b/docs/reference/libebackend/libebackend-sections.txt
@@ -349,6 +349,8 @@ e_server_side_source_get_write_directory
 e_server_side_source_set_write_directory
 e_server_side_source_set_removable
 e_server_side_source_set_writable
+e_server_side_source_set_remote_creatable
+e_server_side_source_set_remote_deletable
 <SUBSECTION Standard>
 E_SERVER_SIDE_SOURCE
 E_IS_SERVER_SIDE_SOURCE
diff --git a/libebackend/e-server-side-source.c b/libebackend/e-server-side-source.c
index e326ec2..9c4ca5f 100644
--- a/libebackend/e-server-side-source.c
+++ b/libebackend/e-server-side-source.c
@@ -41,6 +41,8 @@
 
 #define PRIMARY_GROUP_NAME	"Data Source"
 
+typedef struct _AsyncContext AsyncContext;
+
 struct _EServerSideSourcePrivate {
 	gpointer server;  /* weak pointer */
 
@@ -55,11 +57,19 @@ struct _EServerSideSourcePrivate {
 	gchar *write_directory;
 };
 
+struct _AsyncContext {
+	EDBusSourceRemoteCreatable *remote_creatable;
+	EDBusSourceRemoteDeletable *remote_deletable;
+	GDBusMethodInvocation *invocation;
+};
+
 enum {
 	PROP_0,
 	PROP_ALLOW_AUTH_PROMPT,
 	PROP_EXPORTED,
 	PROP_FILE,
+	PROP_REMOTE_CREATABLE,
+	PROP_REMOTE_DELETABLE,
 	PROP_REMOVABLE,
 	PROP_SERVER,
 	PROP_UID,
@@ -81,6 +91,21 @@ G_DEFINE_TYPE_WITH_CODE (
 		G_TYPE_INITABLE,
 		e_server_side_source_initable_init))
 
+static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->remote_creatable != NULL)
+		g_object_unref (async_context->remote_creatable);
+
+	if (async_context->remote_deletable != NULL)
+		g_object_unref (async_context->remote_deletable);
+
+	if (async_context->invocation != NULL)
+		g_object_unref (async_context->invocation);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
 static gboolean
 server_side_source_parse_data (GKeyFile *key_file,
                                const gchar *data,
@@ -244,6 +269,149 @@ server_side_source_write_cb (EDBusSourceWritable *interface,
 	return TRUE;
 }
 
+/* Helper for server_side_source_remote_create_cb() */
+static void
+server_side_source_remote_create_done_cb (GObject *source_object,
+                                          GAsyncResult *result,
+                                          gpointer user_data)
+{
+	ESource *source;
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	source = E_SOURCE (source_object);
+	async_context = (AsyncContext *) user_data;
+
+	e_source_remote_create_finish (source, result, &error);
+
+	if (error != NULL)
+		g_dbus_method_invocation_take_error (
+			async_context->invocation, error);
+	else
+		e_dbus_source_remote_creatable_complete_create (
+			async_context->remote_creatable,
+			async_context->invocation);
+
+	async_context_free (async_context);
+}
+
+static gboolean
+server_side_source_remote_create_cb (EDBusSourceRemoteCreatable *interface,
+                                     GDBusMethodInvocation *invocation,
+                                     const gchar *uid,
+                                     const gchar *data,
+                                     ESource *source)
+{
+	EServerSideSource *server_side_source;
+	ESourceRegistryServer *server;
+	AsyncContext *async_context;
+	ESource *scratch_source;
+	GDBusObject *dbus_object;
+	EDBusSource *dbus_source;
+	GKeyFile *key_file;
+	GFile *file;
+	GError *error = NULL;
+
+	/* Create a new EServerSideSource from 'uid' and 'data' but
+	 * DO NOT add it to the ESourceRegistryServer yet.  It's up
+	 * to the ECollectionBackend whether to use source as given
+	 * or create its own equivalent EServerSideSource, possibly
+	 * in response to a notification from a remote server. */
+
+	/* Validate the raw data. */
+	key_file = g_key_file_new ();
+	server_side_source_parse_data (key_file, data, strlen (data), &error);
+	g_key_file_free (key_file);
+
+	if (error != NULL) {
+		g_dbus_method_invocation_take_error (invocation, error);
+		return TRUE;
+	}
+
+	server_side_source = E_SERVER_SIDE_SOURCE (source);
+	server = e_server_side_source_get_server (server_side_source);
+
+	file = e_server_side_source_new_user_file (uid);
+	scratch_source = e_server_side_source_new (server, file, &error);
+	g_object_unref (file);
+
+	/* Sanity check. */
+	g_warn_if_fail (
+		((scratch_source != NULL) && (error == NULL)) ||
+		((scratch_source == NULL) && (error != NULL)));
+
+	if (error != NULL) {
+		g_dbus_method_invocation_take_error (invocation, error);
+		return TRUE;
+	}
+
+	dbus_object = e_source_ref_dbus_object (scratch_source);
+	dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
+
+	e_dbus_source_set_data (dbus_source, data);
+
+	g_object_unref (dbus_object);
+	g_object_unref (dbus_source);
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->remote_creatable = g_object_ref (interface);
+	async_context->invocation = g_object_ref (invocation);
+
+	e_source_remote_create (
+		source, scratch_source, NULL,
+		server_side_source_remote_create_done_cb,
+		async_context);
+
+	g_object_unref (scratch_source);
+
+	return TRUE;
+}
+
+/* Helper for server_side_source_remote_delete_cb() */
+static void
+server_side_source_remote_delete_done_cb (GObject *source_object,
+                                          GAsyncResult *result,
+                                          gpointer user_data)
+{
+	ESource *source;
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	source = E_SOURCE (source_object);
+	async_context = (AsyncContext *) user_data;
+
+	e_source_remote_delete_finish (source, result, &error);
+
+	if (error != NULL)
+		g_dbus_method_invocation_take_error (
+			async_context->invocation, error);
+	else
+		e_dbus_source_remote_deletable_complete_delete (
+			async_context->remote_deletable,
+			async_context->invocation);
+
+	async_context_free (async_context);
+}
+
+static gboolean
+server_side_source_remote_delete_cb (EDBusSourceRemoteDeletable *interface,
+                                     GDBusMethodInvocation *invocation,
+                                     ESource *source)
+{
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->remote_deletable = g_object_ref (interface);
+	async_context->invocation = g_object_ref (invocation);
+
+	e_source_remote_delete (
+		source, NULL,
+		server_side_source_remote_delete_done_cb,
+		async_context);
+
+	return TRUE;
+}
+
 static void
 server_side_source_set_file (EServerSideSource *source,
                              GFile *file)
@@ -300,6 +468,18 @@ server_side_source_set_property (GObject *object,
 				g_value_get_object (value));
 			return;
 
+		case PROP_REMOTE_CREATABLE:
+			e_server_side_source_set_remote_creatable (
+				E_SERVER_SIDE_SOURCE (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_REMOTE_DELETABLE:
+			e_server_side_source_set_remote_deletable (
+				E_SERVER_SIDE_SOURCE (object),
+				g_value_get_boolean (value));
+			return;
+
 		case PROP_REMOVABLE:
 			e_server_side_source_set_removable (
 				E_SERVER_SIDE_SOURCE (object),
@@ -362,6 +542,20 @@ server_side_source_get_property (GObject *object,
 				E_SERVER_SIDE_SOURCE (object)));
 			return;
 
+		case PROP_REMOTE_CREATABLE:
+			g_value_set_boolean (
+				value,
+				e_source_get_remote_creatable (
+				E_SOURCE (object)));
+			return;
+
+		case PROP_REMOTE_DELETABLE:
+			g_value_set_boolean (
+				value,
+				e_source_get_remote_deletable (
+				E_SOURCE (object)));
+			return;
+
 		case PROP_REMOVABLE:
 			g_value_set_boolean (
 				value,
@@ -727,6 +921,91 @@ server_side_source_write_finish (ESource *source,
 }
 
 static gboolean
+server_side_source_remote_create_sync (ESource *source,
+                                       ESource *scratch_source,
+                                       GCancellable *cancellable,
+                                       GError **error)
+{
+	ECollectionBackend *backend;
+	ESourceRegistryServer *server;
+	EServerSideSource *server_side_source;
+	gboolean success;
+
+	if (!e_source_get_remote_creatable (source)) {
+		g_set_error (
+			error, G_IO_ERROR,
+			G_IO_ERROR_NOT_SUPPORTED,
+			_("Data source '%s' does not "
+			  "support creating remote resources"),
+			e_source_get_display_name (source));
+		return FALSE;
+	}
+
+	server_side_source = E_SERVER_SIDE_SOURCE (source);
+	server = e_server_side_source_get_server (server_side_source);
+	backend = e_source_registry_server_ref_backend (server, source);
+
+	if (backend == NULL) {
+		g_set_error (
+			error, G_IO_ERROR,
+			G_IO_ERROR_NOT_SUPPORTED,
+			_("Data source '%s' has no collection "
+			  "backend to create the remote resource"),
+			e_source_get_display_name (source));
+		return FALSE;
+	}
+
+	success = e_collection_backend_create_resource_sync (
+		backend, scratch_source, cancellable, error);
+
+	g_object_unref (backend);
+
+	return success;
+}
+
+static gboolean
+server_side_source_remote_delete_sync (ESource *source,
+                                       GCancellable *cancellable,
+                                       GError **error)
+{
+	ECollectionBackend *backend;
+	ESourceRegistryServer *server;
+	EServerSideSource *server_side_source;
+	gboolean success;
+
+	if (!e_source_get_remote_deletable (source)) {
+		g_set_error (
+			error, G_IO_ERROR,
+			G_IO_ERROR_NOT_SUPPORTED,
+			_("Data source '%s' does not "
+			  "support deleting remote resources"),
+			e_source_get_display_name (source));
+		return FALSE;
+	}
+
+	server_side_source = E_SERVER_SIDE_SOURCE (source);
+	server = e_server_side_source_get_server (server_side_source);
+	backend = e_source_registry_server_ref_backend (server, source);
+
+	if (backend == NULL) {
+		g_set_error (
+			error, G_IO_ERROR,
+			G_IO_ERROR_NOT_SUPPORTED,
+			_("Data source '%s' has no collection "
+			  "backend to delete the remote resource"),
+			e_source_get_display_name (source));
+		return FALSE;
+	}
+
+	success = e_collection_backend_delete_resource_sync (
+		backend, source, cancellable, error);
+
+	g_object_unref (backend);
+
+	return success;
+}
+
+static gboolean
 server_side_source_initable_init (GInitable *initable,
                                   GCancellable *cancellable,
                                   GError **error)
@@ -794,6 +1073,8 @@ e_server_side_source_class_init (EServerSideSourceClass *class)
 	source_class->write_sync = server_side_source_write_sync;
 	source_class->write = server_side_source_write;
 	source_class->write_finish = server_side_source_write_finish;
+	source_class->remote_create_sync = server_side_source_remote_create_sync;
+	source_class->remote_delete_sync = server_side_source_remote_delete_sync;
 
 	g_object_class_install_property (
 		object_class,
@@ -831,6 +1112,34 @@ e_server_side_source_class_init (EServerSideSourceClass *class)
 			G_PARAM_CONSTRUCT_ONLY |
 			G_PARAM_STATIC_STRINGS));
 
+	/* This overrides the "remote-creatable" property
+	 * in ESourceClass with a writable version. */
+	g_object_class_install_property (
+		object_class,
+		PROP_REMOTE_CREATABLE,
+		g_param_spec_boolean (
+			"remote-creatable",
+			"Remote Creatable",
+			"Whether the data source "
+			"can create remote resources",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_STATIC_STRINGS));
+
+	/* This overrides the "remote-deletable" property
+	 * in ESourceClass with a writable version. */
+	g_object_class_install_property (
+		object_class,
+		PROP_REMOTE_DELETABLE,
+		g_param_spec_boolean (
+			"remote-deletable",
+			"Remote Deletable",
+			"Whether the data source "
+			"can delete remote resources",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_STATIC_STRINGS));
+
 	/* This overrides the "removable" property
 	 * in ESourceClass with a writable version. */
 	g_object_class_install_property (
@@ -1428,7 +1737,7 @@ void
 e_server_side_source_set_removable (EServerSideSource *source,
                                     gboolean removable)
 {
-	EDBusSourceRemovable *dbus_source_removable = NULL;
+	EDBusSourceRemovable *dbus_interface = NULL;
 	GDBusObject *dbus_object;
 	gboolean currently_removable;
 
@@ -1440,21 +1749,21 @@ e_server_side_source_set_removable (EServerSideSource *source,
 		return;
 
 	if (removable) {
-		dbus_source_removable =
+		dbus_interface =
 			e_dbus_source_removable_skeleton_new ();
 
 		g_signal_connect (
-			dbus_source_removable, "handle-remove",
+			dbus_interface, "handle-remove",
 			G_CALLBACK (server_side_source_remove_cb), source);
 	}
 
 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
 	e_dbus_object_skeleton_set_source_removable (
-		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_source_removable);
+		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
 	g_object_unref (dbus_object);
 
-	if (dbus_source_removable != NULL)
-		g_object_unref (dbus_source_removable);
+	if (dbus_interface != NULL)
+		g_object_unref (dbus_interface);
 
 	g_object_notify (G_OBJECT (source), "removable");
 }
@@ -1479,7 +1788,7 @@ void
 e_server_side_source_set_writable (EServerSideSource *source,
                                    gboolean writable)
 {
-	EDBusSourceWritable *dbus_source_writable = NULL;
+	EDBusSourceWritable *dbus_interface = NULL;
 	GDBusObject *dbus_object;
 	gboolean currently_writable;
 
@@ -1491,22 +1800,135 @@ e_server_side_source_set_writable (EServerSideSource *source,
 		return;
 
 	if (writable) {
-		dbus_source_writable =
+		dbus_interface =
 			e_dbus_source_writable_skeleton_new ();
 
 		g_signal_connect (
-			dbus_source_writable, "handle-write",
+			dbus_interface, "handle-write",
 			G_CALLBACK (server_side_source_write_cb), source);
 	}
 
 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
 	e_dbus_object_skeleton_set_source_writable (
-		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_source_writable);
+		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
 	g_object_unref (dbus_object);
 
-	if (dbus_source_writable != NULL)
-		g_object_unref (dbus_source_writable);
+	if (dbus_interface != NULL)
+		g_object_unref (dbus_interface);
 
 	g_object_notify (G_OBJECT (source), "writable");
 }
 
+/**
+ * e_server_side_source_set_remote_creatable:
+ * @source: an #EServerSideSource
+ * @remote_creatable: whether to export the RemoteCreatable interface
+ *
+ * Indicates whether @source can be used to create resources on a remote
+ * server.  Typically this is only set to %TRUE for collection sources.
+ *
+ * If %TRUE, the RemoteCreatable D-Bus interface is exported at the object
+ * path for @source.  If %FALSE, the RemoteCreatable D-Bus interface is
+ * unexported at the object path for @source, and any attempt by clients
+ * to call e_source_remote_create() will fail.
+ *
+ * Unlike the #ESource:removable and #ESource:writable properties, this
+ * is enforced for both clients of the registry D-Bus service and within
+ * the registry D-Bus service itself.
+ *
+ * Since: 3.6
+ **/
+void
+e_server_side_source_set_remote_creatable (EServerSideSource *source,
+                                           gboolean remote_creatable)
+{
+	EDBusSourceRemoteCreatable *dbus_interface = NULL;
+	GDBusObject *dbus_object;
+	gboolean currently_remote_creatable;
+
+	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
+
+	currently_remote_creatable =
+		e_source_get_remote_creatable (E_SOURCE (source));
+
+	if (remote_creatable == currently_remote_creatable)
+		return;
+
+	if (remote_creatable) {
+		dbus_interface =
+			e_dbus_source_remote_creatable_skeleton_new ();
+
+		g_signal_connect (
+			dbus_interface, "handle-create",
+			G_CALLBACK (server_side_source_remote_create_cb),
+			source);
+	}
+
+	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
+	e_dbus_object_skeleton_set_source_remote_creatable (
+		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
+	g_object_unref (dbus_object);
+
+	if (dbus_interface != NULL)
+		g_object_unref (dbus_interface);
+
+	g_object_notify (G_OBJECT (source), "remote-creatable");
+}
+
+/**
+ * e_server_side_source_set_remote_deletable:
+ * @source: an #EServerSideSource
+ * @remote_deletable: whether to export the RemoteDeletable interface
+ *
+ * Indicates whether @source can be used to delete resources on a remote
+ * server.  Typically this is only set to %TRUE for sources created by an
+ * #ECollectionBackend to represent a remote resource.
+ *
+ * If %TRUE, the RemoteDeletable D-Bus interface is exported at the object
+ * path for @source.  If %FALSE, the RemoteDeletable D-Bus interface is
+ * unexported at the object path for @source, and any attempt by clients
+ * to call e_source_remote_delete() will fail.
+ *
+ * Unlike the #ESource:removable and #ESource:writable properties, this
+ * is enforced for both clients of the registry D-Bus server and within
+ * the registry D-Bus service itself.
+ *
+ * Since: 3.6
+ **/
+void
+e_server_side_source_set_remote_deletable (EServerSideSource *source,
+                                           gboolean remote_deletable)
+{
+	EDBusSourceRemoteDeletable *dbus_interface = NULL;
+	GDBusObject *dbus_object;
+	gboolean currently_remote_deletable;
+
+	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
+
+	currently_remote_deletable =
+		e_source_get_remote_deletable (E_SOURCE (source));
+
+	if (remote_deletable == currently_remote_deletable)
+		return;
+
+	if (remote_deletable) {
+		dbus_interface =
+			e_dbus_source_remote_deletable_skeleton_new ();
+
+		g_signal_connect (
+			dbus_interface, "handle-delete",
+			G_CALLBACK (server_side_source_remote_delete_cb),
+			source);
+	}
+
+	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
+	e_dbus_object_skeleton_set_source_remote_deletable (
+		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
+	g_object_unref (dbus_object);
+
+	if (dbus_interface != NULL)
+		g_object_unref (dbus_interface);
+
+	g_object_notify (G_OBJECT (source), "remote-deletable");
+}
+
diff --git a/libebackend/e-server-side-source.h b/libebackend/e-server-side-source.h
index cdb5277..e9f71df 100644
--- a/libebackend/e-server-side-source.h
+++ b/libebackend/e-server-side-source.h
@@ -109,6 +109,12 @@ void		e_server_side_source_set_removable
 void		e_server_side_source_set_writable
 						(EServerSideSource *source,
 						 gboolean writable);
+void		e_server_side_source_set_remote_creatable
+						(EServerSideSource *source,
+						 gboolean remote_creatable);
+void		e_server_side_source_set_remote_deletable
+						(EServerSideSource *source,
+						 gboolean remote_deletable);
 
 G_END_DECLS
 



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