changeset 28876:cf9ea9f2c0bb

merge of '06b53ea832679e0dfb2e6d5d0c1b69e61f1bd38b' and 'ea2f92f486297b27994d3652e14f799eb0964834'
author Mark Doliner <mark@kingant.net>
date Wed, 04 Nov 2009 18:41:51 +0000
parents 4575d8daba12 (diff) 8464e695c62b (current diff)
children a990da4540d3 86ff30fb8ae3
files ChangeLog libpurple/protocols/jabber/JEPS
diffstat 54 files changed, 1059 insertions(+), 657 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Nov 04 18:41:21 2009 +0000
+++ b/ChangeLog	Wed Nov 04 18:41:51 2009 +0000
@@ -1,3 +1,4 @@
+
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
 version 2.6.4 (??/??/20??):
@@ -10,10 +11,20 @@
 	* Fix building the GnuTLS plugin with older versions of GnuTLS.
 	* Fix DNS TXT query resolution.
 	* Always rejoin open chats after an account reconnects.
+	AIM and ICQ:
+	* Better rate limit calculations and other improvements.  (Aman Gupta)
+	* More detailed error messages when messages fail to send.  (Aman Gupta)
+	* The simultaneous login account option is respected when using
+	  the clientLogin authentication method.
+
 
 	MSN:
 	* Don't forget display names for buddies.
 	* Fix a random crash that might occur when idle.
+	* Fix more FQY 240 connection errors.
+	* Fix a crash that could occur when adding a buddy.
+	* Fix an occasional crash when sending message to an offline user.
+	* Fix a random crash that might occur when idle.
 	* Fix a crash when logging in with some long non-ASCII passwords.
 	  (Shaun Lindsay)
 
@@ -23,6 +34,9 @@
 	* Fix a crash when attempting to validate an invalid JID.
 	* Resolve an issue when connecting to iChat Server when no resource
 	  is specified.
+	* Try to automatically find a STUN server by using an SRV lookup on the
+	  account's domain, and use that for voice and video if found and the user 
+	  didn't set one manually in prefs.
 	* Fix a crash when adding a buddy without an '@'.
 
 	Yahoo:
--- a/autogen.sh	Wed Nov 04 18:41:21 2009 +0000
+++ b/autogen.sh	Wed Nov 04 18:41:51 2009 +0000
@@ -83,7 +83,7 @@
 
 	OUTPUT=`mktemp autogen-XXXXXX`
 
-	printf "%s" "running ${CMD} ${@}... "
+	printf "running %s %s... " ${CMD} "$*"
 	${CMD} ${@} >${OUTPUT} 2>&1
 
 	if [ $? != 0 ] ; then
@@ -99,9 +99,17 @@
 	fi
 }
 
+cleanup () {
+	rm -f autogen-??????
+	echo
+	exit 2
+}
+
 ###############################################################################
 # We really start here, yes, very sneaky!
 ###############################################################################
+trap cleanup 2
+
 FIGLET=`which figlet 2> /dev/null`
 if [ x"${FIGLET}" != x"" ] ; then
 	${FIGLET} -f small ${PACKAGE}
@@ -143,7 +151,7 @@
 run_or_die ${INTLTOOLIZE} ${INTLTOOLIZE_FLAGS:-"-c -f --automake"}
 # This call to sed is needed to work around an annoying bug in intltool 0.40.6
 # See http://developer.pidgin.im/ticket/9520 for details
-run_or_die ${SED} "s:'\^\$\$lang\$\$':\^\$\$lang\$\$:g" -i po/Makefile.in.in
+run_or_die ${SED} -i.bak -e "s:'\^\$\$lang\$\$':\^\$\$lang\$\$:g" po/Makefile.in.in
 run_or_die ${ACLOCAL} ${ACLOCAL_FLAGS:-"-I m4macros"}
 run_or_die ${AUTOHEADER} ${AUTOHEADER_FLAGS}
 run_or_die ${AUTOMAKE} ${AUTOMAKE_FLAGS:-"-a -c --gnu"}
--- a/finch/libgnt/gntentry.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/finch/libgnt/gntentry.c	Wed Nov 04 18:41:51 2009 +0000
@@ -1044,8 +1044,11 @@
 		snprintf(entry->start, len + 1, "%s", text);
 	entry->end = entry->start + len;
 
-	entry->scroll = entry->start + scroll;
-	entry->cursor = entry->end - cursor;
+	if ((entry->scroll = entry->start + scroll) > entry->end)
+		entry->scroll = entry->end;
+
+	if ((entry->cursor = entry->end - cursor) > entry->end)
+		entry->cursor = entry->end;
 
 	if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(entry), GNT_WIDGET_MAPPED))
 		entry_redraw(GNT_WIDGET(entry));
--- a/finch/libgnt/gnttextview.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/finch/libgnt/gnttextview.c	Wed Nov 04 18:41:51 2009 +0000
@@ -67,6 +67,12 @@
 
 static void reset_text_view(GntTextView *view);
 
+static gboolean
+text_view_contains(GntTextView *view, const char *str)
+{
+	return (str >= view->string->str && str < view->string->str + view->string->len);
+}
+
 static void
 gnt_text_view_draw(GntWidget *widget)
 {
@@ -109,7 +115,7 @@
 			char back = *end;
 			chtype fl = seg->flags;
 			*end = '\0';
-			if (select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) {
+			if (select_start && select_start < view->string->str + seg->start && select_end > view->string->str + seg->end) {
 				fl |= A_REVERSE;
 				wattrset(widget->window, fl);
 				wprintw(widget->window, "%s", (view->string->str + seg->start));
@@ -326,9 +332,10 @@
 		select_start = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y);
 		g_timeout_add(500, too_slow, NULL);
 	} else if (event == GNT_MOUSE_UP) {
-		if (select_start) {
+		GntTextView *view = GNT_TEXT_VIEW(widget);
+		if (text_view_contains(view, select_start)) {
 			GString *clip;
-			select_end = gnt_text_view_get_p(GNT_TEXT_VIEW(widget), x - widget->priv.x, y - widget->priv.y);
+			select_end = gnt_text_view_get_p(view, x - widget->priv.x, y - widget->priv.y);
 			if (select_end < select_start) {
 				gchar *t = select_start;
 				select_start = select_end;
@@ -336,7 +343,7 @@
 			}
 			if (select_start == select_end) {
 				if (double_click) {
-					clip = select_word_text(GNT_TEXT_VIEW(widget), select_start);
+					clip = select_word_text(view, select_start);
 					double_click = FALSE;
 				} else {
 					double_click = TRUE;
--- a/libpurple/Makefile.am	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/Makefile.am	Wed Nov 04 18:41:51 2009 +0000
@@ -32,7 +32,7 @@
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = purple.pc
 
-SUBDIRS = $(GCONF_DIR) plugins protocols tests . example
+SUBDIRS = $(GCONF_DIR) plugins protocols . tests example
 
 purple_coresources = \
 	account.c \
--- a/libpurple/account.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/account.c	Wed Nov 04 18:41:51 2009 +0000
@@ -1050,6 +1050,16 @@
 	if(account->system_log)
 		purple_log_free(account->system_log);
 
+	while (account->deny) {
+		g_free(account->deny->data);
+		account->deny = g_slist_delete_link(account->deny, account->deny);
+	}
+
+	while (account->permit) {
+		g_free(account->permit->data);
+		account->permit = g_slist_delete_link(account->permit, account->permit);
+	}
+
 	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
 	PURPLE_DBUS_UNREGISTER_POINTER(priv->current_error);
 	if (priv->current_error) {
--- a/libpurple/cipher.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/cipher.c	Wed Nov 04 18:41:51 2009 +0000
@@ -50,10 +50,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#include <glib.h>
-#include <string.h>
-#include <stdio.h>
-
 #include "internal.h"
 #include "cipher.h"
 #include "dbus-maybe.h"
--- a/libpurple/dnsquery.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/dnsquery.c	Wed Nov 04 18:41:51 2009 +0000
@@ -172,6 +172,7 @@
 	return FALSE;
 }
 
+#ifdef USE_IDN
 static gboolean
 dns_str_is_ascii(const char *name)
 {
@@ -183,6 +184,7 @@
 
 	return TRUE;
 }
+#endif
 
 #if defined(PURPLE_DNSQUERY_USE_FORK)
 
@@ -293,12 +295,11 @@
 			rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname);
 			if (rc != 0) {
 				write_to_parent(child_out, &rc, sizeof(rc));
-				close(child_out);
 				if (show_debug)
 					fprintf(stderr, "dns[%d] Error: IDN conversion returned "
 							"%d\n", getpid(), rc);
 				dns_params.hostname[0] = '\0';
-				continue;
+				break;
 			}
 		} else /* intentional to execute the g_strdup */
 #endif
@@ -323,14 +324,13 @@
 		rc = getaddrinfo(hostname, servname, &hints, &res);
 		write_to_parent(child_out, &rc, sizeof(rc));
 		if (rc != 0) {
-			close(child_out);
 			if (show_debug)
 				printf("dns[%d] Error: getaddrinfo returned %d\n",
 					getpid(), rc);
 			dns_params.hostname[0] = '\0';
 			g_free(hostname);
 			hostname = NULL;
-			continue;
+			break;
 		}
 		tmp = res;
 		while (res) {
--- a/libpurple/dnssrv.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/dnssrv.c	Wed Nov 04 18:41:51 2009 +0000
@@ -248,6 +248,7 @@
 	return list;
 }
 
+#ifdef USE_IDN
 static gboolean
 dns_str_is_ascii(const char *name)
 {
@@ -259,8 +260,60 @@
 
 	return TRUE;
 }
+#endif
 
 #ifndef _WIN32
+static void
+write_to_parent(int in, int out, gconstpointer data, gsize size)
+{
+	const guchar *buf = data;
+	gssize w;
+
+	do {
+		w = write(out, buf, size);
+		if (w > 0) {
+			buf += w;
+			size -= w;
+		} else if (w < 0 && errno == EINTR) {
+			/* Let's try some more; */
+			w = 1;
+		}
+	} while (size > 0 && w > 0);
+
+	if (size != 0) {
+		/* An error occurred */
+		close(out);
+		close(in);
+		_exit(0);
+	}
+}
+
+/* Read size bytes to data. Dies if an error occurs. */
+static void
+read_from_parent(int in, int out, gpointer data, gsize size)
+{
+	guchar *buf = data;
+	gssize r;
+
+	do {
+		r = read(in, data, size);
+		if (r > 0) {
+			buf += r;
+			size -= r;
+		} else if (r < 0 && errno == EINTR) {
+			/* Let's try some more; */
+			r = 1;
+		}
+	} while (size > 0 && r > 0);
+
+	if (size != 0) {
+		/* An error occurred */
+		close(out);
+		close(in);
+		_exit(0);
+	}
+}
+
 
 G_GNUC_NORETURN static void
 resolve(int in, int out)
@@ -279,16 +332,12 @@
 	purple_restore_default_signal_handlers();
 #endif
 
-	if (read(in, &query, sizeof(query)) <= 0) {
-		close(out);
-		close(in);
-		_exit(0);
-	}
+	read_from_parent(in, out, &query, sizeof(query));
 
 	size = res_query( query.query, C_IN, query.type, (u_char*)&answer, sizeof( answer));
 	if (size == -1) {
-		write(out, &(query.type), sizeof(query.type));
-		write(out, &size, sizeof(int));
+		write_to_parent(in, out, &(query.type), sizeof(query.type));
+		write_to_parent(in, out, &size, sizeof(size));
 		close(out);
 		close(in);
 		_exit(0);
@@ -353,19 +402,17 @@
 	if (query.type == T_SRV)
 		ret = purple_srv_sort(ret);
 
-	/* TODO: Check return value */
-	write(out, &(query.type), sizeof(query.type));
-	write(out, &size, sizeof(size));
+	write_to_parent(in, out, &(query.type), sizeof(query.type));
+	write_to_parent(in, out, &size, sizeof(size));
 	while (ret != NULL)
 	{
-		/* TODO: Check return value */
 		if (query.type == T_SRV)
-			write(out, ret->data, sizeof(PurpleSrvResponse));
+			write_to_parent(in, out, ret->data, sizeof(PurpleSrvResponse));
 		if (query.type == T_TXT) {
 			PurpleTxtResponse *response = ret->data;
 			gsize l = strlen(response->content) + 1 /* null byte */;
-			write(out, &l, sizeof(l));
-			write(out, response->content, l);
+			write_to_parent(in, out, &l, sizeof(l));
+			write_to_parent(in, out, response->content, l);
 		}
 
 		g_free(ret->data);
--- a/libpurple/plugins/perl/Makefile.mingw	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/plugins/perl/Makefile.mingw	Wed Nov 04 18:41:51 2009 +0000
@@ -7,10 +7,12 @@
 PIDGIN_TREE_TOP := ../../..
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
+DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES))
+
 TARGET = perl
 
 # Perl headers with /* /* */ type comments.. Turn off warnings.
-CFLAGS += -Wno-comment
+GCCWARNINGS += -Wno-comment
 
 ##
 ## INCLUDE PATHS
--- a/libpurple/plugins/perl/common/Makefile.mingw	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/plugins/perl/common/Makefile.mingw	Wed Nov 04 18:41:51 2009 +0000
@@ -5,9 +5,12 @@
 #
 
 PIDGIN_TREE_TOP := ../../../..
-GCCWARNINGS := -Wno-comment -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wpointer-arith -Wundef -Wno-unused
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
+GCCWARNINGS += -Wno-comment -Wno-unused -Wno-nested-externs
+
+DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES))
+
 TARGET = Purple
 AUTOSPLIT = lib/auto/Purple/autosplit.ix
 EXTUTILS ?= C:/perl/lib/ExtUtils
--- a/libpurple/plugins/perl/perl-handlers.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/plugins/perl/perl-handlers.c	Wed Nov 04 18:41:51 2009 +0000
@@ -649,6 +649,7 @@
 static void
 destroy_cmd_handler(PurplePerlCmdHandler *handler)
 {
+	purple_cmd_unregister(handler->id);
 	cmd_handlers = g_slist_remove(cmd_handlers, handler);
 
 	if (handler->callback != NULL)
@@ -705,7 +706,6 @@
 		return;
 	}
 
-	purple_cmd_unregister(id);
 	destroy_cmd_handler(handler);
 }
 
--- a/libpurple/protocols/jabber/JEPS	Wed Nov 04 18:41:21 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-0045: IN PROGRESS
-	Multi-User Chat
-0047: IN PROGRESS
-	In-Band Bytestreams
-0060: NEED
-	Pub-Sub
-0071: AWAITING FINAL SPEC
-	XHTML-IM
-0073: NEED
-	Basic IM Protocol Suite
-0080: NEED (Do we?)
-	Geographic Location Information
-0084: NEED
-	User Avatars in Jabber
-0085: NEED
-	Chat State Notifications
-0089: WATCH
-	Generic Alerts
-0093: NEED
-	Roster Item Exchange
-0100: NEED
-	Gateway Interaction (Transports)
-0115: WATCH
-	Client Capabilities
-0117: NEED
-	Intermediate IM Protocol Suite
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/XEPS	Wed Nov 04 18:41:51 2009 +0000
@@ -0,0 +1,4 @@
+0060: NEED
+	Pub-Sub
+0080: NEED (Do we?)
+	Geographic Location Information
--- a/libpurple/protocols/jabber/caps.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/jabber/caps.c	Wed Nov 04 18:41:51 2009 +0000
@@ -975,7 +975,7 @@
 	g_free(js->caps_hash);
 	js->caps_hash = jabber_caps_calculate_hash(&info, "sha1");
 	g_list_free(info.identities);
-	g_list_free(features);
+	g_list_free(info.features);
 }
 
 const gchar* jabber_caps_get_own_hash(JabberStream *js)
--- a/libpurple/protocols/jabber/chat.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/jabber/chat.c	Wed Nov 04 18:41:51 2009 +0000
@@ -692,11 +692,11 @@
 }
 
 
-void jabber_chat_change_nick(JabberChat *chat, const char *nick)
+gboolean jabber_chat_change_nick(JabberChat *chat, const char *nick)
 {
 	xmlnode *presence;
 	char *full_jid;
-	PurplePresence *gpresence;
+	PurpleAccount *account;
 	PurpleStatus *status;
 	JabberBuddyState state;
 	char *msg;
@@ -706,11 +706,11 @@
 		purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), "",
 				_("Nick changing not supported in non-MUC chatrooms"),
 				PURPLE_MESSAGE_SYSTEM, time(NULL));
-		return;
+		return FALSE;
 	}
 
-	gpresence = purple_account_get_presence(chat->js->gc->account);
-	status = purple_presence_get_active_status(gpresence);
+	account = purple_connection_get_account(chat->js->gc);
+	status = purple_account_get_active_status(account);
 
 	purple_status_to_jabber(status, &state, &msg, &priority);
 
@@ -722,6 +722,8 @@
 
 	jabber_send(chat->js, presence);
 	xmlnode_free(presence);
+
+	return TRUE;
 }
 
 void jabber_chat_part(JabberChat *chat, const char *msg)
--- a/libpurple/protocols/jabber/chat.h	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/jabber/chat.h	Wed Nov 04 18:41:51 2009 +0000
@@ -89,7 +89,7 @@
 void jabber_chat_register(JabberChat *chat);
 void jabber_chat_change_topic(JabberChat *chat, const char *topic);
 void jabber_chat_set_topic(PurpleConnection *gc, int id, const char *topic);
-void jabber_chat_change_nick(JabberChat *chat, const char *nick);
+gboolean jabber_chat_change_nick(JabberChat *chat, const char *nick);
 void jabber_chat_part(JabberChat *chat, const char *msg);
 void jabber_chat_track_handle(JabberChat *chat, const char *handle,
 		const char *jid, const char *affiliation, const char *role);
--- a/libpurple/protocols/jabber/disco.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/jabber/disco.c	Wed Nov 04 18:41:51 2009 +0000
@@ -421,6 +421,76 @@
 
 }
 
+/* should probably share this code with google.c, or maybe from 2.7.0
+ introduce an abstracted hostname -> IP function in dns.c */
+static void
+jabber_disco_stun_lookup_cb(GSList *hosts, gpointer data,
+	const char *error_message)
+{
+	JabberStream *js = (JabberStream *) data;
+
+	if (error_message) {
+		purple_debug_error("jabber", "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 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_disco_stun_srv_resolve_cb(PurpleSrvResponse *resp, int results, gpointer data)
+{
+	JabberStream *js = (JabberStream *) data;
+
+	purple_debug_info("jabber", "got %d SRV responses for STUN.\n", results);
+	js->srv_query_data = NULL;
+
+	if (results > 0) {
+		purple_debug_info("jabber", "looking up IP for %s:%d\n", 
+			resp[0].hostname, resp[0].port);
+		js->stun_query = 
+			purple_dnsquery_a(resp[0].hostname, resp[0].port, 
+				jabber_disco_stun_lookup_cb, js);
+	}
+}
+
+
 static void
 jabber_disco_server_info_result_cb(JabberStream *js, const char *from,
                                    JabberIqType type, const char *id,
@@ -471,7 +541,10 @@
 			/* autodiscover stun and relays */
 			jabber_google_send_jingle_info(js);
 		} else {
-			/* TODO: add external service discovery here... */
+			js->srv_query_data = 
+				purple_srv_resolve("stun", "udp", js->user->domain,
+					jabber_disco_stun_srv_resolve_cb, js);
+			/* TODO: add TURN support later... */
 		}
 	}
 
--- a/libpurple/protocols/jabber/google.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/jabber/google.c	Wed Nov 04 18:41:51 2009 +0000
@@ -994,8 +994,9 @@
 
 	const char *grt = xmlnode_get_attrib_with_namespace(item, "t", "google:roster");
 	const char *subscription = xmlnode_get_attrib(item, "subscription");
+	const char *ask = xmlnode_get_attrib(item, "ask");
 
-	if (!subscription || !strcmp(subscription, "none")) {
+	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.
 		 */
--- a/libpurple/protocols/jabber/jabber.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed Nov 04 18:41:51 2009 +0000
@@ -1825,7 +1825,7 @@
 		JabberFeature *feature = jabber_features->data;
 		g_free(feature->namespace);
 		g_free(feature);
-		jabber_features = g_list_remove_link(jabber_features, jabber_features);
+		jabber_features = g_list_delete_link(jabber_features, jabber_features);
 	}
 }
 
@@ -1862,7 +1862,7 @@
 		g_free(id->lang);
 		g_free(id->name);
 		g_free(id);
-		jabber_identities = g_list_remove_link(jabber_identities, jabber_identities);
+		jabber_identities = g_list_delete_link(jabber_identities, jabber_identities);
 	}
 }
 
@@ -2606,8 +2606,15 @@
 	if(!chat || !args || !args[0])
 		return PURPLE_CMD_RET_FAILED;
 
-	jabber_chat_change_nick(chat, args[0]);
-	return PURPLE_CMD_RET_OK;
+	if (!jabber_resourceprep_validate(args[0])) {
+		*error = g_strdup(_("Invalid nickname"));
+		return PURPLE_CMD_RET_FAILED;
+	}
+
+	if (jabber_chat_change_nick(chat, args[0]))
+		return PURPLE_CMD_RET_OK;
+	else
+		return PURPLE_CMD_RET_FAILED;
 }
 
 static PurpleCmdRet jabber_cmd_chat_part(PurpleConversation *conv,
--- a/libpurple/protocols/jabber/jingle/jingle.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.c	Wed Nov 04 18:41:51 2009 +0000
@@ -442,15 +442,15 @@
 	if (num_params > 0) {
 		params = g_new0(GParameter, num_params);
 
-		purple_debug_info("jabber", 
-						  "setting param stun-ip for stream using Google auto-config: %s\n",
-						  js->stun_ip);
+		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 Google auto-config: %d\n",
-						  js->stun_port);
+			"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);
--- a/libpurple/protocols/jabber/roster.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/jabber/roster.c	Wed Nov 04 18:41:51 2009 +0000
@@ -72,7 +72,7 @@
 		const char *alias, GSList *groups)
 {
 	GSList *buddies, *l;
-	GSList *pool = NULL;
+	PurpleAccount *account = purple_connection_get_account(js->gc);
 
 	buddies = purple_find_buddies(js->gc->account, jid);
 
@@ -117,25 +117,14 @@
 			groups = g_slist_delete_link(groups, l);
 		} else {
 			/* This buddy isn't in the group on the server anymore */
-			pool = g_slist_prepend(pool, b);
+			purple_debug_info("jabber", "jabber_roster_parse(): Removing %s "
+			                  "from group '%s' on the local list\n",
+			                  purple_buddy_get_name(b),
+			                  purple_group_get_name(g));
+			purple_blist_remove_buddy(b);
 		}
 	}
 
-	if (pool) {
-		GString *tmp = g_string_new(NULL);
-		GSList *list = pool;
-		for ( ; list; list = list->next) {
-			tmp = g_string_append(tmp,
-					purple_group_get_name(purple_buddy_get_group(list->data)));
-			if (list->next)
-				tmp = g_string_append(tmp, ", ");
-		}
-
-		purple_debug_info("jabber", "jabber_roster_parse(): Removing %s from "
-		                  "groups: %s\n", jid, tmp->str);
-		g_string_free(tmp, TRUE);
-	}
-
 	if (groups) {
 		char *tmp = roster_groups_join(groups);
 		purple_debug_info("jabber", "jabber_roster_parse(): Adding %s to "
@@ -145,17 +134,7 @@
 
 	while(groups) {
 		PurpleGroup *g = purple_find_group(groups->data);
-		PurpleBuddy *b = NULL;
-
-		/* If there are buddies we would otherwise delete, move them to
-		 * the new group (instead of deleting them below)
-		 */
-		if (pool) {
-			b = pool->data;
-			pool = g_slist_delete_link(pool, pool);
-		} else {
-			b = purple_buddy_new(js->gc->account, jid, alias);
-		}
+		PurpleBuddy *b = purple_buddy_new(account, jid, alias);
 
 		if(!g) {
 			g = purple_group_new(groups->data);
@@ -169,14 +148,6 @@
 		groups = g_slist_delete_link(groups, groups);
 	}
 
-	/* Remove this person from all the groups they're no longer in on the
-	 * server */
-	while (pool) {
-		PurpleBuddy *b = pool->data;
-		purple_blist_remove_buddy(b);
-		pool = g_slist_delete_link(pool, pool);
-	}
-
 	g_slist_free(buddies);
 }
 
--- a/libpurple/protocols/msn/contact.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/msn/contact.c	Wed Nov 04 18:41:51 2009 +0000
@@ -362,7 +362,7 @@
 	char *display_text;
 
 	passport = xmlnode_get_data(xmlnode_get_child(member, node));
-	if (!purple_email_is_valid(passport)) {
+	if (!msn_email_is_valid(passport)) {
 		g_free(passport);
 		return;
 	}
@@ -765,7 +765,7 @@
 		if (passport == NULL)
 			continue;
 
-		if (!purple_email_is_valid(passport))
+		if (!msn_email_is_valid(passport))
 			continue;
 
 		if ((displayName = xmlnode_get_child(contactInfo, "displayName")))
@@ -1232,8 +1232,13 @@
 	if (user->invite_message) {
 		char *tmp;
 		body = g_markup_escape_text(user->invite_message, -1);
-		tmp = g_markup_escape_text(purple_connection_get_display_name(session->account->gc), -1);
+
+		/* Ignore the cast, we treat it as const anyway. */
+		tmp = (char *)purple_connection_get_display_name(session->account->gc);
+		tmp = tmp ? g_markup_escape_text(tmp, -1) : g_strdup("");
+
 		invite = g_strdup_printf(MSN_CONTACT_INVITE_MESSAGE_XML, body, tmp);
+
 		g_free(body);
 		g_free(tmp);
 
--- a/libpurple/protocols/msn/msn.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/msn/msn.c	Wed Nov 04 18:41:51 2009 +0000
@@ -118,6 +118,29 @@
 	return buf;
 }
 
+gboolean
+msn_email_is_valid(const char *passport)
+{
+	if (purple_email_is_valid(passport)) {
+		/* Special characters aren't allowed in domains, so only go to '@' */
+		while (*passport != '@') {
+			if (*passport == '/')
+				return FALSE;
+			else if (*passport == '?')
+				return FALSE;
+			else if (*passport == '=')
+				return FALSE;
+			/* MSN also doesn't like colons, but that's checked already */
+
+			passport++;
+		}
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
 static gboolean
 msn_send_attention(PurpleConnection *gc, const char *username, guint type)
 {
@@ -611,9 +634,14 @@
 		MsnSession *session = gc->proto_data;
 		if (session) {
 			MsnUser *user = msn_userlist_find_user(session->userlist, who);
-			if (user)
+			if (user) {
 				/* Include these too: MSN_CLIENT_CAP_MSNMOBILE|MSN_CLIENT_CAP_MSNDIRECT ? */
-				ret = (user->clientid & MSN_CLIENT_CAP_WEBMSGR) == 0;
+				if ((user->clientid & MSN_CLIENT_CAP_WEBMSGR) ||
+						user->networkid == MSN_NETWORK_YAHOO)
+					ret = FALSE;
+				else
+					ret = TRUE;
+			}
 		} else
 			ret = FALSE;
 	}
@@ -1511,7 +1539,7 @@
 
 	bname = purple_buddy_get_name(buddy);
 
-	if (!purple_email_is_valid(bname)) {
+	if (!msn_email_is_valid(bname)) {
 		gchar *buf;
 		buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid.  Usernames must be valid email addresses."), bname);
 		if (!purple_conv_present_error(bname, purple_connection_get_account(gc), buf))
--- a/libpurple/protocols/msn/msn.h	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/msn/msn.h	Wed Nov 04 18:41:51 2009 +0000
@@ -133,6 +133,7 @@
 	((MSN_CLIENT_ID_VERSION    << 24) | \
 	 (MSN_CLIENT_ID_CAPABILITIES))
 
+gboolean msn_email_is_valid(const char *passport);
 void msn_act_id(PurpleConnection *gc, const char *entry);
 void msn_send_privacy(PurpleConnection *gc);
 void msn_send_im_message(MsnSession *session, MsnMessage *msg);
--- a/libpurple/protocols/msn/notification.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/msn/notification.c	Wed Nov 04 18:41:51 2009 +0000
@@ -670,7 +670,7 @@
 			                     "User %s is on both Allow and Block list; "
 			                     "removing from Allow list.\n",
 			                     user->passport);
-			msn_userlist_rem_buddy_from_list(session->userlist, user->passport, MSN_LIST_AL);
+			msn_user_unset_op(user, MSN_LIST_AL_OP);
 		}
 
 		if (user->networkid != MSN_NETWORK_UNKNOWN) {
@@ -840,17 +840,48 @@
 	MsnSession *session;
 	PurpleAccount *account;
 	PurpleConnection *gc;
-	char *adl = g_strndup(payload, len);
-	char *reason = g_strdup_printf(_("Unknown error (%d): %s"),
-		GPOINTER_TO_INT(cmd->payload_cbdata), adl);
-	g_free(adl);
+	int error = GPOINTER_TO_INT(cmd->payload_cbdata);
 
 	session = cmdproc->session;
 	account = session->account;
 	gc = purple_account_get_connection(account);
 
-	purple_notify_error(gc, NULL, _("Unable to add user"), reason);
-	g_free(reason);
+	if (error == 241) {
+		/* khc: some googling suggests that error 241 means the buddy is somehow
+		   in the local list, but not the server list, and that we should add
+		   those buddies to the addressbook. For now I will just notify the user
+		   about the raw payload, because I am lazy */
+		xmlnode *adl = xmlnode_from_str(payload, len);
+		GString *emails = g_string_new(NULL);
+
+		xmlnode *domain = xmlnode_get_child(adl, "d");
+		while (domain) {
+			const char *domain_str = xmlnode_get_attrib(domain, "n");
+			xmlnode *contact = xmlnode_get_child(domain, "c");
+			while (contact) {
+				g_string_append_printf(emails, "%s@%s\n",
+					xmlnode_get_attrib(contact, "n"), domain_str);
+				contact = xmlnode_get_next_twin(contact);
+			}
+			domain = xmlnode_get_next_twin(domain);
+		}
+
+		purple_notify_error(gc, NULL,
+			_("The following users are missing from your addressbook"),
+			emails->str);
+		g_string_free(emails, TRUE);
+		xmlnode_free(adl);
+	}
+	else
+	{
+		char *adl = g_strndup(payload, len);
+		char *reason = g_strdup_printf(_("Unknown error (%d): %s"),
+			error, adl);
+		g_free(adl);
+
+		purple_notify_error(gc, NULL, _("Unable to add user"), reason);
+		g_free(reason);
+	}
 }
 
 static void
@@ -878,50 +909,49 @@
 }
 
 static void
-adl_241_error_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
-	size_t len)
+rml_error_parse(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len)
 {
-	/* khc: some googling suggests that error 241 means the buddy is somehow
-	   in the local list, but not the server list, and that we should add
-	   those buddies to the addressbook. For now I will just notify the user
-	   about the raw payload, because I am lazy */
 	MsnSession *session;
 	PurpleAccount *account;
 	PurpleConnection *gc;
-	xmlnode *adl;
-	xmlnode *domain;
-	GString *emails;
+	char *adl, *reason;
+	int error = GPOINTER_TO_INT(cmd->payload_cbdata);
 
 	session = cmdproc->session;
 	account = session->account;
 	gc = purple_account_get_connection(account);
 
-	adl = xmlnode_from_str(payload, len);
-	emails = g_string_new(NULL);
+	adl = g_strndup(payload, len);
+	reason = g_strdup_printf(_("Unknown error (%d): %s"),
+		error, adl);
+	g_free(adl);
 
-	domain = xmlnode_get_child(adl, "d");
-	while (domain) {
-		const char *domain_str = xmlnode_get_attrib(domain, "n");
-		xmlnode *contact = xmlnode_get_child(domain, "c");
-		while (contact) {
-			g_string_append_printf(emails, "%s@%s\n",
-				xmlnode_get_attrib(contact, "n"), domain_str);
-			contact = xmlnode_get_next_twin(contact);
-		}
-		domain = xmlnode_get_next_twin(domain);
-	}
-
-	purple_notify_error(gc, NULL,
-		_("The following users are missing from your addressbook"), emails->str);
-	g_string_free(emails, TRUE);
-	xmlnode_free(adl);
+	purple_notify_error(gc, NULL, _("Unable to remove user"), reason);
+	g_free(reason);
 }
 
 static void
-adl_241_error_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+rml_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
 {
-	cmdproc->last_cmd->payload_cb = adl_241_error_cmd_post;
-	cmd->payload_len = atoi(cmd->params[1]);
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	MsnCommand *cmd = cmdproc->last_cmd;
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	purple_debug_error("msn", "RML error\n");
+	if (cmd->param_count > 1) {
+		cmd->payload_cb = rml_error_parse;
+		cmd->payload_len = atoi(cmd->params[1]);
+		cmd->payload_cbdata = GINT_TO_POINTER(error);
+	} else {
+		char *reason = g_strdup_printf(_("Unknown error (%d)"), error);
+		purple_notify_error(gc, NULL, _("Unable to remove user"), reason);
+		g_free(reason);
+	}
 }
 
 static void
@@ -1068,7 +1098,17 @@
 		/* Where'd this come from? */
 		return;
 
-	if (cmd->param_count == 7) {
+	if (cmd->param_count == 8) {
+		/* Yahoo! Buddy, looks like */
+		networkid = atoi(cmd->params[3]);
+		friendly = g_strdup(purple_url_decode(cmd->params[4]));
+		clientid = strtoul(cmd->params[5], NULL, 10);
+
+		/* cmd->params[7] seems to be a URL to a Yahoo! icon:
+				https://sec.yimg.com/i/us/nt/b/purpley.1.0.png
+		   ... and it's purple, HAH!
+		*/
+	} else if (cmd->param_count == 7) {
 		/* MSNP14+ with Display Picture object */
 		networkid = atoi(cmd->params[3]);
 		friendly = g_strdup(purple_url_decode(cmd->params[4]));
@@ -2095,9 +2135,8 @@
 
 	msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd);
 
-	msn_table_add_cmd(cbs_table, NULL, "241", adl_241_error_cmd);
-
 	msn_table_add_error(cbs_table, "ADL", adl_error);
+	msn_table_add_error(cbs_table, "RML", rml_error);
 	msn_table_add_error(cbs_table, "FQY", fqy_error);
 	msn_table_add_error(cbs_table, "USR", usr_error);
 
--- a/libpurple/protocols/msn/oim.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/msn/oim.c	Wed Nov 04 18:41:51 2009 +0000
@@ -153,7 +153,7 @@
 	gpointer cb_data;
 } MsnOimRequestData;
 
-static void msn_oim_request_helper(MsnOimRequestData *data);
+static gboolean msn_oim_request_helper(MsnOimRequestData *data);
 
 static void
 msn_oim_request_cb(MsnSoapMessage *request, MsnSoapMessage *response,
@@ -202,7 +202,7 @@
 	g_free(data);
 }
 
-static void
+static gboolean
 msn_oim_request_helper(MsnOimRequestData *data)
 {
 	MsnSession *session = data->oim->session;
@@ -224,13 +224,13 @@
 		const char *msn_p;
 
 		token = msn_nexus_get_token(session->nexus, MSN_AUTH_MESSENGER_WEB);
-		g_return_if_fail(token != NULL);
+		g_return_val_if_fail(token != NULL, FALSE);
 
 		msn_t = g_hash_table_lookup(token, "t");
 		msn_p = g_hash_table_lookup(token, "p");
 
-		g_return_if_fail(msn_t != NULL);
-		g_return_if_fail(msn_p != NULL);
+		g_return_val_if_fail(msn_t != NULL, FALSE);
+		g_return_val_if_fail(msn_p != NULL, FALSE);
 
 		passport = xmlnode_get_child(data->body, "Header/PassportCookie");
 		xml_t = xmlnode_get_child(passport, "t");
@@ -248,6 +248,8 @@
 		msn_soap_message_new(data->action, xmlnode_copy(data->body)),
 		data->host, data->url, FALSE,
 		msn_oim_request_cb, data);
+
+	return FALSE;
 }
 
 
--- a/libpurple/protocols/msn/userlist.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/msn/userlist.c	Wed Nov 04 18:41:51 2009 +0000
@@ -539,7 +539,7 @@
 
 	purple_debug_info("msn", "Add user: %s to group: %s\n", who, new_group_name);
 
-	if (!purple_email_is_valid(who))
+	if (!msn_email_is_valid(who))
 	{
 		/* only notify the user about problems adding to the friends list
 		 * maybe we should do something else for other lists, but it probably
--- a/libpurple/protocols/oscar/family_feedbag.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c	Wed Nov 04 18:41:51 2009 +0000
@@ -389,11 +389,10 @@
 
 /**
  * Locally find the presence flag item, and return the setting.  The returned setting is a
- * bitmask of the user flags that you are visible to.  See the AIM_FLAG_* #defines
- * in oscar.h
+ * bitmask of the preferences.  See the AIM_SSI_PRESENCE_FLAG_* #defines in oscar.h.
  *
  * @param list A pointer to the current list of items.
- * @return Return the current visibility mask.
+ * @return Return the current set of preferences.
  */
 guint32 aim_ssi_getpresence(struct aim_ssi_item *list)
 {
@@ -1130,9 +1129,11 @@
  * should show up as idle or not, etc.
  *
  * @param od The oscar odion.
- * @param presence I think it's a bitmask, but I only know what one of the bits is:
- *        0x00000002 - Hide wireless?
+ * @param presence A bitmask of the first 32 entries [0-31] from
+ *        http://dev.aol.com/aim/oscar/#FEEDBAG__BUDDY_PREFS
+ *        0x00000002 - Hide "eBuddy group" (whatever that is)
  *        0x00000400 - Allow others to see your idle time
+ *        0x00020000 - Don't show Recent Buddies
  * @return Return 0 if no errors, otherwise return the error number.
  */
 int aim_ssi_setpresence(OscarData *od, guint32 presence) {
--- a/libpurple/protocols/oscar/family_icbm.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Wed Nov 04 18:41:51 2009 +0000
@@ -151,6 +151,55 @@
 	return AIM_CLIENTTYPE_UNKNOWN;
 }
 
+/*
+ * Subtype 0x0001 - Error
+ */
+static int
+error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
+{
+	int ret = 0;
+	aim_rxcallback_t userfunc;
+	aim_snac_t *snac2;
+	guint16 reason, errcode = 0;
+	char *bn;
+	GSList *tlvlist;
+
+	if (!(snac2 = aim_remsnac(od, snac->id))) {
+		purple_debug_misc("oscar", "icbm error: received response from unknown request!\n");
+		return 0;
+	}
+
+	if (snac2->family != SNAC_FAMILY_ICBM) {
+		purple_debug_misc("oscar", "icbm error: received response from invalid request! %d\n", snac2->family);
+		g_free(snac2->data);
+		g_free(snac2);
+		return 0;
+	}
+
+	if (!(bn = snac2->data)) {
+		purple_debug_misc("oscar", "icbm error: received response from request without a buddy name!\n");
+		g_free(snac2);
+		return 0;
+	}
+
+	reason = byte_stream_get16(bs);
+
+	tlvlist = aim_tlvlist_read(bs);
+	if (aim_tlv_gettlv(tlvlist, 0x0008, 1))
+		errcode = aim_tlv_get16(tlvlist, 0x0008, 1);
+	aim_tlvlist_free(tlvlist);
+
+	/* Notify the user that the message wasn't delivered */
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+		ret = userfunc(od, conn, frame, reason, errcode, bn);
+
+	if (snac2)
+		g_free(snac2->data);
+	g_free(snac2);
+
+	return ret;
+}
+
 /**
  * Subtype 0x0002 - Set ICBM parameters.
  *
@@ -2789,7 +2838,9 @@
 static int
 snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
 {
-	if (snac->subtype == 0x0005)
+	if (snac->subtype == 0x0001)
+		return error(od, conn, mod, frame, snac, bs);
+	else if (snac->subtype == 0x0005)
 		return aim_im_paraminfo(od, conn, mod, frame, snac, bs);
 	else if (snac->subtype == 0x0006)
 		return outgoingim(od, conn, mod, frame, snac, bs);
--- a/libpurple/protocols/oscar/family_oservice.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/oscar/family_oservice.c	Wed Nov 04 18:41:51 2009 +0000
@@ -319,7 +319,10 @@
 	for (i = 0; i < numclasses; i++)
 	{
 		struct rateclass *rateclass;
+		guint32 delta;
+		struct timeval now;
 
+		gettimeofday(&now, NULL);
 		rateclass = g_new0(struct rateclass, 1);
 
 		rateclass->classid = byte_stream_get16(bs);
@@ -339,11 +342,24 @@
 		 * the new version hardcoded here.
 		 */
 		if (mod->version >= 3)
-			byte_stream_getrawbuf(bs, rateclass->unknown, sizeof(rateclass->unknown));
+		{
+			rateclass->delta = byte_stream_get32(bs);
+			rateclass->dropping_snacs = byte_stream_get8(bs);
+
+			delta = rateclass->delta;
+
+			rateclass->last.tv_sec = now.tv_sec - delta / 1000;
+			delta %= 1000;
+			rateclass->last.tv_usec = now.tv_usec - delta * 1000;
+		}
+		else
+		{
+			rateclass->delta = rateclass->dropping_snacs = 0;
+			rateclass->last.tv_sec = now.tv_sec;
+			rateclass->last.tv_usec = now.tv_usec;
+		}
 
 		rateclass->members = g_hash_table_new(g_direct_hash, g_direct_equal);
-		rateclass->last.tv_sec = 0;
-		rateclass->last.tv_usec = 0;
 		conn->rateclasses = g_slist_prepend(conn->rateclasses, rateclass);
 	}
 	conn->rateclasses = g_slist_reverse(conn->rateclasses);
@@ -383,8 +399,7 @@
 	 */
 
 	/*
-	 * Last step in the conn init procedure is to acknowledge that we
-	 * agree to these draconian limitations.
+	 * Subscribe to rate change information for all rate classes.
 	 */
 	aim_srv_rates_addparam(od, conn);
 
@@ -451,7 +466,10 @@
 	aim_rxcallback_t userfunc;
 	guint16 code, classid;
 	struct rateclass *rateclass;
+	guint32 delta;
+	struct timeval now;
 
+	gettimeofday(&now, NULL);
 	code = byte_stream_get16(bs);
 	classid = byte_stream_get16(bs);
 
@@ -468,8 +486,29 @@
 	rateclass->current = byte_stream_get32(bs);
 	rateclass->max = byte_stream_get32(bs);
 
-	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
-		ret = userfunc(od, conn, frame, code, classid, rateclass->windowsize, rateclass->clear, rateclass->alert, rateclass->limit, rateclass->disconnect, rateclass->current, rateclass->max);
+	if (mod->version >= 3)
+	{
+		rateclass->delta = byte_stream_get32(bs);
+		rateclass->dropping_snacs = byte_stream_get8(bs);
+
+		delta = rateclass->delta;
+
+		rateclass->last.tv_sec = now.tv_sec - delta / 1000;
+		delta %= 1000;
+		rateclass->last.tv_usec = now.tv_usec - delta * 1000;
+	}
+	else
+	{
+		rateclass->delta = rateclass->dropping_snacs = 0;
+		rateclass->last.tv_sec = now.tv_sec;
+		rateclass->last.tv_usec = now.tv_usec;
+	}
+
+	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
+		/* Can't pass in guint8 via ... varargs, so we use an unsigned int */
+		unsigned int dropping_snacs = rateclass->dropping_snacs;
+		ret = userfunc(od, conn, frame, code, classid, rateclass->windowsize, rateclass->clear, rateclass->alert, rateclass->limit, rateclass->disconnect, rateclass->current, rateclass->max, rateclass->delta, dropping_snacs);
+	}
 
 	return ret;
 }
--- a/libpurple/protocols/oscar/flap_connection.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c	Wed Nov 04 18:41:51 2009 +0000
@@ -73,7 +73,7 @@
 }
 
 void
-flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci)
+flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_logins)
 {
 	FlapFrame *frame;
 	GSList *tlvlist = NULL;
@@ -94,7 +94,7 @@
 	aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor);
 	aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point);
 	aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build);
-	aim_tlvlist_add_8(&tlvlist, 0x004a, 0x01);
+	aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x03));
 
 	aim_tlvlist_write(&frame->data, &tlvlist);
 
@@ -131,11 +131,13 @@
 rateclass_get_new_current(FlapConnection *conn, struct rateclass *rateclass, struct timeval *now)
 {
 	unsigned long timediff; /* In milliseconds */
+	guint32 current;
 
 	timediff = (now->tv_sec - rateclass->last.tv_sec) * 1000 + (now->tv_usec - rateclass->last.tv_usec) / 1000;
+	current = ((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize;
 
-	/* This formula is taken from the joscar API docs. Preesh. */
-	return MIN(((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize, rateclass->max);
+	/* This formula is taken from http://dev.aol.com/aim/oscar/#RATELIMIT */
+	return MIN(current, rateclass->max);
 }
 
 /*
@@ -161,8 +163,7 @@
 
 			new_current = rateclass_get_new_current(conn, rateclass, &now);
 
-			/* (Add 100ms padding to account for inaccuracies in the calculation) */
-			if (new_current < rateclass->alert + 100)
+			if (rateclass->dropping_snacs || new_current <= rateclass->alert)
 				/* Not ready to send this SNAC yet--keep waiting. */
 				return FALSE;
 
@@ -245,10 +246,9 @@
 		gettimeofday(&now, NULL);
 		new_current = rateclass_get_new_current(conn, rateclass, &now);
 
-		/* (Add 100ms padding to account for inaccuracies in the calculation) */
-		if (new_current < rateclass->alert + 100)
+		if (rateclass->dropping_snacs || new_current <= rateclass->alert)
 		{
-			purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, (rateclass->alert + 100));
+			purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, rateclass->alert);
 
 			enqueue = TRUE;
 		}
--- a/libpurple/protocols/oscar/oscar.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Wed Nov 04 18:41:51 2009 +0000
@@ -144,6 +144,26 @@
 };
 static const int msgerrreasonlen = G_N_ELEMENTS(msgerrreason);
 
+static const char * const errcodereason[] = {
+	N_("Invalid error"),
+	N_("Not logged in"),
+	N_("Cannot receive IM due to parental controls"),
+	N_("Cannot send SMS without accepting terms"),
+	N_("Cannot send SMS"), /* SMS_WITHOUT_DISCLAIMER is weird */
+	N_("Cannot send SMS to this country"),
+	N_("Unknown error"), /* Undocumented */
+	N_("Unknown error"), /* Undocumented */
+	N_("Cannot send SMS to unknown country"),
+	N_("Bot accounts cannot initiate IMs"),
+	N_("Bot account cannot IM this user"),
+	N_("Bot account reached IM limit"),
+	N_("Bot account reached daily IM limit"),
+	N_("Bot account reached monthly IM limit"),
+	N_("Unable to receive offline messages"),
+	N_("Offline message store full")
+};
+static const int errcodereasonlen = G_N_ELEMENTS(errcodereason);
+
 /* All the libfaim->purple callback functions */
 
 /* Only used when connecting with the old-style BUCP login */
@@ -1168,7 +1188,8 @@
 			ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
 			flap_connection_send_version_with_cookie_and_clientinfo(od,
 					conn, conn->cookielen, conn->cookie,
-					od->icq ? &icqinfo : &aiminfo);
+					od->icq ? &icqinfo : &aiminfo,
+					purple_account_get_bool(account, "allow_multiple_logins", OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS));
 		} else {
 			flap_connection_send_version_with_cookie(od, conn,
 					conn->cookielen, conn->cookie);
@@ -1394,9 +1415,9 @@
 	presence = aim_ssi_getpresence(od->ssi.local);
 
 	if (report_idle)
-		aim_ssi_setpresence(od, presence | 0x400);
+		aim_ssi_setpresence(od, presence | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
 	else
-		aim_ssi_setpresence(od, presence & ~0x400);
+		aim_ssi_setpresence(od, presence & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
 }
 
 /**
@@ -1877,7 +1898,7 @@
 			break;
 		case 0x18:
 			/* username connecting too frequently */
-			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
+			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your username has been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
 			break;
 		case 0x1c:
 		{
@@ -1889,7 +1910,7 @@
 		}
 		case 0x1d:
 			/* IP address connecting too frequently */
-			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer."));
+			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your IP address has been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer."));
 			break;
 		default:
 			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Unknown reason"));
@@ -2876,7 +2897,7 @@
 			if (text) {
 				/* Read the number of contacts that we were sent */
 				errno = 0;
-				num = strtoul(text[0], NULL, 10);
+				num = text[0] ? strtoul(text[0], NULL, 10) : 0;
 
 				if (num > 0 && errno == 0) {
 					for (i=0; i<num; i++) {
@@ -3217,17 +3238,18 @@
 	PurpleXfer *xfer;
 #endif
 	va_list ap;
-	guint16 reason;
-	char *data, *buf;
+	guint16 reason, errcode;
+	char *data, *reason_str, *buf;
 
 	va_start(ap, fr);
 	reason = (guint16)va_arg(ap, unsigned int);
+	errcode = (guint16)va_arg(ap, unsigned int);
 	data = va_arg(ap, char *);
 	va_end(ap);
 
 	purple_debug_error("oscar",
-			   "Message error with data %s and reason %hu\n",
-				(data != NULL ? data : ""), reason);
+			   "Message error with data %s and reason %hu and errcode %hu\n",
+				(data != NULL ? data : ""), reason, errcode);
 
 	if ((data == NULL) || (*data == '\0'))
 		/* We can't do anything if data is empty */
@@ -3242,14 +3264,27 @@
 #endif
 
 	/* Data is assumed to be the destination bn */
-	buf = g_strdup_printf(_("Unable to send message: %s"), (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
+
+	reason_str = g_strdup((reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason"));
+	if (errcode != 0 && errcode < errcodereasonlen)
+		buf = g_strdup_printf(_("Unable to send message: %s (%s)"), reason_str,
+		                      _(errcodereason[errcode]));
+	else
+		buf = g_strdup_printf(_("Unable to send message: %s"), reason_str);
+
 	if (!purple_conv_present_error(data, purple_connection_get_account(gc), buf)) {
 		g_free(buf);
-		buf = g_strdup_printf(_("Unable to send message to %s:"), data ? data : "(unknown)");
-		purple_notify_error(od->gc, NULL, buf,
-				  (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
+		if (errcode != 0 && errcode < errcodereasonlen)
+			buf = g_strdup_printf(_("Unable to send message to %s: %s (%s)"),
+			                      data ? data : "(unknown)", reason_str,
+			                      _(errcodereason[errcode]));
+		else
+			buf = g_strdup_printf(_("Unable to send message to %s: %s"),
+			                      data ? data : "(unknown)", reason_str);
+		purple_notify_error(od->gc, NULL, buf, reason_str);
 	}
 	g_free(buf);
+	g_free(reason_str);
 
 	return 1;
 }
@@ -3740,7 +3775,8 @@
 	};
 	va_list ap;
 	guint16 code, rateclass;
-	guint32 windowsize, clear, alert, limit, disconnect, currentavg, maxavg;
+	guint32 windowsize, clear, alert, limit, disconnect, currentavg, maxavg, delta;
+	guint8 dropping_snacs;
 
 	va_start(ap, fr);
 	code = (guint16)va_arg(ap, unsigned int);
@@ -3752,23 +3788,28 @@
 	disconnect = va_arg(ap, guint32);
 	currentavg = va_arg(ap, guint32);
 	maxavg = va_arg(ap, guint32);
+	delta = va_arg(ap, guint32);
+	dropping_snacs = (guint8)va_arg(ap, unsigned int);
 	va_end(ap);
 
 	purple_debug_misc("oscar",
 			   "rate %s (param ID 0x%04hx): curavg = %u, maxavg = %u, alert at %u, "
-		     "clear warning at %u, limit at %u, disconnect at %u (window size = %u)\n",
+		     "clear warning at %u, limit at %u, disconnect at %u, delta is %u, dropping is %u (window size = %u)\n",
 		     (code < 5) ? codes[code] : codes[0],
 		     rateclass,
 		     currentavg, maxavg,
 		     alert, clear,
 		     limit, disconnect,
-		     windowsize);
+		     delta,
+		     dropping_snacs,
+		     windowsize
+		     );
 
 	if (code == AIM_RATE_CODE_LIMIT)
 	{
 		purple_debug_warning("oscar",  _("The last action you attempted could not be "
 				"performed because you are over the rate limit. "
-				"Please wait 10 seconds and try again."));
+				"Please wait 10 seconds and try again.\n"));
 	}
 
 	return 1;
@@ -5264,9 +5305,9 @@
 			report_idle = strcmp(idle_reporting_pref, "none") != 0;
 
 			if (report_idle)
-				aim_ssi_setpresence(od, tmp | 0x400);
+				aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
 			else
-				aim_ssi_setpresence(od, tmp & ~0x400);
+				aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
 		}
 
 
@@ -5276,7 +5317,7 @@
 	for (curitem=od->ssi.local; curitem; curitem=curitem->next) {
 	  if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL)))
 		switch (curitem->type) {
-			case 0x0000: { /* Buddy */
+			case AIM_SSI_TYPE_BUDDY: { /* Buddy */
 				if (curitem->name) {
 					struct aim_ssi_item *groupitem;
 					char *gname, *gname_utf8, *alias, *alias_utf8;
@@ -5342,7 +5383,7 @@
 				}
 			} break;
 
-			case 0x0001: { /* Group */
+			case AIM_SSI_TYPE_GROUP: { /* Group */
 				char *gname;
 				char *gname_utf8;
 
@@ -5362,7 +5403,7 @@
 				g_free(gname_utf8);
 			} break;
 
-			case 0x0002: { /* Permit buddy */
+			case AIM_SSI_TYPE_PERMIT: { /* Permit buddy */
 				if (curitem->name) {
 					/* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */
 					GSList *list;
@@ -5375,7 +5416,7 @@
 				}
 			} break;
 
-			case 0x0003: { /* Deny buddy */
+			case AIM_SSI_TYPE_DENY: { /* Deny buddy */
 				if (curitem->name) {
 					GSList *list;
 					for (list=account->deny; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next);
@@ -5387,7 +5428,7 @@
 				}
 			} break;
 
-			case 0x0004: { /* Permit/deny setting */
+			case AIM_SSI_TYPE_PDINFO: { /* Permit/deny setting */
 				/*
 				 * We don't inherit the permit/deny setting from the server
 				 * for ICQ because, for ICQ, this setting controls who can
@@ -5405,7 +5446,7 @@
 				}
 			} break;
 
-			case 0x0005: { /* Presence setting */
+			case AIM_SSI_TYPE_PRESENCEPREFS: { /* Presence setting */
 				/* We don't want to change Purple's setting because it applies to all accounts */
 			} break;
 		} /* End of switch on curitem->type */
--- a/libpurple/protocols/oscar/oscar.h	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Wed Nov 04 18:41:51 2009 +0000
@@ -661,7 +661,7 @@
 void flap_connection_send(FlapConnection *conn, FlapFrame *frame);
 void flap_connection_send_version(OscarData *od, FlapConnection *conn);
 void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy);
-void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci);
+void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_login);
 void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data);
 void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority);
 void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn);
@@ -1240,7 +1240,7 @@
 #define AIM_SSI_ACK_INVALIDNAME		0x000d
 #define AIM_SSI_ACK_AUTHREQUIRED	0x000e
 
-/* These flags are set in the 0x00c9 TLV of SSI teyp 0x0005 */
+/* These flags are set in the 0x00c9 TLV of SSI type 0x0005 */
 #define AIM_SSI_PRESENCE_FLAG_SHOWIDLE        0x00000400
 #define AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES 0x00020000
 
@@ -1685,7 +1685,8 @@
 	guint32 disconnect;
 	guint32 current;
 	guint32 max;
-	guint8 unknown[5]; /* only present in versions >= 3 */
+	guint32 delta;
+	guint8 dropping_snacs;
 	GHashTable *members; /* Key is family and subtype, value is TRUE. */
 
 	struct timeval last; /**< The time when we last sent a SNAC of this rate class. */
--- a/libpurple/protocols/silc/Makefile.mingw	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/silc/Makefile.mingw	Wed Nov 04 18:41:51 2009 +0000
@@ -7,6 +7,8 @@
 PIDGIN_TREE_TOP := ../../..
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
+DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES))
+
 TARGET = libsilc
 NEEDED_DLLS =		$(SILC_TOOLKIT)/bin/libsilc-1-1-2.dll \
 			$(SILC_TOOLKIT)/bin/libsilcclient-1-1-2.dll
@@ -79,7 +81,7 @@
 $(OBJECTS): $(PURPLE_CONFIG_H)
 
 $(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS)
-	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--image-base,0x64000000 -o $(TARGET).dll
+	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--image-base,0x74000000 -o $(TARGET).dll
 
 ##
 ## CLEAN RULES
--- a/libpurple/protocols/silc10/Makefile.mingw	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/silc10/Makefile.mingw	Wed Nov 04 18:41:51 2009 +0000
@@ -7,6 +7,8 @@
 PIDGIN_TREE_TOP := ../../..
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
+DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES))
+
 TARGET = libsilc
 NEEDED_DLLS =		$(SILC_TOOLKIT)/lib/silc.dll \
 			$(SILC_TOOLKIT)/lib/silcclient.dll
--- a/libpurple/protocols/yahoo/libyahoo.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/yahoo/libyahoo.c	Wed Nov 04 18:41:51 2009 +0000
@@ -249,7 +249,7 @@
 	yahoo_roomlist_get_list,
 	yahoo_roomlist_cancel,
 	yahoo_roomlist_expand_category,
-	NULL, /* can_receive_file */
+	yahoo_can_receive_file, /* can_receive_file */
 	yahoo_send_file,
 	yahoo_new_xfer,
 	yahoo_offline_message, /* offline_message */
--- a/libpurple/protocols/yahoo/libymsg.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Wed Nov 04 18:41:51 2009 +0000
@@ -154,6 +154,7 @@
 	gboolean unicode = FALSE;
 	char *message = NULL;
 	YahooFederation fed = YAHOO_FEDERATION_NONE;
+	char *fedname = NULL;
 
 	if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
 		if (!purple_account_get_remember_password(account))
@@ -194,18 +195,20 @@
 						break;
 					if (p->key == 241) {
 						fed = strtol(p->value, NULL, 10);
+						g_free(fedname);
 						switch (fed) {
 							case YAHOO_FEDERATION_MSN:
-								name = g_strconcat("msn/", name, NULL);
+								name = fedname = g_strconcat("msn/", name, NULL);
 								break;
 							case YAHOO_FEDERATION_OCS:
-								name = g_strconcat("ocs/", name, NULL);
+								name = fedname = g_strconcat("ocs/", name, NULL);
 								break;
 							case YAHOO_FEDERATION_IBM:
-								name = g_strconcat("ibm/", name, NULL);
+								name = fedname = g_strconcat("ibm/", name, NULL);
 								break;
 							case YAHOO_FEDERATION_NONE:
 							default:
+								fedname = NULL;
 								break;
 						}
 						break;
@@ -390,6 +393,7 @@
 			yahoo_update_status(gc, name, f);
 	}
 
+	g_free(fedname);
 }
 
 static void yahoo_do_group_check(PurpleAccount *account, GHashTable *ht, const char *name, const char *group)
@@ -879,6 +883,7 @@
 	char *id;
 	char *msg;
 	YahooFederation fed;
+	char *fed_from;
 };
 
 static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt)
@@ -950,9 +955,6 @@
 	GSList *l = pkt->hash;
 	GSList *list = NULL;
 	struct _yahoo_im *im = NULL;
-	const char *imv = NULL;
-	gint val_11 = 0;
-	char *fed_from = NULL;
 
 	account = purple_connection_get_account(gc);
 
@@ -963,10 +965,11 @@
 			if (pair->key == 4 || pair->key == 1) {
 				im = g_new0(struct _yahoo_im, 1);
 				list = g_slist_append(list, im);
-				im->from = fed_from = pair->value;
+				im->from = pair->value;
 				im->time = time(NULL);
 				im->utf8 = TRUE;
 				im->fed = YAHOO_FEDERATION_NONE;
+				im->fed_from = g_strdup(im->from);
 			}
 			if (im && pair->key == 5)
 				im->active_id = pair->value;
@@ -985,32 +988,75 @@
 			}
 			if (im && pair->key == 241) {
 				im->fed = strtol(pair->value, NULL, 10);
+				g_free(im->fed_from);
 				switch (im->fed) {
 					case YAHOO_FEDERATION_MSN:
-						fed_from = g_strconcat("msn/",im->from, NULL);
+						im->fed_from = g_strconcat("msn/",im->from, NULL);
 						break;
 					case YAHOO_FEDERATION_OCS:
-						fed_from = g_strconcat("ocs/",im->from, NULL);
+						im->fed_from = g_strconcat("ocs/",im->from, NULL);
 						break;
 					case YAHOO_FEDERATION_IBM:
-						fed_from = g_strconcat("ibm/",im->from, NULL);
+						im->fed_from = g_strconcat("ibm/",im->from, NULL);
 						break;
 					case YAHOO_FEDERATION_NONE:
 					default:
+						im->fed_from = g_strdup(im->from);
 						break;
 				}
-				purple_debug_info("yahoo", "Message from federated (%d) buddy %s.\n", im->fed, fed_from);
+				purple_debug_info("yahoo", "Message from federated (%d) buddy %s.\n", im->fed, im->fed_from);
 					
 			}
 			/* peer session id */
-			if (pair->key == 11) {
-				if (im)
-					val_11 = strtol(pair->value, NULL, 10);
+			if (im && (pair->key == 11)) {
+				/* disconnect the peer if connected through p2p and sends wrong value for session id */
+				if( (im->fed == YAHOO_FEDERATION_NONE) && (pkt_type == YAHOO_PKT_TYPE_P2P) 
+						&& (yd->session_id != strtol(pair->value, NULL, 10)) )
+				{
+					purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im->fed_from);
+					/* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
+					g_hash_table_remove(yd->peers, im->fed_from);
+					g_free(im->fed_from);
+					g_free(im);
+					return; /* Not sure whether we should process remaining IMs in this packet */
+				}
 			}
 			/* IMV key */
-			if (pair->key == 63)
+			if (im && pair->key == 63)
 			{
-				imv = pair->value;
+				/* Check for the Doodle IMV, no IMvironment for federated buddies */
+				if (im->from != NULL && im->fed == YAHOO_FEDERATION_NONE)
+				{
+					g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(pair->value));
+
+					if (strstr(pair->value, "doodle;") != NULL)
+					{
+						PurpleWhiteboard *wb;
+
+						if (!purple_privacy_check(account, im->from)) {
+							purple_debug_info("yahoo", "Doodle request from %s dropped.\n",
+												im->from);
+							g_free(im->fed_from);
+							g_free(im);
+							return;
+						}
+						/* I'm not sure the following ever happens -DAA */
+						wb = purple_whiteboard_get_session(account, im->from);
+
+						/* If a Doodle session doesn't exist between this user */
+						if(wb == NULL)
+						{
+							doodle_session *ds;
+							wb = purple_whiteboard_create(account, im->from,
+											DOODLE_STATE_REQUESTED);
+							ds = wb->proto_data;
+							ds->imv_key = g_strdup(pair->value);
+
+							yahoo_doodle_command_send_request(gc, im->from, pair->value);
+							yahoo_doodle_command_send_ready(gc, im->from, pair->value);
+						}
+					}
+				}
 			}
 			if (pair->key == 429)
 				if (im)
@@ -1022,63 +1068,19 @@
 		                  _("Your Yahoo! message did not get sent."), NULL);
 	}
 
-	/* disconnect the peer if connected through p2p and sends wrong value for session id */
-	if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) {
-		purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im ? fed_from : "(im was null)");
-		/* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
-		if (im) {
-			g_hash_table_remove(yd->peers, fed_from);
-			g_free(im);
-		}
-		return;
-	}
-
-	/* TODO: It seems that this check should be per IM, not global */
-	/* Check for the Doodle IMV */
-	/* no doodle with federated buddies -- assumption???  */
-	if (im != NULL && imv!= NULL && im->from != NULL)
-	{
-		g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(imv));
-
-		if (strstr(imv, "doodle;") != NULL)
-		{
-			PurpleWhiteboard *wb;
-
-			if (!purple_privacy_check(account, im->from)) {
-				purple_debug_info("yahoo", "Doodle request from %s dropped.\n", im->from);
-				return;
-			}
-
-			/* I'm not sure the following ever happens -DAA */
-
-			wb = purple_whiteboard_get_session(account, im->from);
-
-			/* If a Doodle session doesn't exist between this user */
-			if(wb == NULL)
-			{
-				doodle_session *ds;
-				wb = purple_whiteboard_create(account, im->from, DOODLE_STATE_REQUESTED);
-				ds = wb->proto_data;
-				ds->imv_key = g_strdup(imv);
-
-				yahoo_doodle_command_send_request(gc, im->from, imv);
-				yahoo_doodle_command_send_ready(gc, im->from, imv);
-			}
-		}
-	}
-
 	for (l = list; l; l = l->next) {
 		YahooFriend *f;
 		char *m, *m2;
 		im = l->data;
 
-		if (!fed_from || !im->msg) {
+		if (!im->fed_from || !im->msg) {
+			g_free(im->fed_from);
 			g_free(im);
 			continue;
 		}
 
-		if (!purple_privacy_check(account, fed_from)) {
-			purple_debug_info("yahoo", "Message from %s dropped.\n", fed_from);
+		if (!purple_privacy_check(account, im->fed_from)) {
+			purple_debug_info("yahoo", "Message from %s dropped.\n", im->fed_from);
 			return;
 		}
 
@@ -1116,10 +1118,11 @@
 		if (!strcmp(m, "<ding>")) {
 			char *username;
 
-			username = g_markup_escape_text(fed_from, -1);
+			username = g_markup_escape_text(im->fed_from, -1);
 			purple_prpl_got_attention(gc, username, YAHOO_BUZZ);
 			g_free(username);
 			g_free(m);
+			g_free(im->fed_from);
 			g_free(im);
 			continue;
 		}
@@ -1127,7 +1130,7 @@
 		m2 = yahoo_codes_to_html(m);
 		g_free(m);
 
-		serv_got_im(gc, fed_from, m2, 0, im->time);
+		serv_got_im(gc, im->fed_from, m2, 0, im->time);
 		g_free(m2);
 
 		/* Official clients don't share buddy images with federated buddies */
@@ -1140,9 +1143,7 @@
 			}
 		}
 
-		if(im->fed != YAHOO_FEDERATION_NONE)
-			g_free(fed_from);
-
+		g_free(im->fed_from);
 		g_free(im);
 	}
 
@@ -3998,7 +3999,7 @@
 
 	}
 
-	if (f && f->status != YAHOO_STATUS_OFFLINE) {
+	if (f && f->status != YAHOO_STATUS_OFFLINE && f->fed == YAHOO_FEDERATION_NONE) {
 		if (!yd->wm) {
 			act = purple_menu_action_new(_("Join in Chat"),
 			                           PURPLE_CALLBACK(yahoo_chat_goto_menu),
@@ -4038,10 +4039,12 @@
 		                           build_presence_submenu(f, gc));
 		m = g_list_append(m, act);
 
-		act = purple_menu_action_new(_("Start Doodling"),
-		                           PURPLE_CALLBACK(yahoo_doodle_blist_node),
-		                           NULL, NULL);
-		m = g_list_append(m, act);
+		if (f->fed == YAHOO_FEDERATION_NONE) {
+			act = purple_menu_action_new(_("Start Doodling"),
+					PURPLE_CALLBACK(yahoo_doodle_blist_node),
+					NULL, NULL);
+			m = g_list_append(m, act);
+		}
 
 		act = purple_menu_action_new(_("Set User Info..."),
 		                           PURPLE_CALLBACK(yahoo_userinfo_blist_node),
@@ -4366,17 +4369,7 @@
 		}
 	}
 
-	if (who[3] == '/') {
-		if (!g_ascii_strncasecmp(who, "msn/", 4)) {
-			fed = YAHOO_FEDERATION_MSN;
-		}
-		else if (!g_ascii_strncasecmp(who, "ocs/", 4)) {
-			fed = YAHOO_FEDERATION_OCS;
-		}
-		else if (!g_ascii_strncasecmp(who, "ibm/", 4)) {
-			fed = YAHOO_FEDERATION_IBM;
-		}
-	}
+	fed = yahoo_get_federation_from_name(who);
 
 	if (who[0] == '+') {
 		/* we have an sms to be sent */
@@ -4508,17 +4501,7 @@
 	YahooFederation fed = YAHOO_FEDERATION_NONE;
 	struct yahoo_packet *pkt = NULL;
 
-	if (who[3] == '/') {
-		if (!g_ascii_strncasecmp(who, "msn/", 4)) {
-			fed = YAHOO_FEDERATION_MSN;
-		}
-		else if (!g_ascii_strncasecmp(who, "ocs/", 4)) {
-			fed = YAHOO_FEDERATION_OCS;
-		}
-		else if (!g_ascii_strncasecmp(who, "ibm/", 4)) {
-			fed = YAHOO_FEDERATION_IBM;
-		}
-	}
+	fed = yahoo_get_federation_from_name(who);
 
 	/* Don't do anything if sms is being typed */
 	if( strncmp(who, "+", 1) == 0 )
@@ -4810,18 +4793,9 @@
 		return;
 
 	f = yahoo_friend_find(gc, bname);
-	if (bname[3] == '/') {
+	fed = yahoo_get_federation_from_name(bname);
+	if (fed != YAHOO_FEDERATION_NONE)
 		fed_bname += 4;
-		if (!g_ascii_strncasecmp(bname, "msn/", 4)) {
-			fed = YAHOO_FEDERATION_MSN;
-		}
-		else if (!g_ascii_strncasecmp(bname, "ocs/", 4)) {
-			fed = YAHOO_FEDERATION_OCS;
-		}
-		else if (!g_ascii_strncasecmp(bname, "ibm/", 4)) {
-			fed = YAHOO_FEDERATION_IBM;
-		}
-	}
 
 	g = purple_buddy_get_group(buddy);
 	if (g)
@@ -4933,18 +4907,8 @@
 	if (!who || who[0] == '\0')
 		return;
 
-	if (who[3] == '/') {
-		if (!g_ascii_strncasecmp(who, "msn/", 4)) {
-			fed = YAHOO_FEDERATION_MSN;
-		}
-		else if (!g_ascii_strncasecmp(who, "ocs/", 4)) {
-			fed = YAHOO_FEDERATION_OCS;
-		}
-		else if (!g_ascii_strncasecmp(who, "ibm/", 4)) {
-			fed = YAHOO_FEDERATION_IBM;
-		}
-	}
-	
+	fed = yahoo_get_federation_from_name(who);
+
 	pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
 
 	if(fed)
@@ -4965,17 +4929,8 @@
 
 	if (!who || who[0] == '\0')
 		return;
-	if (who[3] == '/') {
-		if (!g_ascii_strncasecmp(who, "msn/", 4)) {
-			fed = YAHOO_FEDERATION_MSN;
-		}
-		else if (!g_ascii_strncasecmp(who, "ocs/", 4)) {
-			fed = YAHOO_FEDERATION_OCS;
-		}
-		else if (!g_ascii_strncasecmp(who, "ibm/", 4)) {
-			fed = YAHOO_FEDERATION_IBM;
-		}
-	}
+	fed = yahoo_get_federation_from_name(who);
+
 	pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
 
 	if(fed)
--- a/libpurple/protocols/yahoo/libymsg.h	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/yahoo/libymsg.h	Wed Nov 04 18:41:51 2009 +0000
@@ -346,6 +346,7 @@
 
 char *yahoo_convert_to_numeric(const char *str);
 
+YahooFederation yahoo_get_federation_from_name(const char *who);
 
 /* yahoo_profile.c */
 void yahoo_get_info(PurpleConnection *gc, const char *name);
--- a/libpurple/protocols/yahoo/util.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/yahoo/util.c	Wed Nov 04 18:41:51 2009 +0000
@@ -916,3 +916,18 @@
 
 	return g_string_free(dest, FALSE);
 }
+
+YahooFederation yahoo_get_federation_from_name(const char *who)
+{
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
+	if (who[3] == '/') {
+		if (!g_ascii_strncasecmp(who, "msn", 3))
+			fed = YAHOO_FEDERATION_MSN;
+		else if (!g_ascii_strncasecmp(who, "ocs", 3))
+			fed = YAHOO_FEDERATION_OCS;
+		else if (!g_ascii_strncasecmp(who, "ibm", 3))
+			fed = YAHOO_FEDERATION_IBM;
+	}
+	return fed;
+}
+
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Wed Nov 04 18:41:51 2009 +0000
@@ -1070,6 +1070,13 @@
 	yahoo_packet_send_and_free(pkt, yd);
 }
 
+gboolean yahoo_can_receive_file(PurpleConnection *gc, const char *who)
+{
+	if (!who || yahoo_get_federation_from_name(who) != YAHOO_FEDERATION_NONE)
+		return FALSE;
+	return TRUE;
+}
+
 void yahoo_send_file(PurpleConnection *gc, const char *who, const char *file)
 {
 	struct yahoo_xfer_data *xfer_data;
--- a/libpurple/protocols/yahoo/yahoo_filexfer.h	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.h	Wed Nov 04 18:41:51 2009 +0000
@@ -43,6 +43,18 @@
 PurpleXfer *yahoo_new_xfer(PurpleConnection *gc, const char *who);
 
 /**
+ * Returns TRUE if the buddy can receive file, FALSE otherwise.
+ * Federated users cannot receive files. So this will return FALSE only
+ * for them.
+ *
+ * @param gc The connection
+ * @param who The name of the remote user
+ *
+ * @return TRUE or FALSE
+ */
+gboolean yahoo_can_receive_file(PurpleConnection *gc, const char *who);
+
+/**
  * Send a file.
  *
  * @param gc The PurpleConnection handle.
--- a/libpurple/theme-loader.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/theme-loader.c	Wed Nov 04 18:41:51 2009 +0000
@@ -100,6 +100,7 @@
 	PurpleThemeLoaderPrivate *priv = PURPLE_THEME_LOADER_GET_PRIVATE(loader);
 
 	g_free(priv->type);
+	g_free(priv);
 
 	parent_class->finalize(obj);
 }
--- a/libpurple/win32/global.mak	Wed Nov 04 18:41:21 2009 +0000
+++ b/libpurple/win32/global.mak	Wed Nov 04 18:41:51 2009 +0000
@@ -85,7 +85,7 @@
 DEFINES += -DHAVE_CYRUS_SASL
 endif
 
-DEFINES += -DHAVE_CONFIG_H
+DEFINES += -DHAVE_CONFIG_H -DWIN32_LEAN_AND_MEAN
 
 # Use -g flag when building debug version of Pidgin (including plugins).
 # Use -fnative-struct instead of -mms-bitfields when using mingw 1.1
--- a/pidgin/Makefile.mingw	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/Makefile.mingw	Wed Nov 04 18:41:51 2009 +0000
@@ -7,6 +7,8 @@
 PIDGIN_TREE_TOP := ..
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
+DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES))
+
 NEEDED_DLLS = $(GTKSPELL_TOP)/gtkspell/libgtkspell.dll
 
 ##
@@ -55,12 +57,12 @@
 ##
 PIDGIN_C_SRC =	\
 			gtkaccount.c \
-			gtkblist.c \
+			gtkblist-theme-loader.c \
 			gtkblist-theme.c \
-			gtkblist-theme-loader.c \
-			gtkcertmgr.c \
+			gtkblist.c \
 			gtkcellrendererexpander.c \
 			gtkcellrendererprogress.c \
+			gtkcertmgr.c \
 			gtkconn.c \
 			gtkconv.c \
 			gtkdebug.c \
@@ -70,8 +72,8 @@
 			gtkeventloop.c \
 			gtkexpander.c \
 			gtkft.c \
+			gtkicon-theme-loader.c \
 			gtkicon-theme.c \
-			gtkicon-theme-loader.c \
 			gtkidle.c \
 			gtkimhtml.c \
 			gtkimhtmltoolbar.c \
--- a/pidgin/gtkblist.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/gtkblist.c	Wed Nov 04 18:41:51 2009 +0000
@@ -4184,6 +4184,12 @@
 		}
 	}
 
+	if (hidden_conv) {
+		char *tmp = nametext;
+		nametext = g_strdup_printf("<b>%s</b>", tmp);
+		g_free(tmp);
+	}
+
 	/* Put it all together */
 	if ((!aliased || biglist) && (statustext || idletime)) {
 		/* using <span size='smaller'> breaks the status, so it must be seperated into <small><span>*/
--- a/pidgin/gtkimhtml.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/gtkimhtml.c	Wed Nov 04 18:41:51 2009 +0000
@@ -5053,7 +5053,7 @@
 		                                     It will be destroyed when 'anchor' is destroyed. */
 		anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
 		g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", text, g_free);
-		g_object_set_data(G_OBJECT(anchor), "gtkimhtml_tiptext", text);
+		g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_tiptext", g_strdup(text), g_free);
 		g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free);
 
 		/* This catches the expose events generated by animated
@@ -5075,7 +5075,8 @@
 			gtk_container_add(GTK_CONTAINER(ebox), img);
 			gtk_widget_show(img);
 			g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", text, g_free);
-			g_object_set_data(G_OBJECT(anchor), "gtkimhtml_tiptext", text);
+			g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_tiptext",
+				g_strdup(text), g_free);
 			g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free);
 			gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), ebox, anchor);
 		}
--- a/pidgin/gtkmain.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/gtkmain.c	Wed Nov 04 18:41:51 2009 +0000
@@ -744,7 +744,7 @@
 	}
 
 #if GLIB_CHECK_VERSION(2,2,0)
-	g_set_application_name(_("Pidgin"));
+	g_set_application_name(PIDGIN_NAME);
 #endif /* glib-2.0 >= 2.2.0 */
 
 #ifdef _WIN32
--- a/pidgin/gtkprefs.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/gtkprefs.c	Wed Nov 04 18:41:51 2009 +0000
@@ -77,6 +77,7 @@
 static GtkListStore *smiley_theme_store = NULL;
 static GtkTreeSelection *smiley_theme_sel = NULL;
 static GtkWidget *prefs_proxy_frame = NULL;
+static GtkWidget *prefs_proxy_subframe = NULL;
 
 static GtkWidget *prefs = NULL;
 static GtkWidget *debugbutton = NULL;
@@ -624,7 +625,8 @@
 		_("The default Pidgin status icon theme"));
 	gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, tmp, 2, "", -1);
 	g_free(tmp);
-	g_object_unref(G_OBJECT(pixbuf));
+	if (pixbuf)
+		g_object_unref(G_OBJECT(pixbuf));
 
 	purple_theme_manager_for_each_theme(prefs_themes_sort);
 	pref_sound_generate_markup();
@@ -1886,23 +1888,27 @@
 	pidgin_prefs_checkbox(_("_Enable automatic router port forwarding"),
 			"/purple/network/map_ports", vbox);
 
-	ports_checkbox = pidgin_prefs_checkbox(_("_Manually specify range of ports to listen on"),
-			"/purple/network/ports_range_use", vbox);
-
-	spin_button = pidgin_prefs_labeled_spin_button(vbox, _("_Start port:"),
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+
+	ports_checkbox = pidgin_prefs_checkbox(_("_Manually specify range of ports to listen on:"),
+			"/purple/network/ports_range_use", hbox);
+
+	spin_button = pidgin_prefs_labeled_spin_button(hbox, _("_Start:"),
 			"/purple/network/ports_range_start", 0, 65535, sg);
 	if (!purple_prefs_get_bool("/purple/network/ports_range_use"))
 		gtk_widget_set_sensitive(GTK_WIDGET(spin_button), FALSE);
 	g_signal_connect(G_OBJECT(ports_checkbox), "clicked",
 					 G_CALLBACK(pidgin_toggle_sensitive), spin_button);
 
-	spin_button = pidgin_prefs_labeled_spin_button(vbox, _("_End port:"),
+	spin_button = pidgin_prefs_labeled_spin_button(hbox, _("_End:"),
 			"/purple/network/ports_range_end", 0, 65535, sg);
 	if (!purple_prefs_get_bool("/purple/network/ports_range_use"))
 		gtk_widget_set_sensitive(GTK_WIDGET(spin_button), FALSE);
 	g_signal_connect(G_OBJECT(ports_checkbox), "clicked",
 					 G_CALLBACK(pidgin_toggle_sensitive), spin_button);
 
+	pidgin_add_widget_to_vbox(GTK_BOX(vbox), NULL, NULL, hbox, TRUE, NULL);
+
 	g_object_unref(sg);
 
 	/* TURN server */
@@ -1921,9 +1927,9 @@
 
 	pidgin_prefs_labeled_spin_button(hbox, _("_Port:"),
 		"/purple/network/turn_port", 0, 65535, NULL);
-	hbox = pidgin_prefs_labeled_entry(vbox, _("_Username:"),
+	hbox = pidgin_prefs_labeled_entry(vbox, _("Use_rname:"),
 		"/purple/network/turn_username", sg);
-	pidgin_prefs_labeled_password(hbox, _("_Password:"),
+	pidgin_prefs_labeled_password(hbox, _("Pass_word:"),
 		"/purple/network/turn_password", NULL);
 
 	if (purple_running_gnome()) {
@@ -1967,9 +1973,15 @@
 		gtk_widget_show(browser_button);
 	} else {
 		vbox = pidgin_make_frame(ret, _("Proxy Server"));
-		prefs_proxy_frame = gtk_vbox_new(FALSE, 0);
-
-		pidgin_prefs_dropdown(vbox, _("Proxy _type:"), PURPLE_PREF_STRING,
+		prefs_proxy_frame = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+		prefs_proxy_subframe = gtk_vbox_new(FALSE, 0);
+
+		/* This is a global option that affects SOCKS4 usage even with account-specific proxy settings */
+		pidgin_prefs_checkbox(_("Use remote _DNS with SOCKS4 proxies"),
+							  "/purple/proxy/socks4_remotedns", prefs_proxy_frame);
+		gtk_box_pack_start(GTK_BOX(vbox), prefs_proxy_frame, 0, 0, 0);
+
+		pidgin_prefs_dropdown(prefs_proxy_frame, _("Proxy t_ype:"), PURPLE_PREF_STRING,
 					"/purple/proxy/type",
 					_("No proxy"), "none",
 					"SOCKS 4", "socks4",
@@ -1977,21 +1989,17 @@
 					"HTTP", "http",
 					_("Use Environmental Settings"), "envvar",
 					NULL);
-		gtk_box_pack_start(GTK_BOX(vbox), prefs_proxy_frame, 0, 0, 0);
+		gtk_box_pack_start(GTK_BOX(prefs_proxy_frame), prefs_proxy_subframe, 0, 0, 0);
 		proxy_info = purple_global_proxy_get_info();
 
 		purple_prefs_connect_callback(prefs, "/purple/proxy/type",
-					    proxy_changed_cb, prefs_proxy_frame);
-
-		/* This is a global option that affects SOCKS4 usage even with account-specific proxy settings */
-		pidgin_prefs_checkbox(_("Use remote DNS with SOCKS4 proxies"),
-							  "/purple/proxy/socks4_remotedns", prefs_proxy_frame);
+					    proxy_changed_cb, prefs_proxy_subframe);
 
 		table = gtk_table_new(4, 2, FALSE);
 		gtk_container_set_border_width(GTK_CONTAINER(table), 0);
 		gtk_table_set_col_spacings(GTK_TABLE(table), 5);
 		gtk_table_set_row_spacings(GTK_TABLE(table), 10);
-		gtk_container_add(GTK_CONTAINER(prefs_proxy_frame), table);
+		gtk_container_add(GTK_CONTAINER(prefs_proxy_subframe), table);
 
 
 		label = gtk_label_new_with_mnemonic(_("_Host:"));
@@ -2012,11 +2020,11 @@
 		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 		pidgin_set_accessible_label (entry, label);
 
-		label = gtk_label_new_with_mnemonic(_("_Port:"));
+		label = gtk_label_new_with_mnemonic(_("P_ort:"));
 		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
 		gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
 
-		entry = gtk_entry_new();
+		entry = gtk_spin_button_new_with_range(0, 65535, 1);
 		gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
 		gtk_table_attach(GTK_TABLE(table), entry, 3, 4, 0, 1, GTK_FILL, 0, 0, 0);
 		g_signal_connect(G_OBJECT(entry), "changed",
@@ -2031,7 +2039,7 @@
 		}
 		pidgin_set_accessible_label (entry, label);
 
-		label = gtk_label_new_with_mnemonic(_("_User:"));
+		label = gtk_label_new_with_mnemonic(_("User_name:"));
 		gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
 		gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
 
--- a/pidgin/gtkrequest.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/gtkrequest.c	Wed Nov 04 18:41:51 2009 +0000
@@ -81,6 +81,33 @@
 } PidginRequestData;
 
 static void
+pidgin_widget_decorate_account(GtkWidget *cont, PurpleAccount *account)
+{
+	GtkWidget *image;
+	GdkPixbuf *pixbuf;
+	GtkTooltips *tips;
+
+	if (!account)
+		return;
+
+	pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
+	image = gtk_image_new_from_pixbuf(pixbuf);
+	g_object_unref(G_OBJECT(pixbuf));
+
+	tips = gtk_tooltips_new();
+	gtk_tooltips_set_tip(tips, image, purple_account_get_username(account), NULL);
+
+	if (GTK_IS_DIALOG(cont)) {
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cont)->action_area), image, FALSE, TRUE, 0);
+		gtk_box_reorder_child(GTK_BOX(GTK_DIALOG(cont)->action_area), image, 0);
+	} else if (GTK_IS_HBOX(cont)) {
+		gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
+		gtk_box_pack_end(GTK_BOX(cont), image, FALSE, TRUE, 0);
+	}
+	gtk_widget_show(image);
+}
+
+static void
 generic_response_start(PidginRequestData *data)
 {
 	g_return_if_fail(data != NULL);
@@ -347,6 +374,8 @@
 
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
 
+	pidgin_widget_decorate_account(hbox, account);
+
 	/* Descriptive label */
 	primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL;
 	secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL;
@@ -515,6 +544,8 @@
 	gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
 	gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
 
+	pidgin_widget_decorate_account(hbox, account);
+
 	/* Vertical box */
 	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
@@ -639,6 +670,8 @@
 	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
 
+	pidgin_widget_decorate_account(hbox, account);
+
 	/* Descriptive label */
 	primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL;
 	secondary_esc = (secondary != NULL) ? g_markup_escape_text(secondary, -1) : NULL;
@@ -1144,6 +1177,8 @@
 	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
 	gtk_window_set_default(GTK_WINDOW(win), button);
 
+	pidgin_widget_decorate_account(hbox, account);
+
 	/* Setup the vbox */
 	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
 	gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
--- a/pidgin/gtkstatusbox.c	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/gtkstatusbox.c	Wed Nov 04 18:41:51 2009 +0000
@@ -79,8 +79,8 @@
 
 static void pidgin_status_box_pulse_typing(PidginStatusBox *status_box);
 static void pidgin_status_box_refresh(PidginStatusBox *status_box);
-static void status_menu_refresh_iter(PidginStatusBox *status_box);
-static void pidgin_status_box_regenerate(PidginStatusBox *status_box);
+static void status_menu_refresh_iter(PidginStatusBox *status_box, gboolean status_changed);
+static void pidgin_status_box_regenerate(PidginStatusBox *status_box, gboolean status_changed);
 static void pidgin_status_box_changed(PidginStatusBox *box);
 static void pidgin_status_box_size_request (GtkWidget *widget, GtkRequisition *requisition);
 static void pidgin_status_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
@@ -304,7 +304,7 @@
 	if (status_box->account == account)
 		update_to_reflect_account_status(status_box, account, newstatus);
 	else if (status_box->token_status_account == account)
-		status_menu_refresh_iter(status_box);
+		status_menu_refresh_iter(status_box, TRUE);
 }
 
 static gboolean
@@ -312,6 +312,7 @@
 {
 	if (event->button == 3) {
 		GtkWidget *menu_item;
+		const char *path;
 
 		if (box->icon_box_menu)
 			gtk_widget_destroy(box->icon_box_menu);
@@ -325,7 +326,8 @@
 		menu_item = pidgin_new_item_from_stock(box->icon_box_menu, _("Remove"), GTK_STOCK_REMOVE,
 						     G_CALLBACK(remove_buddy_icon_cb),
 						     box, 0, 0, NULL);
-		if (purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon") == NULL)
+		if (!(path = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon"))
+				|| !*path)
 			gtk_widget_set_sensitive(menu_item, FALSE);
 
 		gtk_menu_popup(GTK_MENU(box->icon_box_menu), NULL, NULL, NULL, NULL,
@@ -559,7 +561,7 @@
 		else
 			statusbox->token_status_account = check_active_accounts_for_identical_statuses();
 
-		pidgin_status_box_regenerate(statusbox);
+		pidgin_status_box_regenerate(statusbox, TRUE);
 
 		break;
 	default:
@@ -821,7 +823,7 @@
  * keyboard signals instead of the changed signal?
  */
 static void
-status_menu_refresh_iter(PidginStatusBox *status_box)
+status_menu_refresh_iter(PidginStatusBox *status_box, gboolean status_changed)
 {
 	PurpleSavedStatus *saved_status;
 	PurpleStatusPrimitive primitive;
@@ -912,18 +914,15 @@
 	} else
 		status_box->active_row = NULL;
 
-	message = purple_savedstatus_get_message(saved_status);
-	if (!purple_savedstatus_is_transient(saved_status) || !message || !*message)
-	{
-		status_box->imhtml_visible = FALSE;
-		gtk_widget_hide_all(status_box->vbox);
-	}
-	else
-	{
-		status_box->imhtml_visible = TRUE;
-		gtk_widget_show_all(status_box->vbox);
+	if (status_changed) {
+		message = purple_savedstatus_get_message(saved_status);
 
 		/*
+		 * If we are going to hide the imhtml, don't retain the
+		 * message because showing the old message later is
+		 * confusing. If we are going to set the message to a pre-set,
+		 * then we need to do this anyway
+		 *
 		 * Suppress the "changed" signal because the status
 		 * was changed programmatically.
 		 */
@@ -931,12 +930,24 @@
 
 		gtk_imhtml_clear(GTK_IMHTML(status_box->imhtml));
 		gtk_imhtml_clear_formatting(GTK_IMHTML(status_box->imhtml));
-		gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0);
+
+		if (!purple_savedstatus_is_transient(saved_status) || !message || !*message)
+		{
+			status_box->imhtml_visible = FALSE;
+			gtk_widget_hide_all(status_box->vbox);
+		}
+		else
+		{
+			status_box->imhtml_visible = TRUE;
+			gtk_widget_show_all(status_box->vbox);
+
+			gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0);
+		}
+
 		gtk_widget_set_sensitive(GTK_WIDGET(status_box->imhtml), TRUE);
+		update_size(status_box);
 	}
 
-	update_size(status_box);
-
 	/* Stop suppressing the "changed" signal. */
 	gtk_widget_set_sensitive(GTK_WIDGET(status_box), TRUE);
 }
@@ -996,50 +1007,50 @@
  * statuses and a token account if they do */
 static PurpleAccount* check_active_accounts_for_identical_statuses(void)
 {
-	PurpleAccount *acct = NULL, *acct2;
-	GList *tmp, *tmp2, *active_accts = purple_accounts_get_all_active();
-	GList *s, *s1, *s2;
-
-	for (tmp = active_accts; tmp; tmp = tmp->next) {
-		acct = tmp->data;
-		s = purple_account_get_status_types(acct);
-		for (tmp2 = tmp->next; tmp2; tmp2 = tmp2->next) {
-			acct2 = tmp2->data;
-
-			/* Only actually look at the statuses if the accounts use the same prpl */
-			if (strcmp(purple_account_get_protocol_id(acct), purple_account_get_protocol_id(acct2))) {
-				acct = NULL;
-				break;
-			}
-
-			s2 = purple_account_get_status_types(acct2);
-
-			s1 = s;
-			while (s1 && s2) {
-				PurpleStatusType *st1 = s1->data, *st2 = s2->data;
-				/* TODO: Are these enough to consider the statuses identical? */
-				if (purple_status_type_get_primitive(st1) != purple_status_type_get_primitive(st2)
-						|| strcmp(purple_status_type_get_id(st1), purple_status_type_get_id(st2))
-						|| strcmp(purple_status_type_get_name(st1), purple_status_type_get_name(st2))) {
-					acct = NULL;
-					break;
-				}
-
-				s1 = s1->next;
-				s2 = s2->next;
-			}
-
-			if (s1 != s2) {/* Will both be NULL if matched */
-				acct = NULL;
+	GList *iter, *active_accts = purple_accounts_get_all_active();
+	PurpleAccount *acct1 = NULL;
+	const char *prpl1 = NULL;
+
+	if (active_accts) {
+		acct1 = active_accts->data;
+		prpl1 = purple_account_get_protocol_id(acct1);
+	} else {
+		/* there's no enabled account */
+		return NULL;
+	}
+
+	/* start at the second account */
+	for (iter = active_accts->next; iter; iter = iter->next) {
+		PurpleAccount *acct2 = iter->data;
+		GList *s1, *s2;
+
+		if (!g_str_equal(prpl1, purple_account_get_protocol_id(acct2))) {
+			acct1 = NULL;
+			break;
+		}
+
+		for (s1 = purple_account_get_status_types(acct1),
+				 s2 = purple_account_get_status_types(acct2); s1 && s2;
+			 s1 = s1->next, s2 = s2->next) {
+			PurpleStatusType *st1 = s1->data, *st2 = s2->data;
+			/* TODO: Are these enough to consider the statuses identical? */
+			if (purple_status_type_get_primitive(st1) != purple_status_type_get_primitive(st2)
+				|| strcmp(purple_status_type_get_id(st1), purple_status_type_get_id(st2))
+				|| strcmp(purple_status_type_get_name(st1), purple_status_type_get_name(st2))) {
+				acct1 = NULL;
 				break;
 			}
 		}
-		if (!acct)
+
+		if (s1 != s2) {/* Will both be NULL if matched */
+			acct1 = NULL;
 			break;
+		}
 	}
+
 	g_list_free(active_accts);
 
-	return acct;
+	return acct1;
 }
 
 static void
@@ -1068,7 +1079,7 @@
 }
 
 static void
-pidgin_status_box_regenerate(PidginStatusBox *status_box)
+pidgin_status_box_regenerate(PidginStatusBox *status_box, gboolean status_changed)
 {
 	GtkIconSize icon_size;
 
@@ -1104,7 +1115,7 @@
 		pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_CUSTOM, NULL, _("New status..."), NULL, NULL);
 		pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_SAVED, NULL, _("Saved statuses..."), NULL, NULL);
 
-		status_menu_refresh_iter(status_box);
+		status_menu_refresh_iter(status_box, status_changed);
 		pidgin_status_box_refresh(status_box);
 
 	} else {
@@ -1156,7 +1167,7 @@
 			update_to_reflect_account_status(status_box, status_box->account,
 							purple_account_get_active_status(status_box->account));
 		else {
-			status_menu_refresh_iter(status_box);
+			status_menu_refresh_iter(status_box, TRUE);
 			pidgin_status_box_refresh(status_box);
 		}
 		return TRUE;
@@ -1229,7 +1240,7 @@
 
 	/* Regenerate the list if it has changed */
 	if (initial_token_acct != status_box->token_status_account) {
-		pidgin_status_box_regenerate(status_box);
+		pidgin_status_box_regenerate(status_box, TRUE);
 	}
 
 }
@@ -1238,13 +1249,14 @@
 current_savedstatus_changed_cb(PurpleSavedStatus *now, PurpleSavedStatus *old, PidginStatusBox *status_box)
 {
 	/* Make sure our current status is added to the list of popular statuses */
-	pidgin_status_box_regenerate(status_box);
+	pidgin_status_box_regenerate(status_box, TRUE);
 }
 
 static void
 saved_status_updated_cb(PurpleSavedStatus *status, PidginStatusBox *status_box)
 {
-	pidgin_status_box_regenerate(status_box);
+	pidgin_status_box_regenerate(status_box,
+		purple_savedstatus_get_current() == status);
 }
 
 static void
@@ -1919,7 +1931,7 @@
 	status_box->token_status_account = check_active_accounts_for_identical_statuses();
 
 	cache_pixbufs(status_box);
-	pidgin_status_box_regenerate(status_box);
+	pidgin_status_box_regenerate(status_box, TRUE);
 
 	purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-changed",
 						status_box,
@@ -2324,18 +2336,6 @@
 	pidgin_status_box_refresh(status_box);
 }
 
-static gboolean
-message_changed(const char *one, const char *two)
-{
-	if (one == NULL && two == NULL)
-		return FALSE;
-
-	if (one == NULL || two == NULL)
-		return TRUE;
-
-	return (g_utf8_collate(one, two) != 0);
-}
-
 static void
 activate_currently_selected_status(PidginStatusBox *status_box)
 {
@@ -2386,6 +2386,7 @@
 
 	if (status_box->account == NULL) {
 		PurpleStatusType *acct_status_type = NULL;
+		const char *id = NULL; /* id of acct_status_type */
 		PurpleStatusPrimitive primitive = GPOINTER_TO_INT(data);
 		/* Global */
 		/* Save the newly selected status to prefs.xml and status.xml */
@@ -2394,7 +2395,6 @@
 		if (status_box->token_status_account) {
 			gint active;
 			PurpleStatus *status;
-			const char *id = NULL;
 			GtkTreePath *path = gtk_tree_row_reference_get_path(status_box->active_row);
 			active = gtk_tree_path_get_indices(path)[0];
 
@@ -2402,37 +2402,35 @@
 
 			status = purple_account_get_active_status(status_box->token_status_account);
 
-			 acct_status_type = find_status_type_by_index(status_box->token_status_account, active);
+			acct_status_type = find_status_type_by_index(status_box->token_status_account, active);
 			id = purple_status_type_get_id(acct_status_type);
 
-			if (strncmp(id, purple_status_get_id(status), strlen(id)) == 0)
+			if (g_str_equal(id, purple_status_get_id(status)) &&
+				purple_strequal(message, purple_status_get_attr_string(status, "message")))
 			{
 				/* Selected status and previous status is the same */
-				if (!message_changed(message, purple_status_get_attr_string(status, "message")))
-				{
-					PurpleSavedStatus *ss = purple_savedstatus_get_current();
-					/* Make sure that statusbox displays the correct thing.
-					 * It can get messed up if the previous selection was a
-					 * saved status that wasn't supported by this account */
-					if ((purple_savedstatus_get_type(ss) == primitive)
-							&& purple_savedstatus_is_transient(ss)
-							&& purple_savedstatus_has_substatuses(ss))
-						changed = FALSE;
-				}
+				PurpleSavedStatus *ss = purple_savedstatus_get_current();
+				/* Make sure that statusbox displays the correct thing.
+				 * It can get messed up if the previous selection was a
+				 * saved status that wasn't supported by this account */
+				if ((purple_savedstatus_get_type(ss) == primitive)
+					&& purple_savedstatus_is_transient(ss)
+					&& purple_savedstatus_has_substatuses(ss))
+					changed = FALSE;
 			}
 		} else {
 			saved_status = purple_savedstatus_get_current();
 			if (purple_savedstatus_get_type(saved_status) == primitive &&
-			    !purple_savedstatus_has_substatuses(saved_status))
+			    !purple_savedstatus_has_substatuses(saved_status) &&
+				purple_strequal(purple_savedstatus_get_message(saved_status), message))
 			{
-				if (!message_changed(purple_savedstatus_get_message(saved_status), message))
-					changed = FALSE;
+				changed = FALSE;
 			}
 		}
 
 		if (changed)
 		{
-			/* Manually find the appropriate transient acct */
+			/* Manually find the appropriate transient status */
 			if (status_box->token_status_account) {
 				GList *iter = purple_savedstatuses_get_all();
 				GList *tmp, *active_accts = purple_accounts_get_all_active();
@@ -2440,27 +2438,31 @@
 				for (; iter != NULL; iter = iter->next) {
 					PurpleSavedStatus *ss = iter->data;
 					const char *ss_msg = purple_savedstatus_get_message(ss);
+					/* find a known transient status that is the same as the
+					 * new selected one */
 					if ((purple_savedstatus_get_type(ss) == primitive) && purple_savedstatus_is_transient(ss) &&
 						purple_savedstatus_has_substatuses(ss) && /* Must have substatuses */
-						!message_changed(ss_msg, message))
+						purple_strequal(ss_msg, message))
 					{
 						gboolean found = FALSE;
-						/* The currently enabled accounts must have substatuses for all the active accts */
+						/* this status must have substatuses for all the active accts */
 						for(tmp = active_accts; tmp != NULL; tmp = tmp->next) {
 							PurpleAccount *acct = tmp->data;
 							PurpleSavedStatusSub *sub = purple_savedstatus_get_substatus(ss, acct);
 							if (sub) {
 								const PurpleStatusType *sub_type = purple_savedstatus_substatus_get_type(sub);
 								const char *subtype_status_id = purple_status_type_get_id(sub_type);
-								if (subtype_status_id && !strcmp(subtype_status_id,
-										purple_status_type_get_id(acct_status_type)))
+								if (purple_strequal(subtype_status_id, id)) {
 									found = TRUE;
+									break;
+								}
 							}
 						}
-						if (!found)
-							continue;
-						saved_status = ss;
-						break;
+
+						if (found) {
+							saved_status = ss;
+							break;
+						}
 					}
 				}
 
@@ -2503,11 +2505,11 @@
 		status_type = find_status_type_by_index(status_box->account, active);
 		id = purple_status_type_get_id(status_type);
 
-		if (strncmp(id, purple_status_get_id(status), strlen(id)) == 0)
+		if (g_str_equal(id, purple_status_get_id(status)) &&
+			purple_strequal(message, purple_status_get_attr_string(status, "message")))
 		{
 			/* Selected status and previous status is the same */
-			if (!message_changed(message, purple_status_get_attr_string(status, "message")))
-				changed = FALSE;
+			changed = FALSE;
 		}
 
 		if (changed)
@@ -2597,7 +2599,7 @@
 	if (status_box->typing == 0)
 	{
 		/* Nothing has changed, so we don't need to do anything */
-		status_menu_refresh_iter(status_box);
+		status_menu_refresh_iter(status_box, FALSE);
 		return;
 	}
 
@@ -2655,14 +2657,14 @@
 			pidgin_status_editor_show(FALSE,
 				purple_savedstatus_is_transient(saved_status)
 					? saved_status : NULL);
-			status_menu_refresh_iter(status_box);
+			status_menu_refresh_iter(status_box, FALSE);
 			return;
 		}
 
 		if (type == PIDGIN_STATUS_BOX_TYPE_SAVED)
 		{
 			pidgin_status_window_show();
-			status_menu_refresh_iter(status_box);
+			status_menu_refresh_iter(status_box, FALSE);
 			return;
 		}
 	}
--- a/pidgin/plugins/perl/common/Makefile.mingw	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/plugins/perl/common/Makefile.mingw	Wed Nov 04 18:41:51 2009 +0000
@@ -5,9 +5,12 @@
 #
 
 PIDGIN_TREE_TOP := ../../../..
-GCCWARNINGS := -Wno-comment -Waggregate-return -Wcast-align -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wextra -Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wpointer-arith -Wundef -Wno-unused
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
+GCCWARNINGS += -Wno-comment -Wno-unused -Wno-nested-externs
+
+DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES))
+
 TARGET = Pidgin
 EXTUTILS ?= C:/perl/lib/ExtUtils
 
--- a/pidgin/plugins/win32/winprefs/Makefile.mingw	Wed Nov 04 18:41:21 2009 +0000
+++ b/pidgin/plugins/win32/winprefs/Makefile.mingw	Wed Nov 04 18:41:51 2009 +0000
@@ -8,6 +8,7 @@
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
 TARGET = winprefs
+DEFINES := $(subst -DWIN32_LEAN_AND_MEAN,,$(DEFINES))
 DEFINES += -DWINVER=0x500
 
 ##
--- a/po/ca.po	Wed Nov 04 18:41:21 2009 +0000
+++ b/po/ca.po	Wed Nov 04 18:41:51 2009 +0000
@@ -33,8 +33,8 @@
 msgstr ""
 "Project-Id-Version: Pidgin\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-09-07 18:26-0700\n"
-"PO-Revision-Date: 2009-07-26 17:23+0200\n"
+"POT-Creation-Date: 2009-10-25 17:57+0100\n"
+"PO-Revision-Date: 2009-10-26 09:20+0100\n"
 "Last-Translator: Josep Puigdemont i Casamajó <josep.puigdemont@gmail.com>\n"
 "Language-Team: Catalan <tradgnome@softcatala.net>\n"
 "MIME-Version: 1.0\n"
@@ -576,13 +576,6 @@
 msgid "Re-enable Account"
 msgstr "Rehabilita el compte"
 
-msgid ""
-"The account has disconnected and you are no longer in this chat. You will be "
-"automatically rejoined in the chat when the account reconnects."
-msgstr ""
-"El compte s'ha desconnectat i ja no sou al xat. Quan es torni a connectar el "
-"compte entrareu de nou automàticament al xat."
-
 msgid "No such command."
 msgstr "No existeix l'ordre."
 
@@ -625,6 +618,13 @@
 msgid "You have left this chat."
 msgstr "Heu sortit d'aquest xat"
 
+msgid ""
+"The account has disconnected and you are no longer in this chat. You will be "
+"automatically rejoined in the chat when the account reconnects."
+msgstr ""
+"El compte s'ha desconnectat i ja no sou al xat. Quan es torni a connectar el "
+"compte entrareu de nou automàticament al xat."
+
 msgid "Logging started. Future messages in this conversation will be logged."
 msgstr ""
 "S'ha iniciat el registre. Es registraran els propers missatges d'aquesta "
@@ -661,6 +661,9 @@
 msgid "Enable Sounds"
 msgstr "Habilita els sons"
 
+msgid "You are not connected."
+msgstr "No esteu connectat."
+
 msgid "<AUTO-REPLY> "
 msgstr "<RESPOSTA-AUTOMÀTICA> "
 
@@ -670,8 +673,8 @@
 msgstr[0] "Llista d'%d usuari:\n"
 msgstr[1] "Llista de %d usuaris:\n"
 
-msgid "Supported debug options are:  version"
-msgstr "Les opcions de depuració disponibles són:  version"
+msgid "Supported debug options are: plugins version"
+msgstr "Les opcions de depuració disponibles són:  plugins version"
 
 msgid "No such command (in this context)."
 msgstr "L'ordre no existeix (en aquest context)."
@@ -977,6 +980,9 @@
 msgid "(none)"
 msgstr "(cap)"
 
+#. XXX: The following expects that finch_notify_message gets called. This
+#. * may not always happen, e.g. when another plugin sets its own
+#. * notify_message. So tread carefully.
 msgid "URI"
 msgstr "URI"
 
@@ -1554,9 +1560,15 @@
 "\n"
 "S'està aconseguint un TinyURL..."
 
-#, fuzzy
+#, c-format
+msgid "TinyURL for above: %s"
+msgstr "Fes un TinyURL d'això d'aquí dalt: %s"
+
+msgid "Please wait while TinyURL fetches a shorter URL ..."
+msgstr "Espreu mentre TinyURL obté una URL més curta..."
+
 msgid "Only create TinyURL for URLs of this length or greater"
-msgstr "Crea TinyURL per a URL així de llargues o més"
+msgstr "Només crea TinyURL per a URL així de llargues o més"
 
 msgid "TinyURL (or other) address prefix"
 msgstr "Prefix de l'adreça TinyURL (o altra)"
@@ -1567,10 +1579,9 @@
 msgid "TinyURL plugin"
 msgstr "Connector TinyURL"
 
-#, fuzzy
 msgid "When receiving a message with URL(s), use TinyURL for easier copying"
 msgstr ""
-"Quan rebeu missagtes amb URL, feu servir TinyURL per a copiar més fàcilment"
+"En rebre missagtes amb URL, s'empra TinyURL perquè sigui més fàcil copiar"
 
 msgid "Online"
 msgstr "En línia"
@@ -1676,27 +1687,25 @@
 msgid "buddy list"
 msgstr "llista d'amics"
 
-#, fuzzy
 msgid "The certificate is self-signed and cannot be automatically checked."
-msgstr ""
-"No es pot comprovar el certificat que presenta «%s» atès que està auto-signat."
-
-#, fuzzy
-msgid "The root certificate this one claims to be issued by is unknown."
-msgstr "El Pidgin no coneix el certificat arrel d'aquest certificat."
-
-#, fuzzy
+msgstr "No es pot comprovar el certificat atès que està auto-signat."
+
+msgid ""
+"The certificate is not trusted because no certificate that can verify it is "
+"currently trusted."
+msgstr ""
+"No es pot confiar en el certificat atès que no hi hi ha cap altre certificat "
+"de confiança que el pugui verificar."
+
 msgid "The certificate is not valid yet."
-msgstr "La cadena de certificació que presenta %s no és vàlida."
-
-#, fuzzy
+msgstr "El certificat encara no és vàlid."
+
 msgid "The certificate has expired and should not be considered valid."
-msgstr "La cadena de certificació que presenta %s no és vàlida."
+msgstr "El certificat ha expirat i no s'hauria de considerar vàlid."
 
 #. Translators: "domain" refers to a DNS domain (e.g. talk.google.com)
-#, fuzzy
 msgid "The certificate presented is not issued to this domain."
-msgstr "La cadena de certificació que presenta %s no és vàlida."
+msgstr "El certificat que s'ha presentat no ha estat emès per a aquest domini."
 
 msgid ""
 "You have no database of root certificates, so this certificate cannot be "
@@ -1705,17 +1714,14 @@
 "Aquest certificat no es pot validar perquè no teniu cap base de dades de "
 "certificats arrel."
 
-#, fuzzy
 msgid "The certificate chain presented is invalid."
-msgstr "La cadena de certificació que presenta %s no és vàlida."
-
-#, fuzzy
+msgstr "La cadena de certificació que s'ha presentat no és vàlida."
+
 msgid "The certificate has been revoked."
-msgstr "Ha finalitzat la trucada."
-
-#, fuzzy
+msgstr "El certificat ha estat revocat."
+
 msgid "An unknown certificate error occurred."
-msgstr "Hi ha hagut un error de connexió desconegut: %s."
+msgstr "S'ha produït un error desconegut en el certificat."
 
 msgid "(DOES NOT MATCH)"
 msgstr "(NO COINCIDEIX)"
@@ -1760,26 +1766,25 @@
 msgid "_View Certificate..."
 msgstr "_Mostra el certificat..."
 
-#, fuzzy, c-format
+#, c-format
 msgid "The certificate for %s could not be validated."
-msgstr "La cadena de certificació que presenta %s no és vàlida."
+msgstr "No s'ha pogut validar el certificat de %s."
 
 # Títol de finestra (josep)
 #. TODO: Probably wrong.
 msgid "SSL Certificate Error"
 msgstr "Error en el certificat SSL"
 
-#, fuzzy
 msgid "Unable to validate certificate"
-msgstr "No s'ha pogut autenticar: %s"
-
-#, fuzzy, c-format
+msgstr "No s'ha pogut certificar"
+
+#, c-format
 msgid ""
 "The certificate claims to be from \"%s\" instead. This could mean that you "
 "are not connecting to the service you believe you are."
 msgstr ""
-"El certificat de «%s» sembla indicar que és de «%s». Això podria voler dir que "
-"us esteu connectant a un servei diferent del que us penseu."
+"El certificat indica que és de «%s». Això podria voler dir que us esteu "
+"connectant a un servei diferent del que us penseu."
 
 #. Make messages
 #, c-format
@@ -1927,6 +1932,10 @@
 msgstr "El procés resoledor ha acabat sense respondre la nostra sol·licitud"
 
 #, c-format
+msgid "Error converting %s to punycode: %d"
+msgstr "S'ha produït un error en convertir %s a punycode: %d"
+
+#, c-format
 msgid "Thread creation failure: %s"
 msgstr "S'ha produït un error en crear un fil: %s"
 
@@ -2020,18 +2029,18 @@
 msgid "File transfer complete"
 msgstr "S'ha completat la transferència del fitxer"
 
-#, fuzzy, c-format
+#, c-format
 msgid "You cancelled the transfer of %s"
 msgstr "Heu cancel·lat la transferència de %s"
 
 msgid "File transfer cancelled"
 msgstr "S'ha cancel·lat la transferència del fitxer"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s cancelled the transfer of %s"
 msgstr "%s ha cancel·lat la transferència de %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s cancelled the file transfer"
 msgstr "%s ha cancel·lat la transferència del fitxer"
 
@@ -2224,28 +2233,30 @@
 "No codecs found. Install some GStreamer codecs found in GStreamer plugins "
 "packages."
 msgstr ""
+"No s'ha trobat cap còdec. Instal·leu els còdecs del GStreamer que podeu "
+"trobar en els paquests de connectors del GStreamer."
 
 msgid ""
 "No codecs left. Your codec preferences in fs-codecs.conf are too strict."
 msgstr ""
-
-#, fuzzy
+"No hi ha cap més còdec. Les preferències dels còdecs al fitxer fs-codecs."
+"conf són massa estrictes."
+
 msgid "A non-recoverable Farsight2 error has occurred."
-msgstr "Hi ha hagut un error de connexió desconegut: %s."
-
-#, fuzzy
-msgid "Conference error."
-msgstr "Conferència tancada"
-
-msgid "Error with your microphone."
-msgstr ""
-
-msgid "Error with your webcam."
-msgstr ""
-
-#, fuzzy, c-format
+msgstr "S'ha produït un error no recuperable del Farsight2."
+
+msgid "Conference error"
+msgstr "Error en la conferència"
+
+msgid "Error with your microphone"
+msgstr "S'ha produït un error amb el micròfon"
+
+msgid "Error with your webcam"
+msgstr "S'ha produït un error amb la càmera web"
+
+#, c-format
 msgid "Error creating session: %s"
-msgstr "S'ha produït un error en crear la connexió"
+msgstr "S'ha produït un error en crear la sessió: %s"
 
 msgid "Error creating conference."
 msgstr "S'ha produït un error en crear la conferència."
@@ -2511,16 +2522,15 @@
 msgid "Test plugin IPC support, as a server. This registers the IPC commands."
 msgstr "Connector de proves per a servidor d'IPC, que registra les ordres IPC."
 
-#, fuzzy
 msgid "Hide Joins/Parts"
-msgstr "Oculta els errors en entrar"
+msgstr "Oculta en entrar/sortir"
 
 #. Translators: Followed by an input request a number of people
 msgid "For rooms with more than this many people"
-msgstr ""
+msgstr "Per sales amb més persones que"
 
 msgid "If user has not spoken in this many minutes"
-msgstr ""
+msgstr "Si l'usuari no ha parlat en"
 
 msgid "Apply hiding rules to buddies"
 msgstr "Aplica les normes d'ocultació als amics"
@@ -3973,11 +3983,11 @@
 msgid "Logo"
 msgstr "Logotip"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "%s will no longer be able to see your status updates.  Do you want to "
 "continue?"
-msgstr "Esteu segur que voleu suprimir %s de la llista d'amics?"
+msgstr "%s no podrà veure l'actualització del vostre estat. Voleu continuar?"
 
 msgid "Cancel Presence Notification"
 msgstr "Cancel·la la notificació de presència"
@@ -3996,6 +4006,9 @@
 msgid "Unsubscribe"
 msgstr "Cancel·la la subscripció"
 
+msgid "Initiate _Chat"
+msgstr "Inicia un _xat"
+
 msgid "Log In"
 msgstr "Connecta"
 
@@ -4580,7 +4593,7 @@
 msgid "configure:  Configure a chat room."
 msgstr "configure:  configura la sala de xat."
 
-msgid "part [room]:  Leave the room."
+msgid "part [message]:  Leave the room."
 msgstr "part [sala]:  surt de la sala."
 
 msgid "register:  Register with a chat room."
@@ -4599,13 +4612,12 @@
 "affiliate &lt;owner|admin|member|outcast|none&gt; [sobrenom1] "
 "[sobrenom2] ...: obtén els usuaris amb una afiliació, o els l'estableix."
 
-#, fuzzy
 msgid ""
 "role &lt;moderator|participant|visitor|none&gt; [nick1] [nick2] ...: Get the "
 "users with a role or set users' role with the room."
 msgstr ""
-"role &lt;usuari&gt; &lt;moderator|participant|visitor|none&gt; [sobrenom1] "
-"[sobrenom2] ...: obtén els usuaris amb el rol especificat, o els l'estableix."
+"role &lt;moderator|participant|visitor|none&gt; [sobrenom1] [sobrenom2] ...: "
+"obtén els usuaris amb el rol especificat, o els l'estableix."
 
 msgid "invite &lt;user&gt; [message]:  Invite a user to the room."
 msgstr "invite &lt;usuari&gt; [sala]:  convida un usuari a la sala."
@@ -5025,7 +5037,6 @@
 msgid "Not expected"
 msgstr "Inesperat"
 
-#, fuzzy
 msgid "Friendly name is changing too rapidly"
 msgstr "El nom amistós canvia massa de pressa"
 
@@ -5245,19 +5256,16 @@
 msgid "Send to Mobile"
 msgstr "Envia a un mòbil"
 
-msgid "Initiate _Chat"
-msgstr "Inicia un _xat"
-
 msgid "SSL support is needed for MSN. Please install a supported SSL library."
 msgstr "L'MSN necessita SSL, instal·leu alguna biblioteca d'SSL permesa."
 
 #, c-format
 msgid ""
 "Unable to add the buddy %s because the username is invalid.  Usernames must "
-"be a valid email address."
+"be valid email addresses."
 msgstr ""
 "No s'ha pogut afegir l'amic %s perquè el nom d'usuari no és vàlid. Els noms "
-"d'usuari han de ser adreces de correu vàlides."
+"d'usuari han de ser adreces de correu electròniques vàlides."
 
 msgid "Unable to Add"
 msgstr "No s'ha pogut afegir"
@@ -5597,10 +5605,10 @@
 "%s ha sol·licitat poder veure la vostra càmera web, però això encara no està "
 "implementat."
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s invited you to view his/her webcam, but this is not yet supported."
 msgstr ""
-"%s ha sol·licitat poder veure la vostra càmera web, però això encara no està "
+"%s us ha convidat a veure la seva càmera web, però això encara no està "
 "implementat."
 
 msgid "Away From Computer"
@@ -6354,9 +6362,9 @@
 msgstr "Port en el servidor"
 
 #. Note to translators: %s in this string is a URL
-#, fuzzy, c-format
+#, c-format
 msgid "Received unexpected response from %s"
-msgstr "S'ha rebut una resposta inesperada de "
+msgstr "S'ha rebut una resposta inesperada de %s"
 
 #. username connecting too frequently
 msgid ""
@@ -6369,9 +6377,9 @@
 
 #. Note to translators: The first %s is a URL, the second is an
 #. error message.
-#, fuzzy, c-format
+#, c-format
 msgid "Error requesting %s: %s"
-msgstr "S'ha produït en sol·licitar "
+msgstr "S'ha produït un error en sol·licitar %s: %s"
 
 msgid "AOL does not allow your screen name to authenticate here"
 msgstr "AOL no permet que us autentiqueu amb aquest nom d'usuari aquí"
@@ -7149,9 +7157,8 @@
 msgid "C_onnect"
 msgstr "C_onnecta"
 
-#, fuzzy
 msgid "You closed the connection."
-msgstr "El servidor ha tancat la connexió"
+msgstr "Heu tancat la connexió."
 
 msgid "Get AIM Info"
 msgstr "Obtén informació de AIM"
@@ -7163,9 +7170,8 @@
 msgid "Get Status Msg"
 msgstr "Aconsegueix el missatge d'estat"
 
-#, fuzzy
 msgid "End Direct IM Session"
-msgstr "S'ha establert una connexió directa de MI"
+msgstr "Finalitzar la sessió de MI directa"
 
 msgid "Direct IM"
 msgstr "MI directa"
@@ -8007,7 +8013,7 @@
 msgid "File Send"
 msgstr "S'ha enviat el fitxer"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%d cancelled the transfer of %s"
 msgstr "%d ha cancel·lat la transferència de %s"
 
@@ -9545,7 +9551,7 @@
 msgstr "Bloca invitacions a conferències i sales de xat"
 
 msgid "Use account proxy for SSL connections"
-msgstr ""
+msgstr "Empra un compte per al servidor intermediàri per a connexions SSL"
 
 msgid "Chat room list URL"
 msgstr "URL de la llista de sales de xat"
@@ -9653,26 +9659,26 @@
 msgid "Ignore buddy?"
 msgstr "Voleu ignorar l'amic?"
 
-#, fuzzy
 msgid "Invalid username or password"
-msgstr "El sobrenom o la contrasenya no són correctes"
-
-#, fuzzy
+msgstr "El sobrenom o la contrasenya no són vàlides"
+
 msgid ""
 "Your account has been locked due to too many failed login attempts.  Please "
 "try logging into the Yahoo! website."
 msgstr ""
-"El compte està blocat perquè s'ha intentat entrar massa cops. Això es pot "
-"solucionar entrant al web de Yahoo!"
+"S'ha blocat el vostre compte perquè s'ha intentat entrar massa cops. Entreu "
+"al web de Yahoo! per solucionar això."
 
 #, c-format
 msgid "Unknown error 52.  Reconnecting should fix this."
-msgstr ""
+msgstr "Error desconegut 52. Es pot sol·lucionar connectant de nou."
 
 msgid ""
 "Error 1013: The username you have entered is invalid.  The most common cause "
 "of this error is entering your email address instead of your Yahoo! ID."
 msgstr ""
+"Error 1013: el nom d'usuari no és vàlid. Pot ser que hagueu introduït la "
+"vostra adreça de correu en lloc del nom d'usuari de Yahoo!"
 
 #, c-format
 msgid "Unknown error number %d. Logging into the Yahoo! website may fix this."
@@ -9764,6 +9770,16 @@
 msgid "Open Inbox"
 msgstr "Obre la safata d'entrada"
 
+msgid "Can't send SMS. Unable to obtain mobile carrier."
+msgstr ""
+"No es poden enviar SMS, no s'ha pogut obtenir l'operador de telefonia mòbil."
+
+msgid "Can't send SMS. Unknown mobile carrier."
+msgstr "No es poden enviar SMS, no es coneix l'operador de telefona mòbil."
+
+msgid "Getting mobile carrier to send the SMS."
+msgstr "S'està obtenint l'operador de telefonia mòbil per a poder enviar SMS."
+
 #. Write a local message to this conversation showing that a request for a
 #. * Doodle session has been made
 #.
@@ -10456,7 +10472,6 @@
 msgid "Layout"
 msgstr "Format"
 
-#, fuzzy
 msgid "The layout of icons, name, and status of the buddy list"
 msgstr "El format de les icones, el nom, i l'estat de la llista d'amics"
 
@@ -10513,9 +10528,8 @@
 
 #. Note to translators: These two strings refer to the font and color
 #. of a buddy list buddy when it is online
-#, fuzzy
 msgid "Online Text"
-msgstr "Text en línia"
+msgstr "Text en estar en línia"
 
 msgid "The text information for when a buddy is online"
 msgstr "Text informatiu per quan un amic estigui en línia"
@@ -10523,18 +10537,16 @@
 #. Note to translators: These two strings refer to the font and color
 #. of a buddy list buddy when it is away
 msgid "Away Text"
-msgstr "Text d'absència"
+msgstr "Text en estar absent"
 
 msgid "The text information for when a buddy is away"
 msgstr "Text informatiu per quan un amic estigui absent"
 
 #. Note to translators: These two strings refer to the font and color
 #. of a buddy list buddy when it is offline
-#, fuzzy
 msgid "Offline Text"
-msgstr "Text de fora de línia"
-
-#, fuzzy
+msgstr "Text fora de línia"
+
 msgid "The text information for when a buddy is offline"
 msgstr "Text informatiu per quan un amic estigui fora de línia"
 
@@ -10559,7 +10571,6 @@
 msgid "Message (Nick Said) Text"
 msgstr "Text del missatge (on s'hi ha dit el sobrenom)"
 
-#, fuzzy
 msgid ""
 "The text information for when a chat has an unread message that mentions "
 "your nickname"
@@ -11005,9 +11016,8 @@
 msgid "_Group:"
 msgstr "_Grup:"
 
-#, fuzzy
 msgid "Auto_join when account connects."
-msgstr "_Entra automàticament quant el compte estigui connectat."
+msgstr "_Entra automàticament quant es connecti el compte."
 
 msgid "_Remain in chat after window is closed."
 msgstr "Co_ntinua al xat quan la finestra es tanqui."
@@ -11121,9 +11131,8 @@
 msgid "/Conversation/New Instant _Message..."
 msgstr "/Conversa/_Missatge instantani nou..."
 
-#, fuzzy
 msgid "/Conversation/Join a _Chat..."
-msgstr "/Conversa/Con_vida..."
+msgstr "/Conversa/Entra a un _xat..."
 
 msgid "/Conversation/_Find..."
 msgstr "/Conversa/_Cerca..."
@@ -11514,7 +11523,7 @@
 msgstr "Estonià"
 
 msgid "Basque"
-msgstr ""
+msgstr "Basc"
 
 msgid "Persian"
 msgstr "Persa"
@@ -11728,6 +11737,13 @@
 "primary language is <b>English</b>.  You are welcome to post in another "
 "language, but the responses may be less helpful.<br/><br/>"
 msgstr ""
+"<font size=\"4\">Ajuda d'altres usuaris del Pidgin:</font> <a href=\"mailto:"
+"support@pidgin.im\">support@pidgin.im</a><br/>Aquesta és una llista de "
+"correu <b>pública</b>. (<a href=\"http://pidgin.im/pipermail/support/"
+"\">arxiu</a>)<br/>No us podem ajudar amb connectors d'altres proveïdors.<br/"
+">En aquesta llista s'hi empra principalment l'<b>anglès</b>.  Podeu escriure-"
+"hi en un altre idioma, però és possible que les respostes no siguin de gaire "
+"ajuda.<br/><br/>"
 
 #, c-format
 msgid ""
@@ -12299,45 +12315,48 @@
 "Usage: %s [OPTION]...\n"
 "\n"
 msgstr ""
-
-#, fuzzy
+"Forma d'ús: %s [OPCIÓ]...\n"
+"\n"
+
 msgid "DIR"
-msgstr "IRC"
+msgstr "DIR"
 
 msgid "use DIR for config files"
-msgstr ""
+msgstr "empra DIR per a fitxers de configuració"
 
 msgid "print debugging messages to stdout"
-msgstr ""
+msgstr "escriu missatges de depuració a la sortida estàndard"
 
 msgid "force online, regardless of network status"
-msgstr ""
+msgstr "força estar en línia, independentment de l'estat de la xarxa"
 
 msgid "display this help and exit"
-msgstr ""
+msgstr "mostra aquesta ajuda i surt"
 
 # FIXME: entrades/registres?
-#, fuzzy
 msgid "allow multiple instances"
-msgstr "Permet diverses entrades simultànies"
+msgstr "permet diverses instàncies"
 
 msgid "don't automatically login"
-msgstr ""
+msgstr "no entra als comptes"
 
 msgid "NAME"
-msgstr ""
+msgstr "NOM"
 
 msgid ""
 "enable specified account(s) (optional argument NAME\n"
 "                      specifies account(s) to use, separated by commas.\n"
 "                      Without this only the first account will be enabled)."
 msgstr ""
+"habilita els comptes especificats (l'argument opcional NAME especifica\n"
+"                      els comptes a emprar, separats per comes. Sense això\n"
+"                      només s'habilitarà el primer compte)."
 
 msgid "X display to use"
-msgstr ""
+msgstr "pantalla d'X a emprar"
 
 msgid "display the current version and exit"
-msgstr ""
+msgstr "mostra la versió actual i surt"
 
 # FIXME: backtrace -> traça (bug-buddy) ?
 #, c-format
@@ -12394,7 +12413,7 @@
 msgstr "%s vol iniciar una sessió de vídeo."
 
 msgid "Incoming Call"
-msgstr ""
+msgstr "Trucada entrant"
 
 msgid "_Pause"
 msgstr "_Pausa"
@@ -12576,50 +12595,54 @@
 msgid "Pounce Target"
 msgstr "Objectiu de l'avís"
 
-#, c-format
 msgid "Started typing"
 msgstr "Hagi començat a escriure"
 
-#, c-format
 msgid "Paused while typing"
 msgstr "S'aturi mentre tecleja"
 
-#, c-format
 msgid "Signed on"
 msgstr "Es connecti"
 
-#, c-format
 msgid "Returned from being idle"
 msgstr "Torna a estar actiu"
 
-#, c-format
 msgid "Returned from being away"
 msgstr "Torni a estar present"
 
-#, c-format
 msgid "Stopped typing"
 msgstr "Pari d'escriure"
 
-#, c-format
 msgid "Signed off"
 msgstr "Es desconnecti"
 
-#, c-format
 msgid "Became idle"
 msgstr "Passi a inactiu"
 
-#, c-format
 msgid "Went away"
 msgstr "En estar absent"
 
-#, c-format
 msgid "Sent a message"
 msgstr "Envia un missatge"
 
-#, c-format
 msgid "Unknown.... Please report this!"
 msgstr "Esdeveniment d'avís desconegut, informeu-nos-en."
 
+msgid "(Custom)"
+msgstr "(Personalitzat)"
+
+msgid "(Default)"
+msgstr "(Predeterminat)"
+
+msgid "The default Pidgin sound theme"
+msgstr "El tema de sons predeterminat del pidgin"
+
+msgid "The default Pidgin buddy list theme"
+msgstr "El tema per a la llista d'amics predeterminat del Pidgin"
+
+msgid "The default Pidgin status icon theme"
+msgstr "El tema de les icones d'estat predeterminat del Pidgin"
+
 msgid "Theme failed to unpack."
 msgstr "No s'ha pogut desempaquetar el tema."
 
@@ -12764,14 +12787,16 @@
 msgid "Cannot start browser configuration program."
 msgstr "No s'ha pogut iniciar el programa de configuració del navegador."
 
-#, fuzzy
 msgid "Disabled"
-msgstr "_Inhabilita"
+msgstr "Inhabilitat"
 
 #, c-format
 msgid "Use _automatically detected IP address: %s"
 msgstr "Empra l'_adreça IP detectada automàticament: %s"
 
+msgid "ST_UN server:"
+msgstr "Servidor ST_UN:"
+
 msgid "<span style=\"italic\">Example: stunserver.org</span>"
 msgstr "<span style=\"italic\">Exemple: stunserver.org</span>"
 
@@ -12797,9 +12822,8 @@
 msgid "Relay Server (TURN)"
 msgstr "Servidor repetidor (TURN)"
 
-#, fuzzy
 msgid "_TURN server:"
-msgstr "Servidor ST_UN:"
+msgstr "Servidor _TURN:"
 
 msgid "Proxy Server &amp; Browser"
 msgstr "Servidor intermediari i navegador"
@@ -14372,35 +14396,29 @@
 "Aquest connector permet a l'usuari personalitzar els formats de les marques "
 "horàries de les converses i dels registres."
 
-#, fuzzy
 msgid "Audio"
-msgstr "Auto"
-
-#, fuzzy
+msgstr "Àudio"
+
 msgid "Video"
 msgstr " Vídeo"
 
 msgid "Output"
-msgstr ""
-
-#, fuzzy
+msgstr "Sortida"
+
 msgid "_Plugin"
-msgstr "Connectors"
-
-#, fuzzy
+msgstr "_Connectors"
+
 msgid "_Device"
-msgstr "Dispositiu"
+msgstr "_Dispositiu"
 
 msgid "Input"
-msgstr ""
-
-#, fuzzy
+msgstr "Entrada"
+
 msgid "P_lugin"
-msgstr "Connectors"
-
-#, fuzzy
+msgstr "C_onnectors"
+
 msgid "D_evice"
-msgstr "Dispositiu"
+msgstr "D_ispositiu"
 
 #. *< magic
 #. *< major version
@@ -14411,18 +14429,19 @@
 #. *< dependencies
 #. *< priority
 #. *< id
-#, fuzzy
 msgid "Voice/Video Settings"
-msgstr "Edita els paràmetres"
+msgstr "Configuració del so/vídeo"
 
 #. *< name
 #. *< version
 msgid "Configure your microphone and webcam."
-msgstr ""
+msgstr "Configureu el micròfon i la càmera web."
 
 #. *< summary
 msgid "Configure microphone and webcam settings for voice/video calls."
 msgstr ""
+"Configureu els paràmetres del micròfon i la càmera web per a trucades de veu/"
+"vídeo."
 
 msgid "Opacity:"
 msgstr "Opacitat:"
@@ -14481,9 +14500,6 @@
 "\n"
 "* Nota: aquest connector requereix Windows 2000 o superior."
 
-msgid "GTK+ Runtime Version"
-msgstr "Versió del mòdul d'execució de GTK+"
-
 #. Autostart
 msgid "Startup"
 msgstr "Inicialització"
@@ -14492,6 +14508,10 @@
 msgid "_Start %s on Windows startup"
 msgstr "_Inicia el %s en iniciar Windows"
 
+# FIXME: entrades/registres?
+msgid "Allow multiple instances"
+msgstr "Permet diverses instàncies"
+
 msgid "_Dockable Buddy List"
 msgstr "Llista _d'amics acoblable"
 
@@ -14553,6 +14573,9 @@
 msgid "This plugin is useful for debbuging XMPP servers or clients."
 msgstr "Aquest connector és útil per a depurar servidors i clients XMPP."
 
+#~ msgid "GTK+ Runtime Version"
+#~ msgstr "Versió del mòdul d'execució de GTK+"
+
 #~ msgid "Calling ... "
 #~ msgstr "S'està trucant..."
 
@@ -14796,9 +14819,6 @@
 #~ msgid "Could not write"
 #~ msgstr "No s'ha pogut escriure"
 
-#~ msgid "Could not connect"
-#~ msgstr "No s'ha pogut connectar"
-
 #~ msgid "Could not create listen socket"
 #~ msgstr "No s'ha pogut crear el sòcol per a escoltar"