# HG changeset patch # User Paul Aurich # Date 1238354962 0 # Node ID f5e613e0533299259d56291145aee56a5d27e0e8 # Parent c422c7b1bde7cbf4f7cdaca62e4cf8aad866f0ae 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. diff -r c422c7b1bde7 -r f5e613e05332 libpurple/Makefile.am --- a/libpurple/Makefile.am Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/Makefile.am Sun Mar 29 19:29:22 2009 +0000 @@ -46,6 +46,7 @@ core.c \ debug.c \ desktopitem.c \ + disco.c \ eventloop.c \ ft.c \ idle.c \ @@ -103,6 +104,7 @@ dbus-maybe.h \ debug.h \ desktopitem.h \ + disco.h \ eventloop.h \ ft.h \ gaim-compat.h \ @@ -165,7 +167,7 @@ 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)) \ diff -r c422c7b1bde7 -r f5e613e05332 libpurple/Makefile.mingw --- a/libpurple/Makefile.mingw Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/Makefile.mingw Sun Mar 29 19:29:22 2009 +0000 @@ -40,6 +40,7 @@ conversation.c \ core.c \ debug.c \ + disco.c \ dnsquery.c \ dnssrv.c \ eventloop.c \ diff -r c422c7b1bde7 -r f5e613e05332 libpurple/protocols/jabber/disco.c --- a/libpurple/protocols/jabber/disco.c Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/protocols/jabber/disco.c Sun Mar 29 19:29:22 2009 +0000 @@ -1,5 +1,5 @@ /* - * purple - Jabber Protocol Plugin + * purple - Jabber Service Discovery * * Copyright (C) 2003, Nathan Walp * @@ -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,7 +34,8 @@ #include "roster.h" #include "pep.h" #include "adhoccommands.h" - +#include "xdata.h" +#include "libpurple/disco.h" struct _jabber_disco_info_cb_data { gpointer data; @@ -268,6 +271,8 @@ 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_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 @@ } +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 @@ 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; +} + diff -r c422c7b1bde7 -r f5e613e05332 libpurple/protocols/jabber/disco.h --- a/libpurple/protocols/jabber/disco.h Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/protocols/jabber/disco.h Sun Mar 29 19:29:22 2009 +0000 @@ -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 *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_ */ diff -r c422c7b1bde7 -r f5e613e05332 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sun Mar 29 19:29:22 2009 +0000 @@ -1062,22 +1062,24 @@ 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); - - purple_request_field_group_add_field(group, field); - - 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); - + 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); + } + 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); + + 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 @@ 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); diff -r c422c7b1bde7 -r f5e613e05332 libpurple/protocols/jabber/jabber.h --- a/libpurple/protocols/jabber/jabber.h Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.h Sun Mar 29 19:29:22 2009 +0000 @@ -44,6 +44,8 @@ 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 @@ * 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); diff -r c422c7b1bde7 -r f5e613e05332 libpurple/protocols/jabber/libxmpp.c --- a/libpurple/protocols/jabber/libxmpp.c Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Sun Mar 29 19:29:22 2009 +0000 @@ -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 @@ 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) diff -r c422c7b1bde7 -r f5e613e05332 libpurple/prpl.h --- a/libpurple/prpl.h Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/prpl.h Sun Mar 29 19:29:22 2009 +0000 @@ -69,6 +69,7 @@ #include "proxy.h" #include "plugin.h" #include "roomlist.h" +#include "disco.h" #include "status.h" #include "whiteboard.h" @@ -459,6 +460,21 @@ * 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) \ diff -r c422c7b1bde7 -r f5e613e05332 libpurple/purple.h.in --- a/libpurple/purple.h.in Sat Mar 28 16:58:32 2009 +0000 +++ b/libpurple/purple.h.in Sun Mar 29 19:29:22 2009 +0000 @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include diff -r c422c7b1bde7 -r f5e613e05332 pidgin/Makefile.am --- a/pidgin/Makefile.am Sat Mar 28 16:58:32 2009 +0000 +++ b/pidgin/Makefile.am Sun Mar 29 19:29:22 2009 +0000 @@ -90,6 +90,7 @@ gtkconv.c \ gtkdebug.c \ gtkdialogs.c \ + gtkdisco.c \ gtkdnd-hints.c \ gtkdocklet.c \ gtkdocklet-x11.c \ @@ -148,6 +149,7 @@ gtkconvwin.h \ gtkdebug.h \ gtkdialogs.h \ + gtkdisco.h \ gtkdnd-hints.h \ gtkdocklet.h \ gtkeventloop.h \ diff -r c422c7b1bde7 -r f5e613e05332 pidgin/Makefile.mingw --- a/pidgin/Makefile.mingw Sat Mar 28 16:58:32 2009 +0000 +++ b/pidgin/Makefile.mingw Sun Mar 29 19:29:22 2009 +0000 @@ -65,6 +65,7 @@ gtkconv.c \ gtkdebug.c \ gtkdialogs.c \ + gtkdisco.c \ gtkdnd-hints.c \ gtkdocklet.c \ gtkeventloop.c \ diff -r c422c7b1bde7 -r f5e613e05332 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Sat Mar 28 16:58:32 2009 +0000 +++ b/pidgin/gtkblist.c Sun Mar 29 19:29:22 2009 +0000 @@ -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 @@ { N_("/Tools/Pr_ivacy"), NULL, pidgin_privacy_dialog_show, 0, "", NULL }, { "/Tools/sep2", NULL, NULL, 0, "", NULL }, { N_("/Tools/_File Transfers"), "T", pidgin_xfer_dialog_show, 0, "", PIDGIN_STOCK_TOOLBAR_TRANSFER }, + { N_("/Tools/Service _Discovery"), NULL, pidgin_disco_dialog_show, 0, "", NULL }, { N_("/Tools/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "", NULL }, { N_("/Tools/System _Log"), NULL, gtk_blist_show_systemlog_cb, 3, "", NULL }, { "/Tools/sep3", NULL, NULL, 0, "", NULL }, @@ -4214,6 +4216,9 @@ 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 diff -r c422c7b1bde7 -r f5e613e05332 pidgin/gtkmain.c --- a/pidgin/gtkmain.c Sat Mar 28 16:58:32 2009 +0000 +++ b/pidgin/gtkmain.c Sun Mar 29 19:29:22 2009 +0000 @@ -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_privacy_init(); pidgin_xfers_init(); pidgin_roomlist_init(); + pidgin_disco_init(); pidgin_log_init(); pidgin_docklet_init(); pidgin_smileys_init();