cpw.darkrain42.xmpp.disco: acd50e52: Applied disco-2.patch from nops with som...

paul at darkrain42.org paul at darkrain42.org
Sat Apr 25 16:17:20 EDT 2009


-----------------------------------------------------------------
Revision: acd50e528b205cc80e237fab9fa2a2452fc52a22
Ancestor: 81bb2e1582a2222b36e57c29ccb573dac27f2a44
Author: paul at darkrain42.org
Date: 2009-03-29T19:29:22
Branch: im.pidgin.cpw.darkrain42.xmpp.disco
URL: http://d.pidgin.im/viewmtn/revision/info/acd50e528b205cc80e237fab9fa2a2452fc52a22

Modified files:
        libpurple/Makefile.am libpurple/Makefile.mingw
        libpurple/protocols/jabber/disco.c
        libpurple/protocols/jabber/disco.h
        libpurple/protocols/jabber/jabber.c
        libpurple/protocols/jabber/jabber.h
        libpurple/protocols/jabber/libxmpp.c libpurple/prpl.h
        libpurple/purple.h.in pidgin/Makefile.am
        pidgin/Makefile.mingw pidgin/gtkblist.c pidgin/gtkmain.c

ChangeLog: 

Applied disco-2.patch from nops with some modifications:
  * Alphabetized includes and Makefiles
  * Removed purple_disco_set_ui_ops(NULL) in finch; ops is NULL by default.
  * A few string changes
  * Removed DISCO_PREF_LAST_SERVER. Default to our server, but store
    the last requested in the JabberStream* and use it if available.

-------------- next part --------------
============================================================
--- libpurple/Makefile.am	61213f767b7d79292ab663c5890e53521842e0a0
+++ libpurple/Makefile.am	beb0ac7e5f35b97931a601617632cca0ba02f13b
@@ -46,6 +46,7 @@ purple_coresources = \
 	core.c \
 	debug.c \
 	desktopitem.c \
+	disco.c \
 	eventloop.c \
 	ft.c \
 	idle.c \
@@ -103,6 +104,7 @@ purple_coreheaders = \
 	dbus-maybe.h \
 	debug.h \
 	desktopitem.h \
+	disco.h \
 	eventloop.h \
 	ft.h \
 	gaim-compat.h \
@@ -165,7 +167,7 @@ dbus_exported = dbus-useful.h dbus-defin
 dbus_headers  = dbus-bindings.h dbus-purple.h dbus-server.h dbus-useful.h dbus-define-api.h dbus-types.h
 
 dbus_exported = dbus-useful.h dbus-define-api.h account.h blist.h buddyicon.h \
-                connection.h conversation.h core.h ft.h log.h notify.h prefs.h roomlist.h \
+                connection.h conversation.h core.h disco.h ft.h log.h notify.h prefs.h roomlist.h \
                 savedstatuses.h smiley.h status.h server.h util.h xmlnode.h prpl.h
 
 purple_build_coreheaders = $(addprefix $(srcdir)/, $(purple_coreheaders)) \
============================================================
--- libpurple/Makefile.mingw	3342db43f09afb0e082aeec557b87013f9c55a8b
+++ libpurple/Makefile.mingw	35451849c5b9dbc4d35450de9069185561db984e
@@ -40,6 +40,7 @@ C_SRC =	\
 			conversation.c \
 			core.c \
 			debug.c \
+			disco.c \
 			dnsquery.c \
 			dnssrv.c \
 			eventloop.c \
============================================================
--- libpurple/protocols/jabber/disco.c	7e64a652e2d52e714087a102194f694263a367ef
+++ libpurple/protocols/jabber/disco.c	86f9ac3c500cf6ebac969f8c0390a3b50f7009c6
@@ -1,5 +1,5 @@
 /*
- * purple - Jabber Protocol Plugin
+ * purple - Jabber Service Discovery
  *
  * Copyright (C) 2003, Nathan Walp <faceprint at faceprint.com>
  *
@@ -22,6 +22,8 @@
 #include "internal.h"
 #include "prefs.h"
 #include "debug.h"
+#include "request.h"
+#include "notify.h"
 
 #include "buddy.h"
 #include "google.h"
@@ -32,8 +34,9 @@
 #include "roster.h"
 #include "pep.h"
 #include "adhoccommands.h"
+#include "xdata.h"
+#include "libpurple/disco.h"
 
-
 struct _jabber_disco_info_cb_data {
 	gpointer data;
 	JabberDiscoInfoCallback *callback;
@@ -268,6 +271,8 @@ void jabber_disco_info_parse(JabberStrea
 					capabilities |= JABBER_CAP_IQ_REGISTER;
 				else if(!strcmp(var, "http://www.xmpp.org/extensions/xep-0199.html#ns"))
 					capabilities |= JABBER_CAP_PING;
+				else if(!strcmp(var, "http://jabber.org/protocol/disco#items"))
+					capabilities |= JABBER_CAP_ITEMS;
 				else if(!strcmp(var, "http://jabber.org/protocol/commands")) {
 					capabilities |= JABBER_CAP_ADHOC;
 				}
@@ -311,7 +316,8 @@ void jabber_disco_info_parse(JabberStrea
 	}
 }
 
-void jabber_disco_items_parse(JabberStream *js, xmlnode *packet) {
+void jabber_disco_items_parse(JabberStream *js, xmlnode *packet)
+{
 	const char *from = xmlnode_get_attrib(packet, "from");
 	const char *type = xmlnode_get_attrib(packet, "type");
 
@@ -396,6 +402,12 @@ jabber_disco_finish_server_info_result_c
 
 }
 
+struct _disco_data {
+	PurpleDiscoList *list;
+	PurpleDiscoService *parent;
+	char *node;
+};
+
 static void
 jabber_disco_server_info_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
 {
@@ -558,4 +570,371 @@ void jabber_disco_info_do(JabberStream *
 	jabber_iq_send(iq);
 }
 
+static PurpleDiscoServiceCategory
+jabber_disco_category_from_string(const gchar *str)
+{
+	if (!strcasecmp(str, "gateway"))
+		return PURPLE_DISCO_SERVICE_CAT_GATEWAY;
+	else if (!strcasecmp(str, "directory"))
+		return PURPLE_DISCO_SERVICE_CAT_DIRECTORY;
+	else if (!strcasecmp(str, "conference"))
+		return PURPLE_DISCO_SERVICE_CAT_MUC;
 
+	return PURPLE_DISCO_SERVICE_CAT_NONE;
+}
+
+static PurpleDiscoServiceType
+jabber_disco_type_from_string(const gchar *str)
+{
+	if (!strcasecmp(str, "xmpp"))
+		return PURPLE_DISCO_SERVICE_TYPE_XMPP;
+	else if (!strcasecmp(str, "icq"))
+		return PURPLE_DISCO_SERVICE_TYPE_ICQ;
+	else if (!strcasecmp(str, "mrim"))
+		return PURPLE_DISCO_SERVICE_TYPE_MAIL;
+	else if (!strcasecmp(str, "user"))
+		return PURPLE_DISCO_SERVICE_TYPE_USER;
+	else if (!strcasecmp(str, "yahoo"))
+		return PURPLE_DISCO_SERVICE_TYPE_YAHOO;
+	else if (!strcasecmp(str, "irc"))
+		return PURPLE_DISCO_SERVICE_TYPE_IRC;
+	else if (!strcasecmp(str, "gadu-gadu"))
+		return PURPLE_DISCO_SERVICE_TYPE_GG;
+	else if (!strcasecmp(str, "aim"))
+		return PURPLE_DISCO_SERVICE_TYPE_AIM;
+	else if (!strcasecmp(str, "qq"))
+		return PURPLE_DISCO_SERVICE_TYPE_QQ;
+	else if (!strcasecmp(str, "msn"))
+		return PURPLE_DISCO_SERVICE_TYPE_MSN;
+
+	return PURPLE_DISCO_SERVICE_TYPE_NONE;
+}
+
+static void
+jabber_disco_service_info_cb(JabberStream *js, xmlnode *packet, gpointer data);
+
+static void
+jabber_disco_service_items_cb(JabberStream *js, xmlnode *packet, gpointer data)
+{
+	struct _disco_data *disco_data = data;
+	PurpleDiscoList *list = disco_data->list;
+	PurpleDiscoService *parent = disco_data->parent;
+	const char *parent_node = disco_data->node;
+	xmlnode *query = xmlnode_get_child(packet, "query");
+	const char *from = xmlnode_get_attrib(packet, "from");
+	const char *result = xmlnode_get_attrib(packet, "type");
+	xmlnode *child;
+	gboolean has_items = FALSE;
+
+	purple_disco_list_set_fetch_count(list, purple_disco_list_get_fetch_count(list) - 1);
+
+	if (!from || !result || !query || (strcmp(result, "result")
+			|| !purple_disco_list_get_proto_data(list))) {
+		if (!purple_disco_list_get_fetch_count(list))
+			purple_disco_set_in_progress(list, FALSE);
+
+		purple_disco_list_unref(list);
+		return;
+	}
+
+	query = xmlnode_get_child(packet, "query");
+
+	for(child = xmlnode_get_child(query, "item"); child;
+			child = xmlnode_get_next_twin(child)) {
+		JabberIq *iq;
+		xmlnode *q;
+		const char *jid, *node;
+		struct _disco_data *disco_data;
+		char *full_node;
+
+		if(!(jid = xmlnode_get_attrib(child, "jid")) || !purple_disco_list_get_proto_data(list))
+			continue;
+
+		node = xmlnode_get_attrib(child, "node");
+
+		if (parent_node) {
+			if (node) {
+				full_node = g_new0(char, strlen(parent_node) + 1 + strlen(node) + 1);
+				strcat(full_node, parent_node);
+				strcat(full_node, "/");
+				strcat(full_node, node);
+			} else {
+				continue;
+			}
+		} else {
+			full_node = g_strdup(node);
+		}
+
+		disco_data = g_new0(struct _disco_data, 1);
+		disco_data->list = list;
+		disco_data->parent = parent;
+		disco_data->node = full_node;
+
+		has_items = TRUE;
+		purple_disco_list_set_fetch_count(list, purple_disco_list_get_fetch_count(list) + 1);
+		purple_disco_list_ref(list);
+		iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info");
+		xmlnode_set_attrib(iq->node, "to", jid);
+		if (full_node && (q = xmlnode_get_child(iq->node, "query")))
+			xmlnode_set_attrib(q, "node", full_node);
+		jabber_iq_set_callback(iq, jabber_disco_service_info_cb, disco_data);
+
+		jabber_iq_send(iq);
+	}
+
+	if (!purple_disco_list_get_fetch_count(list))
+		purple_disco_set_in_progress(list, FALSE);
+	purple_disco_list_unref(list);
+
+	g_free(disco_data->node);
+	g_free(disco_data);
+}
+
+static void
+jabber_disco_service_info_cb(JabberStream *js, xmlnode *packet, gpointer data)
+{
+	struct _disco_data *disco_data = data;
+	PurpleDiscoList *list = disco_data->list;
+	PurpleDiscoService *parent = disco_data->parent;
+	char *node = g_strdup(disco_data->node);
+	xmlnode *query, *ident, *child;
+	const char *from = xmlnode_get_attrib(packet, "from");
+	const char *result = xmlnode_get_attrib(packet, "type");
+	const char *acat, *atype, *adesc, *anode;
+	char *aname;
+	PurpleDiscoService *s;
+	PurpleDiscoServiceCategory cat;
+	PurpleDiscoServiceType type;
+	int flags = PURPLE_DISCO_FLAG_ADD;
+
+	g_free(disco_data->node);
+	g_free(disco_data);
+	purple_disco_list_set_fetch_count(list, purple_disco_list_get_fetch_count(list) - 1);
+
+	if (!from || !result || (strcmp(result, "result") || !purple_disco_list_get_proto_data(list))
+			|| (!(query = xmlnode_get_child(packet, "query")))
+			|| (!(ident = xmlnode_get_child(query, "identity")))) {
+		if (!purple_disco_list_get_fetch_count(list))
+			purple_disco_set_in_progress(list, FALSE);
+
+		purple_disco_list_unref(list);
+		return;
+	}
+
+	acat = xmlnode_get_attrib(ident, "category");
+	atype = xmlnode_get_attrib(ident, "type");
+	adesc = xmlnode_get_attrib(ident, "name");
+	anode = xmlnode_get_attrib(query, "node");
+
+	if (anode) {
+		aname = g_new0(char, strlen(from) + strlen(anode) + 1);
+		strcat(aname, from);
+		strcat(aname, anode);
+	} else {
+		aname = g_strdup(from);
+	}
+
+	cat = jabber_disco_category_from_string(acat);
+	type = jabber_disco_type_from_string(atype);
+
+	for (child = xmlnode_get_child(query, "feature"); child;
+			child = xmlnode_get_next_twin(child)) {
+		const char *var;
+
+		if (!(var = xmlnode_get_attrib(child, "var")))
+			continue;
+		
+		if (!strcmp(var, "jabber:iq:register"))
+			flags |= PURPLE_DISCO_FLAG_REGISTER;
+		
+		if (!strcmp(var, "http://jabber.org/protocol/disco#items"))
+			flags |= PURPLE_DISCO_FLAG_BROWSE;
+
+		if (!strcmp(var, "http://jabber.org/protocol/muc"))
+			cat = PURPLE_DISCO_SERVICE_CAT_MUC;
+	}
+
+	purple_debug_info("disco", "service %s, category %s (%d), type %s (%d), description %s, flags %04x\n",
+			aname,
+			acat, cat,
+			atype, type,
+			adesc, flags);
+
+	s = purple_disco_list_service_new(cat, aname, type, adesc, flags);
+	purple_disco_list_service_add(list, s, parent);
+
+	/* if (flags & PURPLE_DISCO_FLAG_BROWSE) - not all browsable services has this future */
+	{
+		xmlnode *q;
+		JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#items");
+			
+		purple_disco_list_set_fetch_count(list, purple_disco_list_get_fetch_count(list) + 1);
+		purple_disco_list_ref(list);
+		disco_data = g_new0(struct _disco_data, 1);
+		disco_data->list = list;
+		disco_data->parent = s;
+
+		xmlnode_set_attrib(iq->node, "to", from);
+		jabber_iq_set_callback(iq, jabber_disco_service_items_cb, disco_data);
+		if (anode && (q = xmlnode_get_child(iq->node, "query")))
+			xmlnode_set_attrib(q, "node", node);
+		jabber_iq_send(iq);
+	}
+
+	if (!purple_disco_list_get_fetch_count(list))
+		purple_disco_set_in_progress(list, FALSE);
+
+	purple_disco_list_unref(list);
+
+	g_free(aname);
+	g_free(node);
+}
+
+static void
+jabber_disco_server_items_cb(JabberStream *js, xmlnode *packet, gpointer data)
+{
+	PurpleDiscoList *list = data;
+	xmlnode *query, *child;
+	const char *from = xmlnode_get_attrib(packet, "from");
+	const char *type = xmlnode_get_attrib(packet, "type");
+	gboolean has_items = FALSE;
+
+	if (!from || !type)
+		return;
+
+	if (strcmp(type, "result"))
+		return;
+
+	query = xmlnode_get_child(packet, "query");
+
+	for(child = xmlnode_get_child(query, "item"); child;
+			child = xmlnode_get_next_twin(child)) {
+		JabberIq *iq;
+		const char *jid;
+		struct _disco_data *disco_data;
+
+		if(!(jid = xmlnode_get_attrib(child, "jid")) || !purple_disco_list_get_proto_data(list))
+			continue;
+
+		disco_data = g_new0(struct _disco_data, 1);
+		disco_data->list = list;
+
+		has_items = TRUE;
+		purple_disco_list_set_fetch_count(list, purple_disco_list_get_fetch_count(list) + 1);
+		purple_disco_list_ref(list);
+		iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info");
+		xmlnode_set_attrib(iq->node, "to", jid);
+		jabber_iq_set_callback(iq, jabber_disco_service_info_cb, disco_data);
+
+		jabber_iq_send(iq);
+	}
+
+	if (!has_items)
+		purple_disco_set_in_progress(list, FALSE);
+
+	purple_disco_list_unref(list);
+}
+
+static void
+jabber_disco_server_info_cb(JabberStream *js, const char *who, JabberCapabilities caps, gpointer data)
+{
+	PurpleDiscoList *list = data;
+	JabberIq *iq;
+
+	if (caps & JABBER_CAP_ITEMS) {
+		iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#items");
+		xmlnode_set_attrib(iq->node, "to", who);
+		jabber_iq_set_callback(iq, jabber_disco_server_items_cb, list);
+	
+		if (purple_disco_list_get_proto_data(list))
+			jabber_iq_send(iq);
+		else
+			purple_disco_list_unref(list);
+	
+	} else {
+		purple_notify_error(NULL, _("Error"), _("Server doesn't support service discovery"), NULL); 
+		purple_disco_set_in_progress(list, FALSE);
+		purple_disco_list_unref(list);
+	}
+}
+
+static void
+jabber_disco_server_cb(PurpleDiscoList *list, PurpleRequestFields *fields)
+{
+	JabberStream *js;
+	const char *server_name;
+
+	server_name = purple_request_fields_get_string(fields, "server");
+
+	js = purple_disco_list_get_proto_data(list);
+	if (!js) {
+		purple_debug_error("jabber", "Service discovery requested for %s "
+		                             "without proto_data", server_name);
+		return;
+	}
+
+	purple_disco_set_in_progress(list, TRUE);
+	purple_debug_misc("jabber", "Service discovery for %s\n", server_name);
+	if (js->last_disco_server)
+		g_free(js->last_disco_server);
+	js->last_disco_server = g_strdup(server_name);
+
+	jabber_disco_info_do(js, server_name, jabber_disco_server_info_cb, list);
+}
+
+void
+jabber_disco_get_list(PurpleConnection *gc, PurpleDiscoList *list)
+{
+	PurpleRequestFields *fields;
+	PurpleRequestFieldGroup *g;
+	PurpleRequestField *f;
+	JabberStream *js;
+	const char *last_server;
+	
+	purple_debug_misc("disco.c", "get_list\n");
+
+	js = purple_connection_get_protocol_data(gc);
+	purple_disco_list_set_proto_data(list, js);
+
+	last_server = js->last_disco_server;
+	if (last_server == NULL)
+		last_server = js->user->domain;
+
+
+	fields = purple_request_fields_new();
+	g = purple_request_field_group_new(NULL);
+	f = purple_request_field_string_new("server", _("Server"), 
+		last_server ? last_server : js->user->domain, FALSE);
+
+	purple_request_field_group_add_field(g, f);
+	purple_request_fields_add_group(fields, g);
+	
+	purple_disco_list_ref(list);
+	
+	purple_request_fields(gc,
+		_("Server name request"),
+		_("Enter server name"),
+		NULL,
+		fields,
+		_("OK"), G_CALLBACK(jabber_disco_server_cb),
+		_("Cancel"), NULL,
+		purple_connection_get_account(gc), NULL, NULL, list);
+}
+
+void
+jabber_disco_cancel(PurpleDiscoList *list)
+{
+	purple_disco_list_set_proto_data(list, NULL);
+	purple_disco_set_in_progress(list, FALSE);	
+}
+
+int
+jabber_disco_service_register(PurpleConnection *gc, PurpleDiscoService *service)
+{
+	JabberStream *js = gc->proto_data;
+	
+	jabber_register_gateway(js, service->name);
+
+	return 0;
+}
+
============================================================
--- libpurple/protocols/jabber/disco.h	f30f10709e0282c73ff287b1c373440f9ae41e81
+++ libpurple/protocols/jabber/disco.h	76dee344d30fd2e3a7129f5069a0df093966a37f
@@ -1,5 +1,5 @@
 /**
- * @file iq.h JabberID handlers
+ * @file disco.h Jabber Service Discovery
  *
  * purple
  *
@@ -35,4 +35,9 @@ void jabber_disco_info_do(JabberStream *
 void jabber_disco_info_do(JabberStream *js, const char *who,
 		JabberDiscoInfoCallback *callback, gpointer data);
 
+void jabber_disco_get_list(PurpleConnection *gc, PurpleDiscoList* list);
+void jabber_disco_cancel(PurpleDiscoList *list);
+
+int jabber_disco_service_register(PurpleConnection *gc, PurpleDiscoService *service);
+
 #endif /* _PURPLE_JABBER_DISCO_H_ */
============================================================
--- libpurple/protocols/jabber/jabber.c	4abd8fd2b15490137b9a692cd7eb1d2ba05ee5df
+++ libpurple/protocols/jabber/jabber.c	59e080731c22cda59df2ce02c30272f9b73b9666
@@ -1062,22 +1062,24 @@ void jabber_register_parse(JabberStream 
 	group = purple_request_field_group_new(NULL);
 	purple_request_fields_add_group(fields, group);
 
-	if(js->registration)
-		field = purple_request_field_string_new("username", _("Username"), js->user->node, FALSE);
-	else
-		field = purple_request_field_string_new("username", _("Username"), NULL, FALSE);
+	if(xmlnode_get_child(query, "username")) {
+		if(js->registration)
+			field = purple_request_field_string_new("username", _("Username"), js->user->node, FALSE);
+		else
+			field = purple_request_field_string_new("username", _("Username"), NULL, FALSE);
 
-	purple_request_field_group_add_field(group, field);
+		purple_request_field_group_add_field(group, field);
+	}
+	if(xmlnode_get_child(query, "password")) {
+		if(js->registration)
+			field = purple_request_field_string_new("password", _("Password"),
+										purple_connection_get_password(js->gc), FALSE);
+		else
+			field = purple_request_field_string_new("password", _("Password"), NULL, FALSE);
 
-	if(js->registration)
-		field = purple_request_field_string_new("password", _("Password"),
-									purple_connection_get_password(js->gc), FALSE);
-	else
-		field = purple_request_field_string_new("password", _("Password"), NULL, FALSE);
-
-	purple_request_field_string_set_masked(field, TRUE);
-	purple_request_field_group_add_field(group, field);
-
+		purple_request_field_string_set_masked(field, TRUE);
+		purple_request_field_group_add_field(group, field);
+	}
 	if(xmlnode_get_child(query, "name")) {
 		if(js->registration)
 			field = purple_request_field_string_new("name", _("Name"),
@@ -1414,6 +1416,7 @@ void jabber_close(PurpleConnection *gc)
 	g_free(js->old_uri);
 	g_free(js->old_track);
 	g_free(js->expected_rspauth);
+	g_free(js->last_disco_server);
 
 	if (js->keepalive_timeout != -1)
 		purple_timeout_remove(js->keepalive_timeout);
============================================================
--- libpurple/protocols/jabber/jabber.h	04d7b812a19ff636e1797f82e05b38699ed78b89
+++ libpurple/protocols/jabber/jabber.h	14e38fe9e558f9b77c8d03ccdd3837eb4db2bb51
@@ -44,6 +44,8 @@ typedef enum {
 	JABBER_CAP_ADHOC		  = 1 << 12,
 	JABBER_CAP_BLOCKING       = 1 << 13,
 
+	JABBER_CAP_ITEMS          = 1 << 14,
+
 	JABBER_CAP_RETRIEVED      = 1 << 31
 } JabberCapabilities;
 
@@ -242,6 +244,12 @@ struct _JabberStream
 	 * for when we lookup buddy icons from a url
 	 */
 	GSList *url_datas;
+
+	/**
+	 * The last server the user disco'd (or NULL) via the server discovery
+	 * API.
+	 */
+	char *last_disco_server;
 };
 
 typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *shortname, const gchar *namespace);
============================================================
--- libpurple/protocols/jabber/libxmpp.c	720ff02df39b39fd78ea8d0c90d45d4e505811b2
+++ libpurple/protocols/jabber/libxmpp.c	254e4c0c685d5b711aa19288ad958444555fc384
@@ -34,6 +34,7 @@
 #include "iq.h"
 #include "jabber.h"
 #include "chat.h"
+#include "disco.h"
 #include "message.h"
 #include "roster.h"
 #include "si.h"
@@ -119,7 +120,11 @@ static PurplePluginProtocolInfo prpl_inf
 	jabber_attention_types,			/* attention_types */
 
 	sizeof(PurplePluginProtocolInfo),       /* struct_size */
-	NULL
+	NULL,
+	jabber_disco_get_list,			/* disco_get_list */
+	jabber_disco_cancel,			/* disco_cancel */
+	jabber_disco_service_register	/* disco_service_register */
+
 };
 
 static gboolean load_plugin(PurplePlugin *plugin)
============================================================
--- libpurple/prpl.h	227469359e6f3e163b62b7c3a53eabc63bfbcbe5
+++ libpurple/prpl.h	cbeda6b021177c9548bc766128c665f5648aeabf
@@ -69,6 +69,7 @@ typedef struct _PurpleBuddyIconSpec Purp
 #include "proxy.h"
 #include "plugin.h"
 #include "roomlist.h"
+#include "disco.h"
 #include "status.h"
 #include "whiteboard.h"
 
@@ -459,6 +460,21 @@ struct _PurplePluginProtocolInfo
 	 *         destroyed by the caller when it's no longer needed.
 	 */
 	GHashTable *(*get_account_text_table)(PurpleAccount *account);
+
+	/**
+	 * Service discovery prpl callbacks
+	 */
+	void (*disco_get_list)(PurpleConnection *gc, PurpleDiscoList *list);
+
+	/**
+	 * Cancel fetching service list
+	 */
+	void (*disco_cancel)(PurpleDiscoList *list);
+
+	/**
+	 * Register service
+	 */
+	int (*disco_service_register)(PurpleConnection *gc, PurpleDiscoService *service);
 };
 
 #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \
============================================================
--- libpurple/purple.h.in	1fa94bd111d8190501cf48321c9b4fd6d2e5261d
+++ libpurple/purple.h.in	dea46f95559f744f817499d5d4e480c9a8bd4bce
@@ -79,6 +79,7 @@
 #include <prpl.h>
 #include <request.h>
 #include <roomlist.h>
+#include <disco.h>
 #include <savedstatuses.h>
 #include <server.h>
 #include <signals.h>
============================================================
--- pidgin/Makefile.am	83bb46eedfe2d4f347e48eaa9bd015d0fcd8fb8b
+++ pidgin/Makefile.am	30fe12ca622f93eb1d4ce9a275c9d5efd986390d
@@ -90,6 +90,7 @@ pidgin_SOURCES = \
 	gtkconv.c \
 	gtkdebug.c \
 	gtkdialogs.c \
+	gtkdisco.c \
 	gtkdnd-hints.c \
 	gtkdocklet.c \
 	gtkdocklet-x11.c \
@@ -148,6 +149,7 @@ pidgin_headers = \
 	gtkconvwin.h \
 	gtkdebug.h \
 	gtkdialogs.h \
+	gtkdisco.h \
 	gtkdnd-hints.h \
 	gtkdocklet.h \
 	gtkeventloop.h \
============================================================
--- pidgin/Makefile.mingw	159efec3e58c3db9cd5dda2274ab1876e88792be
+++ pidgin/Makefile.mingw	7af2492ea95c6f66d01d921d5b960b38ea6e8eab
@@ -65,6 +65,7 @@ PIDGIN_C_SRC =	\
 			gtkconv.c \
 			gtkdebug.c \
 			gtkdialogs.c \
+			gtkdisco.c \
 			gtkdnd-hints.c \
 			gtkdocklet.c \
 			gtkeventloop.c \
============================================================
--- pidgin/gtkblist.c	96c89bfb2c52da08786705038f9a87ced7afae6a
+++ pidgin/gtkblist.c	e75a8911e71b86edf079872efc2867e166489837
@@ -49,6 +49,7 @@
 #include "gtkconv.h"
 #include "gtkdebug.h"
 #include "gtkdialogs.h"
+#include "gtkdisco.h"
 #include "gtkft.h"
 #include "gtklog.h"
 #include "gtkmenutray.h"
@@ -3332,6 +3333,7 @@ static GtkItemFactoryEntry blist_menu[] 
 	{ N_("/Tools/Pr_ivacy"), NULL, pidgin_privacy_dialog_show, 0, "<Item>", NULL },
 	{ "/Tools/sep2", NULL, NULL, 0, "<Separator>", NULL },
 	{ N_("/Tools/_File Transfers"), "<CTL>T", pidgin_xfer_dialog_show, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_TRANSFER },
+	{ N_("/Tools/Service _Discovery"), NULL, pidgin_disco_dialog_show, 0, "<Item>", NULL },
 	{ N_("/Tools/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "<Item>", NULL },
 	{ N_("/Tools/System _Log"), NULL, gtk_blist_show_systemlog_cb, 3, "<Item>", NULL },
 	{ "/Tools/sep3", NULL, NULL, 0, "<Separator>", NULL },
@@ -4214,6 +4216,9 @@ update_menu_bar(PidginBuddyList *gtkblis
 
 	widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Room List"));
 	gtk_widget_set_sensitive(widget, pidgin_roomlist_is_showable());
+
+	widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Service Discovery"));
+	gtk_widget_set_sensitive(widget, pidgin_disco_is_showable());
 }
 
 static void
============================================================
--- pidgin/gtkmain.c	1f846b8d03b5640cfad052a84d0bbd06b59328d6
+++ pidgin/gtkmain.c	5e81398ff98b71efee6cfdbeef808ed8dc94e3c4
@@ -48,6 +48,7 @@
 #include "gtkconv.h"
 #include "gtkdebug.h"
 #include "gtkdialogs.h"
+#include "gtkdisco.h"
 #include "gtkdocklet.h"
 #include "gtkeventloop.h"
 #include "gtkft.h"
@@ -307,6 +308,7 @@ pidgin_ui_init(void)
 	pidgin_privacy_init();
 	pidgin_xfers_init();
 	pidgin_roomlist_init();
+	pidgin_disco_init();
 	pidgin_log_init();
 	pidgin_docklet_init();
 	pidgin_smileys_init();


More information about the Commits mailing list