changeset 31626:11e629e6c23d

propagate from branch 'im.pidgin.pidgin' (head 075c2902b90abb6349a6b689e26fa0ecf720ca04) to branch 'im.pidgin.pidgin.mxit' (head 3d58b1f843fc2aebf9411756956d07ae96951623)
author andrew.victor@mxit.com
date Tue, 26 Apr 2011 13:43:24 +0000
parents b671728e6ee9 (diff) 000aac6e42fe (current diff)
children 64da22357346
files ChangeLog
diffstat 27 files changed, 502 insertions(+), 237 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Apr 18 21:20:33 2011 +0000
+++ b/ChangeLog	Tue Apr 26 13:43:24 2011 +0000
@@ -13,9 +13,12 @@
 	  on the fly. (Jakub Adam) (half of #13535)
 	* Don't cancel an ongoing call when rejecting the addition of a stream to
 	  the existing call. (Jakub Adam) (#13537)
+	* Pidgin plugins can now override tab completion and detect clicks on
+	  usernames in the chat userlist. (kawaii.neko) (#12599)
 
 	libpurple:
-	* media: Allow obtaining active local and remote candidates. (#11830)
+	* media: Allow obtaining active local and remote candidates. (Jakub
+	  Adam) (#11830)
 	* media: Allow getting/setting video capabilities. (Jakub Adam) (half of
 	  #13095)
 	* Simple Silence Suppression is optional per-account. (Jakub Adam) (half
@@ -41,6 +44,13 @@
 	* Require libgadu 1.10.1 to avoid using internal libgadu.
 	* SSL connection support for GNUTLS users (not on Windows yet!).
 	  (Tomasz Wasilczyk) (#13613)
+	* Don't count received messages or statuses when determining whether
+	  to send a keepalive packet. (Jan Zachorowski) (#13699)
+	* Fix a crash when receiving images on Windows or an incorrect
+	  timestamp in the log when receiving images on Linux. (Tomasz
+	  Wasilczyk) (#10268)
+	* Support XML events, resulting in immediate update of other users'
+	  buddy icons. (Tomasz Wasilczyk) (#13739)
 
 	ICQ:
 	* Fix unsetting your mood when "None" is selected.  (Dustin Gathmann)
--- a/ChangeLog.API	Mon Apr 18 21:20:33 2011 +0000
+++ b/ChangeLog.API	Tue Apr 26 13:43:24 2011 +0000
@@ -8,27 +8,38 @@
 		* cleared-message-history signal (conversation signals)
 		* purple_account_add_buddy_with_invite
 		* purple_account_add_buddies_with_invite
+		* purple_dnsquery_a_account
 		* purple_notify_user_info_add_pair_plaintext
 		* purple_media_get_active_local_candidates
 		* purple_media_get_active_remote_candidates
 		* purple_media_manager_get_video_caps (Jakub Adam) (#13095)
 		* purple_media_manager_set_video_caps (Jakub Adam) (#13095)
 		* purple_pounce_destroy_all_by_buddy (Kartik Mohta) (#1131)
+		* purple_proxy_connect_socks5_account
+		* purple_srv_resolve_account
+		* purple_txt_resolve_account
 		* Added add_buddy_with_invite to PurplePluginProtocolInfo
 		* Added add_buddies_with_invite to PurplePluginProtocolInfo
 		* Added PurpleSrvTxtQueryUiOps which allow UIs to specify their
 		  own mechanisms to resolve SRV and/or TXT queries. It works
 		  similar to PurpleDnsQueryUiOps
+		* purple_marshal_BOOLEAN__POINTER_BOOLEAN (kawaii.neko) (#12599)
 
 		Deprecated:
 		* purple_account_add_buddy
 		* purple_account_add_buddies_with_invite
+		* purple_dnsquery_a
+		* purple_proxy_connect_socks5
+		* purple_srv_resolve
+		* purple_txt_resolve
 		* add_buddy from PurplePluginProtocolInfo struct
 		* add_buddies from PurplePluginProtocolInfo struct
 
 	Pidgin:
 		Added:
 		* pidgin_make_scrollable (Gabriel Schulhof) (#10599)
+		* chat-nick-clicked signal (kawaii.neko) (#12599)
+		* chat-nick-autocomplete signal (kawaii.neko) (#12599)
 
 version 2.7.11 (03/10/2011):
 	* libpurple:
--- a/configure.ac	Mon Apr 18 21:20:33 2011 +0000
+++ b/configure.ac	Tue Apr 26 13:43:24 2011 +0000
@@ -1058,7 +1058,7 @@
 	]])], [
 		AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libgadu.h>]], [[
 #if GG_DEFAULT_PROTOCOL_VERSION < 0x2e
-#error "Your libgadu version is too old. libpurple requires 1.9.0-rc2 or higher."
+#error "Your libgadu version is too old. libpurple requires 1.10.1 or higher."
 #endif
 		]])], [
 			AC_MSG_RESULT(yes)
@@ -1069,7 +1069,7 @@
 			echo
 			echo
 			echo "Your supplied copy of libgadu is too old."
-			echo "Install version 1.9.0-rc2 or newer."
+			echo "Install version 1.10.1 or newer."
 			echo "Then rerun this ./configure"
 			echo
 			echo "Falling back to using our own copy of libgadu"
--- a/libpurple/account.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/account.c	Tue Apr 26 13:43:24 2011 +0000
@@ -294,6 +294,7 @@
 			 proxy_type == PURPLE_PROXY_HTTP       ? "http"   :
 			 proxy_type == PURPLE_PROXY_SOCKS4     ? "socks4" :
 			 proxy_type == PURPLE_PROXY_SOCKS5     ? "socks5" :
+			 proxy_type == PURPLE_PROXY_TOR        ? "tor" :
 			 proxy_type == PURPLE_PROXY_USE_ENVVAR ? "envvar" : "unknown"), -1);
 
 	if ((value = purple_proxy_info_get_host(proxy_info)) != NULL)
@@ -746,6 +747,8 @@
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS4);
 		else if (purple_strequal(data, "socks5"))
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_SOCKS5);
+		else if (purple_strequal(data, "tor"))
+			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_TOR);
 		else if (purple_strequal(data, "envvar"))
 			purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_USE_ENVVAR);
 		else
--- a/libpurple/dnsquery.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/dnsquery.c	Tue Apr 26 13:43:24 2011 +0000
@@ -54,6 +54,7 @@
 	PurpleDnsQueryConnectFunction callback;
 	gpointer data;
 	guint timeout;
+	PurpleAccount *account;
 
 #if defined(PURPLE_DNSQUERY_USE_FORK)
 	PurpleDnsQueryResolverProcess *resolver;
@@ -153,6 +154,7 @@
 resolve_ip(PurpleDnsQueryData *query_data)
 {
 	struct sockaddr_in sin;
+	/* TODO: Use inet_pton for IPv6 support */
 	if (inet_aton(query_data->hostname, &sin.sin_addr))
 	{
 		/*
@@ -341,20 +343,17 @@
 		}
 		freeaddrinfo(tmp);
 #else
-		if (!inet_aton(hostname, &sin.sin_addr)) {
-			struct hostent *hp;
-			if (!(hp = gethostbyname(hostname))) {
-				write_to_parent(child_out, &h_errno, sizeof(int));
-				close(child_out);
-				if (show_debug)
-					printf("DNS Error: %d\n", h_errno);
-				_exit(0);
-			}
-			memset(&sin, 0, sizeof(struct sockaddr_in));
-			memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
-			sin.sin_family = hp->h_addrtype;
-		} else
-			sin.sin_family = AF_INET;
+		struct hostent *hp;
+		if (!(hp = gethostbyname(hostname))) {
+			write_to_parent(child_out, &h_errno, sizeof(int));
+			close(child_out);
+			if (show_debug)
+				printf("DNS Error: %d\n", h_errno);
+			_exit(0);
+		}
+		memset(&sin, 0, sizeof(struct sockaddr_in));
+		memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
+		sin.sin_family = hp->h_addrtype;
 
 		sin.sin_port = htons(dns_params.port);
 		rc = 0;
@@ -669,62 +668,12 @@
 	handle_next_queued_request();
 }
 
-static gboolean
-resolve_host(gpointer data)
+static void
+resolve_host(PurpleDnsQueryData *query_data)
 {
-	PurpleDnsQueryData *query_data;
-
-	query_data = data;
-	query_data->timeout = 0;
-
-	if (resolve_ip(query_data))
-	{
-		/* resolve_ip calls purple_dnsquery_resolved */
-		return FALSE;
-	}
-
-	if (purple_dnsquery_ui_resolve(query_data))
-	{
-		/* The UI is handling the resolve; we're done */
-		return FALSE;
-	}
-
 	queued_requests = g_slist_append(queued_requests, query_data);
 
 	handle_next_queued_request();
-
-	return FALSE;
-}
-
-PurpleDnsQueryData *
-purple_dnsquery_a(const char *hostname, int port,
-				PurpleDnsQueryConnectFunction callback, gpointer data)
-{
-	PurpleDnsQueryData *query_data;
-
-	g_return_val_if_fail(hostname != NULL, NULL);
-	g_return_val_if_fail(port	  != 0, NULL);
-	g_return_val_if_fail(callback != NULL, NULL);
-
-	query_data = g_new(PurpleDnsQueryData, 1);
-	query_data->hostname = g_strdup(hostname);
-	g_strstrip(query_data->hostname);
-	query_data->port = port;
-	query_data->callback = callback;
-	query_data->data = data;
-	query_data->resolver = NULL;
-
-	if (*query_data->hostname == '\0')
-	{
-		purple_dnsquery_destroy(query_data);
-		g_return_val_if_reached(NULL);
-	}
-
-	purple_debug_info("dns", "DNS query for '%s' queued\n", query_data->hostname);
-
-	query_data->timeout = purple_timeout_add(0, resolve_host, query_data);
-
-	return query_data;
 }
 
 #elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK  */
@@ -837,50 +786,116 @@
 	return 0;
 }
 
+static void
+resolve_host(PurpleDnsQueryData *query_data)
+{
+	GError *err = NULL;
+
+	/*
+	 * Spin off a separate thread to perform the DNS lookup so
+	 * that we don't block the UI.
+	 */
+	query_data->resolver = g_thread_create(dns_thread,
+			query_data, FALSE, &err);
+	if (query_data->resolver == NULL)
+	{
+		char message[1024];
+		g_snprintf(message, sizeof(message), _("Thread creation failure: %s"),
+				(err && err->message) ? err->message : _("Unknown reason"));
+		g_error_free(err);
+		purple_dnsquery_failed(query_data, message);
+	}
+}
+
+#else /* not PURPLE_DNSQUERY_USE_FORK or _WIN32 */
+
+/*
+ * We weren't able to do anything fancier above, so use the
+ * fail-safe name resolution code, which is blocking.
+ */
+
+static void
+resolve_host(PurpleDnsQueryData *query_data)
+{
+	struct sockaddr_in sin;
+	GSList *hosts = NULL;
+	struct hostent *hp;
+	gchar *hostname;
+#ifdef USE_IDN
+	if (!dns_str_is_ascii(query_data->hostname)) {
+		int ret = purple_network_convert_idn_to_ascii(query_data->hostname,
+				&hostname);
+		if (ret != 0) {
+			char message[1024];
+			g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
+					query_data->hostname, ret);
+			purple_dnsquery_failed(query_data, message);
+			return;
+		}
+	} else /* fallthrough is intentional to the g_strdup */
+#endif
+	hostname = g_strdup(query_data->hostname);
+
+	if(!(hp = gethostbyname(hostname))) {
+		char message[1024];
+		g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
+				query_data->hostname, h_errno);
+		purple_dnsquery_failed(query_data, message);
+		g_free(hostname);
+		return;
+	}
+	memset(&sin, 0, sizeof(struct sockaddr_in));
+	memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
+	sin.sin_family = hp->h_addrtype;
+	g_free(hostname);
+	sin.sin_port = htons(query_data->port);
+
+	hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
+	hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
+
+	purple_dnsquery_resolved(query_data, hosts);
+}
+
+#endif /* not PURPLE_DNSQUERY_USE_FORK or _WIN32 */
+
 static gboolean
-resolve_host(gpointer data)
+initiate_resolving(gpointer data)
 {
 	PurpleDnsQueryData *query_data;
-	GError *err = NULL;
+	PurpleProxyType proxy_type;
 
 	query_data = data;
 	query_data->timeout = 0;
 
-	if (purple_dnsquery_ui_resolve(query_data))
-	{
-		/* The UI is handling the resolve; we're done */
+	if (resolve_ip(query_data))
+		/* resolve_ip calls purple_dnsquery_resolved */
+		return FALSE;
+
+	proxy_type = purple_proxy_info_get_type(
+		purple_proxy_get_setup(query_data->account));
+	if (proxy_type == PURPLE_PROXY_TOR) {
+		purple_dnsquery_failed(query_data,
+			_("Aborting DNS lookup in Tor Proxy mode."));
 		return FALSE;
 	}
 
-	if (!resolve_ip(query_data))
-	{
-		/*
-		 * Spin off a separate thread to perform the DNS lookup so
-		 * that we don't block the UI.
-		 */
-		query_data->resolver = g_thread_create(dns_thread,
-				query_data, FALSE, &err);
-		if (query_data->resolver == NULL)
-		{
-			char message[1024];
-			g_snprintf(message, sizeof(message), _("Thread creation failure: %s"),
-					(err && err->message) ? err->message : _("Unknown reason"));
-			g_error_free(err);
-			purple_dnsquery_failed(query_data, message);
-		}
-	}
+	if (purple_dnsquery_ui_resolve(query_data))
+		/* The UI is handling the resolve; we're done */
+		return FALSE;
+
+	resolve_host(query_data);
 
 	return FALSE;
 }
 
 PurpleDnsQueryData *
-purple_dnsquery_a(const char *hostname, int port,
+purple_dnsquery_a_account(PurpleAccount *account, const char *hostname, int port,
 				PurpleDnsQueryConnectFunction callback, gpointer data)
 {
 	PurpleDnsQueryData *query_data;
 
 	g_return_val_if_fail(hostname != NULL, NULL);
-	g_return_val_if_fail(port	  != 0, NULL);
+	g_return_val_if_fail(port != 0, NULL);
 	g_return_val_if_fail(callback != NULL, NULL);
 
 	purple_debug_info("dnsquery", "Performing DNS lookup for %s\n", hostname);
@@ -891,115 +906,26 @@
 	query_data->port = port;
 	query_data->callback = callback;
 	query_data->data = data;
+	query_data->account = account;
 
-	if (strlen(query_data->hostname) == 0)
+	if (*query_data->hostname == '\0')
 	{
 		purple_dnsquery_destroy(query_data);
 		g_return_val_if_reached(NULL);
 	}
 
-	/* Don't call the callback before returning */
-	query_data->timeout = purple_timeout_add(0, resolve_host, query_data);
+	query_data->timeout = purple_timeout_add(0, initiate_resolving, query_data);
 
 	return query_data;
 }
 
-#else /* not PURPLE_DNSQUERY_USE_FORK or _WIN32 */
-
-/*
- * We weren't able to do anything fancier above, so use the
- * fail-safe name resolution code, which is blocking.
- */
-
-static gboolean
-resolve_host(gpointer data)
-{
-	PurpleDnsQueryData *query_data;
-	struct sockaddr_in sin;
-	GSList *hosts = NULL;
-
-	query_data = data;
-	query_data->timeout = 0;
-
-	if (purple_dnsquery_ui_resolve(query_data))
-	{
-		/* The UI is handling the resolve; we're done */
-		return FALSE;
-	}
-
-	if (!inet_aton(query_data->hostname, &sin.sin_addr)) {
-		struct hostent *hp;
-		gchar *hostname;
-#ifdef USE_IDN
-		if (!dns_str_is_ascii(query_data->hostname)) {
-			int ret = purple_network_convert_idn_to_ascii(query_data->hostname,
-					&hostname);
-			if (ret != 0) {
-				char message[1024];
-				g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
-						query_data->hostname, ret);
-				purple_dnsquery_failed(query_data, message);
-				return FALSE;
-			}
-		} else /* fallthrough is intentional to the g_strdup */
-#endif
-		hostname = g_strdup(query_data->hostname);
-
-		if(!(hp = gethostbyname(hostname))) {
-			char message[1024];
-			g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
-					query_data->hostname, h_errno);
-			purple_dnsquery_failed(query_data, message);
-			g_free(hostname);
-			return FALSE;
-		}
-		memset(&sin, 0, sizeof(struct sockaddr_in));
-		memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
-		sin.sin_family = hp->h_addrtype;
-		g_free(hostname);
-	} else
-		sin.sin_family = AF_INET;
-	sin.sin_port = htons(query_data->port);
-
-	hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
-	hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
-
-	purple_dnsquery_resolved(query_data, hosts);
-
-	return FALSE;
-}
-
 PurpleDnsQueryData *
 purple_dnsquery_a(const char *hostname, int port,
 				PurpleDnsQueryConnectFunction callback, gpointer data)
 {
-	PurpleDnsQueryData *query_data;
-
-	g_return_val_if_fail(hostname != NULL, NULL);
-	g_return_val_if_fail(port	  != 0, NULL);
-	g_return_val_if_fail(callback != NULL, NULL);
-
-	query_data = g_new(PurpleDnsQueryData, 1);
-	query_data->hostname = g_strdup(hostname);
-	g_strstrip(query_data->hostname);
-	query_data->port = port;
-	query_data->callback = callback;
-	query_data->data = data;
-
-	if (strlen(query_data->hostname) == 0)
-	{
-		purple_dnsquery_destroy(query_data);
-		g_return_val_if_reached(NULL);
-	}
-
-	/* Don't call the callback before returning */
-	query_data->timeout = purple_timeout_add(0, resolve_host, query_data);
-
-	return query_data;
+	return purple_dnsquery_a_account(NULL, hostname, port, callback, data);
 }
 
-#endif /* not PURPLE_DNSQUERY_USE_FORK or _WIN32 */
-
 void
 purple_dnsquery_destroy(PurpleDnsQueryData *query_data)
 {
--- a/libpurple/dnsquery.h	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/dnsquery.h	Tue Apr 26 13:43:24 2011 +0000
@@ -88,6 +88,7 @@
 /**
  * Perform an asynchronous DNS query.
  *
+ * @param account the account that the query is being done for (or NULL)
  * @param hostname The hostname to resolve.
  * @param port     A port number which is stored in the struct sockaddr.
  * @param callback The callback function to call after resolving.
@@ -96,8 +97,28 @@
  * @return NULL if there was an error, otherwise return a reference to
  *         a data structure that can be used to cancel the pending
  *         DNS query, if needed.
+ *
+ * @since 2.8.0
+ */
+PurpleDnsQueryData *purple_dnsquery_a_account(PurpleAccount *account, const char *hostname, int port, PurpleDnsQueryConnectFunction callback, gpointer data);
+
+#ifndef PURPLE_DISABLE_DEPRECATED
+/**
+ * Perform an asynchronous DNS query.
+ *
+ * @param hostname The hostname to resolve.
+ * @param port     A port number which is stored in the struct sockaddr.
+ * @param callback The callback function to call after resolving.
+ * @param data     Extra data to pass to the callback function.
+ *
+ * @return NULL if there was an error, otherwise return a reference to
+ *         a data structure that can be used to cancel the pending
+ *         DNS query, if needed.
+ *
+ * @deprecated Use purple_dnsquery_a_account instead
  */
 PurpleDnsQueryData *purple_dnsquery_a(const char *hostname, int port, PurpleDnsQueryConnectFunction callback, gpointer data);
+#endif
 
 /**
  * Cancel a DNS query and destroy the associated data structure.
--- a/libpurple/dnssrv.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/dnssrv.c	Tue Apr 26 13:43:24 2011 +0000
@@ -30,12 +30,6 @@
 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
 #include <arpa/nameser_compat.h>
 #endif
-#ifndef T_SRV
-#define T_SRV	PurpleDnsTypeSrv
-#endif
-#ifndef T_TXT
-#define T_TXT	PurpleDnsTypeTxt
-#endif
 #else /* WIN32 */
 #include <windns.h>
 /* Missing from the mingw headers */
@@ -47,6 +41,13 @@
 #endif
 #endif
 
+#ifndef T_SRV
+#define T_SRV	PurpleDnsTypeSrv
+#endif
+#ifndef T_TXT
+#define T_TXT	PurpleDnsTypeTxt
+#endif
+
 #include "debug.h"
 #include "dnssrv.h"
 #include "eventloop.h"
@@ -673,11 +674,22 @@
 #endif
 
 PurpleSrvTxtQueryData *
-purple_srv_resolve(const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata)
+purple_srv_resolve(const char *protocol, const char *transport,
+	const char *domain, PurpleSrvCallback cb, gpointer extradata)
+{
+	return purple_srv_resolve_account(NULL, protocol, transport, domain,
+			cb, extradata);
+}
+
+PurpleSrvTxtQueryData *
+purple_srv_resolve_account(PurpleAccount *account, const char *protocol,
+	const char *transport, const char *domain, PurpleSrvCallback cb,
+	gpointer extradata)
 {
 	char *query;
 	char *hostname;
 	PurpleSrvTxtQueryData *query_data;
+	PurpleProxyType proxy_type;
 #ifndef _WIN32
 	PurpleSrvInternalQuery internal_query;
 	int in[2], out[2];
@@ -693,6 +705,14 @@
 		g_return_val_if_reached(NULL);
 	}
 
+	proxy_type = purple_proxy_info_get_type(
+		purple_proxy_get_setup(account));
+	if (proxy_type == PURPLE_PROXY_TOR) {
+		purple_debug_info("dnssrv", "Aborting SRV lookup in Tor Proxy mode.");
+		cb(NULL, 0, extradata);
+		return NULL;
+	}
+
 #ifdef USE_IDN
 	if (!dns_str_is_ascii(domain)) {
 		int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
@@ -794,11 +814,20 @@
 #endif
 }
 
-PurpleSrvTxtQueryData *purple_txt_resolve(const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata)
+PurpleSrvTxtQueryData *purple_txt_resolve(const char *owner,
+	const char *domain, PurpleTxtCallback cb, gpointer extradata)
+{
+	return purple_txt_resolve_account(NULL, owner, domain, cb, extradata);
+}
+
+PurpleSrvTxtQueryData *purple_txt_resolve_account(PurpleAccount *account,
+	const char *owner, const char *domain, PurpleTxtCallback cb,
+	gpointer extradata)
 {
 	char *query;
 	char *hostname;
 	PurpleSrvTxtQueryData *query_data;
+	PurpleProxyType proxy_type;
 #ifndef _WIN32
 	PurpleSrvInternalQuery internal_query;
 	int in[2], out[2];
@@ -808,6 +837,14 @@
 	static gboolean initialized = FALSE;
 #endif
 
+	proxy_type = purple_proxy_info_get_type(
+		purple_proxy_get_setup(account));
+	if (proxy_type == PURPLE_PROXY_TOR) {
+		purple_debug_info("dnssrv", "Aborting TXT lookup in Tor Proxy mode.");
+		cb(NULL, extradata);
+		return NULL;
+	}
+
 #ifdef USE_IDN
 	if (!dns_str_is_ascii(domain)) {
 		int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
@@ -1042,4 +1079,4 @@
 	g_return_val_if_fail(query_data != NULL, 0);
 	
 	return query_data->type;
-}
\ No newline at end of file
+}
--- a/libpurple/dnssrv.h	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/dnssrv.h	Tue Apr 26 13:43:24 2011 +0000
@@ -103,13 +103,31 @@
 /**
  * Queries an SRV record.
  *
+ * @param account the account that the query is being done for (or NULL)
  * @param protocol Name of the protocol (e.g. "sip")
  * @param transport Name of the transport ("tcp" or "udp")
  * @param domain Domain name to query (e.g. "blubb.com")
  * @param cb A callback which will be called with the results
  * @param extradata Extra data to be passed to the callback
+ *
+ * @since 2.8.0
+ */
+PurpleSrvTxtQueryData *purple_srv_resolve_account(PurpleAccount *account, const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata);
+
+#ifndef PURPLE_DISABLE_DEPRECATED
+/**
+ * Queries an SRV record.
+ *
+ * @param protocol Name of the protocol (e.g. "sip")
+ * @param transport Name of the transport ("tcp" or "udp")
+ * @param domain Domain name to query (e.g. "blubb.com")
+ * @param cb A callback which will be called with the results
+ * @param extradata Extra data to be passed to the callback
+ *
+ * @deprecated Use purple_srv_resolve_account instead
  */
 PurpleSrvTxtQueryData *purple_srv_resolve(const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata);
+#endif
 
 /**
  * Cancel an SRV or DNS query.
@@ -121,14 +139,31 @@
 /**
  * Queries an TXT record.
  *
+ * @param account the account that the query is being done for (or NULL)
  * @param owner Name of the protocol (e.g. "_xmppconnect")
  * @param domain Domain name to query (e.g. "blubb.com")
  * @param cb A callback which will be called with the results
  * @param extradata Extra data to be passed to the callback
  *
+ * @since 2.8.0
+ */
+PurpleSrvTxtQueryData *purple_txt_resolve_account(PurpleAccount *account, const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata);
+
+#ifndef PURPLE_DISABLE_DEPRECATED
+/**
+ * Queries an TXT record.
+ *
+ * @param owner Name of the protocol (e.g. "_xmppconnect")
+ * @param domain Domain name to query (e.g. "blubb.com")
+ * @param cb A callback which will be called with the results
+ * @param extradata Extra data to be passed to the callback
+ *
+ * @deprecated Use purple_txt_resolve_account instead
+ *
  * @since 2.6.0
  */
 PurpleSrvTxtQueryData *purple_txt_resolve(const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata);
+#endif
 
 /**
  * Cancel an TXT DNS query.
--- a/libpurple/network.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/network.c	Tue Apr 26 13:43:24 2011 +0000
@@ -991,7 +991,7 @@
 	if (stun_server && stun_server[0] != '\0') {
 		if (purple_network_is_available()) {
 			purple_debug_info("network", "running DNS query for STUN server\n");
-			purple_dnsquery_a(stun_server, 3478, purple_network_ip_lookup_cb,
+			purple_dnsquery_a_account(NULL, stun_server, 3478, purple_network_ip_lookup_cb,
 				&stun_ip);
 		} else {
 			purple_debug_info("network",
@@ -1009,7 +1009,7 @@
 	if (turn_server && turn_server[0] != '\0') {
 		if (purple_network_is_available()) {
 			purple_debug_info("network", "running DNS query for TURN server\n");
-			purple_dnsquery_a(turn_server,
+			purple_dnsquery_a_account(NULL, turn_server,
 				purple_prefs_get_int("/purple/network/turn_port"),
 				purple_network_ip_lookup_cb, &turn_ip);
 		} else {
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Tue Apr 26 13:43:24 2011 +0000
@@ -883,8 +883,9 @@
 	purple_proxy_info_set_type(xf->proxy_info, PURPLE_PROXY_SOCKS5);
 	purple_proxy_info_set_host(xf->proxy_info, xf->proxy_host);
 	purple_proxy_info_set_port(xf->proxy_info, xf->proxy_port);
-	xf->proxy_connection = purple_proxy_connect_socks5(
+	xf->proxy_connection = purple_proxy_connect_socks5_account(
 							   purple_account_get_connection(account),
+							   account,
 							   xf->proxy_info,
 							   dstaddr, 0,
 							   bonjour_bytestreams_connect_cb, xfer);
--- a/libpurple/protocols/gg/gg.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/gg/gg.c	Tue Apr 26 13:43:24 2011 +0000
@@ -1044,6 +1044,29 @@
 }
 
 /**
+ * Try to update avatar of the buddy.
+ *
+ * @param gc     PurpleConnection
+ * @param uin    UIN of the buddy.
+ */
+static void ggp_update_buddy_avatar(PurpleConnection *gc, uin_t uin)
+{
+	gchar *avatarurl;
+	PurpleUtilFetchUrlData *url_data;
+
+	purple_debug_info("gg", "ggp_update_buddy_avatar(gc, %u)\n", uin);
+
+	avatarurl = g_strdup_printf("http://api.gadu-gadu.pl/avatars/%u/0.xml", uin);
+
+	url_data = purple_util_fetch_url_request_len_with_account(
+			purple_connection_get_account(gc), avatarurl, TRUE,
+			"Mozilla/4.0 (compatible; MSIE 5.5)", FALSE, NULL, FALSE, -1,
+			gg_get_avatar_url_cb, gc);
+
+	g_free(avatarurl);
+}
+
+/**
  * Handle change of the status of the buddy.
  *
  * @param gc     PurpleConnection
@@ -1056,18 +1079,10 @@
 {
 	gchar *from;
 	const char *st;
-	gchar *avatarurl;
-	PurpleUtilFetchUrlData *url_data;
+
+	ggp_update_buddy_avatar(gc, uin);
 
 	from = g_strdup_printf("%u", uin);
-	avatarurl = g_strdup_printf("http://api.gadu-gadu.pl/avatars/%s/0.xml", from);
-
-	url_data = purple_util_fetch_url_request_len_with_account(
-			purple_connection_get_account(gc), avatarurl, TRUE,
-			"Mozilla/4.0 (compatible; MSIE 5.5)", FALSE, NULL, FALSE, -1,
-			gg_get_avatar_url_cb, gc);
-
-	g_free(avatarurl);
 
 	switch (status) {
 		case GG_STATUS_NOT_AVAIL:
@@ -1383,8 +1398,8 @@
 			info->pending_richtext_messages = g_list_remove(info->pending_richtext_messages, entry->data);
 			/* We don't have any more images to download */
 			if (strstr(text, "<IMG ID=\"IMGID_HANDLER") == NULL) {
-				gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.msg.sender);
-				serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, ev->event.msg.time);
+				gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.image_reply.sender);
+				serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, time(NULL));
 				g_free(buf);
 				purple_debug_info("gg", "ggp_recv_image_handler: richtext message: %s\n", text);
 				g_free(text);
@@ -1614,6 +1629,75 @@
     g_free(from);
 }
 
+/**
+ * Handling of XML events.
+ *
+ * @param gc PurpleConnection.
+ * @param data Raw XML contents.
+ *
+ * @see http://toxygen.net/libgadu/protocol/#ch1.13
+ */
+static void ggp_xml_event_handler(PurpleConnection *gc, char *data)
+{
+	xmlnode *xml = NULL;
+	xmlnode *xmlnode_next_event;
+
+	xml = xmlnode_from_str(data, -1);
+	if (xml == NULL)
+		goto out;
+
+	xmlnode_next_event = xmlnode_get_child(xml, "event");
+	while (xmlnode_next_event != NULL)
+	{
+		xmlnode *xmlnode_current_event = xmlnode_next_event;
+		
+		xmlnode *xmlnode_type;
+		char *event_type_raw;
+		int event_type = 0;
+		
+		xmlnode *xmlnode_sender;
+		char *event_sender_raw;
+		uin_t event_sender = 0;
+
+		xmlnode_next_event = xmlnode_get_next_twin(xmlnode_next_event);
+		
+		xmlnode_type = xmlnode_get_child(xmlnode_current_event, "type");
+		if (xmlnode_type == NULL)
+			continue;
+		event_type_raw = xmlnode_get_data(xmlnode_type);
+		if (event_type_raw != NULL)
+			event_type = atoi(event_type_raw);
+		g_free(event_type_raw);
+		
+		xmlnode_sender = xmlnode_get_child(xmlnode_current_event, "sender");
+		if (xmlnode_sender != NULL)
+		{
+			event_sender_raw = xmlnode_get_data(xmlnode_sender);
+			if (event_sender_raw != NULL)
+				event_sender = ggp_str_to_uin(event_sender_raw);
+			g_free(event_sender_raw);
+		}
+		
+		switch (event_type)
+		{
+			case 28: /* avatar update */
+				purple_debug_info("gg",
+					"ggp_xml_event_handler: avatar updated (uid: %u)\n",
+					event_sender);
+				ggp_update_buddy_avatar(gc, event_sender);
+				break;
+			default:
+				purple_debug_error("gg",
+					"ggp_xml_event_handler: unsupported event type=%d from=%u\n",
+					event_type, event_sender);
+		}
+	}
+	
+	out:
+		if (xml)
+			xmlnode_free(xml);
+}
+
 static void ggp_callback_recv(gpointer _gc, gint fd, PurpleInputCondition cond)
 {
 	PurpleConnection *gc = _gc;
@@ -1629,7 +1713,7 @@
 			_("Unable to read from socket"));
 		return;
 	}
-	gc->last_received = time(NULL);
+
 	switch (ev->type) {
 		case GG_EVENT_NONE:
 			/* Nothing happened. */
@@ -1731,6 +1815,10 @@
 			ggp_typing_notification_handler(gc, ev->event.typing_notification.uin,
 				ev->event.typing_notification.length);
 			break;
+		case GG_EVENT_XML_EVENT:
+			purple_debug_info("gg", "GG_EVENT_XML_EVENT\n");
+			ggp_xml_event_handler(gc, ev->event.xml_event.data);
+			break;
 		default:
 			purple_debug_error("gg",
 				"unsupported event type=%d\n", ev->type);
--- a/libpurple/protocols/jabber/disco.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/jabber/disco.c	Tue Apr 26 13:43:24 2011 +0000
@@ -480,10 +480,12 @@
 	js->srv_query_data = NULL;
 
 	if (results > 0) {
+		PurpleAccount *account;
 		purple_debug_info("jabber", "looking up IP for %s:%d\n",
 			resp[0].hostname, resp[0].port);
+		account = purple_connection_get_account(js->gc);
 		js->stun_query =
-			purple_dnsquery_a(resp[0].hostname, resp[0].port,
+			purple_dnsquery_a_account(account, resp[0].hostname, resp[0].port,
 				jabber_disco_stun_lookup_cb, js);
 	}
 }
@@ -548,7 +550,9 @@
 		} else if (purple_network_get_stun_ip() == NULL ||
 		    purple_strequal(purple_network_get_stun_ip(), "")) {
 			js->srv_query_data =
-				purple_srv_resolve("stun", "udp", js->user->domain,
+				purple_srv_resolve_account(
+					purple_connection_get_account(js->gc), "stun", "udp",
+					js->user->domain,
 					jabber_disco_stun_srv_resolve_cb, js);
 			/* TODO: add TURN support later... */
 		}
--- a/libpurple/protocols/jabber/google/jingleinfo.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/jabber/google/jingleinfo.c	Tue Apr 26 13:43:24 2011 +0000
@@ -109,13 +109,15 @@
 			const gchar *udp = xmlnode_get_attrib(server, "udp");
 
 			if (host && udp) {
+				PurpleAccount *account;
 				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,
+				account = purple_connection_get_account(js->gc);
+				js->stun_query = purple_dnsquery_a_account(account, host, port,
 					jabber_google_stun_lookup_cb, js);
 			}
 		}
--- a/libpurple/protocols/jabber/jabber.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Tue Apr 26 13:43:24 2011 +0000
@@ -813,7 +813,8 @@
 			try_srv_connect(js);
 		} else {
 			purple_debug_info("jabber","Couldn't connect directly to %s.  Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
-			js->srv_query_data = purple_txt_resolve("_xmppconnect",
+			js->srv_query_data = purple_txt_resolve_account(
+					purple_connection_get_account(gc), "_xmppconnect",
 					js->user->domain, txt_resolved_cb, js);
 		}
 		return;
@@ -1072,7 +1073,7 @@
 		jabber_login_connect(js, js->user->domain, connect_server,
 				purple_account_get_int(account, "port", 5222), TRUE);
 	} else {
-		js->srv_query_data = purple_srv_resolve("xmpp-client",
+		js->srv_query_data = purple_srv_resolve_account(account, "xmpp-client",
 				"tcp", js->user->domain, srv_resolved_cb, js);
 	}
 }
--- a/libpurple/protocols/jabber/si.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/jabber/si.c	Tue Apr 26 13:43:24 2011 +0000
@@ -277,6 +277,7 @@
 
 	if(dstjid != NULL && streamhost->host && streamhost->port > 0) {
 		char *dstaddr, *hash;
+		PurpleAccount *account;
 		jsx->gpi = purple_proxy_info_new();
 		purple_proxy_info_set_type(jsx->gpi, PURPLE_PROXY_SOCKS5);
 		purple_proxy_info_set_host(jsx->gpi, streamhost->host);
@@ -293,8 +294,9 @@
 		/* Per XEP-0065, the 'host' must be SHA1(SID + from JID + to JID) */
 		hash = jabber_calculate_data_hash(dstaddr, strlen(dstaddr), "sha1");
 
-		jsx->connect_data = purple_proxy_connect_socks5(NULL, jsx->gpi,
-				hash, 0,
+		account = purple_connection_get_account(jsx->js->gc);
+		jsx->connect_data = purple_proxy_connect_socks5_account(NULL, account,
+				jsx->gpi, hash, 0,
 				jabber_si_bytestreams_connect_cb, xfer);
 		g_free(hash);
 		g_free(dstaddr);
--- a/libpurple/protocols/qq/qq_network.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/qq/qq_network.c	Tue Apr 26 13:43:24 2011 +0000
@@ -987,7 +987,7 @@
 	}
 
 	purple_debug_info("QQ", "UDP Connect to %s:%d\n", server, port);
-	qd->udp_query_data = purple_dnsquery_a(server, port, udp_host_resolved, gc);
+	qd->udp_query_data = purple_dnsquery_a_account(account, server, port, udp_host_resolved, gc);
 	if ( qd->udp_query_data == NULL ) {
 		purple_debug_error("QQ", "Could not resolve hostname\n");
 		return FALSE;
--- a/libpurple/protocols/simple/simple.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/simple/simple.c	Tue Apr 26 13:43:24 2011 +0000
@@ -1903,7 +1903,8 @@
 	} else { /* UDP */
 		purple_debug_info("simple", "using udp with server %s and port %d\n", hostname, port);
 
-		sip->query_data = purple_dnsquery_a(hostname, port, simple_udp_host_resolved, sip);
+		sip->query_data = purple_dnsquery_a_account(sip->account, hostname,
+			port, simple_udp_host_resolved, sip);
 		if (sip->query_data == NULL) {
 			purple_connection_error_reason(sip->gc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
@@ -1965,7 +1966,7 @@
 		hosttoconnect = purple_account_get_string(account, "proxy", sip->servername);
 	}
 
-	sip->srv_query_data = purple_srv_resolve("sip",
+	sip->srv_query_data = purple_srv_resolve_account(account, "sip",
 			sip->udp ? "udp" : "tcp", hosttoconnect, srvresolved, sip);
 }
 
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Tue Apr 26 13:43:24 2011 +0000
@@ -1660,6 +1660,7 @@
 	}
 	if(val_222 == 3)
 	{
+		PurpleAccount *account;
 		xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map,
 								   xfer_peer_idstring);
 		if(!xfer)
@@ -1679,14 +1680,17 @@
 			return;
 		}
 
+		account = purple_connection_get_account(gc);
 		if (yd->jp)
 		{
-			purple_dnsquery_a(YAHOOJP_XFER_RELAY_HOST, YAHOOJP_XFER_RELAY_PORT,
+			purple_dnsquery_a_account(account, YAHOOJP_XFER_RELAY_HOST,
+							YAHOOJP_XFER_RELAY_PORT,
 							yahoo_xfer_dns_connected_15, xfer);
 		}
 		else
 		{
-			purple_dnsquery_a(YAHOO_XFER_RELAY_HOST, YAHOO_XFER_RELAY_PORT,
+			purple_dnsquery_a_account(account, YAHOO_XFER_RELAY_HOST,
+							YAHOO_XFER_RELAY_PORT,
 							yahoo_xfer_dns_connected_15, xfer);
 		}
 		return;
@@ -1784,7 +1788,6 @@
 	char *xfer_idstring_for_relay = NULL;
 	GSList *l;
 	struct yahoo_packet *pkt_to_send;
-	PurpleAccount *account;
 	struct yahoo_p2p_data *p2p_data;
 
 	yd = gc->proto_data;
@@ -1838,7 +1841,8 @@
 
 	xfer_data->info_val_249 = val_249;
 	xfer_data->xfer_idstring_for_relay = g_strdup(xfer_idstring_for_relay);
-	if(val_249 == 1 || val_249 == 3)	{
+	if(val_249 == 1 || val_249 == 3) {
+		PurpleAccount *account;
 		if (!purple_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL)) {
 			purple_xfer_cancel_remote(xfer);
 			return;
--- a/libpurple/proxy.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/proxy.c	Tue Apr 26 13:43:24 2011 +0000
@@ -69,6 +69,7 @@
 	guchar *read_buffer;
 	gsize read_buf_len;
 	gsize read_len;
+	PurpleAccount *account;
 };
 
 static const char * const socks5errors[] = {
@@ -1367,7 +1368,8 @@
 
 		proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
 	} else {
-		connect_data->query_data = purple_dnsquery_a(connect_data->host,
+		connect_data->query_data = purple_dnsquery_a_account(
+				connect_data->account, connect_data->host,
 				connect_data->port, s4_host_resolved, connect_data);
 
 		if (connect_data->query_data == NULL) {
@@ -2137,6 +2139,7 @@
 			break;
 
 		case PURPLE_PROXY_SOCKS5:
+		case PURPLE_PROXY_TOR:
 			proxy_connect_socks5(connect_data, addr, addrlen);
 			break;
 
@@ -2281,6 +2284,7 @@
 	connect_data->host = g_strdup(host);
 	connect_data->port = port;
 	connect_data->gpi = purple_proxy_get_setup(account);
+	connect_data->account = account;
 
 	if ((purple_proxy_info_get_type(connect_data->gpi) != PURPLE_PROXY_NONE) &&
 		(purple_proxy_info_get_host(connect_data->gpi) == NULL ||
@@ -2299,6 +2303,7 @@
 		case PURPLE_PROXY_HTTP:
 		case PURPLE_PROXY_SOCKS4:
 		case PURPLE_PROXY_SOCKS5:
+		case PURPLE_PROXY_TOR:
 		case PURPLE_PROXY_USE_ENVVAR:
 			connecthost = purple_proxy_info_get_host(connect_data->gpi);
 			connectport = purple_proxy_info_get_port(connect_data->gpi);
@@ -2311,7 +2316,7 @@
 			return NULL;
 	}
 
-	connect_data->query_data = purple_dnsquery_a(connecthost,
+	connect_data->query_data = purple_dnsquery_a_account(account, connecthost,
 			connectport, connection_host_resolved, connect_data);
 	if (connect_data->query_data == NULL)
 	{
@@ -2347,6 +2352,7 @@
 	connect_data->host = g_strdup(host);
 	connect_data->port = port;
 	connect_data->gpi = purple_proxy_get_setup(account);
+	connect_data->account = account;
 
 	if ((purple_proxy_info_get_type(connect_data->gpi) != PURPLE_PROXY_NONE) &&
 		(purple_proxy_info_get_host(connect_data->gpi) == NULL ||
@@ -2365,6 +2371,7 @@
 		case PURPLE_PROXY_HTTP:
 		case PURPLE_PROXY_SOCKS4:
 		case PURPLE_PROXY_SOCKS5:
+		case PURPLE_PROXY_TOR:
 		case PURPLE_PROXY_USE_ENVVAR:
 			purple_debug_info("proxy", "Ignoring Proxy type (%d) for UDP.\n",
 			                  purple_proxy_info_get_type(connect_data->gpi));
@@ -2377,7 +2384,7 @@
 			return NULL;
 	}
 
-	connect_data->query_data = purple_dnsquery_a(connecthost,
+	connect_data->query_data = purple_dnsquery_a_account(account, connecthost,
 			connectport, connection_host_resolved, connect_data);
 	if (connect_data->query_data == NULL)
 	{
@@ -2399,6 +2406,19 @@
 						  PurpleProxyConnectFunction connect_cb,
 						  gpointer data)
 {
+	return purple_proxy_connect_socks5_account(NULL, handle, gpi,
+						  host, port, connect_cb, data);
+}
+/*
+ * Combine some of this code with purple_proxy_connect()
+ */
+PurpleProxyConnectData *
+purple_proxy_connect_socks5_account(void *handle, PurpleAccount *account,
+						  PurpleProxyInfo *gpi,
+						  const char *host, int port,
+						  PurpleProxyConnectFunction connect_cb,
+						  gpointer data)
+{
 	PurpleProxyConnectData *connect_data;
 
 	g_return_val_if_fail(host       != NULL, NULL);
@@ -2414,9 +2434,11 @@
 	connect_data->host = g_strdup(host);
 	connect_data->port = port;
 	connect_data->gpi = gpi;
+	connect_data->account = account;
 
 	connect_data->query_data =
-			purple_dnsquery_a(purple_proxy_info_get_host(gpi),
+			purple_dnsquery_a_account(account,
+					purple_proxy_info_get_host(gpi),
 					purple_proxy_info_get_port(gpi),
 					connection_host_resolved, connect_data);
 	if (connect_data->query_data == NULL)
@@ -2470,6 +2492,8 @@
 			proxytype = PURPLE_PROXY_SOCKS4;
 		else if (purple_strequal(type, "socks5"))
 			proxytype = PURPLE_PROXY_SOCKS5;
+		else if (purple_strequal(type, "tor"))
+			proxytype = PURPLE_PROXY_TOR;
 		else if (purple_strequal(type, "envvar"))
 			proxytype = PURPLE_PROXY_USE_ENVVAR;
 		else
--- a/libpurple/proxy.h	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/proxy.h	Tue Apr 26 13:43:24 2011 +0000
@@ -39,7 +39,8 @@
 	PURPLE_PROXY_HTTP,             /**< HTTP proxy.                       */
 	PURPLE_PROXY_SOCKS4,           /**< SOCKS 4 proxy.                    */
 	PURPLE_PROXY_SOCKS5,           /**< SOCKS 5 proxy.                    */
-	PURPLE_PROXY_USE_ENVVAR        /**< Use environmental settings.       */
+	PURPLE_PROXY_USE_ENVVAR,       /**< Use environmental settings.       */
+	PURPLE_PROXY_TOR               /**< Use a Tor proxy (SOCKS 5 really)  */
 
 } PurpleProxyType;
 
@@ -306,10 +307,39 @@
  *         opaque data structure that can be used to cancel
  *         the pending connection, if needed.
  */
+PurpleProxyConnectData *purple_proxy_connect_socks5_account(void *handle,
+			PurpleAccount *account, PurpleProxyInfo *gpi,
+			const char *host, int port,
+			PurpleProxyConnectFunction connect_cb, gpointer data);
+
+#ifndef PURPLE_DISABLE_DEPRECATED
+/**
+ * Makes a connection through a SOCKS5 proxy.
+ *
+ * @param handle     A handle that should be associated with this
+ *                   connection attempt.  The handle can be used
+ *                   to cancel the connection attempt using the
+ *                   purple_proxy_connect_cancel_with_handle()
+ *                   function.
+ * @param gpi        The PurpleProxyInfo specifying the proxy settings
+ * @param host       The destination host.
+ * @param port       The destination port.
+ * @param connect_cb The function to call when the connection is
+ *                   established.  If the connection failed then
+ *                   fd will be -1 and error message will be set
+ *                   to something descriptive (hopefully).
+ * @param data       User-defined data.
+ *
+ * @return NULL if there was an error, or a reference to an
+ *         opaque data structure that can be used to cancel
+ *         the pending connection, if needed.
+ * @deprecated Use purple_proxy_connect_socks5_account instead
+ */
 PurpleProxyConnectData *purple_proxy_connect_socks5(void *handle,
 			PurpleProxyInfo *gpi,
 			const char *host, int port,
 			PurpleProxyConnectFunction connect_cb, gpointer data);
+#endif
 
 /**
  * Cancel an in-progress connection attempt.  This should be called
--- a/libpurple/signals.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/signals.c	Tue Apr 26 13:43:24 2011 +0000
@@ -880,6 +880,20 @@
 }
 
 void
+purple_marshal_BOOLEAN__POINTER_BOOLEAN(PurpleCallback cb, va_list args,
+									  void *data, void **return_val)
+{
+	gboolean ret_val;
+	void *arg1 = va_arg(args, void *);
+	gboolean arg2 = va_arg(args, gboolean);
+
+	ret_val = ((gboolean (*)(void *, gboolean, void *))cb)(arg1, arg2, data);
+
+	if (return_val != NULL)
+		*return_val = GINT_TO_POINTER(ret_val);
+}
+
+void
 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER(PurpleCallback cb, va_list args,
 											  void *data, void **return_val)
 {
--- a/libpurple/signals.h	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/signals.h	Tue Apr 26 13:43:24 2011 +0000
@@ -339,6 +339,8 @@
 		PurpleCallback cb, va_list args, void *data, void **return_val);
 void purple_marshal_BOOLEAN__POINTER_POINTER(
 		PurpleCallback cb, va_list args, void *data, void **return_val);
+void purple_marshal_BOOLEAN__POINTER_BOOLEAN(
+		PurpleCallback cb, va_list args, void *data, void **return_val);
 void purple_marshal_BOOLEAN__POINTER_POINTER_POINTER(
 		PurpleCallback cb, va_list args, void *data, void **return_val);
 void purple_marshal_BOOLEAN__POINTER_POINTER_UINT(
--- a/libpurple/stun.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/libpurple/stun.c	Tue Apr 26 13:43:24 2011 +0000
@@ -365,7 +365,7 @@
 	purple_debug_info("stun", "got %d SRV responses, server: %s, port: %d\n",
 		results, servername, port);
 
-	purple_dnsquery_a(servername, port, hbn_cb, NULL);
+	purple_dnsquery_a_account(NULL, servername, port, hbn_cb, NULL);
 	g_free(resp);
 }
 
@@ -424,7 +424,7 @@
 	nattype.servername = g_strdup(servername);
 
 	callbacks = g_slist_append(callbacks, cb);
-	purple_srv_resolve("stun", "udp", servername, do_test1,
+	purple_srv_resolve_account(NULL, "stun", "udp", servername, do_test1,
 		(gpointer) servername);
 
 	return &nattype;
--- a/pidgin/gtkaccount.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/pidgin/gtkaccount.c	Tue Apr 26 13:43:24 2011 +0000
@@ -1021,6 +1021,12 @@
 
 	gtk_list_store_append(model, &iter);
 	gtk_list_store_set(model, &iter,
+			0, _("Tor/Privacy (SOCKS5)"),
+			1, PURPLE_PROXY_TOR,
+			-1);
+
+	gtk_list_store_append(model, &iter);
+	gtk_list_store_set(model, &iter,
 			0, _("Use Environmental Settings"),
 			1, PURPLE_PROXY_USE_ENVVAR,
 			-1);
@@ -2254,7 +2260,7 @@
 					 G_CALLBACK(account_treeview_double_click_cb), dialog);
 
 	gtk_notebook_append_page(GTK_NOTEBOOK(accounts_window->notebook),
-		pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1), 
+		pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_NONE, -1, -1),
 		NULL);
 
 	add_columns(treeview, dialog);
--- a/pidgin/gtkconv.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/pidgin/gtkconv.c	Tue Apr 26 13:43:24 2011 +0000
@@ -1792,6 +1792,15 @@
 	gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
 	gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &who, -1);
 
+	/* emit chat-nick-clicked signal */
+	if (event->type == GDK_BUTTON_PRESS) {
+		gint plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
+					pidgin_conversations_get_handle(), "chat-nick-clicked",
+					conv, who, event->button));
+		if (plugin_return)
+			goto handled;
+	}
+
 	if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
 		chat_do_im(gtkconv, who);
 	} else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) {
@@ -1806,6 +1815,7 @@
 					   event->button, event->time);
 	}
 
+handled:
 	g_free(who);
 	gtk_tree_path_free(path);
 
@@ -2122,7 +2132,13 @@
 		case GDK_ISO_Left_Tab:
 			if (gtkconv->entry != entry)
 				break;
-			return tab_complete(conv);
+			{
+				gint plugin_return;
+				plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
+							pidgin_conversations_get_handle(), "chat-nick-autocomplete",
+							conv, event->state & GDK_SHIFT_MASK));
+				return plugin_return ? TRUE : tab_complete(conv);
+			}
 			break;
 
 		case GDK_Page_Up:
@@ -5586,6 +5602,15 @@
 
 		buddyname = (tag->name) + 6;
 
+		/* emit chat-nick-clicked signal */
+		if (event->type == GDK_BUTTON_PRESS) {
+			gint plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
+						pidgin_conversations_get_handle(), "chat-nick-clicked",
+						data, buddyname, btn_event->button));
+			if (plugin_return)
+				return TRUE;
+		}
+
 		if (btn_event->button == 1 &&
 				event->type == GDK_2BUTTON_PRESS) {
 			chat_do_im(PIDGIN_CONVERSATION(conv), buddyname);
@@ -8003,6 +8028,21 @@
 						 purple_value_new(PURPLE_TYPE_BOXED,
 										"PidginConversation *"));
 
+	purple_signal_register(handle, "chat-nick-autocomplete",
+						 purple_marshal_BOOLEAN__POINTER_BOOLEAN,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+							 			PURPLE_SUBTYPE_CONVERSATION));
+
+	purple_signal_register(handle, "chat-nick-clicked",
+						 purple_marshal_BOOLEAN__POINTER_POINTER_UINT,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+							 			PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+
 	/**********************************************************************
 	 * Register commands
 	 **********************************************************************/
--- a/pidgin/gtkdialogs.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/pidgin/gtkdialogs.c	Tue Apr 26 13:43:24 2011 +0000
@@ -102,8 +102,10 @@
 /* Order: Alphabetical by Last Name */
 static const struct developer patch_writers[] = {
 	{"Jakub 'haakon' Adam",            NULL,                        NULL},
+	{"Krzysztof Klinikowski",          NULL,                        NULL},
 	{"Peter 'Fmoo' Ruibal",            NULL,                        NULL},
 	{"Gabriel 'Nix' Schulhof",         NULL,                        NULL},
+	{"Tomasz Wasilczyk",               NULL,                        NULL},
 	{NULL, NULL, NULL}
 };
 
--- a/pidgin/gtkprefs.c	Mon Apr 18 21:20:33 2011 +0000
+++ b/pidgin/gtkprefs.c	Tue Apr 26 13:43:24 2011 +0000
@@ -2041,9 +2041,10 @@
 		pidgin_prefs_dropdown(prefs_proxy_frame, _("Proxy t_ype:"), PURPLE_PREF_STRING,
 					"/purple/proxy/type",
 					_("No proxy"), "none",
-					"SOCKS 4", "socks4",
-					"SOCKS 5", "socks5",
-					"HTTP", "http",
+					_("SOCKS 4"), "socks4",
+					_("SOCKS 5"), "socks5",
+					_("Tor/Privacy (SOCKS5)"), "tor",
+					_("HTTP"), "http",
 					_("Use Environmental Settings"), "envvar",
 					NULL);
 		gtk_box_pack_start(GTK_BOX(prefs_proxy_frame), prefs_proxy_subframe, 0, 0, 0);