changeset 27892:d477b5b53660

propagate from branch 'im.pidgin.pidgin' (head a77a8a85e623af608434736b9e63cc17507ec60c) to branch 'im.pidgin.pidgin.yaz' (head b6620638db9843c51a3140a4bc83482b0a69bd11)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Sat, 27 Sep 2008 13:28:07 +0000
parents 43164dadf922 (diff) b041a72f8878 (current diff)
children 43b19e3dbda7
files libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/message.c libpurple/protocols/yahoo/yahoo.c libpurple/protocols/yahoo/yahoo.h libpurple/protocols/yahoo/yahoo_packet.h libpurple/protocols/yahoo/yahoochat.c pidgin/gtkimhtml.c
diffstat 27 files changed, 1440 insertions(+), 210 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Mon Sep 22 06:17:11 2008 +0000
+++ b/COPYRIGHT	Sat Sep 27 13:28:07 2008 +0000
@@ -425,6 +425,7 @@
 Gal Topper
 Chris Toshok
 Ken Tossell
+Marcus Trautwig
 Tom Tromey
 Todd Troxell
 Brad Turcotte
--- a/ChangeLog	Mon Sep 22 06:17:11 2008 +0000
+++ b/ChangeLog	Sat Sep 27 13:28:07 2008 +0000
@@ -5,6 +5,8 @@
 	* Restored the "Has You" feature to the MSN protocol tooltips.
 	* Fixed a crash on removing a custom buddy icon on a buddy.
 	* Fixed a crash caused by certain self-signed SSL certificates.
+	* Enable a number of strong ciphers which were previously disabled
+	  when using NSS.  (Thanks to Marcus Trautwig.)
 
 	Pidgin:
 	* The status selector now saves your message when changing status.
@@ -13,6 +15,8 @@
 	  help with discoverability.  CTRL+S is no longer bound to mute.
 	* Added ability to change the color of visited links (using the theme
 	  control plugin, or setting the color in ~/.gtkrc-2.0)
+	* Fix a crash occuring when a custom smiley is deleted and re-added and
+	  used in an open conversation after being re-added
 
 	Finch:
 	* A new 'Nested Grouping' option in the 'Grouping' plugin. Group
@@ -20,6 +24,14 @@
 	* A bug was fixed where some key-bindings wouldn't work with some TERMs
 	  (e.g. xterm-color, screen-linux etc.)
 
+	XMPP:
+	* Sending and receiving custom smileys using the specification in
+	  XEP-0231 (bits of binary) and XHTML-IM
+
+	Yahoo:
+	* Only send a Ping once every hour.  This prevents the account from
+	  being disconnected from the server periodically.
+
 version 2.5.1 (08/30/2008):
 	libpurple:
 	* In the Join/Part plugin, add the ability to apply the rules to
--- a/libpurple/dnsquery.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/dnsquery.c	Sat Sep 27 13:28:07 2008 +0000
@@ -461,8 +461,8 @@
 		return FALSE;
 	}
 	if (rc < sizeof(dns_params)) {
-		purple_debug_error("dns", "Tried to read %" G_GSSIZE_FORMAT
-				" bytes from child but only read %" G_GSSIZE_FORMAT "\n",
+		purple_debug_error("dns", "Tried to write %" G_GSSIZE_FORMAT
+				" bytes to child but only wrote %" G_GSSIZE_FORMAT "\n",
 				sizeof(dns_params), rc);
 		purple_dnsquery_resolver_destroy(resolver);
 		return FALSE;
--- a/libpurple/plugins/ssl/ssl-nss.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/plugins/ssl/ssl-nss.c	Sat Sep 27 13:28:07 2008 +0000
@@ -141,6 +141,19 @@
 	g_free(lib);
 	NSS_SetDomesticPolicy();
 
+	SSL_CipherPrefSetDefault(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(TLS_DHE_DSS_WITH_AES_256_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(TLS_RSA_WITH_AES_256_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(TLS_DHE_DSS_WITH_RC4_128_SHA, 1);
+	SSL_CipherPrefSetDefault(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(TLS_DHE_DSS_WITH_AES_128_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(SSL_RSA_WITH_RC4_128_SHA, 1);
+	SSL_CipherPrefSetDefault(TLS_RSA_WITH_AES_128_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(SSL_DHE_RSA_WITH_DES_CBC_SHA, 1);
+	SSL_CipherPrefSetDefault(SSL_DHE_DSS_WITH_DES_CBC_SHA, 1);
+
 	_identity = PR_GetUniqueIdentity("Purple");
 	_nss_methods = PR_GetDefaultIOMethods();
 }
--- a/libpurple/protocols/jabber/Makefile.am	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/Makefile.am	Sat Sep 27 13:28:07 2008 +0000
@@ -11,6 +11,8 @@
 			  buddy.h \
 			  chat.c \
 			  chat.h \
+			  data.c \
+			  data.h \
 			  disco.c \
 			  disco.h \
 			  google.c \
--- a/libpurple/protocols/jabber/Makefile.mingw	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/Makefile.mingw	Sat Sep 27 13:28:07 2008 +0000
@@ -48,6 +48,7 @@
 			buddy.c \
 			caps.c \
 			chat.c \
+			data.c \
 			disco.c \
 			google.c \
 			iq.c \
--- a/libpurple/protocols/jabber/buddy.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Sat Sep 27 13:28:07 2008 +0000
@@ -2498,5 +2498,38 @@
 			js);
 }
 
+gboolean
+jabber_resource_has_capability(const JabberBuddyResource *jbr, const gchar *cap)
+{
+	const GList *iter = NULL;
 
+	if (!jbr->caps) {
+		purple_debug_error("jabber",
+			"Unable to find caps: nothing known about buddy\n");
+		return FALSE;
+	}
 
+	for (iter = jbr->caps->features ; iter ; iter = g_list_next(iter)) {
+		purple_debug_info("jabber", "Found cap: %s\n", (char *)iter->data);
+		if (strcmp(iter->data, cap) == 0) {
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+gboolean
+jabber_buddy_has_capability(const JabberBuddy *jb, const gchar *cap)
+{
+	JabberBuddyResource *jbr = jabber_buddy_find_resource((JabberBuddy*)jb, NULL);
+
+	if (!jbr) {
+		purple_debug_error("jabber",
+			"Unable to find caps: buddy might be offline\n");
+		return FALSE;
+	}
+
+	return jabber_resource_has_capability(jbr, cap);
+}
+
--- a/libpurple/protocols/jabber/buddy.h	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/buddy.h	Sat Sep 27 13:28:07 2008 +0000
@@ -117,4 +117,8 @@
 
 void jabber_vcard_fetch_mine(JabberStream *js);
 
+gboolean jabber_resource_has_capability(const JabberBuddyResource *jbr,
+										const gchar *cap);
+gboolean jabber_buddy_has_capability(const JabberBuddy *jb, const gchar *cap);
+
 #endif /* _PURPLE_JABBER_BUDDY_H_ */
--- a/libpurple/protocols/jabber/chat.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/chat.c	Sat Sep 27 13:28:07 2008 +0000
@@ -31,6 +31,7 @@
 #include "message.h"
 #include "presence.h"
 #include "xdata.h"
+#include "data.h"
 
 GList *jabber_chat_info(PurpleConnection *gc)
 {
@@ -684,6 +685,7 @@
 		xmlnode_insert_data(status, msg, -1);
 	}
 	jabber_send(chat->js, presence);
+	
 	xmlnode_free(presence);
 	g_free(room_jid);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/data.c	Sat Sep 27 13:28:07 2008 +0000
@@ -0,0 +1,247 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+
+#include "internal.h"
+#include "data.h"
+#include "debug.h"
+#include "xmlnode.h"
+#include "util.h"
+#include "iq.h"
+
+static GHashTable *local_data_by_alt = NULL;
+static GHashTable *local_data_by_cid = NULL;
+static GHashTable *remote_data_by_cid = NULL;
+
+JabberData *
+jabber_data_create_from_data(gconstpointer rawdata, gsize size, const char *type,
+	JabberStream *js)
+{
+	JabberData *data = g_new0(JabberData, 1);
+	gchar *checksum = purple_util_get_image_checksum(rawdata, size);
+	gchar cid[256];
+
+	g_snprintf(cid, sizeof(cid), "sha1+%s@bob.xmpp.org", checksum);
+	g_free(checksum);
+
+	data->cid = g_strdup(cid);
+	data->type = g_strdup(type);
+	data->size = size;
+
+	data->data = g_memdup(rawdata, size);
+
+	return data;
+}
+
+JabberData *
+jabber_data_create_from_xml(xmlnode *tag)
+{
+	JabberData *data = g_new0(JabberData, 1);
+	gsize size;
+	gpointer raw_data = NULL;
+
+	if (data == NULL) {
+		purple_debug_error("jabber", "Could not allocate data object\n");
+		g_free(data);
+		return NULL;
+	}
+
+	/* check if this is a "data" tag */
+	if (strcmp(tag->name, "data") != 0) {
+		purple_debug_error("jabber", "Invalid data element");
+		g_free(data);
+		return NULL;
+	}
+
+	data->cid = g_strdup(xmlnode_get_attrib(tag, "cid"));
+	data->type = g_strdup(xmlnode_get_attrib(tag, "type"));
+	
+	raw_data = xmlnode_get_data(tag);
+	data->data = purple_base64_decode(raw_data, &size);
+	data->size = size;
+
+	g_free(raw_data);
+
+	return data;
+}
+
+
+static void
+jabber_data_delete(gpointer cbdata)
+{
+	JabberData *data = cbdata;
+	g_free(data->cid);
+	g_free(data->type);
+	g_free(data->data);
+	g_free(data);
+}
+
+const char *
+jabber_data_get_cid(const JabberData *data)
+{
+	return data->cid;
+}
+
+
+const char *
+jabber_data_get_type(const JabberData *data)
+{
+	return data->type;
+}
+
+gsize
+jabber_data_get_size(const JabberData *data)
+{
+	return data->size;
+}
+
+gpointer
+jabber_data_get_data(const JabberData *data)
+{
+	return data->data;
+}
+
+xmlnode *
+jabber_data_get_xml_definition(const JabberData *data)
+{
+	xmlnode *tag = xmlnode_new("data");
+	char *base64data = purple_base64_encode(data->data, data->size);
+
+	xmlnode_set_namespace(tag, XEP_0231_NAMESPACE);
+	xmlnode_set_attrib(tag, "cid", data->cid);
+	xmlnode_set_attrib(tag, "type", data->type);
+
+	xmlnode_insert_data(tag, base64data, -1);
+
+	g_free(base64data);
+
+	return tag;
+}
+
+xmlnode *
+jabber_data_get_xhtml_im(const JabberData *data, const gchar *alt)
+{
+	xmlnode *img = xmlnode_new("img");
+	char src[128];
+
+	xmlnode_set_attrib(img, "alt", alt);
+	g_snprintf(src, sizeof(src), "cid:%s", data->cid);
+	xmlnode_set_attrib(img, "src", src);
+
+	return img;
+}
+
+xmlnode *
+jabber_data_get_xml_request(const gchar *cid)
+{
+	xmlnode *tag = xmlnode_new("data");
+
+	xmlnode_set_namespace(tag, XEP_0231_NAMESPACE);
+	xmlnode_set_attrib(tag, "cid", cid);
+
+	return tag;
+}
+
+const JabberData *
+jabber_data_find_local_by_alt(const gchar *alt)
+{
+	purple_debug_info("jabber", "looking up local smiley with alt = %s\n", alt);
+	return g_hash_table_lookup(local_data_by_alt, alt);
+}
+
+const JabberData *
+jabber_data_find_local_by_cid(const gchar *cid)
+{
+	purple_debug_info("jabber", "lookup local smiley with cid = %s\n", cid);
+	return g_hash_table_lookup(local_data_by_cid, cid);
+}
+
+const JabberData *
+jabber_data_find_remote_by_cid(const gchar *cid)
+{
+	purple_debug_info("jabber", "lookup remote smiley with cid = %s\n", cid);
+	
+	return g_hash_table_lookup(remote_data_by_cid, cid);
+}
+
+void
+jabber_data_associate_local(JabberData *data, const gchar *alt)
+{
+	purple_debug_info("jabber", "associating local smiley\n alt = %s, cid = %s\n",
+		alt, jabber_data_get_cid(data));
+	g_hash_table_insert(local_data_by_alt, g_strdup(alt), data);
+	g_hash_table_insert(local_data_by_cid, g_strdup(jabber_data_get_cid(data)), 
+		data);
+}
+
+void
+jabber_data_associate_remote(JabberData *data)
+{
+	purple_debug_info("jabber", "associating remote smiley, cid = %s\n",
+		jabber_data_get_cid(data));
+	g_hash_table_insert(remote_data_by_cid, g_strdup(jabber_data_get_cid(data)), 
+		data);
+}
+
+void
+jabber_data_parse(JabberStream *js, xmlnode *packet)
+{
+	JabberIq *result = NULL;
+	const char *who = xmlnode_get_attrib(packet, "from");
+	xmlnode *data_node = xmlnode_get_child(packet, "data");
+	const JabberData *data =
+		jabber_data_find_local_by_cid(xmlnode_get_attrib(data_node, "cid"));
+
+	if (!data) {
+		xmlnode *item_not_found = xmlnode_new("item-not-found");
+
+		result = jabber_iq_new(js, JABBER_IQ_ERROR);
+		xmlnode_set_attrib(result->node, "to", who);
+		xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+		xmlnode_insert_child(result->node, item_not_found);
+	} else {
+		result = jabber_iq_new(js, JABBER_IQ_RESULT);
+		xmlnode_set_attrib(result->node, "to", who);
+		xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+		xmlnode_insert_child(result->node,
+							 jabber_data_get_xml_definition(data));
+	}
+	jabber_iq_send(result);
+}
+
+void
+jabber_data_init(void)
+{
+	purple_debug_info("jabber", "creating hash tables for data objects\n");
+	local_data_by_alt = g_hash_table_new_full(g_str_hash, g_str_equal,
+		g_free, NULL);
+	local_data_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal,
+		g_free, jabber_data_delete);
+	remote_data_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal,
+		g_free, jabber_data_delete);
+}
+
+void
+jabber_data_uninit(void)
+{
+	purple_debug_info("jabber", "destroying hash tables for data objects\n");
+	g_hash_table_destroy(local_data_by_alt);
+	g_hash_table_destroy(local_data_by_cid);
+	g_hash_table_destroy(remote_data_by_cid);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/data.h	Sat Sep 27 13:28:07 2008 +0000
@@ -0,0 +1,73 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
+ */
+ 
+#ifndef JABBER_DATA_H
+#define JABBER_DATA_H
+
+#include "xmlnode.h"
+#include "jabber.h"
+
+#define XEP_0231_NAMESPACE "urn:xmpp:bob"
+
+#include <glib.h>
+
+typedef struct {
+	char *cid;
+	char *type;
+	gsize size;
+	gpointer data;
+} JabberData;
+
+/* creates a JabberData instance from raw data */
+JabberData *jabber_data_create_from_data(gconstpointer data, gsize size,
+										 const char *type, JabberStream *js);
+
+/* create a JabberData instance from an XML "data" element (as defined by
+  XEP 0231 */
+JabberData *jabber_data_create_from_xml(xmlnode *tag);
+
+const char *jabber_data_get_cid(const JabberData *data);
+const char *jabber_data_get_type(const JabberData *data);
+
+gsize jabber_data_get_size(const JabberData *data);
+gpointer jabber_data_get_data(const JabberData *data);
+
+/* returns the XML definition for the data element */
+xmlnode *jabber_data_get_xml_definition(const JabberData *data);
+
+/* returns an XHTML-IM "img" tag given a data instance */
+xmlnode *jabber_data_get_xhtml_im(const JabberData *data, const gchar *alt);
+
+/* returns a data request element (to be included in an iq stanza) for requesting
+  data */
+xmlnode *jabber_data_get_xml_request(const gchar *cid);
+
+/* lookup functions */
+const JabberData *jabber_data_find_local_by_alt(const gchar *alt);
+const JabberData *jabber_data_find_local_by_cid(const gchar *cid);
+const JabberData *jabber_data_find_remote_by_cid(const gchar *cid);
+
+/* store data objects */
+void jabber_data_associate_local(JabberData *data, const gchar *alt);
+void jabber_data_associate_remote(JabberData *data);
+
+/* handles iq requests */
+void jabber_data_parse(JabberStream *js, xmlnode *packet);
+
+void jabber_data_init(void);
+void jabber_data_uninit(void);
+
+#endif /* JABBER_DATA_H */
--- a/libpurple/protocols/jabber/iq.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/iq.c	Sat Sep 27 13:28:07 2008 +0000
@@ -33,6 +33,7 @@
 #include "si.h"
 #include "ping.h"
 #include "adhoccommands.h"
+#include "data.h"
 
 #ifdef _WIN32
 #include "utsname.h"
@@ -355,6 +356,11 @@
 		return;
 	}
 
+	if (xmlnode_get_child_with_namespace(packet, "data", XEP_0231_NAMESPACE)) {
+		jabber_data_parse(js, packet);
+		return;
+	}
+
 	/* If we get here, send the default error reply mandated by XMPP-CORE */
 	if(type && (!strcmp(type, "set") || !strcmp(type, "get"))) {
 		JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR);
--- a/libpurple/protocols/jabber/jabber.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Sat Sep 27 13:28:07 2008 +0000
@@ -42,6 +42,7 @@
 #include "auth.h"
 #include "buddy.h"
 #include "chat.h"
+#include "data.h"
 #include "disco.h"
 #include "google.h"
 #include "iq.h"
@@ -57,6 +58,7 @@
 #include "pep.h"
 #include "adhoccommands.h"
 
+
 #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5)
 
 static PurplePlugin *my_protocol = NULL;
@@ -642,7 +644,8 @@
 	JabberStream *js;
 	JabberBuddy *my_jb = NULL;
 
-	gc->flags |= PURPLE_CONNECTION_HTML;
+	gc->flags |= PURPLE_CONNECTION_HTML |
+		PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY;
 	js = gc->proto_data = g_new0(JabberStream, 1);
 	js->gc = gc;
 	js->fd = -1;
@@ -1901,7 +1904,7 @@
 	JabberID *jid;
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr;
-
+	
 	if(!(jid = jabber_id_new(who)))
 		return;
 
--- a/libpurple/protocols/jabber/libxmpp.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Sat Sep 27 13:28:07 2008 +0000
@@ -43,6 +43,7 @@
 #include "pep.h"
 #include "usertune.h"
 #include "caps.h"
+#include "data.h"
 
 static PurplePluginProtocolInfo prpl_info =
 {
@@ -136,8 +137,7 @@
 			     purple_marshal_VOID__POINTER_POINTER, NULL, 2,
 			     purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
 			     purple_value_new_outgoing(PURPLE_TYPE_STRING));
-			   
-
+	
 	return TRUE;
 }
 
@@ -149,6 +149,8 @@
 	
 	purple_signal_unregister(plugin, "jabber-sending-text");
 	
+	jabber_data_uninit();
+	
 	return TRUE;
 }
 
@@ -241,6 +243,13 @@
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
 						  option);
 
+	/* this should probably be part of global smiley theme settings later on,
+	  shared with MSN */
+	option = purple_account_option_bool_new(_("Show Custom Smileys"),
+		"custom_smileys", TRUE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+		option);
+
 	jabber_init_plugin(plugin);
 
 	purple_prefs_remove("/plugins/prpl/jabber");
@@ -269,11 +278,16 @@
 	
 	jabber_tune_init();
 	jabber_caps_init();
-
+	
+	jabber_data_init();
+	
 	jabber_add_feature("avatarmeta", AVATARNAMESPACEMETA, jabber_pep_namespace_only_when_pep_enabled_cb);
 	jabber_add_feature("avatardata", AVATARNAMESPACEDATA, jabber_pep_namespace_only_when_pep_enabled_cb);
-	jabber_add_feature("buzz", "http://www.xmpp.org/extensions/xep-0224.html#ns", jabber_buzz_isenabled);
-	
+	jabber_add_feature("buzz", "http://www.xmpp.org/extensions/xep-0224.html#ns",
+					   jabber_buzz_isenabled);
+	jabber_add_feature("bob", XEP_0231_NAMESPACE,
+					   jabber_custom_smileys_isenabled);
+
 	jabber_pep_register_handler("avatar", AVATARNAMESPACEMETA, jabber_buddy_avatar_update_metadata);
 }
 
--- a/libpurple/protocols/jabber/message.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/message.c	Sat Sep 27 13:28:07 2008 +0000
@@ -24,13 +24,17 @@
 #include "notify.h"
 #include "server.h"
 #include "util.h"
-
 #include "buddy.h"
 #include "chat.h"
+#include "data.h"
 #include "google.h"
 #include "message.h"
 #include "xmlnode.h"
 #include "pep.h"
+#include "smiley.h"
+#include "iq.h"
+
+#include <string.h>
 
 void jabber_message_free(JabberMessage *jm)
 {
@@ -312,6 +316,225 @@
 	g_free(str);
 }
 
+/* used internally by the functions below */
+typedef struct {
+	gchar *cid;
+	gchar *alt;
+} JabberSmileyRef;
+
+
+static void
+jabber_message_get_refs_from_xmlnode_internal(const xmlnode *message,
+	GHashTable *table)
+{
+	xmlnode *child;
+	
+	for (child = xmlnode_get_child(message, "img") ; child ;
+		 child = xmlnode_get_next_twin(child)) {
+		const gchar *src = xmlnode_get_attrib(child, "src");
+		
+		if (g_str_has_prefix(src, "cid:")) {
+			const gchar *cid = src + 4;
+			
+			/* if we haven't "fetched" this yet... */
+			if (!g_hash_table_lookup(table, cid)) {
+				/* take a copy of the cid and let the SmileyRef own it... */
+				gchar *temp_cid = g_strdup(cid);
+				JabberSmileyRef *ref = g_new0(JabberSmileyRef, 1);
+				const gchar *alt = xmlnode_get_attrib(child, "alt");
+				ref->cid = temp_cid;
+				/* if there is no "alt" string, use the cid... 
+				 include the entire src, eg. "cid:.." to avoid linkification */
+				if (alt && alt[0] != '\0') {
+					/* workaround for when "alt" is set to the value of the
+					 CID (which Jabbim seems to do), to avoid it showing up
+						 as an mailto: link */
+					if (purple_email_is_valid(alt)) {
+						ref->alt = g_strdup_printf("smiley:%s", alt); 
+					} else {
+						ref->alt = g_strdup(alt);
+					}
+				} else {
+					ref->alt = g_strdup(src);
+				}
+				g_hash_table_insert(table, temp_cid, ref);
+			}
+		}
+	}
+		
+	for (child = message->child ; child ; child = child->next) {
+		jabber_message_get_refs_from_xmlnode_internal(child, table);
+	}
+}
+
+static gboolean
+jabber_message_get_refs_steal(gpointer key, gpointer value, gpointer user_data)
+{
+	GList **refs = (GList **) user_data;
+	JabberSmileyRef *ref = (JabberSmileyRef *) value;
+	
+	*refs = g_list_append(*refs, ref);
+	
+	return TRUE;
+}
+
+static GList *
+jabber_message_get_refs_from_xmlnode(const xmlnode *message)
+{
+	GList *refs = NULL;
+	GHashTable *unique_refs = g_hash_table_new(g_str_hash, g_str_equal);
+	
+	jabber_message_get_refs_from_xmlnode_internal(message, unique_refs);
+	(void) g_hash_table_foreach_steal(unique_refs, 
+		jabber_message_get_refs_steal, (gpointer) &refs);
+	g_hash_table_destroy(unique_refs);
+	return refs;
+}
+
+static gchar *
+jabber_message_xml_to_string_strip_img_smileys(xmlnode *xhtml)
+{
+	gchar *markup = xmlnode_to_str(xhtml, NULL);
+	int len = strlen(markup);
+	int pos = 0;
+	GString *out = g_string_new(NULL);
+
+	while (pos < len) {
+		/* this is a bit cludgy, maybe there is a better way to do this...
+		  we need to find all <img> tags within the XHTML and replace those
+			tags with the value of their "alt" attributes */
+		if (g_str_has_prefix(&(markup[pos]), "<img")) {
+			xmlnode *img = NULL;
+			int pos2 = pos;
+			const gchar *src;
+
+			for (; pos2 < len ; pos2++) {
+				if (g_str_has_prefix(&(markup[pos2]), "/>")) {
+					pos2 += 2;
+					break;
+				} else if (g_str_has_prefix(&(markup[pos2]), "</img>")) {
+					pos2 += 5;
+					break;
+				}
+			}
+
+			/* note, if the above loop didn't find the end of the <img> tag,
+			  it the parsed string will be until the end of the input string,
+			  in which case xmlnode_from_str will bail out and return NULL,
+			  in this case the "if" statement below doesn't trigger and the
+			  text is copied unchanged */
+			img = xmlnode_from_str(&(markup[pos]), pos2 - pos);
+			src = xmlnode_get_attrib(img, "src");
+
+			if (g_str_has_prefix(src, "cid:")) {
+				const gchar *alt = xmlnode_get_attrib(img, "alt");
+				/* if the "alt" attribute is empty, put the cid as smiley string */
+				if (alt && alt[0] != '\0') {
+					/* if the "alt" is the same as the CID, as Jabbim does,
+					 this prevents linkification... */
+					if (purple_email_is_valid(alt)) {
+						gchar *safe_alt = g_strdup_printf("smiley:%s", alt);
+						out = g_string_append(out, safe_alt);
+						g_free(safe_alt);
+					} else {
+						out = g_string_append(out, alt);
+					}
+				} else {
+					out = g_string_append(out, src);
+				}
+				pos += pos2 - pos;
+			} else {
+				out = g_string_append_c(out, markup[pos]);
+				pos++;
+			}
+
+			xmlnode_free(img);
+
+		} else {
+			out = g_string_append_c(out, markup[pos]);
+			pos++;
+		}
+	}
+
+	g_free(markup);
+	return g_string_free(out, FALSE);
+}
+
+static void
+jabber_message_add_remote_smileys(const xmlnode *message)
+{
+	xmlnode *data_tag;
+	for (data_tag = xmlnode_get_child_with_namespace(message, "data", XEP_0231_NAMESPACE) ;
+		 data_tag ;
+		 data_tag = xmlnode_get_next_twin(data_tag)) {
+		const gchar *cid = xmlnode_get_attrib(data_tag, "cid");
+		const JabberData *data = jabber_data_find_remote_by_cid(cid);
+
+		if (!data && cid != NULL) {
+			/* we haven't cached this already, let's add it */
+			JabberData *new_data = jabber_data_create_from_xml(data_tag);
+			jabber_data_associate_remote(new_data);
+		}
+	}
+}
+
+/* used in the function below to supply a conversation and shortcut for a
+ smiley */
+typedef struct {
+	PurpleConversation *conv;
+	gchar *alt;
+} JabberDataRef;
+
+static void
+jabber_message_get_data_cb(JabberStream *js, xmlnode *packet, gpointer data)
+{
+	JabberDataRef *ref = (JabberDataRef *) data;
+	PurpleConversation *conv = ref->conv;
+	const gchar *alt = ref->alt;
+	xmlnode *data_element = xmlnode_get_child(packet, "data");
+	xmlnode *item_not_found = xmlnode_get_child(packet, "item-not-found");
+
+	/* did we get a data element as result? */
+	if (data_element) {
+		JabberData *data = jabber_data_create_from_xml(data_element);
+
+		if (data) {
+			jabber_data_associate_remote(data);
+			purple_conv_custom_smiley_write(conv, alt,
+											jabber_data_get_data(data),
+											jabber_data_get_size(data));
+			purple_conv_custom_smiley_close(conv, alt);
+		}
+
+	} else if (item_not_found) {
+		purple_debug_info("jabber",
+			"Responder didn't recognize requested data\n");
+	} else {
+		purple_debug_error("jabber", "Unknown response to data request\n");
+	}
+	g_free(ref->alt);
+	g_free(ref);
+}
+
+static void
+jabber_message_send_data_request(JabberStream *js, PurpleConversation *conv,
+								 const gchar *cid, const gchar *who, 
+								 const gchar *alt)
+{
+	JabberIq *request = jabber_iq_new(js, JABBER_IQ_GET);
+	JabberDataRef *ref = g_new0(JabberDataRef, 1);
+	xmlnode *data_request = jabber_data_get_xml_request(cid);
+
+	xmlnode_set_attrib(request->node, "to", who);
+	ref->conv = conv;
+	ref->alt = g_strdup(alt);
+	jabber_iq_set_callback(request, jabber_message_get_data_cb, ref);
+	xmlnode_insert_child(request->node, data_request);
+
+	jabber_iq_send(request);
+}
+
+
 void jabber_message_parse(JabberStream *js, xmlnode *packet)
 {
 	JabberMessage *jm;
@@ -369,16 +592,101 @@
 				g_free(msg); g_free(tmp);
 			}
 		} else if(!strcmp(child->name, "html") && !strcmp(xmlns,"http://jabber.org/protocol/xhtml-im")) {
-			if(!jm->xhtml && xmlnode_get_child(child, "body")){
-				char *tmp, *c;
+			if(!jm->xhtml && xmlnode_get_child(child, "body")) {
+				char *c;
 				gsize len;
-				tmp = xmlnode_to_str(child, NULL);
-				jm->xhtml = sanitize_utf(tmp, strlen(tmp), &len);
-			        /* Convert all newlines to whitespace. Technically, even regular, non-XML HTML is supposed to ignore newlines, but Pidgin has, as convention
-			 	 * treated \n as a newline for compatibility with other protocols
+
+				const PurpleConnection *gc = js->gc;
+				const gchar *who = xmlnode_get_attrib(packet, "from");
+				PurpleAccount *account = purple_connection_get_account(gc);
+				PurpleConversation *conv = NULL;
+				GList *smiley_refs = NULL;
+				gchar *reformatted_xhtml;
+
+				if (purple_account_get_bool(account, "custom_smileys", TRUE)) {
+					/* find a list of smileys ("cid" and "alt" text pairs)
+					  occuring in the message */
+					smiley_refs = jabber_message_get_refs_from_xmlnode(child);
+					purple_debug_info("jabber", "found %d smileys\n",
+						g_list_length(smiley_refs));
+					
+					if (jm->type == JABBER_MESSAGE_GROUPCHAT) {
+						JabberID *jid = jabber_id_new(jm->from);
+						JabberChat *chat = NULL;
+
+						if (jid) {
+							chat = jabber_chat_find(js, jid->node, jid->domain);
+							conv = chat->conv;
+						}
+
+						jabber_id_free(jid);
+					} else {
+						conv =
+							purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY,
+								who, account);
+						if (!conv) {
+							/* we need to create the conversation here */
+							conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
+								account, who);
+						}
+					}
+
+					/* process any newly provided smileys */
+					jabber_message_add_remote_smileys(packet);
+				}
+
+				/* reformat xhtml so that img tags with a "cid:" src gets
+				  translated to the bare text of the emoticon (the "alt" attrib) */
+				/* this is done also when custom smiley retrieval is turned off,
+				  this way the receiver always sees the shortcut instead */
+				reformatted_xhtml =
+					jabber_message_xml_to_string_strip_img_smileys(child);
+
+//				jm->xhtml = reformatted_xhtml;
+				jm->xhtml = sanitize_utf(reformatted_xhtml,
+							strlen(reformatted_xhtml), &len);
+
+				/* add known custom emoticons to the conversation */
+				/* note: if there were no smileys in the incoming message, or
+				  	if receiving custom smileys is turned off, smiley_refs will
+					be NULL */
+				for (; smiley_refs ; smiley_refs = g_list_delete_link(smiley_refs, smiley_refs)) {
+					JabberSmileyRef *ref = (JabberSmileyRef *) smiley_refs->data;
+					const gchar *cid = ref->cid;
+					const gchar *alt = ref->alt;
+
+					purple_debug_info("jabber", 
+						"about to add custom smiley %s to the conv\n", alt);
+					if (purple_conv_custom_smiley_add(conv, alt, "cid", cid,
+						    TRUE)) {
+						const JabberData *data =
+								jabber_data_find_remote_by_cid(cid);
+						/* if data is already known, we add write it immediatly */
+						if (data) {
+							purple_debug_info("jabber", 
+								"data is already known\n"); 
+							purple_conv_custom_smiley_write(conv, alt,
+								jabber_data_get_data(data),
+								jabber_data_get_size(data));
+							purple_conv_custom_smiley_close(conv, alt);
+						} else {
+							/* we need to request the smiley (data) */
+							purple_debug_info("jabber",
+								"data is unknown, need to request it\n");
+							jabber_message_send_data_request(js, conv, cid, who,
+								alt);
+						}
+					}
+					g_free(ref->cid);
+					g_free(ref->alt);
+					g_free(ref);
+				}
+
+			    /* Convert all newlines to whitespace. Technically, even regular, non-XML HTML is supposed to ignore newlines, but Pidgin has, as convention
+				 * treated \n as a newline for compatibility with other protocols
 				 */
 				for (c = jm->xhtml; *c != '\0'; c++) {
-					if (*c == '\n') 
+					if (*c == '\n')
 						*c = ' ';
 				}
 				g_free(tmp);
@@ -509,6 +817,129 @@
 	jabber_message_free(jm);
 }
 
+static const gchar *
+jabber_message_get_mimetype_from_ext(const gchar *ext)
+{
+	if (strcmp(ext, "png") == 0) {
+		return "image/png";
+	} else if (strcmp(ext, "gif") == 0) {
+		return "image/gif";
+	} else if (strcmp(ext, "jpg") == 0) {
+		return "image/jpeg";
+	} else if (strcmp(ext, "tif") == 0) {
+		return "image/tif";
+	} else {
+		return "image/x-icon"; /* or something... */
+	}
+}
+
+static GList *
+jabber_message_xhtml_find_smileys(const char *xhtml)
+{
+	GList *smileys = purple_smileys_get_all();
+	GList *found_smileys = NULL;
+
+	for (; smileys ; smileys = g_list_delete_link(smileys, smileys)) {
+		PurpleSmiley *smiley = (PurpleSmiley *) smileys->data;
+		const gchar *shortcut = purple_smiley_get_shortcut(smiley);
+		const gssize len = strlen(shortcut);
+
+		gchar *escaped = g_markup_escape_text(shortcut, len);
+		const char *pos = strstr(xhtml, escaped);
+
+		if (pos) {
+			found_smileys = g_list_append(found_smileys, smiley);
+		}
+
+		g_free(escaped);
+	}
+
+	return found_smileys;
+}
+
+static gchar *
+jabber_message_get_smileyfied_xhtml(const gchar *xhtml, const GList *smileys)
+{
+	/* create XML element for all smileys (img tags) */
+	GString *result = g_string_new(NULL);
+	int pos = 0;
+	int length = strlen(xhtml);
+
+	while (pos < length) {
+		const GList *iterator;
+		gboolean found_smiley = FALSE;
+
+		for (iterator = smileys ; iterator ;
+			iterator = g_list_next(iterator)) {
+			const PurpleSmiley *smiley = (PurpleSmiley *) iterator->data;
+			const gchar *shortcut = purple_smiley_get_shortcut(smiley);
+			const gssize len = strlen(shortcut);
+			gchar *escaped = g_markup_escape_text(shortcut, len);
+
+			if (g_str_has_prefix(&(xhtml[pos]), escaped)) {
+				/* we found the current smiley at this position */
+				const JabberData *data =
+					jabber_data_find_local_by_alt(shortcut);
+				xmlnode *img = jabber_data_get_xhtml_im(data, shortcut);
+				int len;
+				gchar *img_text = xmlnode_to_str(img, &len);
+
+				found_smiley = TRUE;
+				result = g_string_append(result, img_text);
+				g_free(img_text);
+				pos += strlen(escaped);
+				g_free(escaped);
+				xmlnode_free(img);
+				break;
+			} else {
+				/* cleanup from the before the next round... */
+				g_free(escaped);
+			}
+		}
+		if (!found_smiley) {
+			/* there was no smiley here, just copy one byte */
+			result = g_string_append_c(result, xhtml[pos]);
+			pos++;
+		}
+	}
+
+	return g_string_free(result, FALSE);
+}
+
+static gboolean
+jabber_conv_support_custom_smileys(const PurpleConnection *gc,
+								   const PurpleConversation *conv,
+								   const gchar *who)
+{
+	JabberStream *js = (JabberStream *) gc->proto_data;
+	JabberBuddy *jb;
+	
+	if (!js) {
+		purple_debug_error("jabber", 
+			"jabber_conv_support_custom_smileys: could not find stream\n");
+		return FALSE;
+	}
+
+	jb = jabber_buddy_find(js, who, FALSE);
+	if (!jb) {
+		purple_debug_error("jabber",
+			"jabber_conv_support_custom smileys: could not find buddy\n");
+		return FALSE;
+	}
+	
+	
+
+	switch (purple_conversation_get_type(conv)) {
+		/* for the time being, we will not support custom smileys in MUCs */
+		case PURPLE_CONV_TYPE_IM:
+			return jabber_buddy_has_capability(jb, XEP_0231_NAMESPACE);
+			break;
+		default:
+			return FALSE;
+			break;
+	}
+}
+
 void jabber_message_send(JabberMessage *jm)
 {
 	xmlnode *message, *child;
@@ -594,7 +1025,55 @@
 	}
 
 	if(jm->xhtml) {
-		child = xmlnode_from_str(jm->xhtml, -1);
+		PurpleAccount *account = purple_connection_get_account(jm->js->gc);
+		PurpleConversation *conv =
+			purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, jm->to,
+				account);
+ 
+		if (jabber_conv_support_custom_smileys(jm->js->gc, conv, jm->to)) {
+			GList *found_smileys = jabber_message_xhtml_find_smileys(jm->xhtml);
+
+			if (found_smileys) {
+				gchar *smileyfied_xhtml = NULL;
+				const GList *iterator;
+
+				for (iterator = found_smileys; iterator ;
+					iterator = g_list_next(iterator)) {
+					const PurpleSmiley *smiley =
+							(PurpleSmiley *) iterator->data;
+					const gchar *shortcut = purple_smiley_get_shortcut(smiley);
+					const JabberData *data =
+						jabber_data_find_local_by_alt(shortcut);
+							
+					/* the object has not been sent before */
+					if (!data) {
+						PurpleStoredImage *image =
+								purple_smiley_get_stored_image(smiley);
+						const gchar *ext = purple_imgstore_get_extension(image);
+						JabberStream *js = jm->js;
+						
+						JabberData *new_data =
+							jabber_data_create_from_data(purple_imgstore_get_data(image),
+								purple_imgstore_get_size(image),
+								jabber_message_get_mimetype_from_ext(ext), js);
+						purple_debug_info("jabber", 
+							"cache local smiley alt = %s, cid = %s\n",
+							shortcut, jabber_data_get_cid(new_data));
+						jabber_data_associate_local(new_data, shortcut);
+					}
+				}
+
+				smileyfied_xhtml =
+					jabber_message_get_smileyfied_xhtml(jm->xhtml, found_smileys);
+				child = xmlnode_from_str(smileyfied_xhtml, -1);
+				g_free(smileyfied_xhtml);
+				g_list_free(found_smileys);
+			} else {
+				child = xmlnode_from_str(jm->xhtml, -1);
+			}
+		} else {
+			child = xmlnode_from_str(jm->xhtml, -1);
+		}
 		if(child) {
 			xmlnode_insert_child(message, child);
 		} else {
@@ -768,3 +1247,11 @@
 	return js->allowBuzz;
 }
 
+gboolean jabber_custom_smileys_isenabled(JabberStream *js, const gchar *shortname,
+										 const gchar *namespace)
+{
+	const PurpleConnection *gc = js->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+
+	return purple_account_get_bool(account, "custom_smileys", TRUE);
+}
--- a/libpurple/protocols/jabber/message.h	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/jabber/message.h	Sat Sep 27 13:28:07 2008 +0000
@@ -80,4 +80,7 @@
 
 gboolean jabber_buzz_isenabled(JabberStream *js, const gchar *shortname, const gchar *namespace);
 
+gboolean jabber_custom_smileys_isenabled(JabberStream *js, const gchar *shortname,
+										 const gchar *namespace);
+
 #endif /* _PURPLE_JABBER_MESSAGE_H_ */
--- a/libpurple/protocols/msn/group.h	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/msn/group.h	Sat Sep 27 13:28:07 2008 +0000
@@ -33,10 +33,10 @@
 #include "userlist.h"
 
 #define MSN_INDIVIDUALS_GROUP_ID	"1983"
-#define MSN_INDIVIDUALS_GROUP_NAME	"Other Contacts"
+#define MSN_INDIVIDUALS_GROUP_NAME	_("Other Contacts")
 
 #define MSN_NON_IM_GROUP_ID		"email"
-#define MSN_NON_IM_GROUP_NAME	"Non-IM Contacts"
+#define MSN_NON_IM_GROUP_NAME	_("Non-IM Contacts")
 
 /**
  * A group.
--- a/libpurple/protocols/msn/notification.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/msn/notification.c	Sat Sep 27 13:28:07 2008 +0000
@@ -613,16 +613,13 @@
 	xmlnode_set_attrib(adl_node, "l", "1");
 
 	/*get the userlist*/
-	for (l = session->userlist->users; l != NULL; l = l->next) {
+	for (l = session->userlist->users; l != NULL; l = l->next){
 		user = l->data;
 
 		/* skip RL & PL during initial dump */
 		if (!(user->list_op & MSN_LIST_OP_MASK))
 			continue;
 
-		if (!strcmp(user->passport, "messenger@microsoft.com"))
-			continue;
-
 		msn_add_contact_xml(session, adl_node, user->passport,
 			user->list_op & MSN_LIST_OP_MASK, user->networkid);
 
@@ -774,6 +771,53 @@
 }
 
 static void
+adl_241_error_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+	size_t len)
+{
+	/* khc: some googling suggests that error 241 means the buddy is somehow
+	   in the local list, but not the server list, and that we should add
+	   those buddies to the addressbook. For now I will just notify the user
+	   about the raw payload, because I am lazy */
+	MsnSession *session;
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	xmlnode *adl;
+	xmlnode *domain;
+	GString *emails;
+
+	session = cmdproc->session;
+	account = session->account;
+	gc = purple_account_get_connection(account);
+
+	adl = xmlnode_from_str(payload, len);
+	emails = g_string_new(NULL);
+
+	domain = xmlnode_get_child(adl, "d");
+	while (domain) {
+		const char *domain_str = xmlnode_get_attrib(domain, "n");
+		xmlnode *contact = xmlnode_get_child(domain, "c");
+		while (contact) {
+			g_string_append_printf(emails, "%s@%s\n",
+				xmlnode_get_attrib(contact, "n"), domain_str);
+			contact = xmlnode_get_next_twin(contact);
+		}
+		domain = xmlnode_get_next_twin(domain);
+	}
+
+	purple_notify_error(gc, NULL,
+		_("The following users are missing from your addressbook"), emails->str);
+	g_string_free(emails, TRUE);
+	xmlnode_free(adl);
+}
+
+static void
+adl_241_error_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	cmdproc->last_cmd->payload_cb = adl_241_error_cmd_post;
+	cmd->payload_len = atoi(cmd->params[1]);
+}
+
+static void
 fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
 			 size_t len)
 {
@@ -1962,6 +2006,8 @@
 
 	msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd);
 
+	msn_table_add_cmd(cbs_table, NULL, "241", adl_241_error_cmd);
+
 	msn_table_add_error(cbs_table, "ADD", add_error);
 	msn_table_add_error(cbs_table, "ADL", adl_error);
 	msn_table_add_error(cbs_table, "REG", reg_error);
--- a/libpurple/protocols/msn/session.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/msn/session.c	Sat Sep 27 13:28:07 2008 +0000
@@ -453,6 +453,8 @@
 	PurpleConnection *gc;
 	PurpleStoredImage *img;
 
+	msn_change_status(session);
+
 	if (session->logged_in)
 		return;
 
@@ -465,8 +467,6 @@
 
 	session->logged_in = TRUE;
 
-	msn_change_status(session);
-
 	purple_connection_set_state(gc, PURPLE_CONNECTED);
 
 	/* Sync users */
--- a/libpurple/protocols/yahoo/yahoo.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Sat Sep 27 13:28:07 2008 +0000
@@ -55,6 +55,12 @@
 
 /* #define TRY_WEBMESSENGER_LOGIN 0 */
 
+/* One hour */
+#define PING_TIMEOUT 3600
+
+/* One minute */
+#define KEEPALIVE_TIMEOUT 60
+
 static void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *, PurpleGroup *);
 #ifdef TRY_WEBMESSENGER_LOGIN
 static void yahoo_login_page_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message);
@@ -3009,6 +3015,7 @@
 	yd->xfer_peer_idstring_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
 	yd->confs = NULL;
 	yd->conf_id = 2;
+	yd->last_keepalive = yd->last_ping = time(NULL);
 
 	yd->current_status = get_yahoo_status_from_purple_status(status);
 
@@ -3067,7 +3074,7 @@
 	}
 	g_slist_free(yd->cookies);
 
-	yd->chat_online = 0;
+	yd->chat_online = FALSE;
 	if (yd->in_chat)
 		yahoo_c_leave(gc, 1); /* 1 = YAHOO_CHAT_ID */
 
@@ -3894,21 +3901,36 @@
 
 static void yahoo_keepalive(PurpleConnection *gc)
 {
+	struct yahoo_packet *pkt;
 	struct yahoo_data *yd = gc->proto_data;
-	struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_send_and_free(pkt, yd);
-
-	if (!yd->chat_online)
-		return;
-
-	if (yd->wm) {
-		ycht_chat_send_keepalive(yd->ycht);
-		return;
+	time_t now = time(NULL);
+
+	/* We're only allowed to send a ping once an hour or the servers will boot us */
+	if ((now - yd->last_ping) >= PING_TIMEOUT) {
+		yd->last_ping = now;
+
+		/* The native client will only send PING or CHATPING */
+		if (yd->chat_online) {
+			if (yd->wm) {
+				ycht_chat_send_keepalive(yd->ycht);
+			} else {
+				pkt = yahoo_packet_new(YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, 0);
+				yahoo_packet_hash_str(pkt, 109, purple_connection_get_display_name(gc));
+				yahoo_packet_send_and_free(pkt, yd);
+			}
+		} else {
+			pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, 0);
+			yahoo_packet_send_and_free(pkt, yd);
+		}
 	}
 
-	pkt = yahoo_packet_new(YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_hash_str(pkt, 109, purple_connection_get_display_name(gc));
-	yahoo_packet_send_and_free(pkt, yd);
+	if ((now - yd->last_keepalive) >= KEEPALIVE_TIMEOUT) {
+		yd->last_keepalive = now;
+		pkt = yahoo_packet_new(YAHOO_SERVICE_KEEPALIVE, YAHOO_STATUS_AVAILABLE, 0);
+		yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc));
+		yahoo_packet_send_and_free(pkt, yd);
+	}
+
 }
 
 static void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g)
--- a/libpurple/protocols/yahoo/yahoo.h	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.h	Sat Sep 27 13:28:07 2008 +0000
@@ -176,6 +176,8 @@
 	 * the server expects us to keep track of the group for which it is sending us contact names.
 	 */
 	char *current_list15_grp;
+	time_t last_ping;
+	time_t last_keepalive;
 };
 
 #define YAHOO_MAX_STATUS_MESSAGE_LENGTH (255)
--- a/libpurple/protocols/yahoo/yahoo_packet.h	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo_packet.h	Sat Sep 27 13:28:07 2008 +0000
@@ -76,7 +76,7 @@
 	YAHOO_SERVICE_IGNORECONTACT,    /* > 1, 7, 13 < 1, 66, 13, 0*/
 	YAHOO_SERVICE_REJECTCONTACT,
 	YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */
-	/* YAHOO_SERVICE_??? = 0x8A, */
+	YAHOO_SERVICE_KEEPALIVE = 0x8A,
 	YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/
 	YAHOO_SERVICE_CHATGOTO,
 	YAHOO_SERVICE_CHATJOIN, /* > 1 104-room 129-1600326591 62-2 */
--- a/libpurple/protocols/yahoo/yahoochat.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Sat Sep 27 13:28:07 2008 +0000
@@ -369,7 +369,7 @@
 	struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data;
 
 	if (pkt->status == 1) {
-		yd->chat_online = 1;
+		yd->chat_online = TRUE;
 
 		/* We need to goto a user in chat */
 		if (yd->pending_chat_goto) {
@@ -411,7 +411,7 @@
 	}
 
 	if (pkt->status == 1) {
-		yd->chat_online = 0;
+		yd->chat_online = FALSE;
 		g_free(yd->pending_chat_room);
 		yd->pending_chat_room = NULL;
 		g_free(yd->pending_chat_id);
@@ -881,7 +881,7 @@
 	yahoo_packet_hash_str(pkt, 1, dn);
 	yahoo_packet_send_and_free(pkt, yd);
 
-	yd->chat_online = 0;
+	yd->chat_online = FALSE;
 	g_free(yd->pending_chat_room);
 	yd->pending_chat_room = NULL;
 	g_free(yd->pending_chat_id);
--- a/pidgin/gtkimhtml.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/pidgin/gtkimhtml.c	Sat Sep 27 13:28:07 2008 +0000
@@ -352,6 +352,9 @@
 			g_string_free (t->values, TRUE);
 			g_free (t->children);
 		}
+		if (t && t->image) {
+			t->image->imhtml = NULL;
+		}
 		g_free (t);
 	}
 }
@@ -1972,7 +1975,6 @@
 	}
 }
 
-/* this isn't used yet
 static void gtk_smiley_tree_remove (GtkSmileyTree     *tree,
 			GtkIMHtmlSmiley   *smiley)
 {
@@ -1988,7 +1990,7 @@
 
 		pos = strchr (t->values->str, *x);
 		if (pos)
-			t = t->children [(int) pos - (int) t->values->str];
+			t = t->children [(unsigned int) pos - (unsigned int) t->values->str];
 		else
 			return;
 
@@ -1999,8 +2001,6 @@
 		t->image = NULL;
 	}
 }
-*/
-
 
 static gint
 gtk_smiley_tree_lookup (GtkSmileyTree *tree,
@@ -2060,6 +2060,25 @@
 	return 0;
 }
 
+static void
+gtk_imhtml_disassociate_smiley_foreach(gpointer key, gpointer value,
+	gpointer user_data)
+{
+	GtkSmileyTree *tree = (GtkSmileyTree *) value;
+	GtkIMHtmlSmiley *smiley = (GtkIMHtmlSmiley *) user_data;
+	gtk_smiley_tree_remove(tree, smiley);
+}
+
+static void
+gtk_imhtml_disassociate_smiley(GtkIMHtmlSmiley *smiley)
+{
+	if (smiley->imhtml) {
+		gtk_smiley_tree_remove(smiley->imhtml->default_smilies, smiley);
+		g_hash_table_foreach(smiley->imhtml->smiley_data, 
+			gtk_imhtml_disassociate_smiley_foreach, smiley);
+	}
+}
+
 void
 gtk_imhtml_associate_smiley (GtkIMHtml       *imhtml,
 			     const gchar     *sml,
@@ -5632,12 +5651,14 @@
 	smiley->smile = g_strdup(shortcut);
 	smiley->hidden = hide;
 	smiley->flags = flags;
+	smiley->imhtml = NULL;
 	gtk_imhtml_smiley_reload(smiley);
 	return smiley;
 }
 
 void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley)
 {
+	gtk_imhtml_disassociate_smiley(smiley);
 	g_free(smiley->smile);
 	g_free(smiley->file);
 	if (smiley->icon)
--- a/pidgin/gtksmiley.c	Mon Sep 22 06:17:11 2008 +0000
+++ b/pidgin/gtksmiley.c	Sat Sep 27 13:28:07 2008 +0000
@@ -273,8 +273,8 @@
 			gsize size = 0;
 			gchar *filename;
 
-			gdk_pixbuf_save_to_bufferv(s->custom_pixbuf, &buffer, &size,
-									   "png", NULL, NULL, NULL);
+			gdk_pixbuf_save_to_buffer(s->custom_pixbuf, &buffer, &size,
+				"png", NULL, "compression", "9", NULL, NULL);
 			filename = purple_util_get_image_filename(buffer, size);
 			s->filename = g_build_filename(purple_smileys_get_storing_dir(), filename, NULL);
 			purple_util_write_data_to_file_absolute(s->filename, buffer, size);
--- a/po/POTFILES.in	Mon Sep 22 06:17:11 2008 +0000
+++ b/po/POTFILES.in	Sat Sep 27 13:28:07 2008 +0000
@@ -98,6 +98,7 @@
 libpurple/protocols/msn/contact.c
 libpurple/protocols/msn/dialog.c
 libpurple/protocols/msn/error.c
+libpurple/protocols/msn/group.h
 libpurple/protocols/msn/msn.c
 libpurple/protocols/msn/nexus.c
 libpurple/protocols/msn/notification.c
--- a/po/de.po	Mon Sep 22 06:17:11 2008 +0000
+++ b/po/de.po	Sat Sep 27 13:28:07 2008 +0000
@@ -11,9 +11,9 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-09-01 10:30+0200\n"
-"PO-Revision-Date: 2008-09-01 10:30+0200\n"
-"Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
+"POT-Creation-Date: 2008-09-27 13:06+0200\n"
+"PO-Revision-Date: 2008-09-27 13:02+0200\n"
+"Last-Translator: Björn Voigt <bjoern@cs.tu-berlin.de>\n"
 "Language-Team: Deutsch <de@li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -76,7 +76,7 @@
 msgid "Remember password"
 msgstr "Passwort speichern"
 
-msgid "There's no protocol plugins installed."
+msgid "There are no protocol plugins installed."
 msgstr "Es sind keine Protokoll-Plugins installiert."
 
 msgid "(You probably forgot to 'make install'.)"
@@ -1128,6 +1128,7 @@
 msgid "%s has sent you a message. (%s)"
 msgstr "%s hat Ihnen eine Nachricht gesendet. (%s)"
 
+#, c-format
 msgid "Unknown pounce event. Please report this!"
 msgstr "Unbekanntes Alarm-Ereignis. Bitte berichten Sie dieses Problem!"
 
@@ -1497,6 +1498,7 @@
 "Wenn eine neue Unterhaltung eröffnet wird, fügt dieses Plugin die letzte "
 "Unterhaltung in die aktuelle Unterhaltung ein."
 
+#, c-format
 msgid "Online"
 msgstr "Online"
 
@@ -1839,8 +1841,9 @@
 "Fehler beim Lesen vom Auflösungsprozess:\n"
 "%s"
 
-msgid "EOF while reading from resolver process"
-msgstr "EOF während vom Resolver-Prozess gelesen wurde"
+#, c-format
+msgid "Resolver process exited without answering our request"
+msgstr "Auflösungsprozess hat sich beendet ohne die Anfrage zu beantworten"
 
 #, c-format
 msgid "Thread creation failure: %s"
@@ -1929,6 +1932,7 @@
 msgid "Transfer of file %s complete"
 msgstr "Übertragung der Datei %s ist komplett"
 
+#, c-format
 msgid "File transfer complete"
 msgstr "Dateiübertragung ist komplett"
 
@@ -1936,6 +1940,7 @@
 msgid "You canceled the transfer of %s"
 msgstr "Sie haben die Dateiübertragung von %s abgebrochen"
 
+#, c-format
 msgid "File transfer cancelled"
 msgstr "Dateiübertragung wurde abgebrochen"
 
@@ -2143,6 +2148,7 @@
 msgid "You are using %s, but this plugin requires %s."
 msgstr "Sie benutzen %s, aber dieses Plugin benötigt %s."
 
+#, c-format
 msgid "This plugin has not defined an ID."
 msgstr "Dieses Plugin hat keine ID definiert."
 
@@ -3038,6 +3044,7 @@
 #. get_yahoo_status_from_purple_status() returns YAHOO_STATUS_CUSTOM for
 #. * the generic away state (YAHOO_STATUS_TYPE_AWAY) with no message
 #. Away stuff
+#, c-format
 msgid "Away"
 msgstr "Abwesend"
 
@@ -3929,6 +3936,7 @@
 msgid "Extended Away"
 msgstr "Abwesend (erweitert)"
 
+#, c-format
 msgid "Do Not Disturb"
 msgstr "Nicht stören"
 
@@ -4554,6 +4562,11 @@
 msgid "File transfer proxies"
 msgstr "Proxys für Dateiübertragungen"
 
+#. this should probably be part of global smiley theme settings later on,
+#. shared with MSN
+msgid "Show Custom Smileys"
+msgstr "Zeige benutzerdefinierte Smileys"
+
 #, c-format
 msgid "%s has left the conversation."
 msgstr "%s hat das Gespräch verlassen."
@@ -4698,166 +4711,220 @@
 "%s ist auf der lokalen Liste, aber nicht auf der Serverliste. Möchten Sie, "
 "dass der Buddy hinzugefügt wird?"
 
+#, c-format
 msgid "Unable to parse message"
 msgstr "Kann die Nachricht nicht parsen"
 
+#, c-format
 msgid "Syntax Error (probably a client bug)"
 msgstr "Syntaxfehler (wahrscheinlich ein Client-Bug)"
 
+#, c-format
 msgid "Invalid email address"
 msgstr "Ungültige E-Mail-Adresse"
 
+#, c-format
 msgid "User does not exist"
 msgstr "Benutzer existiert nicht"
 
+#, c-format
 msgid "Fully qualified domain name missing"
 msgstr "Der Fully Qualified Domain Name fehlt"
 
+#, c-format
 msgid "Already logged in"
 msgstr "Schon angemeldet"
 
+#, c-format
 msgid "Invalid username"
 msgstr "Ungültiger Benutzername"
 
+#, c-format
 msgid "Invalid friendly name"
 msgstr "Ungültiger Freundesname"
 
+#, c-format
 msgid "List full"
 msgstr "Liste voll"
 
+#, c-format
 msgid "Already there"
 msgstr "Schon da"
 
+#, c-format
 msgid "Not on list"
 msgstr "Nicht auf der Liste"
 
+#, c-format
 msgid "User is offline"
 msgstr "Benutzer ist offline"
 
+#, c-format
 msgid "Already in the mode"
 msgstr "Bereits in diesem Modus"
 
+#, c-format
 msgid "Already in opposite list"
 msgstr "Bereits in der „Gegenteil-Liste“"
 
+#, c-format
 msgid "Too many groups"
 msgstr "Zu viele Gruppen"
 
+#, c-format
 msgid "Invalid group"
 msgstr "Ungültige Gruppe"
 
+#, c-format
 msgid "User not in group"
 msgstr "Benutzer ist nicht in der Gruppe"
 
+#, c-format
 msgid "Group name too long"
 msgstr "Name der Gruppe ist zu lang"
 
+#, c-format
 msgid "Cannot remove group zero"
 msgstr "Kann die Gruppe „Null“ nicht entfernen"
 
+#, c-format
 msgid "Tried to add a user to a group that doesn't exist"
 msgstr ""
 "Versuchte einen Benutzer zu einer nichtexistierenden Gruppe hinzuzufügen"
 
+#, c-format
 msgid "Switchboard failed"
 msgstr "Vermittlung gescheitert"
 
+#, c-format
 msgid "Notify transfer failed"
 msgstr "Übertragung der Benachrichtigung gescheitert"
 
+#, c-format
 msgid "Required fields missing"
 msgstr "Notwendige Felder fehlen"
 
+#, c-format
 msgid "Too many hits to a FND"
 msgstr "Zu viele Treffer zu einem FND"
 
+#, c-format
 msgid "Not logged in"
 msgstr "Nicht angemeldet"
 
+#, c-format
 msgid "Service temporarily unavailable"
 msgstr "Dienst momentan nicht verfügbar"
 
+#, c-format
 msgid "Database server error"
 msgstr "Fehler des Datenbank-Servers"
 
+#, c-format
 msgid "Command disabled"
 msgstr "Kommando abgeschaltet"
 
+#, c-format
 msgid "File operation error"
 msgstr "Dateiverarbeitungsfehler"
 
+#, c-format
 msgid "Memory allocation error"
 msgstr "Fehler bei der Speicheranforderung"
 
+#, c-format
 msgid "Wrong CHL value sent to server"
 msgstr "Falscher CHL-Wert zum Server gesendet"
 
+#, c-format
 msgid "Server busy"
 msgstr "Server beschäftigt"
 
+#, c-format
 msgid "Server unavailable"
 msgstr "Server unerreichbar"
 
+#, c-format
 msgid "Peer notification server down"
 msgstr "Peer-Benachrichtigungsserver nicht erreichbar"
 
+#, c-format
 msgid "Database connect error"
 msgstr "Datenbank-Verbindungsfehler"
 
+#, c-format
 msgid "Server is going down (abandon ship)"
 msgstr "Server fährt runter (melden Sie sich ab)"
 
+#, c-format
 msgid "Error creating connection"
 msgstr "Fehler beim Herstellen der Verbindung"
 
+#, c-format
 msgid "CVR parameters are either unknown or not allowed"
 msgstr "CVR-Parameter sind entweder unbekannt oder nicht erlaubt"
 
+#, c-format
 msgid "Unable to write"
 msgstr "Schreiben nicht möglich"
 
+#, c-format
 msgid "Session overload"
 msgstr "Sitzung überlastet"
 
+#, c-format
 msgid "User is too active"
 msgstr "Benutzer ist zu aktiv"
 
+#, c-format
 msgid "Too many sessions"
 msgstr "Zu viele Sitzungen"
 
+#, c-format
 msgid "Passport not verified"
 msgstr "Passport (MSN Benutzerausweis) wurde nicht überprüft"
 
+#, c-format
 msgid "Bad friend file"
 msgstr "Falsche Friends-Datei"
 
+#, c-format
 msgid "Not expected"
 msgstr "Nicht erwartet"
 
+#, c-format
 msgid "Friendly name changes too rapidly"
 msgstr "Benutzernamen werden zu oft geändert"
 
+#, c-format
 msgid "Server too busy"
 msgstr "Server ist zu beschäftigt"
 
+#, c-format
 msgid "Authentication failed"
 msgstr "Authentifizierung fehlgeschlagen"
 
+#, c-format
 msgid "Not allowed when offline"
 msgstr "Nicht erlaubt im Offline-Modus"
 
+#, c-format
 msgid "Not accepting new users"
 msgstr "Akzeptiert keine neuen Benutzer"
 
+#, c-format
 msgid "Kids Passport without parental consent"
 msgstr "Kinder-Passwort ohne die Zustimmung der Eltern"
 
+#, c-format
 msgid "Passport account not yet verified"
 msgstr "Passport-Konto wurde noch nicht überprüft"
 
+#, c-format
 msgid "Passport account suspended"
 msgstr "Passport-Konto gesperrt"
 
+#, c-format
 msgid "Bad ticket"
 msgstr "Falsches Ticket"
 
@@ -4869,6 +4936,12 @@
 msgid "MSN Error: %s\n"
 msgstr "MSN-Fehler: %s\n"
 
+msgid "Other Contacts"
+msgstr "Andere Kontakte"
+
+msgid "Non-IM Contacts"
+msgstr "Nicht-IM-Kontakte"
+
 msgid "Nudge"
 msgstr "Anstoßen"
 
@@ -4939,6 +5012,9 @@
 msgid "Page"
 msgstr "Nachricht"
 
+msgid "Has you"
+msgstr "Hat Sie"
+
 msgid "Home Phone Number"
 msgstr "Private Telefonnummer"
 
@@ -5221,6 +5297,9 @@
 msgid "Unable to add user"
 msgstr "Kann den Benutzer nicht hinzufügen"
 
+msgid "The following users are missing from your addressbook"
+msgstr "Die folgenden Benutzer fehlen in Ihrem Adressbuch"
+
 #, c-format
 msgid "Unable to add user on %s (%s)"
 msgstr "Kann den Benutzer nicht zu %s (%s) hinzufügen"
@@ -5437,9 +5516,6 @@
 msgid "This Hotmail account may not be active."
 msgstr "Dieses Hotmail-Konto ist vielleicht nicht aktiv."
 
-msgid "Has you"
-msgstr "Hat Sie"
-
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -6073,6 +6149,7 @@
 msgid "Error. SSL support is not installed."
 msgstr "Fehler. SSL ist nicht installiert."
 
+#, c-format
 msgid "This conference has been closed. No more messages can be sent."
 msgstr ""
 "Diese Konferenz wurde geschlossen. Es können keine Nachrichten mehr gesendet "
@@ -6130,6 +6207,9 @@
 msgid "AIM Protocol Plugin"
 msgstr "AIM-Protokoll-Plugin"
 
+msgid "ICQ UIN..."
+msgstr "ICQ-UIN..."
+
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -6193,7 +6273,7 @@
 msgstr "Bewertung zum Client"
 
 msgid "Service unavailable"
-msgstr "Server unerreichbar"
+msgstr "Dienst nicht unerreichbar"
 
 msgid "Service not defined"
 msgstr "Dienst nicht definiert"
@@ -6339,18 +6419,23 @@
 msgid "Screen Sharing"
 msgstr "Gemeinsamer Bildschirm"
 
+#, c-format
 msgid "Free For Chat"
 msgstr "Bereit zum Chatten"
 
+#, c-format
 msgid "Not Available"
 msgstr "Nicht verfügbar"
 
+#, c-format
 msgid "Occupied"
 msgstr "Beschäftigt"
 
+#, c-format
 msgid "Web Aware"
 msgstr "In Web"
 
+#, c-format
 msgid "Invisible"
 msgstr "Unsichtbar"
 
@@ -7046,6 +7131,7 @@
 msgid "Attempting to connect to %s:%hu."
 msgstr "Verbindungsversuch mit %s:%hu."
 
+#, c-format
 msgid "Attempting to connect via proxy server."
 msgstr "Verbindungsversuch über einen Proxyserver."
 
@@ -7173,14 +7259,23 @@
 msgid "Other"
 msgstr "Andere"
 
-msgid "Modify my information"
-msgstr "Meine Informationen bearbeiten"
-
-msgid "Update my information"
-msgstr "Meine Informationen aktualisieren"
-
-msgid "Your information has been updated"
-msgstr "Ihre Informationen wurden aktualisiert"
+msgid "Modify information"
+msgstr "Informationen bearbeiten"
+
+msgid "Update information"
+msgstr "Informationen aktualisieren"
+
+#. TODO: We don't really need to notify the user about this, do we?
+#. TODO: Does the user really need to be notified about this?
+msgid "QQ Buddy"
+msgstr "QQ-Buddy"
+
+#, fuzzy
+msgid "Successed:"
+msgstr "Geschwindigkeit:"
+
+msgid "Change buddy information."
+msgstr "Buddy-Informationen bearbeiten"
 
 #, c-format
 msgid ""
@@ -7198,30 +7293,29 @@
 msgid "You rejected %d's request"
 msgstr "Sie haben die Anfrage von %d abgelehnt"
 
-msgid "Input your reason:"
-msgstr "Geben Sie Ihren Grund an:"
-
 msgid "Reject request"
 msgstr "Anfrage ablehnen"
 
 #. title
-msgid "Sorry, you are not my type..."
+msgid "Sorry, you are not my style..."
 msgstr "Tut mir Leid, du bist nicht mein Typ..."
 
 msgid "Add buddy with auth request failed"
 msgstr "Benutzer hinzufügen, wenn Autorisierungsanfrage fehlschlug"
 
-#. TODO: We don't really need to notify the user about this, do we?
-msgid "You have successfully removed a buddy"
-msgstr "Sie haben einen Buddy entfernt"
-
-#. TODO: Does the user really need to be notified about this?
-msgid "You have successfully removed yourself from your friend's buddy list"
-msgstr "Sie haben sich erfolgreich von der Kontaktliste Ihres Freunds entfernt"
-
-#, c-format
-msgid "User %d needs authentication"
-msgstr "Benutzer %d benötigt Authentifizierung"
+msgid "Failed:"
+msgstr "Gescheitert:"
+
+msgid "Remove buddy"
+msgstr "Buddy entfernen"
+
+#, fuzzy
+msgid "Remove from other's buddy list"
+msgstr "Von seiner/ihrer Buddy-Liste entfernen"
+
+#, c-format
+msgid "%d needs authentication"
+msgstr "%d benötigt Authentifizierung"
 
 msgid "Input request here"
 msgstr "Anfrage hier eingeben"
@@ -7237,14 +7331,14 @@
 msgstr "Senden"
 
 #, c-format
-msgid "You have added %d to buddy list"
-msgstr "Sie haben %d zu Ihrer Buddy-Liste hinzugefügt"
-
-msgid "QQid Error"
-msgstr "QQid-Fehler"
-
-msgid "Invalid QQid"
-msgstr "Ungültige QQid"
+msgid "Add into %d's buddy list"
+msgstr "Zu %ds Buddy-Liste hinzufügen"
+
+msgid "QQ Number Error"
+msgstr "Fehler in QQ-Nummer"
+
+msgid "Invalid QQ Number"
+msgstr "Ungültige QQ-Nummer"
 
 msgid "ID: "
 msgstr "ID: "
@@ -7264,19 +7358,19 @@
 msgid "QQ Qun"
 msgstr "QQ-Qun"
 
-msgid "Please enter external group ID"
-msgstr "Bitte geben Sie die externe Gruppen-ID an"
-
-msgid "You can only search for permanent QQ groups\n"
-msgstr "Sie können nur nach permanenten QQ-Gruppen suchen\n"
-
-#, c-format
-msgid "User %d requested to join group %d"
-msgstr "Benutzer %d möchte der Gruppe %d beitreten"
-
-#, c-format
-msgid "Reason: %s"
-msgstr "Grund: %s"
+msgid "Please enter Qun number"
+msgstr "Bitte geben Sie die Qun-Nummer ein"
+
+msgid "You can only search for permanent Qun\n"
+msgstr "Sie können nur nach permanenten Qun suchen\n"
+
+#, c-format
+msgid "%d request to join Qun %d"
+msgstr "%d möchte dem Qun %d beitreten"
+
+#, c-format
+msgid "Message: %s"
+msgstr "Nachricht: %s"
 
 msgid "QQ Qun Operation"
 msgstr "QQ-Qun-Operation"
@@ -7284,24 +7378,24 @@
 msgid "Approve"
 msgstr "Akzeptieren"
 
-#, c-format
-msgid "Your request to join group %d has been rejected by admin %d"
+#, fuzzy, c-format
+msgid "Failed to join Qun %d, operated by admin %d"
+msgstr "Dem Qun %d, moderiert von admin %d, konnte nicht beigetreten werden"
+
+#, fuzzy, c-format
+msgid "Successed to join Qun %d, operated by admin %d"
 msgstr "Ihre Anfrage, der Gruppe %d beizutreten wurde von Admin %d abgelehnt"
 
 #, c-format
-msgid "Your request to join group %d has been approved by admin %d"
-msgstr "Ihre Anfrage, der Gruppe %d beizutreten wurde von Admin %d akzeptiert"
-
-#, c-format
-msgid "You [%d] have left group \"%d\""
-msgstr "Sie [%d] haben die Gruppe „%d“ verlassen"
-
-#, c-format
-msgid "You [%d] have been added to group \"%d\""
-msgstr "Sie [%d] wurden der Gruppe „%d“ hinzugefügt"
-
-msgid "This group has been added to your buddy list"
-msgstr "Diese Gruppe wurde Ihrer Buddy-Liste hinzugefügt"
+msgid "[%d] removed from Qun \"%d\""
+msgstr "[%d] vom Qun „%d“ entfernt"
+
+msgid "Notice:"
+msgstr "Bemerkung:"
+
+#, c-format
+msgid "[%d] added to Qun \"%d\""
+msgstr "[%d] zum Qun „%d“ hinzugefügt"
 
 msgid "I am not a member"
 msgstr "Ich bin kein Mitglied"
@@ -7309,8 +7403,9 @@
 msgid "I am a member"
 msgstr "Ich bin Mitglied"
 
-msgid "I am applying to join"
-msgstr "Ich möchte beitreten"
+#, fuzzy
+msgid "I am requesting"
+msgstr "Ich frage an"
 
 msgid "I am the admin"
 msgstr "Ich bin der Admin"
@@ -7318,17 +7413,22 @@
 msgid "Unknown status"
 msgstr "Unbekannter Status"
 
-msgid "This group does not allow others to join"
-msgstr "Dieser Gruppe können andere nicht beitreten"
-
-msgid "You have successfully left the group"
-msgstr "Sie haben die Gruppe erfolgreich verlassen"
-
-msgid "QQ Group Auth"
-msgstr "QQ-Gruppenauthentifikation"
-
-msgid "Your authorization request has been accepted by the QQ server"
-msgstr "Ihre Autorisierungsanfrage wurde vom QQ-Server akzeptiert"
+msgid "The Qun does not allow others to join"
+msgstr "Diesen Qun können andere nicht beitreten"
+
+msgid "Remove from Qun"
+msgstr "vom Qun entfernen"
+
+#, fuzzy
+msgid "Join to Qun"
+msgstr "Chat betreten"
+
+#, c-format
+msgid "Qun %d denied to join"
+msgstr ""
+
+msgid "Join Qun, Unknow Reply"
+msgstr ""
 
 msgid "You entered a group ID outside the acceptable range"
 msgstr "Sie haben eine Gruppen-ID außerhalb des erlaubten Bereichs angegeben"
@@ -7347,24 +7447,36 @@
 msgid "Do you want to approve the request?"
 msgstr "Wollen sie die Anfrage akzeptieren?"
 
-msgid "Enter your reason:"
-msgstr "Geben Sie Ihren Grund an:"
-
-msgid "You have successfully modified Qun member"
-msgstr "Sie haben die Qun-Mitgliedschaft erfolgreich modifiziert"
-
-msgid "You have successfully modified Qun information"
-msgstr "Sie haben die Qun-Information erfolgreich modifiziert"
+#, fuzzy
+msgid "Change Qun member"
+msgstr "Telefonnummer"
+
+msgid "Change Qun information"
+msgstr "Qun-Informationen bearbeiten"
 
 msgid "You have successfully created a Qun"
 msgstr "Sie haben einen Qun angelegt"
 
-msgid "Would you like to set up the Qun details now?"
+#, fuzzy
+msgid "Would you like to set up the detail information now?"
 msgstr "Möchten Sie jetzt die Qun-Details einstellen?"
 
 msgid "Setup"
 msgstr "Setup"
 
+#, fuzzy, c-format
+msgid ""
+"%s\n"
+"\n"
+"%s"
+msgstr ""
+"%s\n"
+"\n"
+"%s"
+
+msgid "QQ Server News"
+msgstr "QQ-Server-News"
+
 msgid "System Message"
 msgstr "Systemnachricht"
 
@@ -7396,8 +7508,9 @@
 msgid " Video"
 msgstr " Video"
 
-msgid " Space"
-msgstr " Raum"
+#, fuzzy
+msgid " Zone"
+msgstr " Zone"
 
 msgid "Flag"
 msgstr "Flagge"
@@ -7417,20 +7530,36 @@
 msgstr "<b>Letzte Aktualisierung</b>: %s<br>\n"
 
 #, c-format
-msgid "<b>Server</b>: %s: %d<br>\n"
-msgstr "<b>Server</b>: %s: %d<br>\n"
+msgid "<b>Server</b>: %s<br>\n"
+msgstr "<b>Server</b>: %s<br>\n"
 
 #, c-format
 msgid "<b>Connection Mode</b>: %s<br>\n"
 msgstr "<b>Verbindungsmodus</b>: %s<br>\n"
 
 #, c-format
-msgid "<b>Real hostname</b>: %s: %d<br>\n"
-msgstr "<b>Wirklicher Hostname</b>: %s: %d<br>\n"
-
-#, c-format
-msgid "<b>My Public IP</b>: %s<br>\n"
-msgstr "<b>Meine öffentlich IP</b>: %s<br>\n"
+msgid "<b>My Internet Address</b>: %s<br>\n"
+msgstr "<b>Meine Internet-Adresse</b>: %s<br>\n"
+
+#, c-format
+msgid "<b>Sent</b>: %lu<br>\n"
+msgstr "<b>Gesendet</b>: %lu<br>\n"
+
+#, c-format
+msgid "<b>Resend</b>: %lu<br>\n"
+msgstr "<b>Erneut senden</b>: %lu<br>\n"
+
+#, c-format
+msgid "<b>Lost</b>: %lu<br>\n"
+msgstr "<b>Verloren</b>: %lu<br>\n"
+
+#, c-format
+msgid "<b>Received</b>: %lu<br>\n"
+msgstr "<b>Empfangen</b>: %lu<br>\n"
+
+#, c-format
+msgid "<b>Received Duplicate</b>: %lu<br>\n"
+msgstr "<b>Duplikat empfangen</b>: %lu<br>\n"
 
 #, c-format
 msgid "<b>Login Time</b>: %s<br>\n"
@@ -7453,11 +7582,11 @@
 msgid "Change Password"
 msgstr "Passwort ändern"
 
-msgid "Show Login Information"
-msgstr "Login-Informationen anzeigen"
-
-msgid "Leave this QQ Qun"
-msgstr "Dieses QQ-Qun verlassen"
+msgid "Account Information"
+msgstr "Kontoinformationen"
+
+msgid "Leave the QQ Qun"
+msgstr "Diesen QQ-Qun verlassen"
 
 msgid "Block this buddy"
 msgstr "Diesen Buddy blockieren"
@@ -7475,11 +7604,18 @@
 msgid "QQ Protocol\tPlugin"
 msgstr "QQ-Protokoll-Plugin"
 
-msgid "Connect using TCP"
+msgid "Auto"
+msgstr "Auto"
+
+#, fuzzy
+msgid "Connect by TCP"
 msgstr "Über TCP verbinden"
 
-msgid "resend interval(s)"
-msgstr "Neusenden-Intervall(e)"
+msgid "Show server notice"
+msgstr "Server-Nachricht anzeigen"
+
+msgid "Show server news"
+msgstr "Server-News anzeigen"
 
 msgid "Keep alive interval(s)"
 msgstr "Intervall(e) zum Aufrechterhalten der Verbindung (Keep alive)"
@@ -7488,15 +7624,39 @@
 msgstr "Aktualisierungsintervall(e)"
 
 #, c-format
+msgid "Invalid token reply code, 0x%02X"
+msgstr "Ungültiger Token-Antwort-Code, 0x%02X"
+
+#, c-format
 msgid "Invalid token len, %d"
 msgstr "Ungültige Länge des Tokens, %d"
 
+msgid "Unable login for not support Redirect_EX now"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Error password: %s"
+msgstr "Fehler beim Ändern des Passworts"
+
+#, c-format
+msgid "Need active: %s"
+msgstr ""
+
+#, fuzzy, c-format
+msgid "Unable login for unknow reply code 0x%02X"
+msgstr "Ungültiger Token-Antwort-Code, 0x%02X"
+
 msgid "Keep alive error"
 msgstr "Fehler beim Aufrechterhalten der Verbindung (Keep alive)"
 
-msgid "Failed to connect server"
+#, fuzzy
+msgid "Failed to connect all servers"
 msgstr "Verbinden zum Server fehlgeschlagen"
 
+#. we didn't successfully connect. tdt->toc_fd is valid here
+msgid "Unable to connect."
+msgstr "Verbindung nicht möglich."
+
 msgid "Socket error"
 msgstr "Socket-Fehler"
 
@@ -7517,54 +7677,50 @@
 msgid "Connection lost"
 msgstr "Verbindung verloren"
 
+#. Update the login progress status display
+#, fuzzy, c-format
+msgid "Request token"
+msgstr "Anfrage verweigert"
+
 msgid "Couldn't resolve host"
 msgstr "Kann den Hostnamen nicht auflösen"
 
-msgid "hostname is NULL or port is 0"
-msgstr "Hostname ist NULL oder Port ist 0"
+msgid "Invalid server or port"
+msgstr "Ungültiger Server oder Port"
 
 #, c-format
 msgid "Connecting server %s, retries %d"
 msgstr "Verbinde zu Server %s, %d Wiederholungen"
 
-#. we didn't successfully connect. tdt->toc_fd is valid here
-msgid "Unable to connect."
-msgstr "Verbindung nicht möglich."
-
-msgid "Could not resolve hostname"
-msgstr "Konnte den Hostnamen nicht auflösen"
-
-msgid "Unable to login. Check debug log."
-msgstr "Anmeldung fehlgeschlagen, Debugmitschnitt beachten."
-
-msgid "Unable to login"
-msgstr "Anmeldung fehlgeschlagen"
-
-#, c-format
-msgid ""
-"Reply %s(0x%02X )\n"
-"Sent %s(0x%02X )\n"
-"Room id %d, reply [0x%02X]: \n"
-"%s"
+msgid "QQ Error"
+msgstr "QQ-Fehler"
+
+msgid "Unknow SERVER CMD"
+msgstr ""
+
+#, fuzzy, c-format
+msgid ""
+"Error reply of %s(0x%02X)\n"
+"Room %d, reply 0x%02X"
 msgstr ""
 "Antwort %s(0x%02X )\n"
 "Gesendet %s(0x%02X )\n"
 "Raum-ID %d, Antwort [0x%02X]: \n"
 "%s"
 
-msgid "Failed room reply"
-msgstr "Antwort vom Raum gescheitert"
-
-#, c-format
-msgid "You are not a member of group \"%s\"\n"
-msgstr "Sie sind ein Mitglied der Gruppe „%s“\n"
+msgid "QQ Qun Command"
+msgstr "QQ-Qun-Kommando"
+
+#, c-format
+msgid "You are not a member of QQ Qun \"%s\"\n"
+msgstr "Sie sind kein Mitglied des Qun „%s“\n"
 
 msgid "Can not decrypt login reply"
 msgstr "Kann die Antwort der Anmeldung nicht entschlüsseln"
 
-#, c-format
-msgid "Invalid token reply code, 0x%02X"
-msgstr "Ungültiger Token-Antwort-Code, 0x%02X"
+#, fuzzy
+msgid "Unknow reply CMD"
+msgstr "Unbekannter Grund"
 
 #, c-format
 msgid "%d has declined the file %s"
@@ -7577,7 +7733,12 @@
 msgid "%d canceled the transfer of %s"
 msgstr "%d hat die Übertragung von %s abgebrochen"
 
-msgid "Do you want to add this buddy?"
+#, fuzzy
+msgid "Do you approve the requestion?"
+msgstr "Wollen sie die Anfrage akzeptieren?"
+
+#, fuzzy
+msgid "Do you add the buddy?"
 msgstr "Möchten Sie diesen Buddy hinzufügen?"
 
 #. only need to get value
@@ -7588,39 +7749,46 @@
 msgid "Would you like to add him?"
 msgstr "Möchten Sie ihn hinzufügen?"
 
-#, c-format
-msgid "%s has added you [%s] to his or her buddy list"
+#, fuzzy, c-format
+msgid "%s added you [%s] to buddy list"
 msgstr "%s hat Sie [%s] zu seiner Buddy-Liste hinzugefügt"
 
-#, c-format
-msgid "User %s rejected your request"
-msgstr "Benutzer %s hat Ihre Anfrage abgelehnt"
-
-#, c-format
-msgid "User %s approved your request"
-msgstr "Benutzer %s hat Ihre Anfrage akzeptiert"
+#, fuzzy
+msgid "QQ Budy"
+msgstr "Buddy"
+
+#, c-format
+msgid "Requestion rejected by %s"
+msgstr ""
+
+#, c-format
+msgid "Requestion approved by %s"
+msgstr ""
 
 #. TODO: this should go through purple_account_request_authorization()
 #, c-format
 msgid "%s wants to add you [%s] as a friend"
 msgstr "%s möchte Sie [%s] als Freund hinzufügen"
 
-#, c-format
-msgid "Message: %s"
-msgstr "Nachricht: %s"
-
-#, c-format
-msgid "%s is not in your buddy list"
+#, fuzzy, c-format
+msgid "%s is not in buddy list"
 msgstr "%s ist nicht in Ihrer Buddy-Liste"
 
-#, c-format
-msgid "Notice from: %s"
-msgstr "Ankündigung von %s"
+#, fuzzy
+msgid "Would you add?"
+msgstr "Möchten Sie ihn hinzufügen?"
+
+#, c-format
+msgid "From %s:"
+msgstr "Von %s:"
 
 #, c-format
 msgid "%s"
 msgstr "%s"
 
+msgid "QQ Server Notice"
+msgstr "QQ-Server-Nachricht"
+
 msgid "Connection closed (writing)"
 msgstr "Verbindung geschlossen (schreibend)"
 
@@ -8221,6 +8389,7 @@
 msgid "<br><b>Channel Topic:</b><br>%s"
 msgstr "<br><b>Thema des Kanals:</b><br>%s"
 
+#, c-format
 msgid "<br><b>Channel Modes:</b> "
 msgstr "<br><b>Kanal-Modi:</b> "
 
@@ -8245,6 +8414,7 @@
 msgid "Channel Public Keys List"
 msgstr "Liste der öffentlichen Schlüssel des Kanals"
 
+#, c-format
 msgid ""
 "Channel authentication is used to secure the channel from unauthorized "
 "access. The authentication may be based on passphrase and digital "
@@ -8649,6 +8819,7 @@
 msgid "Your Current Mood"
 msgstr "Ihre momentane Stimmung"
 
+#, c-format
 msgid "Normal"
 msgstr "Normal"
 
@@ -9034,37 +9205,47 @@
 msgid "No server statistics available"
 msgstr "Keine Serverstatistik verfügbar"
 
+#, c-format
 msgid "Failure: Version mismatch, upgrade your client"
 msgstr "Fehler: Unterschiedliche Version, aktualisieren Sie Ihren Client"
 
+#, c-format
 msgid "Failure: Remote does not trust/support your public key"
 msgstr ""
 "Fehler: Die entfernte Seite vertraut Ihrem öffentlichen Schlüssel nicht"
 
+#, c-format
 msgid "Failure: Remote does not support proposed KE group"
 msgstr ""
 "Fehler: Entferntes Programm unterstützt nicht die vorgeschlagen KE-Gruppe"
 
+#, c-format
 msgid "Failure: Remote does not support proposed cipher"
 msgstr ""
 "Fehler: Entferntes Programm unterstützt die vorgeschlagene Cipher nicht"
 
+#, c-format
 msgid "Failure: Remote does not support proposed PKCS"
 msgstr "Fehler: Entferntes Programm unterstützt die vorgeschlagene PKCS nicht"
 
+#, c-format
 msgid "Failure: Remote does not support proposed hash function"
 msgstr ""
 "Fehler: Entferntes Programm unterstützt die vorgeschlagen Hashfunktion nicht"
 
+#, c-format
 msgid "Failure: Remote does not support proposed HMAC"
 msgstr "Fehler: Entferntes Programm unterstützt das vorgeschlagene HMAC nicht"
 
+#, c-format
 msgid "Failure: Incorrect signature"
 msgstr "Fehler: Falsche Signatur"
 
+#, c-format
 msgid "Failure: Invalid cookie"
 msgstr "Fehler: Ungültiger Cookie"
 
+#, c-format
 msgid "Failure: Authentication failed"
 msgstr "Fehler: Authentifizierung fehlgeschlagen"
 
@@ -9090,6 +9271,9 @@
 msgid "Could not create listen socket"
 msgstr "Kann Listen-Socket nicht erstellen"
 
+msgid "Could not resolve hostname"
+msgstr "Konnte den Hostnamen nicht auflösen"
+
 msgid "SIP usernames may not contain whitespaces or @ symbols"
 msgstr "SIP-Benutzernamen dürfen keine Leerzeichen oder @-Symbole enthalten"
 
@@ -9158,6 +9342,7 @@
 msgid "Warning of %s not allowed."
 msgstr "Verwarnung von %s nicht erlaubt."
 
+#, c-format
 msgid "A message has been dropped, you are exceeding the server speed limit."
 msgstr ""
 "Eine Nachricht ging verloren. Sie überschreiten die Geschwindigkeitsgrenze "
@@ -9181,30 +9366,39 @@
 "Eine Nachricht von %s hat Sie nicht erreicht, da sie zu schnell gesendet "
 "wurde."
 
+#, c-format
 msgid "Failure."
 msgstr "Fehler."
 
+#, c-format
 msgid "Too many matches."
 msgstr "Zu viele Übereinstimmungen."
 
+#, c-format
 msgid "Need more qualifiers."
 msgstr "Benötige mehr Angaben."
 
+#, c-format
 msgid "Dir service temporarily unavailable."
 msgstr "Verzeichnis-Dienst ist zur Zeit nicht verfügbar."
 
+#, c-format
 msgid "Email lookup restricted."
 msgstr "E-Mail-Suche eingeschränkt."
 
+#, c-format
 msgid "Keyword ignored."
 msgstr "Stichwort ignoriert."
 
+#, c-format
 msgid "No keywords."
 msgstr "Keine Stichwörter."
 
+#, c-format
 msgid "User has no directory information."
 msgstr "Der Benutzer hat kein Profil."
 
+#, c-format
 msgid "Country not supported."
 msgstr "Land nicht unterstützt."
 
@@ -9212,15 +9406,19 @@
 msgid "Failure unknown: %s."
 msgstr "Unbekannter Fehler: %s."
 
+#, c-format
 msgid "Incorrect username or password."
 msgstr "Ungültiger Benutzername oder Passwort."
 
+#, c-format
 msgid "The service is temporarily unavailable."
 msgstr "Der Dienst ist zur Zeit nicht verfügbar."
 
+#, c-format
 msgid "Your warning level is currently too high to log in."
 msgstr "Ihre Warnstufe ist zur Zeit zu hoch, um sich anzumelden."
 
+#, c-format
 msgid ""
 "You have been connecting and disconnecting too frequently.  Wait ten minutes "
 "and try again.  If you continue to try, you will need to wait even longer."
@@ -9474,6 +9672,9 @@
 msgid "doodle: Request user to start a Doodle session"
 msgstr "doodle: Einen Benutzer auffordern, eine Mal-Sitzung zu starten"
 
+msgid "Yahoo ID..."
+msgstr "Yahoo-ID..."
+
 #. *< type
 #. *< ui_requirement
 #. *< flags
@@ -10029,6 +10230,10 @@
 msgstr "Verbindung zu %s nicht möglich"
 
 #, c-format
+msgid "Error reading from %s: response too long (%d bytes limit)"
+msgstr "Fehler beim Lesen von %s: Antwort zu lang (%d Bytes maximal)"
+
+#, c-format
 msgid ""
 "Unable to allocate enough memory to hold the contents from %s.  The web "
 "server may be trying something malicious."
@@ -10057,24 +10262,29 @@
 msgstr " (%s)"
 
 #. 10053
+#, c-format
 msgid "Connection interrupted by other software on your computer."
 msgstr ""
 "Die Verbindung wurde von einer anderen Software auf ihrem Computer "
 "unterbrochen."
 
 #. 10054
+#, c-format
 msgid "Remote host closed connection."
 msgstr "Der entfernte Host hat die Verbindung beendet."
 
 #. 10060
+#, c-format
 msgid "Connection timed out."
 msgstr "Verbindungsabbruch wegen Zeitüberschreitung."
 
 #. 10061
+#, c-format
 msgid "Connection refused."
 msgstr "Verbindung abgelehnt."
 
 #. 10048
+#, c-format
 msgid "Address already in use."
 msgstr "Adresse wird bereits benutzt."
 
@@ -11305,6 +11515,7 @@
 "geschützt.  Die Datei 'COPYRIGHT' enthält die komplette Liste der "
 "Mitwirkenden.  Wir übernehmen keine Haftung für dieses Programm.<BR><BR>"
 
+#, c-format
 msgid "<FONT SIZE=\"4\">IRC:</FONT> #pidgin on irc.freenode.net<BR><BR>"
 msgstr "<FONT SIZE=\"4\">IRC:</FONT> #pidgin auf irc.freenode.net<BR><BR>"
 
@@ -11559,6 +11770,13 @@
 msgid "Color to draw hyperlinks."
 msgstr "Farbe zum Darstellen von Hyperlinks."
 
+msgid "Hyperlink visited color"
+msgstr "Farbe für besuchte Hyperlinks"
+
+msgid "Color to draw hyperlinks after it has been visited (or activated)."
+msgstr ""
+"Farbe zum Darstellen von Hyperlinks, wenn sie besucht (oder aktiviert) wurden"
+
 msgid "Hyperlink prelight color"
 msgstr "Hyperlink-Farbe"
 
@@ -11667,9 +11885,11 @@
 msgid "Save Image"
 msgstr "Bild speichern"
 
+#, c-format
 msgid "_Save Image..."
 msgstr "Bild _speichern..."
 
+#, c-format
 msgid "_Add Custom Smiley..."
 msgstr "Benutzerdefinierten Smiley _hinzufügen..."
 
@@ -12394,21 +12614,27 @@
 msgid "Sound Selection"
 msgstr "Klang-Auswahl"
 
+#, c-format
 msgid "Quietest"
 msgstr "Am leisesten"
 
+#, c-format
 msgid "Quieter"
 msgstr "Leiser"
 
+#, c-format
 msgid "Quiet"
 msgstr "Leise"
 
+#, c-format
 msgid "Loud"
 msgstr "Laut"
 
+#, c-format
 msgid "Louder"
 msgstr "Lauter"
 
+#, c-format
 msgid "Loudest"
 msgstr "Am lautesten"
 
@@ -12429,13 +12655,19 @@
 "Klang-_Abspielbefehl:\n"
 "(%s für den Dateinamen)"
 
+#, fuzzy
+msgid "M_ute sounds"
+msgstr "Stu_mmschalten"
+
 msgid "Sounds when conversation has _focus"
 msgstr "Klang, wenn das Gespräch den _Fokus hat"
 
-msgid "Enable sounds:"
+#, fuzzy
+msgid "_Enable sounds:"
 msgstr "Klänge aktivieren:"
 
-msgid "Volume:"
+#, fuzzy
+msgid "V_olume:"
 msgstr "Lautstärke:"
 
 msgid "Play"
@@ -13385,6 +13617,9 @@
 msgid "Hyperlink Color"
 msgstr "Hyperlink-Farbe"
 
+msgid "Visited Hyperlink Color"
+msgstr "Farbe für besuchte Hyperlinks"
+
 msgid "Highlighted Message Name Color"
 msgstr "Farbe des Absendernamens für hervorgehobene Nachrichten"
 
@@ -13403,6 +13638,7 @@
 msgid "Select Color"
 msgstr "Farbe auswählen"
 
+#, c-format
 msgid "Select Interface Font"
 msgstr "Schriftart wählen"
 
@@ -13629,6 +13865,7 @@
 msgid "Timestamp Format Options"
 msgstr "Zeitstempelformat-Optionen"
 
+#, c-format
 msgid "_Force 24-hour time format"
 msgstr "_Erzwinge 24-Stunden Zeitformat"