changeset 31728:66981e71af29

propagate from branch 'im.pidgin.pidgin' (head 38eaad68c9e65295acb7aa04cd59bb448f058b47) to branch 'im.pidgin.pidgin.mxit' (head 20a7b36a8dc242edd143675b69a3e2864a11afbe)
author andrew.victor@mxit.com
date Mon, 13 Sep 2010 09:57:03 +0000
parents 581a070c3737 (current diff) 277451b94288 (diff)
children 7c5a78a2cc0d
files ChangeLog libpurple/protocols/jabber/google.c libpurple/protocols/jabber/google.h pidgin/pixmaps/emotes/small/16/cool.png pidgin/pixmaps/emotes/small/16/grin.png pidgin/win32/IdleTracker/Makefile.mingw pidgin/win32/IdleTracker/idletrack.c pidgin/win32/IdleTracker/idletrack.h
diffstat 231 files changed, 3223 insertions(+), 2793 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Fri Aug 20 08:35:27 2010 +0000
+++ b/COPYRIGHT	Mon Sep 13 09:57:03 2010 +0000
@@ -18,6 +18,7 @@
 Copyright (C) 1998-2009 by the following:
 
 Saleem Abdulrasool
+Jakub Adam
 Dave Ahlswede
 Manuel Amador
 Matt Amato
--- a/ChangeLog	Fri Aug 20 08:35:27 2010 +0000
+++ b/ChangeLog	Mon Sep 13 09:57:03 2010 +0000
@@ -4,6 +4,40 @@
 	General:
 	* Fix search path for Tk when compiling on Debian Squeeze. (#12465)
 
+	libpurple:
+	* Fall back to an ordinary request if a UI does not support showing a
+	  request with an icon.  Fixes receiving MSN file transfer requests
+	  including a thumbnail in Finch.
+
+	Pidgin:
+	* Add support for the Gadu-Gadu protocol in the gevolution plugin to
+	  provide Evolution integration with contacts with GG IDs. (#10709)
+	* Remap the "Set User Mood" shortcut to Control-D, which does not
+	  conflict with the previous shortcut for Get Buddy Info on the
+	  selected buddy.
+	* Add a plugin action menu (under Tools) for the Voice and Video
+	  Settings plugin.
+
+	Finch:
+	* Add support for drop-down account options (like the SILC cipher
+	  and HMAC options or the QQ protocol version).
+
+	XMPP:
+	* Unify the connection security-related settings into one dropdown.
+	* Fix a crash when multiple accounts are simultaneously performing
+	  SASL authentication when built with Cyrus SASL support.  (thanks
+	  to Jan Kaluza) (#11560)
+	* Restore the ability to connect to XMPP servers that do not offer
+	  Stream ID. (#12331)
+	* Added support for using Google's relay servers when making voice and
+	  video calls to Google clients.
+
+	Yahoo/Yahoo JAPAN:
+	* Stop doing unnecessary lookups of certain alias information.  This
+	  solves deadlocks when a given Yahoo account has a ridiculously large
+	  (>500 buddies) list and may improve login speed for those on slow
+	  connections. (#12532)
+
 version 2.7.3 (08/10/2010):
 	General:
 	* Use silent build rules for automake >1.11. You can enable verbose
--- a/ChangeLog.API	Fri Aug 20 08:35:27 2010 +0000
+++ b/ChangeLog.API	Mon Sep 13 09:57:03 2010 +0000
@@ -1,6 +1,14 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
 version 2.7.4 (MM/DD/YYYY):
+	Perl:
+		Added:
+		* Purple::BuddyList::Chat::get_components
+
+		Changed:
+		* Purple::BuddyList::Chat::new now works properly.  Thanks
+		  to Rafael in devel@conference.pidgin.im for reporting and
+		  testing.
 
 version 2.7.3 (08/10/2010):
 	libpurple:
--- a/finch/gntaccount.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/finch/gntaccount.c	Mon Sep 13 09:57:03 2010 +0000
@@ -236,7 +236,8 @@
 			}
 			else if (type == PURPLE_PREF_STRING_LIST)
 			{
-				/* TODO: */
+				gchar *value = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(entry));
+				purple_account_set_string(account, setting, value);
 			}
 			else
 			{
@@ -430,8 +431,26 @@
 
 			if (type == PURPLE_PREF_STRING_LIST)
 			{
-				/* TODO: Use a combobox */
-				/*       Don't forget to append the widget to prpl_entries */
+				GntWidget *combo = gnt_combo_box_new();
+				GList *opt_iter = purple_account_option_get_list(option);
+				const char *dv = purple_account_option_get_default_list_value(option);
+				const char *active = dv;
+
+				if (account)
+					active = purple_account_get_string(account,
+						purple_account_option_get_setting(option), dv);
+
+				gnt_box_add_widget(GNT_BOX(box), combo);
+				dialog->prpl_entries = g_list_append(dialog->prpl_entries, combo);
+
+				for ( ; opt_iter; opt_iter = opt_iter->next)
+				{
+					PurpleKeyValuePair *kvp = opt_iter->data;
+					gnt_combo_box_add_data(GNT_COMBO_BOX(combo), kvp->value, kvp->key);
+
+					if (g_str_equal(kvp->value, active))
+						gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), kvp->value);
+				}
 			}
 			else
 			{
--- a/finch/gntft.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/finch/gntft.c	Mon Sep 13 09:57:03 2010 +0000
@@ -383,12 +383,10 @@
 		return;
 	}
 
-	data = FINCHXFER(xfer);
-
 	update_title_progress();
 
 	if (purple_xfer_is_canceled(xfer))
-		status = _("Canceled");
+		status = _("Cancelled");
 	else
 		status = _("Failed");
 
@@ -402,7 +400,7 @@
 	char *size_str, *remaining_str;
 	time_t current_time;
 	char prog_str[5];
-	double kb_sent, kb_rem;
+	double kb_sent;
 	double kbps = 0.0;
 	time_t elapsed, now;
 	char *kbsec;
@@ -412,7 +410,6 @@
 		now = time(NULL);
 
 	kb_sent = purple_xfer_get_bytes_sent(xfer) / 1024.0;
-	kb_rem  = purple_xfer_get_bytes_remaining(xfer) / 1024.0;
 	elapsed = (purple_xfer_get_start_time(xfer) > 0 ? now - purple_xfer_get_start_time(xfer) : 0);
 	kbps    = (elapsed > 0 ? (kb_sent / elapsed) : 0);
 
--- a/finch/gntft.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/finch/gntft.h	Mon Sep 13 09:57:03 2010 +0000
@@ -72,9 +72,9 @@
 void finch_xfer_dialog_remove_xfer(PurpleXfer *xfer);
 
 /**
- * Indicate in a file transfer dialog that a transfer was canceled.
+ * Indicate in a file transfer dialog that a transfer was cancelled.
  *
- * @param xfer   The file transfer that was canceled.
+ * @param xfer   The file transfer that was cancelled.
  */
 void finch_xfer_dialog_cancel_xfer(PurpleXfer *xfer);
 
--- a/finch/libgnt/gntentry.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/finch/libgnt/gntentry.c	Mon Sep 13 09:57:03 2010 +0000
@@ -481,7 +481,6 @@
 	GntEntry *entry = GNT_ENTRY(bind);
 	GList *iter;
 	const char *current;
-	int len;
 	
 	if (entry->history->prev && entry->search->needle)
 		current = entry->search->needle;
@@ -491,8 +490,6 @@
 	if (!entry->histlength || !entry->history->next || !*current)
 		return FALSE;
 
-	len = g_utf8_strlen(current, -1);
-
 	for (iter = entry->history->next; iter; iter = iter->next) {
 		const char *str = iter->data;
 		/* A more utf8-friendly version of strstr would have been better, but
--- a/libpurple/account.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/account.c	Mon Sep 13 09:57:03 2010 +0000
@@ -513,6 +513,25 @@
 }
 
 static void
+migrate_xmpp_encryption(PurpleAccount *account)
+{
+	/* When this is removed, nuke the "old_ssl" and "require_tls" settings */
+	if (g_str_equal(purple_account_get_protocol_id(account), "prpl-jabber")) {
+		const char *sec = purple_account_get_string(account, "connection_security", "");
+
+		if (g_str_equal("", sec)) {
+			const char *val = "require_tls";
+			if (purple_account_get_bool(account, "old_ssl", FALSE))
+				val = "old_ssl";
+			else if (!purple_account_get_bool(account, "require_tls", TRUE))
+				val = "opportunistic_tls";
+
+			purple_account_set_string(account, "connection_security", val);
+		}
+	}
+}
+
+static void
 parse_settings(xmlnode *node, PurpleAccount *account)
 {
 	const char *ui;
@@ -579,6 +598,9 @@
 	/* we do this here because we need access to account settings to determine
 	 * if we can/should migrate an old Yahoo! JAPAN account */
 	migrate_yahoo_japan(account);
+	/* we do this here because we need to do it before the user views the
+	 * Edit Account dialog. */
+	migrate_xmpp_encryption(account);
 }
 
 static GList *
@@ -1129,7 +1151,7 @@
 static void
 request_password_cancel_cb(PurpleAccount *account, PurpleRequestFields *fields)
 {
-	/* Disable the account as the user has canceled connecting */
+	/* Disable the account as the user has cancelled connecting */
 	purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
 }
 
--- a/libpurple/conversation.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/conversation.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1124,7 +1124,6 @@
 purple_conv_im_start_typing_timeout(PurpleConvIm *im, int timeout)
 {
 	PurpleConversation *conv;
-	const char *name;
 
 	g_return_if_fail(im != NULL);
 
@@ -1132,7 +1131,6 @@
 		purple_conv_im_stop_typing_timeout(im);
 
 	conv = purple_conv_im_get_conversation(im);
-	name = purple_conversation_get_name(conv);
 
 	im->typing_timeout = purple_timeout_add_seconds(timeout, reset_typing_cb, conv);
 }
@@ -1520,7 +1518,6 @@
 	PurpleAccount *account;
 	PurpleConversation *conv;
 	PurpleConnection *gc;
-	PurplePluginProtocolInfo *prpl_info;
 
 	g_return_if_fail(chat != NULL);
 	g_return_if_fail(who != NULL);
@@ -1529,7 +1526,6 @@
 	conv      = purple_conv_chat_get_conversation(chat);
 	gc        = purple_conversation_get_gc(conv);
 	account   = purple_connection_get_account(gc);
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 
 	/* Don't display this if the person who wrote it is ignored. */
 	if (purple_conv_chat_is_user_ignored(chat, who))
--- a/libpurple/desktopitem.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/desktopitem.c	Mon Sep 13 09:57:03 2010 +0000
@@ -330,7 +330,7 @@
 	if (c == EOF && pos == 0)
 		return NULL;
 
-	buf[pos++] = '\0';
+	buf[pos] = '\0';
 
 	return buf;
 }
--- a/libpurple/ft.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/ft.c	Mon Sep 13 09:57:03 2010 +0000
@@ -752,6 +752,7 @@
 	return xfer->status;
 }
 
+/* FIXME: Rename with cancelled for 3.0.0. */
 gboolean
 purple_xfer_is_canceled(const PurpleXfer *xfer)
 {
--- a/libpurple/ft.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/ft.h	Mon Sep 13 09:57:03 2010 +0000
@@ -58,8 +58,8 @@
 	PURPLE_XFER_STATUS_ACCEPTED,      /**< Receive accepted, but destination file not selected yet */
 	PURPLE_XFER_STATUS_STARTED,       /**< purple_xfer_start has been called. */
 	PURPLE_XFER_STATUS_DONE,          /**< The xfer completed successfully. */
-	PURPLE_XFER_STATUS_CANCEL_LOCAL,  /**< The xfer was canceled by us. */
-	PURPLE_XFER_STATUS_CANCEL_REMOTE  /**< The xfer was canceled by the other end, or we couldn't connect. */
+	PURPLE_XFER_STATUS_CANCEL_LOCAL,  /**< The xfer was cancelled by us. */
+	PURPLE_XFER_STATUS_CANCEL_REMOTE  /**< The xfer was cancelled by the other end, or we couldn't connect. */
 } PurpleXferStatusType;
 
 /**
@@ -304,11 +304,12 @@
 PurpleXferStatusType purple_xfer_get_status(const PurpleXfer *xfer);
 
 /**
- * Returns true if the file transfer was canceled.
+ * Returns true if the file transfer was cancelled.
  *
  * @param xfer The file transfer.
  *
- * @return Whether or not the transfer was canceled.
+ * @return Whether or not the transfer was cancelled.
+ * FIXME: This should be renamed using cancelled for 3.0.0.
  */
 gboolean purple_xfer_is_canceled(const PurpleXfer *xfer);
 
--- a/libpurple/media.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/media.c	Mon Sep 13 09:57:03 2010 +0000
@@ -515,7 +515,8 @@
 
 	if (!media->priv->sessions) {
 		purple_debug_info("media", "Creating hash table for sessions\n");
-		media->priv->sessions = g_hash_table_new(g_str_hash, g_str_equal);
+		media->priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal,
+		                                              g_free, NULL);
 	}
 	g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session);
 }
--- a/libpurple/media/backend-fs2.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/media/backend-fs2.c	Mon Sep 13 09:57:03 2010 +0000
@@ -208,11 +208,7 @@
 	}
 
 	if (priv->participants) {
-		GList *participants =
-				g_hash_table_get_values(priv->participants);
-		for (; participants; participants = g_list_delete_link(
-				participants, participants))
-			g_object_unref(participants->data);
+		g_hash_table_destroy(priv->participants);
 		priv->participants = NULL;
 	}
 
@@ -1425,7 +1421,8 @@
 	if (!priv->sessions) {
 		purple_debug_info("backend-fs2",
 				"Creating hash table for sessions\n");
-		priv->sessions = g_hash_table_new(g_str_hash, g_str_equal);
+		priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal,
+		                                       g_free, NULL);
 	}
 
 	g_hash_table_insert(priv->sessions, g_strdup(session->id), session);
@@ -1461,7 +1458,7 @@
 		purple_debug_info("backend-fs2",
 				"Creating hash table for participants\n");
 		priv->participants = g_hash_table_new_full(g_str_hash,
-				g_str_equal, g_free, NULL);
+				g_str_equal, g_free, g_object_unref);
 	}
 
 	g_hash_table_insert(priv->participants, g_strdup(name), participant);
@@ -1564,6 +1561,30 @@
 			(GSourceFunc)src_pad_added_cb_cb, stream);
 }
 
+static GValueArray *
+append_relay_info(GValueArray *relay_info, const gchar *ip, gint port,
+	const gchar *username, const gchar *password, const gchar *type)
+{
+	GValue value;
+	GstStructure *turn_setup = gst_structure_new("relay-info",
+				"ip", G_TYPE_STRING, ip, 
+				"port", G_TYPE_UINT, port,
+				"username", G_TYPE_STRING, username,
+				"password", G_TYPE_STRING, password,
+	            "relay-type", G_TYPE_STRING, type,
+				NULL);
+
+	if (turn_setup) {
+		memset(&value, 0, sizeof(GValue));
+		g_value_init(&value, GST_TYPE_STRUCTURE);
+		gst_value_set_structure(&value, turn_setup);
+		relay_info = g_value_array_append(relay_info, &value);
+		gst_structure_free(turn_setup);
+	}
+
+	return relay_info;
+}
+                        
 static gboolean
 create_stream(PurpleMediaBackendFs2 *self,
 		const gchar *sess_id, const gchar *who,
@@ -1584,6 +1605,18 @@
 	PurpleMediaBackendFs2Session *session;
 	PurpleMediaBackendFs2Stream *stream;
 	FsParticipant *participant;
+	/* check if the prpl has already specified a relay-info
+	  we need to do this to allow them to override when using non-standard
+	  TURN modes, like Google f.ex. */
+	gboolean got_turn_from_prpl = FALSE;
+	int i;
+
+	for (i = 0 ; i < num_params ; i++) {
+		if (purple_strequal(params[i].name, "relay-info")) {
+			got_turn_from_prpl = TRUE;
+			break;
+		}
+	}
 
 	memcpy(_params, params, sizeof(GParameter) * num_params);
 
@@ -1603,34 +1636,24 @@
 		++_num_params;
 	}
 
-	if (turn_ip && !strcmp("nice", transmitter)) {
+	if (turn_ip && !strcmp("nice", transmitter) && !got_turn_from_prpl) {
 		GValueArray *relay_info = g_value_array_new(0);
-		GValue value;
-		gint turn_port = purple_prefs_get_int(
-				"/purple/network/turn_port");
+		gint port;
 		const gchar *username =	purple_prefs_get_string(
 				"/purple/network/turn_username");
 		const gchar *password = purple_prefs_get_string(
 				"/purple/network/turn_password");
-		GstStructure *turn_setup = gst_structure_new("relay-info",
-				"ip", G_TYPE_STRING, turn_ip, 
-				"port", G_TYPE_UINT, turn_port,
-				"username", G_TYPE_STRING, username,
-				"password", G_TYPE_STRING, password,
-				NULL);
 
-		if (!turn_setup) {
-			purple_debug_error("backend-fs2",
-					"Error creating relay info structure");
-			return FALSE;
+		/* UDP */
+		port = purple_prefs_get_int("/purple/network/turn_port");
+		if (port > 0) {
+			relay_info = append_relay_info(relay_info, turn_ip, port, username,
+				password, "udp");
 		}
 
-		memset(&value, 0, sizeof(GValue));
-		g_value_init(&value, GST_TYPE_STRUCTURE);
-		gst_value_set_structure(&value, turn_setup);
-		relay_info = g_value_array_append(relay_info, &value);
-		gst_structure_free(turn_setup);
-
+		/* should add TCP and perhaps TLS relaying options when these are
+		 supported by libnice using non-google mode */
+		
 		purple_debug_info("backend-fs2",
 			"Setting relay-info on new stream\n");
 		_params[_num_params].name = "relay-info";
@@ -1837,15 +1860,12 @@
 purple_media_backend_fs2_get_codecs(PurpleMediaBackend *self,
 		const gchar *sess_id)
 {
-	PurpleMediaBackendFs2Private *priv;
 	PurpleMediaBackendFs2Session *session;
 	GList *fscodecs;
 	GList *codecs;
 
 	g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
 
-	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
-
 	session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
 
 	if (session == NULL)
@@ -2014,13 +2034,10 @@
 		const gchar *sess_id, const gchar *who, double level)
 {
 #ifdef USE_VV
-	PurpleMediaBackendFs2Private *priv;
 	GList *streams;
 
 	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self));
 
-	priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
-
 	purple_prefs_set_int("/purple/media/audio/volume/output", level);
 
 	streams = get_streams(self, sess_id, who);
--- a/libpurple/media/codec.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/media/codec.c	Mon Sep 13 09:57:03 2010 +0000
@@ -83,9 +83,11 @@
 			PURPLE_MEDIA_CODEC_GET_PRIVATE(info);
 	g_free(priv->encoding_name);
 	for (; priv->optional_params; priv->optional_params =
-			g_list_delete_link(priv->optional_params,
-			priv->optional_params)) {
-		g_free(priv->optional_params->data);
+			g_list_delete_link(priv->optional_params, priv->optional_params)) {
+		PurpleKeyValuePair *param = priv->optional_params->data;
+		g_free(param->key);
+		g_free(param->value);
+		g_free(param);
 	}
 }
 
@@ -302,10 +304,10 @@
 
 	g_free(param->key);
 	g_free(param->value);
-	g_free(param);
 
 	priv->optional_params =
 			g_list_remove(priv->optional_params, param);
+	g_free(param);
 }
 
 PurpleKeyValuePair *
--- a/libpurple/media/codec.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/media/codec.h	Mon Sep 13 09:57:03 2010 +0000
@@ -121,7 +121,8 @@
  *
  * @param The codec to get the optional parameters from.
  *
- * @return The list of optional parameters.
+ * @return The list of optional parameters. The list is owned by the codec and
+ *         should not be freed.
  *
  * @since 2.6.0
  */
--- a/libpurple/network.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/network.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1077,12 +1077,10 @@
 
 	if (protocol) {
 		purple_network_upnp_mapping_remove(&port, protocol, NULL);
-		g_hash_table_remove(upnp_port_mappings, protocol);
 	} else {
 		protocol = g_hash_table_lookup(nat_pmp_port_mappings, &port);
 		if (protocol) {
 			purple_network_nat_pmp_mapping_remove(&port, protocol, NULL);
-			g_hash_table_remove(nat_pmp_port_mappings, protocol);
 		}
 	}
 }
--- a/libpurple/network.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/network.h	Mon Sep 13 09:57:03 2010 +0000
@@ -239,7 +239,7 @@
  * by passing in the return value from either purple_network_listen()
  * or purple_network_listen_range().
  *
- * @param listen_data This listener attempt will be canceled and
+ * @param listen_data This listener attempt will be cancelled and
  *        the struct will be freed.
  */
 void purple_network_listen_cancel(PurpleNetworkListenData *listen_data);
--- a/libpurple/plugins/idle.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/plugins/idle.c	Mon Sep 13 09:57:03 2010 +0000
@@ -110,9 +110,6 @@
 	for(iter = list; iter; iter = iter->next) {
 		acct = (PurpleAccount *)(iter->data);
 
-		if(acct)
-			prpl_id = purple_account_get_protocol_id(acct);
-
 		if(acct && idleable_filter(acct)) {
 			purple_debug_misc("idle", "Idling %s.\n",
 					purple_account_get_username(acct));
--- a/libpurple/plugins/perl/common/BuddyList.xs	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/plugins/perl/common/BuddyList.xs	Mon Sep 13 09:57:03 2010 +0000
@@ -2,6 +2,13 @@
 #include "module.h"
 #include "../perl-handlers.h"
 
+static void
+chat_components_foreach(gpointer key, gpointer value, gpointer user_data)
+{
+	HV *hv = user_data;
+	hv_store(hv, key, strlen(key), newSVpv(value, 0), 0);
+}
+
 MODULE = Purple::BuddyList  PACKAGE = Purple  PREFIX = purple_
 PROTOTYPES: ENABLE
 
@@ -331,6 +338,19 @@
 purple_chat_get_name(chat)
 	Purple::BuddyList::Chat chat
 
+HV *
+purple_chat_get_components(chat)
+	Purple::BuddyList::Chat chat
+INIT:
+	HV * t_HV;
+	GHashTable * t_GHash;
+CODE:
+	t_GHash = purple_chat_get_components(chat);
+	RETVAL = t_HV = newHV();
+	g_hash_table_foreach(t_GHash, chat_components_foreach, t_HV);
+OUTPUT:
+	RETVAL
+
 Purple::BuddyList::Chat
 purple_chat_new(account, alias, components)
 	Purple::Account account
@@ -345,14 +365,14 @@
 	char *t_key, *t_value;
 CODE:
 	t_HV =  (HV *)SvRV(components);
-	t_GHash = g_hash_table_new(g_str_hash, g_str_equal);
+	t_GHash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 
 	for (t_HE = hv_iternext(t_HV); t_HE != NULL; t_HE = hv_iternext(t_HV) ) {
 		t_key = hv_iterkey(t_HE, &len);
 		t_SV = *hv_fetch(t_HV, t_key, len, 0);
 		t_value = SvPVutf8_nolen(t_SV);
 
-		g_hash_table_insert(t_GHash, t_key, t_value);
+		g_hash_table_insert(t_GHash, g_strdup(t_key), g_strdup(t_value));
 	}
 
 	RETVAL = purple_chat_new(account, alias, t_GHash);
--- a/libpurple/plugins/perl/common/Server.xs	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/plugins/perl/common/Server.xs	Mon Sep 13 09:57:03 2010 +0000
@@ -144,6 +144,7 @@
 		g_hash_table_insert(t_GHash, t_key, t_value);
 	}
 	serv_join_chat(conn, t_GHash);
+	g_hash_table_destroy(t_GHash);
 
 void 
 serv_move_buddy(buddy, group1, group2)
--- a/libpurple/plugins/signals-test.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/plugins/signals-test.c	Mon Sep 13 09:57:03 2010 +0000
@@ -592,12 +592,12 @@
 
 static void
 ft_recv_cancel_cb(PurpleXfer *xfer, gpointer data) {
-	purple_debug_misc("signals test", "file receive canceled\n");
+	purple_debug_misc("signals test", "file receive cancelled\n");
 }
 
 static void
 ft_send_cancel_cb(PurpleXfer *xfer, gpointer data) {
-	purple_debug_misc("signals test", "file send canceled\n");
+	purple_debug_misc("signals test", "file send cancelled\n");
 }
 
 static void
--- a/libpurple/prefs.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/prefs.c	Mon Sep 13 09:57:03 2010 +0000
@@ -506,7 +506,6 @@
 		return g_strdup("/");
 
 	name = g_string_new(pref->name);
-	parent = pref->parent;
 
 	for(parent = pref->parent; parent && parent->name; parent = parent->parent) {
 		name = g_string_prepend_c(name, '/');
--- a/libpurple/protocols/bonjour/bonjour.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Mon Sep 13 09:57:03 2010 +0000
@@ -206,18 +206,12 @@
 {
 	PurpleConnection *gc;
 	BonjourData *bd;
-	gboolean disconnected;
-	PurpleStatusType *type;
-	int primitive;
 	PurplePresence *presence;
 	const char *message, *bonjour_status;
 	gchar *stripped;
 
 	gc = purple_account_get_connection(account);
 	bd = gc->proto_data;
-	disconnected = purple_account_is_disconnected(account);
-	type = purple_status_get_type(status);
-	primitive = purple_status_type_get_primitive(type);
 	presence = purple_account_get_presence(account);
 
 	message = purple_status_get_attr_string(status, "message");
--- a/libpurple/protocols/jabber/Makefile.am	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/Makefile.am	Mon Sep 13 09:57:03 2010 +0000
@@ -26,8 +26,20 @@
 			  data.h \
 			  disco.c \
 			  disco.h \
-			  google.c \
-			  google.h \
+			  google/gmail.c \
+			  google/gmail.h \
+			  google/google.c \
+			  google/google.h \
+			  google/google_presence.c \
+			  google/google_presence.h \
+			  google/google_roster.c \
+			  google/google_roster.h \
+			  google/google_session.c \
+			  google/google_session.h \
+			  google/jingleinfo.c \
+			  google/jingleinfo.h \
+			  google/relay.c \
+			  google/relay.h \
 			  ibb.c \
 			  ibb.h \
 			  iq.c \
@@ -98,7 +110,10 @@
 st =
 pkg_LTLIBRARIES      = libjabber.la libxmpp.la
 libjabber_la_SOURCES = $(JABBERSOURCES)
-libjabber_la_LIBADD  = $(GLIB_LIBS) $(SASL_LIBS) $(LIBXML_LIBS) $(IDN_LIBS)
+libjabber_la_LIBADD  = $(GLIB_LIBS) $(SASL_LIBS) $(LIBXML_LIBS) $(IDN_LIBS)\
+	$(FARSIGHT_LIBS) \
+	$(GSTREAMER_LIBS) \
+	$(GSTINTERFACES_LIBS)
 
 libxmpp_la_SOURCES = libxmpp.c
 libxmpp_la_LIBADD = libjabber.la
@@ -111,4 +126,7 @@
 	$(DEBUG_CFLAGS) \
 	$(GLIB_CFLAGS) \
 	$(IDN_CFLAGS) \
-	$(LIBXML_CFLAGS)
+	$(LIBXML_CFLAGS) \
+	$(FARSIGHT_CFLAGS) \
+	$(GSTREAMER_CFLAGS) \
+	$(GSTINTERFACES_CFLAGS)
--- a/libpurple/protocols/jabber/Makefile.mingw	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/Makefile.mingw	Mon Sep 13 09:57:03 2010 +0000
@@ -55,7 +55,13 @@
 			chat.c \
 			data.c \
 			disco.c \
-			google.c \
+			google/gmail.c \
+			google/google.c \
+			google/google_presence.c \
+			google/google_roster.c \
+			google/google_session.c \
+			google/jingleinfo.c \
+			google/relay.c \
 			ibb.c \
 			iq.c \
 			jabber.c \
--- a/libpurple/protocols/jabber/auth.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/auth.c	Mon Sep 13 09:57:03 2010 +0000
@@ -123,7 +123,7 @@
 	if (!PURPLE_CONNECTION_IS_VALID(gc))
 		return;
 
-	/* Disable the account as the user has canceled connecting */
+	/* Disable the account as the user has cancelled connecting */
 	purple_account_set_enabled(purple_connection_get_account(gc), purple_core_get_ui(), FALSE);
 }
 #endif
@@ -251,7 +251,8 @@
 		g_free(msg);
 	} else if (type == JABBER_IQ_RESULT) {
 		query = xmlnode_get_child(packet, "query");
-		if(js->stream_id && xmlnode_get_child(query, "digest")) {
+		if (js->stream_id && *js->stream_id &&
+				xmlnode_get_child(query, "digest")) {
 			char *s, *hash;
 
 			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
@@ -269,8 +270,10 @@
 			g_free(s);
 			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
 			jabber_iq_send(iq);
-
-		} else if(js->stream_id && (x = xmlnode_get_child(query, "crammd5"))) {
+		} else if ((x = xmlnode_get_child(query, "crammd5"))) {
+			/* For future reference, this appears to be a custom OS X extension
+			 * to non-SASL authentication.
+			 */
 			const char *challenge;
 			gchar digest[33];
 			PurpleCipherContext *hmac;
@@ -340,7 +343,8 @@
 	 * is requiring SSL/TLS, we need to enforce it.
 	 */
 	if (!jabber_stream_is_ssl(js) &&
-			purple_account_get_bool(account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) {
+			g_str_equal("require_tls",
+				purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
 		purple_connection_error_reason(js->gc,
 			PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
 			_("You require encryption, but it is not available on this server."));
--- a/libpurple/protocols/jabber/auth_cyrus.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/auth_cyrus.c	Mon Sep 13 09:57:03 2010 +0000
@@ -94,7 +94,6 @@
 	PurpleAccount *account;
 	const char *pw;
 	size_t len;
-	static sasl_secret_t *x = NULL;
 
 	account = purple_connection_get_account(js->gc);
 	pw = purple_account_get_password(account);
@@ -104,15 +103,15 @@
 
 	len = strlen(pw);
 	/* Not an off-by-one because sasl_secret_t defines char data[1] */
-	x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
-
-	if (!x)
+	/* TODO: This can probably be moved to glib's allocator */
+	js->sasl_secret = malloc(sizeof(sasl_secret_t) + len);
+	if (!js->sasl_secret)
 		return SASL_NOMEM;
 
-	x->len = len;
-	strcpy((char*)x->data, pw);
+	js->sasl_secret->len = len;
+	strcpy((char*)js->sasl_secret->data, pw);
 
-	*secret = x;
+	*secret = js->sasl_secret;
 	return SASL_OK;
 }
 
@@ -177,7 +176,7 @@
 	account = purple_connection_get_account(gc);
 	js = purple_connection_get_protocol_data(gc);
 
-	/* Disable the account as the user has canceled connecting */
+	/* Disable the account as the user has cancelled connecting */
 	purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
 }
 
--- a/libpurple/protocols/jabber/buddy.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Mon Sep 13 09:57:03 2010 +0000
@@ -38,7 +38,7 @@
 #include "xdata.h"
 #include "pep.h"
 #include "adhoccommands.h"
-#include "google.h"
+#include "google/google.h"
 
 typedef struct {
 	long idle_seconds;
--- a/libpurple/protocols/jabber/disco.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/disco.c	Mon Sep 13 09:57:03 2010 +0000
@@ -30,7 +30,9 @@
 #include "adhoccommands.h"
 #include "buddy.h"
 #include "disco.h"
-#include "google.h"
+#include "google/google.h"
+#include "google/gmail.h"
+#include "google/jingleinfo.h"
 #include "iq.h"
 #include "jabber.h"
 #include "jingle/jingle.h"
@@ -597,7 +599,7 @@
 	for(child = xmlnode_get_child(query, "item"); child;
 			child = xmlnode_get_next_twin(child)) {
 		JabberIq *iq;
-		const char *jid, *node;
+		const char *jid;
 
 		if(!(jid = xmlnode_get_attrib(child, "jid")))
 			continue;
--- a/libpurple/protocols/jabber/google.c	Fri Aug 20 08:35:27 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1429 +0,0 @@
-/**
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#include "internal.h"
-#include "debug.h"
-#include "mediamanager.h"
-#include "util.h"
-#include "privacy.h"
-#include "dnsquery.h"
-#include "network.h"
-
-#include "buddy.h"
-#include "google.h"
-#include "jabber.h"
-#include "presence.h"
-#include "roster.h"
-#include "iq.h"
-#include "chat.h"
-
-#include "jingle/jingle.h"
-
-#ifdef USE_VV
-
-typedef struct {
-	char *id;
-	char *initiator;
-} GoogleSessionId;
-
-typedef enum {
-	UNINIT,
-	SENT_INITIATE,
-	RECEIVED_INITIATE,
-	IN_PRORESS,
-	TERMINATED
-} GoogleSessionState;
-
-typedef struct {
-	GoogleSessionId id;
-	GoogleSessionState state;
-	PurpleMedia *media;
-	JabberStream *js;
-	char *remote_jid;
-	gboolean video;
-} GoogleSession;
-
-static gboolean
-google_session_id_equal(gconstpointer a, gconstpointer b)
-{
-	GoogleSessionId *c = (GoogleSessionId*)a;
-	GoogleSessionId *d = (GoogleSessionId*)b;
-
-	return !strcmp(c->id, d->id) && !strcmp(c->initiator, d->initiator);
-}
-
-static void
-google_session_destroy(GoogleSession *session)
-{
-	g_free(session->id.id);
-	g_free(session->id.initiator);
-	g_free(session->remote_jid);
-	g_free(session);
-}
-
-static xmlnode *
-google_session_create_xmlnode(GoogleSession *session, const char *type)
-{
-	xmlnode *node = xmlnode_new("session");
-	xmlnode_set_namespace(node, NS_GOOGLE_SESSION);
-	xmlnode_set_attrib(node, "id", session->id.id);
-	xmlnode_set_attrib(node, "initiator", session->id.initiator);
-	xmlnode_set_attrib(node, "type", type);
-	return node;
-}
-
-static void
-google_session_send_candidates(PurpleMedia *media, gchar *session_id,
-		gchar *participant, GoogleSession *session)
-{
-	GList *candidates = purple_media_get_local_candidates(
-			session->media, session_id, session->remote_jid), *iter;
-	PurpleMediaCandidate *transport;
-	gboolean video = FALSE;
-
-	if (!strcmp(session_id, "google-video"))
-		video = TRUE;
-
-	for (iter = candidates; iter; iter = iter->next) {
-		JabberIq *iq;
-		gchar *ip, *port, *username, *password;
-		gchar pref[16];
-		PurpleMediaCandidateType type;
-		xmlnode *sess;
-		xmlnode *candidate;
-		guint component_id;
-		transport = PURPLE_MEDIA_CANDIDATE(iter->data);
-		component_id = purple_media_candidate_get_component_id(
-				transport);
-
-		iq = jabber_iq_new(session->js, JABBER_IQ_SET);
-		sess = google_session_create_xmlnode(session, "candidates");
-		xmlnode_insert_child(iq->node, sess);
-		xmlnode_set_attrib(iq->node, "to", session->remote_jid);
-
-		candidate = xmlnode_new("candidate");
-
-		ip = purple_media_candidate_get_ip(transport);
-		port = g_strdup_printf("%d",
-				purple_media_candidate_get_port(transport));
-		g_ascii_dtostr(pref, 16,
-			purple_media_candidate_get_priority(transport) / 1000.0);
-		username = purple_media_candidate_get_username(transport);
-		password = purple_media_candidate_get_password(transport);
-		type = purple_media_candidate_get_candidate_type(transport);
-
-		xmlnode_set_attrib(candidate, "address", ip);
-		xmlnode_set_attrib(candidate, "port", port);
-		xmlnode_set_attrib(candidate, "name",
-				component_id == PURPLE_MEDIA_COMPONENT_RTP ?
-				video ? "video_rtp" : "rtp" :
-				component_id == PURPLE_MEDIA_COMPONENT_RTCP ?
-				video ? "video_rtcp" : "rtcp" : "none");
-		xmlnode_set_attrib(candidate, "username", username);
-		/*
-		 * As of this writing, Farsight 2 in Google compatibility
-		 * mode doesn't provide a password. The Gmail client
-		 * requires this to be set.
-		 */
-		xmlnode_set_attrib(candidate, "password",
-				password != NULL ? password : "");
-		xmlnode_set_attrib(candidate, "preference", pref);
-		xmlnode_set_attrib(candidate, "protocol",
-				purple_media_candidate_get_protocol(transport)
-				== PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ?
-				"udp" : "tcp");
-		xmlnode_set_attrib(candidate, "type", type ==
-				PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "local" :
-						      type ==
-				PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "stun" :
-					       	      type ==
-				PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" :
-				NULL);
-		xmlnode_set_attrib(candidate, "generation", "0");
-		xmlnode_set_attrib(candidate, "network", "0");
-		xmlnode_insert_child(sess, candidate);
-
-		g_free(ip);
-		g_free(port);
-		g_free(username);
-		g_free(password);
-
-		jabber_iq_send(iq);
-	}
-	purple_media_candidate_list_free(candidates);
-}
-
-static void
-google_session_ready(GoogleSession *session)
-{
-	PurpleMedia *media = session->media;
-	if (purple_media_codecs_ready(media, NULL) &&
-			purple_media_candidates_prepared(media, NULL, NULL)) {
-		gchar *me = g_strdup_printf("%s@%s/%s",
-				session->js->user->node,
-				session->js->user->domain,
-				session->js->user->resource);
-		JabberIq *iq;
-		xmlnode *sess, *desc, *payload;
-		GList *codecs, *iter;
-		gboolean is_initiator = !strcmp(session->id.initiator, me);
-
-		if (!is_initiator &&
-				!purple_media_accepted(media, NULL, NULL)) {
-			g_free(me);
-			return;
-		}
-
-		iq = jabber_iq_new(session->js, JABBER_IQ_SET);
-
-		if (is_initiator) {
-			xmlnode_set_attrib(iq->node, "to", session->remote_jid);
-			xmlnode_set_attrib(iq->node, "from", session->id.initiator);
-			sess = google_session_create_xmlnode(session, "initiate");
-		} else {
-			google_session_send_candidates(session->media,
-					"google-voice", session->remote_jid,
-					session);
-			google_session_send_candidates(session->media,
-					"google-video", session->remote_jid,
-					session);
-			xmlnode_set_attrib(iq->node, "to", session->remote_jid);
-			xmlnode_set_attrib(iq->node, "from", me);
-			sess = google_session_create_xmlnode(session, "accept");
-		}
-		xmlnode_insert_child(iq->node, sess);
-		desc = xmlnode_new_child(sess, "description");
-		if (session->video)
-			xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_VIDEO);
-		else
-			xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_PHONE);
-
-		codecs = purple_media_get_codecs(media, "google-video");
-
-		for (iter = codecs; iter; iter = g_list_next(iter)) {
-			PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
-			gchar *id = g_strdup_printf("%d",
-					purple_media_codec_get_id(codec));
-			gchar *encoding_name =
-					purple_media_codec_get_encoding_name(codec);
-			payload = xmlnode_new_child(desc, "payload-type");
-			xmlnode_set_attrib(payload, "id", id);
-			xmlnode_set_attrib(payload, "name", encoding_name);
-			xmlnode_set_attrib(payload, "width", "320");
-			xmlnode_set_attrib(payload, "height", "200");
-			xmlnode_set_attrib(payload, "framerate", "30");
-			g_free(encoding_name);
-			g_free(id);
-		}
-		purple_media_codec_list_free(codecs);
-
-		codecs = purple_media_get_codecs(media, "google-voice");
-
-		for (iter = codecs; iter; iter = g_list_next(iter)) {
-			PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
-			gchar *id = g_strdup_printf("%d",
-					purple_media_codec_get_id(codec));
-			gchar *encoding_name =
-					purple_media_codec_get_encoding_name(codec);
-			gchar *clock_rate = g_strdup_printf("%d",
-					purple_media_codec_get_clock_rate(codec));
-			payload = xmlnode_new_child(desc, "payload-type");
-			if (session->video)
-				xmlnode_set_namespace(payload, NS_GOOGLE_SESSION_PHONE);
-			xmlnode_set_attrib(payload, "id", id);
-			/*
-			 * Hack to make Gmail accept speex as the codec.
-			 * It shouldn't have to be case sensitive.
-			 */
-			if (purple_strequal(encoding_name, "SPEEX"))
-				xmlnode_set_attrib(payload, "name", "speex");
-			else
-				xmlnode_set_attrib(payload, "name", encoding_name);
-			xmlnode_set_attrib(payload, "clockrate", clock_rate);
-			g_free(clock_rate);
-			g_free(encoding_name);
-			g_free(id);
-		}
-		purple_media_codec_list_free(codecs);
-
-		jabber_iq_send(iq);
-
-		if (is_initiator) {
-			google_session_send_candidates(session->media,
-					"google-voice", session->remote_jid,
-					session);
-			google_session_send_candidates(session->media,
-					"google-video", session->remote_jid,
-					session);
-		}
-
-		g_signal_handlers_disconnect_by_func(G_OBJECT(session->media),
-				G_CALLBACK(google_session_ready), session);
-	}
-}
-
-static void
-google_session_state_changed_cb(PurpleMedia *media, PurpleMediaState state,
-		gchar *sid, gchar *name, GoogleSession *session)
-{
-	if (sid == NULL && name == NULL) {
-		if (state == PURPLE_MEDIA_STATE_END) {
-			google_session_destroy(session);
-		}
-	}
-}
-
-static void
-google_session_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
-		gchar *sid, gchar *name, gboolean local,
-		GoogleSession *session)
-{
-	if (sid != NULL || name != NULL)
-		return;
-
-	if (type == PURPLE_MEDIA_INFO_HANGUP) {
-		xmlnode *sess;
-		JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
-
-		xmlnode_set_attrib(iq->node, "to", session->remote_jid);
-		sess = google_session_create_xmlnode(session, "terminate");
-		xmlnode_insert_child(iq->node, sess);
-
-		jabber_iq_send(iq);
-	} else if (type == PURPLE_MEDIA_INFO_REJECT) {
-		xmlnode *sess;
-		JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
-
-		xmlnode_set_attrib(iq->node, "to", session->remote_jid);
-		sess = google_session_create_xmlnode(session, "reject");
-		xmlnode_insert_child(iq->node, sess);
-
-		jabber_iq_send(iq);
-	} else if (type == PURPLE_MEDIA_INFO_ACCEPT && local == TRUE) {
-		google_session_ready(session);
-	}
-}
-
-static GParameter *
-jabber_google_session_get_params(JabberStream *js, guint *num)
-{
-	guint num_params;
-	GParameter *params = jingle_get_params(js, &num_params);
-	GParameter *new_params = g_new0(GParameter, num_params + 1);
-
-	memcpy(new_params, params, sizeof(GParameter) * num_params);
-
-	purple_debug_info("jabber", "setting Google jingle compatibility param\n");
-	new_params[num_params].name = "compatibility-mode";
-	g_value_init(&new_params[num_params].value, G_TYPE_UINT);
-	g_value_set_uint(&new_params[num_params].value, 1); /* NICE_COMPATIBILITY_GOOGLE */
-
-	g_free(params);
-	*num = num_params + 1;
-	return new_params;
-}
-
-
-gboolean
-jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type)
-{
-	GoogleSession *session;
-	JabberBuddy *jb;
-	JabberBuddyResource *jbr;
-	gchar *jid;
-	GParameter *params;
-	guint num_params;
-
-	/* construct JID to send to */
-	jb = jabber_buddy_find(js, who, FALSE);
-	if (!jb) {
-		purple_debug_error("jingle-rtp",
-				"Could not find Jabber buddy\n");
-		return FALSE;
-	}
-	jbr = jabber_buddy_find_resource(jb, NULL);
-	if (!jbr) {
-		purple_debug_error("jingle-rtp",
-				"Could not find buddy's resource\n");
-	}
-
-	if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) {
-		jid = g_strdup_printf("%s/%s", who, jbr->name);
-	} else {
-		jid = g_strdup(who);
-	}
-
-	session = g_new0(GoogleSession, 1);
-	session->id.id = jabber_get_next_id(js);
-	session->id.initiator = g_strdup_printf("%s@%s/%s", js->user->node,
-			js->user->domain, js->user->resource);
-	session->state = SENT_INITIATE;
-	session->js = js;
-	session->remote_jid = jid;
-
-	if (type & PURPLE_MEDIA_VIDEO)
-		session->video = TRUE;
-
-	session->media = purple_media_manager_create_media(
-			purple_media_manager_get(),
-			purple_connection_get_account(js->gc),
-			"fsrtpconference", session->remote_jid, TRUE);
-
-	purple_media_set_prpl_data(session->media, session);
-
-	g_signal_connect_swapped(G_OBJECT(session->media),
-			"candidates-prepared",
-			G_CALLBACK(google_session_ready), session);
-	g_signal_connect_swapped(G_OBJECT(session->media), "codecs-changed",
-			G_CALLBACK(google_session_ready), session);
-	g_signal_connect(G_OBJECT(session->media), "state-changed",
-			G_CALLBACK(google_session_state_changed_cb), session);
-	g_signal_connect(G_OBJECT(session->media), "stream-info",
-			G_CALLBACK(google_session_stream_info_cb), session);
-
-	params = jabber_google_session_get_params(js, &num_params);
-
-	if (purple_media_add_stream(session->media, "google-voice",
-			session->remote_jid, PURPLE_MEDIA_AUDIO,
-			TRUE, "nice", num_params, params) == FALSE ||
-			(session->video && purple_media_add_stream(
-			session->media, "google-video",
-			session->remote_jid, PURPLE_MEDIA_VIDEO,
-			TRUE, "nice", num_params, params) == FALSE)) {
-		purple_media_error(session->media, "Error adding stream.");
-		purple_media_end(session->media, NULL, NULL);
-		g_free(params);
-		return FALSE;
-	}
-
-	g_free(params);
-
-	return (session->media != NULL) ? TRUE : FALSE;
-}
-
-static gboolean
-google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
-{
-	JabberIq *result;
-	GList *codecs = NULL, *video_codecs = NULL;
-	xmlnode *desc_element, *codec_element;
-	PurpleMediaCodec *codec;
-	const char *xmlns;
-	GParameter *params;
-	guint num_params;
-
-	if (session->state != UNINIT) {
-		purple_debug_error("jabber", "Received initiate for active session.\n");
-		return FALSE;
-	}
-
-	desc_element = xmlnode_get_child(sess, "description");
-	xmlns = xmlnode_get_namespace(desc_element);
-
-	if (purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE))
-		session->video = FALSE;
-	else if (purple_strequal(xmlns, NS_GOOGLE_SESSION_VIDEO))
-		session->video = TRUE;
-	else {
-		purple_debug_error("jabber", "Received initiate with "
-				"invalid namespace %s.\n", xmlns);
-		return FALSE;
-	}
-
-	session->media = purple_media_manager_create_media(
-			purple_media_manager_get(),
-			purple_connection_get_account(js->gc),
-			"fsrtpconference", session->remote_jid, FALSE);
-
-	purple_media_set_prpl_data(session->media, session);
-
-	g_signal_connect_swapped(G_OBJECT(session->media),
-			"candidates-prepared",
-			G_CALLBACK(google_session_ready), session);
-	g_signal_connect_swapped(G_OBJECT(session->media), "codecs-changed",
-			G_CALLBACK(google_session_ready), session);
-	g_signal_connect(G_OBJECT(session->media), "state-changed",
-			G_CALLBACK(google_session_state_changed_cb), session);
-	g_signal_connect(G_OBJECT(session->media), "stream-info",
-			G_CALLBACK(google_session_stream_info_cb), session);
-
-	params = jabber_google_session_get_params(js, &num_params);
-
-	if (purple_media_add_stream(session->media, "google-voice",
-			session->remote_jid, PURPLE_MEDIA_AUDIO, FALSE,
-			"nice", num_params, params) == FALSE ||
-			(session->video && purple_media_add_stream(
-			session->media, "google-video",
-			session->remote_jid, PURPLE_MEDIA_VIDEO,
-			FALSE, "nice", num_params, params) == FALSE)) {
-		purple_media_error(session->media, "Error adding stream.");
-		purple_media_stream_info(session->media,
-				PURPLE_MEDIA_INFO_REJECT, NULL, NULL, TRUE);
-		g_free(params);
-		return FALSE;
-	}
-
-	g_free(params);
-
-	for (codec_element = xmlnode_get_child(desc_element, "payload-type");
-	     codec_element; codec_element = codec_element->next) {
-		const char *id, *encoding_name,  *clock_rate,
-				*width, *height, *framerate;
-		gboolean video;
-		if (codec_element->name &&
-				strcmp(codec_element->name, "payload-type"))
-			continue;
-
-		xmlns = xmlnode_get_namespace(codec_element);
-		encoding_name = xmlnode_get_attrib(codec_element, "name");
-		id = xmlnode_get_attrib(codec_element, "id");
-
-		if (!session->video ||
-				(xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_PHONE))) {
-			clock_rate = xmlnode_get_attrib(
-					codec_element, "clockrate");
-			video = FALSE;
-		} else {
-			width = xmlnode_get_attrib(codec_element, "width");
-			height = xmlnode_get_attrib(codec_element, "height");
-			framerate = xmlnode_get_attrib(
-					codec_element, "framerate");
-			clock_rate = "90000";
-			video = TRUE;
-		}
-
-		if (id) {
-			codec = purple_media_codec_new(atoi(id), encoding_name,
-					video ?	PURPLE_MEDIA_VIDEO :
-					PURPLE_MEDIA_AUDIO,
-					clock_rate ? atoi(clock_rate) : 0);
-			if (video)
-				video_codecs = g_list_append(
-						video_codecs, codec);
-			else
-				codecs = g_list_append(codecs, codec);
-		}
-	}
-
-	if (codecs)
-		purple_media_set_remote_codecs(session->media, "google-voice",
-				session->remote_jid, codecs);
-	if (video_codecs)
-		purple_media_set_remote_codecs(session->media, "google-video",
-				session->remote_jid, video_codecs);
-
-	purple_media_codec_list_free(codecs);
-	purple_media_codec_list_free(video_codecs);
-
-	result = jabber_iq_new(js, JABBER_IQ_RESULT);
-	jabber_iq_set_id(result, iq_id);
-	xmlnode_set_attrib(result->node, "to", session->remote_jid);
-	jabber_iq_send(result);
-
-	return TRUE;
-}
-
-static void
-google_session_handle_candidates(JabberStream  *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
-{
-	JabberIq *result;
-	GList *list = NULL, *video_list = NULL;
-	xmlnode *cand;
-	static int name = 0;
-	char n[4];
-
-	for (cand = xmlnode_get_child(sess, "candidate"); cand;
-			cand = xmlnode_get_next_twin(cand)) {
-		PurpleMediaCandidate *info;
-		const gchar *cname = xmlnode_get_attrib(cand, "name");
-		const gchar *type = xmlnode_get_attrib(cand, "type");
-		const gchar *protocol = xmlnode_get_attrib(cand, "protocol");
-		const gchar *address = xmlnode_get_attrib(cand, "address");
-		const gchar *port = xmlnode_get_attrib(cand, "port");
-		guint component_id;
-
-		if (cname && type && address && port) {
-			PurpleMediaCandidateType candidate_type;
-
-			g_snprintf(n, sizeof(n), "S%d", name++);
-
-			if (g_str_equal(type, "local"))
-				candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
-			else if (g_str_equal(type, "stun"))
-				candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX;
-			else if (g_str_equal(type, "relay"))
-				candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_RELAY;
-			else
-				candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
-
-			if (purple_strequal(cname, "rtcp") ||
-					purple_strequal(cname, "video_rtcp"))
-				component_id = PURPLE_MEDIA_COMPONENT_RTCP;
-			else
-				component_id = PURPLE_MEDIA_COMPONENT_RTP;
-
-			info = purple_media_candidate_new(n, component_id,
-					candidate_type,
-					purple_strequal(protocol, "udp") ?
-							PURPLE_MEDIA_NETWORK_PROTOCOL_UDP :
-							PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
-					address,
-					atoi(port));
-			g_object_set(info, "username", xmlnode_get_attrib(cand, "username"),
-					"password", xmlnode_get_attrib(cand, "password"), NULL);
-			if (!strncmp(cname, "video_", 6))
-				video_list = g_list_append(video_list, info);
-			else
-				list = g_list_append(list, info);
-		}
-	}
-
-	if (list)
-		purple_media_add_remote_candidates(
-				session->media, "google-voice",
-				session->remote_jid, list);
-	if (video_list)
-		purple_media_add_remote_candidates(
-				session->media, "google-video",
-				session->remote_jid, video_list);
-	purple_media_candidate_list_free(list);
-	purple_media_candidate_list_free(video_list);
-
-	result = jabber_iq_new(js, JABBER_IQ_RESULT);
-	jabber_iq_set_id(result, iq_id);
-	xmlnode_set_attrib(result->node, "to", session->remote_jid);
-	jabber_iq_send(result);
-}
-
-static void
-google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
-{
-	xmlnode *desc_element = xmlnode_get_child(sess, "description");
-	xmlnode *codec_element = xmlnode_get_child(
-			desc_element, "payload-type");
-	GList *codecs = NULL, *video_codecs = NULL;
-	JabberIq *result = NULL;
-	const gchar *xmlns = xmlnode_get_namespace(desc_element);
-	gboolean video = (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_VIDEO));
-
-	for (; codec_element; codec_element = codec_element->next) {
-		const gchar *xmlns, *encoding_name, *id,
-				*clock_rate, *width, *height, *framerate;
-		gboolean video_codec = FALSE;
-
-		if (!purple_strequal(codec_element->name, "payload-type"))
-			continue;
-
-		xmlns = xmlnode_get_namespace(codec_element);
-		encoding_name =	xmlnode_get_attrib(codec_element, "name");
-		id = xmlnode_get_attrib(codec_element, "id");
-
-		if (!video || purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE))
-			clock_rate = xmlnode_get_attrib(
-					codec_element, "clockrate");
-		else {
-			clock_rate = "90000";
-			width = xmlnode_get_attrib(codec_element, "width");
-			height = xmlnode_get_attrib(codec_element, "height");
-			framerate = xmlnode_get_attrib(
-					codec_element, "framerate");
-			video_codec = TRUE;
-		}
-
-		if (id && encoding_name) {
-			PurpleMediaCodec *codec = purple_media_codec_new(
-					atoi(id), encoding_name,
-					video_codec ? PURPLE_MEDIA_VIDEO :
-					PURPLE_MEDIA_AUDIO,
-					clock_rate ? atoi(clock_rate) : 0);
-			if (video_codec)
-				video_codecs = g_list_append(
-						video_codecs, codec);
-			else
-				codecs = g_list_append(codecs, codec);
-		}
-	}
-
-	if (codecs)
-		purple_media_set_remote_codecs(session->media, "google-voice",
-				session->remote_jid, codecs);
-	if (video_codecs)
-		purple_media_set_remote_codecs(session->media, "google-video",
-				session->remote_jid, video_codecs);
-
-	purple_media_stream_info(session->media, PURPLE_MEDIA_INFO_ACCEPT,
-			NULL, NULL, FALSE);
-
-	result = jabber_iq_new(js, JABBER_IQ_RESULT);
-	jabber_iq_set_id(result, iq_id);
-	xmlnode_set_attrib(result->node, "to", session->remote_jid);
-	jabber_iq_send(result);
-}
-
-static void
-google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *sess)
-{
-	purple_media_end(session->media, NULL, NULL);
-}
-
-static void
-google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *sess)
-{
-	purple_media_end(session->media, NULL, NULL);
-}
-
-static void
-google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
-{
-	const char *type = xmlnode_get_attrib(sess, "type");
-
-	if (!strcmp(type, "initiate")) {
-		google_session_handle_initiate(js, session, sess, iq_id);
-	} else if (!strcmp(type, "accept")) {
-		google_session_handle_accept(js, session, sess, iq_id);
-	} else if (!strcmp(type, "reject")) {
-		google_session_handle_reject(js, session, sess);
-	} else if (!strcmp(type, "terminate")) {
-		google_session_handle_terminate(js, session, sess);
-	} else if (!strcmp(type, "candidates")) {
-		google_session_handle_candidates(js, session, sess, iq_id);
-	}
-}
-
-void
-jabber_google_session_parse(JabberStream *js, const char *from,
-                            JabberIqType type, const char *iq_id,
-                            xmlnode *session_node)
-{
-	GoogleSession *session = NULL;
-	GoogleSessionId id;
-
-	xmlnode *desc_node;
-
-	GList *iter = NULL;
-
-	if (type != JABBER_IQ_SET)
-		return;
-
-	id.id = (gchar*)xmlnode_get_attrib(session_node, "id");
-	if (!id.id)
-		return;
-
-	id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator");
-	if (!id.initiator)
-		return;
-
-	iter = purple_media_manager_get_media_by_account(
-			purple_media_manager_get(),
-			purple_connection_get_account(js->gc));
-	for (; iter; iter = g_list_delete_link(iter, iter)) {
-		GoogleSession *gsession =
-				purple_media_get_prpl_data(iter->data);
-		if (google_session_id_equal(&(gsession->id), &id)) {
-			session = gsession;
-			break;
-		}
-	}
-	if (iter != NULL) {
-		g_list_free(iter);
-	}
-
-	if (session) {
-		google_session_parse_iq(js, session, session_node, iq_id);
-		return;
-	}
-
-	/* If the session doesn't exist, this has to be an initiate message */
-	if (strcmp(xmlnode_get_attrib(session_node, "type"), "initiate"))
-		return;
-	desc_node = xmlnode_get_child(session_node, "description");
-	if (!desc_node)
-		return;
-	session = g_new0(GoogleSession, 1);
-	session->id.id = g_strdup(id.id);
-	session->id.initiator = g_strdup(id.initiator);
-	session->state = UNINIT;
-	session->js = js;
-	session->remote_jid = g_strdup(session->id.initiator);
-
-	google_session_handle_initiate(js, session, session_node, iq_id);
-}
-#endif /* USE_VV */
-
-static void
-jabber_gmail_parse(JabberStream *js, const char *from,
-                   JabberIqType type, const char *id,
-                   xmlnode *packet, gpointer nul)
-{
-	xmlnode *child;
-	xmlnode *message;
-	const char *to, *url;
-	const char *in_str;
-	char *to_name;
-
-	int i, count = 1, returned_count;
-
-	const char **tos, **froms, **urls;
-	char **subjects;
-
-	if (type == JABBER_IQ_ERROR)
-		return;
-
-	child = xmlnode_get_child(packet, "mailbox");
-	if (!child)
-		return;
-
-	in_str = xmlnode_get_attrib(child, "total-matched");
-	if (in_str && *in_str)
-		count = atoi(in_str);
-
-	/* If Gmail doesn't tell us who the mail is to, let's use our JID */
-	to = xmlnode_get_attrib(packet, "to");
-
-	message = xmlnode_get_child(child, "mail-thread-info");
-
-	if (count == 0 || !message) {
-		if (count > 0) {
-			char *bare_jid = jabber_get_bare_jid(to);
-			const char *default_tos[2] = { bare_jid };
-
-			purple_notify_emails(js->gc, count, FALSE, NULL, NULL, default_tos, NULL, NULL, NULL);
-			g_free(bare_jid);
-		} else {
-			purple_notify_emails(js->gc, count, FALSE, NULL, NULL, NULL, NULL, NULL, NULL);
-		}
-
-		return;
-	}
-
-	/* Loop once to see how many messages were returned so we can allocate arrays
-	 * accordingly */
-	for (returned_count = 0; message; returned_count++, message=xmlnode_get_next_twin(message));
-
-	froms    = g_new0(const char* , returned_count + 1);
-	tos      = g_new0(const char* , returned_count + 1);
-	subjects = g_new0(char* , returned_count + 1);
-	urls     = g_new0(const char* , returned_count + 1);
-
-	to = xmlnode_get_attrib(packet, "to");
-	to_name = jabber_get_bare_jid(to);
-	url = xmlnode_get_attrib(child, "url");
-	if (!url || !*url)
-		url = "http://www.gmail.com";
-
-	message= xmlnode_get_child(child, "mail-thread-info");
-	for (i=0; message; message = xmlnode_get_next_twin(message), i++) {
-		xmlnode *sender_node, *subject_node;
-		const char *from, *tid;
-		char *subject;
-
-		subject_node = xmlnode_get_child(message, "subject");
-		sender_node  = xmlnode_get_child(message, "senders");
-		sender_node  = xmlnode_get_child(sender_node, "sender");
-
-		while (sender_node && (!xmlnode_get_attrib(sender_node, "unread") ||
-		       !strcmp(xmlnode_get_attrib(sender_node, "unread"),"0")))
-			sender_node = xmlnode_get_next_twin(sender_node);
-
-		if (!sender_node) {
-			i--;
-			continue;
-		}
-
-		from = xmlnode_get_attrib(sender_node, "name");
-		if (!from || !*from)
-			from = xmlnode_get_attrib(sender_node, "address");
-		subject = xmlnode_get_data(subject_node);
-		/*
-		 * url = xmlnode_get_attrib(message, "url");
-		 */
-		tos[i] = (to_name != NULL ?  to_name : "");
-		froms[i] = (from != NULL ?  from : "");
-		subjects[i] = (subject != NULL ? subject : g_strdup(""));
-		urls[i] = url;
-
-		tid = xmlnode_get_attrib(message, "tid");
-		if (tid &&
-		    (js->gmail_last_tid == NULL || strcmp(tid, js->gmail_last_tid) > 0)) {
-			g_free(js->gmail_last_tid);
-			js->gmail_last_tid = g_strdup(tid);
-		}
-	}
-
-	if (i>0)
-		purple_notify_emails(js->gc, count, count == i, (const char**) subjects, froms, tos,
-				urls, NULL, NULL);
-
-	g_free(to_name);
-	g_free(tos);
-	g_free(froms);
-	for (i = 0; i < returned_count; i++)
-		g_free(subjects[i]);
-	g_free(subjects);
-	g_free(urls);
-
-	in_str = xmlnode_get_attrib(child, "result-time");
-	if (in_str && *in_str) {
-		g_free(js->gmail_last_time);
-		js->gmail_last_time = g_strdup(in_str);
-	}
-}
-
-void
-jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
-                  const char *id, xmlnode *new_mail)
-{
-	xmlnode *query;
-	JabberIq *iq;
-
-	/* bail if the user isn't interested */
-	if (!purple_account_get_check_mail(js->gc->account))
-		return;
-
-	/* Is this an initial incoming mail notification? If so, send a request for more info */
-	if (type != JABBER_IQ_SET)
-		return;
-
-	/* Acknowledge the notification */
-	iq = jabber_iq_new(js, JABBER_IQ_RESULT);
-	if (from)
-		xmlnode_set_attrib(iq->node, "to", from);
-	xmlnode_set_attrib(iq->node, "id", id);
-	jabber_iq_send(iq);
-
-	purple_debug_misc("jabber",
-		   "Got new mail notification. Sending request for more info\n");
-
-	iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
-	jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
-	query = xmlnode_get_child(iq->node, "query");
-
-	if (js->gmail_last_time)
-		xmlnode_set_attrib(query, "newer-than-time", js->gmail_last_time);
-	if (js->gmail_last_tid)
-		xmlnode_set_attrib(query, "newer-than-tid", js->gmail_last_tid);
-
-	jabber_iq_send(iq);
-	return;
-}
-
-void jabber_gmail_init(JabberStream *js) {
-	JabberIq *iq;
-	xmlnode *usersetting, *mailnotifications;
-
-	if (!purple_account_get_check_mail(purple_connection_get_account(js->gc)))
-		return;
-
-	/*
-	 * Quoting http://code.google.com/apis/talk/jep_extensions/usersettings.html:
-	 * To ensure better compatibility with other clients, rather than
-	 * setting this value to "false" to turn off notifications, it is
-	 * recommended that a client set this to "true" and filter incoming
-	 * email notifications itself.
-	 */
-	iq = jabber_iq_new(js, JABBER_IQ_SET);
-	usersetting = xmlnode_new_child(iq->node, "usersetting");
-	xmlnode_set_namespace(usersetting, "google:setting");
-	mailnotifications = xmlnode_new_child(usersetting, "mailnotifications");
-	xmlnode_set_attrib(mailnotifications, "value", "true");
-	jabber_iq_send(iq);
-
-	iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
-	jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
-	jabber_iq_send(iq);
-}
-
-void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item)
-{
-	PurpleAccount *account = purple_connection_get_account(js->gc);
-	GSList *list = account->deny;
-	const char *jid = xmlnode_get_attrib(item, "jid");
-	char *jid_norm = (char *)jabber_normalize(account, jid);
-
-	while (list) {
-		if (!strcmp(jid_norm, (char*)list->data)) {
-			xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
-			xmlnode_set_attrib(query, "gr:ext", "2");
-			xmlnode_set_attrib(item, "gr:t", "B");
-			return;
-		}
-		list = list->next;
-	}
-}
-
-gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item)
-{
-	PurpleAccount *account = purple_connection_get_account(js->gc);
-	const char *jid = xmlnode_get_attrib(item, "jid");
-	gboolean on_block_list = FALSE;
-
-	char *jid_norm;
-
-	const char *grt = xmlnode_get_attrib_with_namespace(item, "t", NS_GOOGLE_ROSTER);
-	const char *subscription = xmlnode_get_attrib(item, "subscription");
-	const char *ask = xmlnode_get_attrib(item, "ask");
-
-	if ((!subscription || !strcmp(subscription, "none")) && !ask) {
-		/* The Google Talk servers will automatically add people from your Gmail address book
-		 * with subscription=none. If we see someone with subscription=none, ignore them.
-		 */
-		return FALSE;
-	}
-
- 	jid_norm = g_strdup(jabber_normalize(account, jid));
-
-	on_block_list = NULL != g_slist_find_custom(account->deny, jid_norm,
-	                                            (GCompareFunc)strcmp);
-
-	if (grt && (*grt == 'H' || *grt == 'h')) {
-		/* Hidden; don't show this buddy. */
-		GSList *buddies = purple_find_buddies(account, jid_norm);
-		if (buddies)
-			purple_debug_info("jabber", "Removing %s from local buddy list\n",
-			                  jid_norm);
-
-		for ( ; buddies; buddies = g_slist_delete_link(buddies, buddies)) {
-			purple_blist_remove_buddy(buddies->data);
-		}
-
-		g_free(jid_norm);
-		return FALSE;
-	}
-
-	if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) {
-		purple_debug_info("jabber", "Blocking %s\n", jid_norm);
-		purple_privacy_deny_add(account, jid_norm, TRUE);
-	} else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){
-		purple_debug_info("jabber", "Unblocking %s\n", jid_norm);
-		purple_privacy_deny_remove(account, jid_norm, TRUE);
-	}
-
-	g_free(jid_norm);
-	return TRUE;
-}
-
-void jabber_google_roster_add_deny(JabberStream *js, const char *who)
-{
-	PurpleAccount *account;
-	GSList *buddies;
-	JabberIq *iq;
-	xmlnode *query;
-	xmlnode *item;
-	xmlnode *group;
-	PurpleBuddy *b;
-	JabberBuddy *jb;
-	const char *balias;
-
-	jb = jabber_buddy_find(js, who, TRUE);
-
-	account = purple_connection_get_account(js->gc);
-	buddies = purple_find_buddies(account, who);
-	if(!buddies)
-		return;
-
-	b = buddies->data;
-
-	iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
-
-	query = xmlnode_get_child(iq->node, "query");
-	item = xmlnode_new_child(query, "item");
-
-	while(buddies) {
-		PurpleGroup *g;
-
-		b = buddies->data;
-		g = purple_buddy_get_group(b);
-
-		group = xmlnode_new_child(item, "group");
-		xmlnode_insert_data(group, purple_group_get_name(g), -1);
-
-		buddies = buddies->next;
-	}
-
-	balias = purple_buddy_get_local_buddy_alias(b);
-	xmlnode_set_attrib(item, "jid", who);
-	xmlnode_set_attrib(item, "name", balias ? balias : "");
-	xmlnode_set_attrib(item, "gr:t", "B");
-	xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
-	xmlnode_set_attrib(query, "gr:ext", "2");
-
-	jabber_iq_send(iq);
-
-	/* Synthesize a sign-off */
-	if (jb) {
-		JabberBuddyResource *jbr;
-		GList *l = jb->resources;
-		while (l) {
-			jbr = l->data;
-			if (jbr && jbr->name)
-			{
-				purple_debug_misc("jabber", "Removing resource %s\n", jbr->name);
-				jabber_buddy_remove_resource(jb, jbr->name);
-			}
-			l = l->next;
-		}
-	}
-
-	purple_prpl_got_user_status(account, who, "offline", NULL);
-}
-
-void jabber_google_roster_rem_deny(JabberStream *js, const char *who)
-{
-	GSList *buddies;
-	JabberIq *iq;
-	xmlnode *query;
-	xmlnode *item;
-	xmlnode *group;
-	PurpleBuddy *b;
-	const char *balias;
-
-	buddies = purple_find_buddies(purple_connection_get_account(js->gc), who);
-	if(!buddies)
-		return;
-
-	b = buddies->data;
-
-	iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
-
-	query = xmlnode_get_child(iq->node, "query");
-	item = xmlnode_new_child(query, "item");
-
-	while(buddies) {
-		PurpleGroup *g;
-
-		b = buddies->data;
-		g = purple_buddy_get_group(b);
-
-		group = xmlnode_new_child(item, "group");
-		xmlnode_insert_data(group, purple_group_get_name(g), -1);
-
-		buddies = buddies->next;
-	}
-
-	balias = purple_buddy_get_local_buddy_alias(b);
-	xmlnode_set_attrib(item, "jid", who);
-	xmlnode_set_attrib(item, "name", balias ? balias : "");
-	xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
-	xmlnode_set_attrib(query, "gr:ext", "2");
-
-	jabber_iq_send(iq);
-
-	/* See if he's online */
-	jabber_presence_subscription_set(js, who, "probe");
-}
-
-/* This does two passes on the string. The first pass goes through
- * and determine if all the structured text is properly balanced, and
- * how many instances of each there is. The second pass goes and converts
- * everything to HTML, depending on what's figured out by the first pass.
- * It will short circuit once it knows it has no more replacements to make
- */
-char *jabber_google_format_to_html(const char *text)
-{
-	const char *p;
-
-	/* The start of the screen may be consdiered a space for this purpose */
-	gboolean preceding_space = TRUE;
-
-	gboolean in_bold = FALSE, in_italic = FALSE;
-	gboolean in_tag = FALSE;
-
-	gint bold_count = 0, italic_count = 0;
-
-	GString *str;
-
-	for (p = text; *p != '\0'; p = g_utf8_next_char(p)) {
-		gunichar c = g_utf8_get_char(p);
-		if (c == '*' && !in_tag) {
-			if (in_bold && (g_unichar_isspace(*(p+1)) ||
-					*(p+1) == '\0' ||
-					*(p+1) == '<')) {
-				bold_count++;
-				in_bold = FALSE;
-			} else if (preceding_space && !in_bold && !g_unichar_isspace(*(p+1))) {
-				bold_count++;
-				in_bold = TRUE;
-			}
-			preceding_space = TRUE;
-		} else if (c == '_' && !in_tag) {
-			if (in_italic && (g_unichar_isspace(*(p+1)) ||
-					*(p+1) == '\0' ||
-					*(p+1) == '<')) {
-				italic_count++;
-				in_italic = FALSE;
-			} else if (preceding_space && !in_italic && !g_unichar_isspace(*(p+1))) {
-				italic_count++;
-				in_italic = TRUE;
-			}
-			preceding_space = TRUE;
-		} else if (c == '<' && !in_tag) {
-			in_tag = TRUE;
-		} else if (c == '>' && in_tag) {
-			in_tag = FALSE;
-		} else if (!in_tag) {
-			if (g_unichar_isspace(c))
-				preceding_space = TRUE;
-			else
-				preceding_space = FALSE;
-		}
-	}
-
-	str  = g_string_new(NULL);
-	in_bold = in_italic = in_tag = FALSE;
-	preceding_space = TRUE;
-
-	for (p = text; *p != '\0'; p = g_utf8_next_char(p)) {
-		gunichar c = g_utf8_get_char(p);
-
-		if (bold_count < 2 && italic_count < 2 && !in_bold && !in_italic) {
-			g_string_append(str, p);
-			return g_string_free(str, FALSE);
-		}
-
-
-		if (c == '*' && !in_tag) {
-			if (in_bold &&
-			    (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { /* This is safe in UTF-8 */
-				str = g_string_append(str, "</b>");
-				in_bold = FALSE;
-				bold_count--;
-			} else if (preceding_space && bold_count > 1 && !g_unichar_isspace(*(p+1))) {
-				str = g_string_append(str, "<b>");
-				bold_count--;
-				in_bold = TRUE;
-			} else {
-				str = g_string_append_unichar(str, c);
-			}
-			preceding_space = TRUE;
-		} else if (c == '_' && !in_tag) {
-			if (in_italic &&
-			    (g_unichar_isspace(*(p+1))||*(p+1)=='<')) {
-				str = g_string_append(str, "</i>");
-				italic_count--;
-				in_italic = FALSE;
-			} else if (preceding_space && italic_count > 1 && !g_unichar_isspace(*(p+1))) {
-				str = g_string_append(str, "<i>");
-				italic_count--;
-				in_italic = TRUE;
-			} else {
-				str = g_string_append_unichar(str, c);
-			}
-			preceding_space = TRUE;
-		} else if (c == '<' && !in_tag) {
-			str = g_string_append_unichar(str, c);
-			in_tag = TRUE;
-		} else if (c == '>' && in_tag) {
-			str = g_string_append_unichar(str, c);
-			in_tag = FALSE;
-		} else if (!in_tag) {
-			str = g_string_append_unichar(str, c);
-			if (g_unichar_isspace(c))
-				preceding_space = TRUE;
-			else
-				preceding_space = FALSE;
-		} else {
-			str = g_string_append_unichar(str, c);
-		}
-	}
-	return g_string_free(str, FALSE);
-}
-
-void jabber_google_presence_incoming(JabberStream *js, const char *user, JabberBuddyResource *jbr)
-{
-	if (!js->googletalk)
-		return;
-	if (jbr->status && purple_str_has_prefix(jbr->status, "♫ ")) {
-		purple_prpl_got_user_status(js->gc->account, user, "tune",
-					    PURPLE_TUNE_TITLE, jbr->status + strlen("♫ "), NULL);
-		g_free(jbr->status);
-		jbr->status = NULL;
-	} else {
-		purple_prpl_got_user_status_deactive(js->gc->account, user, "tune");
-	}
-}
-
-char *jabber_google_presence_outgoing(PurpleStatus *tune)
-{
-	const char *attr = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
-	return attr ? g_strdup_printf("♫ %s", attr) : g_strdup("");
-}
-
-static void
-jabber_google_stun_lookup_cb(GSList *hosts, gpointer data,
-	const char *error_message)
-{
-	JabberStream *js = (JabberStream *) data;
-
-	if (error_message) {
-		purple_debug_error("jabber", "Google STUN lookup failed: %s\n",
-			error_message);
-		g_slist_free(hosts);
-		js->stun_query = NULL;
-		return;
-	}
-
-	if (hosts && g_slist_next(hosts)) {
-		struct sockaddr *addr = g_slist_next(hosts)->data;
-		char dst[INET6_ADDRSTRLEN];
-		int port;
-
-		if (addr->sa_family == AF_INET6) {
-			inet_ntop(addr->sa_family, &((struct sockaddr_in6 *) addr)->sin6_addr,
-				dst, sizeof(dst));
-			port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
-		} else {
-			inet_ntop(addr->sa_family, &((struct sockaddr_in *) addr)->sin_addr,
-				dst, sizeof(dst));
-			port = ntohs(((struct sockaddr_in *) addr)->sin_port);
-		}
-
-		if (js->stun_ip)
-			g_free(js->stun_ip);
-		js->stun_ip = g_strdup(dst);
-		js->stun_port = port;
-
-		purple_debug_info("jabber", "set Google STUN IP/port address: "
-		                  "%s:%d\n", dst, port);
-
-		/* unmark ongoing query */
-		js->stun_query = NULL;
-	}
-
-	while (hosts != NULL) {
-		hosts = g_slist_delete_link(hosts, hosts);
-		/* Free the address */
-		g_free(hosts->data);
-		hosts = g_slist_delete_link(hosts, hosts);
-	}
-}
-
-static void
-jabber_google_jingle_info_common(JabberStream *js, const char *from,
-                                 JabberIqType type, xmlnode *query)
-{
-	const xmlnode *stun = xmlnode_get_child(query, "stun");
-	gchar *my_bare_jid;
-
-	/*
-	 * Make sure that random people aren't sending us STUN servers. Per
-	 * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these
-	 * stanzas are stamped from our bare JID.
-	 */
-	if (from) {
-		my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
-		if (!purple_strequal(from, my_bare_jid)) {
-			purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n",
-			                  from);
-			g_free(my_bare_jid);
-			return;
-		}
-
-		g_free(my_bare_jid);
-	}
-
-	if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET)
-		return;
-
-	purple_debug_info("jabber", "got google:jingleinfo\n");
-
-	if (stun) {
-		xmlnode *server = xmlnode_get_child(stun, "server");
-
-		if (server) {
-			const gchar *host = xmlnode_get_attrib(server, "host");
-			const gchar *udp = xmlnode_get_attrib(server, "udp");
-
-			if (host && udp) {
-				int port = atoi(udp);
-				/* if there, would already be an ongoing query,
-				 cancel it */
-				if (js->stun_query)
-					purple_dnsquery_destroy(js->stun_query);
-
-				js->stun_query = purple_dnsquery_a(host, port,
-					jabber_google_stun_lookup_cb, js);
-			}
-		}
-	}
-	/* should perhaps handle relays later on, or maybe wait until
-	 Google supports a common standard... */
-}
-
-static void
-jabber_google_jingle_info_cb(JabberStream *js, const char *from,
-                             JabberIqType type, const char *id,
-                             xmlnode *packet, gpointer data)
-{
-	xmlnode *query = xmlnode_get_child_with_namespace(packet, "query",
-			NS_GOOGLE_JINGLE_INFO);
-
-	if (query)
-		jabber_google_jingle_info_common(js, from, type, query);
-	else
-		purple_debug_warning("jabber", "Got invalid google:jingleinfo\n");
-}
-
-void
-jabber_google_handle_jingle_info(JabberStream *js, const char *from,
-                                 JabberIqType type, const char *id,
-                                 xmlnode *child)
-{
-	jabber_google_jingle_info_common(js, from, type, child);
-}
-
-void
-jabber_google_send_jingle_info(JabberStream *js)
-{
-	JabberIq *jingle_info =
-		jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_JINGLE_INFO);
-
-	jabber_iq_set_callback(jingle_info, jabber_google_jingle_info_cb,
-		NULL);
-	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;
-	gchar *uuid = purple_uuid_random();
-
-	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);
-
-	room = g_strdup_printf("private-chat-%s", uuid);	
-	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, "", purple_buddy_get_name(buddy));
-	}
-
-	g_free(room);
-	g_free(uuid);
-}
--- a/libpurple/protocols/jabber/google.h	Fri Aug 20 08:35:27 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/**
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#ifndef PURPLE_JABBER_GOOGLE_H_
-#define PURPLE_JABBER_GOOGLE_H_
-
-/* This is a place for Google Talk-specific XMPP extensions to live
- * such that they don't intermingle with code for the XMPP RFCs and XEPs :) */
-
-#include "jabber.h"
-
-#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);
-
-void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item);
-
-/* Returns FALSE if this should short-circuit processing of this roster item, or TRUE
- * if this roster item should continue to be processed
- */
-gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item);
-
-void jabber_google_presence_incoming(JabberStream *js, const char *who, JabberBuddyResource *jbr);
-char *jabber_google_presence_outgoing(PurpleStatus *tune);
-
-void jabber_google_roster_add_deny(JabberStream *js, const char *who);
-void jabber_google_roster_rem_deny(JabberStream *js, const char *who);
-
-char *jabber_google_format_to_html(const char *text);
-
-gboolean jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type);
-void jabber_google_session_parse(JabberStream *js, const char *from, JabberIqType type, const char *iq, xmlnode *session);
-
-void jabber_google_handle_jingle_info(JabberStream *js, const char *from,
-                                      JabberIqType type, const char *id,
-                                      xmlnode *child);
-void jabber_google_send_jingle_info(JabberStream *js);
-
-void google_buddy_node_chat(PurpleBlistNode *node, gpointer data);
-
-#endif   /* PURPLE_JABBER_GOOGLE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/gmail.c	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,207 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+#include "jabber.h"
+#include "gmail.h"
+
+static void
+jabber_gmail_parse(JabberStream *js, const char *from,
+                   JabberIqType type, const char *id,
+                   xmlnode *packet, gpointer nul)
+{
+	xmlnode *child;
+	xmlnode *message;
+	const char *to, *url;
+	const char *in_str;
+	char *to_name;
+
+	int i, count = 1, returned_count;
+
+	const char **tos, **froms, **urls;
+	char **subjects;
+
+	if (type == JABBER_IQ_ERROR)
+		return;
+
+	child = xmlnode_get_child(packet, "mailbox");
+	if (!child)
+		return;
+
+	in_str = xmlnode_get_attrib(child, "total-matched");
+	if (in_str && *in_str)
+		count = atoi(in_str);
+
+	/* If Gmail doesn't tell us who the mail is to, let's use our JID */
+	to = xmlnode_get_attrib(packet, "to");
+
+	message = xmlnode_get_child(child, "mail-thread-info");
+
+	if (count == 0 || !message) {
+		if (count > 0) {
+			char *bare_jid = jabber_get_bare_jid(to);
+			const char *default_tos[2] = { bare_jid };
+
+			purple_notify_emails(js->gc, count, FALSE, NULL, NULL, default_tos, NULL, NULL, NULL);
+			g_free(bare_jid);
+		} else {
+			purple_notify_emails(js->gc, count, FALSE, NULL, NULL, NULL, NULL, NULL, NULL);
+		}
+
+		return;
+	}
+
+	/* Loop once to see how many messages were returned so we can allocate arrays
+	 * accordingly */
+	for (returned_count = 0; message; returned_count++, message=xmlnode_get_next_twin(message));
+
+	froms    = g_new0(const char* , returned_count + 1);
+	tos      = g_new0(const char* , returned_count + 1);
+	subjects = g_new0(char* , returned_count + 1);
+	urls     = g_new0(const char* , returned_count + 1);
+
+	to = xmlnode_get_attrib(packet, "to");
+	to_name = jabber_get_bare_jid(to);
+	url = xmlnode_get_attrib(child, "url");
+	if (!url || !*url)
+		url = "http://www.gmail.com";
+
+	message= xmlnode_get_child(child, "mail-thread-info");
+	for (i=0; message; message = xmlnode_get_next_twin(message), i++) {
+		xmlnode *sender_node, *subject_node;
+		const char *from, *tid;
+		char *subject;
+
+		subject_node = xmlnode_get_child(message, "subject");
+		sender_node  = xmlnode_get_child(message, "senders");
+		sender_node  = xmlnode_get_child(sender_node, "sender");
+
+		while (sender_node && (!xmlnode_get_attrib(sender_node, "unread") ||
+		       !strcmp(xmlnode_get_attrib(sender_node, "unread"),"0")))
+			sender_node = xmlnode_get_next_twin(sender_node);
+
+		if (!sender_node) {
+			i--;
+			continue;
+		}
+
+		from = xmlnode_get_attrib(sender_node, "name");
+		if (!from || !*from)
+			from = xmlnode_get_attrib(sender_node, "address");
+		subject = xmlnode_get_data(subject_node);
+		/*
+		 * url = xmlnode_get_attrib(message, "url");
+		 */
+		tos[i] = (to_name != NULL ?  to_name : "");
+		froms[i] = (from != NULL ?  from : "");
+		subjects[i] = (subject != NULL ? subject : g_strdup(""));
+		urls[i] = url;
+
+		tid = xmlnode_get_attrib(message, "tid");
+		if (tid &&
+		    (js->gmail_last_tid == NULL || strcmp(tid, js->gmail_last_tid) > 0)) {
+			g_free(js->gmail_last_tid);
+			js->gmail_last_tid = g_strdup(tid);
+		}
+	}
+
+	if (i>0)
+		purple_notify_emails(js->gc, count, count == i, (const char**) subjects, froms, tos,
+				urls, NULL, NULL);
+
+	g_free(to_name);
+	g_free(tos);
+	g_free(froms);
+	for (i = 0; i < returned_count; i++)
+		g_free(subjects[i]);
+	g_free(subjects);
+	g_free(urls);
+
+	in_str = xmlnode_get_attrib(child, "result-time");
+	if (in_str && *in_str) {
+		g_free(js->gmail_last_time);
+		js->gmail_last_time = g_strdup(in_str);
+	}
+}
+
+void
+jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
+                  const char *id, xmlnode *new_mail)
+{
+	xmlnode *query;
+	JabberIq *iq;
+
+	/* bail if the user isn't interested */
+	if (!purple_account_get_check_mail(js->gc->account))
+		return;
+
+	/* Is this an initial incoming mail notification? If so, send a request for more info */
+	if (type != JABBER_IQ_SET)
+		return;
+
+	/* Acknowledge the notification */
+	iq = jabber_iq_new(js, JABBER_IQ_RESULT);
+	if (from)
+		xmlnode_set_attrib(iq->node, "to", from);
+	xmlnode_set_attrib(iq->node, "id", id);
+	jabber_iq_send(iq);
+
+	purple_debug_misc("jabber",
+		   "Got new mail notification. Sending request for more info\n");
+
+	iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
+	jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
+	query = xmlnode_get_child(iq->node, "query");
+
+	if (js->gmail_last_time)
+		xmlnode_set_attrib(query, "newer-than-time", js->gmail_last_time);
+	if (js->gmail_last_tid)
+		xmlnode_set_attrib(query, "newer-than-tid", js->gmail_last_tid);
+
+	jabber_iq_send(iq);
+	return;
+}
+
+void jabber_gmail_init(JabberStream *js) {
+	JabberIq *iq;
+	xmlnode *usersetting, *mailnotifications;
+
+	if (!purple_account_get_check_mail(purple_connection_get_account(js->gc)))
+		return;
+
+	/*
+	 * Quoting http://code.google.com/apis/talk/jep_extensions/usersettings.html:
+	 * To ensure better compatibility with other clients, rather than
+	 * setting this value to "false" to turn off notifications, it is
+	 * recommended that a client set this to "true" and filter incoming
+	 * email notifications itself.
+	 */
+	iq = jabber_iq_new(js, JABBER_IQ_SET);
+	usersetting = xmlnode_new_child(iq->node, "usersetting");
+	xmlnode_set_namespace(usersetting, "google:setting");
+	mailnotifications = xmlnode_new_child(usersetting, "mailnotifications");
+	xmlnode_set_attrib(mailnotifications, "value", "true");
+	jabber_iq_send(iq);
+
+	iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
+	jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
+	jabber_iq_send(iq);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/gmail.h	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,30 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_GMAIL_H_
+#define PURPLE_JABBER_GOOGLE_GMAIL_H_
+
+#include "jabber.h"
+
+void jabber_gmail_init(JabberStream *js);
+void jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
+                       const char *id, xmlnode *new_mail);
+
+#endif /* PURPLE_JABBER_GOOGLE_GMAIL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google.c	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,172 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+
+#include "google.h"
+#include "jabber.h"
+#include "chat.h"
+
+/* This does two passes on the string. The first pass goes through
+ * and determine if all the structured text is properly balanced, and
+ * how many instances of each there is. The second pass goes and converts
+ * everything to HTML, depending on what's figured out by the first pass.
+ * It will short circuit once it knows it has no more replacements to make
+ */
+char *jabber_google_format_to_html(const char *text)
+{
+	const char *p;
+
+	/* The start of the screen may be consdiered a space for this purpose */
+	gboolean preceding_space = TRUE;
+
+	gboolean in_bold = FALSE, in_italic = FALSE;
+	gboolean in_tag = FALSE;
+
+	gint bold_count = 0, italic_count = 0;
+
+	GString *str;
+
+	for (p = text; *p != '\0'; p = g_utf8_next_char(p)) {
+		gunichar c = g_utf8_get_char(p);
+		if (c == '*' && !in_tag) {
+			if (in_bold && (g_unichar_isspace(*(p+1)) ||
+					*(p+1) == '\0' ||
+					*(p+1) == '<')) {
+				bold_count++;
+				in_bold = FALSE;
+			} else if (preceding_space && !in_bold && !g_unichar_isspace(*(p+1))) {
+				bold_count++;
+				in_bold = TRUE;
+			}
+			preceding_space = TRUE;
+		} else if (c == '_' && !in_tag) {
+			if (in_italic && (g_unichar_isspace(*(p+1)) ||
+					*(p+1) == '\0' ||
+					*(p+1) == '<')) {
+				italic_count++;
+				in_italic = FALSE;
+			} else if (preceding_space && !in_italic && !g_unichar_isspace(*(p+1))) {
+				italic_count++;
+				in_italic = TRUE;
+			}
+			preceding_space = TRUE;
+		} else if (c == '<' && !in_tag) {
+			in_tag = TRUE;
+		} else if (c == '>' && in_tag) {
+			in_tag = FALSE;
+		} else if (!in_tag) {
+			if (g_unichar_isspace(c))
+				preceding_space = TRUE;
+			else
+				preceding_space = FALSE;
+		}
+	}
+
+	str  = g_string_new(NULL);
+	in_bold = in_italic = in_tag = FALSE;
+	preceding_space = TRUE;
+
+	for (p = text; *p != '\0'; p = g_utf8_next_char(p)) {
+		gunichar c = g_utf8_get_char(p);
+
+		if (bold_count < 2 && italic_count < 2 && !in_bold && !in_italic) {
+			g_string_append(str, p);
+			return g_string_free(str, FALSE);
+		}
+
+
+		if (c == '*' && !in_tag) {
+			if (in_bold &&
+			    (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { /* This is safe in UTF-8 */
+				str = g_string_append(str, "</b>");
+				in_bold = FALSE;
+				bold_count--;
+			} else if (preceding_space && bold_count > 1 && !g_unichar_isspace(*(p+1))) {
+				str = g_string_append(str, "<b>");
+				bold_count--;
+				in_bold = TRUE;
+			} else {
+				str = g_string_append_unichar(str, c);
+			}
+			preceding_space = TRUE;
+		} else if (c == '_' && !in_tag) {
+			if (in_italic &&
+			    (g_unichar_isspace(*(p+1))||*(p+1)=='<')) {
+				str = g_string_append(str, "</i>");
+				italic_count--;
+				in_italic = FALSE;
+			} else if (preceding_space && italic_count > 1 && !g_unichar_isspace(*(p+1))) {
+				str = g_string_append(str, "<i>");
+				italic_count--;
+				in_italic = TRUE;
+			} else {
+				str = g_string_append_unichar(str, c);
+			}
+			preceding_space = TRUE;
+		} else if (c == '<' && !in_tag) {
+			str = g_string_append_unichar(str, c);
+			in_tag = TRUE;
+		} else if (c == '>' && in_tag) {
+			str = g_string_append_unichar(str, c);
+			in_tag = FALSE;
+		} else if (!in_tag) {
+			str = g_string_append_unichar(str, c);
+			if (g_unichar_isspace(c))
+				preceding_space = TRUE;
+			else
+				preceding_space = FALSE;
+		} else {
+			str = g_string_append_unichar(str, c);
+		}
+	}
+	return g_string_free(str, FALSE);
+}
+
+
+
+void google_buddy_node_chat(PurpleBlistNode *node, gpointer data)
+{
+	PurpleBuddy *buddy;
+	PurpleConnection *gc;
+	JabberStream *js;
+	JabberChat *chat;
+	gchar *room;
+	gchar *uuid = purple_uuid_random();
+
+	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);
+
+	room = g_strdup_printf("private-chat-%s", uuid);	
+	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, "", purple_buddy_get_name(buddy));
+	}
+
+	g_free(room);
+	g_free(uuid);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google.h	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,35 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_H_
+#define PURPLE_JABBER_GOOGLE_H_
+
+/* This is a place for Google Talk-specific XMPP extensions to live
+ * such that they don't intermingle with code for the XMPP RFCs and XEPs :) */
+
+#include "jabber.h"
+
+#define GOOGLE_GROUPCHAT_SERVER "groupchat.google.com"
+
+char *jabber_google_format_to_html(const char *text);
+
+void google_buddy_node_chat(PurpleBlistNode *node, gpointer data);
+
+#endif   /* PURPLE_JABBER_GOOGLE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_presence.c	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,43 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+#include "google_presence.h"
+
+void jabber_google_presence_incoming(JabberStream *js, const char *user, JabberBuddyResource *jbr)
+{
+	if (!js->googletalk)
+		return;
+	if (jbr->status && purple_str_has_prefix(jbr->status, "♫ ")) {
+		purple_prpl_got_user_status(js->gc->account, user, "tune",
+					    PURPLE_TUNE_TITLE, jbr->status + strlen("♫ "), NULL);
+		g_free(jbr->status);
+		jbr->status = NULL;
+	} else {
+		purple_prpl_got_user_status_deactive(js->gc->account, user, "tune");
+	}
+}
+
+char *jabber_google_presence_outgoing(PurpleStatus *tune)
+{
+	const char *attr = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
+	return attr ? g_strdup_printf("♫ %s", attr) : g_strdup("");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_presence.h	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,32 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_PRESENCE_H_
+#define PURPLE_JABBER_GOOGLE_PRESENCE_H_
+
+#include "jabber.h"
+#include "buddy.h"
+#include "status.h"
+
+void jabber_google_presence_incoming(JabberStream *js, const char *who, JabberBuddyResource *jbr);
+char *jabber_google_presence_outgoing(PurpleStatus *tune);
+
+
+#endif /* PURPLE_JABBER_GOOGLE_PRESENCE_H_ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_roster.c	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,206 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+#include "google_roster.h"
+#include "jabber.h"
+#include "presence.h"
+#include "debug.h"
+#include "xmlnode.h"
+
+void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item)
+{
+	PurpleAccount *account = purple_connection_get_account(js->gc);
+	GSList *list = account->deny;
+	const char *jid = xmlnode_get_attrib(item, "jid");
+	char *jid_norm = (char *)jabber_normalize(account, jid);
+
+	while (list) {
+		if (!strcmp(jid_norm, (char*)list->data)) {
+			xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
+			xmlnode_set_attrib(query, "gr:ext", "2");
+			xmlnode_set_attrib(item, "gr:t", "B");
+			return;
+		}
+		list = list->next;
+	}
+}
+
+gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item)
+{
+	PurpleAccount *account = purple_connection_get_account(js->gc);
+	const char *jid = xmlnode_get_attrib(item, "jid");
+	gboolean on_block_list = FALSE;
+
+	char *jid_norm;
+
+	const char *grt = xmlnode_get_attrib_with_namespace(item, "t", NS_GOOGLE_ROSTER);
+	const char *subscription = xmlnode_get_attrib(item, "subscription");
+	const char *ask = xmlnode_get_attrib(item, "ask");
+
+	if ((!subscription || !strcmp(subscription, "none")) && !ask) {
+		/* The Google Talk servers will automatically add people from your Gmail address book
+		 * with subscription=none. If we see someone with subscription=none, ignore them.
+		 */
+		return FALSE;
+	}
+
+ 	jid_norm = g_strdup(jabber_normalize(account, jid));
+
+	on_block_list = NULL != g_slist_find_custom(account->deny, jid_norm,
+	                                            (GCompareFunc)strcmp);
+
+	if (grt && (*grt == 'H' || *grt == 'h')) {
+		/* Hidden; don't show this buddy. */
+		GSList *buddies = purple_find_buddies(account, jid_norm);
+		if (buddies)
+			purple_debug_info("jabber", "Removing %s from local buddy list\n",
+			                  jid_norm);
+
+		for ( ; buddies; buddies = g_slist_delete_link(buddies, buddies)) {
+			purple_blist_remove_buddy(buddies->data);
+		}
+
+		g_free(jid_norm);
+		return FALSE;
+	}
+
+	if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) {
+		purple_debug_info("jabber", "Blocking %s\n", jid_norm);
+		purple_privacy_deny_add(account, jid_norm, TRUE);
+	} else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){
+		purple_debug_info("jabber", "Unblocking %s\n", jid_norm);
+		purple_privacy_deny_remove(account, jid_norm, TRUE);
+	}
+
+	g_free(jid_norm);
+	return TRUE;
+}
+
+void jabber_google_roster_add_deny(JabberStream *js, const char *who)
+{
+	PurpleAccount *account;
+	GSList *buddies;
+	JabberIq *iq;
+	xmlnode *query;
+	xmlnode *item;
+	xmlnode *group;
+	PurpleBuddy *b;
+	JabberBuddy *jb;
+	const char *balias;
+
+	jb = jabber_buddy_find(js, who, TRUE);
+
+	account = purple_connection_get_account(js->gc);
+	buddies = purple_find_buddies(account, who);
+	if(!buddies)
+		return;
+
+	b = buddies->data;
+
+	iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
+
+	query = xmlnode_get_child(iq->node, "query");
+	item = xmlnode_new_child(query, "item");
+
+	while(buddies) {
+		PurpleGroup *g;
+
+		b = buddies->data;
+		g = purple_buddy_get_group(b);
+
+		group = xmlnode_new_child(item, "group");
+		xmlnode_insert_data(group, purple_group_get_name(g), -1);
+
+		buddies = buddies->next;
+	}
+
+	balias = purple_buddy_get_local_buddy_alias(b);
+	xmlnode_set_attrib(item, "jid", who);
+	xmlnode_set_attrib(item, "name", balias ? balias : "");
+	xmlnode_set_attrib(item, "gr:t", "B");
+	xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
+	xmlnode_set_attrib(query, "gr:ext", "2");
+
+	jabber_iq_send(iq);
+
+	/* Synthesize a sign-off */
+	if (jb) {
+		JabberBuddyResource *jbr;
+		GList *l = jb->resources;
+		while (l) {
+			jbr = l->data;
+			if (jbr && jbr->name)
+			{
+				purple_debug_misc("jabber", "Removing resource %s\n", jbr->name);
+				jabber_buddy_remove_resource(jb, jbr->name);
+			}
+			l = l->next;
+		}
+	}
+
+	purple_prpl_got_user_status(account, who, "offline", NULL);
+}
+
+void jabber_google_roster_rem_deny(JabberStream *js, const char *who)
+{
+	GSList *buddies;
+	JabberIq *iq;
+	xmlnode *query;
+	xmlnode *item;
+	xmlnode *group;
+	PurpleBuddy *b;
+	const char *balias;
+
+	buddies = purple_find_buddies(purple_connection_get_account(js->gc), who);
+	if(!buddies)
+		return;
+
+	b = buddies->data;
+
+	iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
+
+	query = xmlnode_get_child(iq->node, "query");
+	item = xmlnode_new_child(query, "item");
+
+	while(buddies) {
+		PurpleGroup *g;
+
+		b = buddies->data;
+		g = purple_buddy_get_group(b);
+
+		group = xmlnode_new_child(item, "group");
+		xmlnode_insert_data(group, purple_group_get_name(g), -1);
+
+		buddies = buddies->next;
+	}
+
+	balias = purple_buddy_get_local_buddy_alias(b);
+	xmlnode_set_attrib(item, "jid", who);
+	xmlnode_set_attrib(item, "name", balias ? balias : "");
+	xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
+	xmlnode_set_attrib(query, "gr:ext", "2");
+
+	jabber_iq_send(iq);
+
+	/* See if he's online */
+	jabber_presence_subscription_set(js, who, "probe");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_roster.h	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,37 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_ROSTER_H_
+#define PURPLE_JABBER_GOOGLE_ROSTER_H_
+
+#include "jabber.h"
+
+void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item);
+
+/* Returns FALSE if this should short-circuit processing of this roster item, or TRUE
+ * if this roster item should continue to be processed
+ */
+gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item);
+
+void jabber_google_roster_add_deny(JabberStream *js, const char *who);
+void jabber_google_roster_rem_deny(JabberStream *js, const char *who);
+
+
+#endif /* PURPLE_JABBER_GOOGLE_ROSTER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_session.c	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,866 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+#include "google_session.h"
+#include "relay.h"
+
+#include "jingle/jingle.h"
+
+#ifdef USE_VV
+
+typedef struct {
+	PurpleMedia *media;
+	gboolean video;
+	GList *remote_audio_candidates; /* list of PurpleMediaCandidate */
+	GList *remote_video_candidates; /* list of PurpleMediaCandidate */
+	gboolean added_streams;		/* this indicates if the streams have been
+	 							   to media (ie. after getting relay credentials */
+} GoogleAVSessionData;
+
+static gboolean
+google_session_id_equal(gconstpointer a, gconstpointer b)
+{
+	GoogleSessionId *c = (GoogleSessionId*)a;
+	GoogleSessionId *d = (GoogleSessionId*)b;
+
+	return !strcmp(c->id, d->id) && !strcmp(c->initiator, d->initiator);
+}
+
+static void
+google_session_destroy(GoogleSession *session)
+{
+	GoogleAVSessionData *session_data =
+		(GoogleAVSessionData *) session->session_data;
+	g_free(session->id.id);
+	g_free(session->id.initiator);
+	g_free(session->remote_jid);
+
+	if (session_data->remote_audio_candidates)
+		purple_media_candidate_list_free(session_data->remote_audio_candidates);
+
+	if (session_data->remote_video_candidates)
+		purple_media_candidate_list_free(session_data->remote_video_candidates);
+
+	g_free(session->session_data);
+	g_free(session);
+}
+
+static xmlnode *
+google_session_create_xmlnode(GoogleSession *session, const char *type)
+{
+	xmlnode *node = xmlnode_new("session");
+	xmlnode_set_namespace(node, NS_GOOGLE_SESSION);
+	xmlnode_set_attrib(node, "id", session->id.id);
+	xmlnode_set_attrib(node, "initiator", session->id.initiator);
+	xmlnode_set_attrib(node, "type", type);
+	return node;
+}
+
+static void
+google_session_send_candidates(PurpleMedia *media, gchar *session_id,
+		gchar *participant, GoogleSession *session)
+{
+	PurpleMedia *session_media =
+		((GoogleAVSessionData *) session->session_data)->media;
+	GList *candidates =
+		purple_media_get_local_candidates(session_media, session_id,
+		    session->remote_jid);
+	GList *iter;
+	PurpleMediaCandidate *transport;
+	gboolean video = FALSE;
+
+	if (!strcmp(session_id, "google-video"))
+		video = TRUE;
+
+	for (iter = candidates; iter; iter = iter->next) {
+		JabberIq *iq;
+		gchar *ip, *port, *username, *password;
+		gchar pref[16];
+		PurpleMediaCandidateType type;
+		xmlnode *sess;
+		xmlnode *candidate;
+		guint component_id;
+		transport = PURPLE_MEDIA_CANDIDATE(iter->data);
+		component_id = purple_media_candidate_get_component_id(
+				transport);
+
+		iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+		sess = google_session_create_xmlnode(session, "candidates");
+		xmlnode_insert_child(iq->node, sess);
+		xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+
+		candidate = xmlnode_new("candidate");
+
+		ip = purple_media_candidate_get_ip(transport);
+		port = g_strdup_printf("%d",
+				purple_media_candidate_get_port(transport));
+		g_ascii_dtostr(pref, 16,
+			purple_media_candidate_get_priority(transport) / 1000.0);
+		username = purple_media_candidate_get_username(transport);
+		password = purple_media_candidate_get_password(transport);
+		type = purple_media_candidate_get_candidate_type(transport);
+
+		xmlnode_set_attrib(candidate, "address", ip);
+		xmlnode_set_attrib(candidate, "port", port);
+		xmlnode_set_attrib(candidate, "name",
+				component_id == PURPLE_MEDIA_COMPONENT_RTP ?
+				video ? "video_rtp" : "rtp" :
+				component_id == PURPLE_MEDIA_COMPONENT_RTCP ?
+				video ? "video_rtcp" : "rtcp" : "none");
+		xmlnode_set_attrib(candidate, "username", username);
+		/*
+		 * As of this writing, Farsight 2 in Google compatibility
+		 * mode doesn't provide a password. The Gmail client
+		 * requires this to be set.
+		 */
+		xmlnode_set_attrib(candidate, "password",
+				password != NULL ? password : "");
+		xmlnode_set_attrib(candidate, "preference", pref);
+		xmlnode_set_attrib(candidate, "protocol",
+				purple_media_candidate_get_protocol(transport)
+				== PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ?
+				"udp" : "tcp");
+		xmlnode_set_attrib(candidate, "type", type ==
+				PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "local" :
+						      type ==
+				PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "stun" :
+					       	      type ==
+				PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" :
+				NULL);
+		xmlnode_set_attrib(candidate, "generation", "0");
+		xmlnode_set_attrib(candidate, "network", "0");
+		xmlnode_insert_child(sess, candidate);
+
+		g_free(ip);
+		g_free(port);
+		g_free(username);
+		g_free(password);
+
+		jabber_iq_send(iq);
+	}
+	purple_media_candidate_list_free(candidates);
+}
+
+static void
+google_session_ready(GoogleSession *session)
+{
+	PurpleMedia *media =
+		((GoogleAVSessionData *)session->session_data)->media;
+	gboolean video =
+		((GoogleAVSessionData *)session->session_data)->video;
+	if (purple_media_codecs_ready(media, NULL) &&
+			purple_media_candidates_prepared(media, NULL, NULL)) {
+		gchar *me = g_strdup_printf("%s@%s/%s",
+				session->js->user->node,
+				session->js->user->domain,
+				session->js->user->resource);
+		JabberIq *iq;
+		xmlnode *sess, *desc, *payload;
+		GList *codecs, *iter;
+		gboolean is_initiator = !strcmp(session->id.initiator, me);
+
+		if (!is_initiator &&
+				!purple_media_accepted(media, NULL, NULL)) {
+			g_free(me);
+			return;
+		}
+
+		iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+		if (is_initiator) {
+			xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+			xmlnode_set_attrib(iq->node, "from", session->id.initiator);
+			sess = google_session_create_xmlnode(session, "initiate");
+		} else {
+			google_session_send_candidates(media,
+					"google-voice", session->remote_jid,
+					session);
+			google_session_send_candidates(media,
+					"google-video", session->remote_jid,
+					session);
+			xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+			xmlnode_set_attrib(iq->node, "from", me);
+			sess = google_session_create_xmlnode(session, "accept");
+		}
+		xmlnode_insert_child(iq->node, sess);
+		desc = xmlnode_new_child(sess, "description");
+		if (video)
+			xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_VIDEO);
+		else
+			xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_PHONE);
+
+		codecs = purple_media_get_codecs(media, "google-video");
+
+		for (iter = codecs; iter; iter = g_list_next(iter)) {
+			PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
+			gchar *id = g_strdup_printf("%d",
+					purple_media_codec_get_id(codec));
+			gchar *encoding_name =
+					purple_media_codec_get_encoding_name(codec);
+			payload = xmlnode_new_child(desc, "payload-type");
+			xmlnode_set_attrib(payload, "id", id);
+			xmlnode_set_attrib(payload, "name", encoding_name);
+			xmlnode_set_attrib(payload, "width", "320");
+			xmlnode_set_attrib(payload, "height", "200");
+			xmlnode_set_attrib(payload, "framerate", "30");
+			g_free(encoding_name);
+			g_free(id);
+		}
+		purple_media_codec_list_free(codecs);
+
+		codecs = purple_media_get_codecs(media, "google-voice");
+
+		for (iter = codecs; iter; iter = g_list_next(iter)) {
+			PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
+			gchar *id = g_strdup_printf("%d",
+					purple_media_codec_get_id(codec));
+			gchar *encoding_name =
+					purple_media_codec_get_encoding_name(codec);
+			gchar *clock_rate = g_strdup_printf("%d",
+					purple_media_codec_get_clock_rate(codec));
+			payload = xmlnode_new_child(desc, "payload-type");
+			if (video)
+				xmlnode_set_namespace(payload, NS_GOOGLE_SESSION_PHONE);
+			xmlnode_set_attrib(payload, "id", id);
+			/*
+			 * Hack to make Gmail accept speex as the codec.
+			 * It shouldn't have to be case sensitive.
+			 */
+			if (purple_strequal(encoding_name, "SPEEX"))
+				xmlnode_set_attrib(payload, "name", "speex");
+			else
+				xmlnode_set_attrib(payload, "name", encoding_name);
+			xmlnode_set_attrib(payload, "clockrate", clock_rate);
+			g_free(clock_rate);
+			g_free(encoding_name);
+			g_free(id);
+		}
+		purple_media_codec_list_free(codecs);
+
+		jabber_iq_send(iq);
+
+		if (is_initiator) {
+			google_session_send_candidates(media,
+					"google-voice", session->remote_jid,
+					session);
+			google_session_send_candidates(media,
+					"google-video", session->remote_jid,
+					session);
+		}
+
+		g_signal_handlers_disconnect_by_func(G_OBJECT(media),
+				G_CALLBACK(google_session_ready), session);
+	}
+}
+
+static void
+google_session_state_changed_cb(PurpleMedia *media, PurpleMediaState state,
+		gchar *sid, gchar *name, GoogleSession *session)
+{
+	if (sid == NULL && name == NULL) {
+		if (state == PURPLE_MEDIA_STATE_END) {
+			google_session_destroy(session);
+		}
+	}
+}
+
+static void
+google_session_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
+		gchar *sid, gchar *name, gboolean local,
+		GoogleSession *session)
+{
+	if (sid != NULL || name != NULL)
+		return;
+
+	if (type == PURPLE_MEDIA_INFO_HANGUP) {
+		xmlnode *sess;
+		JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+		xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+		sess = google_session_create_xmlnode(session, "terminate");
+		xmlnode_insert_child(iq->node, sess);
+
+		jabber_iq_send(iq);
+	} else if (type == PURPLE_MEDIA_INFO_REJECT) {
+		xmlnode *sess;
+		JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+		xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+		sess = google_session_create_xmlnode(session, "reject");
+		xmlnode_insert_child(iq->node, sess);
+
+		jabber_iq_send(iq);
+	} else if (type == PURPLE_MEDIA_INFO_ACCEPT && local == TRUE) {
+		google_session_ready(session);
+	}
+}
+
+static GParameter *
+jabber_google_session_get_params(JabberStream *js, const gchar *relay_ip,
+	guint16 relay_udp, guint16 relay_tcp, guint16 relay_ssltcp,
+    const gchar *relay_username, const gchar *relay_password, guint *num)
+{
+	guint num_params;
+	GParameter *params =
+		jingle_get_params(js, relay_ip, relay_udp, relay_tcp, relay_ssltcp,
+	    	relay_username, relay_password, &num_params);
+	GParameter *new_params = g_new0(GParameter, num_params + 1);
+
+	memcpy(new_params, params, sizeof(GParameter) * num_params);
+
+	purple_debug_info("jabber", "setting Google jingle compatibility param\n");
+	new_params[num_params].name = "compatibility-mode";
+	g_value_init(&new_params[num_params].value, G_TYPE_UINT);
+	g_value_set_uint(&new_params[num_params].value, 1); /* NICE_COMPATIBILITY_GOOGLE */
+
+	g_free(params);
+	*num = num_params + 1;
+	return new_params;
+}
+
+
+static void
+jabber_google_relay_response_session_initiate_cb(GoogleSession *session,
+    const gchar *relay_ip, guint relay_udp, guint relay_tcp, guint relay_ssltcp,
+    const gchar *relay_username, const gchar *relay_password)
+{
+	GParameter *params;
+	guint num_params;
+	JabberStream *js = session->js;
+	GoogleAVSessionData *session_data =
+		(GoogleAVSessionData *) session->session_data;
+
+	session_data->media = purple_media_manager_create_media(
+			purple_media_manager_get(),
+			purple_connection_get_account(js->gc),
+			"fsrtpconference", session->remote_jid, TRUE);
+
+	purple_media_set_prpl_data(session_data->media, session);
+
+	g_signal_connect_swapped(G_OBJECT(session_data->media),
+			"candidates-prepared",
+			G_CALLBACK(google_session_ready), session);
+	g_signal_connect_swapped(G_OBJECT(session_data->media), "codecs-changed",
+			G_CALLBACK(google_session_ready), session);
+	g_signal_connect(G_OBJECT(session_data->media), "state-changed",
+			G_CALLBACK(google_session_state_changed_cb), session);
+	g_signal_connect(G_OBJECT(session_data->media), "stream-info",
+			G_CALLBACK(google_session_stream_info_cb), session);
+
+	params =
+		jabber_google_session_get_params(js, relay_ip, relay_udp, relay_tcp,
+			relay_ssltcp, relay_username, relay_password, &num_params);
+	
+	if (purple_media_add_stream(session_data->media, "google-voice",
+			session->remote_jid, PURPLE_MEDIA_AUDIO,
+			TRUE, "nice", num_params, params) == FALSE ||
+			(session_data->video && purple_media_add_stream(
+			session_data->media, "google-video",
+			session->remote_jid, PURPLE_MEDIA_VIDEO,
+			TRUE, "nice", num_params, params) == FALSE)) {
+		purple_media_error(session_data->media, "Error adding stream.");
+		purple_media_end(session_data->media, NULL, NULL);
+		g_free(params);
+	} else {
+		session_data->added_streams = TRUE;
+	}
+
+	g_free(params);	
+}
+
+
+gboolean
+jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type)
+{
+	GoogleSession *session;
+	JabberBuddy *jb;
+	JabberBuddyResource *jbr;
+	gchar *jid;
+	GoogleAVSessionData *session_data = NULL;
+
+	/* construct JID to send to */
+	jb = jabber_buddy_find(js, who, FALSE);
+	if (!jb) {
+		purple_debug_error("jingle-rtp",
+				"Could not find Jabber buddy\n");
+		return FALSE;
+	}
+	jbr = jabber_buddy_find_resource(jb, NULL);
+	if (!jbr) {
+		purple_debug_error("jingle-rtp",
+				"Could not find buddy's resource\n");
+	}
+
+	if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) {
+		jid = g_strdup_printf("%s/%s", who, jbr->name);
+	} else {
+		jid = g_strdup(who);
+	}
+
+	session = g_new0(GoogleSession, 1);
+	session->id.id = jabber_get_next_id(js);
+	session->id.initiator = g_strdup_printf("%s@%s/%s", js->user->node,
+			js->user->domain, js->user->resource);
+	session->state = SENT_INITIATE;
+	session->js = js;
+	session->remote_jid = jid;
+	session_data = g_new0(GoogleAVSessionData, 1);
+	session->session_data = session_data;
+	
+	if (type & PURPLE_MEDIA_VIDEO)
+		session_data->video = TRUE;
+
+	/* if we got a relay token and relay host in google:jingleinfo, issue an
+	 HTTP request to get that data */
+	if (js->google_relay_host && js->google_relay_token) {
+		jabber_google_do_relay_request(js, session,
+			jabber_google_relay_response_session_initiate_cb);
+	} else {
+		jabber_google_relay_response_session_initiate_cb(session, NULL, 0, 0, 0,
+			NULL, NULL);
+	}
+	
+	/* we don't actually know yet wether it succeeded... maybe this is very
+	 wrong... */
+	return TRUE;
+}
+
+static void
+jabber_google_relay_response_session_handle_initiate_cb(GoogleSession *session,
+    const gchar *relay_ip, guint relay_udp, guint relay_tcp, guint relay_ssltcp,
+    const gchar *relay_username, const gchar *relay_password)
+{
+	GParameter *params;
+	guint num_params;
+	JabberStream *js = session->js;
+	xmlnode *codec_element;
+	xmlnode *desc_element;
+	const gchar *xmlns;
+	PurpleMediaCodec *codec;
+	GList *video_codecs = NULL;
+	GList *codecs = NULL;
+	JabberIq *result;
+	GoogleAVSessionData *session_data =
+		(GoogleAVSessionData *) session->session_data;
+
+	params =
+		jabber_google_session_get_params(js, relay_ip, relay_udp, relay_tcp, 
+	    	relay_ssltcp, relay_username, relay_password, &num_params);
+
+	if (purple_media_add_stream(session_data->media, "google-voice",
+			session->remote_jid, PURPLE_MEDIA_AUDIO, FALSE,
+			"nice", num_params, params) == FALSE ||
+			(session_data->video && purple_media_add_stream(
+			session_data->media, "google-video",
+			session->remote_jid, PURPLE_MEDIA_VIDEO,
+			FALSE, "nice", num_params, params) == FALSE)) {
+		purple_media_error(session_data->media, "Error adding stream.");
+		purple_media_stream_info(session_data->media,
+				PURPLE_MEDIA_INFO_REJECT, NULL, NULL, TRUE);
+	} else {
+		/* successfully added stream(s) */
+		session_data->added_streams = TRUE;
+
+		if (session_data->remote_audio_candidates) {
+			purple_media_add_remote_candidates(session_data->media,
+				"google-voice", session->remote_jid, 
+			    session_data->remote_audio_candidates);
+			purple_media_candidate_list_free(session_data->remote_audio_candidates);
+			session_data->remote_audio_candidates = NULL;
+		}
+		if (session_data->remote_video_candidates) {
+			purple_media_add_remote_candidates(session_data->media,
+				"google-video", session->remote_jid, 
+			    session_data->remote_video_candidates);
+			purple_media_candidate_list_free(session_data->remote_video_candidates);
+			session_data->remote_video_candidates = NULL;
+		}
+	}
+		
+	g_free(params);
+
+	for (codec_element = xmlnode_get_child(desc_element, "payload-type");
+	     codec_element; codec_element = codec_element->next) {
+		const char *id, *encoding_name,  *clock_rate,
+				*width, *height, *framerate;
+		gboolean video;
+		if (codec_element->name &&
+				strcmp(codec_element->name, "payload-type"))
+			continue;
+
+		xmlns = xmlnode_get_namespace(codec_element);
+		encoding_name = xmlnode_get_attrib(codec_element, "name");
+		id = xmlnode_get_attrib(codec_element, "id");
+
+		if (!session_data->video ||
+				(xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_PHONE))) {
+			clock_rate = xmlnode_get_attrib(
+					codec_element, "clockrate");
+			video = FALSE;
+		} else {
+			width = xmlnode_get_attrib(codec_element, "width");
+			height = xmlnode_get_attrib(codec_element, "height");
+			framerate = xmlnode_get_attrib(
+					codec_element, "framerate");
+			clock_rate = "90000";
+			video = TRUE;
+		}
+
+		if (id) {
+			codec = purple_media_codec_new(atoi(id), encoding_name,
+					video ?	PURPLE_MEDIA_VIDEO :
+					PURPLE_MEDIA_AUDIO,
+					clock_rate ? atoi(clock_rate) : 0);
+			if (video)
+				video_codecs = g_list_append(
+						video_codecs, codec);
+			else
+				codecs = g_list_append(codecs, codec);
+		}
+	}
+
+	if (codecs)
+		purple_media_set_remote_codecs(session_data->media, "google-voice",
+				session->remote_jid, codecs);
+	if (video_codecs)
+		purple_media_set_remote_codecs(session_data->media, "google-video",
+				session->remote_jid, video_codecs);
+
+	purple_media_codec_list_free(codecs);
+	purple_media_codec_list_free(video_codecs);
+
+	result = jabber_iq_new(js, JABBER_IQ_RESULT);
+	jabber_iq_set_id(result, session->iq_id);
+	xmlnode_set_attrib(result->node, "to", session->remote_jid);
+	jabber_iq_send(result);
+}
+
+static gboolean
+google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
+{
+	xmlnode *desc_element;
+	const gchar *xmlns;
+	GoogleAVSessionData *session_data =
+		(GoogleAVSessionData *) session->session_data;
+	
+	if (session->state != UNINIT) {
+		purple_debug_error("jabber", "Received initiate for active session.\n");
+		return FALSE;
+	}
+
+	desc_element = xmlnode_get_child(sess, "description");
+	xmlns = xmlnode_get_namespace(desc_element);
+
+	if (purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE))
+		session_data->video = FALSE;
+	else if (purple_strequal(xmlns, NS_GOOGLE_SESSION_VIDEO))
+		session_data->video = TRUE;
+	else {
+		purple_debug_error("jabber", "Received initiate with "
+				"invalid namespace %s.\n", xmlns);
+		return FALSE;
+	}
+
+	session_data->media = purple_media_manager_create_media(
+			purple_media_manager_get(),
+			purple_connection_get_account(js->gc),
+			"fsrtpconference", session->remote_jid, FALSE);
+
+	purple_media_set_prpl_data(session_data->media, session);
+
+	g_signal_connect_swapped(G_OBJECT(session_data->media),
+			"candidates-prepared",
+			G_CALLBACK(google_session_ready), session);
+	g_signal_connect_swapped(G_OBJECT(session_data->media), "codecs-changed",
+			G_CALLBACK(google_session_ready), session);
+	g_signal_connect(G_OBJECT(session_data->media), "state-changed",
+			G_CALLBACK(google_session_state_changed_cb), session);
+	g_signal_connect(G_OBJECT(session_data->media), "stream-info",
+			G_CALLBACK(google_session_stream_info_cb), session);
+
+	session->iq_id = g_strdup(iq_id);
+	
+	if (js->google_relay_host && js->google_relay_token) {
+		jabber_google_do_relay_request(js, session, 
+			jabber_google_relay_response_session_handle_initiate_cb);
+	} else {
+		jabber_google_relay_response_session_handle_initiate_cb(session, NULL,
+			0, 0, 0, NULL, NULL);
+	}
+
+	return TRUE;
+}
+
+
+static void
+google_session_handle_candidates(JabberStream  *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
+{
+	JabberIq *result;
+	GList *list = NULL, *video_list = NULL;
+	xmlnode *cand;
+	static int name = 0;
+	char n[4];
+	GoogleAVSessionData *session_data =
+		(GoogleAVSessionData *) session->session_data;
+	
+	for (cand = xmlnode_get_child(sess, "candidate"); cand;
+			cand = xmlnode_get_next_twin(cand)) {
+		PurpleMediaCandidate *info;
+		const gchar *cname = xmlnode_get_attrib(cand, "name");
+		const gchar *type = xmlnode_get_attrib(cand, "type");
+		const gchar *protocol = xmlnode_get_attrib(cand, "protocol");
+		const gchar *address = xmlnode_get_attrib(cand, "address");
+		const gchar *port = xmlnode_get_attrib(cand, "port");
+		const gchar *preference = xmlnode_get_attrib(cand, "preference");
+		guint component_id;
+
+		if (cname && type && address && port) {
+			PurpleMediaCandidateType candidate_type;
+			guint prio = preference ? atof(preference) * 1000 : 0;
+			
+			g_snprintf(n, sizeof(n), "S%d", name++);
+			
+			if (g_str_equal(type, "local"))
+				candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
+			else if (g_str_equal(type, "stun"))
+				candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX;
+			else if (g_str_equal(type, "relay"))
+				candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_RELAY;
+			else
+				candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
+
+			if (purple_strequal(cname, "rtcp") ||
+					purple_strequal(cname, "video_rtcp"))
+				component_id = PURPLE_MEDIA_COMPONENT_RTCP;
+			else
+				component_id = PURPLE_MEDIA_COMPONENT_RTP;
+
+			info = purple_media_candidate_new(n, component_id,
+					candidate_type,
+					purple_strequal(protocol, "udp") ?
+							PURPLE_MEDIA_NETWORK_PROTOCOL_UDP :
+							PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+					address,
+					atoi(port));
+			g_object_set(info, "username", xmlnode_get_attrib(cand, "username"),
+					"password", xmlnode_get_attrib(cand, "password"),
+			        "priority", prio, NULL);
+			if (!strncmp(cname, "video_", 6)) {
+				if (session_data->added_streams) {
+					video_list = g_list_append(video_list, info);
+				} else {
+					session_data->remote_video_candidates =
+						g_list_append(session_data->remote_video_candidates,
+							info);
+				}
+			} else {
+				if (session_data->added_streams) {
+					list = g_list_append(list, info);
+				} else {
+					session_data->remote_audio_candidates =
+						g_list_append(session_data->remote_audio_candidates,
+							info);
+				}
+			}
+		}
+	}
+
+	if (list) {
+		purple_media_add_remote_candidates(session_data->media, "google-voice",
+			session->remote_jid, list);
+		purple_media_candidate_list_free(list);
+	}
+	if (video_list) {
+		purple_media_add_remote_candidates(session_data->media, "google-video",
+			session->remote_jid, video_list);
+		purple_media_candidate_list_free(video_list);
+	}
+
+	result = jabber_iq_new(js, JABBER_IQ_RESULT);
+	jabber_iq_set_id(result, iq_id);
+	xmlnode_set_attrib(result->node, "to", session->remote_jid);
+	jabber_iq_send(result);
+}
+
+static void
+google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
+{
+	xmlnode *desc_element = xmlnode_get_child(sess, "description");
+	xmlnode *codec_element = xmlnode_get_child(
+			desc_element, "payload-type");
+	GList *codecs = NULL, *video_codecs = NULL;
+	JabberIq *result = NULL;
+	const gchar *xmlns = xmlnode_get_namespace(desc_element);
+	gboolean video = (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_VIDEO));
+	GoogleAVSessionData *session_data =
+		(GoogleAVSessionData *) session->session_data;
+	
+	for (; codec_element; codec_element = codec_element->next) {
+		const gchar *xmlns, *encoding_name, *id,
+				*clock_rate, *width, *height, *framerate;
+		gboolean video_codec = FALSE;
+
+		if (!purple_strequal(codec_element->name, "payload-type"))
+			continue;
+
+		xmlns = xmlnode_get_namespace(codec_element);
+		encoding_name =	xmlnode_get_attrib(codec_element, "name");
+		id = xmlnode_get_attrib(codec_element, "id");
+
+		if (!video || purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE))
+			clock_rate = xmlnode_get_attrib(
+					codec_element, "clockrate");
+		else {
+			clock_rate = "90000";
+			width = xmlnode_get_attrib(codec_element, "width");
+			height = xmlnode_get_attrib(codec_element, "height");
+			framerate = xmlnode_get_attrib(
+					codec_element, "framerate");
+			video_codec = TRUE;
+		}
+
+		if (id && encoding_name) {
+			PurpleMediaCodec *codec = purple_media_codec_new(
+					atoi(id), encoding_name,
+					video_codec ? PURPLE_MEDIA_VIDEO :
+					PURPLE_MEDIA_AUDIO,
+					clock_rate ? atoi(clock_rate) : 0);
+			if (video_codec)
+				video_codecs = g_list_append(
+						video_codecs, codec);
+			else
+				codecs = g_list_append(codecs, codec);
+		}
+	}
+
+	if (codecs)
+		purple_media_set_remote_codecs(session_data->media, "google-voice",
+				session->remote_jid, codecs);
+	if (video_codecs)
+		purple_media_set_remote_codecs(session_data->media, "google-video",
+				session->remote_jid, video_codecs);
+
+	purple_media_stream_info(session_data->media, PURPLE_MEDIA_INFO_ACCEPT,
+			NULL, NULL, FALSE);
+
+	result = jabber_iq_new(js, JABBER_IQ_RESULT);
+	jabber_iq_set_id(result, iq_id);
+	xmlnode_set_attrib(result->node, "to", session->remote_jid);
+	jabber_iq_send(result);
+}
+
+static void
+google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *sess)
+{
+	GoogleAVSessionData *session_data =
+		(GoogleAVSessionData *) session->session_data;
+	purple_media_end(session_data->media, NULL, NULL);
+}
+
+static void
+google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *sess)
+{
+	GoogleAVSessionData *session_data =
+		(GoogleAVSessionData *) session->session_data;
+	purple_media_end(session_data->media, NULL, NULL);
+}
+
+static void
+google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
+{
+	const char *type = xmlnode_get_attrib(sess, "type");
+
+	if (!strcmp(type, "initiate")) {
+		google_session_handle_initiate(js, session, sess, iq_id);
+	} else if (!strcmp(type, "accept")) {
+		google_session_handle_accept(js, session, sess, iq_id);
+	} else if (!strcmp(type, "reject")) {
+		google_session_handle_reject(js, session, sess);
+	} else if (!strcmp(type, "terminate")) {
+		google_session_handle_terminate(js, session, sess);
+	} else if (!strcmp(type, "candidates")) {
+		google_session_handle_candidates(js, session, sess, iq_id);
+	}
+}
+
+void
+jabber_google_session_parse(JabberStream *js, const char *from,
+                            JabberIqType type, const char *iq_id,
+                            xmlnode *session_node)
+{
+	GoogleSession *session = NULL;
+	GoogleSessionId id;
+
+	xmlnode *desc_node;
+
+	GList *iter = NULL;
+
+	if (type != JABBER_IQ_SET)
+		return;
+
+	id.id = (gchar*)xmlnode_get_attrib(session_node, "id");
+	if (!id.id)
+		return;
+
+	id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator");
+	if (!id.initiator)
+		return;
+
+	iter = purple_media_manager_get_media_by_account(
+			purple_media_manager_get(),
+			purple_connection_get_account(js->gc));
+	for (; iter; iter = g_list_delete_link(iter, iter)) {
+		GoogleSession *gsession =
+				purple_media_get_prpl_data(iter->data);
+		if (google_session_id_equal(&(gsession->id), &id)) {
+			session = gsession;
+			break;
+		}
+	}
+	if (iter != NULL) {
+		g_list_free(iter);
+	}
+
+	if (session) {
+		google_session_parse_iq(js, session, session_node, iq_id);
+		return;
+	}
+
+	/* If the session doesn't exist, this has to be an initiate message */
+	if (strcmp(xmlnode_get_attrib(session_node, "type"), "initiate"))
+		return;
+	desc_node = xmlnode_get_child(session_node, "description");
+	if (!desc_node)
+		return;
+	session = g_new0(GoogleSession, 1);
+	session->id.id = g_strdup(id.id);
+	session->id.initiator = g_strdup(id.initiator);
+	session->state = UNINIT;
+	session->js = js;
+	session->remote_jid = g_strdup(session->id.initiator);
+	session->session_data = g_new0(GoogleAVSessionData, 1);
+
+	google_session_handle_initiate(js, session, session_node, iq_id);
+}
+#endif /* USE_VV */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_session.h	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,54 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_SESSION_H_
+#define PURPLE_JABBER_GOOGLE_SESSION_H_
+
+#include "jabber.h"
+
+typedef struct {
+	char *id;
+	char *initiator;
+} GoogleSessionId;
+
+typedef enum {
+	UNINIT,
+	SENT_INITIATE,
+	RECEIVED_INITIATE,
+	IN_PRORESS,
+	TERMINATED
+} GoogleSessionState;
+
+typedef struct {
+	GoogleSessionId id;
+	GoogleSessionState state;
+	JabberStream *js;
+	char *remote_jid;
+	char *iq_id;
+	gpointer session_data;
+} GoogleSession;
+
+gboolean jabber_google_session_initiate(JabberStream *js, const gchar *who,
+    PurpleMediaSessionType type);
+
+void jabber_google_session_parse(JabberStream *js, const char *from,
+    JabberIqType type, const char *iq, xmlnode *session);
+
+#endif /* PURPLE_JABBER_GOOGLE_SESSION_H_ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/jingleinfo.c	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,174 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+#include "jingleinfo.h"
+
+static void
+jabber_google_stun_lookup_cb(GSList *hosts, gpointer data,
+	const char *error_message)
+{
+	JabberStream *js = (JabberStream *) data;
+
+	if (error_message) {
+		purple_debug_error("jabber", "Google STUN lookup failed: %s\n",
+			error_message);
+		g_slist_free(hosts);
+		js->stun_query = NULL;
+		return;
+	}
+
+	if (hosts && g_slist_next(hosts)) {
+		struct sockaddr *addr = g_slist_next(hosts)->data;
+		char dst[INET6_ADDRSTRLEN];
+		int port;
+
+		if (addr->sa_family == AF_INET6) {
+			inet_ntop(addr->sa_family, &((struct sockaddr_in6 *) addr)->sin6_addr,
+				dst, sizeof(dst));
+			port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
+		} else {
+			inet_ntop(addr->sa_family, &((struct sockaddr_in *) addr)->sin_addr,
+				dst, sizeof(dst));
+			port = ntohs(((struct sockaddr_in *) addr)->sin_port);
+		}
+
+		if (js->stun_ip)
+			g_free(js->stun_ip);
+		js->stun_ip = g_strdup(dst);
+		js->stun_port = port;
+
+		purple_debug_info("jabber", "set Google STUN IP/port address: "
+		                  "%s:%d\n", dst, port);
+
+		/* unmark ongoing query */
+		js->stun_query = NULL;
+	}
+
+	while (hosts != NULL) {
+		hosts = g_slist_delete_link(hosts, hosts);
+		/* Free the address */
+		g_free(hosts->data);
+		hosts = g_slist_delete_link(hosts, hosts);
+	}
+}
+
+static void
+jabber_google_jingle_info_common(JabberStream *js, const char *from,
+                                 JabberIqType type, xmlnode *query)
+{
+	const xmlnode *stun = xmlnode_get_child(query, "stun");
+	const xmlnode *relay = xmlnode_get_child(query, "relay");
+	gchar *my_bare_jid;
+
+	/*
+	 * Make sure that random people aren't sending us STUN servers. Per
+	 * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these
+	 * stanzas are stamped from our bare JID.
+	 */
+	if (from) {
+		my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
+		if (!purple_strequal(from, my_bare_jid)) {
+			purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n",
+			                  from);
+			g_free(my_bare_jid);
+			return;
+		}
+
+		g_free(my_bare_jid);
+	}
+
+	if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET)
+		return;
+
+	purple_debug_info("jabber", "got google:jingleinfo\n");
+
+	if (stun) {
+		xmlnode *server = xmlnode_get_child(stun, "server");
+
+		if (server) {
+			const gchar *host = xmlnode_get_attrib(server, "host");
+			const gchar *udp = xmlnode_get_attrib(server, "udp");
+
+			if (host && udp) {
+				int port = atoi(udp);
+				/* if there, would already be an ongoing query,
+				 cancel it */
+				if (js->stun_query)
+					purple_dnsquery_destroy(js->stun_query);
+
+				js->stun_query = purple_dnsquery_a(host, port,
+					jabber_google_stun_lookup_cb, js);
+			}
+		}
+	}
+
+	if (relay) {
+		xmlnode *token = xmlnode_get_child(relay, "token");
+		xmlnode *server = xmlnode_get_child(relay, "server");
+		
+		if (token) {
+			gchar *relay_token = xmlnode_get_data(token);
+
+			/* we let js own the string returned from xmlnode_get_data */
+			js->google_relay_token = relay_token;
+		}
+
+		if (server) {
+			js->google_relay_host = 
+				g_strdup(xmlnode_get_attrib(server, "host"));
+		}
+	}
+}
+
+static void
+jabber_google_jingle_info_cb(JabberStream *js, const char *from,
+                             JabberIqType type, const char *id,
+                             xmlnode *packet, gpointer data)
+{
+	xmlnode *query = xmlnode_get_child_with_namespace(packet, "query",
+			NS_GOOGLE_JINGLE_INFO);
+
+	if (query)
+		jabber_google_jingle_info_common(js, from, type, query);
+	else
+		purple_debug_warning("jabber", "Got invalid google:jingleinfo\n");
+}
+
+void
+jabber_google_handle_jingle_info(JabberStream *js, const char *from,
+                                 JabberIqType type, const char *id,
+                                 xmlnode *child)
+{
+	jabber_google_jingle_info_common(js, from, type, child);
+}
+
+void
+jabber_google_send_jingle_info(JabberStream *js)
+{
+	JabberIq *jingle_info =
+		jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_JINGLE_INFO);
+
+	jabber_iq_set_callback(jingle_info, jabber_google_jingle_info_cb,
+		NULL);
+	purple_debug_info("jabber", "sending google:jingleinfo query\n");
+	jabber_iq_send(jingle_info);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/jingleinfo.h	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,32 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_ROSTER_H_
+#define PURPLE_JABBER_GOOGLE_ROSTER_H_
+
+#include "jabber.h"
+
+void jabber_google_handle_jingle_info(JabberStream *js, const char *from,
+                                      JabberIqType type, const char *id,
+                                      xmlnode *child);
+void jabber_google_send_jingle_info(JabberStream *js);
+
+
+#endif /* PURPLE_JABBER_GOOGLE_ROSTER_H_ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/relay.c	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,151 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+
+#include "relay.h"
+
+typedef struct {
+	GoogleSession *session;
+	JabberGoogleRelayCallback *cb;
+} JabberGoogleRelayCallbackData;
+
+static void
+jabber_google_relay_parse_response(const gchar *response, gchar **ip,
+	guint *udp, guint *tcp, guint *ssltcp, gchar **username, gchar **password)
+{
+	gchar **lines = g_strsplit(response, "\n", -1);
+	int i = 0;
+
+	for (; lines[i] ; i++) {
+		gchar *line = lines[i];
+		gchar **parts = g_strsplit(line, "=", 2);
+		
+		if (parts[0] && parts[1]) {
+			if (purple_strequal(parts[0], "relay.ip")) {
+				*ip = g_strdup(parts[1]);
+			} else if (purple_strequal(parts[0], "relay.udp_port")) {
+				*udp = atoi(parts[1]);
+			} else if (purple_strequal(parts[0], "relay.tcp_port")) {
+				*tcp = atoi(parts[1]);
+			} else if (purple_strequal(parts[0], "relay.ssltcp_port")) {
+				*ssltcp = atoi(parts[1]);
+			} else if (purple_strequal(parts[0], "username")) {
+				*username = g_strdup(parts[1]);
+			} else if (purple_strequal(parts[0], "password")) {
+				*password = g_strdup(parts[1]);
+			}
+		}
+		g_strfreev(parts);
+	}
+
+	g_strfreev(lines);
+}
+
+static void
+jabber_google_relay_remove_url_data(JabberStream *js, 
+	PurpleUtilFetchUrlData *url_data)
+{
+	GList *iter = js->google_relay_requests;
+
+	while (iter) {
+		if (iter->data == url_data) {
+			js->google_relay_requests =
+				g_list_delete_link(js->google_relay_requests, iter);
+			break;
+		}
+	}
+}
+
+static void
+jabber_google_relay_fetch_cb(PurpleUtilFetchUrlData *url_data, 
+	gpointer user_data, const gchar *url_text, gsize len, 
+	const gchar *error_message)
+{
+	JabberGoogleRelayCallbackData *data =
+		(JabberGoogleRelayCallbackData *) user_data;
+	GoogleSession *session = data->session;
+	JabberStream *js = session->js;
+	JabberGoogleRelayCallback *cb = data->cb;
+	gchar *relay_ip = NULL;
+	guint relay_udp = 0;
+	guint relay_tcp = 0;
+	guint relay_ssltcp = 0;
+	gchar *relay_username = NULL;
+	gchar *relay_password = NULL;
+
+	g_free(data);
+	
+	if (url_data) {
+		jabber_google_relay_remove_url_data(js, url_data);
+	}
+
+	purple_debug_info("jabber", "got response on HTTP request to relay server\n");
+
+	if (url_text && len > 0) {
+		purple_debug_info("jabber", "got Google relay request response:\n%s\n",
+			url_text);
+		jabber_google_relay_parse_response(url_text, &relay_ip, &relay_udp,
+			&relay_tcp, &relay_ssltcp, &relay_username, &relay_password);
+	}
+
+	if (cb)
+		cb(session, relay_ip, relay_udp, relay_tcp, relay_ssltcp,
+		   relay_username, relay_password);
+
+	g_free(relay_ip);
+	g_free(relay_username);
+	g_free(relay_password);
+}
+
+void
+jabber_google_do_relay_request(JabberStream *js, GoogleSession *session,
+	JabberGoogleRelayCallback cb)
+{
+	PurpleUtilFetchUrlData *url_data = NULL;
+	gchar *url = g_strdup_printf("http://%s", js->google_relay_host);
+	/* yes, the relay token is included twice as different request headers,
+	   this is apparently needed to make Google's relay servers work... */
+	gchar *request =
+		g_strdup_printf("GET /create_session HTTP/1.0\r\n"
+			            "Host: %s\r\n"
+						"X-Talk-Google-Relay-Auth: %s\r\n"
+						"X-Google-Relay-Auth: %s\r\n\r\n", 
+			js->google_relay_host, js->google_relay_token, js->google_relay_token);
+	JabberGoogleRelayCallbackData *data = g_new0(JabberGoogleRelayCallbackData, 1);
+
+	data->session = session;
+	data->cb = cb;
+	purple_debug_info("jabber", 
+		"sending Google relay request %s to %s\n", request, url); 
+	url_data = 
+		purple_util_fetch_url_request(url, FALSE, NULL, FALSE, request, FALSE,
+			jabber_google_relay_fetch_cb, data);
+	if (url_data) {
+		js->google_relay_requests =
+			g_list_prepend(js->google_relay_requests, url_data);
+	} else {
+		purple_debug_error("jabber", "unable to create Google relay request\n");
+		jabber_google_relay_fetch_cb(NULL, data, NULL, 0, NULL);
+	}
+	g_free(url);
+	g_free(request);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/relay.h	Mon Sep 13 09:57:03 2010 +0000
@@ -0,0 +1,33 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef JABBER_GOOGLE_RELAY
+#define JABBER_GOOGLE_RELAY
+
+#include "google_session.h"
+
+typedef void (JabberGoogleRelayCallback)(GoogleSession *session, const gchar *ip,
+    guint udp_port, guint tcp_port, guint tls_port,
+    const gchar *username, const gchar *password);
+
+void jabber_google_do_relay_request(JabberStream *js, GoogleSession *session,
+	JabberGoogleRelayCallback cb);
+
+#endif /* JABBER_GOOGLE_RELAY */
--- a/libpurple/protocols/jabber/iq.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/iq.c	Mon Sep 13 09:57:03 2010 +0000
@@ -28,7 +28,10 @@
 
 #include "buddy.h"
 #include "disco.h"
-#include "google.h"
+#include "google/gmail.h"
+#include "google/google.h"
+#include "google/jingleinfo.h"
+#include "google/google_session.h"
 #include "iq.h"
 #include "jingle/jingle.h"
 #include "oob.h"
--- a/libpurple/protocols/jabber/jabber.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Sep 13 09:57:03 2010 +0000
@@ -51,7 +51,9 @@
 #include "chat.h"
 #include "data.h"
 #include "disco.h"
-#include "google.h"
+#include "google/google.h"
+#include "google/google_roster.h"
+#include "google/google_session.h"
 #include "ibb.h"
 #include "iq.h"
 #include "jutil.h"
@@ -232,7 +234,7 @@
 		return TRUE;
 	}
 
-	if(purple_account_get_bool(account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) {
+	if (g_str_equal("require_tls", purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
 		purple_connection_error_reason(js->gc,
 				PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
 				_("You require encryption, but no TLS/SSL support was found."));
@@ -244,12 +246,16 @@
 
 void jabber_stream_features_parse(JabberStream *js, xmlnode *packet)
 {
-	if(xmlnode_get_child(packet, "starttls")) {
-		if(jabber_process_starttls(js, packet)) {
+	PurpleAccount *account = purple_connection_get_account(js->gc);
+	const char *connection_security =
+		purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS);
+
+	if (xmlnode_get_child(packet, "starttls")) {
+		if (jabber_process_starttls(js, packet)) {
 			jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
 			return;
 		}
-	} else if(purple_account_get_bool(js->gc->account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS) && !jabber_stream_is_ssl(js)) {
+	} else if (g_str_equal(connection_security, "require_tls") && !jabber_stream_is_ssl(js)) {
 		purple_connection_error_reason(js->gc,
 			 PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
 			_("You require encryption, but it is not available on this server."));
@@ -972,6 +978,9 @@
 	js->stun_ip = NULL;
 	js->stun_port = 0;
 	js->stun_query = NULL;
+	js->google_relay_token = NULL;
+	js->google_relay_host = NULL;
+	js->google_relay_requests = NULL;
 
 	/* if we are idle, set idle-ness on the stream (this could happen if we get
 		disconnected and the reconnects while being idle. I don't think it makes
@@ -1014,7 +1023,7 @@
 	js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user->domain);
 
 	/* if they've got old-ssl mode going, we probably want to ignore SRV lookups */
-	if(purple_account_get_bool(account, "old_ssl", FALSE)) {
+	if (g_str_equal("old_ssl", purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
 		if(purple_ssl_is_supported()) {
 			js->gsc = purple_ssl_connect(account, js->certificate_CN,
 					purple_account_get_int(account, "port", 5223),
@@ -1631,6 +1640,8 @@
 	if(js->sasl_mechs)
 		g_string_free(js->sasl_mechs, TRUE);
 	g_free(js->sasl_cb);
+	/* Note: _not_ g_free.  See auth_cyrus.c:jabber_sasl_cb_secret */
+	free(js->sasl_secret);
 #endif
 	g_free(js->serverFQDN);
 	while(js->commands) {
@@ -1673,6 +1684,21 @@
 		js->stun_query = NULL;
 	}
 
+	/* remove Google relay-related stuff */
+	g_free(js->google_relay_token);
+	g_free(js->google_relay_host);
+	if (js->google_relay_requests) {
+		while (js->google_relay_requests) {
+			PurpleUtilFetchUrlData *url_data =
+				(PurpleUtilFetchUrlData *) js->google_relay_requests->data;
+			purple_util_fetch_url_cancel(url_data);
+			g_free(url_data);
+			js->google_relay_requests = 
+				g_list_delete_link(js->google_relay_requests, 
+					js->google_relay_requests);
+		}
+	}
+
 	g_free(js);
 
 	gc->proto_data = NULL;
@@ -3229,9 +3255,9 @@
 		g_free(resource);
 
 		if (type & PURPLE_MEDIA_AUDIO &&
-				!jabber_resource_has_capability(jbr,
-				JINGLE_APP_RTP_SUPPORT_AUDIO) &&
-				jabber_resource_has_capability(jbr, NS_GOOGLE_VOICE))
+			!jabber_resource_has_capability(jbr,
+			JINGLE_APP_RTP_SUPPORT_AUDIO) &&
+			jabber_resource_has_capability(jbr, NS_GOOGLE_VOICE))
 			return jabber_google_session_initiate(js, who, type);
 		else
 			return jingle_rtp_initiate_media(js, who, type);
--- a/libpurple/protocols/jabber/jabber.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Mon Sep 13 09:57:03 2010 +0000
@@ -80,7 +80,7 @@
 
 #define CAPS0115_NODE "http://pidgin.im/"
 
-#define JABBER_DEFAULT_REQUIRE_TLS    TRUE
+#define JABBER_DEFAULT_REQUIRE_TLS    "require_starttls"
 #define JABBER_DEFAULT_FT_PROXIES     "proxy.eu.jabber.org"
 
 /* Index into attention_types list */
@@ -206,6 +206,7 @@
 #ifdef HAVE_CYRUS_SASL
 	sasl_conn_t *sasl;
 	sasl_callback_t *sasl_cb;
+	sasl_secret_t *sasl_secret;
 	const char *current_mech;
 	int auth_fail_count;
 
@@ -275,7 +276,12 @@
 	gchar *stun_ip;
 	int stun_port;
 	PurpleDnsQueryData *stun_query;
-	/* later add stuff to handle TURN relays... */
+
+	/* stuff for Google's relay handling */
+	gchar *google_relay_token;
+	gchar *google_relay_host;
+	GList *google_relay_requests; /* the HTTP requests to get */
+												/* relay info */
 };
 
 typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *namespace);
--- a/libpurple/protocols/jabber/jingle/jingle.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.c	Mon Sep 13 09:57:03 2010 +0000
@@ -35,6 +35,9 @@
 #include "rtp.h"
 
 #include <string.h>
+#ifdef USE_VV
+#include <gst/gst.h>
+#endif
 
 GType
 jingle_get_type(const gchar *type)
@@ -431,32 +434,91 @@
 				jingle_terminate_sessions_gh, NULL);
 }
 
+#ifdef USE_VV
+static GValueArray *
+jingle_create_relay_info(const gchar *ip, guint port, const gchar *username,
+	const gchar *password, const gchar *relay_type, GValueArray *relay_info)
+{
+	GValue value;
+	GstStructure *turn_setup = gst_structure_new("relay-info",
+		"ip", G_TYPE_STRING, ip, 
+		"port", G_TYPE_UINT, port,
+		"username", G_TYPE_STRING, username,
+		"password", G_TYPE_STRING, password,
+		"relay-type", G_TYPE_STRING, relay_type,
+		NULL);
+	purple_debug_info("jabber", "created gst_structure %" GST_PTR_FORMAT "\n", 
+		turn_setup);
+	if (turn_setup) {
+		memset(&value, 0, sizeof(GValue));
+		g_value_init(&value, GST_TYPE_STRUCTURE);
+		gst_value_set_structure(&value, turn_setup);
+		relay_info = g_value_array_append(relay_info, &value);
+		gst_structure_free(turn_setup);
+	}
+	return relay_info;
+}
+
 GParameter *
-jingle_get_params(JabberStream *js, guint *num)
+jingle_get_params(JabberStream *js, const gchar *relay_ip, guint relay_udp,
+	guint relay_tcp, guint relay_ssltcp, const gchar *relay_username,
+    const gchar *relay_password, guint *num)
 {
 	/* don't set a STUN server if one is set globally in prefs, in that case
 	 this will be handled in media.c */
 	gboolean has_account_stun = js->stun_ip && !purple_network_get_stun_ip();
-	guint num_params = has_account_stun ? 2 : 0;
+	guint num_params = has_account_stun ?
+		(relay_ip ? 3 : 2) : (relay_ip ? 1 : 0);
 	GParameter *params = NULL;
-
+	int next_index = 0;
+	
 	if (num_params > 0) {
 		params = g_new0(GParameter, num_params);
 
-		purple_debug_info("jabber",
-			"setting param stun-ip for stream using auto-discovered IP: %s\n",
-			js->stun_ip);
-		params[0].name = "stun-ip";
-		g_value_init(&params[0].value, G_TYPE_STRING);
-		g_value_set_string(&params[0].value, js->stun_ip);
-		purple_debug_info("jabber", 
-			"setting param stun-port for stream using auto-discovered port: %d\n",
-			js->stun_port);
-		params[1].name = "stun-port";
-		g_value_init(&params[1].value, G_TYPE_UINT);
-		g_value_set_uint(&params[1].value, js->stun_port);
+		if (has_account_stun) {
+			purple_debug_info("jabber", 
+				"setting param stun-ip for stream using Google auto-config: %s\n",
+				js->stun_ip);
+			params[next_index].name = "stun-ip";
+			g_value_init(&params[next_index].value, G_TYPE_STRING);
+			g_value_set_string(&params[next_index].value, js->stun_ip);
+			purple_debug_info("jabber", 
+				"setting param stun-port for stream using Google auto-config: %d\n",
+				js->stun_port);
+			next_index++;
+			params[next_index].name = "stun-port";
+			g_value_init(&params[next_index].value, G_TYPE_UINT);
+			g_value_set_uint(&params[next_index].value, js->stun_port);
+			next_index++;
+		}
+	
+		if (relay_ip) {
+			GValueArray *relay_info = g_value_array_new(0);
+
+			if (relay_udp) {
+				relay_info = 
+					jingle_create_relay_info(relay_ip, relay_udp, relay_username,
+						relay_password, "udp", relay_info);
+			}
+			if (relay_tcp) {
+				relay_info = 
+					jingle_create_relay_info(relay_ip, relay_tcp, relay_username,
+						relay_password, "tcp", relay_info);
+			}
+			if (relay_ssltcp) {
+				relay_info = 
+					jingle_create_relay_info(relay_ip, relay_ssltcp, relay_username,
+						relay_password, "tls", relay_info);
+			}
+			params[next_index].name = "relay-info";
+			g_value_init(&params[next_index].value, G_TYPE_VALUE_ARRAY);
+			g_value_set_boxed(&params[next_index].value, relay_info);
+			g_value_array_free(relay_info);
+		}
 	}
 
 	*num = num_params;
 	return params;
 }
+#endif
+
--- a/libpurple/protocols/jabber/jingle/jingle.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.h	Mon Sep 13 09:57:03 2010 +0000
@@ -78,9 +78,13 @@
 
 void jingle_terminate_sessions(JabberStream *js);
 
+#ifdef USE_VV
 /* create a GParam array given autoconfigured STUN (and later perhaps TURN).
 	if google_talk is TRUE, set compatability mode to GOOGLE_TALK */
-GParameter *jingle_get_params(JabberStream *js, guint *num_params);
+GParameter *jingle_get_params(JabberStream *js, const gchar *relay_ip,
+	guint relay_udp, guint relay_tcp, guint relay_ssltcp,
+    const gchar *relay_username, const gchar *relay_password, guint *num_params);
+#endif
 
 #ifdef __cplusplus
 }
--- a/libpurple/protocols/jabber/jingle/rtp.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.c	Mon Sep 13 09:57:03 2010 +0000
@@ -611,7 +611,8 @@
 				: PURPLE_MEDIA_RECV_VIDEO;
 
 	params = 
-		jingle_get_params(jingle_session_get_js(session), &num_params);
+		jingle_get_params(jingle_session_get_js(session), NULL, 0, 0, 0,
+			NULL, NULL, &num_params);
 
 	creator = jingle_content_get_creator(content);
 	if (!strcmp(creator, "initiator"))
--- a/libpurple/protocols/jabber/jingle/transport.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/transport.c	Mon Sep 13 09:57:03 2010 +0000
@@ -111,8 +111,6 @@
 	JingleTransport *transport;
 	g_return_if_fail(JINGLE_IS_TRANSPORT(object));
 
-	transport = JINGLE_TRANSPORT(object);
-
 	switch (prop_id) {
 		default:	
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -125,8 +123,6 @@
 {
 	JingleTransport *transport;
 	g_return_if_fail(JINGLE_IS_TRANSPORT(object));
-	
-	transport = JINGLE_TRANSPORT(object);
 
 	switch (prop_id) {
 		default:	
--- a/libpurple/protocols/jabber/libxmpp.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Mon Sep 13 09:57:03 2010 +0000
@@ -41,7 +41,7 @@
 #include "si.h"
 #include "message.h"
 #include "presence.h"
-#include "google.h"
+#include "google/google.h"
 #include "pep.h"
 #include "usermood.h"
 #include "usertune.h"
@@ -253,6 +253,7 @@
 {
 	PurpleAccountUserSplit *split;
 	PurpleAccountOption *option;
+	GList *encryption_values = NULL;
 
 	/* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
 	split = purple_account_user_split_new(_("Domain"), NULL, '@');
@@ -263,13 +264,26 @@
 	purple_account_user_split_set_reverse(split, FALSE);
 	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
 
-	option = purple_account_option_bool_new(_("Require SSL/TLS"), "require_tls", JABBER_DEFAULT_REQUIRE_TLS);
-	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
-											   option);
+#define ADD_VALUE(list, desc, v) { \
+	PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \
+	kvp->key = g_strdup((desc)); \
+	kvp->value = g_strdup((v)); \
+	list = g_list_prepend(list, kvp); \
+}
 
-	option = purple_account_option_bool_new(_("Force old (port 5223) SSL"), "old_ssl", FALSE);
+	ADD_VALUE(encryption_values, _("Require encryption"), "require_tls");
+	ADD_VALUE(encryption_values, _("Use encryption if available"), "opportunistic_tls");
+	ADD_VALUE(encryption_values, _("Use old-style SSL"), "old_ssl");
+#if 0
+	ADD_VALUE(encryption_values, "None", "none");
+#endif
+	encryption_values = g_list_reverse(encryption_values);
+
+#undef ADD_VALUE
+
+	option = purple_account_option_list_new(_("Connection security"), "connection_security", encryption_values);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
-											   option);
+						   option);
 
 	option = purple_account_option_bool_new(
 						_("Allow plaintext auth over unencrypted streams"),
--- a/libpurple/protocols/jabber/message.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/message.c	Mon Sep 13 09:57:03 2010 +0000
@@ -30,7 +30,7 @@
 #include "buddy.h"
 #include "chat.h"
 #include "data.h"
-#include "google.h"
+#include "google/google.h"
 #include "message.h"
 #include "xmlnode.h"
 #include "pep.h"
--- a/libpurple/protocols/jabber/oob.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/oob.c	Mon Sep 13 09:57:03 2010 +0000
@@ -185,7 +185,7 @@
 	jabber_oob_xfer_recv_error(xfer, "406");
 }
 
-static void jabber_oob_xfer_recv_canceled(PurpleXfer *xfer) {
+static void jabber_oob_xfer_recv_cancelled(PurpleXfer *xfer) {
 	jabber_oob_xfer_recv_error(xfer, "404");
 }
 
@@ -233,7 +233,7 @@
 		purple_xfer_set_init_fnc(xfer,   jabber_oob_xfer_init);
 		purple_xfer_set_end_fnc(xfer,    jabber_oob_xfer_end);
 		purple_xfer_set_request_denied_fnc(xfer, jabber_oob_xfer_recv_denied);
-		purple_xfer_set_cancel_recv_fnc(xfer, jabber_oob_xfer_recv_canceled);
+		purple_xfer_set_cancel_recv_fnc(xfer, jabber_oob_xfer_recv_cancelled);
 		purple_xfer_set_read_fnc(xfer,   jabber_oob_xfer_read);
 		purple_xfer_set_start_fnc(xfer,  jabber_oob_xfer_start);
 
--- a/libpurple/protocols/jabber/parser.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/parser.c	Mon Sep 13 09:57:03 2010 +0000
@@ -93,10 +93,25 @@
 			}
 		}
 
-		if (js->stream_id == NULL)
+		if (js->stream_id == NULL) {
+#if 0
+			/* This was underspecified in rfc3920 as only being a SHOULD, so
+			 * we cannot rely on it.  See #12331 and Oracle's server.
+			 */
 			purple_connection_error_reason(js->gc,
 					PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
 					_("XMPP stream missing ID"));
+#else
+			/* Instead, let's make up a placeholder stream ID, which we need
+			 * to do because we flag on it being NULL as a special case
+			 * in this parsing code.
+			 */
+			js->stream_id = g_strdup("");
+			purple_debug_info("jabber", "Server failed to specify a stream "
+			                  "ID (underspecified in rfc3920, but intended "
+			                  "to be a MUST; digest legacy auth may fail."); 
+#endif
+		}
 	} else {
 
 		if(js->current)
--- a/libpurple/protocols/jabber/presence.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/presence.c	Mon Sep 13 09:57:03 2010 +0000
@@ -34,7 +34,8 @@
 
 #include "buddy.h"
 #include "chat.h"
-#include "google.h"
+#include "google/google.h"
+#include "google/google_presence.h"
 #include "presence.h"
 #include "iq.h"
 #include "jutil.h"
--- a/libpurple/protocols/jabber/roster.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/roster.c	Mon Sep 13 09:57:03 2010 +0000
@@ -27,7 +27,8 @@
 
 #include "buddy.h"
 #include "chat.h"
-#include "google.h"
+#include "google/google.h"
+#include "google/google_roster.h"
 #include "presence.h"
 #include "roster.h"
 #include "iq.h"
@@ -76,12 +77,9 @@
 
 void jabber_roster_request(JabberStream *js)
 {
-	PurpleAccount *account;
 	JabberIq *iq;
 	xmlnode *query;
 
-	account = purple_connection_get_account(js->gc);
-
 	iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:roster");
 	query = xmlnode_get_child(iq->node, "query");
 
--- a/libpurple/protocols/jabber/si.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/jabber/si.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1666,12 +1666,8 @@
 
 void jabber_si_xfer_send(PurpleConnection *gc, const char *who, const char *file)
 {
-	JabberStream *js;
-
 	PurpleXfer *xfer;
 
-	js = gc->proto_data;
-
 	xfer = jabber_si_new_xfer(gc, who);
 
 	if (file)
--- a/libpurple/protocols/msn/contact.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/contact.c	Mon Sep 13 09:57:03 2010 +0000
@@ -527,16 +527,20 @@
 	g_return_if_fail(session != NULL);
 
 	if (resp != NULL) {
+#ifdef MSN_PARTIAL_LISTS
 		const char *abLastChange;
 		const char *dynamicItemLastChange;
+#endif
 
 		purple_debug_misc("msn", "Got the contact list!\n");
 
 		msn_parse_contact_list(session, resp->xml);
+#ifdef MSN_PARTIAL_LISTS
 		abLastChange = purple_account_get_string(session->account,
 			"ablastChange", NULL);
 		dynamicItemLastChange = purple_account_get_string(session->account,
 			"DynamicItemLastChanged", NULL);
+#endif
 
 		if (state->partner_scenario == MSN_PS_INITIAL) {
 #ifdef MSN_PARTIAL_LISTS
@@ -1565,7 +1569,7 @@
 	
 	if (list == MSN_LIST_PL) {
 		partner_scenario = MSN_PS_CONTACT_API;
-		if (user && user->networkid != MSN_NETWORK_PASSPORT)
+		if (user->networkid != MSN_NETWORK_PASSPORT)
 			member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML,
 			                         "EmailMember", "Email",
 			                         user->member_id_on_pending_list);
--- a/libpurple/protocols/msn/httpconn.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/httpconn.c	Mon Sep 13 09:57:03 2010 +0000
@@ -239,6 +239,9 @@
 		}
 		else
 		{
+			/* I'll be honest, I don't fully understand all this, but this
+			 * causes crashes, Stu. */
+#if 0
 			MsnServConn *servconn;
 
 			/* It's going to die. */
@@ -246,10 +249,9 @@
 
 			servconn = httpconn->servconn;
 
-			/* I'll be honest, I don't fully understand all this, but this
-			 * causes crashes, Stu. */
-			/* if (servconn != NULL)
-				servconn->wasted = TRUE; */
+			if (servconn != NULL)
+				servconn->wasted = TRUE;
+#endif
 
 			g_free(full_session_id);
 			g_free(session_id);
--- a/libpurple/protocols/msn/msn.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/msn.c	Mon Sep 13 09:57:03 2010 +0000
@@ -622,7 +622,6 @@
 {
 	PurpleBuddy *buddy;
 	PurpleConnection *gc;
-	MsnSession *session;
 	MsnMobileData *data;
 	PurpleAccount *account;
 	const char *name;
@@ -634,8 +633,6 @@
 	gc = purple_account_get_connection(account);
 	name = purple_buddy_get_name(buddy);
 
-	session = gc->proto_data;
-
 	data = g_new0(MsnMobileData, 1);
 	data->gc = gc;
 	data->passport = name;
@@ -2084,11 +2081,9 @@
 msn_remove_group(PurpleConnection *gc, PurpleGroup *group)
 {
 	MsnSession *session;
-	MsnCmdProc *cmdproc;
 	const char *gname;
 
 	session = gc->proto_data;
-	cmdproc = session->notification->cmdproc;
 	gname = purple_group_get_name(group);
 
 	purple_debug_info("msn", "Remove group %s\n", gname);
--- a/libpurple/protocols/msn/msnutils.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/msnutils.c	Mon Sep 13 09:57:03 2010 +0000
@@ -541,7 +541,7 @@
 	chlStringParts = (unsigned int *)buf;
 
 	/* this is magic */
-	for (i = 0; i < (strlen(buf) / 4); i += 2) {
+	for (i = 0; i < (len / 4); i += 2) {
 		long long temp;
 
 		chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]);
--- a/libpurple/protocols/msn/notification.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/notification.c	Mon Sep 13 09:57:03 2010 +0000
@@ -92,7 +92,6 @@
 {
 	MsnCmdProc *cmdproc;
 	MsnSession *session;
-	PurpleAccount *account;
 	GString *vers;
 	const char *ver_str;
 	int i;
@@ -101,7 +100,6 @@
 
 	cmdproc = servconn->cmdproc;
 	session = servconn->session;
-	account = session->account;
 
 	vers = g_string_new("");
 
@@ -178,10 +176,8 @@
 usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
-	PurpleAccount *account;
 
 	session = cmdproc->session;
-	account = session->account;
 
 	if (!g_ascii_strcasecmp(cmd->params[1], "OK"))
 	{
@@ -1000,7 +996,6 @@
 {
 	MsnSession *session;
 	PurpleAccount *account;
-	PurpleConnection *gc;
 	MsnUser *user;
 	MsnObject *msnobj = NULL;
 	unsigned long clientid;
@@ -1010,7 +1005,6 @@
 
 	session = cmdproc->session;
 	account = session->account;
-	gc = purple_account_get_connection(account);
 
 	state    = cmd->params[1];
 	passport = cmd->params[2];
@@ -1203,7 +1197,6 @@
 {
 	MsnSession *session;
 	PurpleAccount *account;
-	PurpleConnection *gc;
 	MsnUser *user;
 	MsnObject *msnobj;
 	unsigned long clientid;
@@ -1212,7 +1205,6 @@
 
 	session = cmdproc->session;
 	account = session->account;
-	gc = purple_account_get_connection(account);
 
 	state    = cmd->params[0];
 	passport = cmd->params[1];
@@ -1387,11 +1379,13 @@
 	MsnSession *session;
 	MsnSwitchBoard *swboard;
 	const char *session_id;
+	const char *auth_key;
 	char *host;
 	int port;
 
 	session = cmdproc->session;
 	session_id = cmd->params[0];
+	auth_key = cmd->params[3];
 
 	msn_parse_socket(cmd->params[1], &host, &port);
 
@@ -1401,8 +1395,8 @@
 	swboard = msn_switchboard_new(session);
 
 	msn_switchboard_set_invited(swboard, TRUE);
-	msn_switchboard_set_session_id(swboard, cmd->params[0]);
-	msn_switchboard_set_auth_key(swboard, cmd->params[3]);
+	msn_switchboard_set_session_id(swboard, session_id);
+	msn_switchboard_set_auth_key(swboard, auth_key);
 	swboard->im_user = g_strdup(cmd->params[4]);
 	/* msn_switchboard_add_user(swboard, cmd->params[4]); */
 
@@ -1571,13 +1565,11 @@
 			 size_t len)
 {
 	MsnSession *session;
-	PurpleAccount *account;
 	MsnUser *user;
 	const char *passport;
 	char *str;
 
 	session = cmdproc->session;
-	account = session->account;
 
 	passport = cmd->params[0];
 	user = msn_userlist_find_user(session->userlist, passport);
@@ -1649,7 +1641,9 @@
 {
 	MsnSession *session;
 	const char *value;
+#ifdef MSN_PARTIAL_LISTS
 	const char *clLastChange;
+#endif
 
 	session = cmdproc->session;
 
@@ -1692,9 +1686,9 @@
 	if ((value = msn_message_get_attr(msg, "EmailEnabled")) != NULL)
 		session->passport_info.email_enabled = (gboolean)atol(value);
 
+#ifdef MSN_PARTIAL_LISTS
 	/*starting retrieve the contact list*/
 	clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL);
-#ifdef MSN_PARTIAL_LISTS
 	/* msn_userlist_load defeats all attempts at trying to detect blist sync issues */
 	msn_userlist_load(session);
 	msn_get_contact_list(session, MSN_PS_INITIAL, clLastChange);
@@ -1898,7 +1892,7 @@
 	if ((type_s = g_hash_table_lookup(table, "Type")) != NULL)
 	{
 		int type = atoi(type_s);
-		char buf[MSN_BUF_LEN];
+		char buf[MSN_BUF_LEN] = "";
 		int minutes;
 
 		switch (type)
--- a/libpurple/protocols/msn/session.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/session.c	Mon Sep 13 09:57:03 2010 +0000
@@ -283,7 +283,7 @@
 void
 msn_session_activate_login_timeout(MsnSession *session)
 {
-	if (!session->logged_in) {
+	if (!session->logged_in && session->connected) {
 		session->login_timeout =
 			purple_timeout_add_seconds(MSN_LOGIN_FQY_TIMEOUT,
 			                           msn_login_timeout_cb, session);
--- a/libpurple/protocols/msn/slp.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/slp.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1263,8 +1263,6 @@
 	if (userlist->buddy_icon_window > 0)
 	{
 		GQueue *queue;
-		PurpleAccount *account;
-		const char *username;
 
 		queue = userlist->buddy_icon_requests;
 
@@ -1273,9 +1271,6 @@
 
 		user = g_queue_pop_head(queue);
 
-		account  = userlist->session->account;
-		username = user->passport;
-
 		userlist->buddy_icon_window--;
 		request_user_display(user);
 
@@ -1347,31 +1342,21 @@
 got_user_display(MsnSlpCall *slpcall,
 				 const guchar *data, gsize size)
 {
-	MsnUserList *userlist;
+	MsnSlpLink *slplink;
 	const char *info;
 	PurpleAccount *account;
 
 	g_return_if_fail(slpcall != NULL);
+	slplink = slpcall->slplink;
 
 	info = slpcall->data_info;
 	if (purple_debug_is_verbose())
-		purple_debug_info("msn", "Got User Display: %s\n", slpcall->slplink->remote_user);
-
-	userlist = slpcall->slplink->session->userlist;
-	account = slpcall->slplink->session->account;
-
-	purple_buddy_icons_set_for_user(account, slpcall->slplink->remote_user,
-								  g_memdup(data, size), size, info);
+		purple_debug_info("msn", "Got User Display: %s\n", slplink->remote_user);
 
-#if 0
-	/* Free one window slot */
-	userlist->buddy_icon_window++;
+	account = slplink->session->account;
 
-	purple_debug_info("msn", "got_user_display(): buddy_icon_window++ yields =%d\n",
-					userlist->buddy_icon_window);
-
-	msn_release_buddy_icon_request(userlist);
-#endif
+	purple_buddy_icons_set_for_user(account, slplink->remote_user,
+								  g_memdup(data, size), size, info);
 }
 
 static void
--- a/libpurple/protocols/msn/slplink.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/slplink.c	Mon Sep 13 09:57:03 2010 +0000
@@ -632,7 +632,7 @@
 		slpmsg = msn_slplink_message_find(slplink, header->session_id, header->id);
 		if (slpmsg == NULL)
 		{
-			/* Probably the transfer was canceled */
+			/* Probably the transfer was cancelled */
 			purple_debug_error("msn", "Couldn't find slpmsg\n");
 			return;
 		}
--- a/libpurple/protocols/msn/switchboard.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Mon Sep 13 09:57:03 2010 +0000
@@ -761,12 +761,8 @@
 static void
 iro_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
-	PurpleAccount *account;
-	PurpleConnection *gc;
 	MsnSwitchBoard *swboard;
 
-	account = cmdproc->session->account;
-	gc = account->gc;
 	swboard = cmdproc->data;
 
 	swboard->total_users = atoi(cmd->params[2]);
@@ -778,16 +774,12 @@
 joi_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
-	PurpleAccount *account;
-	PurpleConnection *gc;
 	MsnSwitchBoard *swboard;
 	const char *passport;
 
 	passport = cmd->params[0];
 
 	session = cmdproc->session;
-	account = session->account;
-	gc = account->gc;
 	swboard = cmdproc->data;
 
 	msn_switchboard_add_user(swboard, passport);
--- a/libpurple/protocols/oscar/family_icbm.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1320,7 +1320,7 @@
 
 	/*
 	 * Terminate connection/error code.  0x0001 means the other user
-	 * canceled the connection.
+	 * cancelled the connection.
 	 */
 	if (aim_tlv_gettlv(list2, 0x000b, 1))
 		args.errorcode = aim_tlv_get16(list2, 0x000b, 1);
--- a/libpurple/protocols/oscar/oft.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/oscar/oft.c	Mon Sep 13 09:57:03 2010 +0000
@@ -240,7 +240,7 @@
 peer_oft_close(PeerConnection *conn)
 {
 	/*
-	 * If canceled by local user, and we're receiving a file, and
+	 * If cancelled by local user, and we're receiving a file, and
 	 * we're not connected/ready then send an ICBM cancel message.
 	 */
 	if ((purple_xfer_get_status(conn->xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) &&
--- a/libpurple/protocols/oscar/oscar.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1699,7 +1699,7 @@
 		}
 		else if (args->status == AIM_RENDEZVOUS_CANCEL)
 		{
-			/* The other user canceled a peer request */
+			/* The other user cancelled a peer request */
 			PeerConnection *conn;
 
 			conn = peer_connection_find_by_cookie(od, userinfo->bn, args->cookie);
@@ -4953,7 +4953,7 @@
 		peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
 
 		/* OSCAR_DISCONNECT_LOCAL_CLOSED doesn't write anything to the convo
-		 * window. Let the user know that we canceled the Direct IM. */
+		 * window. Let the user know that we cancelled the Direct IM. */
 		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
 		purple_conversation_write(conv, NULL, _("You closed the connection."),
 				PURPLE_MESSAGE_SYSTEM, time(NULL));
--- a/libpurple/protocols/qq/ChangeLog	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/ChangeLog	Mon Sep 13 09:57:03 2010 +0000
@@ -233,7 +233,7 @@
 2008.08.06 - ccpaging <ccpaging(at)gmail.com>
 	* Rename names of variables, Group, to Room
 	* Functions of group_network merged into qq_network and qq_process
-	* Canceled managing glist of group packet, add sub_cmdd and room_id  to transaction
+	* Cancelled managing glist of group packet, add sub_cmdd and room_id  to transaction
 	* Fixed error of demo group:
 		If 'room list' and 'room infor' are not setup, response received from server will emits 'room_id = 0' packet.
 
--- a/libpurple/protocols/qq/buddy_info.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Mon Sep 13 09:57:03 2010 +0000
@@ -224,12 +224,10 @@
 void qq_request_buddy_info(PurpleConnection *gc, guint32 uid,
 		guint32 update_class, int action)
 {
-	qq_data *qd;
 	gchar raw_data[16] = {0};
 
 	g_return_if_fail(uid != 0);
 
-	qd = (qq_data *) gc->proto_data;
 	g_snprintf(raw_data, sizeof(raw_data), "%u", uid);
 	qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDY_INFO, (guint8 *) raw_data, strlen(raw_data),
 			update_class, action);
@@ -271,7 +269,6 @@
 static void info_modify_ok_cb(modify_info_request *info_request, PurpleRequestFields *fields)
 {
 	PurpleConnection *gc;
-	qq_data *qd;
 	gchar **segments;
 	int index;
 	const char *utf8_str;
@@ -279,8 +276,7 @@
 	int choice_num;
 
 	gc = info_request->gc;
-	g_return_if_fail(gc != NULL && info_request->gc);
-	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail(gc != NULL);
 	segments = info_request->segments;
 	g_return_if_fail(segments != NULL);
 
@@ -390,14 +386,12 @@
 
 static void info_modify_dialogue(PurpleConnection *gc, gchar **segments, int iclass)
 {
-	qq_data *qd;
 	PurpleRequestFieldGroup *group;
 	PurpleRequestFields *fields;
 	modify_info_request *info_request;
 	gchar *utf8_title, *utf8_prim;
 	int index;
 
-	qd = (qq_data *) gc->proto_data;
 	/* Keep one dialog once a time */
 	purple_request_close_with_handle(gc);
 
@@ -416,9 +410,11 @@
 		case QQ_FIELD_CONTACT:
 			utf8_title = g_strdup(_("Modify Contact"));
 			utf8_prim = g_strdup_printf("%s for %s", _("Modify Contact"), segments[0]);
+			break;
 		case QQ_FIELD_ADDR:
 			utf8_title = g_strdup(_("Modify Address"));
 			utf8_prim = g_strdup_printf("%s for %s", _("Modify Address"), segments[0]);
+			break;
 		case QQ_FIELD_EXT:
 			utf8_title = g_strdup(_("Modify Extended Information"));
 			utf8_prim = g_strdup_printf("%s for %s", _("Modify Extended Information"), segments[0]);
@@ -427,6 +423,7 @@
 		default:
 			utf8_title = g_strdup(_("Modify Information"));
 			utf8_prim = g_strdup_printf("%s for %s", _("Modify Information"), segments[0]);
+			break;
 	}
 
 	info_request = g_new0(modify_info_request, 1);
--- a/libpurple/protocols/qq/buddy_list.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/buddy_list.c	Mon Sep 13 09:57:03 2010 +0000
@@ -55,11 +55,9 @@
 /* get a list of online_buddies */
 void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, guint32 update_class)
 {
-	qq_data *qd;
 	guint8 *raw_data;
 	gint bytes = 0;
 
-	qd = (qq_data *) gc->proto_data;
 	raw_data = g_newa(guint8, 5);
 
 	/* 000-000 get online friends cmd
@@ -360,7 +358,6 @@
 
 guint32 qq_process_get_buddies_and_rooms(guint8 *data, gint data_len, PurpleConnection *gc)
 {
-	qq_data *qd;
 	gint i, j;
 	gint bytes;
 	guint8 sub_cmd, reply_code;
@@ -371,8 +368,6 @@
 
 	g_return_val_if_fail(data != NULL && data_len != 0, -1);
 
-	qd = (qq_data *) gc->proto_data;
-
 	bytes = 0;
 	bytes += qq_get8(&sub_cmd, data + bytes);
 	g_return_val_if_fail(sub_cmd == 0x01, -1);
@@ -468,11 +463,6 @@
 	guint8 away_cmd;
 	guint32 misc_status;
 	gboolean fake_video;
-	PurpleAccount *account;
-	PurplePresence *presence;
-
-	account = purple_connection_get_account(gc);
-	presence = purple_account_get_presence(account);
 
 	qd = (qq_data *) gc->proto_data;
 	if (!qd->is_login)
@@ -596,14 +586,13 @@
 void qq_update_buddy_status(PurpleConnection *gc, guint32 uid, guint8 status, guint8 flag)
 {
 	gchar *who;
-	gchar *status_id;
+	const gchar *status_id;
 
 	g_return_if_fail(uid != 0);
 
 	/* purple supports signon and idle time
 	 * but it is not much use for QQ, I do not use them */
 	/* serv_got_update(gc, name, online, 0, q_bud->signon, q_bud->idle, bud->uc); */
-	status_id = "available";
 	switch(status) {
 	case QQ_BUDDY_OFFLINE:
 		status_id = "offline";
@@ -677,13 +666,10 @@
 
 void qq_buddy_data_free_all(PurpleConnection *gc)
 {
-	qq_data *qd;
 	PurpleBuddy *buddy;
 	GSList *buddies, *it;
 	gint count = 0;
 
-	qd = (qq_data *)purple_connection_get_protocol_data(gc);
-
 	buddies = purple_find_buddies(purple_connection_get_account(gc), NULL);
 	for (it = buddies; it; it = it->next) {
 		qq_buddy_data *qbd = NULL;
--- a/libpurple/protocols/qq/buddy_opt.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/buddy_opt.c	Mon Sep 13 09:57:03 2010 +0000
@@ -262,7 +262,6 @@
 
 void qq_process_auth_code(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
 {
-	qq_data *qd;
 	gint bytes;
 	guint8 cmd, reply;
 	guint16 sub_cmd;
@@ -272,8 +271,6 @@
 	g_return_if_fail(data != NULL && data_len != 0);
 	g_return_if_fail(uid != 0);
 
-	qd = (qq_data *) gc->proto_data;
-
 	qq_show_packet("qq_process_auth_code", data, data_len);
 	bytes = 0;
 	bytes += qq_get8(&cmd, data + bytes);
@@ -324,7 +321,7 @@
 	add_req->auth_len = 0;
 
 	who = uid_to_purple_name(uid);
-	msg = g_strdup_printf(_("%u requires verification"), uid);
+	msg = g_strdup_printf(_("%u requires verification: %s"), uid, question);
 	purple_request_input(gc, _("Add buddy question"), msg,
 			_("Enter answer here"),
 			NULL,
@@ -400,7 +397,6 @@
 
 void qq_process_question(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
 {
-	qq_data *qd;
 	gint bytes;
 	guint8 cmd, reply;
 	gchar *question, *answer;
@@ -409,8 +405,6 @@
 
 	g_return_if_fail(data != NULL && data_len != 0);
 
-	qd = (qq_data *) gc->proto_data;
-
 	qq_show_packet("qq_process_question", data, data_len);
 	bytes = 0;
 	bytes += qq_get8(&cmd, data + bytes);
@@ -720,13 +714,10 @@
 /*  process reply to add_buddy_auth request */
 void qq_process_add_buddy_auth(guint8 *data, gint data_len, PurpleConnection *gc)
 {
-	qq_data *qd;
 	gchar **segments, *msg_utf8;
 
 	g_return_if_fail(data != NULL && data_len != 0);
 
-	qd = (qq_data *) gc->proto_data;
-
 	if (data[0] == '0') {
 		purple_debug_info("QQ", "Reply OK for sending authorize\n");
 		return;
@@ -767,11 +758,9 @@
 /* process the server reply for my request to remove myself from a buddy */
 void qq_process_buddy_remove_me(PurpleConnection *gc, guint8 *data, gint data_len, guint32 uid)
 {
-	qq_data *qd;
 	gchar *msg;
 
 	g_return_if_fail(data != NULL && data_len != 0);
-	qd = (qq_data *) gc->proto_data;
 
 	if (data[0] == 0) {
 		purple_debug_info("QQ", "Reply OK for removing me from %u's buddy list\n", uid);
@@ -1004,7 +993,6 @@
 
 void qq_process_buddy_check_code(PurpleConnection *gc, guint8 *data, gint data_len)
 {
-	qq_data *qd;
 	gint bytes;
 	guint8 cmd;
 	guint8 reply;
@@ -1013,8 +1001,6 @@
 
 	g_return_if_fail(data != NULL && data_len >= 5);
 
-	qd = (qq_data *) gc->proto_data;
-
 	qq_show_packet("buddy_check_code", data, data_len);
 
 	bytes = 0;
--- a/libpurple/protocols/qq/file_trans.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/file_trans.c	Mon Sep 13 09:57:03 2010 +0000
@@ -238,12 +238,9 @@
 	gint bytes = 0;
 	guint32 file_key;
 	qq_data *qd;
-	ft_info *info;
 
 	qd = (qq_data *) gc->proto_data;
 
-	info = (ft_info *) qd->xfer->data;
-
 	raw_data = g_newa(guint8, MAX_PACKET_SIZE);
 	file_key = _gen_file_key();
 
@@ -805,9 +802,6 @@
 {
 	gint bytes;
 	guint8 tag;
-	qq_data *qd;
-
-	qd = (qq_data *) gc->proto_data;
 
 	bytes = 0;
 	bytes += qq_get8(&tag, data + bytes);
--- a/libpurple/protocols/qq/group.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/group.c	Mon Sep 13 09:57:03 2010 +0000
@@ -119,13 +119,11 @@
 /* free roomlist space, I have no idea when this one is called... */
 void qq_roomlist_cancel(PurpleRoomlist *list)
 {
-	qq_data *qd;
 	PurpleConnection *gc;
 
 	g_return_if_fail(list != NULL);
 	gc = purple_account_get_connection(list->account);
 
-	qd = (qq_data *) gc->proto_data;
 	purple_roomlist_set_in_progress(list, FALSE);
 	purple_roomlist_unref(list);
 }
--- a/libpurple/protocols/qq/group_im.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/group_im.c	Mon Sep 13 09:57:03 2010 +0000
@@ -48,12 +48,10 @@
 PurpleConversation *qq_room_conv_open(PurpleConnection *gc, qq_room_data *rmd)
 {
 	PurpleConversation *conv;
-	qq_data *qd;
 	gchar *topic_utf8;
 
 	g_return_val_if_fail(rmd != NULL, NULL);
 	g_return_val_if_fail(rmd->title_utf8, NULL);
-	qd = (qq_data *) gc->proto_data;
 
 	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
 			rmd->title_utf8, purple_connection_get_account(gc));
@@ -207,7 +205,6 @@
 /* recv an IM from a group chat */
 void qq_process_room_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type)
 {
-	qq_data *qd;
 	gchar *msg_smiley, *msg_fmt, *msg_utf8;
 	gint bytes, tail_len;
 	struct {
@@ -229,7 +226,6 @@
 
 	/* at least include im_text.msg_len */
 	g_return_if_fail(data != NULL && data_len > 23);
-	qd = (qq_data *) gc->proto_data;
 
 	/* qq_show_packet("ROOM_IM", data, data_len); */
 	memset(&im_text, 0, sizeof(im_text));
@@ -376,7 +372,6 @@
 	gint msg_len;
 	const gchar *start_invalid;
 	gboolean is_smiley_none;
-	guint8 frag_count, frag_index;
 
 	g_return_val_if_fail(NULL != gc && NULL != gc->proto_data, -1);
 	g_return_val_if_fail(id != 0 && what != NULL, -1);
@@ -386,9 +381,6 @@
 
 	/* qq_show_packet("chat IM UTF8", (guint8 *)what, strlen(what)); */
 
-	fmt = qq_im_fmt_new_by_purple(what);
-	is_smiley_none = qq_im_smiley_none(what);
-
 	msg_stripped = purple_markup_strip_html(what);
 	g_return_val_if_fail(msg_stripped != NULL, -1);
 	/* qq_show_packet("IM Stripped", (guint8 *)what, strlen(what)); */
@@ -417,26 +409,10 @@
 
 	qd->send_im_id++;
 	fmt = qq_im_fmt_new_by_purple(what);
-	frag_count = g_slist_length(segments);
-	frag_index = 0;
-/*
-	if (frag_count <= 1) {
-*/
-		for (it = segments; it; it = it->next) {
-			request_room_send_im(gc, id, fmt, (gchar *)it->data);
-			g_free(it->data);
-		}
-/*
-	} else {
-		for (it = segments; it; it = it->next) {
-			request_room_send_im_ex(gc, id, fmt, (gchar *)it->data,
-					qd->send_im_id, frag_count, frag_index);
-			g_free(it->data);
-			frag_index++;
-		}
+	for (it = segments; it; it = g_slist_delete_link(it, it)) {
+		request_room_send_im(gc, id, fmt, (gchar *)it->data);
+		g_free(it->data);
 	}
-*/
 	qq_im_fmt_free(fmt);
-	g_slist_free(segments);
 	return 1;
 }
--- a/libpurple/protocols/qq/group_join.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/group_join.c	Mon Sep 13 09:57:03 2010 +0000
@@ -178,12 +178,10 @@
 /* If comes here, cmd is OK already */
 void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc)
 {
-	qq_data *qd;
 	gint bytes;
 	guint32 id;
 
 	g_return_if_fail(data != NULL && len > 0);
-	qd = (qq_data *) gc->proto_data;
 
 	if (len < 4) {
 		purple_debug_error("QQ", "Invalid exit group reply, expect %d bytes, read %d bytes\n", 4, len);
@@ -201,12 +199,10 @@
 {
 	gint bytes;
 	guint32 id;
-	qq_data *qd;
 	qq_room_data *rmd;
 	gchar *msg;
 
 	g_return_if_fail(data != NULL && len > 0);
-	qd = (qq_data *) gc->proto_data;
 
 	if (len < 4) {
 		purple_debug_error("QQ",
@@ -283,7 +279,6 @@
 /* Attempt to join a group without auth */
 void qq_group_join(PurpleConnection *gc, GHashTable *data)
 {
-	qq_data *qd;
 	gchar *ext_id_str;
 	gchar *id_str;
 	guint32 ext_id;
@@ -291,7 +286,6 @@
 	qq_room_data *rmd;
 
 	g_return_if_fail(data != NULL);
-	qd = (qq_data *) gc->proto_data;
 
 	ext_id_str = g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID);
 	id_str = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID);
--- a/libpurple/protocols/qq/group_opt.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/group_opt.c	Mon Sep 13 09:57:03 2010 +0000
@@ -134,12 +134,10 @@
 {
 	guint32 *old_members, *del_members, *add_members;
 	qq_buddy_data *bd;
-	qq_data *qd;
 	gint i = 0, old = 0, new = 0, del = 0, add = 0;
 	GList *list;
 
 	g_return_if_fail(rmd != NULL);
-	qd = (qq_data *) gc->proto_data;
 	if (new_members[0] == 0xffffffff)
 		return;
 
--- a/libpurple/protocols/qq/im.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/im.c	Mon Sep 13 09:57:03 2010 +0000
@@ -725,7 +725,6 @@
 /* process received normal text IM */
 static void process_im_text(PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header)
 {
-	qq_data *qd;
 	guint16 purple_msg_type;
 	gchar *who;
 	gchar *msg_smiley, *msg_fmt, *msg_utf8;
@@ -749,10 +748,9 @@
 		gchar *msg;		/* no fixed length, ends with 0x00 */
 	} im_text;
 
-	g_return_if_fail (data != NULL && len > 0);
+	g_return_if_fail(data != NULL && len > 0);
 	g_return_if_fail(im_header != NULL);
 
-	qd = (qq_data *) gc->proto_data;
 	memset(&im_text, 0, sizeof(im_text));
 
 	/* qq_show_packet("IM text", data, len); */
@@ -823,7 +821,6 @@
 /* process received extended (2007) text IM */
 static void process_extend_im_text(PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header)
 {
-	qq_data *qd;
 	guint16 purple_msg_type;
 	gchar *who;
 	gchar *msg_smiley, *msg_fmt, *msg_utf8;
@@ -848,10 +845,9 @@
 		guint8 fromMobileQQ;
 	} im_text;
 
-	g_return_if_fail (data != NULL && len > 0);
+	g_return_if_fail(data != NULL && len > 0);
 	g_return_if_fail(im_header != NULL);
 
-	qd = (qq_data *) gc->proto_data;
 	memset(&im_text, 0, sizeof(im_text));
 
 	/* qq_show_packet("Extend IM text", data, len); */
@@ -1043,12 +1039,10 @@
 {
 	qq_data *qd;
 	guint8 raw_data[MAX_PACKET_SIZE - 16];
-	guint16 im_type;
 	gint bytes;
 	time_t now;
 
 	qd = (qq_data *) gc->proto_data;
-	im_type = QQ_NORMAL_IM_TEXT;
 
 	/* purple_debug_info("QQ", "Send IM %d-%d\n", frag_count, frag_index); */
 	bytes = 0;
@@ -1118,13 +1112,12 @@
 	GString *new_string;
 	GString *append_utf8;
 	gchar *start, *p;
-	gint count, len;
+	gint len;
 	qq_emoticon *emoticon;
 
 	g_return_val_if_fail(msg_stripped != NULL, NULL);
 
 	start = msg_stripped;
-	count = 0;
 	new_string = g_string_new("");
 	append_utf8 = g_string_new("");
 	while (*start) {
--- a/libpurple/protocols/qq/qq.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/qq.c	Mon Sep 13 09:57:03 2010 +0000
@@ -89,15 +89,12 @@
 {
 	PurpleConnection *gc;
 	qq_data *qd;
-	PurpleProxyInfo *gpi;
 	const gchar *custom_server;
 
 	gc = purple_account_get_connection(account);
 	g_return_if_fail(gc != NULL  && gc->proto_data != NULL);
 	qd = gc->proto_data;
 
-	gpi = purple_proxy_get_setup(account);
-
 	qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE);
 
 	custom_server = purple_account_get_string(account, "server", NULL);
@@ -381,11 +378,10 @@
 static const char *qq_list_emblem(PurpleBuddy *b)
 {
 	PurpleAccount *account;
-	PurpleConnection *gc;
 	qq_buddy_data *buddy;
 
 	if (!b || !(account = purple_buddy_get_account(b)) ||
-		!(gc = purple_account_get_connection(account)))
+		!purple_account_get_connection(account))
 		return NULL;
 
 	buddy = purple_buddy_get_protocol_data(b);
@@ -618,12 +614,10 @@
 static void action_about_openq(PurplePluginAction *action)
 {
 	PurpleConnection *gc = (PurpleConnection *) action->context;
-	qq_data *qd;
 	GString *info;
 	gchar *title;
 
-	g_return_if_fail(NULL != gc && NULL != gc->proto_data);
-	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail(NULL != gc);
 
 	info = g_string_new("<html><body>");
 	g_string_append(info, _("<p><b>Original Author</b>:<br>\n"));
--- a/libpurple/protocols/qq/qq_base.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/qq_base.c	Mon Sep 13 09:57:03 2010 +0000
@@ -386,7 +386,6 @@
 /* process the login reply packet */
 guint8 qq_process_login( PurpleConnection *gc, guint8 *data, gint data_len)
 {
-	qq_data *qd;
 	guint8 ret = data[0];
 	gchar *msg, *msg_utf8;
 	gchar *error;
@@ -394,8 +393,6 @@
 
 	g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
 
-	qd = (qq_data *) gc->proto_data;
-
 	switch (ret) {
 		case QQ_LOGIN_REPLY_OK:
 			purple_debug_info("QQ", "Login OK\n");
--- a/libpurple/protocols/qq/qq_network.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/qq_network.c	Mon Sep 13 09:57:03 2010 +0000
@@ -482,13 +482,11 @@
 static void udp_pending(gpointer data, gint source, PurpleInputCondition cond)
 {
 	PurpleConnection *gc = NULL;
-	qq_data *qd;
 	guint8 *buf;
 	gint buf_len;
 
 	gc = (PurpleConnection *) data;
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
-	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail(gc != NULL);
 
 	if(cond != PURPLE_INPUT_READ) {
 		purple_connection_error_reason(gc,
@@ -748,14 +746,12 @@
 {
 	PurpleConnection *gc;
 	qq_data *qd;
-	PurpleAccount *account ;
 	qq_connection *conn;
 
 	gc = (PurpleConnection *) data;
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
 
 	qd = (qq_data *) gc->proto_data;
-	account = purple_connection_get_account(gc);
 
 	/* conn_data will be destoryed */
 	qd->conn_data = NULL;
--- a/libpurple/protocols/qq/qq_process.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/qq_process.c	Mon Sep 13 09:57:03 2010 +0000
@@ -58,15 +58,12 @@
 /* default process, decrypt and dump */
 static void process_unknow_cmd(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq)
 {
-	qq_data *qd;
 	gchar *msg;
 
 	g_return_if_fail(data != NULL && data_len != 0);
 
 	qq_show_packet(title, data, data_len);
 
-	qd = (qq_data *) gc->proto_data;
-
 	qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
 			data, data_len,
 			">>> [%d] %s -> [default] decrypt and dump",
@@ -80,12 +77,8 @@
 /* parse the reply to send_im */
 static void do_im_ack(guint8 *data, gint data_len, PurpleConnection *gc)
 {
-	qq_data *qd;
-
 	g_return_if_fail(data != NULL && data_len != 0);
 
-	qd = gc->proto_data;
-
 	if (data[0] != 0) {
 		purple_debug_warning("QQ", "Failed sent IM\n");
 		purple_notify_error(gc, _("Error"), _("Unable to send message."), NULL);
@@ -380,14 +373,11 @@
 /* Send ACK if the sys message needs an ACK */
 static void request_server_ack(PurpleConnection *gc, gchar *funct_str, gchar *from, guint16 seq)
 {
-	qq_data *qd;
 	guint8 *raw_data;
 	gint bytes;
 	guint8 bar;
 
 	g_return_if_fail(funct_str != NULL && from != NULL);
-	qd = (qq_data *) gc->proto_data;
-
 
 	bar = 0x1e;
 	raw_data = g_newa(guint8, strlen(funct_str) + strlen(from) + 16);
@@ -568,11 +558,9 @@
 
 void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
 {
-	qq_data *qd;
 	gint ret;
 
-	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
-	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail (gc != NULL);
 
 	switch (room_cmd) {
 		case 0:
@@ -599,12 +587,10 @@
 
 void qq_update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
 {
-	qq_data *qd;
 	gboolean is_new_turn = FALSE;
 	guint32 next_id;
 
-	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
-	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail(gc != NULL);
 
 	next_id = qq_room_get_next(gc, room_id);
 	purple_debug_info("QQ", "Update rooms, next id %u, prev id %u\n", next_id, room_id);
@@ -689,11 +675,9 @@
 
 static void update_all_rooms_online(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
 {
-	qq_data *qd;
 	guint32 next_id;
 
-	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
-	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail (gc != NULL);
 
 	next_id = qq_room_get_next_conv(gc, room_id);
 	if (next_id <= 0 && room_id <= 0) {
--- a/libpurple/protocols/qq/qq_trans.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/qq_trans.c	Mon Sep 13 09:57:03 2010 +0000
@@ -109,11 +109,9 @@
 static qq_transaction *trans_create(PurpleConnection *gc, gint fd,
 	guint16 cmd, guint16 seq, guint8 *data, gint data_len, guint32 update_class, guint32 ship32)
 {
-	qq_data *qd;
 	qq_transaction *trans;
 
-	g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL);
-	qd = (qq_data *) gc->proto_data;
+	g_return_val_if_fail(gc != NULL, NULL);
 
 	trans = g_new0(qq_transaction, 1);
 
--- a/libpurple/protocols/qq/send_file.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/qq/send_file.c	Mon Sep 13 09:57:03 2010 +0000
@@ -637,10 +637,8 @@
 {
 	PurpleConnection *gc;
 	PurpleAccount *account;
-	guint16 *seq;
 
 	g_return_if_fail (xfer != NULL);
-	seq = (guint16 *) xfer->data;
 	account = purple_xfer_get_account(xfer);
 	gc = purple_account_get_connection(account);
 
@@ -670,10 +668,8 @@
 {
 	PurpleConnection *gc;
 	PurpleAccount *account;
-	ft_info *info;
 
-	g_return_if_fail (xfer != NULL && xfer->data != NULL);
-	info = (ft_info *) xfer->data;
+	g_return_if_fail(xfer != NULL);
 	account = purple_xfer_get_account(xfer);
 	gc = purple_account_get_connection(account);
 
@@ -752,7 +748,7 @@
 	g_return_if_fail (data != NULL && data_len != 0);
 	qd = (qq_data *) gc->proto_data;
 	xfer = qd->xfer;
-	info = (ft_info *) qd->xfer->data;
+	info = (ft_info *) xfer->data;
 
 	if (data_len <= 30 + QQ_CONN_INFO_LEN) {
 		purple_debug_warning("QQ", "Received file reject message is empty\n");
@@ -761,7 +757,7 @@
 
 	bytes = 18 + 12;	/* skip 30 bytes */
 	qq_get_conn_info(info, data + bytes);
-	_qq_xfer_init_socket(qd->xfer);
+	_qq_xfer_init_socket(xfer);
 
 	_qq_xfer_init_udp_channel(info);
 	_qq_send_packet_file_notifyip(gc, sender_uid);
--- a/libpurple/protocols/sametime/sametime.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Mon Sep 13 09:57:03 2010 +0000
@@ -2133,7 +2133,7 @@
 
 
 static void ft_incoming_cancel(PurpleXfer *xfer) {
-  /* incoming transfer rejected or canceled in-progress */
+  /* incoming transfer rejected or cancelled in-progress */
   struct mwFileTransfer *ft = xfer->data;
   if(ft) mwFileTransfer_reject(ft);
 }
--- a/libpurple/protocols/silc/chat.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/silc/chat.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1395,7 +1395,7 @@
 	if (sg->roomlist)
 		purple_roomlist_unref(sg->roomlist);
 
-	sg->roomlist_canceled = FALSE;
+	sg->roomlist_cancelled = FALSE;
 
 	sg->roomlist = purple_roomlist_new(purple_connection_get_account(gc));
 	f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", "channel", TRUE);
@@ -1429,6 +1429,6 @@
 	if (sg->roomlist == list) {
 		purple_roomlist_unref(sg->roomlist);
 		sg->roomlist = NULL;
-		sg->roomlist_canceled = TRUE;
+		sg->roomlist_cancelled = TRUE;
 	}
 }
--- a/libpurple/protocols/silc/ops.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/silc/ops.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1455,7 +1455,7 @@
 			int usercount;
 			PurpleRoomlistRoom *room;
 
-			if (sg->roomlist_canceled)
+			if (sg->roomlist_cancelled)
 				break;
 
 			if (error != SILC_STATUS_OK) {
--- a/libpurple/protocols/silc/silcpurple.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/silc/silcpurple.h	Mon Sep 13 09:57:03 2010 +0000
@@ -85,7 +85,7 @@
 	SilcMimeAssembler mimeass;
 	unsigned int detaching            : 1;
 	unsigned int resuming             : 1;
-	unsigned int roomlist_canceled    : 1;
+	unsigned int roomlist_cancelled   : 1;
 	unsigned int chpk                 : 1;
 } *SilcPurple;
 
--- a/libpurple/protocols/silc10/chat.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/silc10/chat.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1417,7 +1417,7 @@
 	if (sg->roomlist)
 		purple_roomlist_unref(sg->roomlist);
 
-	sg->roomlist_canceled = FALSE;
+	sg->roomlist_cancelled = FALSE;
 
 	sg->roomlist = purple_roomlist_new(purple_connection_get_account(gc));
 	f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", "channel", TRUE);
@@ -1451,6 +1451,6 @@
 	if (sg->roomlist == list) {
 		purple_roomlist_unref(sg->roomlist);
 		sg->roomlist = NULL;
-		sg->roomlist_canceled = TRUE;
+		sg->roomlist_cancelled = TRUE;
 	}
 }
--- a/libpurple/protocols/silc10/ops.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/silc10/ops.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1444,7 +1444,7 @@
 			int usercount;
 			PurpleRoomlistRoom *room;
 
-			if (sg->roomlist_canceled)
+			if (sg->roomlist_cancelled)
 				break;
 
 			if (!success) {
--- a/libpurple/protocols/silc10/silcpurple.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/silc10/silcpurple.h	Mon Sep 13 09:57:03 2010 +0000
@@ -80,7 +80,7 @@
 #endif
 	unsigned int detaching            : 1;
 	unsigned int resuming             : 1;
-	unsigned int roomlist_canceled    : 1;
+	unsigned int roomlist_cancelled   : 1;
 	unsigned int chpk                 : 1;
 } *SilcPurple;
 
--- a/libpurple/protocols/yahoo/libymsg.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Mon Sep 13 09:57:03 2010 +0000
@@ -3906,7 +3906,6 @@
 	PurpleBuddy *buddy;
 	PurpleConnection *gc;
 
-	YahooData *yd;
 	const char *game;
 	char *game2;
 	char *t;
@@ -3917,7 +3916,6 @@
 
 	buddy = (PurpleBuddy *) node;
 	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-	yd = (YahooData *) gc->proto_data;
 
 	f = yahoo_friend_find(gc, purple_buddy_get_name(buddy));
 	if (!f)
@@ -4941,7 +4939,6 @@
 	struct yahoo_packet *pkt;
 	const char *group = NULL;
 	char *group2;
-	YahooFriend *f;
 	const char *bname;
 	const char *fed_bname;
 	YahooFederation fed = YAHOO_FEDERATION_NONE;
@@ -4953,7 +4950,6 @@
 	if (!purple_privacy_check(purple_connection_get_account(gc), bname))
 		return;
 
-	f = yahoo_friend_find(gc, bname);
 	fed = yahoo_get_federation_from_name(bname);
 	if (fed != YAHOO_FEDERATION_NONE)
 		fed_bname += 4;
@@ -5216,15 +5212,11 @@
 {
 	GHashTable *comp;
 	PurpleConnection *gc;
-	YahooData *yd;
-	int id;
 
 	if (!args || !args[0])
 		return PURPLE_CMD_RET_FAILED;
 
 	gc = purple_conversation_get_gc(conv);
-	yd = gc->proto_data;
-	id = yd->conf_id;
 	purple_debug_info("yahoo", "Trying to join %s \n", args[0]);
 
 	comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
--- a/libpurple/protocols/yahoo/util.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/yahoo/util.c	Mon Sep 13 09:57:03 2010 +0000
@@ -43,7 +43,7 @@
 	if(proxy_ssl)
 		ppi = purple_proxy_get_setup(account);
 	else
-		ppi = purple_global_proxy_get_info();
+		ppi = purple_proxy_get_setup(NULL);
 
 	type = purple_proxy_info_get_type(ppi);
 
--- a/libpurple/protocols/yahoo/yahoo_aliases.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_aliases.c	Mon Sep 13 09:57:03 2010 +0000
@@ -145,7 +145,7 @@
 					if (alias != NULL) {
 						serv_got_alias(gc, yid, alias);
 						purple_debug_info("yahoo", "Fetched alias '%s' (%s)\n", alias, id);
-					} else if (buddy_alias != NULL && strcmp(buddy_alias, "") != 0) {
+					} else if (buddy_alias && *buddy_alias && !g_str_equal(buddy_alias, yid)) {
 					/* Or if we have an alias that Yahoo doesn't, send it up */
 						yahoo_update_alias(gc, yid, buddy_alias);
 						purple_debug_info("yahoo", "Sent updated alias '%s'\n", buddy_alias);
--- a/libpurple/protocols/yahoo/yahoo_doodle.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_doodle.c	Mon Sep 13 09:57:03 2010 +0000
@@ -372,7 +372,7 @@
 
 	/* TODO Ask if user wants to save picture before the session is closed */
 
-	wb->state = DOODLE_STATE_CANCELED;
+	wb->state = DOODLE_STATE_CANCELLED;
 	purple_whiteboard_destroy(wb);
 }
 
@@ -460,7 +460,7 @@
 
 	/* g_debug_debug("yahoo", "doodle: yahoo_doodle_end()\n"); */
 
-	if (gc && wb->state != DOODLE_STATE_CANCELED)
+	if (gc && wb->state != DOODLE_STATE_CANCELLED)
 		yahoo_doodle_command_send_shutdown(gc, wb->who);
 
 	g_free(ds->imv_key);
--- a/libpurple/protocols/yahoo/yahoo_doodle.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_doodle.h	Mon Sep 13 09:57:03 2010 +0000
@@ -56,7 +56,7 @@
 #define DOODLE_STATE_REQUESTING  0
 #define DOODLE_STATE_REQUESTED   1
 #define DOODLE_STATE_ESTABLISHED 2
-#define DOODLE_STATE_CANCELED    3
+#define DOODLE_STATE_CANCELLED    3
 
 /* Doodle canvas dimensions */
 #define DOODLE_CANVAS_WIDTH  368
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1235,14 +1235,14 @@
 	PurpleXfer *xfer;
 	struct yahoo_xfer_data *xd;
 	PurpleAccount *account;
-	YahooData* yd;
+	PurpleConnection *gc;
 
 	if (!(xfer = data))
 		return;
 	if (!(xd = xfer->data))
 		return;
-	yd = xd->gc->proto_data;
-	account = purple_connection_get_account(xd->gc);
+	gc = xd->gc;
+	account = purple_connection_get_account(gc);
 	if ((source < 0) || (xd->path == NULL) || (xd->host == NULL)) {
 		purple_xfer_error(PURPLE_XFER_RECEIVE, purple_xfer_get_account(xfer),
 			xfer->who, _("Unable to connect."));
@@ -1253,7 +1253,14 @@
 	if (xd->txbuflen == 0)
 	{
 		gchar* cookies;
-		cookies = yahoo_get_cookies(xd->gc);
+		YahooData *yd = gc->proto_data;
+
+		/* cookies = yahoo_get_cookies(gc);
+		 * This doesn't seem to be working. The function is returning NULL, which yahoo servers don't like
+		 * For now let us not use this function */
+
+		cookies = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t);
+
 		if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && xd->status_15 == ACCEPTED)
 		{
 			if(xd->info_val_249 == 2)
--- a/libpurple/protocols/yahoo/yahoochat.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Mon Sep 13 09:57:03 2010 +0000
@@ -617,9 +617,6 @@
 	char *who = NULL;
 	char *room = NULL;
 	GSList *l;
-	YahooData *yd;
-
-	yd = gc->proto_data;
 
 	for (l = pkt->hash; l; l = l->next) {
 		struct yahoo_pair *pair = l->data;
@@ -638,8 +635,7 @@
 			purple_conv_chat_remove_user(PURPLE_CONV_CHAT(c), who, NULL);
 
 	}
-	if (room)
-		g_free(room);
+	g_free(room);
 }
 
 void yahoo_process_chat_message(PurpleConnection *gc, struct yahoo_packet *pkt)
--- a/libpurple/request.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/request.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1399,6 +1399,11 @@
 		handles = g_list_append(handles, info);
 
 		return info->ui_handle;
+	} else {
+		/* Fall back on the non-icon request if the UI doesn't support icon
+		 requests */
+		return purple_request_action_varg(handle, title, primary, secondary,
+			default_action, account, who, conv, user_data, action_count, actions);
 	}
 
 	return NULL;
--- a/libpurple/stun.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/stun.c	Mon Sep 13 09:57:03 2010 +0000
@@ -105,11 +105,11 @@
 }
 
 static void do_callbacks(void) {
-	while(callbacks) {
+	while (callbacks) {
 		StunCallback cb = callbacks->data;
-		if(cb)
+		if (cb)
 			cb(&nattype);
-		callbacks = g_slist_remove(callbacks, cb);
+		callbacks = g_slist_delete_link(callbacks, callbacks);
 	}
 }
 
@@ -280,7 +280,6 @@
 	GSList *hosts = data;
 	struct stun_conn *sc;
 	static struct stun_header hdr_data;
-	int ret;
 
 	if(fd < 0) {
 		nattype.status = PURPLE_STUN_STATUS_UNKNOWN;
@@ -298,15 +297,14 @@
 
 	sc->incb = purple_input_add(fd, PURPLE_INPUT_READ, reply_cb, sc);
 
-	ret = GPOINTER_TO_INT(hosts->data);
-	hosts = g_slist_remove(hosts, hosts->data);
+	hosts = g_slist_delete_link(hosts, hosts);
 	memcpy(&(sc->addr), hosts->data, sizeof(struct sockaddr_in));
 	g_free(hosts->data);
-	hosts = g_slist_remove(hosts, hosts->data);
-	while(hosts) {
-		hosts = g_slist_remove(hosts, hosts->data);
+	hosts = g_slist_delete_link(hosts, hosts);
+	while (hosts) {
+		hosts = g_slist_delete_link(hosts, hosts);
 		g_free(hosts->data);
-		hosts = g_slist_remove(hosts, hosts->data);
+		hosts = g_slist_delete_link(hosts, hosts);
 	}
 
 	hdr_data.type = htons(MSGTYPE_BINDINGREQUEST);
@@ -341,10 +339,10 @@
 	}
 
 	if (!purple_network_listen_range(12108, 12208, SOCK_DGRAM, hbn_listen_cb, hosts)) {
-		while(hosts) {
-			hosts = g_slist_remove(hosts, hosts->data);
+		while (hosts) {
+			hosts = g_slist_delete_link(hosts, hosts);
 			g_free(hosts->data);
-			hosts = g_slist_remove(hosts, hosts->data);
+			hosts = g_slist_delete_link(hosts, hosts);
 		}
 
 		nattype.status = PURPLE_STUN_STATUS_UNKNOWN;
--- a/libpurple/util.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/util.c	Mon Sep 13 09:57:03 2010 +0000
@@ -3115,7 +3115,7 @@
 		if (text[i] != thechar)
 			text[j++] = text[i];
 
-	text[j++] = '\0';
+	text[j] = '\0';
 }
 
 void
--- a/libpurple/win32/global.mak	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/win32/global.mak	Mon Sep 13 09:57:03 2010 +0000
@@ -37,7 +37,6 @@
 PURPLE_PLUGINS_TOP := $(PURPLE_TOP)/plugins
 PURPLE_PERL_TOP := $(PURPLE_PLUGINS_TOP)/perl
 PIDGIN_TOP := $(PIDGIN_TREE_TOP)/pidgin
-PIDGIN_IDLETRACK_TOP := $(PIDGIN_TOP)/win32/IdleTracker
 PIDGIN_PIXMAPS_TOP := $(PIDGIN_TOP)/pixmaps
 PIDGIN_PLUGINS_TOP := $(PIDGIN_TOP)/plugins
 PURPLE_PO_TOP := $(PIDGIN_TREE_TOP)/po
@@ -48,7 +47,6 @@
 PURPLE_CONFIG_H := $(PIDGIN_TREE_TOP)/config.h
 PIDGIN_REVISION_H := $(PIDGIN_TREE_TOP)/package_revision.h
 PIDGIN_REVISION_RAW_TXT := $(PIDGIN_TREE_TOP)/package_revision_raw.txt
-PIDGIN_IDLETRACK_DLL := $(PIDGIN_IDLETRACK_TOP)/idletrack.dll
 PURPLE_PURPLE_H := $(PURPLE_TOP)/purple.h
 PURPLE_VERSION_H := $(PURPLE_TOP)/version.h
 PURPLE_DLL := $(PURPLE_TOP)/libpurple.dll
--- a/libpurple/win32/targets.mak	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/win32/targets.mak	Mon Sep 13 09:57:03 2010 +0000
@@ -36,9 +36,6 @@
 $(PIDGIN_DLL) $(PIDGIN_DLL).a:
 	$(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) pidgin.dll
 
-$(PIDGIN_IDLETRACK_DLL) $(PIDGIN_IDLETRACK_DLL).a:
-	$(MAKE) -C $(PIDGIN_IDLETRACK_TOP) -f $(MINGW_MAKEFILE) idletrack.dll
-
 $(PIDGIN_EXE):
 	$(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) pidgin.exe
 
--- a/libpurple/win32/win32dep.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/libpurple/win32/win32dep.c	Mon Sep 13 09:57:03 2010 +0000
@@ -35,7 +35,7 @@
 static char *app_data_dir = NULL, *install_dir = NULL,
 	*lib_dir = NULL, *locale_dir = NULL;
 
-static HINSTANCE libpurpledll_hInstance = 0;
+static HINSTANCE libpurpledll_hInstance = NULL;
 
 /*
  *  PUBLIC CODE
@@ -77,16 +77,23 @@
 	BOOL did_load = FALSE;
 	FARPROC proc = 0;
 
-	if(!(hmod = GetModuleHandle(dllname))) {
+	wchar_t *wc_dllname = g_utf8_to_utf16(dllname, -1, NULL, NULL, NULL);
+
+	if(!(hmod = GetModuleHandleW(wc_dllname))) {
 		purple_debug_warning("wpurple", "%s not already loaded; loading it...\n", dllname);
-		if(!(hmod = LoadLibrary(dllname))) {
-			purple_debug_error("wpurple", "Could not load: %s\n", dllname);
+		if(!(hmod = LoadLibraryW(wc_dllname))) {
+			purple_debug_error("wpurple", "Could not load: %s (%s)\n", dllname,
+				g_win32_error_message(GetLastError()));
+			g_free(wc_dllname);
 			return NULL;
 		}
 		else
 			did_load = TRUE;
 	}
 
+	g_free(wc_dllname);
+	wc_dllname = NULL;
+
 	if((proc = GetProcAddress(hmod, procedure))) {
 		purple_debug_info("wpurple", "This version of %s contains %s\n",
 			dllname, procedure);
@@ -124,7 +131,7 @@
 	if (!initialized) {
 		char *tmp = NULL;
 		wchar_t winstall_dir[MAXPATHLEN];
-		if (GetModuleFileNameW(NULL, winstall_dir,
+		if (GetModuleFileNameW(libpurpledll_hInstance, winstall_dir,
 				MAXPATHLEN) > 0) {
 			tmp = g_utf16_to_utf8(winstall_dir, -1,
 				NULL, NULL, NULL);
--- a/pidgin.spec.in	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin.spec.in	Mon Sep 13 09:57:03 2010 +0000
@@ -46,12 +46,14 @@
 %if "%{_vendor}" == "suse"
 # For SuSE:
 BuildRequires: gnutls-devel
+%define sslopts "--enable-gnutls=yes --enable-nss=no"
 %{?_with_dbus:BuildRequires: dbus-1-devel >= 0.35}
 %{!?_without_gstreamer:BuildRequires: gstreamer010-devel >= 0.10}
 Requires(pre): gconf2
 Requires(post): gconf2
 Requires(preun): gconf2
 %else
+%define sslopts "--enable-gnutls=no --enable-nss=yes"
 %{?_with_dbus:BuildRequires: dbus-devel >= 0.35}
 %{!?_without_gstreamer:BuildRequires: gstreamer-devel >= 0.10}
 Requires(pre): GConf2
@@ -230,6 +232,7 @@
                                     --mandir=%{_mandir} \
                                     --sysconfdir=%{_sysconfdir} \
                                     --disable-schemas-install \
+                                    %{sslopts} \
                                     %{!?_with_vv:--disable-vv} \
                                     %{!?_with_dbus:--disable-dbus} \
                                     %{!?_with_avahi:--disable-avahi} \
@@ -471,6 +474,9 @@
 %endif
 
 %changelog
+* Wed Sep 01 2010 Stu Tomlinson <stu@nosnilmot.com>
+- Ensure predictable use of SSL libs
+
 * Wed Jun 02 2010 Stu Tomlinson <stu@nosnilmot.com>
 - add an option to build RPMs using --enable-trayicon-compat
   (--with trayiconcompat)
--- a/pidgin/Makefile.am	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/Makefile.am	Mon Sep 13 09:57:03 2010 +0000
@@ -5,9 +5,6 @@
 		Makefile.mingw \
 		pidgin.pc.in \
 		pidgin-uninstalled.pc.in \
-		win32/IdleTracker/Makefile.mingw \
-		win32/IdleTracker/idletrack.c \
-		win32/IdleTracker/idletrack.h \
 		win32/MinimizeToTray.h \
 		win32/MinimizeToTray.c \
 		win32/pidgin_dll_rc.rc.in \
--- a/pidgin/Makefile.mingw	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/Makefile.mingw	Mon Sep 13 09:57:03 2010 +0000
@@ -33,7 +33,6 @@
 
 INCLUDE_PATHS +=	\
 			$(PURPLE_INCLUDE_PATHS) \
-			-I$(PIDGIN_IDLETRACK_TOP) \
 			-I$(PIDGIN_TOP) \
 			-I$(PIDGIN_TOP)/win32 \
 			-I$(GTK_TOP)/include/gtk-2.0 \
@@ -45,8 +44,7 @@
 
 LIB_PATHS +=		-L$(GTK_TOP)/lib \
 			-L$(PURPLE_TOP) \
-			-L$(PIDGIN_TOP) \
-			-L$(PIDGIN_IDLETRACK_TOP)
+			-L$(PIDGIN_TOP)
 
 ##
 ##  SOURCES, OBJECTS
@@ -121,7 +119,6 @@
 		-lgthread-2.0 \
 		-lpurple \
 		-lz \
-		-lidletrack \
 		-lgtk-win32-2.0 \
 		-latk-1.0 \
 		-lpango-1.0 \
@@ -151,7 +148,6 @@
 install: install_shallow all
 	$(MAKE) -C $(PIDGIN_PLUGINS_TOP) -f $(MINGW_MAKEFILE) install
 	$(MAKE) -C $(PIDGIN_PIXMAPS_TOP) -f $(MINGW_MAKEFILE) install
-	$(MAKE) -C $(PIDGIN_IDLETRACK_TOP) -f $(MINGW_MAKEFILE) install
 
 win32/pidgin_dll_rc.rc: win32/pidgin_dll_rc.rc.in $(PIDGIN_TREE_TOP)/VERSION
 	sed -e 's/@PIDGIN_VERSION@/$(PIDGIN_VERSION)/g' \
@@ -159,7 +155,7 @@
 
 $(EXE_OBJECTS) $(PIDGIN_OBJECTS): $(PIDGIN_CONFIG_H)
 
-$(PIDGIN_TARGET).dll $(PIDGIN_TARGET).dll.a: $(PURPLE_DLL).a $(PIDGIN_IDLETRACK_DLL).a $(PIDGIN_OBJECTS)
+$(PIDGIN_TARGET).dll $(PIDGIN_TARGET).dll.a: $(PURPLE_DLL).a $(PIDGIN_OBJECTS)
 	$(CC) -shared $(PIDGIN_OBJECTS) $(LIB_PATHS) $(PIDGIN_LIBS) $(DLL_LD_FLAGS) -Wl,--output-def,$(PIDGIN_TARGET).def,--out-implib,$(PIDGIN_TARGET).dll.a -o $(PIDGIN_TARGET).dll
 
 $(EXE_TARGET).exe: $(PIDGIN_CONFIG_H) $(PIDGIN_DLL).a $(EXE_OBJECTS) $(PIDGIN_TARGET).dll
@@ -169,7 +165,6 @@
 ## CLEAN RULES
 ##
 clean:
-	$(MAKE) -C $(PIDGIN_IDLETRACK_TOP) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(PIDGIN_PLUGINS_TOP) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(PIDGIN_PIXMAPS_TOP) -f $(MINGW_MAKEFILE) clean
 	rm -f $(PIDGIN_OBJECTS) $(PIDGIN_RC_SRC) $(EXE_OBJECTS) $(EXE_RC_SRC)
--- a/pidgin/gtkblist.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkblist.c	Mon Sep 13 09:57:03 2010 +0000
@@ -3653,6 +3653,9 @@
  ***************************************************/
 static GtkItemFactoryEntry blist_menu[] =
 {
+/* NOTE: Do not set any accelerator to Control+O. It is mapped by 
+   gtk_blist_key_press_cb to "Get User Info" on the selected buddy. */
+
 	/* Buddies menu */
 	{ N_("/_Buddies"), NULL, NULL, 0, "<Branch>", NULL },
 	{ N_("/Buddies/New Instant _Message..."), "<CTL>M", pidgin_dialogs_im, 0, "<StockItem>", PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW },
@@ -3686,7 +3689,7 @@
 	{ N_("/Tools/Plu_gins"), "<CTL>U", pidgin_plugin_dialog_show, 2, "<StockItem>", PIDGIN_STOCK_TOOLBAR_PLUGINS },
 	{ N_("/Tools/Pr_eferences"), "<CTL>P", pidgin_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES },
 	{ N_("/Tools/Pr_ivacy"), NULL, pidgin_privacy_dialog_show, 0, "<Item>", NULL },
-	{ N_("/Tools/Set _Mood"), "<CTL>O", set_mood_show, 0, "<Item>", NULL },
+	{ N_("/Tools/Set _Mood"), "<CTL>D", set_mood_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/R_oom List"), NULL, pidgin_roomlist_dialog_show, 0, "<Item>", NULL },
@@ -3965,7 +3968,6 @@
 			                                 tmp);
 			g_free(tmp);
 		}
-		count = 0;
 
 		count = purple_blist_get_group_size(group, FALSE);
 		if (count != 0) {
@@ -3976,7 +3978,6 @@
 			                                 tmp);
 			g_free(tmp);
 		}
-		count = 0;
 
 		tmp = purple_notify_user_info_get_text_with_newline(user_info, "\n");
 		g_string_append(str, tmp);
@@ -4023,7 +4024,6 @@
 {
 	PurpleBuddy *buddy = NULL;
 	struct _pidgin_blist_node *gtknode = node->ui_data;
-	struct _pidgin_blist_node *gtkbuddynode = NULL;
 	PurplePlugin *prpl;
 	PurplePluginProtocolInfo *prpl_info;
 	const char *name = NULL;
@@ -4034,11 +4034,9 @@
 	if(PURPLE_BLIST_NODE_IS_CONTACT(node)) {
 		if(!gtknode->contact_expanded) {
 			buddy = purple_contact_get_priority_buddy((PurpleContact*)node);
-			gtkbuddynode = ((PurpleBlistNode*)buddy)->ui_data;
 		}
 	} else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
 		buddy = (PurpleBuddy*)node;
-		gtkbuddynode = node->ui_data;
 		p = purple_buddy_get_presence(buddy);
 		if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) {
 			/* This emblem comes from the small emoticon set now,
@@ -4131,7 +4129,6 @@
 pidgin_blist_get_status_icon(PurpleBlistNode *node, PidginStatusIconSize size)
 {
 	GdkPixbuf *ret;
-	const char *protoname = NULL;
 	const char *icon = NULL;
 	struct _pidgin_blist_node *gtknode = node->ui_data;
 	struct _pidgin_blist_node *gtkbuddynode = NULL;
@@ -4158,7 +4155,6 @@
 	if(buddy || chat) {
 		PurpleAccount *account;
 		PurplePlugin *prpl;
-		PurplePluginProtocolInfo *prpl_info;
 
 		if(buddy)
 			account = buddy->account;
@@ -4168,12 +4164,6 @@
 		prpl = purple_find_prpl(purple_account_get_protocol_id(account));
 		if(!prpl)
 			return NULL;
-
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-
-		if(prpl_info && prpl_info->list_icon) {
-			protoname = prpl_info->list_icon(account, buddy);
-		}
 	}
 
 	if(buddy) {
--- a/pidgin/gtkconv.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkconv.c	Mon Sep 13 09:57:03 2010 +0000
@@ -750,9 +750,9 @@
 do_invite(GtkWidget *w, int resp, InviteBuddyInfo *info)
 {
 	const char *buddy, *message;
-	PidginConversation *gtkconv;
-
-	gtkconv = PIDGIN_CONVERSATION(info->conv);
+	PurpleConversation *conv;
+
+	conv = info->conv;
 
 	if (resp == GTK_RESPONSE_OK) {
 		buddy   = gtk_entry_get_text(GTK_ENTRY(info->entry));
@@ -761,8 +761,8 @@
 		if (!g_ascii_strcasecmp(buddy, ""))
 			return;
 
-		serv_chat_invite(purple_conversation_get_gc(info->conv),
-						 purple_conv_chat_get_id(PURPLE_CONV_CHAT(info->conv)),
+		serv_chat_invite(purple_conversation_get_gc(conv),
+						 purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)),
 						 message, buddy);
 	}
 
@@ -856,7 +856,6 @@
 	InviteBuddyInfo *info = NULL;
 
 	if (invite_dialog == NULL) {
-		PurpleConnection *gc;
 		PidginWindow *gtkwin;
 		GtkWidget *label;
 		GtkWidget *vbox, *hbox;
@@ -869,7 +868,6 @@
 		info = g_new0(InviteBuddyInfo, 1);
 		info->conv = conv;
 
-		gc        = purple_conversation_get_gc(conv);
 		gtkwin    = pidgin_conv_get_window(gtkconv);
 
 		/* Create the new dialog. */
@@ -1200,12 +1198,10 @@
 menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget)
 {
 	PidginWindow *win = data;
-	PurpleConversation *conv;
 	PidginConversation *gtkconv;
 	GtkIMHtmlToolbar *toolbar;
 
 	gtkconv = pidgin_conv_window_get_active_gtkconv(win);
-	conv    = gtkconv->active_conv;
 	toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar);
 
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image),
@@ -1911,10 +1907,8 @@
 conv_keypress_common(PidginConversation *gtkconv, GdkEventKey *event)
 {
 	PidginWindow *win;
-	PurpleConversation *conv;
 	int curconv;
 
-	conv     = gtkconv->active_conv;
 	win      = gtkconv->win;
 	curconv = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook));
 
@@ -2009,13 +2003,11 @@
 static gboolean
 entry_key_press_cb(GtkWidget *entry, GdkEventKey *event, gpointer data)
 {
-	PidginWindow *win;
 	PurpleConversation *conv;
 	PidginConversation *gtkconv;
 
 	gtkconv  = (PidginConversation *)data;
 	conv     = gtkconv->active_conv;
-	win      = gtkconv->win;
 
 	if (conv_keypress_common(gtkconv, event))
 		return TRUE;
@@ -2350,12 +2342,9 @@
 			   gchar *new_text, gint new_text_length, gpointer user_data)
 {
 	PidginConversation *gtkconv = (PidginConversation *)user_data;
-	PurpleConversation *conv;
 
 	g_return_if_fail(gtkconv != NULL);
 
-	conv = gtkconv->active_conv;
-
 	if (!purple_prefs_get_bool("/purple/conversations/im/send_typing"))
 		return;
 
@@ -2617,7 +2606,6 @@
 	PidginConversation *gtkconv = (PidginConversation *)data;
 	PurpleConversation *conv = gtkconv->active_conv;
 	PurpleAccount *account;
-	PurplePluginProtocolInfo *prpl_info = NULL;
 
 	GdkPixbuf *buf;
 	GdkPixbuf *scale;
@@ -2628,9 +2616,7 @@
 	gtkconv = PIDGIN_CONVERSATION(conv);
 	account = purple_conversation_get_account(conv);
 
-	if(account && account->gc) {
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl);
-	} else {
+	if (!(account && account->gc)) {
 		gtkconv->u.im->icon_timer = 0;
 		return FALSE;
 	}
@@ -2702,7 +2688,6 @@
 	GList *children;
 	GtkWidget *event;
 	PurpleConversation *conv = gtkconv->active_conv;
-	PidginWindow *gtkwin;
 
 	g_return_if_fail(conv != NULL);
 
@@ -2730,8 +2715,6 @@
 	gtkconv->u.im->anim = NULL;
 	gtkconv->u.im->iter = NULL;
 	gtkconv->u.im->show_icon = FALSE;
-
-	gtkwin = gtkconv->win;
 }
 
 static void
@@ -3684,13 +3667,10 @@
 static void
 update_typing_icon(PidginConversation *gtkconv)
 {
-	PidginWindow *gtkwin;
 	PurpleConvIm *im = NULL;
 	PurpleConversation *conv = gtkconv->active_conv;
 	char *message = NULL;
 
-	gtkwin = gtkconv->win;
-
 	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
 		im = PURPLE_CONV_IM(conv);
 
@@ -5740,10 +5720,8 @@
 						time_t mtime)
 {
 	PidginConversation *gtkconv;
-	PidginWindow *win;
 	PurpleConnection *gc;
 	PurpleAccount *account;
-	PurplePluginProtocolInfo *prpl_info;
 	int gtk_font_options = 0;
 	int gtk_font_options_all = 0;
 	int max_scrollback_lines;
@@ -5830,9 +5808,6 @@
 		g_free(tmp);
 	}
 
-	win = gtkconv->win;
-	prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL;
-
 	line_count = gtk_text_buffer_get_line_count(
 			gtk_text_view_get_buffer(GTK_TEXT_VIEW(
 				gtkconv->imhtml)));
@@ -6263,7 +6238,6 @@
 pidgin_conv_chat_update_user(PurpleConversation *conv, const char *user)
 {
 	PurpleConvChat *chat;
-	PurpleConvChatBuddyFlags flags;
 	PurpleConvChatBuddy *cbuddy;
 	PidginConversation *gtkconv;
 	PidginChatPane *gtkchat;
@@ -6306,8 +6280,6 @@
 
 	g_return_if_fail(alias != NULL);
 
-	flags = purple_conv_chat_user_get_flags(chat, user);
-
 	cbuddy = purple_conv_chat_cb_find(chat, user);
 	if (cbuddy)
 		add_chat_buddy_common(conv, cbuddy, NULL);
@@ -6729,7 +6701,6 @@
 		PurpleConvIm *im = NULL;
 		PurpleAccount *account = purple_conversation_get_account(conv);
 	 	PurpleBuddy *buddy = NULL;
-		PurplePresence *p = NULL;
 		char *markup = NULL;
 		AtkObject *accessibility_obj;
 		/* I think this is a little longer than it needs to be but I'm lazy. */
@@ -6749,7 +6720,6 @@
 		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
 			buddy = purple_find_buddy(account, conv->name);
 			if (buddy) {
-				p = purple_buddy_get_presence(buddy);
 				markup = pidgin_blist_get_name_markup(buddy, FALSE, FALSE);
 			} else {
 				markup = title;
@@ -6964,7 +6934,6 @@
 	int size = 0;
 
 	PurpleAccount *account;
-	PurplePluginProtocolInfo *prpl_info = NULL;
 
 	PurpleBuddyIcon *icon;
 
@@ -6981,8 +6950,6 @@
 		return;
 
 	account = purple_conversation_get_account(conv);
-	if(account && account->gc)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl);
 
 	/* Remove the current icon stuff */
 	children = gtk_container_get_children(GTK_CONTAINER(gtkconv->u.im->icon_container));
@@ -8627,7 +8594,7 @@
 static gboolean
 notebook_press_cb(GtkWidget *widget, GdkEventButton *e, PidginWindow *win)
 {
-	gint nb_x, nb_y, x_rel, y_rel;
+	gint nb_x, nb_y;
 	int tab_clicked;
 	GtkWidget *page;
 	GtkWidget *tab;
@@ -8670,9 +8637,6 @@
 	*/
 	gdk_window_get_origin(win->notebook->window, &nb_x, &nb_y);
 
-	x_rel = e->x_root - nb_x;
-	y_rel = e->y_root - nb_y;
-
 	/* Reset the min/max x/y */
 	win->drag_min_x = 0;
 	win->drag_min_y = 0;
@@ -9239,6 +9203,7 @@
 	if (win && win->window &&
 			!GTK_WIDGET_VISIBLE(win->window) && conv_width != 0) {
 
+#ifdef _WIN32  /* only override window manager placement on Windows */
 		/* ...check position is on screen... */
 		if (conv_x >= gdk_screen_width())
 			conv_x = gdk_screen_width() - 100;
@@ -9251,7 +9216,6 @@
 			conv_y = 100;
 
 		/* ...and move it back. */
-#ifdef _WIN32  /* only override window manager placement on Windows */
 		gtk_window_move(GTK_WINDOW(win->window), conv_x, conv_y);
 #endif
 		gtk_window_resize(GTK_WINDOW(win->window), conv_width, conv_height);
@@ -9503,7 +9467,7 @@
 
 	gtk_widget_show(gtkconv->menu_tabby);
 
-	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
+	if (conv_type == PURPLE_CONV_TYPE_IM)
 		pidgin_conv_update_buddy_icon(conv);
 
 	/* Build and set conversations tab */
@@ -9630,9 +9594,7 @@
 pidgin_conv_window_remove_gtkconv(PidginWindow *win, PidginConversation *gtkconv)
 {
 	unsigned int index;
-	PurpleConversationType conv_type;
-
-	conv_type = purple_conversation_get_type(gtkconv->active_conv);
+
 	index = gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont);
 
 	g_object_ref(gtkconv->tab_cont);
@@ -9965,12 +9927,9 @@
 static void
 conv_placement_by_group(PidginConversation *conv)
 {
-	PurpleConversationType type;
 	PurpleGroup *group = NULL;
 	GList *wl, *cl;
 
-	type = purple_conversation_get_type(conv->active_conv);
-
 	group = conv_get_group(conv);
 
 	/* Go through the list of IMs and find one with this group. */
@@ -10004,12 +9963,10 @@
 static void
 conv_placement_by_account(PidginConversation *conv)
 {
-	PurpleConversationType type;
 	GList *wins, *convs;
 	PurpleAccount *account;
 
 	account = purple_conversation_get_account(conv->active_conv);
-	type = purple_conversation_get_type(conv->active_conv);
 
 	/* Go through the list of IMs and find one with this group. */
 	for (wins = pidgin_conv_windows_get_list(); wins != NULL; wins = wins->next) {
--- a/pidgin/gtkdialogs.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkdialogs.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1288,7 +1288,7 @@
 
 	purple_debug_info("blist", "Removing '%s' from buddy list.\n", buddy->name);
 	/* TODO - Should remove from blist first... then call purple_account_remove_buddy()? */
-	purple_account_remove_buddy(buddy->account, buddy, group);
+	purple_account_remove_buddy(account, buddy, group);
 	purple_blist_remove_buddy(buddy);
 
 	g_free(name);
--- a/pidgin/gtkft.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkft.c	Mon Sep 13 09:57:03 2010 +0000
@@ -112,13 +112,10 @@
 get_xfer_info_strings(PurpleXfer *xfer, char **kbsec, char **time_elapsed,
 					  char **time_remaining)
 {
-	PidginXferUiData *data;
 	double kb_sent, kb_rem;
 	double kbps = 0.0;
 	time_t elapsed, now;
 
-	data = PIDGINXFER(xfer);
-
 	if (xfer->end_time != 0)
 		now = xfer->end_time;
 	else
@@ -159,7 +156,7 @@
 			*time_remaining = g_strdup(_("Finished"));
 		}
 		else if (purple_xfer_is_canceled(xfer)) {
-			*time_remaining = g_strdup(_("Canceled"));
+			*time_remaining = g_strdup(_("Cancelled"));
 		}
 		else if (purple_xfer_get_size(xfer) == 0 || (kb_sent > 0 && kbps == 0)) {
 			*time_remaining = g_strdup(_("Unknown"));
@@ -995,7 +992,7 @@
 									GTK_ICON_SIZE_MENU, NULL);
 
 	if (purple_xfer_is_canceled(xfer))
-		status = _("Canceled");
+		status = _("Cancelled");
 	else
 		status = _("Failed");
 
@@ -1015,7 +1012,6 @@
 {
 	PidginXferUiData *data;
 	char *size_str, *remaining_str;
-	GtkTreeSelection *selection;
 	time_t current_time;
 	GtkTreeIter iter;
 	gboolean valid;
@@ -1066,8 +1062,6 @@
 		g_object_unref(pixbuf);
 	}
 
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(xfer_dialog->tree));
-
 	update_title_progress(dialog);
 	if (xfer == dialog->selected_xfer)
 		update_detailed_info(xfer_dialog, xfer);
--- a/pidgin/gtkft.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkft.h	Mon Sep 13 09:57:03 2010 +0000
@@ -88,10 +88,10 @@
 									 PurpleXfer *xfer);
 
 /**
- * Indicate in a file transfer dialog that a transfer was canceled.
+ * Indicate in a file transfer dialog that a transfer was cancelled.
  *
  * @param dialog The file transfer dialog.
- * @param xfer   The file transfer that was canceled.
+ * @param xfer   The file transfer that was cancelled.
  */
 void pidgin_xfer_dialog_cancel_xfer(PidginXferDialog *dialog,
 									 PurpleXfer *xfer);
--- a/pidgin/gtkidle.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkidle.c	Mon Sep 13 09:57:03 2010 +0000
@@ -29,7 +29,7 @@
 #else
 # ifdef USE_SCREENSAVER
 #  ifdef _WIN32
-#   include "idletrack.h"
+#   include "gtkwin32dep.h"
 #  else
     /* We're on X11 and not MacOS X with IOKit. */
 #   include <X11/Xlib.h>
--- a/pidgin/gtkimhtml.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkimhtml.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1476,10 +1476,8 @@
 static void gtk_imhtml_class_init (GtkIMHtmlClass *klass)
 {
 	GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
-	GtkObjectClass *object_class;
 	GtkBindingSet *binding_set;
 	GObjectClass   *gobject_class;
-	object_class = (GtkObjectClass*) klass;
 	gobject_class = (GObjectClass*) klass;
 	parent_class = g_type_class_ref(GTK_TYPE_TEXT_VIEW);
 	signals[URL_CLICKED] = g_signal_new("url_clicked",
--- a/pidgin/gtkimhtmltoolbar.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkimhtmltoolbar.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1205,9 +1205,7 @@
 /* Boring GTK+ stuff */
 static void gtk_imhtmltoolbar_class_init (GtkIMHtmlToolbarClass *class)
 {
-	GtkObjectClass *object_class;
 	GObjectClass   *gobject_class;
-	object_class = (GtkObjectClass*) class;
 	gobject_class = (GObjectClass*) class;
 	parent_class = g_type_class_ref(GTK_TYPE_HBOX);
 	gobject_class->finalize = gtk_imhtmltoolbar_finalize;
--- a/pidgin/gtkplugin.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkplugin.c	Mon Sep 13 09:57:03 2010 +0000
@@ -800,5 +800,8 @@
 	g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (prefs_plugin_sel), NULL);
 	g_signal_connect(G_OBJECT(plugin_dialog), "response", G_CALLBACK(plugin_dialog_response_cb), sel);
 	gtk_window_set_default_size(GTK_WINDOW(plugin_dialog), 430, 530);
+
+	pidgin_auto_parent_window(plugin_dialog);
+
 	gtk_widget_show_all(plugin_dialog);
 }
--- a/pidgin/gtkpounce.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkpounce.c	Mon Sep 13 09:57:03 2010 +0000
@@ -194,7 +194,6 @@
 {
 	GtkTreeIter iter;
 	PurpleAccount *account;
-	PurplePounceEvent events;
 	gboolean recurring;
 	const char *pouncer;
 	const char *pouncee;
@@ -202,8 +201,6 @@
 
 	account = purple_pounce_get_pouncer(pounce);
 
-	events = purple_pounce_get_events(pounce);
-
 	pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM);
 
 	pouncer = purple_account_get_username(account);
--- a/pidgin/gtkprefs.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkprefs.c	Mon Sep 13 09:57:03 2010 +0000
@@ -1042,11 +1042,40 @@
 }
 
 static GtkWidget *
+add_theme_prefs_combo(GtkWidget *vbox,
+                      GtkSizeGroup *combo_sg, GtkSizeGroup *label_sg,
+                      GtkListStore *theme_store,
+                      GCallback combo_box_cb, gpointer combo_box_cb_user_data, 
+                      const char *label_str, const char *prefs_path,
+                      const char *theme_type)
+{
+	GtkWidget *label;
+	GtkWidget *combo_box = NULL;
+	GtkWidget *themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+
+	label = gtk_label_new(label_str);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+	gtk_size_group_add_widget(label_sg, label);
+	gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0);
+
+	combo_box = prefs_build_theme_combo_box(theme_store,
+						purple_prefs_get_string(prefs_path),
+						theme_type);
+	g_signal_connect(G_OBJECT(combo_box), "changed",
+						(GCallback)combo_box_cb, combo_box_cb_user_data);
+	gtk_size_group_add_widget(combo_sg, combo_box);
+	gtk_box_pack_start(GTK_BOX(themesel_hbox), combo_box, TRUE, TRUE, 0);
+
+	gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0);
+
+	return combo_box;
+}
+
+static GtkWidget *
 theme_page(void)
 {
+	GtkWidget *label;
 	GtkWidget *ret, *vbox;
-	GtkWidget *label;
-	GtkWidget *themesel_hbox;
 	GtkSizeGroup *label_sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 	GtkSizeGroup *combo_sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
@@ -1067,76 +1096,28 @@
 	gtk_widget_show(label);
 
 	/* Buddy List Themes */
-	themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-
-	label = gtk_label_new(_("Buddy List Theme:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_size_group_add_widget(label_sg, label);
-	gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0);
-
-	prefs_blist_themes_combo_box = prefs_build_theme_combo_box(prefs_blist_themes,
-						purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"),
-						"blist");
-	g_signal_connect(G_OBJECT(prefs_blist_themes_combo_box), "changed",
-						(GCallback)prefs_set_blist_theme_cb, NULL);
-	gtk_size_group_add_widget(combo_sg, prefs_blist_themes_combo_box);
-	gtk_box_pack_start(GTK_BOX(themesel_hbox), prefs_blist_themes_combo_box, TRUE, TRUE, 0);
-
-	gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0);
+	prefs_blist_themes_combo_box = add_theme_prefs_combo(
+		vbox, combo_sg, label_sg, prefs_blist_themes,
+		(GCallback)prefs_set_blist_theme_cb, NULL, 
+		_("Buddy List Theme:"), PIDGIN_PREFS_ROOT "/blist/theme", "blist");
 
 	/* Status Icon Themes */
-	themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-
-	label = gtk_label_new(_("Status Icon Theme:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_size_group_add_widget(label_sg, label);
-	gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0);
-
-	prefs_status_themes_combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes,
-						purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"),
-						"icon");
-	g_signal_connect(G_OBJECT(prefs_status_themes_combo_box), "changed",
-						(GCallback)prefs_set_status_icon_theme_cb, NULL);
-	gtk_size_group_add_widget(combo_sg, prefs_status_themes_combo_box);
-	gtk_box_pack_start(GTK_BOX(themesel_hbox), prefs_status_themes_combo_box, TRUE, TRUE, 0);
-
-	gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0);
+	prefs_status_themes_combo_box = add_theme_prefs_combo(
+		vbox, combo_sg, label_sg, prefs_status_icon_themes,
+		(GCallback)prefs_set_status_icon_theme_cb, NULL,
+		_("Status Icon Theme:"), PIDGIN_PREFS_ROOT "/status/icon-theme", "icon");
 
 	/* Sound Themes */
-	themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-
-	label = gtk_label_new(_("Sound Theme:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_size_group_add_widget(label_sg, label);
-	gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0);
-
-	prefs_sound_themes_combo_box = prefs_build_theme_combo_box(prefs_sound_themes,
-						purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"),
-						"sound");
-	g_signal_connect(G_OBJECT(prefs_sound_themes_combo_box), "changed",
-						(GCallback)prefs_set_sound_theme_cb, NULL);
-	gtk_size_group_add_widget(combo_sg, prefs_sound_themes_combo_box);
-	gtk_box_pack_start(GTK_BOX(themesel_hbox), prefs_sound_themes_combo_box, TRUE, TRUE, 0);
-
-	gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0);
+	prefs_sound_themes_combo_box = add_theme_prefs_combo(
+		vbox, combo_sg, label_sg, prefs_sound_themes,
+		(GCallback)prefs_set_sound_theme_cb, NULL,
+		_("Sound Theme:"), PIDGIN_PREFS_ROOT "/sound/theme", "sound");
 
 	/* Smiley Themes */
-	themesel_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-
-	label = gtk_label_new(_("Smiley Theme:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_size_group_add_widget(label_sg, label);
-	gtk_box_pack_start(GTK_BOX(themesel_hbox), label, FALSE, FALSE, 0);
-
-	prefs_smiley_themes_combo_box = prefs_build_theme_combo_box(prefs_smiley_themes,
-						purple_prefs_get_string(PIDGIN_PREFS_ROOT "/smileys/theme"),
-						"smiley");
-	g_signal_connect(G_OBJECT(prefs_smiley_themes_combo_box), "changed",
-						(GCallback)prefs_set_smiley_theme_cb, NULL);
-	gtk_size_group_add_widget(combo_sg, prefs_smiley_themes_combo_box);
-	gtk_box_pack_start(GTK_BOX(themesel_hbox), prefs_smiley_themes_combo_box, TRUE, TRUE, 0);
-
-	gtk_box_pack_start(GTK_BOX(vbox), themesel_hbox, FALSE, FALSE, 0);
+	prefs_smiley_themes_combo_box = add_theme_prefs_combo(
+		vbox, combo_sg, label_sg, prefs_smiley_themes,
+		(GCallback)prefs_set_smiley_theme_cb, NULL,
+		_("Smiley Theme:"), PIDGIN_PREFS_ROOT "/smileys/theme", "smiley");
 
 	/* Custom sort so "none" theme is at top of list */
 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(prefs_smiley_themes),
@@ -1809,9 +1790,10 @@
 
 	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_TURN server:"),
 			sg, entry, TRUE, NULL);
-
-	pidgin_prefs_labeled_spin_button(hbox, _("_Port:"),
+	
+	pidgin_prefs_labeled_spin_button(hbox, _("_UDP Port:"),
 		"/purple/network/turn_port", 0, 65535, NULL);
+
 	hbox = pidgin_prefs_labeled_entry(vbox, _("Use_rname:"),
 		"/purple/network/turn_username", sg);
 	pidgin_prefs_labeled_password(hbox, _("Pass_word:"),
--- a/pidgin/gtkroomlist.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkroomlist.c	Mon Sep 13 09:57:03 2010 +0000
@@ -362,8 +362,6 @@
 
 	style = grl->tipwindow->style;
 
-	max_text_width = 0;
-
 	max_text_width = MAX(grl->tip_width, grl->tip_name_width);
 	max_width = TOOLTIP_BORDER + SMALL_SPACE + max_text_width + TOOLTIP_BORDER;
 
--- a/pidgin/gtksession.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtksession.c	Mon Sep 13 09:57:03 2010 +0000
@@ -166,7 +166,7 @@
 	ret[j++] = g_strdup("--display");
 	ret[j++] = g_strdup((gchar *)gdk_display_get_name(gdk_display_get_default()));
 
-	ret[j++] = NULL;
+	ret[j] = NULL;
 
 	return ret;
 }
--- a/pidgin/gtksmiley.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtksmiley.c	Mon Sep 13 09:57:03 2010 +0000
@@ -520,9 +520,6 @@
 		GtkTreeIter *iter, gpointer data)
 {
 	PurpleSmiley *smiley = NULL;
-	SmileyManager *dialog;
-
-	dialog = (SmileyManager*)data;
 
 	gtk_tree_model_get(model, iter,
 			SMILEY, &smiley,
--- a/pidgin/gtkstatusbox.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkstatusbox.c	Mon Sep 13 09:57:03 2010 +0000
@@ -657,7 +657,6 @@
 static void
 pidgin_status_box_refresh(PidginStatusBox *status_box)
 {
-	GtkIconSize icon_size;
 	GtkStyle *style;
 	char aa_color[8];
 	PurpleSavedStatus *saved_status;
@@ -668,8 +667,6 @@
 	gboolean account_status = FALSE;
 	PurpleAccount *acct = (status_box->account) ? status_box->account : status_box->token_status_account;
 
-	icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
-
 	style = gtk_widget_get_style(GTK_WIDGET(status_box));
 	snprintf(aa_color, sizeof(aa_color), "#%02x%02x%02x",
 		 style->text_aa[GTK_STATE_NORMAL].red >> 8,
@@ -969,11 +966,7 @@
 		PurpleSavedStatus *saved = cur->data;
 		const gchar *message;
 		gchar *stripped = NULL;
-		PurpleStatusPrimitive prim;
-		PidginStatusBoxItemType type = PIDGIN_STATUS_BOX_TYPE_POPULAR;
-
-		/* Get an appropriate status icon */
-		prim = purple_savedstatus_get_type(saved);
+		PidginStatusBoxItemType type;
 
 		if (purple_savedstatus_is_transient(saved))
 		{
@@ -982,16 +975,18 @@
 			 * API returns the message when purple_savedstatus_get_title() is
 			 * called, so we don't need to get the message a second time.
 			 */
+			type = PIDGIN_STATUS_BOX_TYPE_POPULAR;
 		}
 		else
 		{
+			type = PIDGIN_STATUS_BOX_TYPE_SAVED_POPULAR;
+
 			message = purple_savedstatus_get_message(saved);
 			if (message != NULL)
 			{
 				stripped = purple_markup_strip_html(message);
 				purple_util_chrreplace(stripped, '\n', ' ');
 			}
-			type = PIDGIN_STATUS_BOX_TYPE_SAVED_POPULAR;
 		}
 
 		pidgin_status_box_add(statusbox, type,
@@ -1074,17 +1069,13 @@
 					PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, NULL,
 					purple_status_type_get_name(status_type),
 					NULL,
-					GINT_TO_POINTER(purple_status_type_get_primitive(status_type)));
+					GINT_TO_POINTER(prim));
 	}
 }
 
 static void
 pidgin_status_box_regenerate(PidginStatusBox *status_box, gboolean status_changed)
 {
-	GtkIconSize icon_size;
-
-	icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
-
 	/* Unset the model while clearing it */
 	gtk_tree_view_set_model(GTK_TREE_VIEW(status_box->tree_view), NULL);
 	gtk_list_store_clear(status_box->dropdown_store);
--- a/pidgin/gtkutils.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/gtkutils.c	Mon Sep 13 09:57:03 2010 +0000
@@ -680,7 +680,6 @@
 create_protocols_menu(const char *default_proto_id)
 {
 	AopMenu *aop_menu = NULL;
-	PurplePluginProtocolInfo *prpl_info;
 	PurplePlugin *plugin;
 	GdkPixbuf *pixbuf = NULL;
 	GtkSizeGroup *sg;
@@ -702,7 +701,6 @@
 		 p = p->next, i++) {
 
 		plugin = (PurplePlugin *)p->data;
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
 
 		if (gtalk_name && strcmp(gtalk_name, plugin->info->name) < 0) {
 			char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols",
@@ -784,8 +782,6 @@
 	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
 	for (p = list, i = 0; p != NULL; p = p->next, i++) {
-		PurplePlugin *plugin;
-
 		if (show_all)
 			account = (PurpleAccount *)p->data;
 		else {
@@ -799,8 +795,6 @@
 			continue;
 		}
 
-		plugin = purple_find_prpl(purple_account_get_protocol_id(account));
-
 		pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
 
 		if (pixbuf) {
@@ -2790,79 +2784,78 @@
 
 
 gboolean pidgin_gdk_pixbuf_is_opaque(GdkPixbuf *pixbuf) {
-        int width, height, rowstride, i;
-        unsigned char *pixels;
-        unsigned char *row;
-
-        if (!gdk_pixbuf_get_has_alpha(pixbuf))
-                return TRUE;
-
-        width = gdk_pixbuf_get_width (pixbuf);
-        height = gdk_pixbuf_get_height (pixbuf);
-        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
-        pixels = gdk_pixbuf_get_pixels (pixbuf);
-
-        row = pixels;
-        for (i = 3; i < rowstride; i+=4) {
-                if (row[i] < 0xfe)
-                        return FALSE;
-        }
-
-        for (i = 1; i < height - 1; i++) {
-                row = pixels + (i*rowstride);
-                if (row[3] < 0xfe || row[rowstride-1] < 0xfe) {
-                        return FALSE;
-            }
-        }
-
-        row = pixels + ((height-1) * rowstride);
-        for (i = 3; i < rowstride; i+=4) {
-                if (row[i] < 0xfe)
-                        return FALSE;
-        }
-
-        return TRUE;
+	int height, rowstride, i;
+	unsigned char *pixels;
+	unsigned char *row;
+
+	if (!gdk_pixbuf_get_has_alpha(pixbuf))
+		return TRUE;
+
+	height = gdk_pixbuf_get_height (pixbuf);
+	rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+	pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+	row = pixels;
+	for (i = 3; i < rowstride; i+=4) {
+		if (row[i] < 0xfe)
+			return FALSE;
+	}
+
+	for (i = 1; i < height - 1; i++) {
+		row = pixels + (i * rowstride);
+		if (row[3] < 0xfe || row[rowstride - 1] < 0xfe) {
+			return FALSE;
+	    }
+	}
+
+	row = pixels + ((height - 1) * rowstride);
+	for (i = 3; i < rowstride; i += 4) {
+		if (row[i] < 0xfe)
+			return FALSE;
+	}
+
+	return TRUE;
 }
 
 void pidgin_gdk_pixbuf_make_round(GdkPixbuf *pixbuf) {
 	int width, height, rowstride;
-        guchar *pixels;
-        if (!gdk_pixbuf_get_has_alpha(pixbuf))
-                return;
-        width = gdk_pixbuf_get_width(pixbuf);
-        height = gdk_pixbuf_get_height(pixbuf);
-        rowstride = gdk_pixbuf_get_rowstride(pixbuf);
-        pixels = gdk_pixbuf_get_pixels(pixbuf);
-
-        if (width < 6 || height < 6)
-                return;
-        /* Top left */
-        pixels[3] = 0;
-        pixels[7] = 0x80;
-        pixels[11] = 0xC0;
-        pixels[rowstride + 3] = 0x80;
-        pixels[rowstride * 2 + 3] = 0xC0;
-
-        /* Top right */
-        pixels[width * 4 - 1] = 0;
-        pixels[width * 4 - 5] = 0x80;
-        pixels[width * 4 - 9] = 0xC0;
-        pixels[rowstride + (width * 4) - 1] = 0x80;
-        pixels[(2 * rowstride) + (width * 4) - 1] = 0xC0;
-
-        /* Bottom left */
-        pixels[(height - 1) * rowstride + 3] = 0;
-        pixels[(height - 1) * rowstride + 7] = 0x80;
-        pixels[(height - 1) * rowstride + 11] = 0xC0;
-        pixels[(height - 2) * rowstride + 3] = 0x80;
-        pixels[(height - 3) * rowstride + 3] = 0xC0;
-
-        /* Bottom right */
-        pixels[height * rowstride - 1] = 0;
-        pixels[(height - 1) * rowstride - 1] = 0x80;
-        pixels[(height - 2) * rowstride - 1] = 0xC0;
-        pixels[height * rowstride - 5] = 0x80;
-        pixels[height * rowstride - 9] = 0xC0;
+	guchar *pixels;
+	if (!gdk_pixbuf_get_has_alpha(pixbuf))
+		return;
+	width = gdk_pixbuf_get_width(pixbuf);
+	height = gdk_pixbuf_get_height(pixbuf);
+	rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+	pixels = gdk_pixbuf_get_pixels(pixbuf);
+
+	if (width < 6 || height < 6)
+		return;
+	/* Top left */
+	pixels[3] = 0;
+	pixels[7] = 0x80;
+	pixels[11] = 0xC0;
+	pixels[rowstride + 3] = 0x80;
+	pixels[rowstride * 2 + 3] = 0xC0;
+
+	/* Top right */
+	pixels[width * 4 - 1] = 0;
+	pixels[width * 4 - 5] = 0x80;
+	pixels[width * 4 - 9] = 0xC0;
+	pixels[rowstride + (width * 4) - 1] = 0x80;
+	pixels[(2 * rowstride) + (width * 4) - 1] = 0xC0;
+
+	/* Bottom left */
+	pixels[(height - 1) * rowstride + 3] = 0;
+	pixels[(height - 1) * rowstride + 7] = 0x80;
+	pixels[(height - 1) * rowstride + 11] = 0xC0;
+	pixels[(height - 2) * rowstride + 3] = 0x80;
+	pixels[(height - 3) * rowstride + 3] = 0xC0;
+
+	/* Bottom right */
+	pixels[height * rowstride - 1] = 0;
+	pixels[(height - 1) * rowstride - 1] = 0x80;
+	pixels[(height - 2) * rowstride - 1] = 0xC0;
+	pixels[height * rowstride - 5] = 0x80;
+	pixels[height * rowstride - 9] = 0xC0;
 }
 
 const char *pidgin_get_dim_grey_string(GtkWidget *widget) {
--- a/pidgin/pidginstock.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/pidginstock.h	Mon Sep 13 09:57:03 2010 +0000
@@ -44,7 +44,7 @@
 #define PIDGIN_STOCK_DOWNLOAD        "pidgin-download"
 #define PIDGIN_STOCK_EDIT            "pidgin-edit"
 #define PIDGIN_STOCK_FGCOLOR         "pidgin-fgcolor"
-#define PIDGIN_STOCK_FILE_CANCELED   "pidgin-file-canceled"
+#define PIDGIN_STOCK_FILE_CANCELED   "pidgin-file-cancelled"
 #define PIDGIN_STOCK_FILE_DONE       "pidgin-file-done"
 #define PIDGIN_STOCK_IGNORE          "pidgin-ignore"
 #define PIDGIN_STOCK_INFO            "pidgin-info"
--- a/pidgin/pixmaps/emotes/default/24/default.theme.in	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/pixmaps/emotes/default/24/default.theme.in	Mon Sep 13 09:57:03 2010 +0000
@@ -419,6 +419,98 @@
 female-fighter.png  o-+     O-+
 yin-yang.png        (%)
 
+# Following Yahoo! Messenger 8.1
+[Yahoo JAPAN]
+happy.png           :)      :-)
+question.png        :-/     :-\\
+shocked.png         :-O     :O      :-o     :o 
+devil.png           >:)
+angel.png           O:-)    o:-)    0:-)
+sick.png            :-&
+sleepy.png          (:|
+hypnotized.png      @-)
+on-the-phone.png    :)]
+sad.png             :(      :-(
+amorous.png         :x      :-x     :X      :-X
+angry.png           X-(     x-(     X(      x(
+crying.png          :((
+glasses-nerdy.png   :-B     :-b
+quiet.png           :-$
+drool.png           =P~     =p~
+lying.png           :^O     :^o
+call-me.png         :-c
+wink.png            ;)      ;-)
+embarrassed.png     :">
+mean.png            :->     :>
+laugh.png           :))     :-))
+bye.png             =;
+arrogant.png        [-(
+thinking.png        :-?
+waiting.png         :-w     :-W
+at-wits-end.png     ~x(     ~X(
+excited.png         :D      :-D     :d      :-d
+tongue.png          :-P     :P      :-p     :p
+glasses-cool.png    B-)     b-)
+neutral.png         :|      :-|
+sleeping.png        I-)     i-)     |-)
+clown.png           :o)     :O)
+doh.png             #-o     #-O
+weep.png            :-<
+go-away.png         :-h
+lashes.png          ;;)
+kiss.png            :-*     :*
+confused.png        :-S     :-s
+sarcastic.png       /:)
+eyeroll.png         8-|
+silly.png           8-}
+clap.png            =D>     =d>
+mad-tongue.png      >:P     >:p
+time-out.png        :-t     :-T
+hug-left.png        >:D<    >:d<
+love-over.png       =((
+hot.png             #:-S    #:-s
+rotfl.png           =)) :-j :-J 
+loser.png           L-)     l-)
+party.png           <:-P    <:-p
+nervous.png         :-SS       :-Ss    :-sS    :-ss
+cowboy.png          <):)
+desire.png          8->
+! skywalker.png     C:-)    c:-)    C:)     c:)
+! monkey.png        :-(|)  :(|)
+
+# Hidden Yahoo emotes
+alien.png           =:)     >-)
+beat-up.png         b-(     B-(
+chicken.png         ~:>
+coffee.png          ~o)     ~O)
+cow.png             3:-O    3:-o
+dance.png           \\:D/   \\:d/
+rose.png            @};-
+dont-know.png       :-L     :-l
+skeleton.png        8-X     8-x
+lamp.png            *-:)
+monkey.png          :(|)
+coins.png           $-)
+peace.png           :)>-
+pig.png             :@)
+pray.png            [-o<    [-O<
+pumpkin.png         (~~)
+shame.png           [-X     [-x
+flag.png            **==
+clover.png          %%-
+musical-note.png    :-"
+giggle.png          ;))
+worship.png         ^:)^
+star.png            (*)
+waving.png          >:/
+talktohand.png      :-@
+
+# Only available after activating the Yahoo! Fighter IMVironment
+male-fighter1.png   o->     O->
+male-fighter2.png   o=>     O=>
+female-fighter.png  o-+     O-+
+yin-yang.png        (%)
+
 
 # Following MySpaceIM Beta 1.0.697.0
 [MySpaceIM]
@@ -428,7 +520,7 @@
 glasses-nerdy.png   B)
 bulgy-eyes.png	    %)
 freaked-out.png	    :E
-smile.png	    :)      :-)
+happy.png	    :)      :-)
 amorous.png	    :X
 laugh.png	    :))
 mohawk.png	    -:
--- a/pidgin/pixmaps/emotes/small/16/Makefile.am	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/pixmaps/emotes/small/16/Makefile.am	Mon Sep 13 09:57:03 2010 +0000
@@ -34,7 +34,6 @@
     confused.png \
     console.png \
     cold.png \
-    cool.png \
     cross.png \
     crying.png \
     devil.png \
@@ -44,7 +43,6 @@
     excruciating.png \
     eyeroll.png \
     girl.png \
-    grin.png \
     happy.png \
     hug-left.png \
     hug-right.png \
@@ -77,6 +75,7 @@
     star.png \
     stressed.png \
     thinking.png \
+    thunder.png \
     tongue.png \
     tv.png \
     uhm-yeah.png \
Binary file pidgin/pixmaps/emotes/small/16/cool.png has changed
Binary file pidgin/pixmaps/emotes/small/16/glasses-cool.png has changed
Binary file pidgin/pixmaps/emotes/small/16/grin.png has changed
--- a/pidgin/pixmaps/emotes/small/16/small.theme.in	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/pixmaps/emotes/small/16/small.theme.in	Mon Sep 13 09:57:03 2010 +0000
@@ -1,5 +1,5 @@
 _Name=Small
-_Description=Smaller versions of the default smilies
+_Description=Smaller versions of the default smileys
 Icon=wink.png
 Author=Hylke Bons
 
@@ -13,10 +13,12 @@
 tongue.png          :P      :p      :-P     :-p
 shocked.png         =-O     =-o
 kiss.png            :-*
+glasses-cool.png    8-)
 embarrassed.png     :-[
 crying.png          :'(     :'-(
 thinking.png        :-/     :-\\
 angel.png           O:-)    o:-)
+shut-mouth.png      :-X
 
 
 [XMPP]
@@ -29,18 +31,23 @@
 tongue.png          :P      :p      :-P     :-p
 shocked.png         =-O     =-o     :-O     :-o
 kiss.png            :kiss:  :-*
+glasses-cool.png    8-)     B-)
 embarrassed.png     :-[
 crying.png          :'-(    :'(
 thinking.png        :-/     :-\\
 angel.png           O:-)    o:-)
+shut-mouth.png      :-X
 
 # Following XEP-0038 + GTalk
 angry.png           >:-(    >:(     X-(    x-(
+rose.png            @->--   :rose:
 phone.png           :telephone:
+lamp.png            :jabber:
 in_love.png         :heart: :love:  <3
 musical-note.png    :music:
 beer.png            :beer:
 coffee.png          :coffee:
+star.png            :star:
 
 # Others
 neutral.png         :|      :-|
@@ -61,6 +68,8 @@
 angel.png           O:-)
 thinking.png        :-\\    :-/
 crying.png          :'(
+shut-mouth.png      :-X
+glasses-cool.png    8-)
 
 
 # Following Windows Live Messenger 8.1
@@ -70,6 +79,7 @@
 wink.png            ;)      ;-)
 shocked.png         :-O     :-o     :O      :o
 tongue.png          :-P     :P      :-p     :p
+glasses-cool.png    (H)     (h)
 angry.png           :@      :-@
 embarrassed.png     :$      :-$
 confused.png        :S      :s      :-S     :-s
@@ -79,21 +89,28 @@
 devil.png           (6)
 angel.png           (A)     (a)
 in_love.png         (L)     (l)
+star.png            (*)
 musical-note.png    (8)
+rose.png            (F)     (f)
 kiss.png            (K)     (k)
 camera.png          (P)     (p)
+lamp.png            (I)     (i)
 coffee.png          (C)     (c)
 phone.png           (T)     (t)
 hug-left.png        ({)
 hug-right.png       (})
 beer.png            (B)     (b)
+boy.png             (Z)     (z)
+girl.png            (X)     (x)
 sarcastic.png       ^o)
 sick.png            +o(
 plate.png           (pl)
 mobile.png          (mp)
 dont-know.png       :^)
 thinking.png        *-)
+thunder.png         (li)
 party.png           <:o)
+eyeroll.png         8-)
 sleepy.png          |-) 
 
 # Hidden MSN emotes
@@ -106,28 +123,37 @@
 shocked.png         /:O      /jy       /surprised
 party.png           /8-)     /dy       /revel
 crying.png          /:<      /ll       /cry
+shut-mouth.png      /:X      /bz       /shut_mouth
 sleeping.png        /:Z      /shui     /sleep
 embarrassed.png     /:-|     /gg       /embarassed
+pissed-off.png      /:@      /fn       /pissed_off
 excited.png         /:D      /cy       /toothy_smile
 happy.png           /:)      /wx       /small_smile
 sad.png             /:(      /ng       /sad
+glasses-cool.png    /:+      /kuk      /cool
 sick.png            /:T      /tu       /vomit
 sleepy.png          /|-)     /kun      /sleepy
 hot.png             /:L      /sweat
 question.png        /?       /yiw      /question
+excruciating.png    /:8      /zhem     /excrutiating
 afraid.png          /shake   /fad      /shake
 amorous.png         /love    /aiq      /love
 search.png          /find    /zhao     /search
 hug-left.png        /hug     /yb       /hug
+lamp.png            /!       /dp       /lightbulb
+thunder.png         /li      /shd      /lightning
 musical-note.png    /music   /yy       /music
 coffee.png          /coffee  /kf       /coffee
 hungry.png          /eat     /fan      /eat
+rose.png            /rose    /mg       /rose
 kiss.png            /kiss    /wen      /kiss
 in_love.png         /heart   /xin      /heart
 meeting.png         /meeting /hy       /meeting
 phone.png           /phone   /dh       /phone
 tv.png              /TV      /ds       /TV
 angry.png           /<O>     /oh       /angry
+girl.png            /<00>    /nv       /woman
+boy.png             /<11>    /nan      /man
 
 
 # Following ICQ 6.0
@@ -146,9 +172,12 @@
 embarrassed.png     :-[
 devil.png           ]:->
 angel.png           O:-)
+rose.png            @}->--
+shut-mouth.png      :-X     :X      :-x     :x
 thinking.png        :-\\    :-/
 beer.png            *DRINK*
 excited.png         :-D     :D
+glasses-cool.png    8-)
 amorous.png         *IN\ LOVE*
 
 
@@ -165,17 +194,21 @@
 amorous.png         :x      :-x     :X      :-X
 angry.png           X-(     x-(     X(      x(
 crying.png          :((
+drool.png           =P~     =p~
+lying.png           :^O     :^o
 wink.png            ;)      ;-)
 embarrassed.png     :">
 mean.png            :->     :>
 thinking.png        :-?
 excited.png         :D      :-D     :d      :-d
 tongue.png          :-P     :P      :-p     :p
+glasses-cool.png    B-)     b-)
 neutral.png         :|      :-|
 sleeping.png        I-)     i-)     |-)
 kiss.png            :-*     :*
 confused.png        :-S     :-s
 sarcastic.png       /:)
+eyeroll.png         8-|
 hug-left.png        >:D<    >:d<
 hot.png             #:-S    #:-s
 party.png           <:-P    <:-p
@@ -183,38 +216,48 @@
 
 # Hidden Yahoo emotes
 coffee.png          ~o)     ~O)
+rose.png            @};-
 dont-know.png       :-L     :-l
+lamp.png            *-:)
 shame.png           [-X     [-x
 musical-note.png    :-"
+star.png            (*)
 
 # Following Yahoo! Messenger 8.1
 [Yahoo JAPAN]
-smile.png           :)      :-)
+happy.png           :)      :-)
 question.png        :-/     :-\\
-shock.png           :-O     :O      :-o     :o 
+shocked.png         :-O     :O      :-o     :o 
 devil.png           >:)
 angel.png           O:-)    o:-)    0:-)
 sick.png            :-&
-yawn.png            (:|
+sleepy.png          (:|
 sad.png             :(      :-(
+amorous.png         :x      :-x     :X      :-X
 angry.png           X-(     x-(     X(      x(
 crying.png          :((
 wink.png            ;)      ;-)
 thinking.png        :-?
-smile-big.png       :D      :-D     :d      :-d
+excited.png         :D      :-D     :d      :-d
 tongue.png          :-P     :P      :-p     :p
+glasses-cool.png    B-)     b-)
 neutral.png         :|      :-|
-sleepy.png          I-)     i-)     |-)
+sleeping.png        I-)     i-)     |-)
 kiss.png            :-*     :*
 confused.png        :-S     :-s
+sarcastic.png       /:)
+eyeroll.png         8-|
 hug-left.png        >:D<    >:d<
 party.png           <:-P    <:-p
 
 # Hidden Yahoo emotes
 coffee.png          ~o)     ~O)
+rose.png            @};-
 dont-know.png       :-L     :-l
+lamp.png            *-:)
 shame.png           [-X     [-x
 musical-note.png    :-"
+star.png            (*)
 
 
 # Following MySpaceIM Beta 1.0.697.0
@@ -222,10 +265,13 @@
 excited.png  	    :D      :-D
 devil.png	    }:)
 confused.png	    :Z
+happy.png	    :)      :-)
 amorous.png	    :X
+pirate.png	    P)
 shocked.png	    :O
 neutral.png	    :|
 tongue.png	    :P      :p
+pissed-off.png	    B|
 wink.png	    ;-)     ;)
 sad.png		    :[
 kiss.png            :x
@@ -240,7 +286,7 @@
 shocked.png         :-O     :O
 tongue.png          :-P     :P
 embarrassed.png     :-$     :$
-cool.png            8-)
+glasses-cool.png    8-)
 in_love.png         (H)
 rose.png            (F)
 ### Added in v3.0
@@ -252,7 +298,7 @@
 lamp.png            (i)
 pissed-off.png      :e      :-e
 shut-mouth.png      :-x     :x
-grumpy.png          (z)
+thunder.png         (z)
 coffee.png          (U)
 mrgreen.png         (G)
 ### Added in v5.0
@@ -265,7 +311,7 @@
 drool.png           :-~     :~
 sleeping.png        :-z     :z
 lying.png           :L)
-nerdy.png           8-|     8|
+glasses-nerdy.png   8-|     8|
 pirate.png          P-)
 ### Added in v5.9.7
 bored.png           :-[     :[
Binary file pidgin/pixmaps/emotes/small/16/thunder.png has changed
--- a/pidgin/plugins/gevolution/add_buddy_dialog.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/plugins/gevolution/add_buddy_dialog.c	Mon Sep 13 09:57:03 2010 +0000
@@ -54,8 +54,7 @@
 
 	gevo_addrbooks_model_unref(dialog->addrbooks);
 
-	if (dialog->username != NULL)
-		g_free(dialog->username);
+	g_free(dialog->username);
 
 	g_free(dialog);
 
@@ -289,7 +288,7 @@
 	{
 		EContact *contact = E_CONTACT(c->data);
 		const char *name;
-		GList *aims, *jabbers, *yahoos, *msns, *icqs, *novells;
+		GList *aims, *jabbers, *yahoos, *msns, *icqs, *novells, *ggs;
 
 		name = e_contact_get_const(contact, E_CONTACT_FULL_NAME);
 
@@ -299,9 +298,11 @@
 		msns    = e_contact_get(contact, E_CONTACT_IM_MSN);
 		icqs    = e_contact_get(contact, E_CONTACT_IM_ICQ);
 		novells = e_contact_get(contact, E_CONTACT_IM_GROUPWISE);
+		ggs     = e_contact_get(contact, E_CONTACT_IM_GADUGADU);
 
 		if (aims == NULL && jabbers == NULL && yahoos == NULL &&
-			msns == NULL && icqs == NULL && novells == NULL)
+			msns == NULL && icqs == NULL && novells == NULL &&
+			ggs == NULL)
 		{
 			GtkTreeIter iter;
 
@@ -320,6 +321,7 @@
 			add_ims(dialog, contact, name, msns,    "prpl-msn");
 			add_ims(dialog, contact, name, icqs,    "prpl-icq");
 			add_ims(dialog, contact, name, novells, "prpl-novell");
+			add_ims(dialog, contact, name, ggs,     "prpl-gg");
 		}
 	}
 
@@ -365,7 +367,7 @@
 	{
 		EContact *contact = E_CONTACT(l->data);
 		const char *name;
-		GList *aims, *jabbers, *yahoos, *msns, *icqs, *novells;
+		GList *aims, *jabbers, *yahoos, *msns, *icqs, *novells, *ggs;
 
 		name = e_contact_get_const(contact, E_CONTACT_FULL_NAME);
 
@@ -381,9 +383,11 @@
 		msns    = e_contact_get(contact, E_CONTACT_IM_MSN);
 		icqs    = e_contact_get(contact, E_CONTACT_IM_ICQ);
 		novells = e_contact_get(contact, E_CONTACT_IM_GROUPWISE);
+		ggs     = e_contact_get(contact, E_CONTACT_IM_GADUGADU);
 
 		if (aims == NULL && jabbers == NULL && yahoos == NULL &&
-			msns == NULL && icqs == NULL && novells == NULL)
+			msns == NULL && icqs == NULL && novells == NULL &&
+			ggs == NULL)
 		{
 			GtkTreeIter iter;
 
@@ -402,6 +406,7 @@
 			add_ims(dialog, contact, name, msns,    "prpl-msn");
 			add_ims(dialog, contact, name, icqs,    "prpl-icq");
 			add_ims(dialog, contact, name, novells, "prpl-novell");
+			add_ims(dialog, contact, name, ggs,     "prpl-gg");
 		}
 	}
 }
--- a/pidgin/plugins/gevolution/gevo-util.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/plugins/gevolution/gevo-util.c	Mon Sep 13 09:57:03 2010 +0000
@@ -111,6 +111,8 @@
 		protocol_field = E_CONTACT_IM_JABBER;
 	else if (!strcmp(protocol_id, "prpl-novell"))
 		protocol_field = E_CONTACT_IM_GROUPWISE;
+	else if (!strcmp(protocol_id, "prpl-gg"))
+		protocol_field = E_CONTACT_IM_GADUGADU;
 
 	return protocol_field;
 }
--- a/pidgin/plugins/gevolution/gevolution.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/plugins/gevolution/gevolution.c	Mon Sep 13 09:57:03 2010 +0000
@@ -125,6 +125,7 @@
 	update_ims_from_contact(contact, name, "prpl-msn",    E_CONTACT_IM_MSN);
 	update_ims_from_contact(contact, name, "prpl-icq",    E_CONTACT_IM_ICQ);
 	update_ims_from_contact(contact, name, "prpl-novell", E_CONTACT_IM_GROUPWISE);
+	update_ims_from_contact(contact, name, "prpl-gg",     E_CONTACT_IM_GADUGADU);
 }
 
 static void
--- a/pidgin/plugins/gevolution/new_person_dialog.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/plugins/gevolution/new_person_dialog.c	Mon Sep 13 09:57:03 2010 +0000
@@ -153,6 +153,8 @@
 			field = E_CONTACT_IM_MSN;
 		else if (!strcmp(im_service, "prpl-novell"))
 			field = E_CONTACT_IM_GROUPWISE;
+		else if (!strcmp(im_service, "prpl-gg"))
+			field = E_CONTACT_IM_GADUGADU;
 
 		if (field > 0)
 		{
@@ -202,8 +204,7 @@
 	if (name != NULL)
 		e_contact_name_free(name);
 
-	if (full_name != NULL)
-		g_free(full_name);
+	g_free(full_name);
 
 	delete_win_cb(NULL, NULL, dialog);
 }
--- a/pidgin/plugins/notify.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/plugins/notify.c	Mon Sep 13 09:57:03 2010 +0000
@@ -303,7 +303,6 @@
 attach_signals(PurpleConversation *conv)
 {
 	PidginConversation *gtkconv = NULL;
-	PidginWindow *gtkwin = NULL;
 	GSList *imhtml_ids = NULL, *entry_ids = NULL;
 	guint id;
 
@@ -313,8 +312,6 @@
 		return 0;
 	}
 
-	gtkwin  = gtkconv->win;
-
 	if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus")) {
 		/* TODO should really find a way to make this work no matter
 		 * where the focus is inside the conv window, without having
@@ -358,13 +355,11 @@
 detach_signals(PurpleConversation *conv)
 {
 	PidginConversation *gtkconv = NULL;
-	PidginWindow *gtkwin = NULL;
 	GSList *ids = NULL, *l;
 
 	gtkconv = PIDGIN_CONVERSATION(conv);
 	if (!gtkconv)
 		return;
-	gtkwin  = gtkconv->win;
 
 	ids = purple_conversation_get_data(conv, "notify-imhtml-signals");
 	for (l = ids; l != NULL; l = l->next)
@@ -650,7 +645,6 @@
 apply_method()
 {
 	GList *convs;
-	PidginWindow *purplewin = NULL;
 
 	for (convs = purple_get_conversations(); convs != NULL;
 	     convs = convs->next) {
@@ -659,7 +653,6 @@
 		/* remove notifications */
 		unnotify(conv, FALSE);
 
-		purplewin = PIDGIN_CONVERSATION(conv)->win;
 		if (GPOINTER_TO_INT(purple_conversation_get_data(conv, "notify-message-count")) != 0)
 			/* reattach appropriate notifications */
 			notify(conv, FALSE);
--- a/pidgin/plugins/vvconfig.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/plugins/vvconfig.c	Mon Sep 13 09:57:03 2010 +0000
@@ -28,6 +28,9 @@
 
 #include <gst/interfaces/propertyprobe.h>
 
+/* container window for showing a stand-alone configurator */
+static GtkWidget *window = NULL;
+
 static PurpleMediaElementInfo *old_video_src = NULL, *old_video_sink = NULL,
 		*old_audio_src = NULL, *old_audio_sink = NULL;
 
@@ -502,6 +505,59 @@
 	return TRUE;
 }
 
+static void
+config_destroy(GtkObject *w, gpointer nul)
+{
+	purple_debug_info("vvconfig", "closing vv configuration window\n");
+	window = NULL;
+}
+
+static void
+config_close(GtkObject *w, gpointer nul)
+{
+	gtk_widget_destroy(GTK_WIDGET(window));
+}
+
+static void
+show_config(PurplePluginAction *action)
+{
+	if (!window) {
+		GtkWidget *vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
+		GtkWidget *hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
+		GtkWidget *config_frame = get_plugin_config_frame(NULL);
+		GtkWidget *close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+		
+		gtk_container_add(GTK_CONTAINER(vbox), config_frame);
+		gtk_container_add(GTK_CONTAINER(vbox), hbox);
+		window = pidgin_create_window(_("Voice/Video Settings"),
+			PIDGIN_HIG_BORDER, NULL, TRUE);
+		g_signal_connect(G_OBJECT(window), "destroy", 
+			G_CALLBACK(config_destroy), NULL);
+		g_signal_connect(G_OBJECT(close), "clicked",
+		    G_CALLBACK(config_close), NULL);
+		gtk_box_pack_end(GTK_BOX(hbox), close, FALSE, FALSE, PIDGIN_HIG_BORDER);
+		gtk_container_add(GTK_CONTAINER(window), vbox);
+		gtk_widget_show(GTK_WIDGET(close));
+		gtk_widget_show(GTK_WIDGET(vbox));
+		gtk_widget_show(GTK_WIDGET(hbox));
+	}
+	gtk_window_present(GTK_WINDOW(window));
+}
+
+
+static GList *
+actions(PurplePlugin *plugin, gpointer context)
+{
+	GList *l = NULL;
+	PurplePluginAction *act = NULL;
+
+	act = purple_plugin_action_new(_("Voice and Video Settings"),
+		show_config);
+	l = g_list_append(l, act);
+
+	return l;
+}
+
 static gboolean
 plugin_unload(PurplePlugin *plugin)
 {
@@ -525,32 +581,32 @@
 
 static PurplePluginInfo info =
 {
-	PURPLE_PLUGIN_MAGIC,			/**< magic		*/
-	PURPLE_MAJOR_VERSION,			/**< major version	*/
-	PURPLE_MINOR_VERSION,			/**< minor version	*/
-	PURPLE_PLUGIN_STANDARD,			/**< type		*/
-	PIDGIN_PLUGIN_TYPE,			/**< ui_requirement	*/
-	0,					/**< flags		*/
-	NULL,					/**< dependencies	*/
-	PURPLE_PRIORITY_DEFAULT,		/**< priority		*/
+	PURPLE_PLUGIN_MAGIC,                         /**< magic          */
+	PURPLE_MAJOR_VERSION,                        /**< major version  */
+	PURPLE_MINOR_VERSION,                        /**< minor version  */
+	PURPLE_PLUGIN_STANDARD,                      /**< type           */
+	PIDGIN_PLUGIN_TYPE,                          /**< ui_requirement */
+	0,                                           /**< flags          */
+	NULL,                                        /**< dependencies   */
+	PURPLE_PRIORITY_DEFAULT,                     /**< priority       */
 
-	"gtk-maiku-vvconfig",			/**< id			*/
-	N_("Voice/Video Settings"),		/**< name		*/
-	DISPLAY_VERSION,			/**< version		*/
-	N_("Configure your microphone and webcam."), /**< summary	*/
+	"gtk-maiku-vvconfig",                        /**< id             */
+	N_("Voice/Video Settings"),                  /**< name           */
+	DISPLAY_VERSION,                             /**< version        */
+	N_("Configure your microphone and webcam."), /**< summary        */
 	N_("Configure microphone and webcam "
-	   "settings for voice/video calls."),	/**< description	*/
-	"Mike Ruprecht <cmaiku@gmail.com>",	/**< author		*/
-	PURPLE_WEBSITE,				/**< homepage		*/
+	   "settings for voice/video calls."),       /**< description    */
+	"Mike Ruprecht <cmaiku@gmail.com>",          /**< author         */
+	PURPLE_WEBSITE,                              /**< homepage       */
 
-	plugin_load,				/**< load		*/
-	plugin_unload,				/**< unload		*/
-	NULL,					/**< destroy		*/
+	plugin_load,                                 /**< load           */
+	plugin_unload,                               /**< unload         */
+	NULL,                                        /**< destroy        */
 
-	&ui_info,				/**< ui_info		*/
-	NULL,					/**< extra_info		*/
-	NULL,					/**< prefs_info		*/
-	NULL,					/**< actions		*/
+	&ui_info,                                    /**< ui_info        */
+	NULL,                                        /**< extra_info     */
+	NULL,                                        /**< prefs_info     */
+	actions,                                     /**< actions        */
 
 	/* padding */
 	NULL,
--- a/pidgin/win32/IdleTracker/Makefile.mingw	Fri Aug 20 08:35:27 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-#
-# Makefile.mingw
-#
-# Description: Makefile for idletrack
-#
-
-PIDGIN_TREE_TOP := ../../..
-include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
-
-TARGET = idletrack
-
-##
-##  SOURCES, OBJECTS
-##
-
-C_SRC =	idletrack.c
-
-OBJECTS = $(C_SRC:%.c=%.o)
-
-include $(PIDGIN_COMMON_RULES)
-
-##
-## TARGET DEFINITIONS
-##
-
-.PHONY: all install clean
-
-all: $(TARGET).dll
-
-install: $(PIDGIN_INSTALL_DIR)
-	cp $(TARGET).dll $(PIDGIN_INSTALL_DIR)
-
-##
-## BUILD DLL
-##
-
-$(TARGET).dll $(TARGET).dll.a: $(OBJECTS)
-	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--out-implib,$(TARGET).dll.a -o $(TARGET).dll
-
-##
-## CLEAN RULES
-##
-
-clean:
-	rm -f $(OBJECTS) $(TARGET).dll $(TARGET).dll.a
-
-include $(PIDGIN_COMMON_TARGETS)
--- a/pidgin/win32/IdleTracker/idletrack.c	Fri Aug 20 08:35:27 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,188 +0,0 @@
-/*
- *  idletrack.c
- *
- *  Authors: mrgentry @ http://www.experts-exchange.com
- *           Herman Bloggs <hermanator12002@yahoo.com>
- *  Date: February, 2003
- *  Description: Track user inactivity.
- *
- *  Andrew Whewell <awhewell@users.sourceforge.net> - 25th June 2004. Added
- *  support for GetLastInputInfo under Windows 2000 and above. This avoids having
- *  IDLETRACK.DLL hook itself into every process on the machine, which makes
- *  upgrades easier. The hook mechanism is also used by key loggers, so not
- *  using hooks doesn't put the willys up programs that keep an eye out for
- *  loggers.
- *
- *  Windows 9x doesn't have GetLastInputInfo - when Purple runs on these machines
- *  the code silently falls back onto the old hooking scheme.
- */
-#define _WIN32_WINNT 0x0500
-#include "idletrack.h"
-
-#define EXPORT __declspec(dllexport)
-
-static HANDLE hMapObject = NULL;
-static DWORD *lastTime = NULL;
-static HHOOK keyHook = NULL;
-static HHOOK mouseHook = NULL;
-static HINSTANCE g_hInstance = NULL;
-static POINT g_point;
-
-/* GetLastInputInfo address and module - if g_GetLastInputInfo == NULL then
- * we fall back on the old "hook the world" method. GetLastInputInfo was brought
- * in with Windows 2000 so Windows 9x will still hook everything.
- */
-typedef BOOL (WINAPI *GETLASTINPUTINFO)(LASTINPUTINFO *);
-static HMODULE g_user32 = NULL;
-static GETLASTINPUTINFO g_GetLastInputInfo = NULL;
-
-static DWORD* setup_shared_mem() {
-	BOOL fInit;
-
-	/* Set up the shared memory. */
-	hMapObject = CreateFileMapping((HANDLE) 0xFFFFFFFF, /* use paging file        */
-								   NULL,                /* no security attributes */
-								   PAGE_READWRITE,      /* read/write access      */
-								   0,                   /* size: high 32-bits     */
-								   sizeof(DWORD),       /* size: low 32-bits      */
-								   "timermem");         /* name of map object     */
-
-	if(hMapObject == NULL)
-		return NULL;
-
-	/* The first process to attach initializes memory. */
-	fInit = (GetLastError() != ERROR_ALREADY_EXISTS);
-
-	/* Get a pointer to the file-mapped shared memory. */
-	lastTime = (DWORD*) MapViewOfFile(hMapObject,     /* object to map view of    */
-									  FILE_MAP_WRITE, /* read/write access        */
-									  0,              /* high offset:  map from   */
-									  0,              /* low offset:   beginning  */
-									  0);             /* default: map entire file */
-
-	if(lastTime == NULL)
-		return NULL;
-
-	*lastTime = GetTickCount();
-
-	return lastTime;
-}
-
-
-static LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
-	if(!(code < 0)) {
-		if(lastTime == NULL)
-			lastTime = setup_shared_mem();
-
-		if(lastTime)
-			*lastTime = GetTickCount();
-	}
-	return CallNextHookEx(keyHook, code, wParam, lParam);
-}
-
-
-static LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) {
-	/* We need to verify that the Mouse pointer has actually moved. */
-	if(!(code < 0) &&
-			!((g_point.x == ((MOUSEHOOKSTRUCT*) lParam)->pt.x) &&
-			(g_point.y == ((MOUSEHOOKSTRUCT*) lParam)->pt.y))) {
-		g_point.x = ((MOUSEHOOKSTRUCT*) lParam)->pt.x;
-		g_point.y = ((MOUSEHOOKSTRUCT*) lParam)->pt.y;
-
-		if(lastTime == NULL)
-			lastTime = setup_shared_mem();
-
-		if(lastTime)
-			*lastTime = GetTickCount();
-	}
-	return CallNextHookEx(mouseHook, code, wParam, lParam);
-}
-
-
-EXPORT DWORD winpidgin_get_lastactive() {
-	DWORD result = 0;
-
-	/* If we have GetLastInputInfo then use it, otherwise use the hooks*/
-	if(g_GetLastInputInfo != NULL) {
-		LASTINPUTINFO lii;
-		memset(&lii, 0, sizeof(lii));
-		lii.cbSize = sizeof(lii);
-		if(g_GetLastInputInfo(&lii)) {
-			result = lii.dwTime;
-		}
-	} else {
-		if(lastTime == NULL)
-			lastTime = setup_shared_mem();
-
-		if(lastTime)
-			result = *lastTime;
-	}
-
-	return result;
-}
-
-
-EXPORT BOOL winpidgin_set_idlehooks() {
-	/* Is GetLastInputInfo available?*/
-	g_user32 = LoadLibrary("user32.dll");
-	if(g_user32) {
-		g_GetLastInputInfo = (GETLASTINPUTINFO) GetProcAddress(g_user32, "GetLastInputInfo");
-	}
-
-	/* If we couldn't find GetLastInputInfo then fall back onto the hooking scheme*/
-	if(g_GetLastInputInfo == NULL) {
-		/* Set up the shared memory.*/
-		lastTime = setup_shared_mem();
-		if(lastTime == NULL)
-			return FALSE;
-		*lastTime = GetTickCount();
-
-	/* Set up the keyboard hook.*/
-		keyHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
-		if(keyHook == NULL) {
-			UnmapViewOfFile(lastTime);
-			CloseHandle(hMapObject);
-			return FALSE;
-		}
-
-		/* Set up the mouse hook.*/
-		mouseHook = SetWindowsHookEx(WH_MOUSE, MouseProc, g_hInstance, 0);
-		if(mouseHook == NULL) {
-			UnhookWindowsHookEx(keyHook);
-			UnmapViewOfFile(lastTime);
-			CloseHandle(hMapObject);
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
-
-EXPORT void winpidgin_remove_idlehooks() {
-	if(g_user32 != NULL)
-		FreeLibrary(g_user32);
-	if(keyHook)
-		UnhookWindowsHookEx(keyHook);
-	if(mouseHook)
-		UnhookWindowsHookEx(mouseHook);
-	if(lastTime)
-		UnmapViewOfFile(lastTime);
-	if(hMapObject)
-		CloseHandle(hMapObject);
-}
-
-/* suppress gcc "no previous prototype" warning */
-BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved);
-BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {
-	switch(dwReason) {
-		case DLL_PROCESS_ATTACH:
-			g_hInstance = hInstance;
-			g_point.x = 0;
-			g_point.y = 0;
-			break;
-		case DLL_PROCESS_DETACH:
-			break;
-	}
-	return TRUE;
-}
--- a/pidgin/win32/IdleTracker/idletrack.h	Fri Aug 20 08:35:27 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-/*
- * idletrack.h
- */
-#include <windows.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-DWORD winpidgin_get_lastactive(void);
-BOOL winpidgin_set_idlehooks(void);
-void winpidgin_remove_idlehooks(void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
--- a/pidgin/win32/gtkwin32dep.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/win32/gtkwin32dep.c	Mon Sep 13 09:57:03 2010 +0000
@@ -43,7 +43,6 @@
 #include "network.h"
 
 #include "resource.h"
-#include "idletrack.h"
 #include "zlib.h"
 #include "untar.h"
 
@@ -377,15 +376,19 @@
 
 void winpidgin_init(HINSTANCE hint) {
 	FARPROC proc;
+	gchar *exchndl_dll_path;
 
 	purple_debug_info("winpidgin", "winpidgin_init start\n");
 
 	exe_hInstance = hint;
 
-	proc = wpurple_find_and_loadproc("exchndl.dll", "SetLogFile");
+	exchndl_dll_path = g_build_filename(wpurple_install_dir(), "exchndl.dll", NULL);
+	proc = wpurple_find_and_loadproc(exchndl_dll_path, "SetLogFile");
+	g_free(exchndl_dll_path);
+	exchndl_dll_path = NULL;
 	if (proc) {
 		gchar *debug_dir, *locale_debug_dir;
-		
+
 		debug_dir = g_build_filename(purple_user_dir(), "pidgin.RPT", NULL);
 		locale_debug_dir = g_locale_from_utf8(debug_dir, -1, NULL, NULL, NULL);
 
@@ -397,10 +400,6 @@
 		g_free(locale_debug_dir);
 	}
 
-	/* IdleTracker Initialization */
-	if(!winpidgin_set_idlehooks())
-		purple_debug_error("winpidgin", "Failed to initialize idle tracker\n");
-
 	winpidgin_spell_init();
 	purple_debug_info("winpidgin", "GTK+ :%u.%u.%u\n",
 		gtk_major_version, gtk_minor_version, gtk_micro_version);
@@ -429,9 +428,6 @@
 	if(messagewin_hwnd)
 		DestroyWindow(messagewin_hwnd);
 
-	/* Idle tracker cleanup */
-	winpidgin_remove_idlehooks();
-
 }
 
 /* DLL initializer */
@@ -535,5 +531,18 @@
 				   (winR.right - winR.left),
 				   (winR.bottom - winR.top), TRUE);
 	}
+
 }
 
+DWORD winpidgin_get_lastactive() {
+	DWORD result = 0;
+
+	LASTINPUTINFO lii;
+	memset(&lii, 0, sizeof(lii));
+	lii.cbSize = sizeof(lii);
+	if (GetLastInputInfo(&lii))
+		result = lii.dwTime;
+
+	return result;
+}
+
--- a/pidgin/win32/gtkwin32dep.h	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/win32/gtkwin32dep.h	Mon Sep 13 09:57:03 2010 +0000
@@ -39,6 +39,7 @@
 void winpidgin_ensure_onscreen(GtkWidget *win);
 void winpidgin_conv_blink(PurpleConversation *conv, PurpleMessageFlags flags);
 void winpidgin_window_flash(GtkWindow *window, gboolean flash);
+DWORD winpidgin_get_lastactive(void);
 
 /* init / cleanup */
 void winpidgin_init(HINSTANCE);
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Mon Sep 13 09:57:03 2010 +0000
@@ -268,7 +268,7 @@
   DetailPrint "Downloading GTK+ Runtime ... ($R2)"
   NSISdl::download /TIMEOUT=10000 $R2 $R1
   Pop $R0
-  StrCmp $R0 "cancel" done
+  ;StrCmp $R0 "cancel" done
   StrCmp $R0 "success" +2
     MessageBox MB_RETRYCANCEL "$(PIDGINGTKDOWNLOADERROR)" /SD IDCANCEL IDRETRY retry IDCANCEL done
 
@@ -304,6 +304,7 @@
     WriteRegStr HKLM "${HKLM_APP_PATHS_KEY}" "Path" "$INSTDIR\Gtk\bin"
     WriteRegStr HKLM ${PIDGIN_REG_KEY} "" "$INSTDIR"
     WriteRegStr HKLM ${PIDGIN_REG_KEY} "Version" "${PIDGIN_VERSION}"
+    WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\pidgin.exe"
     WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "DisplayName" "Pidgin"
     WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "DisplayVersion" "${PIDGIN_VERSION}"
     WriteRegStr HKLM "${PIDGIN_UNINSTALL_KEY}" "HelpLink" "http://developer.pidgin.im/wiki/Using Pidgin"
@@ -317,6 +318,7 @@
   pidgin_hkcu:
     WriteRegStr HKCU ${PIDGIN_REG_KEY} "" "$INSTDIR"
     WriteRegStr HKCU ${PIDGIN_REG_KEY} "Version" "${PIDGIN_VERSION}"
+    WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\pidgin.exe"
     WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "DisplayName" "Pidgin"
     WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "DisplayVersion" "${PIDGIN_VERSION}"
     WriteRegStr HKCU "${PIDGIN_UNINSTALL_KEY}" "HelpLink" "http://developer.pidgin.im/wiki/Using Pidgin"
@@ -619,7 +621,6 @@
     RMDir "$INSTDIR\spellcheck\lib"
     RMDir "$INSTDIR\spellcheck"
     Delete "$INSTDIR\freebl3.dll"
-    Delete "$INSTDIR\idletrack.dll"
     Delete "$INSTDIR\libjabber.dll"
     Delete "$INSTDIR\libnspr4.dll"
     Delete "$INSTDIR\libmeanwhile-1.dll"
--- a/pidgin/win32/winpidgin.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/win32/winpidgin.c	Mon Sep 13 09:57:03 2010 +0000
@@ -605,9 +605,9 @@
 		char *lpszCmdLine, int nCmdShow) {
 	wchar_t errbuf[512];
 	wchar_t pidgin_dir[MAX_PATH];
+	wchar_t *pidgin_dir_start = NULL;
 	wchar_t exe_name[MAX_PATH];
 	HMODULE hmod;
-	wchar_t *tmp;
 	wchar_t *wtmp;
 	int pidgin_argc;
 	char **pidgin_argv; /* This is in utf-8 */
@@ -672,14 +672,14 @@
 	if (GetModuleFileNameW(NULL, pidgin_dir, MAX_PATH) != 0) {
 
 		/* primitive dirname() */
-		tmp = wcsrchr(pidgin_dir, L'\\');
+		pidgin_dir_start = wcsrchr(pidgin_dir, L'\\');
 
-		if (tmp) {
+		if (pidgin_dir_start) {
 			HMODULE hmod;
-			tmp[0] = L'\0';
+			pidgin_dir_start[0] = L'\0';
 
 			/* tmp++ will now point to the executable file name */
-			wcscpy(exe_name, tmp + 1);
+			wcscpy(exe_name, pidgin_dir_start + 1);
 
 			wcscat(pidgin_dir, L"\\exchndl.dll");
 			if ((hmod = LoadLibraryW(pidgin_dir))) {
@@ -702,7 +702,8 @@
 				proc = GetProcAddress(hmod, "SetDebugInfoDir");
 				if (proc) {
 					char *pidgin_dir_ansi = NULL;
-					tmp[0] = L'\0';
+					/* Restore pidgin_dir to point to where the executable is */
+					pidgin_dir_start[0] = L'\0';
 					i = WideCharToMultiByte(CP_ACP, 0, pidgin_dir,
 						-1, NULL, 0, NULL, NULL);
 					if (i != 0) {
@@ -728,7 +729,8 @@
 
 			}
 
-			tmp[0] = L'\0';
+			/* Restore pidgin_dir to point to where the executable is */
+			pidgin_dir_start[0] = L'\0';
 		}
 	} else {
 		DWORD dw = GetLastError();
@@ -763,9 +765,14 @@
 			return 0;
 
 	/* Now we are ready for Pidgin .. */
-	if ((hmod = LoadLibraryW(L"pidgin.dll")))
+	wcscat(pidgin_dir, L"\\pidgin.dll");
+	if ((hmod = LoadLibraryW(pidgin_dir)))
 		pidgin_main = (LPFNPIDGINMAIN) GetProcAddress(hmod, "pidgin_main");
 
+	/* Restore pidgin_dir to point to where the executable is */
+	if (pidgin_dir_start)
+		pidgin_dir_start[0] = L'\0';
+
 	if (!pidgin_main) {
 		DWORD dw = GetLastError();
 		BOOL mod_not_found = (dw == ERROR_MOD_NOT_FOUND || dw == ERROR_DLL_NOT_FOUND);
--- a/pidgin/win32/wspell.c	Fri Aug 20 08:35:27 2010 +0000
+++ b/pidgin/win32/wspell.c	Mon Sep 13 09:57:03 2010 +0000
@@ -73,25 +73,29 @@
 static void load_gtkspell() {
 	UINT old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
 	gchar *tmp, *tmp2;
+
 	const char *path = g_getenv("PATH");
 	tmp = g_build_filename(wpurple_install_dir(), "spellcheck", NULL);
-	tmp2 = g_strdup_printf("%s%s%s", (path ? path : ""),
+	tmp2 = g_strdup_printf("%s%s%s", tmp,
 		(path ? G_SEARCHPATH_SEPARATOR_S : ""),
-		tmp);
+		(path ? path : ""));
 	g_free(tmp);
 	g_setenv("PATH", tmp2, TRUE);
+	g_free(tmp2);
 
+	tmp = g_build_filename(wpurple_install_dir(), "spellcheck", GTKSPELL_DLL, NULL);
 	/* Suppress error popups */
-	wpidginspell_new_attach_proxy = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_new_attach" );
+	wpidginspell_new_attach_proxy = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_new_attach" );
 	if (wpidginspell_new_attach_proxy) {
-		wpidginspell_get_from_text_view = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_get_from_text_view");
-		wpidginspell_detach = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_detach");
-		wpidginspell_set_language = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_set_language");
-		wpidginspell_recheck_all = (void*) wpurple_find_and_loadproc(GTKSPELL_DLL, "gtkspell_recheck_all");
+		wpidginspell_get_from_text_view = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_get_from_text_view");
+		wpidginspell_detach = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_detach");
+		wpidginspell_set_language = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_set_language");
+		wpidginspell_recheck_all = (void*) wpurple_find_and_loadproc(tmp, "gtkspell_recheck_all");
 	} else {
-		purple_debug_warning("wspell", "Couldn't load gtkspell (%s) \n", GTKSPELL_DLL);
+		purple_debug_warning("wspell", "Couldn't load gtkspell (%s) \n", tmp);
 		/*wpidginspell_new_attach = wgtkspell_new_attach;*/
 	}
+	g_free(tmp);
 	SetErrorMode(old_error_mode);
 }
 
--- a/po/af.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/af.po	Mon Sep 13 09:57:03 2010 +0000
@@ -802,7 +802,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Wag vir oordrag om te begin"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Gekanselleer"
 
 msgid "Failed"
@@ -15698,15 +15698,6 @@
 #~ "afkomstig te wees.  Dit kan beteken dat u nie tans aan die diens gekoppel "
 #~ "is wat u dink nie."
 
-#~ msgid "You canceled the transfer of %s"
-#~ msgstr "U het die oordrag van %s gekanselleer"
-
-#~ msgid "%s canceled the transfer of %s"
-#~ msgstr "%s het die oordrag van %s gekanselleer"
-
-#~ msgid "%s canceled the file transfer"
-#~ msgstr "%s het die lêeroordrag gekanselleer"
-
 #~ msgid "Join/Part Hiding Configuration"
 #~ msgstr "Opstelling vir in- en uitgaanversteking"
 
@@ -16292,7 +16283,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Kon nie %s vir skryf open nie!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Lêeroordrag het misluk; ander kant het waarskynlik gekanselleer."
 
 #~ msgid "Could not connect for transfer."
--- a/po/am.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/am.po	Mon Sep 13 09:57:03 2010 +0000
@@ -812,7 +812,7 @@
 msgstr ""
 
 #, fuzzy
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "ተወው"
 
 #, fuzzy
--- a/po/ar.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ar.po	Mon Sep 13 09:57:03 2010 +0000
@@ -791,7 +791,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "في انتظار بدء النقل"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "أُلغِيَ"
 
 msgid "Failed"
@@ -16584,7 +16584,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "لايمكن فتح %s للكتابة!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "فشل ارسال الملف: من المحتمل أن المستقبِل ألغى العملية."
 
 #~ msgid "Could not connect for transfer."
--- a/po/as.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/as.po	Mon Sep 13 09:57:03 2010 +0000
@@ -789,7 +789,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "বিনিময়ৰ আৰম্ভত অপেক্ষা কৰা হৈছে"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "বাতিল কৰা হৈছে"
 
 msgid "Failed"
--- a/po/az.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/az.po	Mon Sep 13 09:57:03 2010 +0000
@@ -809,7 +809,7 @@
 msgid "Waiting for transfer to begin"
 msgstr ""
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr ""
 
 msgid "Failed"
@@ -16008,7 +16008,7 @@
 #~ msgid "Invalid Groupname"
 #~ msgstr "Səhv istifadəçi adı."
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Fayl transferi bacarılmadı, güman ki digər tərəfdən ləğv edildi."
 
 #~ msgid "Could not connect for transfer."
--- a/po/be@latin.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/be@latin.po	Mon Sep 13 09:57:03 2010 +0000
@@ -801,7 +801,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Čakańnie pačatku pieradačy"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Anulavanaja"
 
 msgid "Failed"
@@ -16704,7 +16704,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Niemahčyma adčynić %s dziela zapisu!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Pamyłka pieradačy fajłu; aperacyja, mabyć, anulavanaja z taho boku."
 
 #~ msgid "Could not connect for transfer."
--- a/po/bg.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/bg.po	Mon Sep 13 09:57:03 2010 +0000
@@ -820,7 +820,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Изчакване пренасянето да започне"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Отказан"
 
 msgid "Failed"
@@ -16574,7 +16574,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "%s не може да бъде отворен за запис!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Неуспешен пренос на файла. Получателят вероятно е отказал получаването."
 
--- a/po/bn.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/bn.po	Mon Sep 13 09:57:03 2010 +0000
@@ -843,7 +843,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "স্থানান্তর শুরু করার জন্য অপেক্ষা করা হচ্ছে"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "বাতিল করা হয়েছে"
 
 # mark6
--- a/po/bn_IN.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/bn_IN.po	Mon Sep 13 09:57:03 2010 +0000
@@ -795,7 +795,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "পরিবহণ আরম্ভে অপেক্ষা চলছে"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "বাতিল করা হয়েছে"
 
 msgid "Failed"
--- a/po/bs.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/bs.po	Mon Sep 13 09:57:03 2010 +0000
@@ -822,7 +822,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Cekanje na pocetak transfera"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Otkazano"
 
 msgid "Failed"
@@ -17049,7 +17049,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Nije bilo moguce otvoriti %s za pisanje!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Transfer datoteke je neuspio; druga strana je vjerovatno odustala."
 
 #~ msgid "Could not connect for transfer."
--- a/po/ca.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ca.po	Mon Sep 13 09:57:03 2010 +0000
@@ -834,7 +834,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "S'està esperant a iniciar la transferència"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "S'ha cancel·lat"
 
 msgid "Failed"
@@ -16326,7 +16326,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "No s'ha pogut obrir %s per a escriure-hi."
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Ha fallat la transferència de fitxers. Probablement s'ha cancel·lat a "
 #~ "l'altra banda."
--- a/po/ca@valencia.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ca@valencia.po	Mon Sep 13 09:57:03 2010 +0000
@@ -834,7 +834,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "S'està esperant a iniciar la transferència"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "S'ha cancel·lat"
 
 msgid "Failed"
@@ -16324,7 +16324,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "No s'ha pogut obrir %s per a escriure-hi."
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Ha fallat la transferència de fitxers. Probablement s'ha cancel·lat a "
 #~ "l'altra banda."
--- a/po/cs.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/cs.po	Mon Sep 13 09:57:03 2010 +0000
@@ -793,7 +793,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Čekám na začátek přenosu"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Zrušeno"
 
 msgid "Failed"
@@ -16042,7 +16042,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Nemohu otevřít %s pro zápis!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Přenos souboru selhal; druhá strana jej pravděpodobně přerušila."
 
 #~ msgid "Could not connect for transfer."
--- a/po/da.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/da.po	Mon Sep 13 09:57:03 2010 +0000
@@ -812,7 +812,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Venter på at overførsel skal starte"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Annulleret"
 
 msgid "Failed"
@@ -16489,7 +16489,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Kunne ikke åbne %s til skrivning!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Filoverførsel fejlede - den anden side har sikkert afbrudt."
 
 #~ msgid "Could not connect for transfer."
--- a/po/de.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/de.po	Mon Sep 13 09:57:03 2010 +0000
@@ -11,9 +11,9 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-08-01 00:18+0200\n"
-"PO-Revision-Date: 2010-08-01 00:16+0200\n"
-"Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
+"POT-Creation-Date: 2010-09-02 19:45+0200\n"
+"PO-Revision-Date: 2010-09-06 10:01+0200\n"
+"Last-Translator: Björn Voigt <bjoern@cs.tu-berlin.de>\n"
 "Language-Team: Deutsch <de@li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -813,7 +813,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Warte auf den Beginn der Dateiübertragung"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Abgebrochen"
 
 msgid "Failed"
@@ -4772,11 +4772,17 @@
 msgid "Domain"
 msgstr "Domain"
 
-msgid "Require SSL/TLS"
-msgstr "SSL/TLS voraussetzen"
-
-msgid "Force old (port 5223) SSL"
-msgstr "Erzwinge altes SSL (Port 5223)"
+msgid "Require encryption"
+msgstr "Verschlüsselung fordern"
+
+msgid "Use encryption if available"
+msgstr "Verschlüsselung benutzen, wenn verfügbar"
+
+msgid "Use old-style SSL"
+msgstr "Alte SSL-Methode verwenden"
+
+msgid "Connection security"
+msgstr "Verbindungssicherheit"
 
 msgid "Allow plaintext auth over unencrypted streams"
 msgstr "Erlaube Klartext-Authentifikation über einen unverschlüsselten Kanal"
@@ -7218,96 +7224,6 @@
 msgid "File %s is %s, which is larger than the maximum size of %s."
 msgstr "Datei %s (%s) ist größer als die maximale Größe von %s."
 
-msgid ""
-"(There was an error receiving this message.  The buddy you are speaking with "
-"is probably using a different encoding than expected.  If you know what "
-"encoding he is using, you can specify it in the advanced account options for "
-"your AIM/ICQ account.)"
-msgstr ""
-"(Es gab einen Fehler beim Empfangen dieser Nachricht.  Der Buddy, mit dem "
-"Sie sich unterhalten benutzt wahrscheinlich eine andere Kodierung als "
-"erwartet.  Wenn Sie wissen, welche Kodierung er benutzt, können Sie diese in "
-"den erweiterten Konto-Optionen Ihres AIM/ICQ-Kontos angeben.)"
-
-#, c-format
-msgid ""
-"(There was an error receiving this message.  Either you and %s have "
-"different encodings selected, or %s has a buggy client.)"
-msgstr ""
-"(Es gab einen Fehler beim Empfang dieser Nachricht.  Entweder haben Sie und %"
-"s unterschiedliche Kodierungen gesetzt oder %s hat einen fehlerhaften "
-"Client.)"
-
-#. Label
-msgid "Buddy Icon"
-msgstr "Buddy-Icon"
-
-msgid "Voice"
-msgstr "Stimme"
-
-msgid "AIM Direct IM"
-msgstr "AIM direkte Nachricht"
-
-msgid "Get File"
-msgstr "Datei abrufen"
-
-msgid "Games"
-msgstr "Spiele"
-
-msgid "ICQ Xtraz"
-msgstr "ICQ Xtraz"
-
-msgid "Add-Ins"
-msgstr "Zusätze"
-
-msgid "Send Buddy List"
-msgstr "Buddy-Liste senden"
-
-msgid "ICQ Direct Connect"
-msgstr "ICQ direkte Verbindung"
-
-msgid "AP User"
-msgstr "AP Benutzer"
-
-msgid "ICQ RTF"
-msgstr "ICQ RTF"
-
-msgid "Nihilist"
-msgstr "Nihilist"
-
-msgid "ICQ Server Relay"
-msgstr "ICQ Server Relay"
-
-msgid "Old ICQ UTF8"
-msgstr "Altes ICQ UTF-8"
-
-msgid "Trillian Encryption"
-msgstr "Trillian-Verschlüsselung"
-
-msgid "ICQ UTF8"
-msgstr "ICQ UTF-8"
-
-msgid "Hiptop"
-msgstr "Hiptop"
-
-msgid "Security Enabled"
-msgstr "Sicherheit aktiviert"
-
-msgid "Video Chat"
-msgstr "Video-Chat"
-
-msgid "iChat AV"
-msgstr "iChat AV"
-
-msgid "Live Video"
-msgstr "Live-Video"
-
-msgid "Camera"
-msgstr "Kamera"
-
-msgid "Screen Sharing"
-msgstr "Gemeinsamer Bildschirm"
-
 msgid "Free For Chat"
 msgstr "Bereit zum Chatten"
 
@@ -7338,15 +7254,6 @@
 msgid "At lunch"
 msgstr "Zur Mittagspause"
 
-msgid "IP Address"
-msgstr "IP-Adresse"
-
-msgid "Warning Level"
-msgstr "Warnstufe"
-
-msgid "Buddy Comment"
-msgstr "Buddy-Kommentar"
-
 #, c-format
 msgid "Unable to connect to authentication server: %s"
 msgstr "Verbindung zum Authentifizierungsserver nicht möglich: %s"
@@ -7446,17 +7353,6 @@
 msgid "Unable to initialize connection"
 msgstr "Kann Verbindung nicht erstellen"
 
-msgid "Please authorize me so I can add you to my buddy list."
-msgstr ""
-"Bitte autorisieren Sie mich, sodass ich Sie in meine Buddy-Liste aufnehmen "
-"kann."
-
-msgid "No reason given."
-msgstr "Kein Grund angegeben."
-
-msgid "Authorization Denied Message:"
-msgstr "Nachricht für die Ablehnung der Autorisierung:"
-
 #, c-format
 msgid ""
 "The user %u has denied your request to add them to your buddy list for the "
@@ -7467,6 +7363,9 @@
 "Liste hinzufügen zu dürfen, und zwar aus folgendem Grund:\n"
 "%s"
 
+msgid "No reason given."
+msgstr "Kein Grund angegeben."
+
 msgid "ICQ authorization denied."
 msgstr "ICQ-Autorisierung verweigert."
 
@@ -7582,60 +7481,13 @@
 msgstr[1] ""
 "Sie haben %hu Nachrichten von %s aus unbekannten Gründen nicht erhalten."
 
-#, c-format
-msgid "User information not available: %s"
-msgstr "Benutzerinformation nicht verfügbar: %s"
-
-msgid "Online Since"
-msgstr "Online seit"
-
-msgid "Member Since"
-msgstr "Mitglied seit"
-
-msgid "Capabilities"
-msgstr "Fähigkeiten"
-
 msgid "Your AIM connection may be lost."
 msgstr "Ihre AIM-Verbindung könnte unterbrochen sein."
 
-#. The conversion failed!
-msgid ""
-"[Unable to display a message from this user because it contained invalid "
-"characters.]"
-msgstr ""
-"[Kann die Nachricht von diesem Benutzer nicht anzeigen, da sie ungültige "
-"Zeichen enthält.]"
-
 #, c-format
 msgid "You have been disconnected from chat room %s."
 msgstr "Die Verbindung zum Raum %s wurde unterbrochen."
 
-msgid "Mobile Phone"
-msgstr "Handynummer"
-
-msgid "Personal Web Page"
-msgstr "Persönliche Webseite"
-
-#. aim_userinfo_t
-#. strip_html_tags
-msgid "Additional Information"
-msgstr "Zusätzliche Informationen"
-
-msgid "Zip Code"
-msgstr "PLZ"
-
-msgid "Work Information"
-msgstr "Information (Arbeit)"
-
-msgid "Division"
-msgstr "Abteilung"
-
-msgid "Position"
-msgstr "Position"
-
-msgid "Web Page"
-msgstr "Webseite"
-
 msgid "Pop-Up Message"
 msgstr "Pop-Up Nachricht"
 
@@ -7922,8 +7774,8 @@
 msgid "Change Address To:"
 msgstr "Ändere die Adresse zu:"
 
-msgid "<i>you are not waiting for authorization</i>"
-msgstr "<i>Sie warten derzeit auf keine Autorisierungen</i>"
+msgid "you are not waiting for authorization"
+msgstr "Sie warten derzeit auf keine Autorisierungen"
 
 msgid "You are awaiting authorization from the following buddies"
 msgstr "Sie warten auf Autorisierung von den folgenden Buddys"
@@ -7978,9 +7830,6 @@
 msgid "Search for Buddy by Email Address..."
 msgstr "Suche Buddys nach E-Mail-Adresse..."
 
-msgid "Search for Buddy by Information"
-msgstr "Suche Buddy nach Information"
-
 msgid "Use clientLogin"
 msgstr "clientLogin benutzen"
 
@@ -8268,8 +8117,8 @@
 msgstr "Ihre Anfrage wurde abgelehnt."
 
 #, c-format
-msgid "%u requires verification"
-msgstr "%u erfordert Autorisierung"
+msgid "%u requires verification: %s"
+msgstr "%u erfordert Überprüfung: %s"
 
 msgid "Add buddy question"
 msgstr "Buddy-Frage hinzufügen"
@@ -10146,6 +9995,9 @@
 msgid "Computer"
 msgstr "Computer"
 
+msgid "Mobile Phone"
+msgstr "Handynummer"
+
 msgid "PDA"
 msgstr "PDA"
 
@@ -10580,6 +10432,9 @@
 msgid "Write Error"
 msgstr "Schreibfehler"
 
+msgid "IP Address"
+msgstr "IP-Adresse"
+
 msgid "Yahoo! Japan Profile"
 msgstr "Yahoo!-Japan-Profil"
 
@@ -10621,6 +10476,9 @@
 msgid "Cool Link 3"
 msgstr "Cooler Link 3"
 
+msgid "Member Since"
+msgstr "Mitglied seit"
+
 msgid "Last Update"
 msgstr "Letzte Aktualisierung"
 
@@ -11247,6 +11105,11 @@
 "Listenfenster zu diesem Dialog zurückkehren und Konten hinzufügen, "
 "bearbeiten oder löschen"
 
+#, c-format
+msgid "%s%s%s%s wants to add you (%s) to his or her buddy list%s%s"
+msgstr ""
+"%s%s%s%s möchte Sie (%s) zu seiner oder ihrer Buddy-Liste hinzufügen%s%s"
+
 #. Buddy List
 msgid "Background Color"
 msgstr "Hintergrundfarbe"
@@ -11506,6 +11369,8 @@
 msgid "Edit User Mood"
 msgstr "Benutzerstimmung ändern"
 
+#. NOTE: Do not set any accelerator to Control+O. It is mapped by
+#. gtk_blist_key_press_cb to "Get User Info" on the selected buddy.
 #. Buddies menu
 msgid "/_Buddies"
 msgstr "/_Buddys"
@@ -13648,6 +13513,9 @@
 msgid "_TURN server:"
 msgstr "_TURN-Server:"
 
+msgid "_UDP Port:"
+msgstr "_UDP-Port:"
+
 msgid "Use_rname:"
 msgstr "_Benutzername:"
 
@@ -14143,6 +14011,10 @@
 "<b>Dateigröße:</b> %s\n"
 "<b>Bildgröße:</b> %dx%d"
 
+#. Label
+msgid "Buddy Icon"
+msgstr "Buddy-Icon"
+
 #, c-format
 msgid "The file '%s' is too large for %s.  Please try a smaller image.\n"
 msgstr ""
@@ -14228,7 +14100,7 @@
 msgid "Small"
 msgstr "Klein"
 
-msgid "Smaller versions of the default smilies"
+msgid "Smaller versions of the default smileys"
 msgstr "Kleinere Versionen der Default-Smileys"
 
 msgid "Response Probability:"
@@ -15079,6 +14951,9 @@
 msgid "Half Operator"
 msgstr "Half-Operator"
 
+msgid "Voice"
+msgstr "Stimme"
+
 msgid "Authorization dialog"
 msgstr "Autorisierungsdialog"
 
@@ -15268,6 +15143,9 @@
 msgid "Voice/Video Settings"
 msgstr "Sprach-/Video-Einstellungen"
 
+msgid "Voice and Video Settings"
+msgstr "Sprach- und Video-Einstellungen"
+
 #. *< name
 #. *< version
 msgid "Configure your microphone and webcam."
@@ -15397,7 +15275,7 @@
 msgstr ""
 "Dieses Plugin ist nützlich zur Fehlersuche in XMPP-Servern oder -Clients."
 
-#. $(^Name) is the current Version name (e.g. Pidgin 2.7.0).  $_CLICK will become a translated version of "Click Next to continue."
+#. $(^Name) is the current Version name (e.g. Pidgin 2.7.0).  $_CLICK will become a translated version of "Click Next to continue."  DO NOT translate the CLICK in $_CLICK.  It will break the installer.
 msgid ""
 "$(^Name) is released under the GNU General Public License (GPL). The license "
 "is provided here for information purposes only. $_CLICK"
--- a/po/dz.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/dz.po	Mon Sep 13 09:57:03 2010 +0000
@@ -818,7 +818,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "གནས་སོར་འགོ་བཙུགས་ནིའི་དོན་ལུ་བསྒུག་དོ།"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "ཆ་མེད་བཏང་ཡི།"
 
 msgid "Failed"
@@ -16889,7 +16889,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "བྲིས་ནིའི་དོན་ལུ %s ཁ་ཕྱེ་མ་ཚུགས།"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "ཡིག་སྣོད་གནས་སོར་འཐུས་ཤོར་བྱུང་ནུག ཕྱོགས་གཞན་མི་འདི་ཆ་མེད་བཏང་ཡི།"
 
 #~ msgid "Could not connect for transfer."
--- a/po/el.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/el.po	Mon Sep 13 09:57:03 2010 +0000
@@ -804,7 +804,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Αναμονή έναρξης μεταφοράς"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Ακυρώθηκε"
 
 msgid "Failed"
@@ -16284,7 +16284,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Αδύνατο το άνοιγμα του %s για εγγραφή!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Αποτυχία μεταφοράς αρχείου. Πιθανώς να ακυρώθηκε από την άλλη πλευρά."
 
--- a/po/en_AU.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/en_AU.po	Mon Sep 13 09:57:03 2010 +0000
@@ -834,8 +834,8 @@
 msgid "Waiting for transfer to begin"
 msgstr "Waiting for transfer to begin"
 
-msgid "Canceled"
-msgstr "Canceled"
+msgid "Cancelled"
+msgstr "Cancelled"
 
 msgid "Failed"
 msgstr "Failed"
@@ -2128,14 +2128,14 @@
 
 #, fuzzy, c-format
 msgid "You cancelled the transfer of %s"
-msgstr "You canceled the transfer of %s"
+msgstr "You cancelled the transfer of %s"
 
 msgid "File transfer cancelled"
 msgstr "File transfer cancelled"
 
 #, fuzzy, c-format
 msgid "%s cancelled the transfer of %s"
-msgstr "%s canceled the transfer of %s"
+msgstr "%s cancelled the transfer of %s"
 
 #, fuzzy, c-format
 msgid "%s cancelled the file transfer"
@@ -9265,7 +9265,7 @@
 
 #, fuzzy, c-format
 msgid "%d cancelled the transfer of %s"
-msgstr "%s canceled the transfer of %s"
+msgstr "%s cancelled the transfer of %s"
 
 #, fuzzy, c-format
 msgid "<b>Group Title:</b> %s<br>"
@@ -9346,7 +9346,7 @@
 
 #, fuzzy
 msgid "Place Closed"
-msgstr "Canceled"
+msgstr "Cancelled"
 
 msgid "Microphone"
 msgstr ""
@@ -17062,8 +17062,8 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Could not open %s for writing!"
 
-#~ msgid "File transfer failed; other side probably canceled."
-#~ msgstr "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
+#~ msgstr "File transfer failed; other side probably cancelled."
 
 #~ msgid "Could not connect for transfer."
 #~ msgstr "Could not connect for transfer."
--- a/po/en_CA.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/en_CA.po	Mon Sep 13 09:57:03 2010 +0000
@@ -834,7 +834,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Waiting for transfer to begin"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Cancelled"
 
 msgid "Failed"
@@ -17050,7 +17050,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Could not open %s for writing!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "File transfer failed; other side probably cancelled."
 
 #~ msgid "Could not connect for transfer."
--- a/po/en_GB.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/en_GB.po	Mon Sep 13 09:57:03 2010 +0000
@@ -793,7 +793,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Waiting for transfer to begin"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Cancelled"
 
 msgid "Failed"
--- a/po/eo.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/eo.po	Mon Sep 13 09:57:03 2010 +0000
@@ -766,7 +766,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Atendante la alŝutoeko"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Rezignita"
 
 msgid "Failed"
--- a/po/es.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/es.po	Mon Sep 13 09:57:03 2010 +0000
@@ -916,7 +916,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Esperando el comienzo de la transferencia"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Cancelado"
 
 msgid "Failed"
--- a/po/et.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/et.po	Mon Sep 13 09:57:03 2010 +0000
@@ -795,7 +795,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Oodatakse ülekande algust"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Tühistatud"
 
 msgid "Failed"
@@ -16081,7 +16081,7 @@
 #~ msgid "Password Change Successful"
 #~ msgstr "Paroolimuutmine õnnestus"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Tõrge ülekandmisel, ilmselt tühistas teine pool ülekande."
 
 #~ msgid "Could not connect for transfer."
--- a/po/eu.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/eu.po	Mon Sep 13 09:57:03 2010 +0000
@@ -801,7 +801,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Transferentzia hasteko zain"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Bertan behera utzi da"
 
 msgid "Failed"
@@ -16340,7 +16340,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Ezin izan da %s ireki idazteko!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Fitxategi-transferentziak huts egin du; beste aldekoak beharbada bertan "
 #~ "behera utziko zuen."
--- a/po/fa.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/fa.po	Mon Sep 13 09:57:03 2010 +0000
@@ -808,7 +808,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "در حال انتظار برای آغاز انتقال"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "صرف نظر شد"
 
 msgid "Failed"
@@ -16683,7 +16683,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "نمی‌توان %s را برای نوشتن باز کرد!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "انتقال پرونده شکست خورد؛ احتمالاً طرف دیگر انصراف داده است."
 
 #~ msgid "Could not connect for transfer."
--- a/po/fi.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/fi.po	Mon Sep 13 09:57:03 2010 +0000
@@ -802,7 +802,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Odotetaan lähetyksen alkamista"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Peruutettu"
 
 msgid "Failed"
@@ -16262,7 +16262,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "%s:n avaaminen kirjoitusta varten epäonnistui!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Tiedostonsiirto epäonnistui. Toinen osapuoli luultavasti katkaisi siirron."
 
@@ -17459,7 +17459,7 @@
 #~ msgid "Your request to send file[%s] has been rejected by buddy[%d]"
 #~ msgstr "Pyyntösi lähettää tiedosto (%s) one evätty tuttavan (%d) toimesta"
 
-#~ msgid "The sending process of file[%s] has been canceled by buddy[%d]"
+#~ msgid "The sending process of file[%s] has been cancelled by buddy[%d]"
 #~ msgstr "Tiedoston (%s) lähetys on peruutettu tuttavan (%d) toimesta"
 
 #~ msgid "Blink tray icon for unread..."
--- a/po/fr.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/fr.po	Mon Sep 13 09:57:03 2010 +0000
@@ -821,7 +821,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "En attente de début de transfert"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Annulé"
 
 msgid "Failed"
@@ -16009,7 +16009,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Impossible d'ouvrir %s pour l'écriture"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Échec du transfert de fichier. Annulation probable du correspondant."
 
--- a/po/ga.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ga.po	Mon Sep 13 09:57:03 2010 +0000
@@ -750,7 +750,7 @@
 msgstr ""
 
 #, fuzzy
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Cealaithe"
 
 #, fuzzy
--- a/po/gl.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/gl.po	Mon Sep 13 09:57:03 2010 +0000
@@ -807,7 +807,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Agardando o comezo da transferencia"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Cancelado"
 
 msgid "Failed"
--- a/po/gu.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/gu.po	Mon Sep 13 09:57:03 2010 +0000
@@ -789,7 +789,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "પરિવહન શરૂ થવા માટે રાહ જોઈ રહ્યા છીએ"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "રદ થયેલ"
 
 msgid "Failed"
--- a/po/he.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/he.po	Mon Sep 13 09:57:03 2010 +0000
@@ -781,7 +781,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "ממתין להעברה להתחיל"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "בוטל"
 
 msgid "Failed"
--- a/po/hi.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/hi.po	Mon Sep 13 09:57:03 2010 +0000
@@ -780,7 +780,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "हस्तांतरण के शुरु होने की प्रतीक्षा करता है."
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "रद्द"
 
 msgid "Failed"
--- a/po/hu.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/hu.po	Mon Sep 13 09:57:03 2010 +0000
@@ -804,7 +804,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Várakozás az átvitel indulására"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Megszakítva"
 
 msgid "Failed"
--- a/po/hy.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/hy.po	Mon Sep 13 09:57:03 2010 +0000
@@ -755,7 +755,7 @@
 msgid "Waiting for transfer to begin"
 msgstr ""
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr ""
 
 msgid "Failed"
--- a/po/id.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/id.po	Mon Sep 13 09:57:03 2010 +0000
@@ -815,7 +815,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Menunggu transfer untuk mulai"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Dibatalkan"
 
 msgid "Failed"
@@ -16769,7 +16769,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "%s tidak dapat dibuka untuk penulisan!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Transfer file gagal; sisi lainnya kemungkinan membatalkan."
 
 #~ msgid "Could not connect for transfer."
--- a/po/it.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/it.po	Mon Sep 13 09:57:03 2010 +0000
@@ -808,7 +808,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "In attesa dell'inizio del trasferimento"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Annullato"
 
 msgid "Failed"
--- a/po/ja.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ja.po	Mon Sep 13 09:57:03 2010 +0000
@@ -808,7 +808,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "転送開始を待っています"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "キャンセルしました"
 
 msgid "Failed"
@@ -16759,7 +16759,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "書き込みモードで %s を開けません!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "ファイル転送が失敗しました。おそらく向こう側がキャンセルしたのでしょう。"
 
--- a/po/ka.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ka.po	Mon Sep 13 09:57:03 2010 +0000
@@ -807,7 +807,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "ველოდები გადატანის დაწყებას"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "გაუქმებულია"
 
 #, fuzzy
--- a/po/km.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/km.po	Mon Sep 13 09:57:03 2010 +0000
@@ -777,7 +777,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "រង់ចាំ​ការ​ផ្ទេរ​ចាប់ផ្ដើម"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "បានបោះបង់"
 
 msgid "Failed"
--- a/po/kn.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/kn.po	Mon Sep 13 09:57:03 2010 +0000
@@ -802,7 +802,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "ವರ್ಗಾವಣೆಯ ಪ್ರಾರಂಭಕ್ಕಾಗಿ ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "ರದ್ದಾಗಿದೆ"
 
 msgid "Failed"
@@ -15930,7 +15930,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "ಬರೆಯುವದಕ್ಕಾಗಿ  %s ತೆರೆಯಲು ಆಗಲಿಲ್ಲ"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "ಕಡತ ವರ್ಗಾವಣೆ ವಿಫಲ ; ಬಹುಶ: ಆಚೆಯವರು ರದ್ದು ಮಾಡಿದರು"
 
 #~ msgid "Could not connect for transfer."
--- a/po/ko.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ko.po	Mon Sep 13 09:57:03 2010 +0000
@@ -816,7 +816,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "전송 시작을 기다리고 있습니다."
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "취소되었습니다."
 
 msgid "Failed"
@@ -16691,7 +16691,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "쓰기 모드에서 %s 을(를) 열 수 없습니다!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "파일 전송에 실패했습니다. 아마도 상대측에서 취소한 것 같습니다."
 
 #~ msgid "Could not connect for transfer."
--- a/po/ku.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ku.po	Mon Sep 13 09:57:03 2010 +0000
@@ -828,7 +828,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Li benda destpêkirina transferê ye"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Hate Betalkirin"
 
 msgid "Failed"
--- a/po/lo.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/lo.po	Mon Sep 13 09:57:03 2010 +0000
@@ -744,7 +744,7 @@
 msgid "Waiting for transfer to begin"
 msgstr ""
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr ""
 
 msgid "Failed"
--- a/po/lt.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/lt.po	Mon Sep 13 09:57:03 2010 +0000
@@ -826,7 +826,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Laukiama perdavimo pradžios"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Atšaukta"
 
 msgid "Failed"
--- a/po/mk.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/mk.po	Mon Sep 13 09:57:03 2010 +0000
@@ -806,7 +806,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Чекам да започне преносот"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Откажано"
 
 msgid "Failed"
@@ -16667,7 +16667,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Не можам да ја отворам %s за запишување!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Размената на датотека не успеа. Другата страна веројатно откажа."
 
 #~ msgid "Could not connect for transfer."
--- a/po/ml.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ml.po	Mon Sep 13 09:57:03 2010 +0000
@@ -788,7 +788,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "ഇടപാടു് ആരംഭിക്കുന്നതിനായി കാത്തിരിക്കുന്നു"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "റദ്ദാക്കിയിരിക്കുന്നു"
 
 msgid "Failed"
--- a/po/mn.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/mn.po	Mon Sep 13 09:57:03 2010 +0000
@@ -774,7 +774,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Файл шилжүүлэлт эхлүүлэхийг хүлээж байна"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Цуцлагдсан"
 
 msgid "Failed"
@@ -15602,7 +15602,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Завсар хийхээр %sийг нээж чадсангүй!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Файл дамжуулалт амжилттгүй боллоо."
 
 #~ msgid "Could not connect for transfer."
--- a/po/mr.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/mr.po	Mon Sep 13 09:57:03 2010 +0000
@@ -779,7 +779,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "स्थानांतर सुरू करण्याची प्रतिक्षा करत आहे"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "रद्द केले"
 
 msgid "Failed"
--- a/po/ms_MY.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ms_MY.po	Mon Sep 13 09:57:03 2010 +0000
@@ -741,7 +741,7 @@
 msgid "Waiting for transfer to begin"
 msgstr ""
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr ""
 
 msgid "Failed"
--- a/po/my_MM.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/my_MM.po	Mon Sep 13 09:57:03 2010 +0000
@@ -834,7 +834,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Waiting for transfer to begin"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Cancelled"
 
 msgid "Failed"
@@ -17057,7 +17057,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Could not open %s for writing!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "File transfer failed; other side probably cancelled."
 
 #~ msgid "Could not connect for transfer."
--- a/po/nb.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/nb.po	Mon Sep 13 09:57:03 2010 +0000
@@ -803,7 +803,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Venter på at overføringen skal starte"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Avbrutt"
 
 msgid "Failed"
@@ -16208,7 +16208,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Klarte ikke åpne %s for skriving!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Filoverføringen mislyktes - sannsynligvis avbrutt på den andre siden."
 
--- a/po/ne.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ne.po	Mon Sep 13 09:57:03 2010 +0000
@@ -824,7 +824,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "स्थानान्तरण सुरू गर्नकोलागि पर्खिरहेको"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "रद्द गरियो"
 
 msgid "Failed"
@@ -17025,7 +17025,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "लेख्नका लागि %s खोल्न सकिदैन!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "फाइल स्थान्तरणमा असफल; अन्य साइड सम्भवत: रद्द गरियो ।"
 
 #~ msgid "Could not connect for transfer."
--- a/po/nl.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/nl.po	Mon Sep 13 09:57:03 2010 +0000
@@ -804,7 +804,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Wacht op starten van overdracht"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Geannuleerd"
 
 msgid "Failed"
--- a/po/nn.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/nn.po	Mon Sep 13 09:57:03 2010 +0000
@@ -797,7 +797,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Ventar på at overføringa skal begynna"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Avbroten"
 
 msgid "Failed"
--- a/po/oc.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/oc.po	Mon Sep 13 09:57:03 2010 +0000
@@ -754,7 +754,7 @@
 msgid "Waiting for transfer to begin"
 msgstr ""
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Anullat"
 
 msgid "Failed"
--- a/po/or.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/or.po	Mon Sep 13 09:57:03 2010 +0000
@@ -799,7 +799,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "ସ୍ଥାନାନ୍ତରଣ ଆରମ୍ଭ ହେବାକୁ ଅପେକ୍ଷା କରୁଛି"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "ବାତିଲ କରାଗଲା"
 
 msgid "Failed"
--- a/po/pa.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/pa.po	Mon Sep 13 09:57:03 2010 +0000
@@ -784,7 +784,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "ਭੇਜਣ ਸ਼ੁਰੂ ਕਰਨ ਦੀ ਉਡੀਕ ਜਾਰੀ"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "ਰੱਦ ਹੈ"
 
 msgid "Failed"
@@ -15891,7 +15891,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "%s ਨੂੰ ਲਿਖਣ ਲਈ ਖੋਲਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "ਫਾਇਲ ਸੰਚਾਰ ਅਸਫਲ ਹੈ; ਦੂਜੇ ਪਾਸੇ ਤੋਂ ਰੱਦ ਕੀਤਾ ਗਿਆ ਹੈ।"
 
 #~ msgid "Could not connect for transfer."
--- a/po/pl.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/pl.po	Mon Sep 13 09:57:03 2010 +0000
@@ -818,7 +818,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Oczekiwanie na rozpoczęcie przesyłu"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Anulowano"
 
 msgid "Failed"
--- a/po/ps.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ps.po	Mon Sep 13 09:57:03 2010 +0000
@@ -779,7 +779,7 @@
 msgid "Waiting for transfer to begin"
 msgstr ""
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "فسخ شوه"
 
 msgid "Failed"
--- a/po/pt.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/pt.po	Mon Sep 13 09:57:03 2010 +0000
@@ -843,7 +843,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Esperando que a transferência comece"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Cancelado"
 
 msgid "Failed"
@@ -17029,7 +17029,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Não foi possível abrir %s para escrita!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Tranferência de ficheiro falhou; o outro lado provavelmente cancelou-a."
 
--- a/po/pt_BR.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/pt_BR.po	Mon Sep 13 09:57:03 2010 +0000
@@ -804,7 +804,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Esperando o começo da transferência"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Cancelada"
 
 msgid "Failed"
@@ -16432,7 +16432,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Não foi possível abrir %s para escrita!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Transferência de arquivo falhou; o outro lado provavelmente cancelou-a."
 
--- a/po/ro.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ro.po	Mon Sep 13 09:57:03 2010 +0000
@@ -807,7 +807,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Se așteaptă începerea transferului"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Oprit"
 
 msgid "Failed"
--- a/po/ru.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ru.po	Mon Sep 13 09:57:03 2010 +0000
@@ -807,7 +807,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Ожидание начала передачи"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Отменено"
 
 msgid "Failed"
@@ -16446,7 +16446,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Не удалось открыть %s для записи!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Не удалось произвести передачу файлов; вероятно, отменили на той стороне."
 
--- a/po/si.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/si.po	Mon Sep 13 09:57:03 2010 +0000
@@ -757,7 +757,7 @@
 msgid "Waiting for transfer to begin"
 msgstr ""
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "අහෝසි කරන්න"
 
 msgid "Failed"
--- a/po/sk.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/sk.po	Mon Sep 13 09:57:03 2010 +0000
@@ -803,7 +803,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Čaká sa na začiatok prenosu"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Zrušené"
 
 msgid "Failed"
@@ -16124,7 +16124,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Nepodarilo sa otvoriť %s pre zápis!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Prenos súboru zlyhal; druhá strana ho asi zrušila."
 
 #~ msgid "Could not connect for transfer."
--- a/po/sl.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/sl.po	Mon Sep 13 09:57:03 2010 +0000
@@ -812,7 +812,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Čakanje na začetek prenosa"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Preklicano"
 
 msgid "Failed"
--- a/po/sq.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/sq.po	Mon Sep 13 09:57:03 2010 +0000
@@ -814,7 +814,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Po pritet të fillojë shpërngulja"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Anuluar"
 
 msgid "Failed"
--- a/po/sr.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/sr.po	Mon Sep 13 09:57:03 2010 +0000
@@ -791,7 +791,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Чекам да пренос почне"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Откажи"
 
 msgid "Failed"
@@ -16453,7 +16453,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Не могу да отворим %s за упис!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Неуспешан пренос датотеке; друга страна је вероватно отказала."
 
 #~ msgid "Could not connect for transfer."
--- a/po/sr@latin.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/sr@latin.po	Mon Sep 13 09:57:03 2010 +0000
@@ -792,7 +792,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Čekam da prenos počne"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Otkaži"
 
 msgid "Failed"
@@ -16471,7 +16471,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Ne mogu da otvorim %s za upis!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "Neuspešan prenos datoteke; druga strana je verovatno otkazala."
 
 #~ msgid "Could not connect for transfer."
--- a/po/sv.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/sv.po	Mon Sep 13 09:57:03 2010 +0000
@@ -797,7 +797,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Väntar på att överföringen ska inledas"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Avbruten"
 
 msgid "Failed"
@@ -16135,7 +16135,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Kunde inte öppna %s för läsning!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Filöverföringen misslyckades, antagligen eftersom andra sidan avbröt."
 
--- a/po/sw.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/sw.po	Mon Sep 13 09:57:03 2010 +0000
@@ -784,7 +784,7 @@
 msgid "Waiting for transfer to begin"
 msgstr ""
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Imeghairishwa"
 
 msgid "Failed"
--- a/po/ta.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ta.po	Mon Sep 13 09:57:03 2010 +0000
@@ -795,7 +795,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "பரிமாற்றம் ஆரம்பமாவதற்காக காத்திருக்கிறது"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "தவிர்க்கப்பட்டது"
 
 msgid "Failed"
@@ -16101,7 +16101,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "%s யை எழுதுவதற்காக திறக்கமுடியவில்லை!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "கோப்பு அனுப்புதலில் பிழை; ஒருவேளை மறுபக்கத்தில் தவிர்த்திருக்கலாம்."
 
 #~ msgid "Could not connect for transfer."
--- a/po/te.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/te.po	Mon Sep 13 09:57:03 2010 +0000
@@ -787,7 +787,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "ప్రారంభించడానికి బదిలీ కోసం నిరీక్షణ "
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "రద్దుచేయి"
 
 msgid "Failed"
--- a/po/th.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/th.po	Mon Sep 13 09:57:03 2010 +0000
@@ -804,7 +804,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "กำลังรอการรับส่งแฟ้ม"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "ยกเลิก"
 
 msgid "Failed"
--- a/po/tr.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/tr.po	Mon Sep 13 09:57:03 2010 +0000
@@ -805,7 +805,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Aktarımın başlaması bekleniyor"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "İptal Edildi"
 
 msgid "Failed"
@@ -16367,7 +16367,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "%s yazma için açılamıyor!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Dosya transferi gerçekleştirilemedi; karşı taraf iptal etmiş olabilir."
 
--- a/po/uk.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/uk.po	Mon Sep 13 09:57:03 2010 +0000
@@ -809,7 +809,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Очікування початку передачі"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Скасовано"
 
 msgid "Failed"
--- a/po/ur.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/ur.po	Mon Sep 13 09:57:03 2010 +0000
@@ -815,7 +815,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "ٹرانسفر ہونے کے لئے انتظار کررہا ہے"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr " منسوخ کیا گیا"
 
 msgid "Failed"
@@ -16800,7 +16800,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "لکھنے کے لئے %s کھول نہیں سکا!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "فائل ٹرانسفر ناکام ہوا؛یا ممکن ہے دوسری حانب منسوخ ہوا ہے۔"
 
 #~ msgid "Could not connect for transfer."
--- a/po/vi.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/vi.po	Mon Sep 13 09:57:03 2010 +0000
@@ -805,7 +805,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Đợi bắt đầu truyền"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "Bị thôi"
 
 msgid "Failed"
--- a/po/xh.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/xh.po	Mon Sep 13 09:57:03 2010 +0000
@@ -843,7 +843,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "Ulindele ukuba ukudlulisa kuqalise"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "IRhoxisiwe"
 
 msgid "Failed"
@@ -17192,7 +17192,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "Akukwazekanga ukuvula i-%s malunga nokubhala!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr ""
 #~ "Ukudluliswa kwefayili akuphumelelanga; mhlawumbi elinye icala licinyiwe."
 
--- a/po/zh_CN.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/zh_CN.po	Mon Sep 13 09:57:03 2010 +0000
@@ -777,7 +777,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "正在等待传送开始"
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "已取消"
 
 msgid "Failed"
@@ -15530,7 +15530,7 @@
 #~ msgid "Could not open %s for writing!"
 #~ msgstr "无法打开 %s 写入!"
 
-#~ msgid "File transfer failed; other side probably canceled."
+#~ msgid "File transfer failed; other side probably cancelled."
 #~ msgstr "文件传送失败;可能其中一端取消了传送。"
 
 #~ msgid "Could not connect for transfer."
--- a/po/zh_HK.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/zh_HK.po	Mon Sep 13 09:57:03 2010 +0000
@@ -868,7 +868,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "等待開始傳輸檔案中..."
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "已取消"
 
 msgid "Failed"
--- a/po/zh_TW.po	Fri Aug 20 08:35:27 2010 +0000
+++ b/po/zh_TW.po	Mon Sep 13 09:57:03 2010 +0000
@@ -866,7 +866,7 @@
 msgid "Waiting for transfer to begin"
 msgstr "等待開始傳輸檔案中..."
 
-msgid "Canceled"
+msgid "Cancelled"
 msgstr "已取消"
 
 msgid "Failed"