changeset 28746:3fec904938a2

merge of '466c48e634f92dbe476c9d7504ef7eb91a4b304e' and '9afa0cfda64ff9907b43b21fe64f17f698d2aa0d'
author John Bailey <rekkanoryo@rekkanoryo.org>
date Mon, 12 Oct 2009 19:54:27 +0000
parents 11d40ac36996 (current diff) 63dc67b32577 (diff)
children f55bd60e2738 791281a6e21d
files ChangeLog
diffstat 6 files changed, 162 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- 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
 	 *
--- 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)
--- 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);
--- 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);
+}
--- 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_ */