cpw.gillux.detachablepurple: 024d1924: Rewritten the "GetBuddyList" D-Bus metho...

gillux at soc.pidgin.im gillux at soc.pidgin.im
Sun May 20 13:20:53 EDT 2012


----------------------------------------------------------------------
Revision: 024d19242602fd188011bbb4d9849e65b8d4a10f
Parent:   1cceaeb7d3d76f2a6a6a424a65cef49fe8fb2cf9
Author:   gillux at soc.pidgin.im
Date:     05/20/12 12:45:05
Branch:   im.pidgin.cpw.gillux.detachablepurple
URL: http://d.pidgin.im/viewmtn/revision/info/024d19242602fd188011bbb4d9849e65b8d4a10f

Changelog: 

Rewritten the "GetBuddyList" D-Bus method for the new gdbus-based API.
Much more simpler and cleaner. :)

Changes against parent 1cceaeb7d3d76f2a6a6a424a65cef49fe8fb2cf9

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

-------------- next part --------------
============================================================
--- libpurple/blist.c	5c60239af51f3caae935f756237bc680520cae71
+++ libpurple/blist.c	408e31c454e4cd726b961dac67e33bb005469af1
@@ -25,6 +25,7 @@
 
 #include "internal.h"
 #include "accountlist.h"
+#include "blist.h"
 #include "dbus-maybe.h"
 #include "dbus/blist.h"
 #include "debug.h"
@@ -398,7 +399,7 @@ purple_blist_load()
 
 	/* In remote mode, get the buddy list from the daemon instead. */
 	if (purple_core_is_remote_mode())
-		return purple_blist_load_RPC();
+		return purple_blist_load_RPC(PURPLE_OBJECT(PURPLE_BLIST));
 
 	purple = purple_util_read_xml_from_file("blist.xml", _("buddy list"));
 
============================================================
--- libpurple/dbus/constructor.c	541fbb8647299455e608f15334fa3c8a84b4a82c
+++ libpurple/dbus/constructor.c	cc724c41d602cddceb2a3cd1e347e8c623912b37
@@ -351,14 +351,21 @@ purple_constructor_foreach_pobjects(GVar
 	GVariantIter iter;
 	GVariant *array, *pobject;
 
-	g_variant_get(box, "(@a(oa(sv)))", &array);
+	/* Some callers may box the variant in a tuple, while others may not. */
+	if (g_variant_type_is_tuple(g_variant_get_type(box)))
+		g_variant_get(box, "(@a(oa(sv)))", &array);
+	else
+		array = box;
 
 	g_variant_iter_init(&iter, array);
 	while ((pobject = g_variant_iter_next_value(&iter)) != NULL) {
 		treatment(pobject, user_data);
 		g_variant_unref(pobject);
 	}
-	g_variant_unref(array);
+
+	/* Only free the array if it has been unpacked. */
+	if (array != box)
+		g_variant_unref(array);
 }
 
 /**
============================================================
--- libpurple/dbus/blist.c	59804fdab8fca26208b4df3adf127547847e4921
+++ libpurple/dbus/blist.c	6176cc9fe81b5dc805f584063830973f792c87e2
@@ -26,55 +26,18 @@
 #include "blist-node.h"
 #include "core.h"
 #include "dbus/blist.h"
-#include "dbus/blist-client.h"
 #include "dbus/blist.xml.h"
+#include "dbus/constructor.h"
 #include "dbus-maybe.h"
 #include "dbus-purple.h"
 
+/* The type PurpleBuddyList is only defined in libpurple/blist.c. While we
+ * don't strictly need it, we use it here and there for the sake of
+ * consistency. Hence this dummy type definition: */
+typedef void PurpleBlist;
 
-/* Server side dbus methods.
- * Theses functions needs PurpleBListDBus declared, and must go before the
- * inclusion of blist-server.h, in which they are defined. */
-gboolean DBUS_purple_blist_get_buddy_list(PurpleBListDBus *blist, GPtrArray **groups, GPtrArray **contacts, GPtrArray **buddies, GPtrArray **chats, GError** error);
-#include "dbus/blist-server.h"
+static GVariant * purple_blist_get_buddy_list(PurpleBlist *blist);
 
-/* DBus transfered data formats */
-#define DBUS_PURPLE_BLIST_SETTING \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID) \
-)
-#define DBUS_PURPLE_BLIST_SETTINGS \
-( \
-	dbus_g_type_get_collection("GPtrArray", \
-		DBUS_PURPLE_BLIST_SETTING) \
-)
-#define DBUS_PURPLE_GROUP_PACK \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, G_TYPE_STRING, DBUS_PURPLE_BLIST_SETTINGS, \
-		G_TYPE_INVALID) \
-)
-#define DBUS_PURPLE_CONTACT_PACK \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, \
-		DBUS_PURPLE_BLIST_SETTINGS, G_TYPE_INVALID) \
-)
-#define DBUS_PURPLE_BUDDY_PACK \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, \
-		G_TYPE_STRING, DBUS_PURPLE_BLIST_SETTINGS, G_TYPE_INVALID) \
-)
-#define DBUS_PURPLE_CHAT_PACK \
-( \
-	dbus_g_type_get_struct("GValueArray", \
-		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, \
-		DBUS_TYPE_G_STRING_STRING_HASHTABLE, G_TYPE_STRING, \
-		DBUS_PURPLE_BLIST_SETTINGS, G_TYPE_INVALID) \
-)
-
 /* A convenience macro. */
 #define parent_node_dbus_path(node) purple_object_get_dbus_path(PURPLE_OBJECT(purple_blist_node_parent(node)))
 
@@ -105,222 +68,37 @@ purple_blist_class_dbus_init(PurpleObjec
 	pobjclass->build_dbus_path = purple_blist_build_dbus_path;
 
 	if (purple_core_is_daemon_mode()) {
+		/* D-Bus method handlers. */
+		purple_object_bind_dbus_callback
+		  (pobjclass, purple_blist_interface_info.name,
+		   "GetBuddyList", (GCallback)purple_blist_get_buddy_list);
 	}
 }
 
 /**
- * Callback used by settings_to_ptr_array().
- * Builds a DBUS_PURPLE_BLIST_SETTING struct, to export a setting on dbus.
+ * Recursive function. Goes through the buddy list and fills the
+ * GVariantBuilders from what it encounters.
  */
 static void
-blist_setting_to_array(const char *name, GValue *value, GPtrArray *settings)
+pack_node(PurpleBlistNode *node,
+          GVariantBuilder *groups,  GVariantBuilder *contacts,
+          GVariantBuilder *buddies, GVariantBuilder *chats)
 {
-	GValue setting = {0, };
-	gboolean ok;
-
-	g_value_init(&setting, DBUS_PURPLE_BLIST_SETTING);
-	g_value_take_boxed(&setting,
-	         dbus_g_type_specialized_construct(DBUS_PURPLE_BLIST_SETTING));
-	ok = dbus_g_type_struct_set(&setting, 0, name, 1, value, G_MAXUINT);
-
-	g_return_if_fail(ok == TRUE);
-	g_ptr_array_add(settings, g_value_get_boxed(&setting));
-}
-
-/**
- * Converts the settings of the provided PurpleBlistNode into a
- * DBUS_PURPLE_BLIST_SETTINGS GPtrArray (array of GValues), to export them on
- * dbus. Caller is responsible for freeing the array and the GValues in it.
- * Used to pack data in DBUS_purple_blist_get_buddy_list().
- */
-static GPtrArray *
-settings_to_ptr_array(PurpleBlistNode *node)
-{
-	GPtrArray *array;
-	GHashTable *settings_hash;
-
-	array = g_ptr_array_new();
-	settings_hash = purple_blist_node_get_settings(PURPLE_BLIST_NODE(node));
-	g_hash_table_foreach(settings_hash,
-	                     (GHFunc)blist_setting_to_array, array);
-	return array;
-}
-
-/**
- * Packs a PurpleGroup in a DBUS_PURPLE_GROUP_PACK struct,
- * to export it on dbus, and append it in the provided groups array.
- * Used to pack data in DBUS_purple_blist_get_buddy_list().
- */
-static void
-pack_group(GPtrArray *groups, PurpleGroup *group)
-{
-	GValue group_pack = {0, };
-	gboolean ok;
-	char *group_path;
-	const char *group_name;
-	GPtrArray *settings_pack;
-
-	g_value_init(&group_pack, DBUS_PURPLE_GROUP_PACK);
-	g_value_set_boxed(&group_pack,
-	            dbus_g_type_specialized_construct(DBUS_PURPLE_GROUP_PACK));
-
-	group_path = purple_object_get_dbus_path(PURPLE_OBJECT(group));
-	group_name = purple_group_get_name(group);
-	settings_pack = settings_to_ptr_array(PURPLE_BLIST_NODE(group));
-	ok = dbus_g_type_struct_set(&group_pack,
-	                            0, group_path,
-	                            1, group_name,
-	                            2, settings_pack, G_MAXUINT);
-
-	g_ptr_array_foreach(settings_pack, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(settings_pack, TRUE);
-
-	g_return_if_fail(ok == TRUE);
-	g_ptr_array_add(groups, g_value_get_boxed(&group_pack));
-}
-
-/**
- * Packs a PurpleContact in a DBUS_PURPLE_CONTACT_PACK struct,
- * to export it on dbus, and append it in the provided contacts array.
- * Used to pack data in DBUS_purple_blist_get_buddy_list().
- */
-static void
-pack_contact(GPtrArray *contacts, PurpleContact *contact)
-{
-	GValue contact_pack = {0, };
-	gboolean ok;
-	char* contact_path;
-	const char *alias;
-	char *parent_path;
-	GPtrArray *settings_pack;
-
-	g_value_init(&contact_pack, DBUS_PURPLE_CONTACT_PACK);
-	g_value_set_boxed(&contact_pack,
-	          dbus_g_type_specialized_construct(DBUS_PURPLE_CONTACT_PACK));
-
-	contact_path = purple_object_get_dbus_path(PURPLE_OBJECT(contact));
-	alias = purple_contact_get_alias(contact);
-	parent_path = parent_node_dbus_path(PURPLE_BLIST_NODE(contact));
-	settings_pack = settings_to_ptr_array(PURPLE_BLIST_NODE(contact));
-	ok = dbus_g_type_struct_set(&contact_pack,
-	                            0, contact_path,
-	                            1, alias,
-	                            2, parent_path,
-	                            3, settings_pack, G_MAXUINT);
-
-	g_ptr_array_foreach(settings_pack, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(settings_pack, TRUE);
-
-	g_return_if_fail(ok == TRUE);
-	g_ptr_array_add(contacts, g_value_get_boxed(&contact_pack));
-}
-
-/**
- * Packs a PurpleBuddy in a DBUS_PURPLE_BUDDY_PACK struct,
- * to export it on dbus, and append it in the provided buddies array.
- * Used to pack data in DBUS_purple_blist_get_buddy_list().
- */
-static void
-pack_buddy(GPtrArray *buddies, PurpleBuddy *buddy)
-{
-	GValue buddy_pack = {0, };
-	gboolean ok;
-	char *buddy_path;
-	char *account_path;
-	const char *name;
-	const char *alias;
-	char *parent_path;
-	GPtrArray *settings_pack;
-
-	g_value_init(&buddy_pack, DBUS_PURPLE_BUDDY_PACK);
-	g_value_set_boxed(&buddy_pack,
-	          dbus_g_type_specialized_construct(DBUS_PURPLE_BUDDY_PACK));
-
-	buddy_path   = purple_object_get_dbus_path(PURPLE_OBJECT(buddy));
-	account_path = purple_object_get_dbus_path(
-	                      PURPLE_OBJECT(purple_buddy_get_account(buddy)));
-	name  = purple_buddy_get_name(buddy);
-	alias = purple_buddy_get_alias_only(buddy);
-	parent_path = parent_node_dbus_path(PURPLE_BLIST_NODE(buddy));
-	settings_pack = settings_to_ptr_array(PURPLE_BLIST_NODE(buddy));
-	ok = dbus_g_type_struct_set(&buddy_pack,
-	                            0, buddy_path,
-	                            1, account_path,
-	                            2, name,
-	                            3, alias,
-	                            4, parent_path,
-	                            5, settings_pack, G_MAXUINT);
-
-	g_ptr_array_foreach(settings_pack, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(settings_pack, TRUE);
-
-	g_return_if_fail(ok == TRUE);
-	g_ptr_array_add(buddies, g_value_get_boxed(&buddy_pack));
-}
-
-/**
- * Packs a PurpleChat in a DBUS_PURPLE_CHAT_PACK struct,
- * to export it on dbus, and append it in the provided chats array.
- * Used to pack data in DBUS_purple_blist_get_buddy_list().
- */
-static void
-pack_chat(GPtrArray *chats, PurpleChat *chat)
-{
-	GValue chat_pack = {0, };
-	gboolean ok;
-	char *chat_path;
-	char *account_path;
-	const char *alias;
-	GHashTable *components;
-	char *parent_path;
-	GPtrArray *settings_pack;
-
-	g_value_init(&chat_pack, DBUS_PURPLE_CHAT_PACK);
-	g_value_set_boxed(&chat_pack,
-	          dbus_g_type_specialized_construct(DBUS_PURPLE_CHAT_PACK));
-
-	chat_path    = purple_object_get_dbus_path(PURPLE_OBJECT(chat));
-	account_path = purple_object_get_dbus_path(
-	                        PURPLE_OBJECT(purple_chat_get_account(chat)));
-	alias        = purple_chat_get_alias(chat);
-	components   = purple_chat_get_components(chat);
-	parent_path  = parent_node_dbus_path(PURPLE_BLIST_NODE(chat));
-	settings_pack = settings_to_ptr_array(PURPLE_BLIST_NODE(chat));
-	ok = dbus_g_type_struct_set(&chat_pack,
-	                            0, chat_path,
-	                            1, account_path,
-	                            2, alias,
-	                            3, components,
-	                            4, parent_path,
-	                            5, settings_pack, G_MAXUINT);
-
-	g_ptr_array_foreach(settings_pack, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(settings_pack, TRUE);
-
-	g_return_if_fail(ok == TRUE);
-	g_ptr_array_add(chats, g_value_get_boxed(&chat_pack));
-}
-
-/**
- * Recursive function. Goes through the buddy list and fills the GPtrArrays
- * from what it encounter.
- * Used to pack data in purple_blist_get_buddy_list_RPC().
- */
-static void
-pack_node(PurpleBlistNode *node, GPtrArray *groups, GPtrArray *contacts,
-          GPtrArray *buddies, GPtrArray *chats)
-{
 	PurpleBlistNode *child;
 
 	while (node) {
 		if (PURPLE_IS_GROUP(node)) {
-			pack_group(groups, PURPLE_GROUP(node));
+			g_variant_builder_add_value
+			  (groups, purple_constructor_pack_pobject(node));
 		} else if(PURPLE_IS_CONTACT(node)) {
-			pack_contact(contacts, PURPLE_CONTACT(node));
+			g_variant_builder_add_value
+			  (contacts, purple_constructor_pack_pobject(node));
 		} else if(PURPLE_IS_BUDDY(node)) {
-		    pack_buddy(buddies, PURPLE_BUDDY(node));
+			g_variant_builder_add_value
+			  (buddies, purple_constructor_pack_pobject(node));
 		} else if(PURPLE_IS_CHAT(node)) {
-		    pack_chat(chats, PURPLE_CHAT(node));
+			g_variant_builder_add_value
+			  (chats, purple_constructor_pack_pobject(node));
 		}
 
 		child = purple_blist_node_first_child(node);
@@ -331,279 +109,76 @@ pack_node(PurpleBlistNode *node, GPtrArr
 	}
 }
 
-gboolean
-DBUS_purple_blist_get_buddy_list(PurpleBListDBus *blist, GPtrArray **groups,
-                                 GPtrArray **contacts, GPtrArray **buddies,
-                                 GPtrArray **chats, GError** error)
+static GVariant *
+purple_blist_get_buddy_list(PurpleBlist *blist)
 {
-        PurpleBlistNode *node;
+	GVariantBuilder groups, contacts, buddies, chats;
+	PurpleBlistNode *root = purple_blist_get_root();
+	const gchar *root_path = NULL;
 
-	*groups   = g_ptr_array_new();
-	*contacts = g_ptr_array_new();
-	*buddies  = g_ptr_array_new();
-	*chats    = g_ptr_array_new();
-	node = purple_blist_get_root();
-	pack_node(purple_blist_get_root(),
-	          *groups, *contacts, *buddies, *chats);
-	return TRUE;
-}
+	g_variant_builder_init(&groups,   (const GVariantType *) "a(oa(sv))");
+	g_variant_builder_init(&contacts, (const GVariantType *) "a(oa(sv))");
+	g_variant_builder_init(&buddies,  (const GVariantType *) "a(oa(sv))");
+	g_variant_builder_init(&chats,    (const GVariantType *) "a(oa(sv))");
 
-static void
-set_blist_setting(GValueArray* box, GHashTable *settings)
-{
-	GValue val = {0, };
-	gboolean ok;
-	char *name = NULL;
-	GValue *value;
+	pack_node(purple_blist_get_root(),
+	          &groups, &contacts, &buddies, &chats);
+	if (root)
+		root_path = purple_object_get_dbus_path(PURPLE_OBJECT(root));
 
-	g_value_init(&val, DBUS_PURPLE_BLIST_SETTING);
-	g_value_set_boxed(&val, box);
-	ok = dbus_g_type_struct_get(&val, 0, &name, 1, &value, G_MAXUINT);
-	if (ok)
-		g_hash_table_replace(settings, g_strdup(name),
-		                     purple_g_value_slice_dup(value));
-	g_free(name);
-	g_value_unset(&val);
-	g_value_unset(value);
+	return g_variant_new("(@a(oa(sv))"  /* groups    */
+	                      "@a(oa(sv))"  /* contacts  */
+	                      "@a(oa(sv))"  /* buddies   */
+	                      "@a(oa(sv))"  /* chats     */
+	                      "o)",         /* root node */
+	                     g_variant_builder_end(&groups),
+	                     g_variant_builder_end(&contacts),
+	                     g_variant_builder_end(&buddies),
+	                     g_variant_builder_end(&chats),
+	                     root_path);
 }
 
-static void
-set_blist_settings(PurpleBlistNode *node, GPtrArray *settings)
-{
-	g_ptr_array_foreach(settings, (GFunc)set_blist_setting,
-	                     purple_blist_node_get_settings(node));
-}
-
-static void
-unpack_groups_cb(GValueArray* box)
-{
-	GValue val = {0, };
-	PurpleGroup *group;
-	PurpleRunningMode mode;
-	gboolean ok;
-	char *group_path = NULL;
-	char *group_name = NULL;
-	GPtrArray *settings = NULL;
-
-	/* Each group consists of a DBUS_PURPLE_GROUP_PACK */
-	g_value_init(&val, DBUS_PURPLE_GROUP_PACK);
-	g_value_set_boxed(&val, box);
-	ok = dbus_g_type_struct_get(&val,
-	                            0, &group_path,
-	                            1, &group_name,
-	                            2, &settings, G_MAXUINT);
-	
-	if (ok && group_path[0] && group_name[0]) {
-		/* Temporarly go in mirror mode and create a local group. */
-		mode = purple_core_get_running_mode();
-		purple_core_set_running_mode(PURPLE_RUN_MIRROR_MODE);
-		group = purple_group_new(group_name);
-		purple_object_install_dbus_infos(PURPLE_OBJECT(group),
-		                             DBUS_GROUP_INTERFACE, group_path);
-		set_blist_settings(PURPLE_BLIST_NODE(group), settings);
-		purple_core_set_running_mode(mode);
-	} else {
-		purple_debug_warning("dbus", "GetBuddyList: received an invalid group\n");
-	}
-
-	g_free(group_path);
-	g_free(group_name);
-	g_ptr_array_foreach(settings, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(settings, TRUE);
-	g_value_unset(&val);
-	g_value_array_free(box);
-}
-
-
-static void
-unpack_contacts_cb(GValueArray* box)
-{
-	GValue val = {0, };
-	PurpleContact *contact;
-	PurpleRunningMode mode;
-	gboolean ok;
-	GObject *parent;
-	char *contact_path = NULL;
-	char *alias = NULL;
-	char *parent_path = NULL;
-	GPtrArray *settings = NULL;
-
-	/* Each contact consists of a DBUS_PURPLE_CONTACT_PACK */
-	g_value_init(&val, DBUS_PURPLE_CONTACT_PACK);
-	g_value_set_boxed(&val, box);
-	ok = dbus_g_type_struct_get(&val,
-	                            0, &contact_path,
-	                            1, &alias,
-	                            2, &parent_path,
-	                            3, &settings, G_MAXUINT);
-
-	if (ok && contact_path[0]) {
-		/* Temporarly go in mirror mode, and create a local contact. */
-		mode = purple_core_get_running_mode();
-		purple_core_set_running_mode(PURPLE_RUN_MIRROR_MODE);
-		contact = purple_contact_new();
-		purple_object_install_dbus_infos(PURPLE_OBJECT(contact),
-		                         DBUS_CONTACT_INTERFACE, contact_path);
-		parent = purple_dbus_get_gobject_by_path(parent_path);
-		if (parent)
-			purple_blist_node_add_child(PURPLE_BLIST_NODE(parent),
-			                            PURPLE_BLIST_NODE(contact));
-		if (alias[0])
-			purple_blist_alias_contact(contact, alias);
-		set_blist_settings(PURPLE_BLIST_NODE(contact), settings);
-		purple_core_set_running_mode(mode);
-	} else {
-		purple_debug_warning("dbus", "GetBuddyList: received an invalid contact\n");
-	}
-
-	g_free(contact_path);
-	g_free(alias);
-	g_free(parent_path);
-	g_ptr_array_foreach(settings, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(settings, TRUE);
-	g_value_unset(&val);
-	g_value_array_free(box);
-}
-
-static void
-unpack_buddies_cb(GValueArray* box)
-{
-	GValue val = {0, };
-	PurpleBuddy *buddy;
-	PurpleRunningMode mode;
-	gboolean ok;
-	GObject *parent;
-	GObject *account;
-	char *buddy_path = NULL;
-	char *account_path = NULL;
-	char *name = NULL;
-	char *alias = NULL;
-	char *parent_path = NULL;
-	GPtrArray *settings = NULL;
-
-	/* Each buddy consists of a DBUS_PURPLE_BUDDY_PACK */
-	g_value_init(&val, DBUS_PURPLE_BUDDY_PACK);
-	g_value_set_boxed(&val, box);
-	ok = dbus_g_type_struct_get(&val,
-	                            0, &buddy_path,
-	                            1, &account_path,
-	                            2, &name,
-	                            3, &alias,
-	                            4, &parent_path,
-	                            5, &settings, G_MAXUINT);
-
-	if (ok && account_path[0])
-		account = purple_dbus_get_gobject_by_path(account_path);
-	if (ok && buddy_path[0] && PURPLE_IS_ACCOUNT(account)) {
-		/* Temporarly go in mirror mode, and create a local buddy. */
-		mode = purple_core_get_running_mode();
-		purple_core_set_running_mode(PURPLE_RUN_MIRROR_MODE);
-		parent = purple_dbus_get_gobject_by_path(parent_path);
-		buddy = purple_buddy_new(PURPLE_ACCOUNT(account), name, alias,
-		                         PURPLE_BLIST_NODE(parent));
-		purple_object_install_dbus_infos(PURPLE_OBJECT(buddy),
-		                         DBUS_BUDDY_INTERFACE, buddy_path);
-		purple_core_set_running_mode(mode);
-		set_blist_settings(PURPLE_BLIST_NODE(buddy), settings);
-	} else {
-		purple_debug_warning("dbus", "GetBuddyList: received an invalid buddy\n");
-	}
-
-	g_free(buddy_path);
-	g_free(account_path);
-	g_free(name);
-	g_free(alias);
-	g_free(parent_path);
-	g_ptr_array_foreach(settings, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(settings, TRUE);
-	g_value_unset(&val);
-	g_value_array_free(box);
-}
-
-static void
-unpack_chats_cb(GValueArray* box)
-{
-	GValue val = {0, };
-	PurpleChat *chat;
-	PurpleRunningMode mode;
-	gboolean ok;
-	GObject *parent;
-	GObject *account;
-	char *chat_path = NULL;
-	char *account_path = NULL;
-	char *alias = NULL;
-	GHashTable *components = NULL;
-	char *parent_path = NULL;
-	GPtrArray *settings = NULL;
-
-	/* Each chat consists of a DBUS_PURPLE_CHAT_PACK */
-	g_value_init(&val, DBUS_PURPLE_CHAT_PACK);
-	g_value_set_boxed(&val, box);
-	ok = dbus_g_type_struct_get(&val,
-	                            0, &chat_path,
-	                            1, &account_path,
-	                            2, &alias,
-	                            3, &components,
-	                            4, &parent_path,
-	                            5, &settings, G_MAXUINT);
-
-	if (ok && account_path[0])
-		account = purple_dbus_get_gobject_by_path(account_path);
-	if (ok && chat_path[0] && PURPLE_IS_ACCOUNT(account) && components) {
-		/* Temporarly go in mirror mode, and create a local chat. */
-		mode = purple_core_get_running_mode();
-		purple_core_set_running_mode(PURPLE_RUN_MIRROR_MODE);
-		parent = purple_dbus_get_gobject_by_path(parent_path);
-		chat = purple_chat_new(PURPLE_ACCOUNT(account), alias,
-		                       components);
-		purple_object_install_dbus_infos(PURPLE_OBJECT(chat),
-		                         DBUS_CHAT_INTERFACE, chat_path);
-		if (parent)
-			purple_blist_node_add_child(PURPLE_BLIST_NODE(parent),
-			                            PURPLE_BLIST_NODE(chat));
-		purple_core_set_running_mode(mode);
-		set_blist_settings(PURPLE_BLIST_NODE(chat), settings);
-	} else {
-		purple_debug_warning("dbus", "GetChatList: received an invalid chat\n");
-	}
-
-	g_free(chat_path);
-	g_free(account_path);
-	g_free(alias);
-	g_hash_table_destroy(components);
-	g_free(parent_path);
-	g_ptr_array_foreach(settings, (GFunc)g_value_array_free, NULL);
-	g_ptr_array_free(settings, TRUE);
-	g_value_unset(&val);
-	g_value_array_free(box);
-}
-
 void
-purple_blist_load_RPC(void)
+purple_blist_load_RPC(PurpleObject *blist)
 {
-	PurpleBListDBus *blist = purple_blist_dbus_get_instance();
-	DBusGProxy *proxy = purple_object_get_dbus_obj_proxy(PURPLE_OBJECT(blist));
-	GError *error = NULL;
-	GPtrArray *groups;
-	GPtrArray *contacts;
-	GPtrArray *buddies;
-	GPtrArray *chats;
+	GVariant *groups, *contacts, *buddies, *chats, *root, *ret;
 
 	/* In remote mode the buddy list is already loaded by the daemon.
 	 * We need get it here.
 	 */
-	if(!im_pidgin_purple_blist_get_buddy_list(proxy, &groups, &contacts,
-	                                          &buddies, &chats, &error)) {
-		PURPLE_RPC_FAILED(purple_blist_load, error);
-		return;
-	}
+	ret = purple_object_dbus_call(blist, purple_blist_interface_info.name,
+	                              "GetBuddyList");
+	if (!ret)
+		return; /* Likely a connection problem. */
 
-	g_ptr_array_foreach(groups,   (GFunc)unpack_groups_cb,   NULL);
-	g_ptr_array_foreach(contacts, (GFunc)unpack_contacts_cb, NULL);
-	g_ptr_array_foreach(buddies,  (GFunc)unpack_buddies_cb,  NULL);
-	g_ptr_array_foreach(chats,    (GFunc)unpack_chats_cb,    NULL);
-	g_ptr_array_free(groups,   TRUE);
-	g_ptr_array_free(contacts, TRUE);
-	g_ptr_array_free(buddies,  TRUE);
-	g_ptr_array_free(chats,    TRUE);
+	g_variant_get(ret, "(@a(oa(sv))"  /* groups    */
+	                    "@a(oa(sv))"  /* contacts  */
+	                    "@a(oa(sv))"  /* buddies   */
+	                    "@a(oa(sv))"  /* chats     */
+	                    "@o)",        /* root node */
+	                    &groups, &contacts, &buddies, &chats, &root);
+	/* This one is a bit tricky because these classes are all child
+	 * of the PurpleBlistNode class, which holds a bunch of
+	 * cross-referenced properties: each blist node have a parent,
+	 * a child, a next and a prev object reference property.
+	 * These properties are converted to/from dbus path names when
+	 * they are got/set. Therefore, during the creation of these
+	 * objects, some of their links will not be resolved.
+	 * To solve this problem, we first create the objects and
+	 * then reload their object reference properties. */
+	purple_constructor_load_pobjs_unsync(groups,   PURPLE_TYPE_GROUP);
+	purple_constructor_load_pobjs_unsync(contacts, PURPLE_TYPE_CONTACT);
+	purple_constructor_load_pobjs_unsync(buddies,  PURPLE_TYPE_BUDDY);
+	purple_constructor_load_pobjs_unsync(chats,    PURPLE_TYPE_CHAT);
+
+	purple_constructor_reload_pobjs_objpath_props(groups);
+	purple_constructor_reload_pobjs_objpath_props(contacts);
+	purple_constructor_reload_pobjs_objpath_props(buddies);
+	purple_constructor_reload_pobjs_objpath_props(chats);
+
+	/* Now we've got all the blist nodes, maybe we can reference
+	 * one of them as the root node. */
+	purple_object_set_dbus_property(blist, "root", root);
+
+	g_variant_unref(ret);
 }
============================================================
--- libpurple/dbus/blist.h	deaab5b09e0ca6fa5bf600c25df96ad036e2e4af
+++ libpurple/dbus/blist.h	793372e20c51411bae373d2403355c410b2c4bcf
@@ -38,14 +38,14 @@ void purple_blist_class_dbus_init(Purple
  * but since this type is only defined in libpurple/blist.c, we use the
  * upper-class instead.
  */
-void purple_blist_load_RPC(void);
+void purple_blist_load_RPC(PurpleObject *blist);
 
 G_END_DECLS
 
 #else /* !HAVE_DBUS */
 
 #define purple_blist_class_dbus_init(klass)                      ((void)0)
-#define purple_blist_load_RPC()                                  ((void)0)
+#define purple_blist_load_RPC(blist)                             ((void)0)
 
 #endif /* HAVE_DBUS */
 #endif /* _PURPLE_DBUS_BLIST_H */
============================================================
--- libpurple/dbus/blist.xml	2010b7b838f6acea6ca8e18c21f872924ab40e7a
+++ libpurple/dbus/blist.xml	2897566e338f85d4acd0e80fe7f2d769f311e1e4
@@ -1,24 +1,16 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <node>
 	<interface name="im.pidgin.purple.blist">
+		<property type="o" name="root" access="read" />
+
 		<method name="GetBuddyList">
-			<!-- group: s = group path name; s = group name;
-			            a(sv) = settings -->
-			<arg type="a(ssa(sv))" name="groups" direction="out" />
-			<!-- contact: s = contact path name; s = alias;
-			              s = parent path name; a(sv) = settings -->
-			<arg type="a(sssa(sv))" name="contacts"
-			     direction="out" />
-			<!-- buddy: s = buddy path name; s = account; s = name;
-			            s = alias; s = parent path name;
-			            a(sv) = settings -->
-			<arg type="a(sssssa(sv))" name="buddies"
-			     direction="out" />
-			<!-- chat: s = chat path name; s = account; s = alias;
-			           a{ss} = components; s = parent path name;
-			           a(sv) = settings -->
-			<arg type="a(sssa{ss}sa(sv))" name="chats"
-			     direction="out" />
+			<!--  a(           o           a(      s       v))
+			objects^  dbus-path^  properties^  name^  value^ -->
+			<arg type="a(oa(sv))" name="groups"   direction="out" />
+			<arg type="a(oa(sv))" name="contacts" direction="out" />
+			<arg type="a(oa(sv))" name="buddies"  direction="out" />
+			<arg type="a(oa(sv))" name="chats"    direction="out" />
+			<arg type="o"         name="rootnode" direction="out" />
 		</method>
 	</interface>
 </node>


More information about the Commits mailing list