Mercurial > pidgin
diff libpurple/protocols/jabber/jabber.c @ 25124:ba362a67278c
propagate from branch 'im.pidgin.pidgin' (head 2747d5e0324ca6b81e83bbb8b75e1efebcbbad6e)
to branch 'im.pidgin.soc.2008.xmpp' (head 72d6870ed2c62423a05ed89822db25d9916ecf2b)
author | Tobias Markmann <tfar@soc.pidgin.im> |
---|---|
date | Sun, 03 Aug 2008 23:16:24 +0000 |
parents | fa8567fa0ca0 9f8951284a2e |
children | 907ca9a36fe0 |
line wrap: on
line diff
--- a/libpurple/protocols/jabber/jabber.c Sun Aug 03 05:13:29 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sun Aug 03 23:16:24 2008 +0000 @@ -39,6 +39,7 @@ #include "version.h" #include "xmlnode.h" +#include "caps.h" #include "auth.h" #include "buddy.h" #include "chat.h" @@ -60,7 +61,11 @@ #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) static PurplePlugin *my_protocol = NULL; + GList *jabber_features = NULL; +GList *jabber_identities = NULL; + +GHashTable *jabber_contact_info = NULL; static void jabber_unregister_account_cb(JabberStream *js); static void try_srv_connect(JabberStream *js); @@ -513,6 +518,33 @@ jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); } +static void +txt_resolved_cb(PurpleTxtResponse *resp, int results, gpointer data) +{ + PurpleConnection *gc = data; + JabberStream *js = gc->proto_data; + int n; + + if (results == 0) { + gchar *tmp; + tmp = g_strdup_printf(_("Could not find alternative XMPP connection methods after failing to connect directly.\n")); + purple_connection_error_reason (gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); + g_free(tmp); + } + + for (n = 0; n < results; n++) { + gchar **token; + token = g_strsplit(resp[n].content, "=", 2); + if (!strcmp(token[0], "_xmpp-client-xbosh")) { + purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]); + js->bosh.url = g_strdup(token[1]); + g_strfreev(token); + break; + } + g_strfreev(token); + } +} static void jabber_login_callback(gpointer data, gint source, const gchar *error) @@ -525,12 +557,8 @@ purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record.\n", error); try_srv_connect(js); } else { - gchar *tmp; - tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), - error); - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); - g_free(tmp); + purple_debug_info("jabber","Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain); + purple_txt_resolve("_xmppconnect", js->user->domain, txt_resolved_cb, gc); } return; } @@ -708,7 +736,7 @@ /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll * invoke the magic of SRV lookups, to figure out host and port */ if(!js->gsc) { - if(connect_server[0]) { + if(connect_server[0]) { jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE); } else { js->srv_query_data = purple_srv_resolve("xmpp-client", @@ -1427,31 +1455,27 @@ js->idle = idle ? time(NULL) - idle : idle; } -void jabber_add_feature(const char *shortname, const char *namespace, JabberFeatureEnabled cb) { +void jabber_add_feature(const char *namespace, JabberFeatureEnabled cb) { JabberFeature *feat; - g_return_if_fail(shortname != NULL); g_return_if_fail(namespace != NULL); feat = g_new0(JabberFeature,1); - feat->shortname = g_strdup(shortname); feat->namespace = g_strdup(namespace); feat->is_enabled = cb; /* try to remove just in case it already exists in the list */ - jabber_remove_feature(shortname); + jabber_remove_feature(namespace); jabber_features = g_list_append(jabber_features, feat); } -void jabber_remove_feature(const char *shortname) { +void jabber_remove_feature(const char *namespace) { GList *feature; for(feature = jabber_features; feature; feature = feature->next) { JabberFeature *feat = (JabberFeature*)feature->data; - if(!strcmp(feat->shortname, shortname)) { - g_free(feat->shortname); + if(!strcmp(feat->namespace, namespace)) { g_free(feat->namespace); - g_free(feature->data); jabber_features = g_list_delete_link(jabber_features, feature); break; @@ -1459,6 +1483,27 @@ } } +void jabber_add_identity(const gchar *category, const gchar *type, const gchar *name) { + GList *identity; + JabberIdentity *ident; + /* both required according to XEP-0030 */ + g_return_if_fail(category != NULL); + g_return_if_fail(type != NULL); + + for(identity = jabber_identities; identity; identity = identity->next) { + JabberIdentity *ident = (JabberIdentity*)identity->data; + if(!strcmp(ident->category, category)) { + if (!strcmp(ident->type, type)) return; + } + } + + ident = g_new0(JabberIdentity, 1); + ident->category = g_strdup(category); + ident->type = g_strdup(type); + ident->name = g_strdup(name); + jabber_identities = g_list_append(jabber_identities, ident); +} + const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b) { return "jabber"; @@ -2459,8 +2504,78 @@ _("buzz: Buzz a user to get their attention"), NULL); } +/* IPC fucntions*/ + +/* + * IPC function for checking wheather a client at a full JID supports a certain feature. + * + * @param fulljid The full JID of the client. + * @param featrure The feature's namespace. + * + * @return TRUE if supports feature; else FALSE. + */ +static gboolean +jabber_ipc_contact_has_feature(gchar *fulljid, gchar *feature) +{ + JabberCapsKey *caps_info = NULL; + JabberCapsValueExt *capabilities = NULL; + + caps_info = g_hash_table_lookup(jabber_contact_info, fulljid); + + if (!caps_info) return FALSE; + capabilities = g_hash_table_lookup(capstable, caps_info); + + if (g_list_find_custom(capabilities->features, feature, strcmp) == NULL) return FALSE ; + return TRUE; +} + +static void +jabber_ipc_add_feature(gchar *feature) +{ + if (feature == 0) return; + jabber_add_feature(feature, 0); + + // send presence with new caps info for all connected accounts + jabber_caps_broadcast_change(); +} + void jabber_init_plugin(PurplePlugin *plugin) { - my_protocol = plugin; + my_protocol = plugin; + + jabber_add_identity("client", "pc", PACKAGE); + + /* initialize jabber_features list */ + jabber_add_feature("jabber:iq:last", 0); + jabber_add_feature("jabber:iq:oob", 0); + jabber_add_feature("jabber:iq:time", 0); + jabber_add_feature("xmpp:urn:time", 0); + jabber_add_feature("jabber:iq:version", 0); + jabber_add_feature("jabber:x:conference", 0); + jabber_add_feature("http://jabber.org/protocol/bytestreams", 0); + jabber_add_feature("http://jabber.org/protocol/disco#info", 0); + jabber_add_feature("http://jabber.org/protocol/disco#items", 0); +#if 0 + jabber_add_feature("http://jabber.org/protocol/ibb", 0); +#endif + jabber_add_feature("http://jabber.org/protocol/muc", 0); + jabber_add_feature("http://jabber.org/protocol/muc#user", 0); + jabber_add_feature("http://jabber.org/protocol/si", 0); + jabber_add_feature("http://jabber.org/protocol/si/profile/file-transfer", 0); + jabber_add_feature("http://jabber.org/protocol/xhtml-im", 0); + jabber_add_feature("urn:xmpp:ping", 0); + + jabber_contact_info = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, jabber_caps_destroy_key); + + /* IPC functions */ + purple_plugin_ipc_register(plugin, "contact_has_feature", PURPLE_CALLBACK(jabber_ipc_contact_has_feature), + purple_marshal_BOOLEAN__POINTER_POINTER, + purple_value_new(PURPLE_TYPE_BOOLEAN), 2, + purple_value_new(PURPLE_TYPE_STRING), + purple_value_new(PURPLE_TYPE_STRING)); + purple_plugin_ipc_register(plugin, "add_feature", PURPLE_CALLBACK(jabber_ipc_add_feature), + purple_marshal_VOID__POINTER, + NULL, 1, + purple_value_new(PURPLE_TYPE_STRING)); }