changeset 26686:ff33b65b2448

Iteratively expand the disco tree as prompted by the UI. Walking the entire tree automatically = bad. This doesn't really work yet. The UI needs to be updated to support the little expandy things like on the buddy list. It doesn't crash, though, and retrieves the first level.
author Paul Aurich <paul@darkrain42.org>
date Tue, 14 Apr 2009 06:54:44 +0000
parents 6b3a23ecbb42
children 217a3ad87fc4
files libpurple/dbus-analyze-functions.py libpurple/disco.c libpurple/disco.h libpurple/protocols/jabber/disco.c
diffstat 4 files changed, 164 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/dbus-analyze-functions.py	Mon Apr 13 16:54:25 2009 +0000
+++ b/libpurple/dbus-analyze-functions.py	Tue Apr 14 06:54:44 2009 +0000
@@ -32,8 +32,10 @@
     "purple_connection_new_unregister",
 
     # Similar to all the above:
+    "purple_disco_list_set_service_close_func",
     "purple_disco_list_set_cancel_func",
     "purple_disco_list_set_protocol_data",
+    "purple_disco_list_set_expand_func",
     "purple_disco_list_set_register_func",
 
     # This is excluded because this script treats PurpleLogReadFlags*
--- a/libpurple/disco.c	Mon Apr 13 16:54:25 2009 +0000
+++ b/libpurple/disco.c	Tue Apr 14 06:54:44 2009 +0000
@@ -49,6 +49,10 @@
 	struct {
 		PurpleDiscoCancelFunc cancel_cb;
 		PurpleDiscoCloseFunc close_cb; /**< Callback to free the prpl data */
+		PurpleDiscoServiceCloseFunc service_close_cb;
+		PurpleDiscoServiceExpandFunc expand_cb; /**< Expand a service (iteratively
+		                                             look for things that are
+		                                             "sub-elements" in the tree */
 		PurpleDiscoRegisterFunc register_cb;
 	} ops;
 };
@@ -61,8 +65,10 @@
 	gchar *name; /**< The name of the service. */
 	gchar *description; /**< The name of the service. */
 
+	gpointer proto_data;
+
+	gchar *gateway_type; /**< The type of the gateway service. */
 	PurpleDiscoServiceType type; /**< The type of service. */
-	gchar *gateway_type; /**< The type of the gateway service. */
 	PurpleDiscoServiceFlags flags;
 };
 
@@ -96,6 +102,9 @@
 
 static void purple_disco_list_service_destroy(PurpleDiscoList *list, PurpleDiscoService *r)
 {
+	if (list->ops.service_close_cb)
+		list->ops.service_close_cb(r);
+
 	g_free(r->name);
 	g_free(r->description);
 	g_free(r->gateway_type);
@@ -147,8 +156,9 @@
 		ops->add_service(list, service, parent);
 }
 
-PurpleDiscoService *purple_disco_list_service_new(PurpleDiscoServiceType type, const gchar *name,
-		const gchar *description, PurpleDiscoServiceFlags flags)
+PurpleDiscoService *purple_disco_list_service_new(PurpleDiscoServiceType type,
+		const gchar *name, const gchar *description,
+		PurpleDiscoServiceFlags flags, gpointer proto_data)
 {
 	PurpleDiscoService *s;
 
@@ -160,6 +170,7 @@
 	s->type = type;
 	s->description = g_strdup(description);
 	s->flags = flags;
+	s->proto_data = proto_data;
 
 	return s;
 }
@@ -191,6 +202,24 @@
 	purple_disco_list_set_in_progress(list, FALSE);
 }
 
+void purple_disco_service_expand(PurpleDiscoService *service)
+{
+	PurpleDiscoList *list;
+
+	g_return_if_fail(service != NULL);
+	g_return_if_fail((service->flags & PURPLE_DISCO_BROWSE) == PURPLE_DISCO_BROWSE);
+
+	list = service->list;
+
+	if (list->ops.expand_cb)
+		list->ops.expand_cb(list, service);
+	else
+		purple_debug_warning("disco", "Cannot expand %s for account %s, "
+		                              "protocol did not provide expand op.\n",
+		                     service->name,
+		                     purple_account_get_username(list->account));
+}
+
 void purple_disco_service_register(PurpleDiscoService *service)
 {
 	PurpleDiscoList *list;
@@ -205,6 +234,11 @@
 
 	if (list->ops.register_cb)
 		list->ops.register_cb(pc, service);
+	else
+		purple_debug_warning("disco", "Cannot register to %s for account %s, "
+		                              "protocol did not provide register op.\n",
+		                     service->name,
+		                     purple_account_get_username(list->account));
 }
 
 const gchar *purple_disco_service_get_name(PurpleDiscoService *service)
@@ -221,6 +255,14 @@
 	return service->description;
 }
 
+gpointer
+purple_disco_service_get_protocol_data(PurpleDiscoService *service)
+{
+	g_return_val_if_fail(service != NULL, NULL);
+
+	return service->proto_data;
+}
+
 PurpleDiscoServiceType
 purple_disco_service_get_type(PurpleDiscoService *service)
 {
@@ -315,6 +357,14 @@
 	return list->proto_data;
 }
 
+void purple_disco_list_set_service_close_func(PurpleDiscoList *list,
+                                              PurpleDiscoServiceCloseFunc cb)
+{
+	g_return_if_fail(list != NULL);
+
+	list->ops.service_close_cb = cb;
+}
+
 void purple_disco_list_set_cancel_func(PurpleDiscoList *list, PurpleDiscoCancelFunc cb)
 {
 	g_return_if_fail(list != NULL);
@@ -322,6 +372,12 @@
 	list->ops.cancel_cb = cb;
 }
 
+void purple_disco_list_set_expand_func(PurpleDiscoList *list, PurpleDiscoServiceExpandFunc cb)
+{
+	g_return_if_fail(list != NULL);
+	list->ops.expand_cb = cb;
+}
+
 void purple_disco_list_set_register_func(PurpleDiscoList *list, PurpleDiscoRegisterFunc cb)
 {
 	g_return_if_fail(list != NULL);
--- a/libpurple/disco.h	Mon Apr 13 16:54:25 2009 +0000
+++ b/libpurple/disco.h	Tue Apr 14 06:54:44 2009 +0000
@@ -52,6 +52,10 @@
  * @param list  The disco list.
  */
 typedef void (*PurpleDiscoCloseFunc)(PurpleDiscoList *list);
+typedef void (*PurpleDiscoServiceCloseFunc)(PurpleDiscoService *service);
+
+typedef void (*PurpleDiscoServiceExpandFunc)(PurpleDiscoList *list,
+                                             PurpleDiscoService *service);
 
 /**
  * A prpl callback called to initiate registration with the specificed
@@ -172,7 +176,8 @@
 PurpleDiscoService *
 purple_disco_list_service_new(PurpleDiscoServiceType type, const gchar *name,
                               const gchar *description,
-                              PurpleDiscoServiceFlags flags);
+                              PurpleDiscoServiceFlags flags,
+                              gpointer proto_data);
 
 /**
  * Add service to list
@@ -180,6 +185,19 @@
 void purple_disco_list_service_add(PurpleDiscoList *list, PurpleDiscoService *service, PurpleDiscoService *parent);
 
 /**
+ * Expand a (browsable) service. The UI should call this in order to
+ * iteratively browse the children of this service. The service must
+ * have the PURPLE_DISCO_BROWSE flag set.
+ *
+ * You probably don't want to call this if the service already has children.
+ *
+ * @param service  The browsable disco service.
+ *
+ * @since TODO
+ */
+void purple_disco_service_expand(PurpleDiscoService *service);
+
+/**
  * Register service
  * @param service The service that will be registered
  */
@@ -206,6 +224,18 @@
 const gchar* purple_disco_service_get_description(PurpleDiscoService *service);
 
 /**
+ * Returns the service's protocol-specific data.
+ *
+ * This should only be called from the associated prpl.
+ *
+ * @param service The disco service.
+ * @return        The protocol data.
+ *
+ * @since TODO
+ */
+gpointer purple_disco_service_get_protocol_data(PurpleDiscoService *service);
+
+/**
  * Return a service's type.
  *
  * @param service The service.
@@ -350,8 +380,14 @@
  */
 gpointer purple_disco_list_get_protocol_data(PurpleDiscoList *list);
 
-void purple_disco_list_set_cancel_func(PurpleDiscoList *list, PurpleDiscoCancelFunc cb);
-void purple_disco_list_set_register_func(PurpleDiscoList *list, PurpleDiscoRegisterFunc cb);
+void purple_disco_list_set_service_close_func(PurpleDiscoList *list,
+                                              PurpleDiscoServiceCloseFunc cb);
+void purple_disco_list_set_cancel_func(PurpleDiscoList *list,
+                                       PurpleDiscoCancelFunc cb);
+void purple_disco_list_set_expand_func(PurpleDiscoList *list,
+                                       PurpleDiscoServiceExpandFunc cb);
+void purple_disco_list_set_register_func(PurpleDiscoList *list,
+                                         PurpleDiscoRegisterFunc cb);
 
 /**
  * Sets the UI operations structure to be used in all purple service discovery.
--- a/libpurple/protocols/jabber/disco.c	Mon Apr 13 16:54:25 2009 +0000
+++ b/libpurple/protocols/jabber/disco.c	Tue Apr 14 06:54:44 2009 +0000
@@ -54,12 +54,17 @@
 }
 
 struct jabber_disco_list_data {
-	JabberStream *js;
+	JabberStream *js; /* TODO: Needed? */
 	PurpleDiscoList *list;
 	char *server;
 	int fetch_count;
 };
 
+struct jabber_disco_service_data {
+	char *jid;
+	char *node;
+};
+
 static void
 jabber_disco_bytestream_server_cb(JabberStream *js, const char *from,
                                   JabberIqType type, const char *id,
@@ -761,6 +766,7 @@
 	PurpleDiscoService *parent, *service;
 	PurpleDiscoServiceType service_type;
 	PurpleDiscoServiceFlags flags;
+	struct jabber_disco_service_data *service_data;
 
 	disco_data = data;
 	list_data = disco_data->list_data;
@@ -773,10 +779,8 @@
 
 	--list_data->fetch_count;
 
-	if (list_data->list == NULL) {
-		if (list_data->fetch_count == 0)
-			jabber_disco_list_data_destroy(list_data);
-
+	if (!purple_disco_list_get_in_progress(list)) {
+		purple_disco_list_unref(list);
 		return;
 	}
 
@@ -818,8 +822,13 @@
 	else
 		aname = g_strdup(from);
 
+	service_data = g_new0(struct jabber_disco_service_data, 1);
+	service_data->jid = g_strdup(from);
+	if (anode)
+		service_data->node = g_strdup(anode);
+
 	service = purple_disco_list_service_new(service_type, aname,
-			xmlnode_get_attrib(identity, "name"), flags);
+			xmlnode_get_attrib(identity, "name"), flags, service_data);
 	g_free(aname);
 
 	if (service_type == PURPLE_DISCO_SERVICE_TYPE_GATEWAY)
@@ -829,24 +838,11 @@
 
 	purple_disco_list_service_add(list, service, parent);
 
-	/* if (flags & PURPLE_DISCO_FLAG_BROWSE) - not all browsable services have this feature */
-	{
-		++list_data->fetch_count;
-		purple_disco_list_ref(list);
-		disco_data = g_new0(struct _disco_data, 1);
-		disco_data->list_data = list_data;
-		disco_data->parent = service;
-
-		jabber_disco_items_do(js, from, node, jabber_disco_service_items_cb,
-		                      disco_data);
-	}
-
 	if (list_data->fetch_count == 0)
 		purple_disco_list_set_in_progress(list, FALSE);
 
 	purple_disco_list_unref(list);
 
-	g_free(aname);
 	g_free(node);
 }
 
@@ -859,16 +855,12 @@
 	xmlnode *query, *child;
 	gboolean has_items = FALSE;
 
-	if (!from || type == JABBER_IQ_ERROR)
-		return;
-
 	list_data = data;
 	--list_data->fetch_count;
 
-	if (list_data->list == NULL) {
-		if (list_data->fetch_count == 0)
-			jabber_disco_list_data_destroy(list_data);
-
+	if (!from || type == JABBER_IQ_ERROR ||
+			!purple_disco_list_get_in_progress(list_data->list)) {
+		purple_disco_list_unref(list_data->list);
 		return;
 	}
 
@@ -968,24 +960,50 @@
 }
 
 static void
+jabber_disco_service_close(PurpleDiscoService *service)
+{
+	struct jabber_disco_service_data *data;
+
+	data = purple_disco_service_get_protocol_data(service);
+	g_free(data->jid);
+	g_free(data->node);
+	g_free(data);
+}
+
+#if 0
+static void
 jabber_disco_cancel(PurpleDiscoList *list)
 {
-	struct jabber_disco_list_data *list_data = purple_disco_list_get_protocol_data(list);
-	purple_disco_list_set_protocol_data(list, NULL, NULL);
+	/* This space intentionally letft blank */
+}
+#endif
+
+static void
+jabber_disco_list_expand(PurpleDiscoList *list, PurpleDiscoService *service)
+{
+	PurpleAccount *account;
+	PurpleConnection *pc;
+	JabberStream *js;
+	struct jabber_disco_list_data *list_data;
+	struct jabber_disco_service_data *service_data;
+	struct _disco_data *disco_data;
 
-	if (list_data->fetch_count == 0) {
-		/* Nothing outstanding, just free it now... */
-		jabber_disco_list_data_destroy(list_data);
-	} else {
-		int i;
-		/* Lose all our references to the PurpleDiscoList */
-		for (i = 0; i < list_data->fetch_count; ++i) {
-			purple_disco_list_unref(list);
-		}
+	account = purple_disco_list_get_account(list);
+	pc = purple_account_get_connection(account);
+	js = purple_connection_get_protocol_data(pc);
+
+	list_data = purple_disco_list_get_protocol_data(list);
 
-		/* We'll free list_data when fetch_count is down to 0 */
-		list_data->list = NULL;
-	}
+	++list_data->fetch_count;
+	purple_disco_list_ref(list);
+	disco_data = g_new0(struct _disco_data, 1);
+	disco_data->list_data = list_data;
+	disco_data->parent = service;
+
+	service_data = purple_disco_service_get_protocol_data(service);
+
+	jabber_disco_items_do(js, service_data->jid, service_data->node,
+	                      jabber_disco_service_items_cb, disco_data);
 }
 
 static void
@@ -1014,8 +1032,13 @@
 	disco_list_data = g_new0(struct jabber_disco_list_data, 1);
 	disco_list_data->list = list;
 	disco_list_data->js = js;
-	purple_disco_list_set_protocol_data(list, disco_list_data, disco_proto_data_destroy_cb);
+	purple_disco_list_set_protocol_data(list, disco_list_data,
+	                                    disco_proto_data_destroy_cb);
+	purple_disco_list_set_service_close_func(list, jabber_disco_service_close);
+#if 0
 	purple_disco_list_set_cancel_func(list, jabber_disco_cancel);
+#endif
+	purple_disco_list_set_expand_func(list, jabber_disco_list_expand);
 	purple_disco_list_set_register_func(list, jabber_disco_service_register);
 
 	purple_request_input(gc, _("Server name request"), _("Enter an XMPP Server"),