changeset 31424:b11ce3aecca9

merged from im.pidgin.pidgin
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 29 Nov 2010 19:49:04 +0900
parents 8cd02ebf6ed6 (current diff) 18d56b13fe8b (diff)
children 8fd65bb260cf
files configure.ac libpurple/protocols/msn/msn.c
diffstat 29 files changed, 382 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Nov 24 19:52:47 2010 +0900
+++ b/ChangeLog	Mon Nov 29 19:49:04 2010 +0900
@@ -1,8 +1,23 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
 version 2.7.8 (??/??/????):
+	General:
+	* Fix the exceptions in purple-remote on Python 2.6+. (Ari Pollak)
+	  (#12151)
+
+	libpurple:
+	* Fix multipart parsing when '=' is included in the boundary for
+	  purple_mime_document_parse. (Jakub Adam) (#11598)
+
+	Gadu-Gadu:
+	* Updated our bundled libgadu and minimum requirement for external
+	  libgadu to 1.9.0. (#12789)
+
 	MSN:
-	* Don't show ourselves in the list of endpoints that can be disconnected.
+	* Stop showing ourselves in the list of endpoints that can be
+	  disconnected.
+	* Allow full-size display names, by not escaping (most) non-English
+	  characters. (#8508)
 
 version 2.7.7 (11/23/2010):
 	General:
--- a/configure.ac	Wed Nov 24 19:52:47 2010 +0900
+++ b/configure.ac	Mon Nov 29 19:49:04 2010 +0900
@@ -1046,7 +1046,7 @@
 	gadu_manual_check="no"
 fi
 if test "x$gadu_manual_check" = "xno"; then
-	PKG_CHECK_MODULES(GADU, [libgadu >= 1.9.0-rc2], [
+	PKG_CHECK_MODULES(GADU, [libgadu >= 1.9.0], [
 		gadu_includes="yes"
 		gadu_libs="yes"
 	], [
--- a/libpurple/mime.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/mime.c	Mon Nov 29 19:49:04 2010 +0900
@@ -436,6 +436,34 @@
 	g_free(bnd);
 }
 
+#define BOUNDARY "boundary="
+static char *
+parse_boundary(const char *ct)
+{
+	char *boundary_begin = g_strstr_len(ct, -1, BOUNDARY);
+	char *boundary_end;
+
+	if (!boundary_begin)
+		return NULL;
+
+	boundary_begin += sizeof(BOUNDARY) - 1;
+
+	if (*boundary_begin == '"') {
+		boundary_end = strchr(++boundary_begin, '"');
+		if (!boundary_end)
+			return NULL;
+	} else {
+		boundary_end = strchr(boundary_begin, ' ');
+		if (!boundary_end) {
+			boundary_end = strchr(boundary_begin, ';');
+			if (!boundary_end)
+				boundary_end = boundary_begin + strlen(boundary_begin);
+		}
+	}
+
+	return g_strndup(boundary_begin, boundary_end - boundary_begin);
+}
+#undef BOUNDARY
 
 PurpleMimeDocument *
 purple_mime_document_parsen(const char *buf, gsize len)
@@ -456,10 +484,11 @@
 
 	{
 		const char *ct = fields_get(&doc->fields, "content-type");
-		if(ct && purple_str_has_prefix(ct, "multipart")) {
-			char *bd = strrchr(ct, '=');
-			if(bd++) {
+		if (ct && purple_str_has_prefix(ct, "multipart")) {
+			char *bd = parse_boundary(ct);
+			if (bd) {
 				doc_parts_load(doc, bd, b, n);
+				g_free(bd);
 			}
 		}
 	}
--- a/libpurple/network.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/network.c	Mon Nov 29 19:49:04 2010 +0900
@@ -350,17 +350,15 @@
 
 	if (success) {
 		/* add port mapping to hash table */
-		gint *key = g_new(gint, 1);
-		gint *value = g_new(gint, 1);
-		*key = purple_network_get_port_from_fd(listen_data->listenfd);
-		*value = listen_data->socket_type;
-		g_hash_table_insert(upnp_port_mappings, key, value);
+		gint key = purple_network_get_port_from_fd(listen_data->listenfd);
+		gint value = listen_data->socket_type;
+		g_hash_table_insert(upnp_port_mappings, GINT_TO_POINTER(key), GINT_TO_POINTER(value));
 	}
 
 	if (listen_data->cb)
 		listen_data->cb(listen_data->listenfd, listen_data->cb_data);
 
-	/* Clear the UPnP mapping data, since it's complete and purple_netweork_listen_cancel() will try to cancel
+	/* Clear the UPnP mapping data, since it's complete and purple_network_listen_cancel() will try to cancel
 	 * it otherwise. */
 	listen_data->mapping_data = NULL;
 	purple_network_listen_cancel(listen_data);
@@ -370,16 +368,16 @@
 purple_network_finish_pmp_map_cb(gpointer data)
 {
 	PurpleNetworkListenData *listen_data;
-	gint *key = g_new(gint, 1);
-	gint *value = g_new(gint, 1);
+	gint key;
+	gint value;
 
 	listen_data = data;
 	listen_data->timer = 0;
 
 	/* add port mapping to hash table */
-	*key = purple_network_get_port_from_fd(listen_data->listenfd);
-	*value = listen_data->socket_type;
-	g_hash_table_insert(nat_pmp_port_mappings, key, value);
+	key = purple_network_get_port_from_fd(listen_data->listenfd);
+	value = listen_data->socket_type;
+	g_hash_table_insert(nat_pmp_port_mappings, GINT_TO_POINTER(key), GINT_TO_POINTER(value));
 
 	if (listen_data->cb)
 		listen_data->cb(listen_data->listenfd, listen_data->cb_data);
@@ -1045,42 +1043,42 @@
 purple_network_upnp_mapping_remove(gpointer key, gpointer value,
 	gpointer user_data)
 {
-	gint port = (gint) *((gint *) key);
-	gint protocol = (gint) *((gint *) value);
+	gint port = GPOINTER_TO_INT(key);
+	gint protocol = GPOINTER_TO_INT(value);
 	purple_debug_info("network", "removing UPnP port mapping for port %d\n",
 		port);
-	purple_upnp_remove_port_mapping(port, 
-		protocol == SOCK_STREAM ? "TCP" : "UDP", 
+	purple_upnp_remove_port_mapping(port,
+		protocol == SOCK_STREAM ? "TCP" : "UDP",
 		purple_network_upnp_mapping_remove_cb, NULL);
-	g_hash_table_remove(upnp_port_mappings, key);
+	g_hash_table_remove(upnp_port_mappings, GINT_TO_POINTER(port));
 }
 
 static void
 purple_network_nat_pmp_mapping_remove(gpointer key, gpointer value,
 	gpointer user_data)
 {
-	gint port = (gint) *((gint *) key);
-	gint protocol = (gint) *((gint *) value);
+	gint port = GPOINTER_TO_INT(key);
+	gint protocol = GPOINTER_TO_INT(value);
 	purple_debug_info("network", "removing NAT-PMP port mapping for port %d\n",
 		port);
 	purple_pmp_destroy_map(
-		protocol == SOCK_STREAM ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP, 
+		protocol == SOCK_STREAM ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP,
 		port);
-	g_hash_table_remove(nat_pmp_port_mappings, key);
+	g_hash_table_remove(nat_pmp_port_mappings, GINT_TO_POINTER(port));
 }
 
 void
 purple_network_remove_port_mapping(gint fd)
 {
 	int port = purple_network_get_port_from_fd(fd);
-	gint *protocol = g_hash_table_lookup(upnp_port_mappings, &port);
+	gint protocol = GPOINTER_TO_INT(g_hash_table_lookup(upnp_port_mappings, GINT_TO_POINTER(port)));
 
 	if (protocol) {
-		purple_network_upnp_mapping_remove(&port, protocol, NULL);
+		purple_network_upnp_mapping_remove(GINT_TO_POINTER(port), GINT_TO_POINTER(protocol), NULL);
 	} else {
-		protocol = g_hash_table_lookup(nat_pmp_port_mappings, &port);
+		protocol = GPOINTER_TO_INT(g_hash_table_lookup(nat_pmp_port_mappings, GINT_TO_POINTER(port)));
 		if (protocol) {
-			purple_network_nat_pmp_mapping_remove(&port, protocol, NULL);
+			purple_network_nat_pmp_mapping_remove(GINT_TO_POINTER(port), GINT_TO_POINTER(protocol), NULL);
 		}
 	}
 }
@@ -1178,16 +1176,14 @@
 
 	purple_pmp_init();
 	purple_upnp_init();
-	
+
 	purple_network_set_stun_server(
 		purple_prefs_get_string("/purple/network/stun_server"));
 	purple_network_set_turn_server(
 		purple_prefs_get_string("/purple/network/turn_server"));
 
-	upnp_port_mappings = 
-		g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
-	nat_pmp_port_mappings =
-		g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
+	upnp_port_mappings = g_hash_table_new(g_direct_hash, g_direct_equal);
+	nat_pmp_port_mappings = g_hash_table_new(g_direct_hash, g_direct_equal);
 }
 
 
@@ -1231,13 +1227,13 @@
 #endif
 	purple_signal_unregister(purple_network_get_handle(),
 							 "network-configuration-changed");
-	
+
 	if (stun_ip)
 		g_free(stun_ip);
 
 	g_hash_table_destroy(upnp_port_mappings);
 	g_hash_table_destroy(nat_pmp_port_mappings);
 
-	/* TODO: clean up remaining port mappings, note calling 
+	/* TODO: clean up remaining port mappings, note calling
 	 purple_upnp_remove_port_mapping from here doesn't quite work... */
 }
--- a/libpurple/protocols/gg/lib/dcc7.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/gg/lib/dcc7.c	Mon Nov 29 19:49:04 2010 +0900
@@ -731,6 +731,7 @@
 		e->event.dcc7_accept.remote_port = dcc->remote_port;
 	} else {
 		e->type = GG_EVENT_DCC7_PENDING;
+		e->event.dcc7_pending.dcc7 = dcc;
 	}
 
 	if (gg_dcc7_connect(sess, dcc) == -1) {
@@ -1004,6 +1005,7 @@
 
 				if (gg_dcc7_reverse_connect(dcc) != -1) {
 					e->type = GG_EVENT_DCC7_PENDING;
+					e->event.dcc7_pending.dcc7 = dcc;
 				} else {
 					e->type = GG_EVENT_DCC7_ERROR;
 					e->event.dcc_error = GG_ERROR_DCC7_NET;
--- a/libpurple/protocols/gg/lib/events.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/gg/lib/events.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1149,6 +1149,7 @@
 
 			e->type = GG_EVENT_NOTIFY60;
 			e->event.notify60 = malloc(sizeof(*e->event.notify60));
+
 			if (!e->event.notify60) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
 				goto fail;
@@ -1159,7 +1160,7 @@
 			while (length >= sizeof(struct gg_notify_reply80)) {
 				uint32_t descr_len;
 				char *tmp;
-				
+
 				e->event.notify60[i].uin	= gg_fix32(n->uin);
 				e->event.notify60[i].status	= gg_fix32(n->status);
 				e->event.notify60[i].remote_ip	= n->remote_ip;
@@ -1169,7 +1170,6 @@
 				e->event.notify60[i].version	= 0x00;	/* not-supported */
 				e->event.notify60[i].time	= 0;	/* not-supported */
 
-				
 				descr_len = gg_fix32(n->descr_len);
 
 				length -= sizeof(struct gg_notify_reply80);
--- a/libpurple/protocols/gg/lib/libgadu.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/gg/lib/libgadu.c	Mon Nov 29 19:49:04 2010 +0900
@@ -69,7 +69,7 @@
 #  include <openssl/rand.h>
 #endif
 
-#define GG_LIBGADU_VERSION "1.9.0-rc2"
+#define GG_LIBGADU_VERSION "1.9.0"
 
 /**
  * Poziom rejestracji informacji odpluskwiających. Zmienna jest maską bitową
@@ -180,7 +180,7 @@
 #ifdef __GNUC__
 __attribute__ ((unused))
 #endif
-= "$Id: libgadu.c 878 2009-11-16 23:48:19Z wojtekka $";
+= "$Id: libgadu.c 923 2010-03-09 20:03:29Z wojtekka $";
 #endif
 
 #endif /* DOXYGEN */
@@ -1316,41 +1316,65 @@
  * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML.
  *
  * \param dst Bufor wynikowy (może być \c NULL)
- * \param utf_msg Tekst źródłowy
+ * \param src Tekst źródłowy w UTF-8
  * \param format Atrybuty tekstu źródłowego
  * \param format_len Długość bloku atrybutów tekstu źródłowego
  *
+ * \note Wynikowy tekst nie jest idealnym kodem HTML, ponieważ ma jak
+ * dokładniej odzwierciedlać to, co wygenerowałby oryginalny klient.
+ *
  * \note Dokleja \c \\0 na końcu bufora wynikowego.
  *
  * \return Długość tekstu wynikowego bez \c \\0 (nawet jeśli \c dst to \c NULL).
  */
-static int gg_convert_to_html(char *dst, const char *utf_msg, const unsigned char *format, int format_len)
+static int gg_convert_to_html(char *dst, const char *src, const unsigned char *format, int format_len)
 {
 	const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">";
 	const int span_len = 75;
-	const char img_fmt[] = "<img src=\"%02x%02x%02x%02x%02x%02x%02x%02x\">";
-	const int img_len = 28;
+	const char img_fmt[] = "<img name=\"%02x%02x%02x%02x%02x%02x%02x%02x\">";
+	const int img_len = 29;
 	int char_pos = 0;
-	int format_idx = 3;
+	int format_idx = 0;
 	unsigned char old_attr = 0;
 	const unsigned char *color = (const unsigned char*) "\x00\x00\x00";
 	int len, i;
 
 	len = 0;
 
-	for (i = 0; utf_msg[i] != 0; i++) {
-		unsigned char attr;
-		int attr_pos;
+	/* Nie mamy atrybutów dla pierwsze znaku, a tekst nie jest pusty, więc
+	 * tak czy inaczej trzeba otworzyć <span>. */
+
+	if (src[0] != 0 && (format_idx + 3 > format_len || (format[format_idx] | (format[format_idx + 1] << 8)) != 0)) {
+		if (dst != NULL)
+			sprintf(&dst[len], span_fmt, 0, 0, 0);
+
+		len += span_len;
+	}
+
+	/* Pętla przechodzi też przez kończące \0, żeby móc dokleić obrazek
+	 * na końcu tekstu. */
 
-		if (format_idx + 3 <= format_len) {
+	for (i = 0; ; i++) {
+		/* Analizuj atrybuty tak długo jak dotyczą aktualnego znaku. */
+		for (;;) {
+			unsigned char attr;
+			int attr_pos;
+
+			if (format_idx + 3 > format_len)
+				break;
+
 			attr_pos = format[format_idx] | (format[format_idx + 1] << 8);
+
+			if (attr_pos != char_pos)
+				break;
+
 			attr = format[format_idx + 2];
-		} else {
-			attr_pos = -1;
-			attr = 0;
-		}
+
+			/* Nie doklejaj atrybutów na końcu, co najwyżej obrazki. */
 
-		if (attr_pos == char_pos) {
+			if (src[i] == 0)
+				attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR);
+
 			format_idx += 3;
 
 			if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0) {
@@ -1377,7 +1401,7 @@
 				if (dst != NULL)
 					sprintf(&dst[len], span_fmt, color[0], color[1], color[2]);
 				len += span_len;
-			} else if (char_pos == 0) {
+			} else if (char_pos == 0 && src[0] != 0) {
 				if (dst != NULL)
 					sprintf(&dst[len], span_fmt, 0, 0, 0);
 				len += span_len;
@@ -1410,14 +1434,11 @@
 			}
 
 			old_attr = attr;
-		} else if (i == 0) {
-			if (dst != NULL)
-				sprintf(&dst[len], span_fmt, 0, 0, 0);
-
-			len += span_len;
 		}
 
-		switch (utf_msg[i]) {
+		/* Doklej znak zachowując htmlowe escapowanie. */
+
+		switch (src[i]) {
 			case '&':
 				gg_append(dst, &len, "&amp;", 5);
 				break;
@@ -1437,19 +1458,25 @@
 				gg_append(dst, &len, "<br>", 4);
 				break;
 			case '\r':
+			case 0:
 				break;
 			default:
 				if (dst != NULL)
-					dst[len] = utf_msg[i];
+					dst[len] = src[i];
 				len++;
 		}
 
 		/* Sprawdź, czy bajt nie jest kontynuacją znaku unikodowego. */
 
-		if ((utf_msg[i] & 0xc0) != 0xc0)
+		if ((src[i] & 0xc0) != 0xc0)
 			char_pos++;
+
+		if (src[i] == 0)
+			break;
 	}
 
+	/* Zamknij tagi. */
+
 	if ((old_attr & GG_FONT_UNDERLINE) != 0)
 		gg_append(dst, &len, "</u>", 4);
 
@@ -1459,16 +1486,8 @@
 	if ((old_attr & GG_FONT_BOLD) != 0)
 		gg_append(dst, &len, "</b>", 4);
 
-	/* Dla pustych tekstów dodaj pusty <span>. */
-
-	if (i == 0) {
-		if (dst != NULL)
-			sprintf(&dst[len], span_fmt, 0, 0, 0);
-
-		len += span_len;
-	}
-
-	gg_append(dst, &len, "</span>", 7);
+	if (src[0] != 0)
+		gg_append(dst, &len, "</span>", 7);
 
 	if (dst != NULL)
 		dst[len] = 0;
@@ -1564,7 +1583,7 @@
 			formatlen = 9;
 		}
 
-		len = gg_convert_to_html(NULL, utf_msg, format, formatlen);
+		len = gg_convert_to_html(NULL, utf_msg, format + 3, formatlen - 3);
 
 		html_msg = malloc(len + 1);
 
@@ -1573,7 +1592,7 @@
 			goto cleanup;
 		}
 
-		gg_convert_to_html(html_msg, utf_msg, format, formatlen);
+		gg_convert_to_html(html_msg, utf_msg, format + 3, formatlen - 3);
 
 		s80.seq = gg_fix32(seq_no);
 		s80.msgclass = gg_fix32(msgclass);
--- a/libpurple/protocols/gg/lib/libgadu.h	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/gg/lib/libgadu.h	Mon Nov 29 19:49:04 2010 +0900
@@ -865,6 +865,13 @@
 };
 
 /**
+ * Opis zdarzenia \c GG_EVENT_DCC7_PENDING.
+ */
+struct gg_event_dcc7_pending {
+	struct gg_dcc7 *dcc7;	/**< Struktura połączenia */
+};
+
+/**
  * Opis zdarzenia \c GG_EVENT_DCC7_REJECT.
  */
 struct gg_event_dcc7_reject {
@@ -908,6 +915,7 @@
 	struct gg_dcc7 *dcc7_new;	/**< Nowe połączenie bezpośrednie (\c GG_EVENT_DCC7_NEW) */
 	enum gg_error_t dcc7_error;	/**< Błąd połączenia bezpośredniego (\c GG_EVENT_DCC7_ERROR) */
 	struct gg_event_dcc7_connected dcc7_connected;	/**< Informacja o zestawieniu połączenia bezpośredniego (\c GG_EVENT_DCC7_CONNECTED) */
+	struct gg_event_dcc7_pending dcc7_pending;	/**< Trwa próba połączenia bezpośredniego (\c GG_EVENT_DCC7_PENDING) */
 	struct gg_event_dcc7_reject dcc7_reject;	/**< Odrzucono połączenia bezpośredniego (\c GG_EVENT_DCC7_REJECT) */
 	struct gg_event_dcc7_accept dcc7_accept;	/**< Zaakceptowano połączenie bezpośrednie (\c GG_EVENT_DCC7_ACCEPT) */
 };
--- a/libpurple/protocols/msn/cmdproc.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/cmdproc.c	Mon Nov 29 19:49:04 2010 +0900
@@ -122,7 +122,7 @@
 	servconn = cmdproc->servconn;
 
 	if (!servconn->connected) {
-		/* TODO: Need to free trans */
+		msn_transaction_destroy(trans);
 		return;
 	}
 
@@ -156,6 +156,8 @@
 
 	msn_servconn_write(servconn, data, len);
 
+	if (!trans->saveable)
+		msn_transaction_destroy(trans);
 	g_free(data);
 }
 
--- a/libpurple/protocols/msn/httpconn.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/httpconn.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1,5 +1,5 @@
 /**
- * @file httpmethod.c HTTP connection method
+ * @file httpconn.c HTTP connection method
  *
  * purple
  *
--- a/libpurple/protocols/msn/msn.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/msn.c	Mon Nov 29 19:49:04 2010 +0900
@@ -250,7 +250,7 @@
 	MsnSession *session;
 	MsnTransaction *trans;
 	PurpleAccount *account;
-	const char *real_alias;
+	char real_alias[BUDDY_ALIAS_MAXLEN+1];
 	struct public_alias_closure *closure;
 	gchar *tmp;
 	gsize dummy;
@@ -268,8 +268,7 @@
 	else
 		real_alias = "";
 
-	if (strlen(real_alias) > BUDDY_ALIAS_MAXLEN)
-	{
+	if (*alias) {
 		if (failure_cb) {
 			struct public_alias_closure *closure =
 				g_new0(struct public_alias_closure, 1);
@@ -284,8 +283,8 @@
 		return;
 	}
 
-	if (*real_alias == '\0') {
-		real_alias = purple_url_encode(purple_account_get_username(account));
+	if (real_alias[0] == '\0') {
+		strcpy(real_alias, purple_account_get_username(account));
 	}
 
 	closure = g_new0(struct public_alias_closure, 1);
@@ -1187,18 +1186,26 @@
 static GList *
 msn_actions(PurplePlugin *plugin, gpointer context)
 {
+	PurpleConnection *gc;
+	MsnSession *session;
 	GList *m = NULL;
 	PurplePluginAction *act;
 
+	gc = (PurpleConnection *) context;
+	session = gc->proto_data;
+
 	act = purple_plugin_action_new(_("Set Friendly Name..."),
 								 msn_show_set_friendly_name);
 	m = g_list_append(m, act);
 	m = g_list_append(m, NULL);
 
-	act = purple_plugin_action_new(_("View Locations..."),
-	                               msn_show_locations);
-	m = g_list_append(m, act);
-	m = g_list_append(m, NULL);
+	if (session->protocol_ver >= 16)
+	{
+		act = purple_plugin_action_new(_("View Locations..."),
+		                               msn_show_locations);
+		m = g_list_append(m, act);
+		m = g_list_append(m, NULL);
+	}
 
 	act = purple_plugin_action_new(_("Set Home Phone Number..."),
 								 msn_show_set_home_phone);
@@ -2124,7 +2131,6 @@
 		trans = msn_transaction_new(cmdproc, "PNG", NULL);
 		msn_transaction_set_saveable(trans, FALSE);
 		msn_cmdproc_send_trans(cmdproc, trans);
-		msn_transaction_destroy(trans);
 	}
 }
 
--- a/libpurple/protocols/msn/notification.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/notification.c	Mon Nov 29 19:49:04 2010 +0900
@@ -309,7 +309,6 @@
 	trans = msn_transaction_new(notification->cmdproc, "OUT", NULL);
 	msn_transaction_set_saveable(trans, FALSE);
 	msn_cmdproc_send_trans(notification->cmdproc, trans);
-	msn_transaction_destroy(trans);
 
 	msn_notification_disconnect(notification);
 }
--- a/libpurple/protocols/msn/p2p.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/p2p.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1,3 +1,27 @@
+/**
+ * @file p2p.c MSN P2P functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
 #include "internal.h"
 
 #include "p2p.h"
@@ -71,6 +95,6 @@
 msn_p2p_msg_is_data(const MsnP2PHeaderFlag flags)
 {
 	return (flags == P2P_MSN_OBJ_DATA ||
-	        flags == (P2P_WML2009_COMP | P2P_MSN_OBJ_DATA) ||
+	        flags == (P2P_WLM2009_COMP | P2P_MSN_OBJ_DATA) ||
 	        flags == P2P_FILE_DATA);
 }
--- a/libpurple/protocols/msn/p2p.h	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/p2p.h	Mon Nov 29 19:49:04 2010 +0900
@@ -1,3 +1,27 @@
+/**
+ * @file p2p.h MSN P2P functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
 #ifndef MSN_P2P_H
 #define MSN_P2P_H
 
@@ -49,7 +73,7 @@
 	P2P_CLOSE           = 0x40,       /**< Close session */
 	P2P_TLP_ERROR       = 0x80,       /**< Error at transport layer protocol */
 	P2P_DC_HANDSHAKE    = 0x100,      /**< Direct Handshake */
-	P2P_WML2009_COMP    = 0x1000000,  /**< Compatibility with WLM 2009 */
+	P2P_WLM2009_COMP    = 0x1000000,  /**< Compatibility with WLM 2009 */
 	P2P_FILE_DATA       = 0x1000030   /**< File transfer data */
 } MsnP2PHeaderFlag;
 /* Info From:
--- a/libpurple/protocols/msn/sbconn.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/sbconn.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1,3 +1,27 @@
+/**
+ * @file sbconn.c MSN Switchboard Connection
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
 #include "internal.h"
 #include "debug.h"
 
--- a/libpurple/protocols/msn/sbconn.h	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/sbconn.h	Mon Nov 29 19:49:04 2010 +0900
@@ -1,3 +1,27 @@
+/**
+ * @file sbconn.h MSN Switchboard Connection
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
 #ifndef MSN_SBCONN_H
 #define MSN_SBCONN_H
 
--- a/libpurple/protocols/msn/slpcall.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/slpcall.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1061,7 +1061,7 @@
 	body = slpmsg->buffer;
 	body_len = slpmsg->header->offset;
 
-	if (slpmsg->header->flags == P2P_NO_FLAG || slpmsg->header->flags == P2P_WML2009_COMP)
+	if (slpmsg->header->flags == P2P_NO_FLAG || slpmsg->header->flags == P2P_WLM2009_COMP)
 	{
 		char *body_str;
 
--- a/libpurple/protocols/msn/slplink.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/slplink.c	Mon Nov 29 19:49:04 2010 +0900
@@ -518,7 +518,7 @@
 			msn_directconn_send_handshake(directconn);
 #endif
 	}
-	else if (slpmsg->header->flags == P2P_NO_FLAG || slpmsg->header->flags == P2P_WML2009_COMP ||
+	else if (slpmsg->header->flags == P2P_NO_FLAG || slpmsg->header->flags == P2P_WLM2009_COMP ||
 			msn_p2p_msg_is_data(slpmsg->header->flags))
 	{
 		/* Release all the messages and send the ACK */
--- a/libpurple/protocols/msn/slpmsg.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/slpmsg.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1,5 +1,5 @@
 /**
- * @file slpmsg.h SLP Message functions
+ * @file slpmsg.c SLP Message functions
  *
  * purple
  *
--- a/libpurple/protocols/msn/slpmsg_part.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/slpmsg_part.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1,3 +1,27 @@
+/**
+ * @file slpmsg_part.c MSNSLP Parts
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
 #include "internal.h"
 #include "debug.h"
 
--- a/libpurple/protocols/msn/slpmsg_part.h	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/slpmsg_part.h	Mon Nov 29 19:49:04 2010 +0900
@@ -1,3 +1,27 @@
+/**
+ * @file slpmsg_part.h MSNSLP Parts
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
 #ifndef MSN_SLPMSG_PART_H
 #define MSN_SLPMSG_PART_H
 
--- a/libpurple/protocols/msn/switchboard.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/switchboard.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1147,7 +1147,6 @@
 		trans = msn_transaction_new(cmdproc, "OUT", NULL);
 		msn_transaction_set_saveable(trans, FALSE);
 		msn_cmdproc_send_trans(cmdproc, trans);
-		msn_transaction_destroy(trans);
 
 		msn_switchboard_destroy(swboard);
 	}
--- a/libpurple/protocols/msn/user.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/user.c	Mon Nov 29 19:49:04 2010 +0900
@@ -203,6 +203,8 @@
 		status = "phone";
 	else if (!g_ascii_strcasecmp(state, "LUN"))
 		status = "lunch";
+	else if (!g_ascii_strcasecmp(state, "HDN"))
+		status = NULL;
 	else
 		status = "available";
 
--- a/libpurple/protocols/msn/xfer.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/xfer.c	Mon Nov 29 19:49:04 2010 +0900
@@ -1,3 +1,27 @@
+/**
+ * @file xfer.c MSN File Transfer functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
 #include "internal.h"
 #include "debug.h"
 
--- a/libpurple/protocols/msn/xfer.h	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/protocols/msn/xfer.h	Mon Nov 29 19:49:04 2010 +0900
@@ -1,3 +1,27 @@
+/**
+ * @file xfer.h MSN File Transfer functions
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
 
 #include "slpcall.h"
 
--- a/libpurple/purple-remote	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/purple-remote	Mon Nov 29 19:49:04 2010 +0900
@@ -36,7 +36,8 @@
     def __call__(self, *args):
         result = self.cobj.obj.__getattr__(self.attr)(*args)
         if result == 0:
-            raise "Error: " + self.attr + " " + str(args) + " returned " + str(result)
+            raise Exception("Error: %s %s returned %s" %
+                            (self.attr, args, result))
         return result
             
 def show_help(requested=False):
@@ -223,7 +224,7 @@
                             elif type == "i":
                                 methodparams.append(int(value))
                             else:
-                                raise "Don't know how to handle type \"%s\"" % type
+                                raise Exception("Don't know how to handle type \"%s\"" % type)
                     return purple.__getattr__(command)(*methodparams)
             show_help()
 
--- a/libpurple/upnp.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/libpurple/upnp.c	Mon Nov 29 19:49:04 2010 +0900
@@ -162,9 +162,9 @@
 	while(discovery_callbacks) {
 		gpointer data;
 		PurpleUPnPCallback cb = discovery_callbacks->data;
-		discovery_callbacks = g_slist_remove(discovery_callbacks, cb);
+		discovery_callbacks = g_slist_delete_link(discovery_callbacks, discovery_callbacks);
 		data = discovery_callbacks->data;
-		discovery_callbacks = g_slist_remove(discovery_callbacks, data);
+		discovery_callbacks = g_slist_delete_link(discovery_callbacks, discovery_callbacks);
 		cb(success, data);
 	}
 }
--- a/pidgin/gtkdialogs.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/pidgin/gtkdialogs.c	Mon Nov 29 19:49:04 2010 +0900
@@ -168,7 +168,6 @@
 	{N_("Greek"),               "el", "Bouklis Panos", "panos@echidna-band.com"},
 	{N_("Australian English"),  "en_AU", "Peter Lawler", "trans@six-by-nine.com.au"},
 	{N_("Canadian English"),    "en_CA", "Adam Weinberger", "adamw@gnome.org"},
-	{N_("British English"),     "en_GB", "Luke Ross", "lukeross@sys3175.co.uk"},
 	{N_("Esperanto"),           "eo", "Stéphane Fillod", "fillods@users.sourceforge.net"},
 	{N_("Spanish"),             "es", "Javier Fernández-Sanguino Peña", "jfs@debian.org"},
 	{N_("Estonian"),            "et", "Ivar Smolin", "okul@linux.ee"},
@@ -260,6 +259,7 @@
 	{N_("Czech"),               "cs", "Honza Král", NULL},
 	{N_("Czech"),               "cs", "Miloslav Trmac", "mitr@volny.cz"},
 	{N_("German"),              "de", "Daniel Seifert, Karsten Weiss", NULL},
+	{N_("British English"),     "en_GB", "Luke Ross", "luke@lukeross.name"},
 	{N_("Spanish"),             "es", "JM Pérez Cáncer", NULL},
 	{N_("Spanish"),             "es", "Nicolás Lichtmaier", NULL},
 	{N_("Spanish"),             "es", "Amaya Rodrigo", NULL},
--- a/pidgin/gtkscrollbook.c	Wed Nov 24 19:52:47 2010 +0900
+++ b/pidgin/gtkscrollbook.c	Mon Nov 29 19:49:04 2010 +0900
@@ -65,9 +65,13 @@
 }
 
 static gboolean
-scroll_left_cb(PidginScrollBook *scroll_book)
+scroll_left_cb(PidginScrollBook *scroll_book, GdkEventButton *event)
 {
 	int index;
+
+	if (event->type != GDK_BUTTON_PRESS)
+		return FALSE;
+
 	index = gtk_notebook_get_current_page(GTK_NOTEBOOK(scroll_book->notebook));
 
 	if (index > 0)
@@ -76,9 +80,13 @@
 }
 
 static gboolean
-scroll_right_cb(PidginScrollBook *scroll_book)
+scroll_right_cb(PidginScrollBook *scroll_book, GdkEventButton *event)
 {
 	int index, count;
+
+	if (event->type != GDK_BUTTON_PRESS)
+		return FALSE;
+
 	index = gtk_notebook_get_current_page(GTK_NOTEBOOK(scroll_book->notebook));
 	count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(scroll_book->notebook));
 
@@ -131,9 +139,10 @@
 }
 
 static gboolean
-scroll_close_cb(PidginScrollBook *scroll_book)
+scroll_close_cb(PidginScrollBook *scroll_book, GdkEventButton *event)
 {
-	gtk_widget_destroy(gtk_notebook_get_nth_page(GTK_NOTEBOOK(scroll_book->notebook), gtk_notebook_get_current_page(GTK_NOTEBOOK(scroll_book->notebook))));
+	if (event->type == GDK_BUTTON_PRESS)	
+		gtk_widget_destroy(gtk_notebook_get_nth_page(GTK_NOTEBOOK(scroll_book->notebook), gtk_notebook_get_current_page(GTK_NOTEBOOK(scroll_book->notebook))));
 	return FALSE;
 }