changeset 31821:17a4b32f4d46

propagate from branch 'im.pidgin.pidgin' (head 8480ab9498b0e22b164f3a40c100f59e2d6dd916) to branch 'im.pidgin.pidgin.next.minor' (head 490036a7b4ce807cb851ded91af7d959fe1c029e)
author Paul Aurich <paul@darkrain42.org>
date Sun, 30 Jan 2011 17:52:06 +0000
parents 28e27a37e4b4 (current diff) 24d62d6f72cc (diff)
children 6c660dc7cb6a
files ChangeLog configure.ac libpurple/mediamanager.c pidgin/gtkstatusbox.c pidgin/gtkutils.c
diffstat 54 files changed, 1278 insertions(+), 744 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Sun Jan 09 04:40:07 2011 +0000
+++ b/COPYRIGHT	Sun Jan 30 17:52:06 2011 +0000
@@ -81,6 +81,7 @@
 Norbert Buchmuller
 Johannes Buchner
 Sean Burke
+Gabriel Burt
 Thomas Butter
 Trevor Caira
 Andrea Canciani
@@ -94,6 +95,7 @@
 Matěj Cepl
 Cerulean Studios, LLC
 Jonathan Champ
+Markos Chandras
 Matthew Chapman
 Christophe Chapuis
 Patrick Cheung
@@ -130,6 +132,7 @@
 Florian Delizy
 Jiri Denemark
 Vinicius Depizzol
+Marc Dequènes
 Philip Derrin
 Taso N. Devetzis
 Balwinder Singh Dheeman
@@ -579,6 +582,7 @@
 Timmy Yee
 Li Yuan
 Yuriy Yevgrafov
+Jan Zachorowski
 Nickolai Zeldovich
 Tom Zickel
 Marco Ziech
--- a/ChangeLog	Sun Jan 09 04:40:07 2011 +0000
+++ b/ChangeLog	Sun Jan 30 17:52:06 2011 +0000
@@ -15,8 +15,20 @@
 	  number of times video must be scaled down, saving CPU time. (Jakub Adam)
 	  (half of #13095)
 	* Starting multiple video calls and ending one no longer causes the other
-	  calls to stop sending audio and video. (Jakub Adam) (#12758)
-	* Perl bindings now respect LDFLAGS. (Peter Volkov) (#12638)
+	  calls to stop sending audio and video. (Jakub Adam) (#12758, #13237)
+	* Perl bindings now respect LDFLAGS. (Peter Volkov, Markos Chandras)
+	  (#12638)
+	* Added AddTrust External Root CA.  (#11554)
+	* Resolve some issues validating X.509 certificates signed off the CAcert
+	  Class 3 intermediate cert when using the GnuTLS SSL/TLS plugin.
+
+	Gadu-Gadu:
+	* Don't drop whole messages when text is colored. (Jan Zachorowski)
+	  (#13259)
+
+	Groupwise:
+	* Don't show two windows when using "Get Info" on a buddy. (Gabriel Burt;
+	  Novell, Inc.) (#13108)
 
 	IRC:
 	* Don't send ISON messages longer than 512 bytes. (Jeffrey Honig) (#9692)
@@ -25,6 +37,10 @@
 	* Stop sending audio when placing a call on hold. (Jakub Adam) (#13032)
 	* Stop translating gpointers to ints in the dbus API.  This removes
 	  functions from the dbus API.  (The openSUSE Project) (#12507)
+	* Fix D-Bus introspection calls that omit the interface parameter.  (Tom
+	  Samstag) (#13073)
+	* Fixed bugs in purple_str_to_time() that caused the most recent 'make
+	  check' failures.  (Nader Morshed) (#13131)
 
 	Pidgin:
 	* Support using the Page Up and Page Down keys on the numeric keypad in
@@ -35,6 +51,9 @@
 	Plugins:
 	* The Voice/Video Settings plugin no longer resets selected devices to
 	  defaults. (Jakub Adam) (#13044)
+	* The Voice/Video Settings plugin no longer crashes when a stored device
+	  name is not found in the list of available devices. (Jakub Adam)
+	  (#13238)
 	* The Autoaccept plugin now allows disabling filename escaping. (Rok
 	  Mandeljc) (half of #11459)
 	* The Autoaccept plugin now allows choosing Reject/Ask/Accept for
@@ -46,6 +65,8 @@
 	XMPP:
 	* Don't crash when receiving an unexpected/invalid jingle transport type.
 	  (Nikita Kozlov) (#13136)
+	* Handle Connection: Close headers for BOSH, when the server does not
+	  terminate the connection itself. (#13008)
 
 	Yahoo!/Yahoo! JAPAN:
 	* Fix a crash when an account disconnects before a p2p session is
@@ -931,7 +952,7 @@
 	  from you on MSN.
 	* Support sending an invite message to buddies when requesting
 	  authorization from them on MSN.
-	* Timeout switchboard connections aggressively (60 seconds).
+	* Timeout switchboard connections after 60 seconds (msn-pecan devs).
 
 	XMPP:
 	* Voice & Video support with Jingle (XEP-0166, 0167, 0176, & 0177),
--- a/configure.ac	Sun Jan 09 04:40:07 2011 +0000
+++ b/configure.ac	Sun Jan 30 17:52:06 2011 +0000
@@ -2406,7 +2406,7 @@
 
 AC_MSG_CHECKING(for me pot o' gold)
 AC_MSG_RESULT(no)
-AC_CHECK_FUNCS(gethostid lrand48)
+AC_CHECK_FUNCS(gethostid lrand48 timegm)
 AC_CHECK_FUNCS(memcpy memmove random strchr strerror vprintf)
 AC_CHECK_HEADERS(malloc.h paths.h sgtty.h stdarg.h sys/cdefs.h)
 AC_CHECK_HEADERS(sys/file.h sys/filio.h sys/ioctl.h sys/msgbuf.h)
--- a/libpurple/certificate.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/certificate.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1602,7 +1602,7 @@
 	GSList *ca_crts, *cur;
 	GByteArray *last_fpr, *ca_fpr;
 	gboolean valid = FALSE;
-	gchar *ca_id;
+	gchar *ca_id, *ca2_id;
 
 	peer_crt = (PurpleCertificate *) chain->data;
 
@@ -1619,7 +1619,6 @@
 		return;
 	} /* if (self signed) */
 
-	/* Next, attempt to verify the last certificate against a CA */
 	ca = purple_certificate_find_pool(x509_tls_cached.scheme_name, "ca");
 
 	/* Next, check that the certificate chain is valid */
@@ -1669,6 +1668,9 @@
 		return;
 	} /* if (signature chain not good) */
 
+	/* Next, attempt to verify the last certificate is signed by a trusted
+	 * CA, or is a trusted CA (based on fingerprint).
+	 */
 	/* If, for whatever reason, there is no Certificate Authority pool
 	   loaded, we'll verify the subject name and then warn about thsi. */
 	if ( !ca ) {
@@ -1684,27 +1686,31 @@
 
 	end_crt = g_list_last(chain)->data;
 
-	/* Attempt to look up the last certificate's issuer */
-	ca_id = purple_certificate_get_issuer_unique_id(end_crt);
+	/* Attempt to look up the last certificate, and the last certificate's
+	 * issuer. 
+	 */
+	ca_id  = purple_certificate_get_issuer_unique_id(end_crt);
+	ca2_id = purple_certificate_get_unique_id(end_crt);
 	purple_debug_info("certificate/x509/tls_cached",
 			  "Checking for a CA with DN=%s\n",
 			  ca_id);
-	ca_crts = x509_ca_get_certs(ca_id);
+	purple_debug_info("certificate/x509/tls_cached",
+			  "Also checking for a CA with DN=%s\n",
+			  ca2_id);
+	ca_crts = g_slist_concat(x509_ca_get_certs(ca_id), x509_ca_get_certs(ca2_id));
+	g_free(ca_id);
+	g_free(ca2_id);
 	if ( NULL == ca_crts ) {
 		flags |= PURPLE_CERTIFICATE_CA_UNKNOWN;
 
 		purple_debug_warning("certificate/x509/tls_cached",
-				  "Certificate Authority with DN='%s' not "
-				  "found. I'll prompt the user, I guess.\n",
-				  ca_id);
-		g_free(ca_id);
+				  "No Certificate Authorities with either DN found "
+				  "found. I'll prompt the user, I guess.\n");
 
 		x509_tls_cached_check_subject_name(vrq, flags);
 		return;
 	}
 
-	g_free(ca_id);
-
 	/*
 	 * Check the fingerprints; if they match, then this certificate *is* one
 	 * of the designated "trusted roots", and we don't need to verify the
@@ -1714,10 +1720,6 @@
 	 *
 	 * If the fingerprints don't match, we'll fall back to checking the
 	 * signature.
-	 *
-	 * GnuTLS doesn't seem to include the final root in the verification
-	 * list, so this check will never succeed.  NSS *does* include it in
-	 * the list, so here we are.
 	 */
 	last_fpr = purple_certificate_get_fingerprint_sha1(end_crt);
 	for (cur = ca_crts; cur; cur = cur->next) {
--- a/libpurple/dbus-analyze-signals.py	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/dbus-analyze-signals.py	Sun Jan 30 17:52:06 2011 +0000
@@ -32,7 +32,7 @@
         continue
 
     signal = nameregex.sub(lambda x:x.group()[1].upper(), '-'+signal)
-    print "\"<signal name='%s'>\\n\""%signal
+    print "\"    <signal name='%s'>\\n\""%signal
 
     args = marshal.split('_')
     # ['purple', 'marshal', <return type>, '', args...]
@@ -52,9 +52,9 @@
                 type = 't'
             elif arg == "BOOLEAN":
                 type = 'b'
-            print "\"<arg type='%s'/>\\n\""%type
+            print "\"      <arg type='%s'/>\\n\""%type
 
-    print "\"</signal>\\n\""
+    print "\"    </signal>\\n\""
 
 print ";"
 
--- a/libpurple/dbus-server.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/dbus-server.c	Sun Jan 30 17:52:06 2011 +0000
@@ -501,7 +501,9 @@
 
 	g_string_append(str, "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN' 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n");
 	g_string_append_printf(str, "<node name='%s'>\n", DBUS_PATH_PURPLE);
-	g_string_append_printf(str, "<interface name='%s'>\n", DBUS_INTERFACE_PURPLE);
+	g_string_append(str, "  <interface name='org.freedesktop.DBus.Introspectable'>\n    <method name='Introspect'>\n      <arg name='data' direction='out' type='s'/>\n    </method>\n  </interface>\n\n");
+
+	g_string_append_printf(str, "  <interface name='%s'>\n", DBUS_INTERFACE_PURPLE);
 
 	bindings_list = NULL;
 	purple_signal_emit(purple_dbus_get_handle(), "dbus-introspect", &bindings_list);
@@ -517,7 +519,7 @@
 		{
 			const char *text;
 
-			g_string_append_printf(str, "<method name='%s'>\n", bindings[i].name);
+			g_string_append_printf(str, "    <method name='%s'>\n", bindings[i].name);
 
 			text = bindings[i].parameters;
 			while (*text)
@@ -529,10 +531,10 @@
 				name = dbus_gettext(&text);
 
 				g_string_append_printf(str,
-						"<arg name='%s' type='%s' direction='%s'/>\n",
+						"      <arg name='%s' type='%s' direction='%s'/>\n",
 						name, type, direction);
 			}
-			g_string_append(str, "</method>\n");
+			g_string_append(str, "    </method>\n");
 		}
 	}
 
@@ -549,7 +551,7 @@
 	}
 	g_string_append(str, signals);
 
-	g_string_append(str, "</interface>\n</node>\n");
+	g_string_append(str, "  </interface>\n</node>\n");
 
 	reply = dbus_message_new_method_return(message);
 	dbus_message_append_args(reply, DBUS_TYPE_STRING, &(str->str),
@@ -568,10 +570,8 @@
 			"dbus-method-called", connection, message))
 		return DBUS_HANDLER_RESULT_HANDLED;
 
-	if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
-			dbus_message_has_path(message, DBUS_PATH_PURPLE) &&
-			dbus_message_has_interface(message, DBUS_INTERFACE_INTROSPECTABLE) &&
-			dbus_message_has_member(message, "Introspect"))
+	if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect") &&
+			dbus_message_has_path(message, DBUS_PATH_PURPLE))
 	{
 		DBusMessage *reply;
 		reply = purple_dbus_introspect(message);
--- a/libpurple/media/backend-fs2.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/media/backend-fs2.c	Sun Jan 30 17:52:06 2011 +0000
@@ -155,6 +155,44 @@
 {
 }
 
+static gboolean
+event_probe_cb(GstPad *srcpad, GstEvent *event, gboolean release_pad)
+{
+	if (GST_EVENT_TYPE(event) == GST_EVENT_CUSTOM_DOWNSTREAM
+		&& gst_event_has_name(event, "purple-unlink-tee")) {
+
+		const GstStructure *s = gst_event_get_structure(event);
+
+		gst_pad_unlink(srcpad, gst_pad_get_peer(srcpad));
+
+		gst_pad_remove_event_probe(srcpad,
+			g_value_get_uint(gst_structure_get_value(s, "handler-id")));
+
+		if (g_value_get_boolean(gst_structure_get_value(s, "release-pad")))
+			gst_element_release_request_pad(GST_ELEMENT_PARENT(srcpad), srcpad);
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+unlink_teepad_dynamic(GstPad *srcpad, gboolean release_pad)
+{
+	guint id = gst_pad_add_event_probe(srcpad, G_CALLBACK(event_probe_cb), NULL);
+
+	if (GST_IS_GHOST_PAD(srcpad))
+		srcpad = gst_ghost_pad_get_target(GST_GHOST_PAD(srcpad));
+
+	gst_element_send_event(gst_pad_get_parent_element(srcpad),
+		gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM,
+			gst_structure_new("purple-unlink-tee",
+				"release-pad", G_TYPE_BOOLEAN, release_pad,
+				"handler-id", G_TYPE_UINT, id,
+				NULL)));
+}
+
 static void
 purple_media_backend_fs2_dispose(GObject *obj)
 {
@@ -179,7 +217,7 @@
 					g_list_delete_link(sessions, sessions)) {
 				PurpleMediaBackendFs2Session *session = sessions->data;
 				if (session->srcpad) {
-					gst_pad_set_blocked(session->srcpad, TRUE);
+					unlink_teepad_dynamic(session->srcpad, FALSE);
 					gst_object_unref(session->srcpad);
 					session->srcpad = NULL;
 				}
--- a/libpurple/mediamanager.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/mediamanager.c	Sun Jan 30 17:52:06 2011 +0000
@@ -400,7 +400,6 @@
 	GstIteratorResult result;
 
 	gst_element_release_request_pad(GST_ELEMENT_PARENT(pad), pad);
-	gst_pad_set_blocked(pad, FALSE);
 
 	iter = gst_element_iterate_src_pads(parent);
 
--- a/libpurple/protocols/gg/gg.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/gg/gg.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1464,6 +1464,10 @@
 				increased_len += 4;
 				under = FALSE;
 			}
+
+			if (actformat->font & GG_FONT_COLOR) {
+				cformats += sizeof(struct gg_msg_richtext_color);
+			}
 		}
 
 		msg = message->str;
--- a/libpurple/protocols/jabber/auth_cyrus.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/jabber/auth_cyrus.c	Sun Jan 30 17:52:06 2011 +0000
@@ -520,9 +520,12 @@
 		g_free(dec_in);
 
 		if (js->sasl_state != SASL_OK) {
-			/* This should never happen! */
+			/* This happens when the server sends back jibberish
+			 * in the "additional data with success" case.
+			 * Seen with Wildfire 3.0.1.
+			 */
 			*error = g_strdup(_("Invalid response from server"));
-			g_return_val_if_reached(JABBER_SASL_STATE_FAIL);
+			return JABBER_SASL_STATE_FAIL;
 		}
 	}
 
--- a/libpurple/protocols/jabber/bosh.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/jabber/bosh.c	Sun Jan 30 17:52:06 2011 +0000
@@ -108,8 +108,27 @@
 	int requests; /* number of outstanding HTTP requests */
 
 	gboolean headers_done;
+	gboolean close;
+};
 
-};
+static void
+debug_dump_http_connections(PurpleBOSHConnection *conn)
+{
+	int i;
+
+	g_return_if_fail(conn != NULL);
+
+	for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) {
+		PurpleHTTPConnection *httpconn = conn->connections[i];
+		if (httpconn == NULL)
+			purple_debug_misc("jabber", "BOSH %p->connections[%d] = (nil)\n",
+			                  conn, i);
+		else
+			purple_debug_misc("jabber", "BOSH %p->connections[%d] = %p, state = %d"
+			                  ", requests = %d\n", conn, i, httpconn,
+			                  httpconn->state, httpconn->requests);
+	}
+}
 
 static void http_connection_connect(PurpleHTTPConnection *conn);
 static void http_connection_send_request(PurpleHTTPConnection *conn,
@@ -263,18 +282,8 @@
 {
 	int i;
 
-	if (purple_debug_is_verbose()) {
-		for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) {
-			PurpleHTTPConnection *httpconn = conn->connections[i];
-			if (httpconn == NULL)
-				purple_debug_misc("jabber", "BOSH %p->connections[%d] = (nil)\n",
-				                  conn, i);
-			else
-				purple_debug_misc("jabber", "BOSH %p->connections[%d] = %p, state = %d"
-				                  ", requests = %d\n", conn, i, httpconn,
-				                  httpconn->state, httpconn->requests);
-		}
-	}
+	if (purple_debug_is_verbose())
+		debug_dump_http_connections(conn);
 
 	/* Easy solution: Does everyone involved support pipelining? Hooray! Just use
 	 * one TCP connection! */
@@ -297,11 +306,23 @@
 			return NULL;
 	}
 
-	/* Third loop, look for one that's NULL and create a new connection */
+	/* Third loop, is something offline that we can connect? */
+	for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) {
+		if (conn->connections[i] &&
+				conn->connections[i]->state == HTTP_CONN_OFFLINE) {
+			purple_debug_info("jabber", "bosh: Reconnecting httpconn "
+			                            "(%i, %p)\n", i, conn->connections[i]);
+			http_connection_connect(conn->connections[i]);
+			return NULL;
+		}
+	}
+
+	/* Fourth loop, look for one that's NULL and create a new connection */
 	for (i = 0; i < NUM_HTTP_CONNECTIONS; ++i) {
 		if (!conn->connections[i]) {
-			purple_debug_info("jabber", "bosh: Creating and connecting new httpconn\n");
 			conn->connections[i] = jabber_bosh_http_connection_init(conn);
+			purple_debug_info("jabber", "bosh: Creating and connecting new httpconn "
+			                            "(%i, %p)\n", i, conn->connections[i]);
 
 			http_connection_connect(conn->connections[i]);
 			return NULL;
@@ -444,6 +465,25 @@
 	send_timer_cb(bosh);
 }
 
+static void
+jabber_bosh_disable_pipelining(PurpleBOSHConnection *bosh)
+{
+	/* Do nothing if it's already disabled */
+	if (!bosh->pipelining)
+		return;
+
+	bosh->pipelining = FALSE;
+	if (bosh->connections[1] == NULL) {
+		bosh->connections[1] = jabber_bosh_http_connection_init(bosh);
+		http_connection_connect(bosh->connections[1]);
+	} else {
+		/* Shouldn't happen; this should be the only place pipelining
+		 * is turned off.
+		 */
+		g_warn_if_reached();
+	}
+}
+
 static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node) {
 	xmlnode *child;
 	JabberStream *js = conn->js;
@@ -611,6 +651,8 @@
 static void
 connection_common_established_cb(PurpleHTTPConnection *conn)
 {
+	purple_debug_misc("jabber", "bosh: httpconn %p re-connected\n", conn);
+
 	/* Indicate we're ready and reset some variables */
 	conn->state = HTTP_CONN_CONNECTED;
 	if (conn->requests != 0)
@@ -622,9 +664,13 @@
 		g_string_free(conn->read_buf, TRUE);
 		conn->read_buf = NULL;
 	}
+	conn->close = FALSE;
 	conn->headers_done = FALSE;
 	conn->handled_len = conn->body_len = 0;
 
+	if (purple_debug_is_verbose())
+		debug_dump_http_connections(conn->bosh);
+
 	if (conn->bosh->js->reinit)
 		jabber_bosh_connection_send(conn->bosh, PACKET_NORMAL, NULL);
 	else if (conn->bosh->state == BOSH_CONN_ONLINE) {
@@ -639,6 +685,7 @@
 
 static void http_connection_disconnected(PurpleHTTPConnection *conn)
 {
+	gboolean had_requests = FALSE;
 	/*
 	 * Well, then. Fine! I never liked you anyway, server! I was cheating on you
 	 * with AIM!
@@ -662,7 +709,8 @@
 		conn->writeh = 0;
 	}
 
-	if (conn->requests > 0 && conn->read_buf->len == 0) {
+	had_requests = (conn->requests > 0);
+	if (had_requests && conn->read_buf->len == 0) {
 		purple_debug_error("jabber", "bosh: Adjusting BOSHconn requests (%d) to %d\n",
 		                   conn->bosh->requests, conn->bosh->requests - conn->requests);
 		conn->bosh->requests -= conn->requests;
@@ -671,13 +719,15 @@
 
 	if (conn->bosh->pipelining) {
 		/* Hmmmm, fall back to multiple connections */
-		conn->bosh->pipelining = FALSE;
-		if (conn->bosh->connections[1] == NULL) {
-			conn->bosh->connections[1] = jabber_bosh_http_connection_init(conn->bosh);
-			http_connection_connect(conn->bosh->connections[1]);
-		}
+		jabber_bosh_disable_pipelining(conn->bosh);
 	}
 
+	if (!had_requests)
+		/* If the server disconnected us without any requests, let's
+		 * just wait until we have something to send before we reconnect
+		 */
+		return;
+
 	if (++conn->bosh->failed_connections == MAX_FAILED_CONNECTIONS) {
 		purple_connection_error_reason(conn->bosh->js->gc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
@@ -704,30 +754,49 @@
 
 	cursor = conn->read_buf->str + conn->handled_len;
 
+	if (purple_debug_is_verbose())
+		purple_debug_misc("jabber", "BOSH server sent: %s\n", cursor);
+
+	/* TODO: Chunked encoding and check response version :/ */
 	if (!conn->headers_done) {
-		const char *content_length = purple_strcasestr(cursor, "\r\nContent-Length");
+		const char *content_length = purple_strcasestr(cursor, "\r\nContent-Length:");
+		const char *connection = purple_strcasestr(cursor, "\r\nConnection:");
 		const char *end_of_headers = strstr(cursor, "\r\n\r\n");
 
 		/* Make sure Content-Length is in headers, not body */
 		if (content_length && (!end_of_headers || content_length < end_of_headers)) {
-			const char *sep;
 			int len;
 
-			if ((sep = strstr(content_length, ": ")) == NULL ||
-					strstr(sep, "\r\n") == NULL)
+			if (strstr(content_length, "\r\n") == NULL)
 				/*
 				 * The packet ends in the middle of the Content-Length line.
 				 * We'll try again later when we have more.
 				 */
 				return;
 
-			len = atoi(sep + 2);
+			len = atoi(content_length + strlen("\r\nContent-Length:"));
 			if (len == 0)
-				purple_debug_warning("jabber", "Found mangled Content-Length header.\n");
+				purple_debug_warning("jabber", "Found mangled Content-Length header, or server returned 0-length response.\n");
 
 			conn->body_len = len;
 		}
 
+		if (connection && (!end_of_headers || content_length < end_of_headers)) {
+			const char *tmp;
+			if (strstr(connection, "\r\n") == NULL)
+				return;
+
+
+			tmp = connection + strlen("\r\nConnection:");
+			while (*tmp && (*tmp == ' ' || *tmp == '\t'))
+				++tmp;
+
+			if (!g_ascii_strncasecmp(tmp, "close", strlen("close"))) {
+				conn->close = TRUE;
+				jabber_bosh_disable_pipelining(conn->bosh);
+			}
+		}
+
 		if (end_of_headers) {
 			conn->headers_done = TRUE;
 			conn->handled_len = end_of_headers - conn->read_buf->str + 4;
@@ -752,6 +821,14 @@
 	http_received_cb(conn->read_buf->str + conn->handled_len, conn->body_len,
 	                 conn->bosh);
 
+	/* Connection: Close? */
+	if (conn->close && conn->state == HTTP_CONN_CONNECTED) {
+		if (purple_debug_is_verbose())
+			purple_debug_misc("jabber", "bosh (%p), server sent Connection: "
+			                            "close\n", conn);
+		http_connection_disconnected(conn);
+	}
+
 	if (conn->bosh->state == BOSH_CONN_ONLINE &&
 			(conn->bosh->requests == 0 || conn->bosh->pending->bufused > 0)) {
 		purple_debug_misc("jabber", "BOSH: Sending an empty request\n");
@@ -791,10 +868,11 @@
 
 	if (cnt == 0 || (cnt < 0 && errno != EAGAIN)) {
 		if (cnt < 0)
-			purple_debug_info("jabber", "bosh read=%d, errno=%d, error=%s\n",
-			                  cnt, errno, g_strerror(errno));
+			purple_debug_info("jabber", "BOSH (%p) read=%d, errno=%d, error=%s\n",
+			                  conn, cnt, errno, g_strerror(errno));
 		else
-			purple_debug_info("jabber", "bosh server closed the connection\n");
+			purple_debug_info("jabber", "BOSH server closed the connection (%p)\n",
+			                  conn);
 
 		/*
 		 * If the socket is closed, the processing really needs to know about
@@ -911,6 +989,9 @@
 	else
 		ret = write(conn->fd, data, len);
 
+	if (purple_debug_is_verbose())
+		purple_debug_misc("jabber", "BOSH (%p): wrote %d bytes\n", conn, ret);
+
 	return ret;
 }
 
@@ -975,7 +1056,10 @@
 
 	if (purple_debug_is_unsafe() && purple_debug_is_verbose())
 		/* Will contain passwords for SASL PLAIN and is verbose */
-		purple_debug_misc("jabber", "BOSH: Sending %s\n", data);
+		purple_debug_misc("jabber", "BOSH (%p): Sending %s\n", conn, data);
+	else if (purple_debug_is_verbose())
+		purple_debug_misc("jabber", "BOSH (%p): Sending request of "
+		                            "%" G_GSIZE_FORMAT " bytes.\n", conn, len);
 
 	if (conn->writeh == 0)
 		ret = http_connection_do_send(conn, data, len);
--- a/libpurple/protocols/msn/directconn.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/directconn.c	Sun Jan 30 17:52:06 2011 +0000
@@ -539,13 +539,11 @@
 msn_dc_enqueue_part(MsnDirectConn *dc, MsnSlpMessagePart *part)
 {
 	MsnDirectConnPacket *p;
-	guint32 length;
+	size_t length;
 
-	length = part->size + P2P_PACKET_HEADER_SIZE;
-	p = msn_dc_new_packet(length);
-
-	memcpy(p->data, part->header, P2P_PACKET_HEADER_SIZE);
-	memcpy(p->data + P2P_PACKET_HEADER_SIZE, part->buffer, part->size);
+	p = msn_dc_new_packet(0);
+	p->data = (guchar *)msn_slpmsgpart_serialize(part, &length);
+	p->length = length - P2P_PACKET_FOOTER_SIZE; /* DC doesn't need footer? */
 
 	p->sent_cb = msn_dc_send_packet_cb;
 	p->part = msn_slpmsgpart_ref(part);
--- a/libpurple/protocols/msn/error.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/error.c	Sun Jan 30 17:52:06 2011 +0000
@@ -31,7 +31,7 @@
 
 typedef struct
 {
-	PurpleConnection *gc;
+	MsnSession *session;
 	char *who;
 	char *group;
 	gboolean add;
@@ -293,9 +293,9 @@
 		group = purple_find_group(data->group);
 
 	if (group != NULL)
-		buddy = purple_find_buddy_in_group(purple_connection_get_account(data->gc), data->who, group);
+		buddy = purple_find_buddy_in_group(data->session->account, data->who, group);
 	else
-		buddy = purple_find_buddy(purple_connection_get_account(data->gc), data->who);
+		buddy = purple_find_buddy(data->session->account, data->who);
 
 	if (buddy != NULL)
 		purple_blist_remove_buddy(buddy);
@@ -309,14 +309,9 @@
 	/* this *should* be necessary !! */
 	msn_complete_sync_issue(data);
 #endif
+	MsnUserList *userlist = data->session->userlist;
 
-	if (g_list_find(purple_connections_get_all(), data->gc) != NULL)
-	{
-		MsnSession *session = data->gc->proto_data;
-		MsnUserList *userlist = session->userlist;
-
-		msn_userlist_add_buddy(userlist, data->who, data->group);
-	}
+	msn_userlist_add_buddy(userlist, data->who, data->group);
 
 	g_free(data->group);
 	g_free(data->who);
@@ -326,18 +321,14 @@
 static void
 msn_rem_cb(MsnAddRemData *data)
 {
+	MsnUserList *userlist = data->session->userlist;
 	msn_complete_sync_issue(data);
 
-	if (g_list_find(purple_connections_get_all(), data->gc) != NULL)
-	{
-		MsnSession *session = data->gc->proto_data;
-		MsnUserList *userlist = session->userlist;
 
-		if (data->group == NULL) {
-			msn_userlist_rem_buddy_from_list(userlist, data->who, MSN_LIST_FL);
-		} else {
-			g_free(data->group);
-		}
+	if (data->group == NULL) {
+		msn_userlist_rem_buddy_from_list(userlist, data->who, MSN_LIST_FL);
+	} else {
+		g_free(data->group);
 	}
 
 	g_free(data->who);
@@ -356,10 +347,10 @@
 	account = session->account;
 	gc = purple_account_get_connection(account);
 
-	data        = g_new0(MsnAddRemData, 1);
-	data->who   = g_strdup(passport);
-	data->group = g_strdup(group_name);
-	data->gc    = gc;
+	data          = g_new0(MsnAddRemData, 1);
+	data->who     = g_strdup(passport);
+	data->group   = g_strdup(group_name);
+	data->session = session;
 
 	msg = g_strdup_printf(_("Buddy list synchronization issue in %s (%s)"),
 						  purple_account_get_username(account),
@@ -382,7 +373,7 @@
 	}
 
 	purple_request_action(gc, NULL, msg, reason, PURPLE_DEFAULT_ACTION_NONE,
-						purple_connection_get_account(gc), data->who, NULL,
+						account, data->who, NULL,
 						data, 2,
 						_("Yes"), G_CALLBACK(msn_add_cb),
 						_("No"), G_CALLBACK(msn_rem_cb));
@@ -390,3 +381,4 @@
 	g_free(reason);
 	g_free(msg);
 }
+
--- a/libpurple/protocols/msn/msg.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/msg.c	Sun Jan 30 17:52:06 2011 +0000
@@ -613,15 +613,7 @@
 
 	if (msg->msnslp_message)
 	{
-		g_string_append_printf(str, "Session ID: %u\r\n", msg->part->header->session_id);
-		g_string_append_printf(str, "ID:         %u\r\n", msg->part->header->id);
-		g_string_append_printf(str, "Offset:     %" G_GUINT64_FORMAT "\r\n", msg->part->header->offset);
-		g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", msg->part->header->total_size);
-		g_string_append_printf(str, "Length:     %u\r\n", msg->part->header->length);
-		g_string_append_printf(str, "Flags:      0x%x\r\n", msg->part->header->flags);
-		g_string_append_printf(str, "ACK ID:     %u\r\n", msg->part->header->ack_id);
-		g_string_append_printf(str, "SUB ID:     %u\r\n", msg->part->header->ack_sub_id);
-		g_string_append_printf(str, "ACK Size:   %" G_GUINT64_FORMAT "\r\n", msg->part->header->ack_size);
+		msn_slpmsgpart_to_string(msg->part, str);
 
 		if (purple_debug_is_verbose() && body != NULL)
 		{
@@ -638,27 +630,17 @@
 			else
 			{
 				int i;
-				int bin_len;
 
-				if (msg->part->footer->value == P2P_APPID_SESSION)
-					bin_len = P2P_PACKET_HEADER_SIZE;
-				else
-					bin_len = body_len;
-
-				for (i = 0; i < bin_len; i++)
+				for (i = 0; i < body_len; i++)
 				{
 					g_string_append_printf(str, "%.2hhX ", body[i]);
 					if ((i % 16) == 15)
 						g_string_append(str, "\r\n");
 				}
 
-				if (bin_len == P2P_PACKET_HEADER_SIZE)
-					g_string_append_printf(str, "%s ", body + P2P_PACKET_HEADER_SIZE);
 				g_string_append(str, "\r\n");
 			}
 		}
-
-		g_string_append_printf(str, "Footer:     0x%08X\r\n", msg->part->footer->value);
 	}
 	else
 	{
--- a/libpurple/protocols/msn/msg.h	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/msg.h	Sun Jan 30 17:52:06 2011 +0000
@@ -79,7 +79,6 @@
 	MsnMsgType type;
 
 	gboolean msnslp_message;
-	MsnSlpMessage *slpmsg;
 	MsnSlpMessagePart *part;
 
 	char *remote_user;
@@ -99,7 +98,6 @@
 								  been ref'ed for using it in a callback. */
 
 	MsnCommand *cmd;
-	MsnTransaction *trans;
 
 	MsnMsgCb ack_cb; /**< The callback to call when we receive an ACK of this
 					   message. */
@@ -107,8 +105,6 @@
 					   message. */
 	void *ack_data; /**< The data used by callbacks. */
 
-	MsnMsgErrorType error; /**< The error of the message. */
-
 	guint32 retries;
 };
 
--- a/libpurple/protocols/msn/p2p.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/p2p.c	Sun Jan 30 17:52:06 2011 +0000
@@ -27,12 +27,32 @@
 #include "p2p.h"
 #include "msnutils.h"
 
-MsnP2PHeader *
-msn_p2p_header_from_wire(const char *wire)
+MsnP2PInfo *
+msn_p2p_info_new(void)
+{
+	return g_new0(MsnP2PInfo, 1);
+}
+
+MsnP2PInfo *
+msn_p2p_info_dup(MsnP2PInfo *info)
+{
+	MsnP2PInfo *new_info = g_new0(MsnP2PInfo, 1);
+	*new_info = *info;
+	return new_info;
+}
+
+void
+msn_p2p_info_free(MsnP2PInfo *info)
+{
+	g_free(info);
+}
+
+size_t
+msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire)
 {
 	MsnP2PHeader *header;
 
-	header = g_new(MsnP2PHeader, 1);
+	header = &info->header;
 
 	header->session_id = msn_pop32le(wire);
 	header->id         = msn_pop32le(wire);
@@ -44,15 +64,17 @@
 	header->ack_sub_id = msn_pop32le(wire);
 	header->ack_size   = msn_pop64le(wire);
 
-	return header;
+	return P2P_PACKET_HEADER_SIZE;
 }
 
 char *
-msn_p2p_header_to_wire(MsnP2PHeader *header)
+msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len)
 {
+	MsnP2PHeader *header;
 	char *wire;
 	char *tmp;
 
+	header = &info->header;
 	tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE);
 
 	msn_push32le(tmp, header->session_id);
@@ -65,35 +87,58 @@
 	msn_push32le(tmp, header->ack_sub_id);
 	msn_push64le(tmp, header->ack_size);
 
+	if (len)
+		*len = P2P_PACKET_HEADER_SIZE;
+
 	return wire;
 
 }
 
-MsnP2PFooter *
-msn_p2p_footer_from_wire(const char *wire)
+size_t
+msn_p2p_footer_from_wire(MsnP2PInfo *info, const char *wire)
 {
 	MsnP2PFooter *footer;
 
-	footer = g_new(MsnP2PFooter, 1);
+	footer = &info->footer;
 
 	footer->value = msn_pop32be(wire);
 
-	return footer;
+	return P2P_PACKET_FOOTER_SIZE;
 }
 
 char *
-msn_p2p_footer_to_wire(MsnP2PFooter *footer)
+msn_p2p_footer_to_wire(MsnP2PInfo *info, size_t *len)
 {
+	MsnP2PFooter *footer;
 	char *wire;
 	char *tmp;
 
+	footer = &info->footer;
 	tmp = wire = g_new(char, P2P_PACKET_FOOTER_SIZE);
 
 	msn_push32be(tmp, footer->value);
 
+	if (len)
+		*len = P2P_PACKET_FOOTER_SIZE;
+
 	return wire;
 }
 
+void
+msn_p2p_info_to_string(MsnP2PInfo *info, GString *str)
+{
+	g_string_append_printf(str, "Session ID: %u\r\n", info->header.session_id);
+	g_string_append_printf(str, "ID:         %u\r\n", info->header.id);
+	g_string_append_printf(str, "Offset:     %" G_GUINT64_FORMAT "\r\n", info->header.offset);
+	g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", info->header.total_size);
+	g_string_append_printf(str, "Length:     %u\r\n", info->header.length);
+	g_string_append_printf(str, "Flags:      0x%x\r\n", info->header.flags);
+	g_string_append_printf(str, "ACK ID:     %u\r\n", info->header.ack_id);
+	g_string_append_printf(str, "SUB ID:     %u\r\n", info->header.ack_sub_id);
+	g_string_append_printf(str, "ACK Size:   %" G_GUINT64_FORMAT "\r\n", info->header.ack_size);
+	g_string_append_printf(str, "Footer:     0x%08X\r\n", info->footer.value);
+}
+
 gboolean
 msn_p2p_msg_is_data(const MsnP2PHeaderFlag flags)
 {
@@ -102,3 +147,135 @@
 	        flags == P2P_FILE_DATA);
 }
 
+gboolean
+msn_p2p_info_is_valid(MsnP2PInfo *info)
+{
+	return info->header.total_size >= info->header.length;
+}
+
+gboolean
+msn_p2p_info_is_final(MsnP2PInfo *info)
+{
+	return info->header.offset + info->header.length >= info->header.total_size;
+}
+
+guint32
+msn_p2p_info_get_session_id(MsnP2PInfo *info)
+{
+	return info->header.session_id;
+}
+
+guint32
+msn_p2p_info_get_id(MsnP2PInfo *info)
+{
+	return info->header.id;
+}
+
+guint64
+msn_p2p_info_get_offset(MsnP2PInfo *info)
+{
+	return info->header.offset;
+}
+
+guint64
+msn_p2p_info_get_total_size(MsnP2PInfo *info)
+{
+	return info->header.total_size;
+}
+
+guint32
+msn_p2p_info_get_length(MsnP2PInfo *info)
+{
+	return info->header.length;
+}
+
+guint32
+msn_p2p_info_get_flags(MsnP2PInfo *info)
+{
+	return info->header.flags;
+}
+
+guint32
+msn_p2p_info_get_ack_id(MsnP2PInfo *info)
+{
+	return info->header.ack_id;
+}
+
+guint32
+msn_p2p_info_get_ack_sub_id(MsnP2PInfo *info)
+{
+	return info->header.ack_sub_id;
+}
+
+guint64
+msn_p2p_info_get_ack_size(MsnP2PInfo *info)
+{
+	return info->header.ack_size;
+}
+
+guint32
+msn_p2p_info_get_app_id(MsnP2PInfo *info)
+{
+	return info->footer.value;
+}
+
+void
+msn_p2p_info_set_session_id(MsnP2PInfo *info, guint32 session_id)
+{
+	info->header.session_id = session_id;
+}
+
+void
+msn_p2p_info_set_id(MsnP2PInfo *info, guint32 id)
+{
+	info->header.id = id;
+}
+
+void
+msn_p2p_info_set_offset(MsnP2PInfo *info, guint64 offset)
+{
+	info->header.offset = offset;
+}
+
+void
+msn_p2p_info_set_total_size(MsnP2PInfo *info, guint64 total_size)
+{
+	info->header.total_size = total_size;
+}
+
+void
+msn_p2p_info_set_length(MsnP2PInfo *info, guint32 length)
+{
+	info->header.length = length;
+}
+
+void
+msn_p2p_info_set_flags(MsnP2PInfo *info, guint32 flags)
+{
+	info->header.flags = flags;
+}
+
+void
+msn_p2p_info_set_ack_id(MsnP2PInfo *info, guint32 ack_id)
+{
+	info->header.ack_id = ack_id;
+}
+
+void
+msn_p2p_info_set_ack_sub_id(MsnP2PInfo *info, guint32 ack_sub_id)
+{
+	info->header.ack_sub_id = ack_sub_id;
+}
+
+void
+msn_p2p_info_set_ack_size(MsnP2PInfo *info, guint64 ack_size)
+{
+	info->header.ack_size = ack_size;
+}
+
+void
+msn_p2p_info_set_app_id(MsnP2PInfo *info, guint32 app_id)
+{
+	info->footer.value = app_id;
+}
+
--- a/libpurple/protocols/msn/p2p.h	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/p2p.h	Sun Jan 30 17:52:06 2011 +0000
@@ -58,6 +58,11 @@
 } MsnP2PFooter;
 #define P2P_PACKET_FOOTER_SIZE (1 * 4)
 
+typedef struct {
+	MsnP2PHeader header;
+	MsnP2PFooter footer;
+} MsnP2PInfo;
+
 typedef enum
 {
 	P2P_NO_FLAG         = 0x0,        /**< No flags specified */
@@ -88,19 +93,98 @@
 	P2P_APPID_DISPLAY   = 0xC         /**< Display Image */
 } MsnP2PAppId;
 
-MsnP2PHeader *
-msn_p2p_header_from_wire(const char *wire);
+MsnP2PInfo *
+msn_p2p_info_new(void);
+
+MsnP2PInfo *
+msn_p2p_info_dup(MsnP2PInfo *info);
+
+void
+msn_p2p_info_free(MsnP2PInfo *info);
+
+size_t
+msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire);
 
 char *
-msn_p2p_header_to_wire(MsnP2PHeader *header);
+msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len);
 
-MsnP2PFooter *
-msn_p2p_footer_from_wire(const char *wire);
+size_t
+msn_p2p_footer_from_wire(MsnP2PInfo *info, const char *wire);
 
 char *
-msn_p2p_footer_to_wire(MsnP2PFooter *footer);
+msn_p2p_footer_to_wire(MsnP2PInfo *info, size_t *len);
+
+void
+msn_p2p_info_to_string(MsnP2PInfo *info, GString *str);
 
 gboolean
 msn_p2p_msg_is_data(const MsnP2PHeaderFlag flags);
 
+gboolean
+msn_p2p_info_is_valid(MsnP2PInfo *info);
+
+gboolean
+msn_p2p_info_is_final(MsnP2PInfo *info);
+
+guint32
+msn_p2p_info_get_session_id(MsnP2PInfo *info);
+
+guint32
+msn_p2p_info_get_id(MsnP2PInfo *info);
+
+guint64
+msn_p2p_info_get_offset(MsnP2PInfo *info);
+
+guint64
+msn_p2p_info_get_total_size(MsnP2PInfo *info);
+
+guint32
+msn_p2p_info_get_length(MsnP2PInfo *info);
+
+guint32
+msn_p2p_info_get_flags(MsnP2PInfo *info);
+
+guint32
+msn_p2p_info_get_ack_id(MsnP2PInfo *info);
+
+guint32
+msn_p2p_info_get_ack_sub_id(MsnP2PInfo *info);
+
+guint64
+msn_p2p_info_get_ack_size(MsnP2PInfo *info);
+
+guint32
+msn_p2p_info_get_app_id(MsnP2PInfo *info);
+
+void
+msn_p2p_info_set_session_id(MsnP2PInfo *info, guint32 session_id);
+
+void
+msn_p2p_info_set_id(MsnP2PInfo *info, guint32 id);
+
+void
+msn_p2p_info_set_offset(MsnP2PInfo *info, guint64 offset);
+
+void
+msn_p2p_info_set_total_size(MsnP2PInfo *info, guint64 total_size);
+
+void
+msn_p2p_info_set_length(MsnP2PInfo *info, guint32 length);
+
+void
+msn_p2p_info_set_flags(MsnP2PInfo *info, guint32 flags);
+
+void
+msn_p2p_info_set_ack_id(MsnP2PInfo *info, guint32 ack_id);
+
+void
+msn_p2p_info_set_ack_sub_id(MsnP2PInfo *info, guint32 ack_sub_id);
+
+void
+msn_p2p_info_set_ack_size(MsnP2PInfo *info, guint64 ack_size);
+
+void
+msn_p2p_info_set_app_id(MsnP2PInfo *info, guint32 app_id);
+
 #endif /* MSN_P2P_H */
+
--- a/libpurple/protocols/msn/sbconn.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/sbconn.c	Sun Jan 30 17:52:06 2011 +0000
@@ -126,8 +126,6 @@
 	trans->payload = payload;
 	trans->payload_len = payload_len;
 
-	msg->trans = trans;
-
 	msn_cmdproc_send_trans(cmdproc, trans);
 }
 
--- a/libpurple/protocols/msn/slp.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/slp.c	Sun Jan 30 17:52:06 2011 +0000
@@ -293,7 +293,7 @@
 gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path)
 {
 	gsize size = 0;
-	MsnFileContext header;
+	MsnFileContext context;
 	gchar *u8 = NULL;
 	gchar *ret;
 	gunichar2 *uni = NULL;
@@ -323,28 +323,28 @@
 
 	preview = purple_xfer_get_thumbnail(xfer, &preview_len);
 
-	header.length = MSN_FILE_CONTEXT_SIZE;
-	header.version = 2; /* V.3 contains additional unnecessary data */
-	header.file_size = size;
+	context.length = MSN_FILE_CONTEXT_SIZE;
+	context.version = 2; /* V.3 contains additional unnecessary data */
+	context.file_size = size;
 	if (preview)
-		header.type = 0;
+		context.type = 0;
 	else
-		header.type = 1;
+		context.type = 1;
 
 	len = MIN(len, MAX_FILE_NAME_LEN);
 	for (currentChar = 0; currentChar < len; currentChar++) {
-		header.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
+		context.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
 	}
-	memset(&header.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
+	memset(&context.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
 
-	memset(&header.unknown1, 0, sizeof(header.unknown1));
-	header.unknown2 = 0xffffffff;
+	memset(&context.unknown1, 0, sizeof(context.unknown1));
+	context.unknown2 = 0xffffffff;
 
 	/* Mind the cast, as in, don't free it after! */
-	header.preview = (char *)preview;
-	header.preview_len = preview_len;
+	context.preview = (char *)preview;
+	context.preview_len = preview_len;
 
-	u8 = msn_file_context_to_wire(&header);
+	u8 = msn_file_context_to_wire(&context);
 	ret = purple_base64_encode((const guchar *)u8, MSN_FILE_CONTEXT_SIZE + preview_len);
 
 	g_free(uni);
--- a/libpurple/protocols/msn/slpcall.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/slpcall.c	Sun Jan 30 17:52:06 2011 +0000
@@ -511,7 +511,7 @@
 		/* File Transfer */
 		PurpleAccount *account;
 		PurpleXfer *xfer;
-		MsnFileContext *header;
+		MsnFileContext *file_context;
 		char *buf;
 		gsize bin_len;
 		guint32 file_size;
@@ -528,12 +528,12 @@
 							 slpcall->slplink->remote_user);
 
 		buf = (char *)purple_base64_decode(context, &bin_len);
-		header = msn_file_context_from_wire(buf, bin_len);
+		file_context = msn_file_context_from_wire(buf, bin_len);
 
-		if (header != NULL) {
-			file_size = header->file_size;
+		if (file_context != NULL) {
+			file_size = file_context->file_size;
 
-			file_name = g_convert((const gchar *)&header->file_name,
+			file_name = g_convert((const gchar *)&file_context->file_name,
 			                      MAX_FILE_NAME_LEN * 2,
 			                      "UTF-8", "UTF-16LE",
 			                      NULL, NULL, NULL);
@@ -554,16 +554,16 @@
 
 			xfer->data = slpcall;
 
-			if (header->preview) {
-				purple_xfer_set_thumbnail(xfer, header->preview,
-				                          header->preview_len,
+			if (file_context->preview) {
+				purple_xfer_set_thumbnail(xfer, file_context->preview,
+				                          file_context->preview_len,
 				    					  "image/png");
-				g_free(header->preview);
+				g_free(file_context->preview);
 			}
 
 			purple_xfer_request(xfer);
 		}
-		g_free(header);
+		g_free(file_context);
 		g_free(buf);
 
 		accepted = TRUE;
@@ -1059,16 +1059,21 @@
 	MsnSlpCall *slpcall;
 	const guchar *body;
 	gsize body_len;
+	guint32 session_id;
+	guint32 flags;
 
 	slpcall = NULL;
 	body = slpmsg->buffer;
-	body_len = slpmsg->header->offset;
+	body_len = msn_p2p_info_get_offset(slpmsg->p2p_info);
 
-	if (slpmsg->header->flags == P2P_NO_FLAG || slpmsg->header->flags == P2P_WLM2009_COMP)
+	session_id = msn_p2p_info_get_session_id(slpmsg->p2p_info);
+	flags = msn_p2p_info_get_flags(slpmsg->p2p_info);
+
+	if (flags == P2P_NO_FLAG || flags == P2P_WLM2009_COMP)
 	{
 		char *body_str;
 
-		if (slpmsg->header->session_id == 64)
+		if (session_id == 64)
 		{
 			/* This is for handwritten messages (Ink) */
 			GError *error = NULL;
@@ -1125,9 +1130,9 @@
 		}
 		g_free(body_str);
 	}
-	 else if (msn_p2p_msg_is_data(slpmsg->header->flags))
+	 else if (msn_p2p_msg_is_data(flags))
 	{
-		slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->header->session_id);
+		slpcall = msn_slplink_find_slp_call_with_session_id(slplink, session_id);
 
 		if (slpcall != NULL)
 		{
@@ -1142,22 +1147,13 @@
 			slpcall->wasted = TRUE;
 		}
 	}
-#if 0
-	else if (slpmsg->header->flags == 0x100)
-	{
-		slpcall = slplink->directconn->initial_call;
-
-		if (slpcall != NULL)
-			msn_slpcall_session_init(slpcall);
-	}
-#endif
-	else if (slpmsg->header->flags == P2P_ACK)
+	else if (flags == P2P_ACK)
 	{
 		/* Acknowledgement of previous message. Don't do anything currently. */
 	}
 	else
 		purple_debug_warning("msn", "Unprocessed SLP message with flags 0x%04x\n",
-		                     slpmsg->header->flags);
+		                     flags);
 
 	return slpcall;
 }
--- a/libpurple/protocols/msn/slplink.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/slplink.c	Sun Jan 30 17:52:06 2011 +0000
@@ -281,17 +281,21 @@
 msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
 {
 	MsnSlpMessagePart *part;
+	MsnP2PInfo *info;
 	long long real_size;
 	size_t len = 0;
+	guint64 offset;
 
 	/* Maybe we will want to create a new msg for this slpmsg instead of
 	 * reusing the same one all the time. */
-	part = msn_slpmsgpart_new(slpmsg->header, slpmsg->footer);
+	info = slpmsg->p2p_info;
+	part = msn_slpmsgpart_new(info);
 	part->ack_data = slpmsg;
 
-	real_size = (slpmsg->header->flags == P2P_ACK) ? 0 : slpmsg->size;
+	real_size = (msn_p2p_info_get_flags(info) == P2P_ACK) ? 0 : slpmsg->size;
 
-	if (slpmsg->header->offset < real_size)
+	offset = msn_p2p_info_get_offset(info);
+	if (offset < real_size)
 	{
 		if (slpmsg->slpcall && slpmsg->slpcall->xfer && purple_xfer_get_type(slpmsg->slpcall->xfer) == PURPLE_XFER_SEND &&
 				purple_xfer_get_status(slpmsg->slpcall->xfer) == PURPLE_XFER_STATUS_STARTED)
@@ -301,15 +305,15 @@
 		}
 		else
 		{
-			len = slpmsg->size - slpmsg->header->offset;
+			len = slpmsg->size - offset;
 
 			if (len > MSN_SBCONN_MAX_SIZE)
 				len = MSN_SBCONN_MAX_SIZE;
 
-			msn_slpmsgpart_set_bin_data(part, slpmsg->buffer + slpmsg->header->offset, len);
+			msn_slpmsgpart_set_bin_data(part, slpmsg->buffer + offset, len);
 		}
 
-		slpmsg->header->length = len;
+		msn_p2p_info_set_length(slpmsg->p2p_info, len);
 	}
 
 #if 0
@@ -326,7 +330,7 @@
 	msn_slplink_send_part(slplink, part);
 
 
-	if (msn_p2p_msg_is_data(slpmsg->header->flags) &&
+	if (msn_p2p_msg_is_data(msn_p2p_info_get_flags(info)) &&
 		(slpmsg->slpcall != NULL))
 	{
 		slpmsg->slpcall->progress = TRUE;
@@ -334,7 +338,7 @@
 		if (slpmsg->slpcall->progress_cb != NULL)
 		{
 			slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size,
-										 len, slpmsg->header->offset);
+										 len, offset);
 		}
 	}
 
@@ -344,27 +348,30 @@
 static void
 msn_slplink_release_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
 {
-	slpmsg = slpmsg;
-	slpmsg->footer = g_new0(MsnP2PFooter, 1);
+	MsnP2PInfo *info;
+	guint32 flags;
+
+	info = slpmsg->p2p_info;
 
-	if (slpmsg->header->flags == P2P_NO_FLAG)
+	flags = msn_p2p_info_get_flags(info);
+	if (flags == P2P_NO_FLAG)
 	{
-		slpmsg->header->ack_id = rand() % 0xFFFFFF00;
+		msn_p2p_info_set_ack_id(info, rand() % 0xFFFFFF00);
 	}
-	else if (msn_p2p_msg_is_data(slpmsg->header->flags))
+	else if (msn_p2p_msg_is_data(flags))
 	{
 		MsnSlpCall *slpcall;
 		slpcall = slpmsg->slpcall;
 
 		g_return_if_fail(slpcall != NULL);
-		slpmsg->header->session_id = slpcall->session_id;
-		slpmsg->footer->value = slpcall->app_id;
-		slpmsg->header->ack_id = rand() % 0xFFFFFF00;
+		msn_p2p_info_set_session_id(info, slpcall->session_id);
+		msn_p2p_info_set_app_id(info, slpcall->app_id);
+		msn_p2p_info_set_ack_id(info, rand() % 0xFFFFFF00);
 	}
 
-	slpmsg->header->id = slpmsg->id;
+	msn_p2p_info_set_id(info, slpmsg->id);
 
-	slpmsg->header->total_size = slpmsg->size;
+	msn_p2p_info_set_total_size(info, slpmsg->size);
 
 	msn_slplink_send_msgpart(slplink, slpmsg);
 }
@@ -400,20 +407,20 @@
 }
 
 static MsnSlpMessage *
-msn_slplink_create_ack(MsnSlpLink *slplink, MsnP2PHeader *header)
+msn_slplink_create_ack(MsnSlpLink *slplink, MsnP2PInfo *info)
 {
 	MsnSlpMessage *slpmsg;
 
-	slpmsg = msn_slpmsg_ack_new(header);
+	slpmsg = msn_slpmsg_ack_new(info);
 	msn_slpmsg_set_slplink(slpmsg, slplink);
 
 	return slpmsg;
 }
 
 static void
-msn_slplink_send_ack(MsnSlpLink *slplink, MsnP2PHeader *header)
+msn_slplink_send_ack(MsnSlpLink *slplink, MsnP2PInfo *info)
 {
-	MsnSlpMessage *slpmsg = msn_slplink_create_ack(slplink, header);
+	MsnSlpMessage *slpmsg = msn_slplink_create_ack(slplink, info);
 
 	msn_slplink_send_slpmsg(slplink, slpmsg);
 	msn_slpmsg_destroy(slpmsg);
@@ -428,7 +435,7 @@
 	{
 		MsnSlpMessage *slpmsg = e->data;
 
-		if ((slpmsg->header->session_id == session_id) && (slpmsg->id == id))
+		if ((msn_p2p_info_get_session_id(slpmsg->p2p_info) == session_id) && (slpmsg->id == id))
 			return slpmsg;
 	}
 
@@ -436,22 +443,26 @@
 }
 
 static MsnSlpMessage *
-init_first_msg(MsnSlpLink *slplink, MsnP2PHeader *header)
+init_first_msg(MsnSlpLink *slplink, MsnP2PInfo *info)
 {
 	MsnSlpMessage *slpmsg;
+	guint32 session_id;
+	guint32 flags;
 
 	slpmsg = msn_slpmsg_new(slplink);
-	slpmsg->id = header->id;
-	slpmsg->header->session_id = header->session_id;
-	slpmsg->size = header->total_size;
-	slpmsg->header->flags = header->flags;
+	slpmsg->id = msn_p2p_info_get_id(info);
+	session_id = msn_p2p_info_get_session_id(info);
+	msn_p2p_info_set_session_id(slpmsg->p2p_info, session_id);
+	slpmsg->size = msn_p2p_info_get_total_size(info);
+	flags = msn_p2p_info_get_flags(info);
+	msn_p2p_info_set_flags(slpmsg->p2p_info, flags);
 
-	if (slpmsg->header->session_id)
+	if (session_id)
 	{
-		slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->header->session_id);
+		slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, session_id);
 		if (slpmsg->slpcall != NULL)
 		{
-			if (msn_p2p_msg_is_data(header->flags))
+			if (msn_p2p_msg_is_data(flags))
 			{
 				PurpleXfer *xfer = slpmsg->slpcall->xfer;
 				if (xfer != NULL)
@@ -488,9 +499,10 @@
 }
 
 static void
-process_complete_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg, MsnP2PHeader *header)
+process_complete_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg, MsnP2PInfo *info)
 {
 	MsnSlpCall *slpcall;
+	guint32 flags;
 
 	slpcall = msn_slp_process_msg(slplink, slpmsg);
 
@@ -501,8 +513,10 @@
 
 	purple_debug_info("msn", "msn_slplink_process_msg: slpmsg complete\n");
 
-	if (slpmsg->header->flags == P2P_NO_FLAG || slpmsg->header->flags == P2P_WLM2009_COMP ||
-			msn_p2p_msg_is_data(slpmsg->header->flags))
+	flags = msn_p2p_info_get_flags(slpmsg->p2p_info);
+
+	if (flags == P2P_NO_FLAG || flags == P2P_WLM2009_COMP ||
+	    msn_p2p_msg_is_data(flags))
 	{
 		/* Release all the messages and send the ACK */
 
@@ -515,11 +529,11 @@
 			 */
 			purple_debug_info("msn", "msn_slplink_process_msg: save ACK\n");
 
-			slpcall->slplink->dc->prev_ack = msn_slplink_create_ack(slplink, header);
+			slpcall->slplink->dc->prev_ack = msn_slplink_create_ack(slplink, info);
 		} else if (!slpcall->wasted) {
 			purple_debug_info("msn", "msn_slplink_process_msg: send ACK\n");
 
-			msn_slplink_send_ack(slplink, header);
+			msn_slplink_send_ack(slplink, info);
 			msn_slplink_send_queued_slpmsgs(slplink);
 		}
 	}
@@ -539,16 +553,17 @@
 		purple_xfer_prpl_ready(slpmsg->slpcall->xfer);
 	}
 	else if (slpmsg->size && slpmsg->buffer) {
-		if (G_MAXSIZE - part->size < part->header->offset
-				|| (part->header->offset + part->size) > slpmsg->size
-				|| slpmsg->header->offset != part->header->offset) {
+		guint64 offset = msn_p2p_info_get_offset(part->info);
+		if (G_MAXSIZE - part->size < offset
+				|| (offset + part->size) > slpmsg->size
+				|| msn_p2p_info_get_offset(slpmsg->p2p_info) != offset) {
 			purple_debug_error("msn",
 				"Oversized slpmsg - msgsize=%lld offset=%" G_GUINT64_FORMAT " len=%" G_GSIZE_FORMAT "\n",
-				slpmsg->size, part->header->offset, part->size);
+				slpmsg->size, offset, part->size);
 			g_return_if_reached();
 		} else {
-			memcpy(slpmsg->buffer + part->header->offset, part->buffer, part->size);
-			slpmsg->header->offset += part->size;
+			memcpy(slpmsg->buffer + offset, part->buffer, part->size);
+			msn_p2p_info_set_offset(slpmsg->p2p_info, offset + part->size);
 		}
 	}
 }
@@ -557,12 +572,12 @@
 msn_slplink_process_msg(MsnSlpLink *slplink, MsnSlpMessagePart *part)
 {
 	MsnSlpMessage *slpmsg;
-	MsnP2PHeader *header;
+	MsnP2PInfo *info;
 	guint64 offset;
 
-	header = part->header;
+	info = part->info;
 
-	if (header->total_size < header->length)
+	if (!msn_p2p_info_is_valid(info))
 	{
 		/* We seem to have received a bad header */
 		purple_debug_warning("msn", "Total size listed in SLP binary header "
@@ -571,12 +586,15 @@
 		return;
 	}
 
-	offset = header->offset;
+	offset = msn_p2p_info_get_offset(info);
 
 	if (offset == 0)
-		slpmsg = init_first_msg(slplink, header);
+		slpmsg = init_first_msg(slplink, info);
 	else {
-		slpmsg = msn_slplink_message_find(slplink, header->session_id, header->id);
+		guint32 session_id, id;
+		session_id = msn_p2p_info_get_session_id(info);
+		id = msn_p2p_info_get_id(info);
+		slpmsg = msn_slplink_message_find(slplink, session_id, id);
 		if (slpmsg == NULL)
 		{
 			/* Probably the transfer was cancelled */
@@ -587,8 +605,7 @@
 
 	slpmsg_add_part(slpmsg, part);
 
-
-	if (msn_p2p_msg_is_data(slpmsg->header->flags) &&
+	if (msn_p2p_msg_is_data(msn_p2p_info_get_flags(slpmsg->p2p_info)) &&
 		(slpmsg->slpcall != NULL))
 	{
 		slpmsg->slpcall->progress = TRUE;
@@ -606,8 +623,8 @@
 #endif
 
 	/* All the pieces of the slpmsg have been received */
-	if (header->offset + header->length >= header->total_size)
-		process_complete_msg(slplink, slpmsg, header);
+	if (msn_p2p_info_is_final(info))
+		process_complete_msg(slplink, slpmsg, info);
 
 	/* NOTE: The slpmsg will be destroyed in process_complete_msg or left in
 	   the slplink until fully received. Don't free it here!
--- a/libpurple/protocols/msn/slpmsg.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/slpmsg.c	Sun Jan 30 17:52:06 2011 +0000
@@ -48,8 +48,7 @@
 	else
 		slpmsg->slplink = NULL;
 
-	slpmsg->header = g_new0(MsnP2PHeader, 1);
-	slpmsg->footer = NULL;
+	slpmsg->p2p_info = msn_p2p_info_new();
 
 	return slpmsg;
 }
@@ -90,8 +89,7 @@
 
 	slplink->slp_msgs = g_list_remove(slplink->slp_msgs, slpmsg);
 
-	g_free(slpmsg->header);
-	g_free(slpmsg->footer);
+	msn_p2p_info_free(slpmsg->p2p_info);
 
 	g_free(slpmsg);
 }
@@ -193,7 +191,6 @@
 	slpmsg = msn_slpmsg_new(slplink);
 	msn_slpmsg_set_body(slpmsg, body, body_len);
 
-	slpmsg->sip = TRUE;
 	slpmsg->slpcall = slpcall;
 
 	g_free(body);
@@ -201,18 +198,20 @@
 	return slpmsg;
 }
 
-MsnSlpMessage *msn_slpmsg_ack_new(MsnP2PHeader *header)
+MsnSlpMessage *msn_slpmsg_ack_new(MsnP2PInfo *ack_info)
 {
 	MsnSlpMessage *slpmsg;
+	MsnP2PInfo *new_info;
 
 	slpmsg = msn_slpmsg_new(NULL);
 
-	slpmsg->header->session_id = header->session_id;
-	slpmsg->size       = header->total_size;
-	slpmsg->header->flags      = P2P_ACK;
-	slpmsg->header->ack_id     = header->id;
-	slpmsg->header->ack_sub_id = header->ack_id;
-	slpmsg->header->ack_size   = header->total_size;
+	new_info = slpmsg->p2p_info;
+	msn_p2p_info_set_session_id(new_info, msn_p2p_info_get_session_id(ack_info));
+	slpmsg->size = msn_p2p_info_get_total_size(ack_info);
+	msn_p2p_info_set_flags(new_info, P2P_ACK);
+	msn_p2p_info_set_ack_id(new_info, msn_p2p_info_get_id(ack_info));
+	msn_p2p_info_set_ack_sub_id(new_info, msn_p2p_info_get_ack_id(ack_info));
+	msn_p2p_info_set_ack_size(new_info, msn_p2p_info_get_total_size(ack_info));
 	slpmsg->info = "SLP ACK";
 
 	return slpmsg;
@@ -224,7 +223,7 @@
 
 	slpmsg = msn_slpmsg_new(NULL);
 	slpmsg->slpcall = slpcall;
-	slpmsg->header->flags = P2P_MSN_OBJ_DATA;
+	msn_p2p_info_set_flags(slpmsg->p2p_info, P2P_MSN_OBJ_DATA);
 	slpmsg->info = "SLP DATA";
 
 	msn_slpmsg_set_image(slpmsg, img);
@@ -239,7 +238,7 @@
 	slpmsg = msn_slpmsg_new(NULL);
 
 	slpmsg->slpcall = slpcall;
-	slpmsg->header->session_id = slpcall->session_id;
+	msn_p2p_info_set_session_id(slpmsg->p2p_info, slpcall->session_id);
 	msn_slpmsg_set_body(slpmsg, NULL, 4);
 	slpmsg->info = "SLP DATA PREP";
 
@@ -254,7 +253,7 @@
 	slpmsg = msn_slpmsg_new(NULL);
 
 	slpmsg->slpcall = slpcall;
-	slpmsg->header->flags = P2P_FILE_DATA;
+	msn_p2p_info_set_flags(slpmsg->p2p_info, P2P_FILE_DATA);
 	slpmsg->info = "SLP FILE";
 	slpmsg->size = size;
 
@@ -267,27 +266,25 @@
 	char *footer;
 	char *base;
 	char *tmp;
-	size_t siz;
+	size_t header_size, footer_size;
 
-	base = g_malloc(P2P_PACKET_HEADER_SIZE + slpmsg->size + P2P_PACKET_FOOTER_SIZE);
+	header = msn_p2p_header_to_wire(slpmsg->p2p_info, &header_size);
+	footer = msn_p2p_footer_to_wire(slpmsg->p2p_info, &footer_size);
+
+	base = g_malloc(header_size + slpmsg->size + footer_size);
 	tmp = base;
 
-	header = msn_p2p_header_to_wire(slpmsg->header);
-	footer = msn_p2p_footer_to_wire(slpmsg->footer);
-
-	siz = P2P_PACKET_HEADER_SIZE;
 	/* Copy header */
-	memcpy(tmp, header, siz);
-	tmp += siz;
+	memcpy(tmp, header, header_size);
+	tmp += header_size;
 
 	/* Copy body */
 	memcpy(tmp, slpmsg->buffer, slpmsg->size);
 	tmp += slpmsg->size;
 
 	/* Copy footer */
-	siz = P2P_PACKET_FOOTER_SIZE;
-	memcpy(tmp, footer, siz);
-	tmp += siz;
+	memcpy(tmp, footer, footer_size);
+	tmp += footer_size;
 
 	*ret_size = tmp - base;
 
@@ -303,15 +300,7 @@
 
 	str = g_string_new(NULL);
 
-	g_string_append_printf(str, "Session ID: %u\r\n", slpmsg->header->session_id);
-	g_string_append_printf(str, "ID:         %u\r\n", slpmsg->header->id);
-	g_string_append_printf(str, "Offset:     %" G_GUINT64_FORMAT "\r\n", slpmsg->header->offset);
-	g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", slpmsg->header->total_size);
-	g_string_append_printf(str, "Length:     %u\r\n", slpmsg->header->length);
-	g_string_append_printf(str, "Flags:      0x%x\r\n", slpmsg->header->flags);
-	g_string_append_printf(str, "ACK ID:     %u\r\n", slpmsg->header->ack_id);
-	g_string_append_printf(str, "SUB ID:     %u\r\n", slpmsg->header->ack_sub_id);
-	g_string_append_printf(str, "ACK Size:   %" G_GUINT64_FORMAT "\r\n", slpmsg->header->ack_size);
+	msn_p2p_info_to_string(slpmsg->p2p_info, str);
 
 	if (purple_debug_is_verbose() && slpmsg->buffer != NULL) {
 		g_string_append_len(str, (gchar*)slpmsg->buffer, slpmsg->size);
@@ -324,7 +313,5 @@
 
 	}
 
-	g_string_append_printf(str, "Footer:     %u\r\n", slpmsg->footer->value);
-
 	purple_debug_info("msn", "SlpMessage %s:\n{%s}\n", slpmsg->info, str->str);
 }
--- a/libpurple/protocols/msn/slpmsg.h	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/slpmsg.h	Sun Jan 30 17:52:06 2011 +0000
@@ -45,13 +45,10 @@
 	MsnSlpLink *slplink; /**< The slplink through which this slp message is being sent. */
 	MsnSession *session;
 
-	MsnP2PHeader *header;
-	MsnP2PFooter *footer;
+	MsnP2PInfo *p2p_info;
 
 	long id;
 
-	gboolean sip; /**< A flag that states if this is a SIP slp message. */
-
 	gboolean ft;
 	PurpleStoredImage *img;
 	guchar *buffer;
@@ -94,8 +91,6 @@
 void msn_slpmsg_set_body(MsnSlpMessage *slpmsg, const char *body,
 						 long long size);
 void msn_slpmsg_set_image(MsnSlpMessage *slpmsg, PurpleStoredImage *img);
-void msn_slpmsg_open_file(MsnSlpMessage *slpmsg,
-						  const char *file_name);
 MsnSlpMessage * msn_slpmsg_sip_new(MsnSlpCall *slpcall, int cseq,
 								   const char *header,
 								   const char *branch,
@@ -109,7 +104,7 @@
  *
  * @return A new SlpMessage with ACK headers
  */
-MsnSlpMessage *msn_slpmsg_ack_new(MsnP2PHeader *header);
+MsnSlpMessage *msn_slpmsg_ack_new(MsnP2PInfo *info);
 
 /**
  * Create a new SLP message for MsnObject data.
--- a/libpurple/protocols/msn/slpmsg_part.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/slpmsg_part.c	Sun Jan 30 17:52:06 2011 +0000
@@ -28,16 +28,14 @@
 #include "slpmsg.h"
 #include "slpmsg_part.h"
 
-MsnSlpMessagePart *msn_slpmsgpart_new(MsnP2PHeader *header, MsnP2PFooter *footer)
+MsnSlpMessagePart *msn_slpmsgpart_new(MsnP2PInfo *info)
 {
 	MsnSlpMessagePart *part;
 
 	part = g_new0(MsnSlpMessagePart, 1);
 
-	if (header)
-		part->header = g_memdup(header, P2P_PACKET_HEADER_SIZE);
-	if (footer)
-		part->footer = g_memdup(footer, P2P_PACKET_FOOTER_SIZE);
+	if (info)
+		part->info = msn_p2p_info_dup(info);
 
 	part->ack_cb = msn_slpmsgpart_ack;
 	part->nak_cb = msn_slpmsgpart_nak;
@@ -48,20 +46,22 @@
 MsnSlpMessagePart *msn_slpmsgpart_new_from_data(const char *data, size_t data_len)
 {
 	MsnSlpMessagePart *part;
+	size_t len;
 	int body_len;
 
 	if (data_len < P2P_PACKET_HEADER_SIZE) {
 		return NULL;
 	}
 
-	part = msn_slpmsgpart_new(NULL, NULL);
+	part = msn_slpmsgpart_new(NULL);
+	part->info = msn_p2p_info_new();
 
 	/* Extract the binary SLP header */
-	part->header = msn_p2p_header_from_wire(data);
-	data += P2P_PACKET_HEADER_SIZE;
+	len = msn_p2p_header_from_wire(part->info, data);
+	data += len;
 
 	/* Extract the body */
-	body_len = data_len - P2P_PACKET_HEADER_SIZE - P2P_PACKET_FOOTER_SIZE;
+	body_len = data_len - len - P2P_PACKET_FOOTER_SIZE;
 	/* msg->body_len = msg->msnslp_header.length; */
 
 	if (body_len > 0) {
@@ -73,15 +73,14 @@
 
 	/* Extract the footer */
 	if (body_len >= 0)
-		part->footer = msn_p2p_footer_from_wire(data);
+		msn_p2p_footer_from_wire(part->info, data);
 
 	return part;
 }
 
 static void msn_slpmsgpart_destroy(MsnSlpMessagePart *part)
 {
-	g_free(part->header);
-	g_free(part->footer);
+	g_free(part->info);
 	g_free(part->buffer);
 
 	g_free(part);
@@ -138,27 +137,25 @@
 	char *footer;
 	char *base;
 	char *tmp;
-	size_t siz;
+	size_t header_size, footer_size;
 
-	base = g_malloc(P2P_PACKET_HEADER_SIZE + part->size + P2P_PACKET_FOOTER_SIZE);
+	header = msn_p2p_header_to_wire(part->info, &header_size);
+	footer = msn_p2p_footer_to_wire(part->info, &footer_size);
+
+	base = g_malloc(header_size + part->size + footer_size);
 	tmp = base;
 
-	header = msn_p2p_header_to_wire(part->header);
-	footer = msn_p2p_footer_to_wire(part->footer);
-
-	siz = P2P_PACKET_HEADER_SIZE;
 	/* Copy header */
-	memcpy(tmp, header, siz);
-	tmp += siz;
+	memcpy(tmp, header, header_size);
+	tmp += header_size;
 
 	/* Copy body */
 	memcpy(tmp, part->buffer, part->size);
 	tmp += part->size;
 
 	/* Copy footer */
-	siz = P2P_PACKET_FOOTER_SIZE;
-	memcpy(tmp, footer, siz);
-	tmp += siz;
+	memcpy(tmp, footer, footer_size);
+	tmp += footer_size;
 
 	*ret_size = tmp - base;
 
@@ -167,23 +164,27 @@
 
 	return base;
 }
+
 /* We have received the message ack */
 void
 msn_slpmsgpart_ack(MsnSlpMessagePart *part, void *data)
 {
 	MsnSlpMessage *slpmsg;
+	guint64 offset;
 	long long real_size;
 
 	slpmsg = data;
 
-	real_size = (slpmsg->header->flags == P2P_ACK) ? 0 : slpmsg->size;
+	real_size = (msn_p2p_info_get_flags(slpmsg->p2p_info) == P2P_ACK) ? 0 : slpmsg->size;
 
-	slpmsg->header->offset += part->header->length;
+	offset = msn_p2p_info_get_offset(slpmsg->p2p_info);
+	offset += msn_p2p_info_get_length(part->info);
+	msn_p2p_info_set_offset(slpmsg->p2p_info, offset);
 
 	slpmsg->parts = g_list_remove(slpmsg->parts, part);
 	msn_slpmsgpart_unref(part);
 
-	if (slpmsg->header->offset < real_size)
+	if (offset < real_size)
 	{
 		if (slpmsg->slpcall->xfer && purple_xfer_get_status(slpmsg->slpcall->xfer) == PURPLE_XFER_STATUS_STARTED)
 		{
@@ -196,7 +197,7 @@
 	else
 	{
 		/* The whole message has been sent */
-		if (msn_p2p_msg_is_data(slpmsg->header->flags))
+		if (msn_p2p_msg_is_data(msn_p2p_info_get_flags(slpmsg->p2p_info)))
 		{
 			if (slpmsg->slpcall != NULL)
 			{
@@ -222,3 +223,9 @@
 	msn_slpmsgpart_unref(part);
 }
 
+void
+msn_slpmsgpart_to_string(MsnSlpMessagePart *part, GString *str)
+{
+	msn_p2p_info_to_string(part->info, str);
+}
+
--- a/libpurple/protocols/msn/slpmsg_part.h	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/slpmsg_part.h	Sun Jan 30 17:52:06 2011 +0000
@@ -34,8 +34,7 @@
 {
 	guint ref_count;
 
-	MsnP2PHeader *header;
-	MsnP2PFooter *footer;
+	MsnP2PInfo *info;
 
 	MsnSlpPartCb ack_cb;
 	MsnSlpPartCb nak_cb;
@@ -45,7 +44,7 @@
 	size_t size;
 };
 
-MsnSlpMessagePart *msn_slpmsgpart_new(MsnP2PHeader *header, MsnP2PFooter *footer);
+MsnSlpMessagePart *msn_slpmsgpart_new(MsnP2PInfo *info);
 
 MsnSlpMessagePart *msn_slpmsgpart_new_from_data(const char *data, size_t data_len);
 
@@ -60,4 +59,8 @@
 void msn_slpmsgpart_ack(MsnSlpMessagePart *part, void *data);
 
 void msn_slpmsgpart_nak(MsnSlpMessagePart *part, void *data);
+
+void msn_slpmsgpart_to_string(MsnSlpMessagePart *part, GString *str);
+
 #endif /* MSN_SLPMSG_PART_H */
+
--- a/libpurple/protocols/msn/xfer.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/xfer.c	Sun Jan 30 17:52:06 2011 +0000
@@ -162,25 +162,25 @@
 }
 
 gchar *
-msn_file_context_to_wire(MsnFileContext *header)
+msn_file_context_to_wire(MsnFileContext *context)
 {
 	gchar *ret, *tmp;
 
-	tmp = ret = g_new(gchar, MSN_FILE_CONTEXT_SIZE + header->preview_len + 1);
+	tmp = ret = g_new(gchar, MSN_FILE_CONTEXT_SIZE + context->preview_len + 1);
 
-	msn_push32le(tmp, header->length);
-	msn_push32le(tmp, header->version);
-	msn_push64le(tmp, header->file_size);
-	msn_push32le(tmp, header->type);
-	memcpy(tmp, header->file_name, MAX_FILE_NAME_LEN * 2);
+	msn_push32le(tmp, context->length);
+	msn_push32le(tmp, context->version);
+	msn_push64le(tmp, context->file_size);
+	msn_push32le(tmp, context->type);
+	memcpy(tmp, context->file_name, MAX_FILE_NAME_LEN * 2);
 	tmp += MAX_FILE_NAME_LEN * 2;
-	memcpy(tmp, header->unknown1, sizeof(header->unknown1));
-	tmp += sizeof(header->unknown1);
-	msn_push32le(tmp, header->unknown2);
-	if (header->preview) {
-		memcpy(tmp, header->preview, header->preview_len);
+	memcpy(tmp, context->unknown1, sizeof(context->unknown1));
+	tmp += sizeof(context->unknown1);
+	msn_push32le(tmp, context->unknown2);
+	if (context->preview) {
+		memcpy(tmp, context->preview, context->preview_len);
 	}
-	tmp[header->preview_len] = '\0';
+	tmp[context->preview_len] = '\0';
 
 	return ret;
 }
@@ -188,48 +188,48 @@
 MsnFileContext *
 msn_file_context_from_wire(const char *buf, gsize len)
 {
-	MsnFileContext *header;
+	MsnFileContext *context;
 
 	if (!buf || len < MSN_FILE_CONTEXT_SIZE)
 		return NULL;
 
-	header = g_new(MsnFileContext, 1);
+	context = g_new(MsnFileContext, 1);
 
-	header->length = msn_pop32le(buf);
-	header->version = msn_pop32le(buf);
-	if (header->version == 2) {
+	context->length = msn_pop32le(buf);
+	context->version = msn_pop32le(buf);
+	if (context->version == 2) {
 		/* The length field is broken for this version. No check. */
-		header->length = MSN_FILE_CONTEXT_SIZE;
-	} else if (header->version == 3) {
-		if (header->length != MSN_FILE_CONTEXT_SIZE + 63) {
-			g_free(header);
+		context->length = MSN_FILE_CONTEXT_SIZE;
+	} else if (context->version == 3) {
+		if (context->length != MSN_FILE_CONTEXT_SIZE + 63) {
+			g_free(context);
 			return NULL;
 		} else if (len < MSN_FILE_CONTEXT_SIZE + 63) {
-			g_free(header);
+			g_free(context);
 			return NULL;
 		}
 	} else {
-		purple_debug_warning("msn", "Received MsnFileContext with unknown version: %d\n", header->version);
-		g_free(header);
+		purple_debug_warning("msn", "Received MsnFileContext with unknown version: %d\n", context->version);
+		g_free(context);
 		return NULL;
 	}
 
-	header->file_size = msn_pop64le(buf);
-	header->type = msn_pop32le(buf);
-	memcpy(header->file_name, buf, MAX_FILE_NAME_LEN * 2);
+	context->file_size = msn_pop64le(buf);
+	context->type = msn_pop32le(buf);
+	memcpy(context->file_name, buf, MAX_FILE_NAME_LEN * 2);
 	buf += MAX_FILE_NAME_LEN * 2;
-	memcpy(header->unknown1, buf, sizeof(header->unknown1));
-	buf += sizeof(header->unknown1);
-	header->unknown2 = msn_pop32le(buf);
+	memcpy(context->unknown1, buf, sizeof(context->unknown1));
+	buf += sizeof(context->unknown1);
+	context->unknown2 = msn_pop32le(buf);
 
-	if (header->type == 0 && len > header->length) {
-		header->preview_len = len - header->length;
-		header->preview = g_memdup(buf, header->preview_len);
+	if (context->type == 0 && len > context->length) {
+		context->preview_len = len - context->length;
+		context->preview = g_memdup(buf, context->preview_len);
 	} else {
-		header->preview_len = 0;
-		header->preview = NULL;
+		context->preview_len = 0;
+		context->preview = NULL;
 	}
 
-	return header;
+	return context;
 }
 
--- a/libpurple/protocols/msn/xfer.h	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/msn/xfer.h	Sun Jan 30 17:52:06 2011 +0000
@@ -22,6 +22,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
+#ifndef MSN_XFER_H
+#define MSN_XFER_H
 
 #include "slpcall.h"
 
@@ -56,8 +58,10 @@
 void msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session);
 
 gchar *
-msn_file_context_to_wire(MsnFileContext *header);
+msn_file_context_to_wire(MsnFileContext *context);
 
 MsnFileContext *
 msn_file_context_from_wire(const char *buf, gsize len);
 
+#endif /* MSN_XFER_H */
+
--- a/libpurple/protocols/novell/novell.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/novell/novell.c	Sun Jan 30 17:52:06 2011 +0000
@@ -74,7 +74,7 @@
 _sync_privacy_lists(NMUser *user);
 
 static void
-_show_info(PurpleConnection * gc, NMUserRecord * user_record);
+_show_info(PurpleConnection * gc, NMUserRecord * user_record, char * name);
 
 const char *
 _get_conference_name(int id);
@@ -705,7 +705,7 @@
 		user_record = (NMUserRecord *) resp_data;
 		if (user_record) {
 			_show_info(purple_account_get_connection(user->client_data),
-					   user_record);
+					   user_record, g_strdup(name));
 		}
 	} else {
 		gc = purple_account_get_connection(user->client_data);
@@ -1505,7 +1505,7 @@
 
 /* Display a dialog box showing the properties for the given user record */
 static void
-_show_info(PurpleConnection * gc, NMUserRecord * user_record)
+_show_info(PurpleConnection * gc, NMUserRecord * user_record, char * name)
 {
 	PurpleNotifyUserInfo *user_info =	purple_notify_user_info_new();
 	int count, i;
@@ -1544,9 +1544,10 @@
 		}
 	}
 
-	purple_notify_userinfo(gc, nm_user_record_get_userid(user_record),
-						 user_info, NULL, NULL);
+	purple_notify_userinfo(gc, name, user_info, NULL, NULL);
 	purple_notify_user_info_destroy(user_info);
+
+	g_free(name);
 }
 
 /* Send a join conference, the first item in the parms list is the
@@ -2912,11 +2913,9 @@
 
 		user_record = nm_find_user_record(user, name);
 		if (user_record) {
-
-			_show_info(gc, user_record);
+			_show_info(gc, user_record, g_strdup(name));
 
 		} else {
-
 			rc = nm_send_get_details(user, name,
 									 _get_details_resp_show_info, g_strdup(name));
 
--- a/libpurple/protocols/oscar/family_feedbag.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c	Sun Jan 30 17:52:06 2011 +0000
@@ -44,10 +44,66 @@
  */
 
 #include "oscar.h"
+#include "debug.h"
 
 static int aim_ssi_addmoddel(OscarData *od);
 
 /**
+ * List types based on http://dev.aol.com/aim/oscar/#FEEDBAG (archive.org)
+ * and http://iserverd.khstu.ru/oscar/ssi_item.html
+ *
+ * @param type The type of a list item as integer number, as provided by an aim_ssi_item struct.
+ * @return Returns the name of the item type as a character string.
+ */
+static const gchar*
+aim_ssi_type_to_string(guint16 type)
+{
+	struct TypeStringPair
+	{
+		guint16 type;
+		const gchar *string;
+	};
+	static const struct TypeStringPair type_strings[] = {
+		{ 0x0000, "Buddy" },
+		{ 0x0001, "Group" },
+		{ 0x0002, "Permit/Visible" },
+		{ 0x0003, "Deny/Invisible" },
+		{ 0x0004, "PDInfo" },
+		{ 0x0005, "PresencePrefs" }, 
+		{ 0x0006, "Non-Buddy Info" },
+		{ 0x0009, "ClientPrefs" },
+		{ 0x000e, "ICQDeny/Ignore" },
+		{ 0x0014, "Buddy Icon" }, 
+		{ 0x0015, "Recent Buddies" },
+		{ 0x0019, "Non-Buddy" },
+		{ 0x001d, "Vanity Info" },
+		{ 0x0020, "ICQ-MDir" },
+		{ 0x0029, "Facebook" },
+	};
+	int i;
+	for (i = 0; i < G_N_ELEMENTS(type_strings); i++) {
+		if (type_strings[i].type == type) {
+			return type_strings[i].string;
+		}
+	}
+	return "unknown";
+}
+
+/** For debug log output: Appends a line containing information about a given list item to a string.
+ *
+ * @param str String to which the line will be appended.
+ * @param prefix A string which will be prepended to the line.
+ * @param item List item from which information is extracted.
+ */
+static void
+aim_ssi_item_debug_append(GString *str, char *prefix, struct aim_ssi_item *item)
+{
+	g_string_append_printf(str, 
+		"%s gid=0x%04hx, bid=0x%04hx, list_type=0x%04hx [%s], name=%s.\n",
+		prefix, item->gid, item->bid, item->type, aim_ssi_type_to_string(item->type), item->name);
+}
+
+/**
  * Locally rebuild the 0x00c8 TLV in the additional data of the given group.
  *
  * @param list A pointer to a pointer to the current list of items.
@@ -478,6 +534,7 @@
 	struct aim_ssi_item *cur1, *cur2;
 	struct aim_ssi_tmp *cur, *new;
 	int n = 0;
+	GString *debugstr = g_string_new("");
 
 	/*
 	 * The variable "n" is used to limit the number of addmoddel's that
@@ -517,6 +574,7 @@
 					cur->next = new;
 				} else
 					od->ssi.pending = new;
+			       	aim_ssi_item_debug_append(debugstr, "Deleting item ", cur1);
 			}
 		}
 	}
@@ -537,6 +595,7 @@
 					cur->next = new;
 				} else
 					od->ssi.pending = new;
+			       	aim_ssi_item_debug_append(debugstr, "Adding item ", cur1);
 			}
 		}
 	}
@@ -558,9 +617,21 @@
 					cur->next = new;
 				} else
 					od->ssi.pending = new;
+			       	aim_ssi_item_debug_append(debugstr, "Modifying item ", cur1);
 			}
 		}
 	}
+	if (debugstr->len > 0) {
+		purple_debug_info("oscar", "%s", debugstr->str);
+		if (purple_debug_is_verbose()) {
+	    		g_string_truncate(debugstr, 0);
+			for (cur1 = od->ssi.local; cur1; cur1 = cur1->next) 
+				aim_ssi_item_debug_append(debugstr, "\t", cur1);
+			purple_debug_misc("oscar", "Dumping item list of account %s:\n%s",
+				purple_connection_get_account(od->gc)->username, debugstr->str);
+		}
+	}
+	g_string_free(debugstr, TRUE);
 
 	/* We're out of stuff to do, so tell the AIM servers we're done and exit */
 	if (!od->ssi.pending) {
@@ -1165,6 +1236,7 @@
 	guint16 namelen, gid, bid, type;
 	char *name;
 	GSList *data;
+	GString *debugstr = g_string_new("");
 
 	fmtver = byte_stream_get8(bs); /* Version of ssi data.  Should be 0x00 */
 	od->ssi.numitems += byte_stream_get16(bs); /* # of items in this SSI SNAC */
@@ -1179,10 +1251,13 @@
 		bid = byte_stream_get16(bs);
 		type = byte_stream_get16(bs);
 		data = aim_tlvlist_readlen(bs, byte_stream_get16(bs));
-		aim_ssi_itemlist_add(&od->ssi.official, name, gid, bid, type, data);
+		aim_ssi_item_debug_append(debugstr, "\t", aim_ssi_itemlist_add(&od->ssi.official, name, gid, bid, type, data));
 		g_free(name);
 		aim_tlvlist_free(data);
 	}
+	purple_debug_misc("oscar", "Reading items from tlvlist for account %s:\n%s",
+		purple_connection_get_account(od->gc)->username, debugstr->str);
+	g_string_free(debugstr, TRUE);
 
 	/* Read in the timestamp */
 	od->ssi.timestamp = byte_stream_get32(bs);
--- a/libpurple/protocols/zephyr/Zinternal.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/zephyr/Zinternal.c	Sun Jan 30 17:52:06 2011 +0000
@@ -30,7 +30,6 @@
 #else
 #include <arpa/inet.h>
 #include <sys/socket.h>
-#include <utmp.h>
 #endif
 
 int __Zephyr_fd = -1;
--- a/libpurple/protocols/zephyr/zephyr.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Sun Jan 30 17:52:06 2011 +0000
@@ -870,12 +870,12 @@
 			zephyr_triple *zt1, *zt2;
 			gchar *send_inst_utf8;
 			zephyr_account *zephyr = gc->proto_data;
-			zt1 = new_triple(gc->proto_data,notice.z_class, notice.z_class_inst, notice.z_recipient);
-			zt2 = find_sub_by_triple(gc->proto_data,zt1);
+			zt1 = new_triple(zephyr,notice.z_class, notice.z_class_inst, notice.z_recipient);
+			zt2 = find_sub_by_triple(zephyr,zt1);
 			if (!zt2) {
 				/* This is a server supplied subscription */
 				zephyr->subscrips = g_slist_append(zephyr->subscrips, new_triple(zephyr,zt1->class,zt1->instance,zt1->recipient));
-				zt2 = find_sub_by_triple(gc->proto_data,zt1);
+				zt2 = find_sub_by_triple(zephyr,zt1);
 			}
 
 			if (!zt2->open) {
@@ -1499,6 +1499,7 @@
 
 static void process_anyone(PurpleConnection *gc)
 {
+	zephyr_account *zephyr = purple_connection_get_protocol_data(gc);
 	FILE *fd;
 	gchar buff[BUFSIZ], *filename;
 	PurpleGroup *g;
@@ -1515,7 +1516,7 @@
 			strip_comments(buff);
 			if (buff[0]) {
 				if (!(b = purple_find_buddy(gc->account, buff))) {
-					char *stripped_user = zephyr_strip_local_realm(gc->proto_data,buff);
+					char *stripped_user = zephyr_strip_local_realm(zephyr,buff);
 					purple_debug_info("zephyr","stripped_user %s\n",stripped_user);
 					if (!(b = purple_find_buddy(gc->account,stripped_user))){
 						b = purple_buddy_new(gc->account, stripped_user, NULL);
@@ -1924,13 +1925,12 @@
 	fclose(fd);
 }
 
-static void write_anyone(PurpleConnection *gc)
+static void write_anyone(zephyr_account *zephyr)
 {
 	GSList *buddies;
 	char *fname;
 	FILE *fd;
 	PurpleAccount *account;
-	zephyr_account* zephyr = gc->proto_data;
 	fname = g_strdup_printf("%s/.anyone", purple_home_dir());
 	fd = g_fopen(fname, "w");
 	if (!fd) {
@@ -1938,7 +1938,7 @@
 		return;
 	}
 
-	account = purple_connection_get_account(gc);
+	account = zephyr->account;
 	for (buddies = purple_find_buddies(account, NULL); buddies;
 			buddies = g_slist_delete_link(buddies, buddies)) {
 		PurpleBuddy *b = buddies->data;
@@ -1966,10 +1966,10 @@
 	g_list_free(zephyr->pending_zloc_names);
 
 	if (purple_account_get_bool(gc->account, "write_anyone", FALSE))
-		write_anyone(gc);
+		write_anyone(zephyr);
 
 	if (purple_account_get_bool(gc->account, "write_zsubs", FALSE))
-		write_zsubs(gc->proto_data);
+		write_zsubs(zephyr);
 
 	s = zephyr->subscrips;
 	while (s) {
@@ -2032,7 +2032,7 @@
 	char *recipient;
 	zephyr_account *zephyr = gc->proto_data;
 
-	zt = find_sub_by_id(gc->proto_data,id);
+	zt = find_sub_by_id(zephyr,id);
 	if (!zt)
 		/* this should never happen. */
 		return -EINVAL;
@@ -2432,8 +2432,8 @@
 	if (!g_ascii_strcasecmp(recip, "%me%"))
 		recip = zephyr->username;
 
-	zt1 = new_triple(gc->proto_data,classname, instname, recip);
-	zt2 = find_sub_by_triple(gc->proto_data,zt1);
+	zt1 = new_triple(zephyr,classname, instname, recip);
+	zt2 = find_sub_by_triple(zephyr,zt1);
 	if (zt2) {
 		free_triple(zt1);
 		if (!zt2->open) {
@@ -2563,7 +2563,7 @@
 	zephyr_account* zephyr = gc->proto_data;
 	char *sender = (char *)zephyr->username;
 
-	zt = find_sub_by_id(gc->proto_data,id);
+	zt = find_sub_by_id(zephyr,id);
 	/* find_sub_by_id can return NULL */
 	if (!zt)
 		return;
--- a/libpurple/util.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/libpurple/util.c	Sun Jan 30 17:52:06 2011 +0000
@@ -664,159 +664,192 @@
 	return mktime(&tm);
 }
 
+/* originally taken from GLib trunk 1-6-11 */
+/* originally licensed as LGPL 2+ */
+static time_t
+mktime_utc(struct tm *tm)
+{
+	time_t retval;
+
+#ifndef HAVE_TIMEGM
+	static const gint days_before[] =
+	{
+		0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+	};
+#endif
+
+#ifndef HAVE_TIMEGM
+	if (tm->tm_mon < 0 || tm->tm_mon > 11)
+		return (time_t) -1;
+
+	retval = (tm->tm_year - 70) * 365;
+	retval += (tm->tm_year - 68) / 4;
+	retval += days_before[tm->tm_mon] + tm->tm_mday - 1;
+
+	if (tm->tm_year % 4 == 0 && tm->tm_mon < 2)
+		retval -= 1;
+
+	retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec;
+#else
+	retval = timegm (tm);
+#endif /* !HAVE_TIMEGM */
+
+	return retval;
+}
+
 time_t
 purple_str_to_time(const char *timestamp, gboolean utc,
-                 struct tm *tm, long *tz_off, const char **rest)
+	struct tm *tm, long *tz_off, const char **rest)
 {
-	time_t retval = 0;
-	static struct tm t;
-	const char *c = timestamp;
-	int year = 0;
+	struct tm t;
+	const gchar *str;
+	gint year = 0;
 	long tzoff = PURPLE_NO_TZ_OFF;
-
-	time(&retval);
-	localtime_r(&retval, &t);
+	time_t retval;
+	gboolean mktime_with_utc = TRUE;
 
 	if (rest != NULL)
 		*rest = NULL;
 
+	g_return_val_if_fail(timestamp != NULL, 0);
+
+	str = timestamp;
+
+	/* Strip leading whitespace */
+	while (g_ascii_isspace(*str))
+		str++;
+
+	if (*str == '\0') {
+		if (rest != NULL && *str != '\0')
+			*rest = str;
+
+		return 0;
+	}
+
+	if (!g_ascii_isdigit(*str) && *str != '-' && *str != '+') {
+		if (rest != NULL && *str != '\0')
+			*rest = str;
+
+		return 0;
+	}
+
 	/* 4 digit year */
-	if (sscanf(c, "%04d", &year) && year > 1900)
-	{
-		c += 4;
-		if (*c == '-')
-			c++;
+	if (sscanf(str, "%04d", &year) && year >= 1900) {
+		str += 4;
+
+		if (*str == '-' || *str == '/')
+			str++;
+
 		t.tm_year = year - 1900;
 	}
 
 	/* 2 digit month */
-	if (!sscanf(c, "%02d", &t.tm_mon))
-	{
-		if (rest != NULL && *c != '\0')
-			*rest = c;
+	if (!sscanf(str, "%02d", &t.tm_mon)) {
+		if (rest != NULL && *str != '\0')
+			*rest = str;
+
 		return 0;
 	}
-	c += 2;
-	if (*c == '-' || *c == '/')
-		c++;
+
+	str += 2;
 	t.tm_mon -= 1;
 
+	if (*str == '-' || *str == '/')
+		str++;
+
 	/* 2 digit day */
-	if (!sscanf(c, "%02d", &t.tm_mday))
-	{
-		if (rest != NULL && *c != '\0')
-			*rest = c;
+	if (!sscanf(str, "%02d", &t.tm_mday)) {
+		if (rest != NULL && *str != '\0')
+			*rest = str;
+
 		return 0;
 	}
-	c += 2;
-	if (*c == '/')
-	{
-		c++;
-
-		if (!sscanf(c, "%04d", &t.tm_year))
-		{
-			if (rest != NULL && *c != '\0')
-				*rest = c;
+
+	str += 2;
+
+	/* Grab the year off the end if there's still stuff */
+	if (*str == '/' || *str == '-') {
+		/* But make sure we don't read the year twice */
+		if (year >= 1900) {
+			if (rest != NULL && *str != '\0')
+				*rest = str;
+
+			return 0;
+		}
+
+		str++;
+
+		if (!sscanf(str, "%04d", &t.tm_year)) {
+			if (rest != NULL && *str != '\0')
+				*rest = str;
+
 			return 0;
 		}
+
 		t.tm_year -= 1900;
-	}
-	else if (*c == 'T' || *c == '.')
-	{
-		c++;
-		/* we have more than a date, keep going */
-
-		/* 2 digit hour */
-		if ((sscanf(c, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && (c = c + 8)) ||
-		    (sscanf(c, "%02d%02d%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && (c = c + 6)))
+	} else if (*str == 'T' || *str == '.') {
+		str++;
+
+		/* Continue grabbing the hours/minutes/seconds */
+		if ((sscanf(str, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 &&
+				(str += 8)) ||
+		    (sscanf(str, "%02d%02d%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 &&
+				(str += 6)))
 		{
-			gboolean offset_positive = FALSE;
-			int tzhrs;
-			int tzmins;
-
-			t.tm_isdst = -1;
-
-			if (*c == '.') {
+			gint sign, tzhrs, tzmins;
+
+			if (*str == '.') {
+				/* Cut off those pesky micro-seconds */
 				do {
-					c++;
-				} while (*c >= '0' && *c <= '9'); /* dealing with precision we don't care about */
-			}
-			if (*c == '+')
-				offset_positive = TRUE;
-			if (((*c == '+' || *c == '-') && (c = c + 1)) &&
-			    ((sscanf(c, "%02d:%02d", &tzhrs, &tzmins) == 2 && (c = c + 5)) ||
-			     (sscanf(c, "%02d%02d", &tzhrs, &tzmins) == 2 && (c = c + 4))))
-			{
-				tzoff = tzhrs*60*60 + tzmins*60;
-				if (offset_positive)
-					tzoff *= -1;
-			}
-			else if ((*c == 'Z') && (c = c + 1))
-			{
-				/* 'Z' = Zulu = UTC */
-				tzoff = 0;
+					str++;
+				} while (*str >= '0' && *str <= '9');
 			}
-			else if (utc)
-			{
-				static struct tm tmptm;
-				time_t tmp;
-				tmp = mktime(&t);
-				/* we care about whether it *was* dst, and the offset, here on this
-				 * date, not whether we are currently observing dst locally *now*.
-				 * This isn't perfect, because we would need to know in advance the
-				 * offset we are trying to work out in advance to be sure this
-				 * works for times around dst transitions but it'll have to do. */
-				localtime_r(&tmp, &tmptm);
-				t.tm_isdst = tmptm.tm_isdst;
-#ifdef HAVE_TM_GMTOFF
-				t.tm_gmtoff = tmptm.tm_gmtoff;
-#endif
-			}
-
-			if (rest != NULL && *c != '\0')
-			{
-				if (*c == ' ')
-					c++;
-				if (*c != '\0')
-					*rest = c;
+
+			sign = (*str == '+') ? -1 : 1;
+
+			/* Process the timezone */
+			if (*str == '+' || *str == '-') {
+				str++;
+
+				if (((sscanf(str, "%02d:%02d", &tzhrs, &tzmins) == 2 && (str += 5)) ||
+					(sscanf(str, "%02d%02d", &tzhrs, &tzmins) == 2 && (str += 4))))
+				{
+					tzoff = tzhrs * 60 * 60 + tzmins * 60;
+					tzoff *= sign;
+				} else {
+					if (rest != NULL && *str != '\0')
+						*rest = str;
+
+					return 0;
+				}
+			} else if (*str == 'Z') {
+				/* 'Z' = Zulu = UTC */
+				str++;
+				utc = TRUE;
+			} else if (!utc) {
+				/* Local Time */
+				t.tm_isdst = -1;
+				mktime_with_utc = FALSE;
 			}
 
-			if (tzoff != PURPLE_NO_TZ_OFF || utc)
-			{
-#if defined(_WIN32)
-				long sys_tzoff;
-#endif
-
-#if defined(_WIN32) || defined(HAVE_TM_GMTOFF) || defined (HAVE_TIMEZONE)
-				if (tzoff == PURPLE_NO_TZ_OFF)
-					tzoff = 0;
-#endif
-
-#ifdef _WIN32
-				if ((sys_tzoff = wpurple_get_tz_offset()) == -1)
-					tzoff = PURPLE_NO_TZ_OFF;
-				else
-					tzoff += sys_tzoff;
-#else
-#ifdef HAVE_TM_GMTOFF
-				tzoff += t.tm_gmtoff;
-#else
-#	ifdef HAVE_TIMEZONE
-				tzset();    /* making sure */
-				tzoff -= timezone;
-#	endif
-#endif
-#endif /* _WIN32 */
-			}
-		}
-		else
-		{
-			if (rest != NULL && *c != '\0')
-				*rest = c;
+			if (utc)
+				tzoff = 0;
 		}
 	}
 
-	retval = mktime(&t);
+	if (rest != NULL && *str != '\0') {
+		/* Strip trailing whitespace */
+		while (g_ascii_isspace(*str))
+			str++;
+
+		if (*str != '\0')
+			*rest = str;
+	}
+
+	if (mktime_with_utc)
+		retval = mktime_utc(&t);
+	else
+		retval = mktime(&t);
 
 	if (tm != NULL)
 		*tm = t;
--- a/pidgin/gtkdialogs.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/pidgin/gtkdialogs.c	Sun Jan 30 17:52:06 2011 +0000
@@ -73,7 +73,7 @@
 static const struct developer developers[] = {
 	{"Daniel 'datallah' Atallah",          NULL,                  NULL},
 	{"Paul 'darkrain42' Aurich",           NULL,                  NULL},
-	{"John 'rekkanoryo' Bailey",           N_("bug master"),      NULL},
+	{"John 'rekkanoryo' Bailey",           NULL,                  NULL},
 	{"Ethan 'Paco-Paco' Blanton",          NULL,                  NULL},
 	{"Hylke Bons",                         N_("artist"),          "hylkebons@gmail.com"},
 	/* feel free to not translate this */
@@ -199,7 +199,7 @@
 	{N_("Kurdish"),             "ku", "Rizoyê Xerzî", "rizoxerzi@hotmail.com"},
 	{N_("Lao"),                 "lo", "Anousak Souphavah", "anousak@gmail.com"},
 	{N_("Maithili"),            "mai", "Sangeeta Kumari", "sangeeta_0975@yahoo.com"},
-	{"Meadow Mari",             "mhr", "David Preece", "davidpreece1@gmail.com"},
+	{N_("Meadow Mari"),         "mhr", "David Preece", "davidpreece1@gmail.com"},
 	{N_("Macedonian"),          "mk", "Arangel Angov ", "arangel@linux.net.mk"},
 	{N_("Macedonian"),          "mk", "Ivana Kirkovska", "ivana.kirkovska@gmail.com"},
 	{N_("Macedonian"),          "mk", "Jovan Naumovski", "jovan@lugola.net"},
--- a/pidgin/gtkutils.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/pidgin/gtkutils.c	Sun Jan 30 17:52:06 2011 +0000
@@ -1458,6 +1458,7 @@
 
 static void dnd_image_ok_callback(_DndData *data, int choice)
 {
+	const gchar *shortname;
 	gchar *filedata;
 	size_t size;
 	struct stat st;
@@ -1512,7 +1513,9 @@
 
 			break;
 		}
-		id = purple_imgstore_add_with_id(filedata, size, data->filename);
+		shortname = strrchr(data->filename, G_DIR_SEPARATOR);
+		shortname = shortname ? shortname + 1 : data->filename;
+		id = purple_imgstore_add_with_id(filedata, size, shortname);
 
 		gtk_text_buffer_get_iter_at_mark(GTK_IMHTML(gtkconv->entry)->text_buffer, &iter,
 						 gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer));
--- a/pidgin/plugins/vvconfig.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/pidgin/plugins/vvconfig.c	Sun Jan 30 17:52:06 2011 +0000
@@ -82,20 +82,11 @@
 	GstPropertyProbe *probe;
 	const GParamSpec *pspec;
 
-	if (!strcmp(element_name, "<custom>")) {
-		ret = g_list_prepend(ret, NULL);
-		ret = g_list_prepend(ret, (gpointer)_("Default"));
-		ret = g_list_prepend(ret, "");
-		return ret;
-	}
-
 	ret = g_list_prepend(ret, (gpointer)_("Default"));
 	ret = g_list_prepend(ret, "");
 
-	if (*element_name == '\0') {
-		ret = g_list_prepend(ret, NULL);
-		ret = g_list_reverse(ret);
-		return ret;
+	if (!strcmp(element_name, "<custom>") || (*element_name == '\0')) {
+		return g_list_reverse(ret);
 	}
 
 	element = gst_element_factory_make(element_name, "test");
@@ -120,9 +111,7 @@
 		array = gst_property_probe_probe_and_get_values (probe, pspec);
 		if (array == NULL) {
 			purple_debug_info("vvconfig", "'%s' has no devices\n", element_name);
-			ret = g_list_prepend(ret, NULL);
-			ret = g_list_reverse(ret);
-			return ret;
+			return g_list_reverse(ret);
 		}
 
 		for (n=0; n < array->n_values; ++n) {
@@ -153,10 +142,7 @@
 	}
 	gst_object_unref(element);
 
-	ret = g_list_prepend(ret, NULL);
-	ret = g_list_reverse(ret);
-
-	return ret;
+	return g_list_reverse(ret);
 }
 
 static GList *
@@ -173,7 +159,6 @@
 			ret = g_list_prepend(ret, (gpointer)plugins[0]);
 		}
 	}
-	ret = g_list_prepend(ret, NULL);
 	ret = g_list_reverse(ret);
 	return ret;
 }
@@ -236,7 +221,8 @@
 	pref = g_strdup(name);
 	strcpy(pref + strlen(pref) - strlen("plugin"), "device");
 	devices = get_element_devices(value);
-	if (g_list_find(devices, purple_prefs_get_string(pref)) == NULL)
+	if (g_list_find_custom(devices, purple_prefs_get_string(pref),
+			(GCompareFunc)strcmp) == NULL)
 		purple_prefs_set_string(pref, g_list_next(devices)->data);
 	widget = pidgin_prefs_dropdown_from_list(parent,
 			label, PURPLE_PREF_STRING,
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Sun Jan 09 04:40:07 2011 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Sun Jan 30 17:52:06 2011 +0000
@@ -530,6 +530,7 @@
     Push "xmpp"
     Call un.UnregisterURIHandler
 
+    Delete "$INSTDIR\ca-certs\AddTrust_External_Root.pem"
     Delete "$INSTDIR\ca-certs\America_Online_Root_Certification_Authority_1.pem"
     Delete "$INSTDIR\ca-certs\AOL_Member_CA.pem"
     Delete "$INSTDIR\ca-certs\CAcert_Class3.pem"
--- a/pidgin/win32/winpidgin.c	Sun Jan 09 04:40:07 2011 +0000
+++ b/pidgin/win32/winpidgin.c	Sun Jan 30 17:52:06 2011 +0000
@@ -632,11 +632,11 @@
 			} else {
 				if (strchr(__argv[i], 'd'))
 					debug = TRUE;
-				else if (strchr(__argv[i], 'h'))
+				if (strchr(__argv[i], 'h'))
 					help = TRUE;
-				else if (strchr(__argv[i], 'v'))
+				if (strchr(__argv[i], 'v'))
 					version = TRUE;
-				else if (strchr(__argv[i], 'm'))
+				if (strchr(__argv[i], 'm'))
 					multiple = TRUE;
 			}
 		}
--- a/po/POTFILES.in	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/POTFILES.in	Sun Jan 30 17:52:06 2011 +0000
@@ -124,8 +124,8 @@
 libpurple/protocols/mxit/filexfer.c
 libpurple/protocols/mxit/http.c
 libpurple/protocols/mxit/login.c
+libpurple/protocols/mxit/multimx.c
 libpurple/protocols/mxit/mxit.c
-libpurple/protocols/mxit/multimx.c
 libpurple/protocols/mxit/profile.c
 libpurple/protocols/mxit/protocol.c
 libpurple/protocols/mxit/roster.c
@@ -148,8 +148,8 @@
 libpurple/protocols/oscar/oft.c
 libpurple/protocols/oscar/oscar.c
 libpurple/protocols/oscar/peer.c
+libpurple/protocols/oscar/userinfo.c
 libpurple/protocols/oscar/util.c
-libpurple/protocols/oscar/userinfo.c
 libpurple/protocols/oscar/visibility.c
 libpurple/protocols/qq/buddy_info.c
 libpurple/protocols/qq/buddy_list.c
--- a/po/ar.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/ar.po	Sun Jan 30 17:52:06 2011 +0000
@@ -747,9 +747,9 @@
 #, c-format
 msgid "File Transfers - %d%% of %d file"
 msgid_plural "File Transfers - %d%% of %d files"
-msgstr[0] "نقل الملفات - %d%% من %0.sصفر ملفات"
-msgstr[1] "نقل الملفات - %d%% من %0.sملف واحد"
-msgstr[2] "نقل الملفات - %d%% من %0.sملفين"
+msgstr[0] "نقل الملفات - %d%% من صفر ملفات"
+msgstr[1] "نقل الملفات - %d%% من ملف واحد"
+msgstr[2] "نقل الملفات - %d%% من ملفين"
 msgstr[3] "نقل الملفات - %d%% من %d ملفات"
 msgstr[4] "نقل الملفات - %d%% من %d ملفا"
 msgstr[5] "نقل الملفات - %d%% من %d ملف"
@@ -921,9 +921,9 @@
 #, c-format
 msgid "%s (%s) has %d new message."
 msgid_plural "%s (%s) has %d new messages."
-msgstr[0] "لا رسائل%0.s جديدة لـ ‏%s (%s)."
-msgstr[1] "‏%s (%s) لديه %0.sرسالة واحدة جديدة"
-msgstr[2] "‏%s (%s) لديه %0.sرسالتان جديدتان."
+msgstr[0] "لا رسائل جديدة لـ ‏%s ‏(%s)."
+msgstr[1] "‏%s (%s) لديه رسالة واحدة جديدة"
+msgstr[2] "‏%s (%s) لديه رسالتان جديدتان."
 msgstr[3] "‏%s (%s) لديه %d رسائل جديدة."
 msgstr[4] "‏%s (%s) لديه %d رسالة جديدة."
 msgstr[5] "‏%s (%s) لديه %d رسالة جديدة."
@@ -11231,9 +11231,9 @@
 #, c-format
 msgid "%s, %d hour"
 msgid_plural "%s, %d hours"
-msgstr[0] "%s، %0.sلا ساعات"
-msgstr[1] "‏%s، %0.sساعة واحدة"
-msgstr[2] "‏%s، %0.sساعتين"
+msgstr[0] "%s، لا ساعات"
+msgstr[1] "‏%s، ساعة واحدة"
+msgstr[2] "‏%s، ساعتين"
 msgstr[3] "‏%s، %d ساعات"
 msgstr[4] "‏%s، %d ساعة"
 msgstr[5] "‏%s، %d ساعة"
@@ -11251,9 +11251,9 @@
 #, c-format
 msgid "%s, %d minute"
 msgid_plural "%s, %d minutes"
-msgstr[0] "‏%s، %0.sلا دقائق"
-msgstr[1] "‏%s، %0.sدقيقة واحدة"
-msgstr[2] "‏%s، %0.sدقيقتين"
+msgstr[0] "‏%s، لا دقائق"
+msgstr[1] "‏%s، دقيقة واحدة"
+msgstr[2] "‏%s، دقيقتين"
 msgstr[3] "%s، %d دقائق"
 msgstr[4] "%s، %d دقيقة"
 msgstr[5] "%s، %d دقيقة"
@@ -11604,13 +11604,12 @@
 msgid "The text information for a buddy's status"
 msgstr "غيّر معلومات المستخدم لأجل %s"
 
-#, c-format
 msgid "You have %d contact named %s. Would you like to merge them?"
 msgid_plural ""
 "You currently have %d contacts named %s. Would you like to merge them?"
-msgstr[0] "لا مراسلين%0.s لديك باسم %s. أتريد دمجهم؟"
-msgstr[1] "لديك مراسل واحد%0.s باسم %s. أتريد دمجه؟"
-msgstr[2] "لديك مراسليْن%0.s باسم %s. أتريد دمجهما؟"
+msgstr[0] "%0.sلا مراسلين لديك باسم %s. أتريد دمجهم؟"
+msgstr[1] "%0.sلديك مراسل واحد باسم %s. أتريد دمجه؟"
+msgstr[2] "%0.sلديك مراسليْن باسم %s. أتريد دمجهما؟"
 msgstr[3] "لديك %d مراسلين باسم %s. أتريد دمجهم؟"
 msgstr[4] "لديك %d مراسلا باسم %s. أتريد دمجهم؟"
 msgstr[5] "لديك %d مراسل باسم %s. أتريد دمجهم؟"
@@ -11948,12 +11947,11 @@
 msgid "/Tools/Room List"
 msgstr "/الأدوات/قائمة الغرف"
 
-#, c-format
 msgid "%d unread message from %s\n"
 msgid_plural "%d unread messages from %s\n"
-msgstr[0] "لا رسائل%0.s غير مقروءة من %s\n"
-msgstr[1] "رسالة واحدة%0.s غير مقروءة من %s\n"
-msgstr[2] "رسالتان%0.s غير مقروءتان من %s\n"
+msgstr[0] "%0.sلا رسائل غير مقروءة من %s\n"
+msgstr[1] "%0.sرسالة واحدة غير مقروءة من %s\n"
+msgstr[2] "%0.sرسالتان غير مقروءتان من %s\n"
 msgstr[3] "%d رسائل غير مقروءة من %s\n"
 msgstr[4] "%d رسالة غير مقروءة من %s\n"
 msgstr[5] "%d رسالة غير مقروءة من %s\n"
@@ -12932,13 +12930,13 @@
 "You are about to remove the contact containing %s and %d other buddies from "
 "your buddy list.  Do you want to continue?"
 msgstr[0] ""
-"أنت بصدد إزالة مراسل يحتوي %s و %0.sلا أصدقاء من قائمة أصدقائك.  هل تريد "
+"أنت بصدد إزالة مراسل يحتوي %s ولا أصدقاء من قائمة أصدقائك.  هل تريد "
 "الاستمرار؟"
 msgstr[1] ""
-"أنت بصدد إزالة مراسل يحتوي %s و %0.sصديق آخر من قائمة أصدقائك.  هل تريد "
+"أنت بصدد إزالة مراسل يحتوي %s وصديق آخر من قائمة أصدقائك.  هل تريد "
 "الاستمرار؟"
 msgstr[2] ""
-"أنت بصدد إزالة مراسل يحتوي %s و %0.sصديقين آخرين من قائمة أصدقائك.  هل تريد "
+"أنت بصدد إزالة مراسل يحتوي %s وصديقين آخرين من قائمة أصدقائك.  هل تريد "
 "الاستمرار؟"
 msgstr[3] ""
 "أنت بصدد إزالة مراسل يحتوي %s و %d أصدقاء آخرين من قائمة أصدقائك.  هل تريد "
@@ -13504,12 +13502,12 @@
 #, c-format
 msgid "%s has %d new message."
 msgid_plural "%s has %d new messages."
-msgstr[0] "لا رسائل%0.s جديدة ل %s."
-msgstr[1] "رسالة%0.s جديدة ل %s."
-msgstr[2] "رسالتان%0.s جديدتان ل %s."
-msgstr[3] "%Id رسائل جديدة ل %s."
-msgstr[4] "%Id رسالة جديدة ل %s."
-msgstr[5] "%Id رسالة جديدة ل %s."
+msgstr[0] "لا رسائل جديدة ل‍ %s."
+msgstr[1] "رسالة جديدة ل‍ %s."
+msgstr[2] "رسالتان جديدتان ل‍ %s."
+msgstr[3] "%2$d رسائل جديدة ل‍ %1$s."
+msgstr[4] "%2$d رسالة جديدة ل‍ %1$s."
+msgstr[5] "%2$d رسالة جديدة ل‍ %1$s."
 
 #, c-format
 msgid "<b>%d new email.</b>"
--- a/po/az.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/az.po	Sun Jan 30 17:52:06 2011 +0000
@@ -15,7 +15,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: KBabel 1.3\n"
 
 #. Translators may want to transliterate the name.
--- a/po/ca.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/ca.po	Sun Jan 30 17:52:06 2011 +0000
@@ -3,7 +3,7 @@
 # Copyright (C) unknown, Robert Millan <zeratul2@wanadoo.es>
 # Copyright (C) December 2003 (from 2003-12-12 until 2003-12-18),
 #               January (2004-01-07,12), Xan <dxpublica@telefonica.net>
-# Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010
+# Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
 #               Josep Puigdemont i Casamajó <josep.puigdemont@gmail.com>
 #
 # This file is distributed under the same license as the Pidgin package.
@@ -33,8 +33,8 @@
 msgstr ""
 "Project-Id-Version: Pidgin\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-12-23 07:57+0100\n"
-"PO-Revision-Date: 2010-12-23 08:04+0100\n"
+"POT-Creation-Date: 2011-01-30 11:04+0100\n"
+"PO-Revision-Date: 2011-01-30 11:11+0100\n"
 "Last-Translator: Josep Puigdemont i Casamajó <josep.puigdemont@gmail.com>\n"
 "Language-Team: Catalan <tradgnome@softcatala.net>\n"
 "Language: ca\n"
@@ -2387,9 +2387,12 @@
 "Camí on desar els fitxers\n"
 "(introduïu tot el camí)"
 
-msgid "Automatically reject from users not in buddy list"
-msgstr ""
-"Rebutja automàticament dels usuaris que no estiguin a la llista d'amics"
+msgid ""
+"When a file-transfer request arrives from a user who is\n"
+"*not* on your buddy list:"
+msgstr ""
+"Quan arribi una sol·licitud de transferència d'un fitxer d'un\n"
+"usuari que *no* és a la vostra llista d'amics:"
 
 msgid ""
 "Notify with a popup when an autoaccepted file transfer is complete\n"
@@ -2402,6 +2405,10 @@
 msgid "Create a new directory for each user"
 msgstr "Crea un directori nou per a cada usuari"
 
+#, fuzzy
+msgid "Escape the filenames"
+msgstr "%s ha cancel·lat la transferència del fitxer"
+
 msgid "Notes"
 msgstr "Notes"
 
@@ -3859,7 +3866,10 @@
 msgid "Server requires plaintext authentication over an unencrypted stream"
 msgstr "El servidor requereix autenticació de text sobre un flux no xifrat"
 
-#. This should never happen!
+#. This happens when the server sends back jibberish
+#. * in the "additional data with success" case.
+#. * Seen with Wildfire 3.0.1.
+#.
 msgid "Invalid response from server"
 msgstr "La resposta del servidor no és vàlida"
 
@@ -6201,6 +6211,20 @@
 msgid "Retrieving User Information..."
 msgstr "S'està obtenint informació de l'usuari..."
 
+#. you were kicked
+msgid "You have been kicked from this MultiMX."
+msgstr "Us han fet fora d'aquest MultiMX."
+
+msgid "was kicked"
+msgstr "ha estat fet fora"
+
+msgid "_Room Name:"
+msgstr "Nom de la _Sala:"
+
+#. Display system message in chat window
+msgid "You have invited"
+msgstr "Heu convidat"
+
 msgid "Loading menu..."
 msgstr "S'està carregant el menú..."
 
@@ -6229,20 +6253,6 @@
 msgid "Enable splash-screen popup"
 msgstr "Habilita la pantalla de presentació emergent"
 
-#. you were kicked
-msgid "You have been kicked from this MultiMX."
-msgstr "Us han fet fora d'aquest MultiMX."
-
-msgid "was kicked"
-msgstr "ha estat fet fora"
-
-msgid "_Room Name:"
-msgstr "Nom de la _Sala:"
-
-#. Display system message in chat window
-msgid "You have invited"
-msgstr "Heu convidat"
-
 msgid "Last Online"
 msgstr "Darrer cop en línia"
 
@@ -7917,75 +7927,6 @@
 "necessari per poder enviar imatges instantànies. Atès que es revelarà la "
 "vostra adreça IP, això es pot considerar un risc de privadesa."
 
-msgid "Invalid SNAC"
-msgstr "SNAC invàlid"
-
-msgid "Server rate limit exceeded"
-msgstr "S'ha excedit el límit de velocitat del servidor"
-
-msgid "Client rate limit exceeded"
-msgstr "S'ha excedit el límit de velocitat del client"
-
-msgid "Service unavailable"
-msgstr "Servei no disponible"
-
-msgid "Service not defined"
-msgstr "Servei no definit"
-
-msgid "Obsolete SNAC"
-msgstr "SNAC obsolet"
-
-msgid "Not supported by host"
-msgstr "El servidor no ho permet"
-
-msgid "Not supported by client"
-msgstr "El client no ho permet"
-
-msgid "Refused by client"
-msgstr "Rebutjat pel client"
-
-msgid "Reply too big"
-msgstr "Resposta massa gran"
-
-msgid "Responses lost"
-msgstr "S'han perdut respostes"
-
-msgid "Request denied"
-msgstr "Petició denegada"
-
-msgid "Busted SNAC payload"
-msgstr "Càrrega SNAC malmesa"
-
-msgid "Insufficient rights"
-msgstr "Drets insuficients"
-
-msgid "In local permit/deny"
-msgstr "En la llista de permès/denegat local"
-
-msgid "Warning level too high (sender)"
-msgstr "Nivell d'avís massa alt (remitent)"
-
-msgid "Warning level too high (receiver)"
-msgstr "Nivell d'avís massa alt (receptor)"
-
-msgid "User temporarily unavailable"
-msgstr "Usuari no disponible temporalment"
-
-msgid "No match"
-msgstr "Cap coincidència"
-
-msgid "List overflow"
-msgstr "Sobreeiximent de la llista"
-
-msgid "Request ambiguous"
-msgstr "Petició ambigua"
-
-msgid "Queue full"
-msgstr "Cua plena"
-
-msgid "Not while on AOL"
-msgstr "No es pot fer mentre estigui a AOL"
-
 #. Label
 msgid "Buddy Icon"
 msgstr "Icona de l'amic"
@@ -8104,6 +8045,75 @@
 msgid "Capabilities"
 msgstr "Capacitats"
 
+msgid "Invalid SNAC"
+msgstr "SNAC invàlid"
+
+msgid "Server rate limit exceeded"
+msgstr "S'ha excedit el límit de velocitat del servidor"
+
+msgid "Client rate limit exceeded"
+msgstr "S'ha excedit el límit de velocitat del client"
+
+msgid "Service unavailable"
+msgstr "Servei no disponible"
+
+msgid "Service not defined"
+msgstr "Servei no definit"
+
+msgid "Obsolete SNAC"
+msgstr "SNAC obsolet"
+
+msgid "Not supported by host"
+msgstr "El servidor no ho permet"
+
+msgid "Not supported by client"
+msgstr "El client no ho permet"
+
+msgid "Refused by client"
+msgstr "Rebutjat pel client"
+
+msgid "Reply too big"
+msgstr "Resposta massa gran"
+
+msgid "Responses lost"
+msgstr "S'han perdut respostes"
+
+msgid "Request denied"
+msgstr "Petició denegada"
+
+msgid "Busted SNAC payload"
+msgstr "Càrrega SNAC malmesa"
+
+msgid "Insufficient rights"
+msgstr "Drets insuficients"
+
+msgid "In local permit/deny"
+msgstr "En la llista de permès/denegat local"
+
+msgid "Warning level too high (sender)"
+msgstr "Nivell d'avís massa alt (remitent)"
+
+msgid "Warning level too high (receiver)"
+msgstr "Nivell d'avís massa alt (receptor)"
+
+msgid "User temporarily unavailable"
+msgstr "Usuari no disponible temporalment"
+
+msgid "No match"
+msgstr "Cap coincidència"
+
+msgid "List overflow"
+msgstr "Sobreeiximent de la llista"
+
+msgid "Request ambiguous"
+msgstr "Petició ambigua"
+
+msgid "Queue full"
+msgstr "Cua plena"
+
+msgid "Not while on AOL"
+msgstr "No es pot fer mentre estigui a AOL"
+
 #. Translators: This string is a menu option that, if selected, will cause
 #. you to appear online to the chosen user even when your status is set to
 #. Invisible.
@@ -8703,14 +8713,14 @@
 msgid "Select Server"
 msgstr "Seleccioneu un servidor"
 
-msgid "QQ2005"
-msgstr "QQ2005"
+msgid "QQ2008"
+msgstr "QQ2008"
 
 msgid "QQ2007"
 msgstr "QQ2007"
 
-msgid "QQ2008"
-msgstr "QQ2008"
+msgid "QQ2005"
+msgstr "QQ2005"
 
 msgid "Connect by TCP"
 msgstr "Connecta amb TCP"
@@ -12284,10 +12294,6 @@
 msgid "Fatal Error"
 msgstr "Error fatal"
 
-# Fixme
-msgid "bug master"
-msgstr "bug master"
-
 msgid "artist"
 msgstr "artista"
 
@@ -12469,6 +12475,9 @@
 msgid "Maithili"
 msgstr "Maithili"
 
+msgid "Meadow Mari"
+msgstr "Txeremís oriental"
+
 msgid "Macedonian"
 msgstr "Macedoni"
 
@@ -15626,6 +15635,14 @@
 msgid "You do not have permission to uninstall this application."
 msgstr "No tens permís per desinstal.lar aquesta aplicació."
 
+#~ msgid "Automatically reject from users not in buddy list"
+#~ msgstr ""
+#~ "Rebutja automàticament dels usuaris que no estiguin a la llista d'amics"
+
+# Fixme
+#~ msgid "bug master"
+#~ msgstr "bug master"
+
 #~ msgid "Error requesting %s"
 #~ msgstr "S'ha produït un error en sol·licitar %s"
 
--- a/po/de.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/de.po	Sun Jan 30 17:52:06 2011 +0000
@@ -2,7 +2,7 @@
 # Pidgin German translation
 # Copyright (C) 2001, Daniel Seifert <Pidgin-translation@dseifert.de>
 # Copyright (C) 2002, Karsten Weiss <knweiss@gmx.de>
-# Copyright (C) 2002-2010, Björn Voigt <bjoern@cs.tu-berlin.de>,
+# Copyright (C) 2002-2011, Björn Voigt <bjoern@cs.tu-berlin.de>,
 #                     Jochen Kemnade <jochenkemnade@web.de>
 #
 # This file is distributed under the same license as the Pidgin package.
@@ -11,9 +11,9 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-12-22 10:12+0100\n"
-"PO-Revision-Date: 2010-12-22 10:21+0100\n"
-"Last-Translator: Björn Voigt <bjoern@cs.tu-berlin.de>\n"
+"POT-Creation-Date: 2011-01-25 20:46+0100\n"
+"PO-Revision-Date: 2011-01-25 20:46+0100\n"
+"Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
 "Language-Team: German <de@li.org>\n"
 "Language: de\n"
 "MIME-Version: 1.0\n"
@@ -401,7 +401,7 @@
 msgstr "Chat betreten"
 
 msgid "Please enter the name of the chat you want to join."
-msgstr "Bitte geben Sie die den Namen des Chats an, den Sie betreten möchten."
+msgstr "Bitte geben Sie den Namen des Chats an, den Sie betreten möchten."
 
 msgid "Join"
 msgstr "Betreten"
@@ -568,7 +568,7 @@
 msgstr "Konten reaktivieren"
 
 msgid "No such command."
-msgstr "Es gibt kein solches Kommando."
+msgstr "Unbekanntes Kommando."
 
 msgid "Syntax Error:  You typed the wrong number of arguments to that command."
 msgstr ""
@@ -581,7 +581,8 @@
 msgstr "Dieses Kommando funktioniert nur in Chats, nicht bei IMs."
 
 msgid "That command only works in IMs, not chats."
-msgstr "Dieses Kommando funktioniert nur bei IMs, nicht bei Chats."
+msgstr ""
+"Dieses Kommando funktioniert nur bei Sofortnachrichten, nicht bei Chats."
 
 msgid "That command doesn't work on this protocol."
 msgstr "Dieses Kommando funktioniert nicht in diesem Protokoll."
@@ -646,7 +647,7 @@
 msgstr "Einladen..."
 
 msgid "Enable Logging"
-msgstr "Mitschnitt einschalten"
+msgstr "Mitschnitt aktivieren"
 
 msgid "Enable Sounds"
 msgstr "Klänge aktivieren"
@@ -801,7 +802,7 @@
 msgstr "Status"
 
 msgid "Close this window when all transfers finish"
-msgstr "Schließe dieses Fenster, wenn alle Übertragungen abgeschlossen sind"
+msgstr "Fenster schließen, wenn alle Übertragungen abgeschlossen sind"
 
 msgid "Clear finished transfers"
 msgstr "Entferne komplette Übertragungen"
@@ -816,7 +817,7 @@
 msgstr "Abgebrochen"
 
 msgid "Failed"
-msgstr "Gescheitert"
+msgstr "Fehlgeschlagen"
 
 #, c-format
 msgid "%.2f KiB/s"
@@ -884,11 +885,11 @@
 
 #, c-format
 msgid "Conversations in %s"
-msgstr "Unterhaltung in %s"
+msgstr "Unterhaltungen in %s"
 
 #, c-format
 msgid "Conversations with %s"
-msgstr "Unterhaltung mit %s"
+msgstr "Unterhaltungen mit %s"
 
 msgid "All Conversations"
 msgstr "Alle Unterhaltungen"
@@ -910,7 +911,7 @@
 msgstr "Ablehnen"
 
 msgid "Call in progress."
-msgstr "Anruf läuft."
+msgstr "Verbindungsaufbau."
 
 msgid "The call has been terminated."
 msgstr "Der Anruf wurde beendet."
@@ -926,7 +927,7 @@
 "starten."
 
 msgid "You have rejected the call."
-msgstr "Sie haben den Anruf abgelehnt."
+msgstr "Sie haben den Anruf abgewiesen."
 
 msgid "call: Make an audio call."
 msgstr "call: Einen Audio-Anruf tätigen."
@@ -1009,7 +1010,7 @@
 msgstr "Keine Einstellungsoptionen für dieses Plugin."
 
 msgid "Error loading plugin"
-msgstr "Beim Laden des Plugins traten Fehler auf"
+msgstr "Beim Laden des Plugins ist ein Fehler aufgetreten"
 
 msgid "The selected file is not a valid plugin."
 msgstr "Die gewählte Datei ist kein gültiges Plugin."
@@ -1021,7 +1022,7 @@
 "genaue Fehlermeldung zu sehen."
 
 msgid "Select plugin to install"
-msgstr "Wählen Sie ein Plugin zum Installieren"
+msgstr "Zu installierendes Plugin auswählen"
 
 msgid "You can (un)load plugins from the following list."
 msgstr "Die können Plugins von der folgenden Liste laden bzw. entladen."
@@ -1064,10 +1065,10 @@
 msgstr "Alarm, wenn Buddy..."
 
 msgid "Signs on"
-msgstr "sich angemeldet"
+msgstr "sich anmeldet"
 
 msgid "Signs off"
-msgstr "sich abgemeldet"
+msgstr "sich abmeldet"
 
 msgid "Goes away"
 msgstr "hinausgeht"
@@ -1085,7 +1086,7 @@
 msgstr "zu tippen beginnt"
 
 msgid "Pauses while typing"
-msgstr "beim Tippen anhält"
+msgstr "das Tippen unterbricht"
 
 msgid "Stops typing"
 msgstr "aufhört zu tippen"
@@ -1119,13 +1120,13 @@
 msgstr "Wiederkehrend"
 
 msgid "Cannot create pounce"
-msgstr "Kann Alarm nicht erzeugen"
+msgstr "Alarm konnte nicht erstellt werden"
 
 msgid "You do not have any accounts."
 msgstr "Sie haben keine Kontos."
 
 msgid "You must create an account first before you can create a pounce."
-msgstr "Sie müssen ein Konto anlegen, bevor Sie einen Alarm erzeugen können."
+msgstr "Sie müssen ein Konto anlegen, bevor Sie einen Alarm einrichten können."
 
 #, c-format
 msgid "Are you sure you want to delete the pounce on %s for %s?"
@@ -1164,7 +1165,7 @@
 
 #, c-format
 msgid "%s has become idle (%s)"
-msgstr "%s wurde untätig (%s)"
+msgstr "%s ist nun untätig (%s)"
 
 #, c-format
 msgid "%s has gone away. (%s)"
@@ -1178,7 +1179,7 @@
 msgstr "Unbekanntes Alarm-Ereignis. Bitte berichten Sie dieses Problem!"
 
 msgid "Based on keyboard use"
-msgstr "Abhängig von Tastaturbenutzung"
+msgstr "Abhängig von der Tastaturbenutzung"
 
 msgid "From last sent message"
 msgstr "Von letzter gesendeter Nachricht"
@@ -1199,7 +1200,7 @@
 msgstr "Mitschnitt-Format"
 
 msgid "Log IMs"
-msgstr "IMs mitschneiden"
+msgstr "Sofortnachrichten mitschneiden"
 
 msgid "Log chats"
 msgstr "Chats mitschneiden"
@@ -1247,7 +1248,7 @@
 msgstr "Drücken Sie 'Enter', um mehr Räume dieser Kategorie zu finden."
 
 msgid "Get"
-msgstr "Holen"
+msgstr "Abrufen"
 
 #. Create the window.
 msgid "Room List"
@@ -1441,7 +1442,7 @@
 msgstr "Statusmeldungen"
 
 msgid "Error loading the plugin."
-msgstr "Beim Laden des Plugins traten Fehler auf."
+msgstr "Beim Laden des Plugins ist ein Fehler aufgetreten."
 
 msgid "Couldn't find X display"
 msgstr "Konnte X-Display nicht finden"
@@ -1519,7 +1520,7 @@
 msgstr "<b>Unterhaltung mit %s am %s:</b><br>"
 
 msgid "History Plugin Requires Logging"
-msgstr "Das Verlaufs-Plugin erfordert das Mitschneiden"
+msgstr "Für das Verlaufs-Plugin muss das Mitschneiden aktiviert sein"
 
 msgid ""
 "Logging can be enabled from Tools -> Preferences -> Logging.\n"
@@ -1543,7 +1544,7 @@
 "When a new conversation is opened this plugin will insert the last "
 "conversation into the current conversation."
 msgstr ""
-"Wenn eine neue Unterhaltung eröffnet wird, fügt dieses Plugin die letzte "
+"Wenn eine neue Unterhaltung begonnen wird, fügt dieses Plugin die letzte "
 "Unterhaltung in die aktuelle Unterhaltung ein."
 
 #, c-format
@@ -1607,7 +1608,7 @@
 msgstr "Verschachtelte Gruppen (experimentell)"
 
 msgid "Provides alternate buddylist grouping options."
-msgstr "Bietet alternative Einstellungen für die Kontaktlisten-Gruppierung."
+msgstr "Bietet alternative Einstellungen für die Gruppierung der Kontaktliste."
 
 msgid "Lastlog"
 msgstr "Verlauf"
@@ -1900,11 +1901,11 @@
 
 #, c-format
 msgid "Failed to get name: %s"
-msgstr "Kann den Namen nicht bekommen: %s"
+msgstr "Name konnte nicht abgerufen werden: %s"
 
 #, c-format
 msgid "Failed to get serv name: %s"
-msgstr "Kann den Serv-Namen nicht bekommen: %s"
+msgstr "Serv-Name konnte nicht abgerufen werden: %s"
 
 msgid "Purple's D-BUS server is not running for the reason listed below"
 msgstr "Purple's D-Bus-Server läuft aus dem folgenden Grund nicht"
@@ -2041,7 +2042,7 @@
 msgstr "Übertragung der Datei %s ist komplett"
 
 msgid "File transfer complete"
-msgstr "Dateiübertragung ist komplett"
+msgstr "Dateiübertragung abgeschlossen"
 
 #, c-format
 msgid "You cancelled the transfer of %s"
@@ -2368,8 +2369,12 @@
 "Pfad in denen die Dateien gespeichert werden sollen\n"
 "(Bitte geben Sie den vollständigen Pfad an)"
 
-msgid "Automatically reject from users not in buddy list"
-msgstr "Automatisch von Benutzern ablehnen, die nicht in der Buddy-Liste sind"
+msgid ""
+"When a file-transfer request arrives from a user who is\n"
+"*not* on your buddy list:"
+msgstr ""
+"Wenn eine Dateitransferanfrage von einem Benutzer ankommt, \n"
+"der *nicht* in Ihrer Buddy-Liste ist:"
 
 msgid ""
 "Notify with a popup when an autoaccepted file transfer is complete\n"
@@ -2382,6 +2387,9 @@
 msgid "Create a new directory for each user"
 msgstr "Für jeden Benutzer ein neues Verzeichnis anlegen"
 
+msgid "Escape the filenames"
+msgstr "Sonderzeichen in Dateinamen ersetzen"
+
 msgid "Notes"
 msgstr "Notizen"
 
@@ -3850,7 +3858,10 @@
 "Der Server erfordert eine Klartext-Authentifizierung über einen "
 "unverschlüsselten Kanal"
 
-#. This should never happen!
+#. This happens when the server sends back jibberish
+#. * in the "additional data with success" case.
+#. * Seen with Wildfire 3.0.1.
+#.
 msgid "Invalid response from server"
 msgstr "Ungültige Serverantwort"
 
@@ -8730,14 +8741,14 @@
 msgid "Select Server"
 msgstr "Server wählen"
 
-msgid "QQ2005"
-msgstr "QQ2005"
+msgid "QQ2008"
+msgstr "QQ2008"
 
 msgid "QQ2007"
 msgstr "QQ2007"
 
-msgid "QQ2008"
-msgstr "QQ2008"
+msgid "QQ2005"
+msgstr "QQ2005"
 
 msgid "Connect by TCP"
 msgstr "Über TCP verbinden"
@@ -12328,9 +12339,6 @@
 msgid "Fatal Error"
 msgstr "Schwerer Fehler"
 
-msgid "bug master"
-msgstr "Bug-Master"
-
 msgid "artist"
 msgstr "Künstler"
 
@@ -12510,6 +12518,9 @@
 msgid "Maithili"
 msgstr "Maithili"
 
+msgid "Meadow Mari"
+msgstr "Wiesen-Mari"
+
 msgid "Macedonian"
 msgstr "Makedonisch"
 
@@ -13448,10 +13459,10 @@
 msgstr "Budd_y-Name:"
 
 msgid "Si_gns on"
-msgstr "si_ch angemeldet"
+msgstr "si_ch anmeldet"
 
 msgid "Signs o_ff"
-msgstr "sich abgemel_det"
+msgstr "sich abmel_det"
 
 msgid "Goes a_way"
 msgstr "hinausgeh_t"
@@ -15662,15 +15673,3 @@
 
 msgid "You do not have permission to uninstall this application."
 msgstr "Sie haben keine Berechtigung, diese Anwendung zu deinstallieren."
-
-#~ msgid "Error requesting %s"
-#~ msgstr "Fehler beim Anfordern von %s"
-
-#~ msgid "An error occurred on the in-band bytestream transfer\n"
-#~ msgstr "Bei der In-Band-Bytestrom-Übertragung trat ein Fehler auf\n"
-
-#~ msgid "Transfer was closed."
-#~ msgstr "Übertragung wurde geschlossen."
-
-#~ msgid "Failed to open in-band bytestream"
-#~ msgstr "Öffnen des In-Band-Bytestroms fehlgeschlagen"
--- a/po/el.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/el.po	Sun Jan 30 17:52:06 2011 +0000
@@ -18,7 +18,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: Plural-Forms:  nplurals=2; plural=(n != 1)\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
 "X-Generator: Lokalize 0.3\n"
 
 #. Translators may want to transliterate the name.
--- a/po/en_AU.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/en_AU.po	Sun Jan 30 17:52:06 2011 +0000
@@ -16,7 +16,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=n>1;\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
--- a/po/en_GB.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/en_GB.po	Sun Jan 30 17:52:06 2011 +0000
@@ -15,7 +15,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=n>1;\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
--- a/po/eu.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/eu.po	Sun Jan 30 17:52:06 2011 +0000
@@ -16,7 +16,7 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "X-Generator: KBabel 1.9.1\n"
-"Plural-Forms: Plural-Forms: Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
--- a/po/gl.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/gl.po	Sun Jan 30 17:52:06 2011 +0000
@@ -18,7 +18,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: KBabel 1.11.4\n"
 
 #. Translators may want to transliterate the name.
--- a/po/hu.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/hu.po	Sun Jan 30 17:52:06 2011 +0000
@@ -1,22 +1,22 @@
 # Hungarian translation of pidgin.
-# Copyright (C) 2003, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+# Copyright (C) 2003, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 # This file is distributed under the same license as the Pidgin package.
 # The Hungarian translation of Pidgin was sponsored by Novell Hungary, many thanks for it!
 #
 # Zoltan Sutto <suttozoltan@chello.hu>, 2003.
-# Gabor Kelemen <kelemeng at gnome dot hu>, 2005, 2006, 2007, 2008, 2009, 2010.
-msgid ""
-msgstr ""
-"Project-Id-Version: pidgin 2.7\n"
+# Gabor Kelemen <kelemeng at gnome dot hu>, 2005, 2006, 2007, 2008, 2009, 2010, 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: pidgin 2.7.10\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-12-21 15:20+0100\n"
-"PO-Revision-Date: 2010-12-21 15:19+0100\n"
+"POT-Creation-Date: 2011-01-25 15:12+0100\n"
+"PO-Revision-Date: 2011-01-25 15:12+0100\n"
 "Last-Translator: Gabor Kelemen <kelemeng at gnome dot hu>\n"
 "Language-Team: Hungarian <gnome at fsf dot hu>\n"
-"Language: \n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"Language: \n"
 "Plural-Forms:  nplurals=2; plural=(n != 1);\n"
 "X-Generator: KBabel 1.11.4\n"
 
@@ -2350,9 +2350,12 @@
 "A fájlok mentési útvonala\n"
 "(Teljes elérési utat adjon meg)"
 
-msgid "Automatically reject from users not in buddy list"
-msgstr ""
-"Automatikus visszautasítás a partnerlistán nem szereplő felhasználóktól"
+msgid ""
+"When a file-transfer request arrives from a user who is\n"
+"*not* on your buddy list:"
+msgstr ""
+"Ha fájlküldési kérés érkezik egy a partnerlistán NEM szereplő\n"
+"felhasználótól:"
 
 msgid ""
 "Notify with a popup when an autoaccepted file transfer is complete\n"
@@ -2365,6 +2368,9 @@
 msgid "Create a new directory for each user"
 msgstr "Új könyvtár létrehozása minden felhasználóhoz"
 
+msgid "Escape the filenames"
+msgstr "Fájlnevek escape-elése."
+
 msgid "Notes"
 msgstr "Megjegyzések"
 
@@ -3828,7 +3834,10 @@
 msgstr ""
 "A kiszolgáló szöveges hitelesítést követel meg egy nem titkosított csatornán"
 
-#. This should never happen!
+#. This happens when the server sends back jibberish
+#. * in the "additional data with success" case.
+#. * Seen with Wildfire 3.0.1.
+#.
 msgid "Invalid response from server"
 msgstr "Érvénytelen válasz a kiszolgálótól"
 
@@ -6757,8 +6766,8 @@
 #, c-format
 msgid "Unable to send message. Could not get details for user (%s)."
 msgstr ""
-"Az üzenetet nem lehet elküldeni. A felhasználó részletei nem kérhetőek le "
-"(%s)."
+"Az üzenetet nem lehet elküldeni. A felhasználó részletei nem kérhetőek le (%"
+"s)."
 
 #, c-format
 msgid "Unable to add %s to your buddy list (%s)."
@@ -7191,8 +7200,8 @@
 "%s tried to send you a %s file, but we only allow files up to %s over Direct "
 "IM.  Try using file transfer instead.\n"
 msgstr ""
-"%s egy %s fájlt próbált küldeni, de közvetlen kapcsolatban legfeljebb csak "
-"%s méretű fájl küldhető. Próbálkozzon inkább a fájlátvitellel.\n"
+"%s egy %s fájlt próbált küldeni, de közvetlen kapcsolatban legfeljebb csak %"
+"s méretű fájl küldhető. Próbálkozzon inkább a fájlátvitellel.\n"
 
 #, c-format
 msgid "File %s is %s, which is larger than the maximum size of %s."
@@ -8628,14 +8637,14 @@
 msgid "Select Server"
 msgstr "Válassza ki a kiszolgálót"
 
-msgid "QQ2005"
-msgstr "QQ2005"
+msgid "QQ2008"
+msgstr "QQ2008"
 
 msgid "QQ2007"
 msgstr "QQ2007"
 
-msgid "QQ2008"
-msgstr "QQ2008"
+msgid "QQ2005"
+msgstr "QQ2005"
 
 msgid "Connect by TCP"
 msgstr "Kapcsolódás TCP segítségével"
@@ -10831,8 +10840,8 @@
 #, c-format
 msgid "Access denied: HTTP proxy server forbids port %d tunneling"
 msgstr ""
-"Hozzáférés megtagadva: a HTTP proxy kiszolgáló tiltja az alagutazást a(z) "
-"%d. porton"
+"Hozzáférés megtagadva: a HTTP proxy kiszolgáló tiltja az alagutazást a(z) %"
+"d. porton"
 
 #, c-format
 msgid "Error resolving %s"
@@ -11080,8 +11089,8 @@
 "An error was encountered reading your %s.  The file has not been loaded, and "
 "the old file has been renamed to %s~."
 msgstr ""
-"Hiba történt a(z) %s olvasásakor. Ez a fájl nem lett betöltve, a régi fájl "
-"%s~ néven lett elmentve."
+"Hiba történt a(z) %s olvasásakor. Ez a fájl nem lett betöltve, a régi fájl %"
+"s~ néven lett elmentve."
 
 msgid ""
 "Chat over IM.  Supports AIM, Google Talk, Jabber/XMPP, MSN, Yahoo and more"
@@ -12207,10 +12216,6 @@
 msgid "Fatal Error"
 msgstr "Végzetes hiba"
 
-# fixme: jobb ötlet?
-msgid "bug master"
-msgstr "hibaritkító"
-
 msgid "artist"
 msgstr "grafikus"
 
@@ -12390,6 +12395,9 @@
 msgid "Maithili"
 msgstr "Maithili"
 
+msgid "Meadow Mari"
+msgstr "Mari"
+
 msgid "Macedonian"
 msgstr "macedón"
 
@@ -12510,8 +12518,8 @@
 "to multiple messaging services at once.  %s is written in C using GTK+.  %s "
 "is released, and may be modified and redistributed,  under the terms of the "
 "GPL version 2 (or later).  A copy of the GPL is distributed with %s.  %s is "
-"copyrighted by its contributors, a list of whom is also distributed with "
-"%s.  There is no warranty for %s.<BR><BR>"
+"copyrighted by its contributors, a list of whom is also distributed with %"
+"s.  There is no warranty for %s.<BR><BR>"
 msgstr ""
 "A %s egy libpurple alapú moduláris üzenetküldő kliens, amely egyszerre több "
 "üzenetküldő szolgáltatáshoz is képes csatlakozni. A %s GTK+ használatával, C "
@@ -13061,16 +13069,16 @@
 
 #, c-format
 msgid ""
-"Are you sure you want to permanently delete the log of the conversation in "
-"%s which started at %s?"
+"Are you sure you want to permanently delete the log of the conversation in %"
+"s which started at %s?"
 msgstr ""
 "Biztos, hogy törölni akarja a(z) %s csatornán folytatott, %s időpontban "
 "kezdődött beszélgetés naplóját?"
 
 #, c-format
 msgid ""
-"Are you sure you want to permanently delete the system log which started at "
-"%s?"
+"Are you sure you want to permanently delete the system log which started at %"
+"s?"
 msgstr ""
 "Biztos, hogy törölni akarja a(z) %s időpontban kezdődött rendszernaplót?"
 
@@ -15421,8 +15429,8 @@
 #, no-c-format
 msgid ""
 "Error Installing Spellchecking ($R3).$\\rIf retrying fails, manual "
-"installation instructions are at: http://developer.pidgin.im/wiki/Installing"
-"%20Pidgin#manual_win32_spellcheck_installation"
+"installation instructions are at: http://developer.pidgin.im/wiki/Installing%"
+"20Pidgin#manual_win32_spellcheck_installation"
 msgstr ""
 "Hiba a helyesírás-ellenőrző telepítésekor. ($R3).$\\rHa az újrapróbálkozás "
 "meghiúsul, akkor saját kezűleg is telepítheti a http://developer.pidgin.im/"
--- a/po/hy.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/hy.po	Sun Jan 30 17:52:06 2011 +0000
@@ -3,7 +3,6 @@
 # This file is distributed under the same license as the PACKAGE package.
 # David Avsharyan <avsharyan@gmail.com>, 2009.
 #
-#, fuzzy
 msgid ""
 msgstr ""
 "Project-Id-Version: am\n"
@@ -16,7 +15,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
--- a/po/mn.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/mn.po	Sun Jan 30 17:52:06 2011 +0000
@@ -15,7 +15,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
 
 #. Translators may want to transliterate the name.
 #. It is not to be translated.
--- a/po/ms_MY.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/ms_MY.po	Sun Jan 30 17:52:06 2011 +0000
@@ -15,7 +15,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: KBabel 1.11.4\n"
 
 #. Translators may want to transliterate the name.
--- a/po/ta.po	Sun Jan 09 04:40:07 2011 +0000
+++ b/po/ta.po	Sun Jan 30 17:52:06 2011 +0000
@@ -19,7 +19,7 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Poedit-Country: INDIA\n"
 "X-Generator: Lokalize 1.0\n"
 "X-Poedit-Bookmarks: -1,470,-1,-1,-1,-1,-1,-1,-1,1715\n"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/ca-certs/AddTrust_External_Root.pem	Sun Jan 30 17:52:06 2011 +0000
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
--- a/share/ca-certs/Makefile.am	Sun Jan 09 04:40:07 2011 +0000
+++ b/share/ca-certs/Makefile.am	Sun Jan 30 17:52:06 2011 +0000
@@ -1,4 +1,5 @@
 CERTIFICATES = \
+		AddTrust_External_Root.pem \
 		America_Online_Root_Certification_Authority_1.pem \
 		CAcert_Root.pem \
 		CAcert_Class3.pem \