changeset 31781:ac43f26c7f61

merge of '269c6e29c67a1c066871499e76575d4700bf6744' and 'f456e895f18adad6c0e3178c99a73f6fbd439487'
author Ethan Blanton <elb@pidgin.im>
date Thu, 11 Aug 2011 14:44:44 +0000
parents db4e78a1f46b (current diff) c563769843b2 (diff)
children 727edf2625f5
files ChangeLog libpurple/protocols/jabber/jabber.c
diffstat 19 files changed, 272 insertions(+), 113 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Jul 17 21:57:50 2011 +0000
+++ b/ChangeLog	Thu Aug 11 14:44:44 2011 +0000
@@ -3,9 +3,14 @@
 version 2.10.0 (MM/DD/YYYY):
 	Pidgin:
 	* Make the max size of incoming smileys a pref instead of hardcoding it.
-	  (Quentin Brandon)(#5231)
+	  (Quentin Brandon) (#5231)
 	* Added a plugin information dialog to show information for plugins
 	  that aren't otherwise visible in the plugins dialog.
+	* Fix building with GTK+ earlier than 2.14.0 (GTK+ 2.10 is still the
+	  minimum supported) (#14261)
+
+	libpurple:
+	* Fix a potential crash in the Log Reader plugin when reading QIP logs.
 
 	Libpurple:
 	* Fix a large number of strcpy() and strcat() invocations to use
@@ -19,6 +24,15 @@
 	  (#5242)
 	* Better status message handling. (Tomasz Wasilczyk) (#14314)
 	* Merged two buddy blocking methods. (Tomasz Wasilczyk) (#5303)
+	* Fix building of the bundled libgadu library with older versions
+	  of GnuTLS. (patch plucked from upstream) (#14365)
+
+	ICQ:
+	* Fix crash selecting Tools->Set Mood when you're online with an
+	  ICQ account that is configured as an AIM account. (#14437)
+
+	IRC:
+	* Fix the handling of formatting following mIRC ^O (#14436)
 
 	MSN:
 	* Fix seemingly random crashing. (#14307)
@@ -26,6 +40,12 @@
 	XMPP:
 	* Do not generate malformed XML ("</>") when setting an empty mood.
 	  (#14342)
+	* Fix the /join <room> behavior.  (Broken when adding support for
+	  <room>@<server>)  (#14205)
+
+	Yahoo!/Yahoo! JAPAN:
+	* Fix coming out of idle while in an unavailable state
+	* Fix logging into Yahoo! JAPAN.  (#14259)
 
 version 2.9.0 (06/23/2011):
 	Pidgin:
--- a/ChangeLog.API	Sun Jul 17 21:57:50 2011 +0000
+++ b/ChangeLog.API	Thu Aug 11 14:44:44 2011 +0000
@@ -1,6 +1,10 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
 version 2.10.0:
+	libpurple:
+		Added:
+		* purple_srv_txt_query_destroy (accidentally left out of 2.8.0)
+
 	Pidgin:
 		Added:
 		* pidgin_dialogs_plugins_info (should not be used by anything but Pidgin)
--- a/libpurple/dnsquery.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/dnsquery.c	Thu Aug 11 14:44:44 2011 +0000
@@ -154,8 +154,27 @@
 static gboolean
 resolve_ip(PurpleDnsQueryData *query_data)
 {
+#if defined(HAVE_GETADDRINFO) && defined(AI_NUMERICHOST)
+	struct addrinfo hints, *res;
+	char servname[20];
+
+	g_snprintf(servname, sizeof(servname), "%d", query_data->port);
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_flags |= AI_NUMERICHOST;
+
+	if (0 == getaddrinfo(query_data->hostname, servname, &hints, &res))
+	{
+		GSList *hosts = NULL;
+		hosts = g_slist_append(hosts, GINT_TO_POINTER(res->ai_addrlen));
+		hosts = g_slist_append(hosts, g_memdup(res->ai_addr, res->ai_addrlen));
+		purple_dnsquery_resolved(query_data, hosts);
+
+		freeaddrinfo(res);
+		return TRUE;
+	}
+#else /* defined(HAVE_GETADDRINFO) && defined(AI_NUMERICHOST) */
 	struct sockaddr_in sin;
-	/* TODO: Use inet_pton for IPv6 support */
 	if (inet_aton(query_data->hostname, &sin.sin_addr))
 	{
 		/*
@@ -171,6 +190,7 @@
 
 		return TRUE;
 	}
+#endif
 
 	return FALSE;
 }
--- a/libpurple/dnssrv.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/dnssrv.c	Thu Aug 11 14:44:44 2011 +0000
@@ -250,6 +250,52 @@
 	return list;
 }
 
+static PurpleSrvTxtQueryData *
+query_data_new(int type, gchar *query, gpointer extradata)
+{
+	PurpleSrvTxtQueryData *query_data = g_new0(PurpleSrvTxtQueryData, 1);
+	query_data->type = type;
+	query_data->extradata = extradata;
+	query_data->query = query;
+#ifndef _WIN32
+	query_data->fd_in = -1;
+	query_data->fd_out = -1;
+#endif
+	return query_data;
+}
+
+void
+purple_srv_txt_query_destroy(PurpleSrvTxtQueryData *query_data)
+{
+	PurpleSrvTxtQueryUiOps *ops = purple_srv_txt_query_get_ui_ops();
+
+	if (ops && ops->destroy)
+		ops->destroy(query_data);
+
+	if (query_data->handle > 0)
+		purple_input_remove(query_data->handle);
+#ifdef _WIN32
+	if (query_data->resolver != NULL)
+	{
+		/*
+		 * It's not really possible to kill a thread.  So instead we
+		 * just set the callback to NULL and let the DNS lookup
+		 * finish.
+		 */
+		query_data->cb.srv = NULL;
+		return;
+	}
+	g_free(query_data->error_message);
+#else
+	if (query_data->fd_out != -1)
+		close(query_data->fd_out);
+	if (query_data->fd_in != -1)
+		close(query_data->fd_in);
+#endif
+	g_free(query_data->query);
+	g_free(query_data);
+}
+
 #ifdef USE_IDN
 static gboolean
 dns_str_is_ascii(const char *name)
@@ -523,7 +569,7 @@
 	}
 
 	waitpid(query_data->pid, &status, 0);
-	purple_srv_cancel(query_data);
+	purple_srv_txt_query_destroy(query_data);
 }
 
 #else /* _WIN32 */
@@ -583,7 +629,7 @@
 	query_data->resolver = NULL;
 	query_data->handle = 0;
 
-	purple_srv_cancel(query_data);
+	purple_srv_txt_query_destroy(query_data);
 
 	return FALSE;
 }
@@ -730,13 +776,10 @@
 	purple_debug_info("dnssrv","querying SRV record for %s: %s\n", domain,
 			query);
 	g_free(hostname);
-	
-	query_data = g_new0(PurpleSrvTxtQueryData, 1);
-	query_data->type = PurpleDnsTypeSrv;
+
+	query_data = query_data_new(PurpleDnsTypeSrv, query, extradata);
 	query_data->cb.srv = cb;
-	query_data->extradata = extradata;
-	query_data->query = query;
-	
+
 	if (purple_srv_txt_query_ui_resolve(query_data))
 	{
 		return query_data;
@@ -746,6 +789,7 @@
 	if(pipe(in) || pipe(out)) {
 		purple_debug_error("dnssrv", "Could not create pipe\n");
 		g_free(query);
+		g_free(query_data);
 		cb(NULL, 0, extradata);
 		return NULL;
 	}
@@ -753,8 +797,9 @@
 	pid = fork();
 	if (pid == -1) {
 		purple_debug_error("dnssrv", "Could not create process!\n");
+		g_free(query);
+		g_free(query_data);
 		cb(NULL, 0, extradata);
-		g_free(query);
 		return NULL;
 	}
 
@@ -762,6 +807,7 @@
 	if (pid == 0)
 	{
 		g_free(query);
+		g_free(query_data);
 
 		close(out[0]);
 		close(in[1]);
@@ -784,8 +830,6 @@
 	query_data->fd_in = in[1];
 	query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data);
 
-	g_free(query);
-
 	return query_data;
 #else
 	if (!initialized) {
@@ -862,13 +906,10 @@
 	purple_debug_info("dnssrv","querying TXT record for %s: %s\n", domain,
 			query);
 	g_free(hostname);
-	
-	query_data = g_new0(PurpleSrvTxtQueryData, 1);
-	query_data->type = PurpleDnsTypeTxt;
+
+	query_data = query_data_new(PurpleDnsTypeTxt, query, extradata);
 	query_data->cb.txt = cb;
-	query_data->extradata = extradata;
-	query_data->query = query;
-	
+
 	if (purple_srv_txt_query_ui_resolve(query_data)) {
 		/* query intentionally not freed
 		 */
@@ -879,6 +920,7 @@
 	if(pipe(in) || pipe(out)) {
 		purple_debug_error("dnssrv", "Could not create pipe\n");
 		g_free(query);
+		g_free(query_data);
 		cb(NULL, extradata);
 		return NULL;
 	}
@@ -886,8 +928,9 @@
 	pid = fork();
 	if (pid == -1) {
 		purple_debug_error("dnssrv", "Could not create process!\n");
+		g_free(query);
+		g_free(query_data);
 		cb(NULL, extradata);
-		g_free(query);
 		return NULL;
 	}
 
@@ -895,6 +938,7 @@
 	if (pid == 0)
 	{
 		g_free(query);
+		g_free(query_data);
 
 		close(out[0]);
 		close(in[1]);
@@ -911,14 +955,12 @@
 
 	if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
 		purple_debug_error("dnssrv", "Could not write to TXT resolver\n");
-	
+
 	query_data->pid = pid;
 	query_data->fd_out = out[0];
 	query_data->fd_in = in[1];
 	query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data);
 
-	g_free(query);
-
 	return query_data;
 #else
 	if (!initialized) {
@@ -949,39 +991,15 @@
 }
 
 void
-purple_srv_cancel(PurpleSrvTxtQueryData *query_data)
+purple_txt_cancel(PurpleSrvTxtQueryData *query_data)
 {
-	PurpleSrvTxtQueryUiOps *ops = purple_srv_txt_query_get_ui_ops();
-
-	if (ops && ops->destroy)
-		ops->destroy(query_data);
-	
-	if (query_data->handle > 0)
-		purple_input_remove(query_data->handle);
-#ifdef _WIN32
-	if (query_data->resolver != NULL)
-	{
-		/*
-		 * It's not really possible to kill a thread.  So instead we
-		 * just set the callback to NULL and let the DNS lookup
-		 * finish.
-		 */
-		query_data->cb.srv = NULL;
-		return;
-	}
-	g_free(query_data->query);
-	g_free(query_data->error_message);
-#else
-	close(query_data->fd_out);
-	close(query_data->fd_in);
-#endif
-	g_free(query_data);
+	purple_srv_txt_query_destroy(query_data);
 }
 
 void
-purple_txt_cancel(PurpleSrvTxtQueryData *query_data)
+purple_srv_cancel(PurpleSrvTxtQueryData *query_data)
 {
-	purple_srv_cancel(query_data);
+	purple_srv_txt_query_destroy(query_data);
 }
 
 const gchar *
@@ -1006,12 +1024,41 @@
 static void
 purple_srv_query_resolved(PurpleSrvTxtQueryData *query_data, GList *records)
 {
+	GList *l;
+	PurpleSrvResponse *records_array;
+	int i = 0, length;
+
 	g_return_if_fail(records != NULL);
-	
-	purple_debug_info("dnssrv", "SRV records resolved for %s, count: %d\n", query_data->query, g_list_length(records));
-	
-	if (query_data->cb.srv != NULL)
-		query_data->cb.srv(purple_srv_sort(records)->data, g_list_length(records), query_data->extradata);
+
+	if (query_data->cb.srv == NULL) {
+		purple_srv_txt_query_destroy(query_data);
+
+		while (records) {
+			g_free(records->data);
+			records = g_list_delete_link(records, records);
+		}
+		return;
+	}
+
+	records = purple_srv_sort(records);
+	length = g_list_length(records);
+
+	purple_debug_info("dnssrv", "SRV records resolved for %s, count: %d\n",
+	                            query_data->query, length);
+
+	records_array = g_new(PurpleSrvResponse, length);
+	for (l = records; l; l = l->next, i++) {
+		records_array[i] = *(PurpleSrvResponse *)l->data;
+	}
+
+	query_data->cb.srv(records_array, length, query_data->extradata);
+
+	purple_srv_txt_query_destroy(query_data);
+
+	while (records) {
+		g_free(records->data);
+		records = g_list_delete_link(records, records);
+	}
 }
 
 /*
@@ -1024,19 +1071,29 @@
 
 	purple_debug_info("dnssrv", "TXT entries resolved for %s, count: %d\n", query_data->query, g_list_length(entries));
 
+	/* the callback should g_free the entries.
+	 */
 	if (query_data->cb.txt != NULL)
 		query_data->cb.txt(entries, query_data->extradata);
+	else {
+		while (entries) {
+			g_free(entries->data);
+			entries = g_list_delete_link(entries, entries);
+		}
+	}
+
+	purple_srv_txt_query_destroy(query_data);
 }
 
 static void
 purple_srv_query_failed(PurpleSrvTxtQueryData *query_data, const gchar *error_message)
 {
 	purple_debug_error("dnssrv", "%s\n", error_message);
-	
+
 	if (query_data->cb.srv != NULL)
 		query_data->cb.srv(NULL, 0, query_data->extradata);
-		
-	purple_srv_cancel(query_data);
+
+	purple_srv_txt_query_destroy(query_data);
 }
 
 static gboolean
@@ -1069,7 +1126,7 @@
 purple_srv_txt_query_get_query(PurpleSrvTxtQueryData *query_data)
 {
 	g_return_val_if_fail(query_data != NULL, NULL);
-	
+
 	return query_data->query;
 }
 
@@ -1078,6 +1135,6 @@
 purple_srv_txt_query_get_type(PurpleSrvTxtQueryData *query_data)
 {
 	g_return_val_if_fail(query_data != NULL, 0);
-	
+
 	return query_data->type;
 }
--- a/libpurple/dnssrv.h	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/dnssrv.h	Thu Aug 11 14:44:44 2011 +0000
@@ -133,6 +133,8 @@
  * Cancel an SRV or DNS query.
  *
  * @param query_data The request to cancel.
+ *
+ * @deprecated Use purple_srv_txt_query_destroy instead
  */
 void purple_srv_cancel(PurpleSrvTxtQueryData *query_data);
 
@@ -170,6 +172,8 @@
  *
  * @param query_data The request to cancel.
  * @since 2.6.0
+ *
+ * @deprecated Use purple_srv_txt_query_destroy instead
  */
 void purple_txt_cancel(PurpleSrvTxtQueryData *query_data);
 
--- a/libpurple/plugins/log_reader.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/plugins/log_reader.c	Thu Aug 11 14:44:44 2011 +0000
@@ -1454,11 +1454,15 @@
 		const char *footer = NULL;
 		GString *temp = NULL;
 
-		if ((c = strstr(c, "\n")))
-		{
-			*c = '\0';
-			c++;
-		}
+		/* There's always a trailing '\n' at the end of the file (see above), so
+		 * just quit out if we don't find another, because we're at the end.
+		 */
+		c = strchr(c, '\n');
+		if (!c)
+			break;
+
+		*c = '\0';
+		c++;
 
 		/* Convert links.
 		 *
@@ -1482,14 +1486,14 @@
 				char *end_paren;
 				char *space;
 
-				if (!(end_paren = strstr(link, ")")))
+				if (!(end_paren = strchr(link, ')')))
 				{
 					/* Something is not as we expect.  Bail out. */
 					break;
 				}
 
 				if (!temp)
-					temp = g_string_sized_new(c ? (c - 1 - line) : strlen(line));
+					temp = g_string_sized_new(strlen(line));
 
 				g_string_append_len(temp, line, (tmp - line));
 
@@ -1504,7 +1508,7 @@
 
 				/* The \r is a bit of a hack to keep there from being a \r in
 				 * the link text, which may not matter. */
-				if ((space = strstr(end_paren, " ")) || (space = strstr(end_paren, "\r")))
+				if ((space = strchr(end_paren, ' ')) || (space = strchr(end_paren, '\r')))
 				{
 					g_string_append_len(temp, end_paren + 1, space - end_paren - 1);
 
@@ -1539,7 +1543,7 @@
 		if (*line == '[') {
 			const char *timestamp;
 
-			if ((timestamp = strstr(line, "]"))) {
+			if ((timestamp = strchr(line, ']'))) {
 				line++;
 				/* TODO: Parse the timestamp and convert it to Purple's format. */
 				g_string_append(formatted, "<font size=\"2\">(");
@@ -1658,7 +1662,7 @@
 					}
 				}
 			} else {
-				const char *line2 = strstr(line, ":");
+				const char *line2 = strchr(line, ':');
 				if (line2) {
 					const char *acct_name;
 					line2++;
@@ -1819,7 +1823,7 @@
 
 		gboolean add_new_log = FALSE;
 
-		if (*c) {
+		if (c && *c) {
 			if (purple_str_has_prefix(c, QIP_LOG_IN_MESSAGE) ||
 				purple_str_has_prefix(c, QIP_LOG_OUT_MESSAGE)) {
 
@@ -1828,11 +1832,11 @@
 				new_line = c;
 
 				/* find EOL */
-				c = strstr(c, "\n");
+				c = strchr(c, '\n');
 				c++;
 
 				/* Find the last '(' character. */
-				if ((tmp = strstr(c, "\n")) != NULL) {
+				if ((tmp = strchr(c, '\n')) != NULL) {
 					while (*tmp && *tmp != '(') --tmp;
 					c = tmp;
 				} else {
@@ -1902,10 +1906,10 @@
 			start_log = new_line;
 		}
 
-		if (*c) {
+		if (c && *c) {
 			/* find EOF */
-			c = strstr(c, "\n");
-			c++;
+			if ((c = strchr(c, '\n')))
+				c++;
 		}
 	}
 
@@ -1983,13 +1987,13 @@
 			is_in_message = purple_str_has_prefix(line, QIP_LOG_IN_MESSAGE_ESC);
 
 			/* find EOL */
-			c = strstr(c, "\n");
+			c = strchr(c, '\n');
 
 			/* XXX: Do we need buddy_name when we have buddy->alias? */
 			buddy_name = ++c;
 
 			/* Find the last '(' character. */
-			if ((tmp = strstr(c, "\n")) != NULL) {
+			if ((tmp = strchr(c, '\n')) != NULL) {
 				while (*tmp && *tmp != '(') --tmp;
 				c = tmp;
 			} else {
@@ -2042,12 +2046,12 @@
 					}
 
 					/* find EOF */
-					c = strstr(c, "\n");
+					c = strchr(c, '\n');
 					line = ++c;
 				}
 			}
 		} else {
-			if ((c = strstr(c, "\n")))
+			if ((c = strchr(c, '\n')))
 				*c = '\0';
 
 			if (line[0] != '\n' && line[0] != '\r') {
@@ -2186,7 +2190,7 @@
 				                  " length = (%d)\n",
 				                  sn, data->path, data->offset, data->length);
 			}
-			c = strstr(c, "\n");
+			c = strchr(c, '\n');
 			c++;
 		}
 
@@ -2342,7 +2346,7 @@
 		char *end;
 		char *old_tag;
 		char *tag;
-		end = strstr(start, "\n");
+		end = strchr(start, '\n');
 		if (!end)
 			break;
 		*end = '\0';
--- a/libpurple/prefs.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/prefs.c	Thu Aug 11 14:44:44 2011 +0000
@@ -277,6 +277,12 @@
 		}
 	}
 
+	if ((pref_type == PURPLE_PREF_BOOLEAN || pref_type == PURPLE_PREF_INT) &&
+			pref_value == NULL) {
+		/* Missing a value attribute */
+		return;
+	}
+
 	if(purple_strequal(element_name, "item")) {
 		struct purple_pref *pref;
 
--- a/libpurple/protocols/gg/lib/libgadu.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/gg/lib/libgadu.c	Thu Aug 11 14:44:44 2011 +0000
@@ -893,8 +893,7 @@
 		gnutls_global_init();
 		gnutls_certificate_allocate_credentials(&tmp->xcred);
 		gnutls_init(&tmp->session, GNUTLS_CLIENT);
-		gnutls_priority_set_direct(tmp->session, "NORMAL:-VERS-TLS", NULL);
-//		gnutls_priority_set_direct(tmp->session, "NONE:+VERS-SSL3.0:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL", NULL);
+		gnutls_set_default_priority(tmp->session);
 		gnutls_credentials_set(tmp->session, GNUTLS_CRD_CERTIFICATE, tmp->xcred);
 #elif defined(GG_CONFIG_HAVE_OPENSSL)
 		char buf[1024];
--- a/libpurple/protocols/irc/parse.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/irc/parse.c	Thu Aug 11 14:44:44 2011 +0000
@@ -459,6 +459,7 @@
 				decoded = g_string_append(decoded, "</U>");
 			if (font)
 				decoded = g_string_append(decoded, "</FONT>");
+			bold = italic = underline = font = FALSE;
 			break;
 		default:
 			purple_debug(PURPLE_DEBUG_ERROR, "irc", "Unexpected mIRC formatting character %d\n", *cur);
--- a/libpurple/protocols/jabber/jabber.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Thu Aug 11 14:44:44 2011 +0000
@@ -3009,7 +3009,7 @@
 {
 	JabberChat *chat = jabber_chat_find_by_conv(conv);
 	GHashTable *components;
-	JabberID *jid;
+	JabberID *jid = NULL;
 	const char *room = NULL, *server = NULL, *handle = NULL;
 
 	if (!chat || !args || !args[0])
@@ -3017,7 +3017,8 @@
 
 	components = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
 
-	jid = jabber_id_new(args[0]);
+	if (strchr(args[0], '@'))
+		jid = jabber_id_new(args[0]);
 	if (jid) {
 		room   = jid->node;
 		server = jid->domain;
@@ -3673,8 +3674,7 @@
 	                  PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
 	                  PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber",
 	                  jabber_cmd_chat_join,
-	                  _("join: &lt;room&gt; [password]:  Join a chat on this server."),
-	                  /* _("join: &lt;room[@server]&gt; [password]:  Join a chat."), */
+	                  _("join: &lt;room[@server]&gt; [password]:  Join a chat."),
 	                  NULL);
 	commands = g_slist_prepend(commands, GUINT_TO_POINTER(id));
 
--- a/libpurple/protocols/msn/contact.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/msn/contact.c	Thu Aug 11 14:44:44 2011 +0000
@@ -474,7 +474,7 @@
 }
 
 /*parse contact list*/
-static void
+static gboolean
 msn_parse_contact_list(MsnSession *session, xmlnode *node)
 {
 	xmlnode *fault, *faultnode;
@@ -499,13 +499,14 @@
 			if (g_str_equal(errorcode, "ABDoesNotExist")) {
 				msn_create_address_book(session);
 				g_free(errorcode);
-				return;
+				return FALSE;
 			}
 
 			g_free(errorcode);
 		}
 
 		msn_get_contact_list(session, MSN_PS_INITIAL, NULL);
+		return FALSE;
 	} else {
 		xmlnode *service;
 
@@ -514,6 +515,7 @@
 			 service; service = xmlnode_get_next_twin(service)) {
 			msn_parse_each_service(session, service);
 		}
+		return TRUE;
 	}
 }
 
@@ -534,23 +536,24 @@
 
 		purple_debug_misc("msn", "Got the contact list!\n");
 
-		msn_parse_contact_list(session, resp->xml);
+		if (msn_parse_contact_list(session, resp->xml)) {
 #ifdef MSN_PARTIAL_LISTS
-		abLastChange = purple_account_get_string(session->account,
-			"ablastChange", NULL);
-		dynamicItemLastChange = purple_account_get_string(session->account,
-			"DynamicItemLastChanged", NULL);
+			abLastChange = purple_account_get_string(session->account,
+				"ablastChange", NULL);
+			dynamicItemLastChange = purple_account_get_string(session->account,
+				"DynamicItemLastChanged", NULL);
 #endif
 
-		if (state->partner_scenario == MSN_PS_INITIAL) {
+			if (state->partner_scenario == MSN_PS_INITIAL) {
 #ifdef MSN_PARTIAL_LISTS
-			/* XXX: this should be enabled when we can correctly do partial
-			   syncs with the server. Currently we need to retrieve the whole
-			   list to detect sync issues */
-			msn_get_address_book(session, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange);
+				/* XXX: this should be enabled when we can correctly do partial
+				   syncs with the server. Currently we need to retrieve the whole
+				   list to detect sync issues */
+				msn_get_address_book(session, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange);
 #else
-			msn_get_address_book(session, MSN_PS_INITIAL, NULL, NULL);
+				msn_get_address_book(session, MSN_PS_INITIAL, NULL, NULL);
 #endif
+			}
 		}
 	}
 }
--- a/libpurple/protocols/msn/notification.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/msn/notification.c	Thu Aug 11 14:44:44 2011 +0000
@@ -198,6 +198,9 @@
 	{
 		/* RPS authentication */
 
+		if (session->nexus)
+			msn_nexus_destroy(session->nexus);
+
 		session->nexus = msn_nexus_new(session);
 
 		session->nexus->policy = g_strdup(cmd->params[3]);
--- a/libpurple/protocols/msn/session.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/msn/session.c	Thu Aug 11 14:44:44 2011 +0000
@@ -288,6 +288,8 @@
 msn_session_activate_login_timeout(MsnSession *session)
 {
 	if (!session->logged_in && session->connected) {
+		if (session->login_timeout)
+			purple_timeout_remove(session->login_timeout);
 		session->login_timeout =
 			purple_timeout_add_seconds(MSN_LOGIN_FQY_TIMEOUT,
 			                           msn_login_timeout_cb, session);
--- a/libpurple/protocols/oscar/oscar.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Thu Aug 11 14:44:44 2011 +0000
@@ -743,11 +743,15 @@
 	gc->flags |= PURPLE_CONNECTION_HTML;
 	if (oscar_util_valid_name_icq((purple_account_get_username(account)))) {
 		od->icq = TRUE;
-		gc->flags |= PURPLE_CONNECTION_SUPPORT_MOODS;
 	} else {
 		gc->flags |= PURPLE_CONNECTION_AUTO_RESP;
 	}
 
+	/* Set this flag based on the protocol_id rather than the username,
+	   because that is what's tied to the get_moods prpl callback. */
+	if (g_str_equal(purple_account_get_protocol_id(account), "prpl-icq"))
+		gc->flags |= PURPLE_CONNECTION_SUPPORT_MOODS;
+
 	od->default_port = purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT);
 
 	encryption_type = purple_account_get_string(account, "encryption", OSCAR_DEFAULT_ENCRYPTION);
--- a/libpurple/protocols/sametime/sametime.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Thu Aug 11 14:44:44 2011 +0000
@@ -922,6 +922,11 @@
   alias = mwSametimeGroup_getAlias(stgroup);
   type = mwSametimeGroup_getType(stgroup);
 
+  if (!name) {
+    DEBUG_WARN("Can't ensure a null group\n");
+    return NULL;
+  }
+
   DEBUG_INFO("attempting to ensure group %s, called %s\n",
 	     NSTR(name), NSTR(alias));
 
--- a/libpurple/protocols/yahoo/libymsg.h	Sun Jul 17 21:57:50 2011 +0000
+++ b/libpurple/protocols/yahoo/libymsg.h	Thu Aug 11 14:44:44 2011 +0000
@@ -48,7 +48,7 @@
 #define YAHOO_ROOMLIST_LOCALE "us"
 
 /* Yahoo! JAPAN stuff */
-#define YAHOOJP_PAGER_HOST_REQ_URL "http://cs1.msg.vip.ogk.yahoo.co.jp/capacity"
+#define YAHOOJP_PAGER_HOST_REQ_URL "http://cs1.yahoo.co.jp/capacity"
 #define YAHOOJP_TOKEN_URL "https://login.yahoo.co.jp/config/pwtoken_get?src=ymsgr&ts=&login=%s&passwd=%s&chal=%s"
 #define YAHOOJP_LOGIN_URL "https://login.yahoo.co.jp/config/pwtoken_login?src=ymsgr&ts=&token=%s"
 #define YAHOOJP_PROFILE_URL "http://profiles.yahoo.co.jp/"
--- a/pidgin/gtkdialogs.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/pidgin/gtkdialogs.c	Thu Aug 11 14:44:44 2011 +0000
@@ -794,7 +794,8 @@
 	GList *l = NULL;
 	PurplePlugin *plugin = NULL;
 	char *title = g_strdup_printf(_("%s Plugin Information"), PIDGIN_NAME);
-	const char *pname, *pauthor, *pver, *pwebsite, *pid;
+	char *pname = NULL, *pauthor = NULL;
+	const char *pver, *pwebsite, *pid;
 	gboolean ploaded, punloadable;
 	static GtkWidget *plugins_info = NULL;
 
@@ -806,8 +807,8 @@
 	for(l = purple_plugins_get_all(); l; l = l->next) {
 		plugin = (PurplePlugin *)l->data;
 
-		pname = purple_plugin_get_name(plugin);
-		pauthor = purple_plugin_get_author(plugin);
+		pname = g_markup_escape_text(purple_plugin_get_name(plugin), -1);
+		pauthor = g_markup_escape_text(purple_plugin_get_author(plugin), -1);
 		pver = purple_plugin_get_version(plugin);
 		pwebsite = purple_plugin_get_homepage(plugin);
 		pid = purple_plugin_get_id(plugin);
@@ -829,6 +830,8 @@
 	g_signal_connect(G_OBJECT(plugins_info), "destroy",
 			G_CALLBACK(gtk_widget_destroyed), &plugins_info);
 	g_free(title);
+	g_free(pname);
+	g_free(pauthor);
 }
 
 static void
--- a/pidgin/gtkmedia.c	Sun Jul 17 21:57:50 2011 +0000
+++ b/pidgin/gtkmedia.c	Thu Aug 11 14:44:44 2011 +0000
@@ -538,12 +538,20 @@
 	GdkWindow *window = NULL;
 
 	if (data->participant == NULL)
+#if GTK_CHECK_VERSION(2, 14, 0)
 		window = gtk_widget_get_window(priv->local_video);
+#else
+		window = (priv->local_video)->window;
+#endif
 	else {
 		GtkWidget *widget = pidgin_media_get_widget(data->gtkmedia,
 				data->session_id, data->participant);
 		if (widget)
+#if GTK_CHECK_VERSION(2, 14, 0)
 			window = gtk_widget_get_window(widget);
+#else
+			window = widget->window;
+#endif
 	}
 
 	if (window) {
--- a/po/de.po	Sun Jul 17 21:57:50 2011 +0000
+++ b/po/de.po	Thu Aug 11 14:44:44 2011 +0000
@@ -11,8 +11,8 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-06-21 09:12+0200\n"
-"PO-Revision-Date: 2011-06-21 09:11+0200\n"
+"POT-Creation-Date: 2011-08-11 10:27+0200\n"
+"PO-Revision-Date: 2011-08-11 10:12+0200\n"
 "Last-Translator: Björn Voigt <bjoern@cs.tu-berlin.de>\n"
 "Language-Team: German <de@li.org>\n"
 "Language: de\n"
@@ -1959,7 +1959,7 @@
 msgstr "Unbekannter Grund"
 
 msgid "Aborting DNS lookup in Tor Proxy mode."
-msgstr "DNS-Anfrage im Tor-Proxy-Modus abgebrochen"
+msgstr "DNS-Anfrage im Tor-Proxy-Modus abgebrochen."
 
 #, c-format
 msgid ""
@@ -4778,8 +4778,8 @@
 msgstr ""
 "invite &lt;Benutzer&gt; [Nachricht]:  Lade einen Benutzer in den Raum ein."
 
-msgid "join: &lt;room&gt; [password]:  Join a chat on this server."
-msgstr "join: &lt;Raum&gt; [Passwort]:  Betrete einen Chat auf diesem Server."
+msgid "join: &lt;room[@server]&gt; [password]:  Join a chat."
+msgstr "join: &lt;Raum[@Server]&gt; [Passwort]:  Betrete einen Chat."
 
 msgid "kick &lt;user&gt; [reason]:  Kick a user from the room."
 msgstr "kick &lt;Benutzer&gt; [Grund]:  Kickt einen Benutzer aus dem Raum."
@@ -11134,6 +11134,9 @@
 msgid "/Help/De_veloper Information"
 msgstr "/Hilfe/_Entwickler-Informationen"
 
+msgid "/Help/_Plugin Information"
+msgstr "/Hilfe/_Plugin-Informationen"
+
 msgid "/Help/_Translator Information"
 msgstr "/Hilfe/Über_setzer-Informationen"
 
@@ -12149,6 +12152,13 @@
 msgid "%s Translator Information"
 msgstr "%s-Übersetzer-Informationen"
 
+#, c-format
+msgid "%s Plugin Information"
+msgstr "%s Plugin-Informationen"
+
+msgid "Plugin Information"
+msgstr "Plugin-Informationen"
+
 msgid "_Name"
 msgstr "_Name"
 
@@ -12750,7 +12760,7 @@
 
 #, c-format
 msgid "Exiting because another libpurple client is already running.\n"
-msgstr "Wird geschlossen, da bereits ein anderer libpurple-Client läuft\n"
+msgstr "Wird geschlossen, da bereits ein anderer libpurple-Client läuft.\n"
 
 msgid "_Media"
 msgstr "_Medien"
@@ -13116,6 +13126,12 @@
 msgid "F_lash window when IMs are received"
 msgstr "Fenster b_linkt, wenn IM-Nachrichten empfangen werden"
 
+msgid "Resize incoming custom smileys"
+msgstr "Erhaltene benutzerdefinierte Smileys skalieren"
+
+msgid "Maximum size:"
+msgstr "Maximale Größe:"
+
 msgid "Minimum input area height in lines:"
 msgstr "Minimale Höhe des Eingabefeldes in Zeilen:"