# HG changeset patch # User John Bailey # Date 1255377267 0 # Node ID 3fec904938a22de8ad93d6f0e2c668de74a30c13 # Parent 11d40ac3699635607855406b86e87fe0a28243f8# Parent 63dc67b32577e806b8633f16568870d375a52edc merge of '466c48e634f92dbe476c9d7504ef7eb91a4b304e' and '9afa0cfda64ff9907b43b21fe64f17f698d2aa0d' diff -r 11d40ac36996 -r 3fec904938a2 ChangeLog --- a/ChangeLog Mon Oct 12 17:57:23 2009 +0000 +++ b/ChangeLog Mon Oct 12 19:54:27 2009 +0000 @@ -12,6 +12,8 @@ * Don't forget display names for buddies. XMPP: + * Users connecting to Google Talk now have an "Initiate Chat" context menu + option for their buddies. (Eion Robb) * Fix a crash when attempting to validate an invalid JID. * Resolve an issue when connecting to iChat Server when no resource is specified. diff -r 11d40ac36996 -r 3fec904938a2 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Mon Oct 12 17:57:23 2009 +0000 +++ b/libpurple/protocols/jabber/buddy.c Mon Oct 12 19:54:27 2009 +0000 @@ -38,6 +38,7 @@ #include "xdata.h" #include "pep.h" #include "adhoccommands.h" +#include "google.h" typedef struct { long idle_seconds; @@ -1842,6 +1843,13 @@ m = g_list_append(m, act); } + if (js->googletalk) { + act = purple_menu_action_new(_("Initiate _Chat"), + PURPLE_CALLBACK(google_buddy_node_chat), + NULL, NULL); + m = g_list_append(m, act); + } + /* * This if-condition implements parts of XEP-0100: Gateway Interaction * diff -r 11d40ac36996 -r 3fec904938a2 libpurple/protocols/jabber/chat.c --- a/libpurple/protocols/jabber/chat.c Mon Oct 12 17:57:23 2009 +0000 +++ b/libpurple/protocols/jabber/chat.c Mon Oct 12 19:54:27 2009 +0000 @@ -209,19 +209,96 @@ g_hash_table_insert(hash_table, g_strdup(key), g_strdup(value)); } -void jabber_chat_join(PurpleConnection *gc, GHashTable *data) +static JabberChat *jabber_chat_new(JabberStream *js, const char *room, + const char *server, const char *handle, + const char *password, GHashTable *data) { JabberChat *chat; - char *room, *server, *handle, *passwd; + char *jid; + + g_return_val_if_fail(jabber_chat_find(js, room, server) == NULL, NULL); + + chat = g_new0(JabberChat, 1); + chat->js = js; + + chat->room = g_strdup(room); + chat->server = g_strdup(server); + chat->handle = g_strdup(handle); + + /* Copy the data hash table to chat->components */ + chat->components = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + if (data == NULL) { + g_hash_table_insert(chat->components, g_strdup("handle"), g_strdup(handle)); + g_hash_table_insert(chat->components, g_strdup("room"), g_strdup(room)); + g_hash_table_insert(chat->components, g_strdup("server"), g_strdup(server)); + /* g_hash_table_insert(chat->components, g_strdup("password"), g_strdup(server)); */ + } else { + g_hash_table_foreach(data, insert_in_hash_table, chat->components); + } + + chat->members = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + (GDestroyNotify)jabber_chat_member_free); + + jid = g_strdup_printf("%s@%s", room, server); + g_hash_table_insert(js->chats, jid, chat); + + return chat; +} + +JabberChat *jabber_join_chat(JabberStream *js, const char *room, + const char *server, const char *handle, + const char *password, GHashTable *data) +{ + JabberChat *chat; + + PurpleConnection *gc; + PurpleAccount *account; + PurpleStatus *status; + xmlnode *presence, *x; - char *tmp, *room_jid, *full_jid; - JabberStream *js = gc->proto_data; - PurplePresence *gpresence; - PurpleStatus *status; JabberBuddyState state; char *msg; int priority; + char *jid; + + chat = jabber_chat_new(js, room, server, handle, password, data); + g_return_val_if_fail(chat != NULL, NULL); + + gc = js->gc; + account = purple_connection_get_account(gc); + status = purple_account_get_active_status(account); + purple_status_to_jabber(status, &state, &msg, &priority); + + presence = jabber_presence_create_js(js, state, msg, priority); + g_free(msg); + + jid = g_strdup_printf("%s@%s/%s", room, server, handle); + xmlnode_set_attrib(presence, "to", jid); + g_free(jid); + + x = xmlnode_new_child(presence, "x"); + xmlnode_set_namespace(x, "http://jabber.org/protocol/muc"); + + if (password && *password) { + xmlnode *p = xmlnode_new_child(x, "password"); + xmlnode_insert_data(p, password, -1); + } + + jabber_send(js, presence); + xmlnode_free(presence); + + return chat; +} + +void jabber_chat_join(PurpleConnection *gc, GHashTable *data) +{ + char *room, *server, *handle, *passwd; + JabberID *jid; + JabberStream *js = gc->proto_data; + char *tmp; + room = g_hash_table_lookup(data, "room"); server = g_hash_table_lookup(data, "server"); handle = g_hash_table_lookup(data, "handle"); @@ -256,51 +333,23 @@ return; } - if(jabber_chat_find(js, room, server)) - return; - + /* Normalize the room and server parameters */ tmp = g_strdup_printf("%s@%s", room, server); - room_jid = g_strdup(jabber_normalize(NULL, tmp)); + jid = jabber_id_new(tmp); g_free(tmp); - chat = g_new0(JabberChat, 1); - chat->js = gc->proto_data; - - chat->room = g_strdup(room); - chat->server = g_strdup(server); - chat->handle = g_strdup(handle); - - /* Copy the data hash table to chat->components */ - chat->components = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - g_hash_table_foreach(data, insert_in_hash_table, chat->components); - - chat->members = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, - (GDestroyNotify)jabber_chat_member_free); - - g_hash_table_insert(js->chats, room_jid, chat); + if (jid == NULL) { + /* TODO: Error message */ - gpresence = purple_account_get_presence(gc->account); - status = purple_presence_get_active_status(gpresence); - - purple_status_to_jabber(status, &state, &msg, &priority); - - presence = jabber_presence_create_js(js, state, msg, priority); - full_jid = g_strdup_printf("%s/%s", room_jid, handle); - xmlnode_set_attrib(presence, "to", full_jid); - g_free(full_jid); - g_free(msg); - - x = xmlnode_new_child(presence, "x"); - xmlnode_set_namespace(x, "http://jabber.org/protocol/muc"); - - if(passwd && *passwd) { - xmlnode *password = xmlnode_new_child(x, "password"); - xmlnode_insert_data(password, passwd, -1); + g_return_if_reached(); } - jabber_send(js, presence); - xmlnode_free(presence); + /* + * Now that we've done all that nice core-interface stuff, let's join + * this room! + */ + jabber_join_chat(js, jid->node, jid->domain, handle, passwd, data); + jabber_id_free(jid); } void jabber_chat_leave(PurpleConnection *gc, int id) diff -r 11d40ac36996 -r 3fec904938a2 libpurple/protocols/jabber/chat.h --- a/libpurple/protocols/jabber/chat.h Mon Oct 12 17:57:23 2009 +0000 +++ b/libpurple/protocols/jabber/chat.h Mon Oct 12 19:54:27 2009 +0000 @@ -57,6 +57,19 @@ GList *jabber_chat_info(PurpleConnection *gc); GHashTable *jabber_chat_info_defaults(PurpleConnection *gc, const char *chat_name); char *jabber_get_chat_name(GHashTable *data); + +/** + * in-prpl function for joining a chat room. Doesn't require sticking goop + * into a hash table. + * + * @param password The password (if required) to join the room. May be NULL. + * @param data The chat hash table. May be NULL (it will be generated + * for current core<>prpl API interface.) + */ +JabberChat *jabber_join_chat(JabberStream *js, const char *room, + const char *server, const char *handle, + const char *password, GHashTable *data); + void jabber_chat_join(PurpleConnection *gc, GHashTable *data); JabberChat *jabber_chat_find(JabberStream *js, const char *room, const char *server); diff -r 11d40ac36996 -r 3fec904938a2 libpurple/protocols/jabber/google.c --- a/libpurple/protocols/jabber/google.c Mon Oct 12 17:57:23 2009 +0000 +++ b/libpurple/protocols/jabber/google.c Mon Oct 12 19:54:27 2009 +0000 @@ -31,6 +31,7 @@ #include "jabber.h" #include "presence.h" #include "iq.h" +#include "chat.h" #include "jingle/jingle.h" @@ -1425,3 +1426,43 @@ purple_debug_info("jabber", "sending google:jingleinfo query\n"); jabber_iq_send(jingle_info); } + +void google_buddy_node_chat(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *buddy; + PurpleConnection *gc; + JabberStream *js; + JabberChat *chat; + gchar *room; + guint32 tmp, a, b; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + buddy = PURPLE_BUDDY(node); + gc = purple_account_get_connection(purple_buddy_get_account(buddy)); + g_return_if_fail(gc != NULL); + js = purple_connection_get_protocol_data(gc); + + /* Generate a version 4 UUID */ + tmp = g_random_int(); + a = 0x4000 | (tmp & 0xFFF); /* 0x4000 to 0x4FFF */ + tmp >>= 12; + b = ((1 << 3) << 12) | (tmp & 0x3FFF); /* 0x8000 to 0xBFFF */ + + tmp = g_random_int(); + room = g_strdup_printf("private-chat-%08x-%04x-%04x-%04x-%04x%08x", + g_random_int(), + tmp & 0xFFFF, + a, + b, + (tmp >> 16) & 0xFFFF, g_random_int()); + + chat = jabber_join_chat(js, room, GOOGLE_GROUPCHAT_SERVER, js->user->node, + NULL, NULL); + if (chat) { + chat->muc = TRUE; + jabber_chat_invite(gc, chat->id, "", buddy->name); + } + + g_free(room); +} diff -r 11d40ac36996 -r 3fec904938a2 libpurple/protocols/jabber/google.h --- a/libpurple/protocols/jabber/google.h Mon Oct 12 17:57:23 2009 +0000 +++ b/libpurple/protocols/jabber/google.h Mon Oct 12 19:54:27 2009 +0000 @@ -31,6 +31,8 @@ #define GOOGLE_VIDEO_CAP "http://www.google.com/xmpp/protocol/video/v1" #define GOOGLE_JINGLE_INFO_NAMESPACE "google:jingleinfo" +#define GOOGLE_GROUPCHAT_SERVER "groupchat.google.com" + void jabber_gmail_init(JabberStream *js); void jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *new_mail); @@ -59,4 +61,6 @@ xmlnode *child); void jabber_google_send_jingle_info(JabberStream *js); +void google_buddy_node_chat(PurpleBlistNode *node, gpointer data); + #endif /* PURPLE_JABBER_GOOGLE_H_ */