cpw.gillux.detachablepurple: f53ace82: Rewritten the GetAllAccounts D-Bus metho...

gillux at soc.pidgin.im gillux at soc.pidgin.im
Sat May 12 16:56:48 EDT 2012


----------------------------------------------------------------------
Revision: f53ace8239cc403b8c3b0f96ea236cdf2eb3f123
Parent:   d463ee6521874098ff99fcd5585b9ed4ae453739
Author:   gillux at soc.pidgin.im
Date:     05/12/12 16:13:24
Branch:   im.pidgin.cpw.gillux.detachablepurple
URL: http://d.pidgin.im/viewmtn/revision/info/f53ace8239cc403b8c3b0f96ea236cdf2eb3f123

Changelog: 

Rewritten the GetAllAccounts D-Bus method implementation of
PurpleConstructor. It's now GVariant-based, simpler and cleaner. :-)

Changes against parent d463ee6521874098ff99fcd5585b9ed4ae453739

  patched  libpurple/dbus/constructor.c
  patched  libpurple/dbus/constructor.xml

-------------- next part --------------
============================================================
--- libpurple/dbus/constructor.c	1380e91ead82f2ac7053453f30fca9072c48dd88
+++ libpurple/dbus/constructor.c	c23b1c484d68df283c332481d25003b7da7fe34f
@@ -34,6 +34,8 @@
 #include "debug.h"
 #include "marshallers.h"
 
+#include "glib-2.30.h" /* g_dbus_gvariant_to_gvalue() */
+
 /**
  * PurpleConstructor, a dummy class to remotely create and load gobjects over DBus.
  *
@@ -59,23 +61,6 @@ G_DEFINE_TYPE(PurpleConstructor, purple_
 
 G_DEFINE_TYPE(PurpleConstructor, purple_constructor, PURPLE_TYPE_OBJECT)
 
-/* DBus transfered data formats */
-#define DBUS_STRUCT_PROPERTY \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID) \
-)
-#define DBUS_COLLECTION_PROPS \
-( \
-	dbus_g_type_get_collection("GPtrArray", \
-		DBUS_STRUCT_PROPERTY) \
-)
-#define DBUS_STRUCT_ACCOUNT \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, DBUS_COLLECTION_PROPS, G_TYPE_INVALID) \
-)
-
 static GVariant* purple_constructor_get_all_accounts(void);
 
 static char*
@@ -114,6 +99,8 @@ static void purple_constructor_class_ini
 	/* Both client and daemon can build this well-known name. */
 	pobjclass->build_dbus_path = purple_constructor_build_dbus_path;
 	if (purple_core_is_daemon_mode()) {
+		purple_object_bind_dbus_callback(pobjclass, "GetAllAccounts",
+		                                 (GCallback)purple_constructor_get_all_accounts);
 		/**
 		 * Add dbus stuff to this gobject.
 		 */
@@ -188,279 +175,167 @@ DBUS_purple_constructor_new_account(Purp
 	}
 }
 
-/**
- * A callback used in pack_accounts_cb().
- * Packs the given prop_name named property into a
- * { prop_name, prop_gvalue } dbus structure and append it in props_pack.
+/* Creates a new proxy gobject of type_name, initializing its properties with
+ * what's in props, and sets its object path to dbus_path.
  */
-static void
-pack_account_prop_cb(char *prop_name, PurpleAccount *acc, GPtrArray *props_pack)
+static gpointer
+purple_constructor_new_proxy_object(gchar *type_name, char *dbus_path, GVariant *props)
 {
-	GValue prop = {0, };
-	GValue prop_val = {0, };
-	GValue prop_val2 = {0, };
-	GParamSpec *prop_spec;
-	gboolean ok;
+	GType type;
+	GParameter *params;
+	guint n_params, i = 0;
+	GVariantIter iter;
+	GVariant *prop;
+	const gchar *prop_name;
+	GVariant *prop_value;
+	gpointer object;
 
-	/* Each property consists of a DBUS_STRUCT_PROPERTY */
-	g_value_init(&prop, DBUS_STRUCT_PROPERTY);
-	g_value_take_boxed(&prop, dbus_g_type_specialized_construct(
-			DBUS_STRUCT_PROPERTY));
+	/* Retreive the type. */
+	type = g_type_from_name(type_name);
+	g_return_val_if_fail(type != 0, NULL);
 
-	/* First find out the property GType */
-	prop_spec = g_object_class_find_property(G_OBJECT_GET_CLASS(acc),
-						prop_name);
-	g_return_if_fail(prop_spec != NULL);
-	g_value_init(&prop_val, G_PARAM_SPEC_VALUE_TYPE(prop_spec));
-	/* Then get it */
-	g_object_get_property(G_OBJECT(acc), prop_name,	&prop_val);
+	/* Parse the given properties and build the parmas array. */
+	g_variant_iter_init(&iter, props);
+	n_params = g_variant_iter_n_children(&iter);
+	params = g_new0(GParameter, n_params);
+	while ((prop = g_variant_iter_next_value(&iter)) != NULL && i < n_params) {
+		g_variant_get(prop, "(sv)", &prop_name, &prop_value);
+		params[i].name = prop_name;
 
-	if (G_VALUE_HOLDS_OBJECT(&prop_val)) {
-		/* Convert gobjects into dbus path names. */
-		g_value_init(&prop_val2, G_TYPE_STRING);
-		g_value_transform(&prop_val, &prop_val2);
-	} else {
-		/* Regular value. */
-		g_value_init(&prop_val2, G_VALUE_TYPE(&prop_val));
-		g_value_copy(&prop_val, &prop_val2);
+		/* Maybe convert object path names into object references. */
+		if (g_variant_is_of_type(prop_value, G_VARIANT_TYPE_OBJECT_PATH)) {
+			const gchar *path = g_variant_get_string(prop_value, NULL);
+			GObject *obj = purple_dbus_get_gobject_by_path(path);
+			g_value_init(&params[i].value, G_TYPE_OBJECT);
+			g_value_set_object(&params[i].value, obj);
+		} else {
+			g_dbus_gvariant_to_gvalue(prop_value, &params[i].value);
+		}
+		i++;
+
+		g_variant_unref(prop_value);
+		g_variant_unref(prop);
 	}
-	g_value_unset(&prop_val);
 
-	/* Setup the DBus struct, with our extracted data */
-	ok = dbus_g_type_struct_set(&prop,
-				0, prop_name,
-				1, &prop_val2,
-				G_MAXUINT);
-	g_value_unset(&prop_val2);
-	g_return_if_fail(ok == TRUE);
+	/* Create this object with the given properties. */
+	object = g_object_newv(type, n_params, params);
 
-	/* Finally append this fresh struct to the array */
-	g_ptr_array_add(props_pack, g_value_get_boxed(&prop));
+	/* Free all these temporary data. */
+	while (n_params--) {
+		g_free((gchar*)params[n_params].name);
+		g_value_unset(&params[n_params].value);
+	}
+	g_free(params);
+
+	return object;
 }
 
-/**
- * A callback used in DBUS_purple_constructor_get_all_accounts().
- * Packs the given acc account into a { dbus_path, protocol_id, account_struct }
- * dbus structure and append it in accounts_pack.
- */
-static void
-pack_accounts_cb(PurpleAccount *acc, GPtrArray *accounts_pack, GPtrArray *exported_props)
+/* Packs all the exported properties of a PurpleObject into an a(sv) GVariant. */
+static GVariant*
+pack_pobject_properties(PurpleObject *pobject)
 {
-	GValue acc_props = {0, };
+	GVariantBuilder builder;
+	GParamSpec *pspec;
+	GVariant *prop;
+	GDBusPropertyInfo **props_info;
 	char *prop_name;
-	GPtrArray* props_pack = g_ptr_array_new();
-	int i;
-	gboolean ok;
 
-	g_return_if_fail(props_pack != NULL);
+	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+	props_info = PURPLE_OBJECT_GET_CLASS(pobject)->dbus_ifaceinfo->properties;
+	for (; *props_info; props_info++) {
+		prop_name = (*props_info)->name;
+		if (!prop_name)
+			continue;
 
-	/* Each account consists of a DBUS_STRUCT_ACCOUNT */
-	g_value_init(&acc_props, DBUS_STRUCT_ACCOUNT);
-	g_value_set_boxed(&acc_props,
-			dbus_g_type_specialized_construct(DBUS_STRUCT_ACCOUNT));
+		pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(pobject)),
+		                                     prop_name);
+		if (!pspec)
+			continue;
 
-	/* Fill props_pack with every property of acc */
-	for (i = 0; i < exported_props->len; i++) {
-		prop_name = exported_props->pdata[i];
-		pack_account_prop_cb(prop_name, acc, props_pack);
+		prop = purple_object_get_dbus_property(pobject, prop_name);
+		if (!prop)
+			continue;
+		prop = g_variant_new("(sv)", prop_name, prop);
+		g_variant_builder_add_value(&builder, prop);
 	}
-
-	/* Setup the DBus struct, with our extracted data */
-	ok = dbus_g_type_struct_set(&acc_props,
-				0, purple_account_get_protocol_id(acc),
-				1, props_pack,
-				G_MAXUINT);
-	g_ptr_array_foreach(props_pack, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(props_pack, TRUE);
-	g_return_if_fail(ok == TRUE);
-
-	/* Finally append this fresh struct to the array */
-	g_ptr_array_add(accounts_pack, g_value_get_boxed(&acc_props));
+	return g_variant_builder_end(&builder);
 }
 
-/**
- * This is what is actually called when someone calls the dbus method
- * GetAllAccounts. It packs the accounts and their properties in the
- * glib-dbus data format.
- */
-gboolean
-DBUS_purple_constructor_get_all_accounts(PurpleConstructor* con, GPtrArray** accounts, GError** error)
+static GVariant*
+pack_account(PurpleAccount *account)
 {
-	PurpleAccount *acc;
-	GPtrArray *exported_props = NULL;
-	GList *glist_accs;
-	char *interface;
-
-	/* We send an array of accounts. The complete data format, as
-	 * defined in dbus-constructor.h, is something like :
-	 * GPtrArray *account = [
-	 *     struct {
-	 *         char      *protocol_id; // Needed to properly g_object_new()
-	 *         GPtrArray *properties [
-	 *             struct {
-	 *                char   *property_name;
-	 *                GValue *property_value; 
-	 *             }
-	 *         ];
-	 *     }
-	 * ]
-	 */
-	*accounts = g_ptr_array_new();
-	g_return_val_if_fail(*accounts != NULL, FALSE);
-
-	/* Fill *accounts with every account */
-	glist_accs = purple_accounts_all();
-	for (; glist_accs; glist_accs = glist_accs->next) {
-		acc = glist_accs->data;
-
-		if (!exported_props) {
-			/* Grab all the properties names */
-			interface = purple_object_get_dbus_obj_interface(PURPLE_OBJECT(acc));
-			exported_props = purple_object_get_dbus_props(
-				PURPLE_TYPE_ACCOUNT, interface);
-
-		}
-		pack_accounts_cb(acc, *accounts, exported_props);
-	}
-	g_ptr_array_foreach(exported_props, (GFunc)g_free, NULL);
-	g_ptr_array_free(exported_props, TRUE);
-
-	return TRUE;
+	PurpleObject *pobj = PURPLE_OBJECT(account);
+	return g_variant_new("(o at a(sv))",
+	                     purple_object_get_dbus_path(pobj),
+	                     pack_pobject_properties(pobj));
 }
 
-/**
- * A callback used in load_accounts_cb().
- * Unpacks the { prop_name, prop_gvalue } dbus structure and set
- * the prop_name property in the given account.
- */
+/* Unpacks a GVariant-packed account and creates local PurpleAccounts
+ * that will act as proxy objects. */
 static void
-load_account_prop_cb(GValueArray* box, PurpleAccount* account)
+load_account(GVariant *account)
 {
-	char* prop_name;
-	GValue value_box = {0, };
-	GValue *prop_val;
-	GValue prop_val2 = {0, };
-	GParamSpec *pspec;
+	PurpleAccount *paccount;
+	GVariant *props;
+	gchar *dbus_path;
 
-	/* Each property consists of a DBUS_STRUCT_PROPERTY */
-	g_value_init(&value_box, DBUS_STRUCT_PROPERTY);
-	g_value_set_boxed(&value_box, box);
+	g_variant_get(account, "(o at a(sv))", &dbus_path, &props);
 
-	dbus_g_type_struct_get(&value_box, 0, &prop_name, 1, &prop_val,
-			G_MAXUINT);
+	paccount = purple_constructor_new_proxy_object("PurpleAccount", dbus_path, props);
+	g_variant_unref(props);
 
-	pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(account),
-										prop_name);
-	g_value_init(&prop_val2, G_PARAM_SPEC_VALUE_TYPE(pspec));			
-	if (G_TYPE_IS_OBJECT(G_PARAM_SPEC_VALUE_TYPE(pspec))
-		&& G_VALUE_HOLDS_STRING(prop_val)) {
-		/* Convert dbus path names into gobjects. */
-		g_value_transform(prop_val, &prop_val2);
-	} else {
-		/* Regular value. */
-		g_value_copy(prop_val, &prop_val2);
-	}
-	g_object_set_property(G_OBJECT(account), prop_name, prop_val);
+	purple_object_set_dbus_path(PURPLE_OBJECT(paccount), dbus_path);
+	g_free(dbus_path);
 
-	g_free(prop_name);
-	g_value_unset(&value_box);
-	g_value_unset(prop_val);
+	purple_account_dbus_init(paccount);
+	/* This signal will add our new account in the account list. */
+	g_signal_emit_by_name(G_OBJECT(paccount), "new");
+	purple_object_set_synchronized(PURPLE_OBJECT(paccount), TRUE);	
 }
 
 /**
- * A helper function used in DBUS_purple_constructor_get_all_accounts().
- * Finds a property named prop_name in prop_array array of structs.
+ * This is what is actually executed on the daemon side when someone calls
+ * the dbus method GetAllAccounts. It packs the accounts and their properties
+ * in the gdbus data format.
  */
-static GValue*
-get_prop_by_name(GPtrArray *prop_array, char *prop_name)
+static GVariant*
+purple_constructor_get_all_accounts(void)
 {
-	int i;
-	GValue val = {0, };
-	GValue value_box = {0, };
+	GVariantBuilder builder;
+	GList *all = purple_accounts_all();;
 
-	g_value_init(&value_box, DBUS_STRUCT_PROPERTY);
-	g_value_init(&val, G_TYPE_STRING);
-
-	for (i = 0; i < prop_array->len; i++) {
-		g_value_set_boxed(&value_box, prop_array->pdata[i]);
-		dbus_g_type_struct_get_member(&value_box, 0, &val);
-		if (purple_strequal(g_value_get_string(&val), prop_name)) {
-			g_value_unset(&val);
-			g_value_init(&val, G_TYPE_VALUE);
-			dbus_g_type_struct_get_member(&value_box, 1, &val);
-			g_value_unset(&value_box);
-			return g_value_get_boxed(&val);
-		}
+	/* Pack every account into an array of accounts. */
+	g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+	while (all) {
+		PurpleAccount *account = all->data;
+		g_variant_builder_add_value(&builder, pack_account(account));
+		all = all->next;
 	}
-	g_value_unset(&value_box);
-	return NULL;
+	return g_variant_new("(@a(oa(sv)))", g_variant_builder_end(&builder));
 }
 
 /**
- * A callback used in purple_accounts_get_all_RPC().
- * Unpacks the { dbus_path, protocol_id, account_struct } dbus structure and construct
- * a new account based on these informations.
+ * This is what a client calls when it wants to call the dbus method
+ * GetAllAccounts. It unpacks the gdbus formatted data and creates proxy
+ * PurpleAccounts.
  */
-static void
-load_accounts_cb(GValueArray* box)
-{
-	GValue val = {0, };
-	PurpleAccount *acc;
-	char *protocol_id;
-	GPtrArray *prop_array;
-	GValue *username;
-	PurpleRunningMode mode;
-
-	/* Each account consists of a DBUS_STRUCT_ACCOUNT */
-	g_value_init(&val, DBUS_STRUCT_ACCOUNT);
-	g_value_set_boxed(&val, box);
-	dbus_g_type_struct_get(&val,
-		0, &protocol_id, 1, &prop_array, G_MAXUINT);
-
-	/* First get the username, it is needed to construct the account */
-	username = get_prop_by_name(prop_array, "username");
-	if (!username) {
-		purple_debug_warning("dbus",
-			"Couldn't load the account: username not found\n");
-		return;
-	}
-	/* Temporarly go in mirror mode, and it will create a local account */
-	mode = purple_core_get_running_mode();
-	purple_core_set_running_mode(PURPLE_RUN_MIRROR_MODE);
-	acc = purple_account_new(g_value_get_string(username), protocol_id);
-
-	/* Then load the others properties. Keep the mirror mode here,
-	 * otherwise it will try to remotely set the properties.
-	 */
-	g_ptr_array_foreach(prop_array, (GFunc)load_account_prop_cb, acc);
-	purple_core_set_running_mode(mode);
-
-	g_free(protocol_id);
-	g_value_unset(username);
-	g_ptr_array_free(prop_array, TRUE);
-	g_value_unset(&val);
-	g_value_array_free(box);
-}
-
 void
 purple_accounts_get_all_RPC(void)
 {
 	PurpleConstructor* con = purple_constructor_get_instance();
-	DBusGProxy *proxy = purple_object_get_dbus_obj_proxy(PURPLE_OBJECT(con));
-	GError *error = NULL;
-	GPtrArray* accounts;
+	GVariant *ret, *accounts, *account;
+	GVariantIter iter;
 
-	/* In remote mode accounts are already loaded by the daemon.
-	 * We need to get those here.
-	 */
-	if(!im_pidgin_purple_constructor_get_all_accounts(proxy, &accounts, &error)) {
-		PURPLE_RPC_FAILED(purple_constructor_get_all_accounts, error);
-		return;
+	/* Download all the accounts. */
+	ret = purple_object_dbus_call(PURPLE_OBJECT(con), "GetAllAccounts");
+	g_variant_get(ret, "(@a(oa(sv)))", &accounts);
+
+	/* Unpack all this data. */
+	g_variant_iter_init(&iter, accounts);
+	while ((account = g_variant_iter_next_value(&iter)) != NULL) {
+		load_account(account);
+		g_variant_unref(account);
 	}
-
-	g_ptr_array_foreach(accounts, (GFunc)load_accounts_cb, NULL);
-	purple_debug_info("dbus",
-			"Loaded %i remote account(s).\n", accounts->len);
-
-	g_ptr_array_free(accounts, TRUE);
+	purple_debug_info("dbus", "Loaded %d accounts.\n", g_variant_n_children(accounts));
+	g_variant_unref(accounts);
 }
============================================================
--- libpurple/dbus/constructor.xml	89633f956f700cee79554af90843fcbcc5802810
+++ libpurple/dbus/constructor.xml	cc0ef12d7ab746dee94647f3630be6b242af8ff5
@@ -8,7 +8,7 @@
 			<arg type="s" name="protocol_id" direction="in" />
 		</method>
 		<method name="GetAllAccounts">
-			<arg type="a(sa(sv))" name="accounts" direction="out" />
+			<arg type="a(oa(sv))" name="accounts" direction="out" />
 		</method>
 
 		<signal name="PurpleConnectionCreated">


More information about the Commits mailing list