changeset 30789:0d5dab71be7a

propagate from branch 'im.pidgin.pidgin' (head 637cbec3044756a8ef4273f687d84b18f10b05c4) to branch 'im.pidgin.soc.2010.icq-tlc' (head 12dd3c1a3cb110106f7ef72077145596ea358642)
author ivan.komarov@soc.pidgin.im
date Sun, 23 May 2010 17:22:51 +0000
parents 053776c347c8 (current diff) 173e403cffbb (diff)
children 674a656893a3
files
diffstat 38 files changed, 2725 insertions(+), 1814 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Thu May 20 13:51:24 2010 +0000
+++ b/COPYRIGHT	Sun May 23 17:22:51 2010 +0000
@@ -481,6 +481,7 @@
 Marcus Sundberg
 Mårten Svantesson (fursten)
 Amir Szekely (kichik)
+Gábor Szuromi (kukkerman)
 Robert T.
 Greg Taeger
 Rob Taft
--- a/ChangeLog	Thu May 20 13:51:24 2010 +0000
+++ b/ChangeLog	Sun May 23 17:22:51 2010 +0000
@@ -17,6 +17,12 @@
 	MSN:
 	* Fix unnecessary bandwidth consumption for buddy icon requests when
 	  buddies have capital letters in their passport addresses.
+	* Support for direct connections, enabling faster file transfers,
+	  smiley and buddy icon loading.  (Gábor Szuromi)
+
+	XMPP:
+	* Allow connecting to servers that advertise EXTERNAL (broken in
+	  2.7.0)
 
 version 2.7.0 (05/12/2010):
 	General:
--- a/libpurple/protocols/jabber/auth_cyrus.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/jabber/auth_cyrus.c	Sun May 23 17:22:51 2010 +0000
@@ -270,7 +270,7 @@
 					 */
 					js->auth_mech = NULL;
 					jabber_auth_start_old(js);
-					return JABBER_SASL_STATE_CONTINUE;					
+					return JABBER_SASL_STATE_CONTINUE;
 				}
 
 				break;
@@ -399,6 +399,7 @@
                    xmlnode **reply, char **error)
 {
 	xmlnode *mechnode;
+	JabberSaslState ret;
 
 	js->sasl_mechs = g_string_new("");
 
@@ -407,7 +408,8 @@
 	{
 		char *mech_name = xmlnode_get_data(mechnode);
 
-		if (!mech_name || !*mech_name) {
+		if (!mech_name || !*mech_name ||
+				g_str_equal(mech_name, "EXTERNAL")) {
 			g_free(mech_name);
 			continue;
 		}
@@ -418,7 +420,16 @@
 	}
 
 	jabber_sasl_build_callbacks(js);
-	return jabber_auth_start_cyrus(js, reply, error);
+	ret = jabber_auth_start_cyrus(js, reply, error);
+
+	/*
+	 * Triggered if no overlap between server and client
+	 * supported mechanisms.
+	 */
+	if (ret == JABBER_SASL_STATE_FAIL && *error == NULL)
+		*error = g_strdup(_("Server does not use any supported authentication method"));
+
+	return ret;
 }
 
 static JabberSaslState
@@ -540,7 +551,7 @@
 
 			return jabber_auth_start_cyrus(js, reply, error);
 
-		} else if ((js->auth_fail_count == 1) && 
+		} else if ((js->auth_fail_count == 1) &&
 				   (js->current_mech && g_str_equal(js->current_mech, "GSSAPI"))) {
 			/* If we tried GSSAPI first, it failed, and it was the only method we had to try, try jabber:iq:auth
 			 * for compatibility with iChat 10.5 Server and other jabberd based servers.
--- a/libpurple/protocols/jabber/auth_scram.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/jabber/auth_scram.c	Sun May 23 17:22:51 2010 +0000
@@ -517,13 +517,24 @@
 	gsize len;
 
 	enc_in = xmlnode_get_data(packet);
-	g_return_val_if_fail(enc_in != NULL && *enc_in != '\0', FALSE);
+	if (data->step != 3 && (!enc_in || *enc_in == '\0')) {
+		*error = g_strdup(_("Invalid challenge from server"));
+		g_free(enc_in);
+		return JABBER_SASL_STATE_FAIL;
+	}
 
-	if (data->step == 3)
+	if (data->step == 3) {
+		/*
+		 * If the server took the slow approach (sending the verifier
+		 * as a challenge/response pair), we get here.
+		 */
+		g_free(enc_in);
 		return JABBER_SASL_STATE_OK;
+	}
 
 	if (data->step != 2) {
 		*error = g_strdup(_("Unexpected response from server"));
+		g_free(enc_in);
 		return JABBER_SASL_STATE_FAIL;
 	}
 
@@ -532,7 +543,7 @@
 	if (!dec_in || len != strlen(dec_in)) {
 		/* Danger afoot; SCRAM shouldn't contain NUL bytes */
 		g_free(dec_in);
-		*error = g_strdup(_("Invalid challenge from server"));
+		*error = g_strdup(_("Malicious challenge from server"));
 		return JABBER_SASL_STATE_FAIL;
 	}
 
--- a/libpurple/protocols/msn/Makefile.am	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/Makefile.am	Sun May 23 17:22:51 2010 +0000
@@ -14,6 +14,8 @@
 	contact.h\
 	dialog.c \
 	dialog.h \
+	directconn.c \
+	directconn.h \
 	error.c \
 	error.h \
 	group.c \
--- a/libpurple/protocols/msn/Makefile.mingw	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/Makefile.mingw	Sun May 23 17:22:51 2010 +0000
@@ -41,6 +41,7 @@
 			command.c \
 			contact.c\
 			dialog.c \
+			directconn.c \
 			error.c \
 			group.c \
 			history.c \
--- a/libpurple/protocols/msn/directconn.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/directconn.c	Sun May 23 17:22:51 2010 +0000
@@ -27,479 +27,976 @@
 #include "slp.h"
 #include "slpmsg.h"
 
-/**************************************************************************
- * Directconn Specific
- **************************************************************************/
-
-void
-msn_directconn_send_handshake(MsnDirectConn *directconn)
-{
-	MsnSlpLink *slplink;
-	MsnSlpMessage *slpmsg;
-
-	g_return_if_fail(directconn != NULL);
-
-	slplink = directconn->slplink;
-
-	slpmsg = msn_slpmsg_new(slplink);
-	slpmsg->flags = 0x100;
-
-	if (directconn->nonce != NULL)
-	{
-		guint32 t1;
-		guint16 t2;
-		guint16 t3;
-		guint16 t4;
-		guint64 t5;
-
-		sscanf (directconn->nonce, "%08X-%04hX-%04hX-%04hX-%012" G_GINT64_MODIFIER "X", &t1, &t2, &t3, &t4, &t5);
-
-		t1 = GUINT32_TO_LE(t1);
-		t2 = GUINT16_TO_LE(t2);
-		t3 = GUINT16_TO_LE(t3);
-		t4 = GUINT16_TO_BE(t4);
-		t5 = GUINT64_TO_BE(t5);
-
-		slpmsg->ack_id     = t1;
-		slpmsg->ack_sub_id = t2 | (t3 << 16);
-		slpmsg->ack_size   = t4 | t5;
-	}
-
-	g_free(directconn->nonce);
-
-	msn_slplink_send_slpmsg(slplink, slpmsg);
-
-	directconn->acked =TRUE;
-}
+#pragma pack(push,1)
+typedef struct {
+	guint32 session_id;
+	guint32 seq_id;
+	guint64 offset;
+	guint64 total_size;
+	guint32 length;
+	guint32 flags;
+	guint32 ack_id;
+	guint32 ack_uid;
+	guint64 ack_size;
+/*	guint8  body[1]; */
+} MsnDcContext;
+#pragma pack(pop)
 
-/**************************************************************************
- * Connection Functions
- **************************************************************************/
-
-static int
-create_listener(int port)
-{
-	int fd;
-	int flags;
-	const int on = 1;
-
-#if 0
-	struct addrinfo hints;
-	struct addrinfo *c, *res;
-	char port_str[5];
-
-	snprintf(port_str, sizeof(port_str), "%d", port);
-
-	memset(&hints, 0, sizeof(hints));
-
-	hints.ai_flags = AI_PASSIVE;
-	hints.ai_family = AF_UNSPEC;
-	hints.ai_socktype = SOCK_STREAM;
+#define DC_PACKET_HEADER_SIZE sizeof(MsnDcContext)
+#define DC_MAX_BODY_SIZE      8*1024
+#define DC_MAX_PACKET_SIZE    (DC_PACKET_HEADER_SIZE + DC_MAX_BODY_SIZE)
 
-	if (getaddrinfo(NULL, port_str, &hints, &res) != 0)
-	{
-		purple_debug_error("msn", "Could not get address info: %s.\n",
-						 port_str);
-		return -1;
-	}
-
-	for (c = res; c != NULL; c = c->ai_next)
-	{
-		fd = socket(c->ai_family, c->ai_socktype, c->ai_protocol);
+static void
+msn_dc_calculate_nonce_hash(MsnDirectConnNonceType type,
+                            const guchar nonce[16], gchar nonce_hash[37])
+{
+	guchar digest[20];
 
-		if (fd < 0)
-			continue;
-
-		setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
-		if (bind(fd, c->ai_addr, c->ai_addrlen) == 0)
-			break;
-
-		close(fd);
-	}
-
-	if (c == NULL)
-	{
-		purple_debug_error("msn", "Could not find socket: %s.\n", port_str);
-		return -1;
+	if (type == DC_NONCE_SHA1) {
+		PurpleCipher *cipher = purple_ciphers_find_cipher("sha1");
+		PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL);
+		purple_cipher_context_append(context, nonce, sizeof(nonce));
+		purple_cipher_context_digest(context, sizeof(digest), digest, NULL);
+		purple_cipher_context_destroy(context);
+	} else if (type == DC_NONCE_PLAIN) {
+		memcpy(digest, nonce, 16);
 	}
 
-	freeaddrinfo(res);
-#else
-	struct sockaddr_in sockin;
-
-	fd = socket(AF_INET, SOCK_STREAM, 0);
-
-	if (fd < 0)
-		return -1;
-
-	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0)
-	{
-		close(fd);
-		return -1;
-	}
-
-	memset(&sockin, 0, sizeof(struct sockaddr_in));
-	sockin.sin_family = AF_INET;
-	sockin.sin_port = htons(port);
-
-	if (bind(fd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0)
-	{
-		close(fd);
-		return -1;
-	}
-#endif
-
-	if (listen (fd, 4) != 0)
-	{
-		close (fd);
-		return -1;
-	}
-
-	flags = fcntl(fd, F_GETFL);
-	fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-#ifndef _WIN32
-	fcntl(fd, F_SETFD, FD_CLOEXEC);
-#endif
-
-	return fd;
+	g_sprintf(nonce_hash,
+	          "%08X-%04X-%04X-%04X-%08X%04X",
+	          GUINT32_FROM_LE(*((guint32 *)(digest + 0))),
+	          GUINT16_FROM_LE(*((guint16 *)(digest + 4))),
+	          GUINT16_FROM_LE(*((guint16 *)(digest + 6))),
+	          GUINT16_FROM_BE(*((guint16 *)(digest + 8))),
+	          GUINT32_FROM_BE(*((guint32 *)(digest + 10))),
+	          GUINT16_FROM_BE(*((guint16 *)(digest + 14)))
+	);
 }
 
-static gssize
-msn_directconn_write(MsnDirectConn *directconn,
-					 const char *data, size_t len)
+static void
+msn_dc_generate_nonce(MsnDirectConn *dc)
 {
-	char *buffer, *tmp;
-	size_t buf_size;
-	gssize ret;
-	guint32 sent_len;
-
-	g_return_val_if_fail(directconn != NULL, 0);
-
-	buf_size = len + 4;
-	buffer = tmp = g_malloc(buf_size);
-
-	sent_len = GUINT32_TO_LE(len);
+	guint32 *nonce;
+	int i;
 
-	memcpy(tmp, &sent_len, 4);
-	tmp += 4;
-	memcpy(tmp, data, len);
-	tmp += len;
-
-	ret = write(directconn->fd, buffer, buf_size);
-
-#ifdef DEBUG_DC
-	char *str;
-	str = g_strdup_printf("%s/msntest/w%.4d.bin", g_get_home_dir(), directconn->c);
+	nonce = (guint32 *)&dc->nonce;
+	for (i = 0; i < 4; i++)
+		nonce[i] = rand();
 
-	FILE *tf = g_fopen(str, "w");
-	fwrite(buffer, 1, buf_size, tf);
-	fclose(tf);
+	msn_dc_calculate_nonce_hash(dc->nonce_type, dc->nonce, dc->nonce_hash);
 
-	g_free(str);
-#endif
-
-	g_free(buffer);
-
-	directconn->c++;
-
-	return ret;
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "DC %p generated nonce %s\n", dc, dc->nonce_hash);
 }
 
-#if 0
-void
-msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce)
+static MsnDirectConnPacket *
+msn_dc_new_packet(guint32 length)
 {
-	guint32 t1;
-	guint16 t2;
-	guint16 t3;
-	guint16 t4;
-	guint64 t5;
-
-	g_return_if_fail(directconn != NULL);
-	g_return_if_fail(nonce      != NULL);
-
-	sscanf (nonce, "%08X-%04hX-%04hX-%04hX-%012llX", &t1, &t2, &t3, &t4, &t5);
+	MsnDirectConnPacket	*p;
 
-	t1 = GUINT32_TO_LE(t1);
-	t2 = GUINT16_TO_LE(t2);
-	t3 = GUINT16_TO_LE(t3);
-	t4 = GUINT16_TO_BE(t4);
-	t5 = GUINT64_TO_BE(t5);
-
-	directconn->slpheader = g_new0(MsnSlpHeader, 1);
+	p = g_new0(MsnDirectConnPacket, 1);
+	p->length = length;
+	p->data = g_malloc(length);
 
-	directconn->slpheader->ack_id     = t1;
-	directconn->slpheader->ack_sub_id = t2 | (t3 << 16);
-	directconn->slpheader->ack_size   = t4 | t5;
-}
-#endif
-
-void
-msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg)
-{
-	char *body;
-	size_t body_len;
-
-	body = msn_message_gen_slp_body(msg, &body_len);
-
-	msn_directconn_write(directconn, body, body_len);
+	return p;
 }
 
 static void
-read_cb(gpointer data, gint source, PurpleInputCondition cond)
+msn_dc_destroy_packet(MsnDirectConnPacket *p)
+{
+	g_free(p->data);
+
+	if (p->msg)
+		msn_message_unref(p->msg);
+
+	g_free(p);
+}
+
+MsnDirectConn *
+msn_dc_new(MsnSlpCall *slpcall)
 {
-	MsnDirectConn* directconn;
-	char *body;
-	size_t body_len;
-	gssize len;
+	MsnDirectConn *dc;
+
+	g_return_val_if_fail(slpcall != NULL, NULL);
+
+	dc = g_new0(MsnDirectConn, 1);
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_new %p\n", dc);
+
+	dc->slplink = slpcall->slplink;
+	dc->slpcall = slpcall;
+
+	if (dc->slplink->dc != NULL)
+		purple_debug_warning("msn", "msn_dc_new: slplink already has an allocated DC!\n");
+
+	dc->slplink->dc = dc;
 
-	purple_debug_info("msn", "read_cb: %d, %d\n", source, cond);
+	dc->msg_body = NULL;
+	dc->prev_ack = NULL;
+	dc->listen_data = NULL;
+	dc->connect_data = NULL;
+	dc->listenfd = -1;
+	dc->listenfd_handle = 0;
+	dc->connect_timeout_handle = 0;
+	dc->fd = -1;
+	dc->recv_handle = 0;
+	dc->send_handle = 0;
+	dc->state = DC_STATE_CLOSED;
+	dc->in_buffer = NULL;
+	dc->out_queue = g_queue_new();
+	dc->msg_pos = -1;
+	dc->send_connection_info_msg_cb = NULL;
+	dc->ext_ip = NULL;
+	dc->timeout_handle = 0;
+	dc->progress = FALSE;
+	/*dc->num_calls = 1;*/
 
-	directconn = data;
+	/* TODO: Probably should set this based on buddy caps */
+	dc->nonce_type = DC_NONCE_PLAIN;
+	msn_dc_generate_nonce(dc);
+
+	return dc;
+}
+
+void
+msn_dc_destroy(MsnDirectConn *dc)
+{
+	MsnSlpLink *slplink;
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_destroy %p\n", dc);
 
-	/* Let's read the length of the data. */
-#error This code is broken.  See the note below.
-	/*
-	 * TODO: This has problems!  First of all, sizeof(body_len) will be
-	 *       different on 32bit systems and on 64bit systems (4 bytes
-	 *       vs. 8 bytes).
-	 *       Secondly, we're reading from a TCP stream.  There is no
-	 *       guarantee that we have received the number of bytes we're
-	 *       trying to read.  We need to read into a buffer.  If read
-	 *       returns <0 then we need to check errno.  If errno is EAGAIN
-	 *       then don't destroy anything, just exit and wait for more
-	 *       data.  See every other function in libpurple that does this
-	 *       correctly for an example.
-	 */
-	len = read(directconn->fd, &body_len, sizeof(body_len));
+	g_return_if_fail(dc != NULL);
+
+	slplink = dc->slplink;
+
+	if (dc->slpcall != NULL)
+		dc->slpcall->wait_for_socket = FALSE;
+
+	slplink->dc = NULL;
+
+	if (slplink->swboard == NULL)
+		msn_slplink_destroy(slplink);
+
+	g_free(dc->msg_body);
+
+	if (dc->prev_ack) {
+		msn_slpmsg_destroy(dc->prev_ack);
+	}
+
+	if (dc->listen_data != NULL) {
+		purple_network_listen_cancel(dc->listen_data);
+	}
+
+	if (dc->connect_data != NULL) {
+		purple_proxy_connect_cancel(dc->connect_data);
+	}
+
+	if (dc->listenfd != -1) {
+		purple_network_remove_port_mapping(dc->listenfd);
+		close(dc->listenfd);
+	}
 
-	if (len <= 0)
-	{
-		/* ERROR */
-		purple_debug_error("msn", "error reading\n");
+	if (dc->listenfd_handle != 0) {
+		purple_input_remove(dc->listenfd_handle);
+	}
+
+	if (dc->connect_timeout_handle != 0) {
+		purple_timeout_remove(dc->connect_timeout_handle);
+	}
+
+	if (dc->fd != -1) {
+		close(dc->fd);
+	}
+
+	if (dc->send_handle != 0) {
+		purple_input_remove(dc->send_handle);
+	}
 
-		if (directconn->inpa)
-			purple_input_remove(directconn->inpa);
+	if (dc->recv_handle != 0) {
+		purple_input_remove(dc->recv_handle);
+	}
+
+	g_free(dc->in_buffer);
 
-		close(directconn->fd);
+	if (dc->out_queue != NULL) {
+		while (!g_queue_is_empty(dc->out_queue))
+			msn_dc_destroy_packet( g_queue_pop_head(dc->out_queue) );
 
-		msn_directconn_destroy(directconn);
+		g_queue_free(dc->out_queue);
+	}
 
-		return;
+	g_free(dc->ext_ip);
+
+	if (dc->timeout_handle != 0) {
+		purple_timeout_remove(dc->timeout_handle);
 	}
 
-	body_len = GUINT32_FROM_LE(body_len);
+	g_free(dc);
+}
+
+/*
+void
+msn_dc_ref(MsnDirectConn *dc)
+{
+	g_return_if_fail(dc != NULL);
+
+	dc->num_calls++;
+}
+
+void
+msn_dc_unref(MsnDirectConn *dc)
+{
+	g_return_if_fail(dc != NULL);
+
+
+	if (dc->num_calls > 0) {
+		dc->num_calls--;
+	}
+}
+*/
+
+void
+msn_dc_send_invite(MsnDirectConn *dc)
+{
+	MsnSlpCall    *slpcall;
+	MsnSlpMessage *msg;
+	gchar *header;
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_send_invite %p\n", dc);
+
+	g_return_if_fail(dc != NULL);
+
+	slpcall = dc->slpcall;
+	g_return_if_fail(slpcall != NULL);
 
-	purple_debug_info("msn", "body_len=%" G_GSIZE_FORMAT "\n", body_len);
+	header = g_strdup_printf(
+		"INVITE MSNMSGR:%s MSNSLP/1.0",
+		slpcall->slplink->remote_user
+	);
+
+	msg = msn_slpmsg_sip_new(
+		slpcall,
+		0,
+		header,
+		slpcall->branch,
+		"application/x-msnmsgr-transrespbody",
+		dc->msg_body
+	);
+	msg->info = "DC INVITE";
+	msg->text_body = TRUE;
+	g_free(header);
+	g_free(dc->msg_body);
+	dc->msg_body = NULL;
+
+	msn_slplink_queue_slpmsg(slpcall->slplink, msg);
+}
+
+void
+msn_dc_send_ok(MsnDirectConn *dc)
+{
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_send_ok %p\n", dc);
+
+	g_return_if_fail(dc != NULL);
+
+	msn_slp_send_ok(dc->slpcall, dc->slpcall->branch,
+		"application/x-msnmsgr-transrespbody", dc->msg_body);
+	g_free(dc->msg_body);
+	dc->msg_body = NULL;
+
+	msn_slplink_send_slpmsg(dc->slpcall->slplink, dc->prev_ack);
+	msn_slpmsg_destroy(dc->prev_ack);
+	dc->prev_ack = NULL;
+	msn_slplink_send_queued_slpmsgs(dc->slpcall->slplink);
+}
+
+void
+msn_dc_fallback_to_p2p(MsnDirectConn *dc)
+{
+	MsnSlpLink *slplink;
+	MsnSlpCall *slpcall;
+	GQueue *queue = NULL;
 
-	if (body_len <= 0)
-	{
-		/* ERROR */
-		purple_debug_error("msn", "error reading\n");
+	purple_debug_info("msn", "msn_dc_try_fallback_to_p2p %p\n", dc);
+
+	g_return_if_fail(dc != NULL);
+
+	slpcall = dc->slpcall;
+	slplink = msn_slplink_ref(dc->slplink);
+	if (slpcall && !g_queue_is_empty(dc->out_queue)) {
+		queue = dc->out_queue;
+		dc->out_queue = NULL;
+	}
+
+	msn_dc_destroy(dc);
+
+	if (slpcall) {
+		msn_slpcall_session_init(slpcall);
+		if (queue) {
+			while (!g_queue_is_empty(queue)) {
+				MsnDirectConnPacket *p = g_queue_pop_head(queue);
+				msn_slplink_send_msg(slplink, p->msg);
+				msn_dc_destroy_packet(p);
+			}
+			g_queue_free(queue);
+		}
+	}
+	msn_slplink_unref(slplink);
+}
+
+static void
+msn_dc_parse_binary_header(MsnDirectConn *dc)
+{
+	MsnSlpHeader *h;
+	MsnDcContext *context;
+
+	g_return_if_fail(dc != NULL);
+
+	h = &dc->header;
+	/* Skip packet size */
+	context = (MsnDcContext *)(dc->in_buffer + 4);
 
-		if (directconn->inpa)
-			purple_input_remove(directconn->inpa);
+	h->session_id = GUINT32_FROM_LE(context->session_id);
+	h->id = GUINT32_FROM_LE(context->seq_id);
+	h->offset = GUINT64_FROM_LE(context->offset);
+	h->total_size = GUINT64_FROM_LE(context->total_size);
+	h->length = GUINT32_FROM_LE(context->length);
+	h->flags = GUINT32_FROM_LE(context->flags);
+	h->ack_id = GUINT32_FROM_LE(context->ack_id);
+	h->ack_sub_id = GUINT32_FROM_LE(context->ack_uid);
+	h->ack_size = GUINT64_FROM_LE(context->ack_size);
+}
+
+static const gchar *
+msn_dc_serialize_binary_header(MsnDirectConn *dc) {
+	MsnSlpHeader *h;
+	static MsnDcContext bin_header;
+
+	g_return_val_if_fail(dc != NULL, NULL);
+
+	h = &dc->header;
 
-		close(directconn->fd);
+	bin_header.session_id = GUINT32_TO_LE(h->session_id);
+	bin_header.seq_id = GUINT32_TO_LE(h->id);
+	bin_header.offset = GUINT64_TO_LE(h->offset);
+	bin_header.total_size = GUINT64_TO_LE(h->total_size);
+	bin_header.length = GUINT32_TO_LE(h->length);
+	bin_header.flags = GUINT32_TO_LE(h->flags);
+	bin_header.ack_id = GUINT32_TO_LE(h->ack_id);
+	bin_header.ack_uid = GUINT32_TO_LE(h->ack_sub_id);
+	bin_header.ack_size = GUINT64_TO_LE(h->ack_size);
+
+	return (const gchar *)&bin_header;
+}
 
-		msn_directconn_destroy(directconn);
+static void
+msn_dc_send_cb(gpointer data, gint fd, PurpleInputCondition cond)
+{
+	MsnDirectConn *dc = data;
+	MsnDirectConnPacket *p;
+	int bytes_to_send;
+	int bytes_sent;
 
+	g_return_if_fail(dc != NULL);
+	g_return_if_fail(fd != -1);
+
+	if (g_queue_is_empty(dc->out_queue)) {
+		if (dc->send_handle != 0) {
+			purple_input_remove(dc->send_handle);
+			dc->send_handle = 0;
+		}
 		return;
 	}
 
-	body = g_try_malloc(body_len);
-
-	if (body != NULL)
-	{
-		/* Let's read the data. */
-		len = read(directconn->fd, body, body_len);
+	p = g_queue_peek_head(dc->out_queue);
 
-		purple_debug_info("msn", "len=%" G_GSIZE_FORMAT "\n", len);
-	}
-	else
-	{
-		purple_debug_error("msn", "Failed to allocate memory for read\n");
-		len = 0;
+	if (dc->msg_pos < 0) {
+		/* First we send the length of the packet */
+		guint32 len = GUINT32_TO_LE(p->length);
+		bytes_sent = send(fd, &len, 4, 0);
+		if (bytes_sent < 0) {
+			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+				return;
+
+			purple_debug_warning("msn", "msn_dc_send_cb: send error\n");
+			msn_dc_destroy(dc);
+			return;
+		}
+		dc->msg_pos = 0;
 	}
 
-	if (len > 0)
-	{
-		MsnMessage *msg;
-
-#ifdef DEBUG_DC
-		str = g_strdup_printf("%s/msntest/r%.4d.bin", g_get_home_dir(), directconn->c);
-
-		FILE *tf = g_fopen(str, "w");
-		fwrite(body, 1, len, tf);
-		fclose(tf);
-
-		g_free(str);
-#endif
-
-		directconn->c++;
+	bytes_to_send = p->length - dc->msg_pos;
+	bytes_sent = send(fd, p->data + dc->msg_pos, bytes_to_send, 0);
+	if (bytes_sent < 0) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return;
 
-		msg = msn_message_new_msnslp();
-		msn_message_parse_slp_body(msg, body, body_len);
-
-		purple_debug_info("msn", "directconn: process_msg\n");
-		msn_slplink_process_msg(directconn->slplink, msg);
-	}
-	else
-	{
-		/* ERROR */
-		purple_debug_error("msn", "error reading\n");
-
-		if (directconn->inpa)
-			purple_input_remove(directconn->inpa);
-
-		close(directconn->fd);
-
-		msn_directconn_destroy(directconn);
+		purple_debug_warning("msn", "msn_dc_send_cb: send error\n");
+		msn_dc_destroy(dc);
+		return;
 	}
 
-	g_free(body);
+	dc->progress = TRUE;
+
+	dc->msg_pos += bytes_sent;
+	if (dc->msg_pos == p->length) {
+		if (p->sent_cb != NULL)
+			p->sent_cb(p);
+
+		g_queue_pop_head(dc->out_queue);
+		msn_dc_destroy_packet(p);
+
+		dc->msg_pos = -1;
+	}
 }
 
 static void
-connect_cb(gpointer data, gint source, PurpleInputCondition cond)
+msn_dc_enqueue_packet(MsnDirectConn *dc, MsnDirectConnPacket *p)
 {
-	MsnDirectConn* directconn;
-	int fd;
-
-	purple_debug_misc("msn", "directconn: connect_cb: %d, %d.\n", source, cond);
-
-	directconn = data;
-	directconn->connect_data = NULL;
-
-	if (TRUE)
-	{
-		fd = source;
-	}
-	else
-	{
-		struct sockaddr_in client_addr;
-		socklen_t client;
-		fd = accept (source, (struct sockaddr *)&client_addr, &client);
-	}
-
-	directconn->fd = fd;
+	gboolean was_empty;
 
-	if (fd > 0)
-	{
-		directconn->inpa = purple_input_add(fd, PURPLE_INPUT_READ, read_cb,
-										  directconn);
-
-		if (TRUE)
-		{
-			/* Send foo. */
-			msn_directconn_write(directconn, "foo", strlen("foo") + 1);
+	was_empty = g_queue_is_empty(dc->out_queue);
+	g_queue_push_tail(dc->out_queue, p);
 
-			/* Send Handshake */
-			msn_directconn_send_handshake(directconn);
-		}
-		else
-		{
-		}
-	}
-	else
-	{
-		/* ERROR */
-		purple_debug_error("msn", "could not add input\n");
-
-		if (directconn->inpa)
-			purple_input_remove(directconn->inpa);
-
-		close(directconn->fd);
+	if (was_empty && dc->send_handle == 0) {
+		dc->send_handle = purple_input_add(dc->fd, PURPLE_INPUT_WRITE, msn_dc_send_cb, dc);
+		msn_dc_send_cb(dc, dc->fd, PURPLE_INPUT_WRITE);
 	}
 }
 
 static void
-directconn_connect_cb(gpointer data, gint source, const gchar *error_message)
+msn_dc_send_foo(MsnDirectConn *dc)
+{
+	MsnDirectConnPacket	*p;
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_send_foo %p\n", dc);
+
+	p = msn_dc_new_packet(4);
+
+	memcpy(p->data, "foo\0", 4);
+
+	msn_dc_enqueue_packet(dc, p);
+}
+
+static void
+msn_dc_send_handshake_with_nonce(MsnDirectConn *dc, MsnDirectConnPacket *p)
 {
-	if (error_message)
-		purple_debug_error("msn", "Error making direct connection: %s\n", error_message);
+	const gchar *h;
+
+	h = msn_dc_serialize_binary_header(dc);
+	memcpy(p->data, h, DC_PACKET_HEADER_SIZE);
+
+	memcpy(p->data + offsetof(MsnDcContext, ack_id), dc->nonce, 16);
+
+	msn_dc_enqueue_packet(dc, p);
+}
 
-	connect_cb(data, source, PURPLE_INPUT_READ);
+static void
+msn_dc_send_handshake(MsnDirectConn *dc)
+{
+	MsnDirectConnPacket *p;
+
+	p = msn_dc_new_packet(DC_PACKET_HEADER_SIZE);
+
+	dc->header.session_id = 0;
+	dc->header.id = dc->slpcall->slplink->slp_seq_id++;
+	dc->header.offset = 0;
+	dc->header.total_size = 0;
+	dc->header.length = 0;
+	dc->header.flags = 0x100;
+
+	msn_dc_send_handshake_with_nonce(dc, p);
 }
 
-gboolean
-msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port)
+static void
+msn_dc_send_handshake_reply(MsnDirectConn *dc)
 {
-	MsnSession *session;
+	MsnDirectConnPacket *p;
+
+	p = msn_dc_new_packet(DC_PACKET_HEADER_SIZE);
+
+	dc->header.id = dc->slpcall->slplink->slp_seq_id++;
+	dc->header.length = 0;
 
-	g_return_val_if_fail(directconn != NULL, FALSE);
-	g_return_val_if_fail(host       != NULL, TRUE);
-	g_return_val_if_fail(port        > 0,    FALSE);
+	msn_dc_send_handshake_with_nonce(dc, p);
+}
 
-	session = directconn->slplink->session;
+static gboolean
+msn_dc_verify_handshake(MsnDirectConn *dc, guint32 packet_length)
+{
+	guchar nonce[16];
+	gchar  nonce_hash[37];
+
+	if (packet_length != DC_PACKET_HEADER_SIZE)
+		return FALSE;
+
+	memcpy(nonce, dc->in_buffer + 4 + offsetof(MsnDcContext, ack_id), 16);
 
-#if 0
-	if (session->http_method)
-	{
-		servconn->http_data->gateway_host = g_strdup(host);
-	}
-#endif
+	if (dc->nonce_type == DC_NONCE_PLAIN) {
+		if (memcmp(dc->nonce, nonce, 16) == 0) {
+			purple_debug_info("msn",
+					"Nonce from buddy request and nonce from DC attempt match, "
+					"allowing direct connection\n");
+			return TRUE;
+		} else {
+			purple_debug_warning("msn",
+					"Nonce from buddy request and nonce from DC attempt "
+					"don't match, ignoring direct connection\n");
+			return FALSE;
+		}
+
+	} else if (dc->nonce_type == DC_NONCE_SHA1) {
+		msn_dc_calculate_nonce_hash(dc->nonce_type, nonce, nonce_hash);
 
-	directconn->connect_data = purple_proxy_connect(NULL, session->account,
-			host, port, directconn_connect_cb, directconn);
+		if (g_str_equal(dc->remote_nonce, nonce_hash)) {
+			purple_debug_info("msn",
+					"Received nonce %s from buddy request "
+					"and calculated nonce %s from DC attempt. "
+					"Nonces match, allowing direct connection\n",
+					dc->remote_nonce, nonce_hash);
+			return TRUE;
+		} else {
+			purple_debug_warning("msn",
+					"Received nonce %s from buddy request "
+					"and calculated nonce %s from DC attempt. "
+					"Nonces don't match, ignoring direct connection\n",
+					dc->remote_nonce, nonce_hash);
+			return FALSE;
+		}
+	} else
+		return FALSE;
+}
 
-	return (directconn->connect_data != NULL);
+static void
+msn_dc_send_packet_cb(MsnDirectConnPacket *p)
+{
+	if (p->msg != NULL && p->msg->ack_cb != NULL)
+		p->msg->ack_cb(p->msg, p->msg->ack_data);
 }
 
 void
-msn_directconn_listen(MsnDirectConn *directconn)
+msn_dc_enqueue_msg(MsnDirectConn *dc, MsnMessage *msg)
 {
-	int port;
-	int fd;
+	MsnDirectConnPacket *p;
+	guint32 length;
+
+	length = msg->body_len + DC_PACKET_HEADER_SIZE;
+	p = msn_dc_new_packet(length);
+
+	memcpy(p->data, &msg->msnslp_header, DC_PACKET_HEADER_SIZE);
+	memcpy(p->data + DC_PACKET_HEADER_SIZE, msg->body, msg->body_len);
+
+	p->sent_cb = msn_dc_send_packet_cb;
+	p->msg = msn_message_ref(msg);
+
+	msn_dc_enqueue_packet(dc, p);
+}
 
-	port = 7000;
+static int
+msn_dc_process_packet(MsnDirectConn *dc, guint32 packet_length)
+{
+	g_return_val_if_fail(dc != NULL, DC_PROCESS_ERROR);
+
+	switch (dc->state) {
+	case DC_STATE_CLOSED:
+		break;
+
+	case DC_STATE_FOO:
+		/* FOO message is always 4 bytes long */
+		if (packet_length != 4 || memcmp(dc->in_buffer, "\4\0\0\0foo", 8) != 0)
+			return DC_PROCESS_FALLBACK;
+
+		dc->state = DC_STATE_HANDSHAKE;
+		break;
 
-	for (fd = -1; fd < 0;)
-		fd = create_listener(++port);
+	case DC_STATE_HANDSHAKE:
+		if (!msn_dc_verify_handshake(dc, packet_length))
+			return DC_PROCESS_FALLBACK;
+
+		msn_dc_send_handshake_reply(dc);
+		dc->state = DC_STATE_ESTABLISHED;
 
-	directconn->fd = fd;
+		msn_slpcall_session_init(dc->slpcall);
+		dc->slpcall = NULL;
+		break;
+
+	case DC_STATE_HANDSHAKE_REPLY:
+		if (!msn_dc_verify_handshake(dc, packet_length))
+			return DC_PROCESS_FALLBACK;
+
+		dc->state = DC_STATE_ESTABLISHED;
 
-	directconn->inpa = purple_input_add(fd, PURPLE_INPUT_READ, connect_cb,
-		directconn);
+		msn_slpcall_session_init(dc->slpcall);
+		dc->slpcall = NULL;
+		break;
+
+	case DC_STATE_ESTABLISHED:
+		msn_slplink_process_msg(
+			dc->slplink,
+			&dc->header,
+			dc->in_buffer + 4 + DC_PACKET_HEADER_SIZE,
+			dc->header.length
+		);
 
-	directconn->port = port;
-	directconn->c = 0;
+		/*
+		if (dc->num_calls == 0) {
+			msn_dc_destroy(dc);
+
+			return DC_PROCESS_CLOSE;
+		}
+		*/
+		break;
+	}
+
+	return DC_PROCESS_OK;
 }
 
-MsnDirectConn*
-msn_directconn_new(MsnSlpLink *slplink)
+static void
+msn_dc_recv_cb(gpointer data, gint fd, PurpleInputCondition cond)
 {
-	MsnDirectConn *directconn;
+	MsnDirectConn *dc;
+	int free_buf_space;
+	int bytes_received;
+	guint32 packet_length;
+
+	g_return_if_fail(data != NULL);
+	g_return_if_fail(fd != -1);
+
+	dc = data;
+	free_buf_space = dc->in_size - dc->in_pos;
+
+	bytes_received = recv(fd, dc->in_buffer + dc->in_pos, free_buf_space, 0);
+	if (bytes_received < 0) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return;
+
+		purple_debug_warning("msn", "msn_dc_recv_cb: recv error\n");
+
+		if(dc->state != DC_STATE_ESTABLISHED)
+			msn_dc_fallback_to_p2p(dc);
+		else
+			msn_dc_destroy(dc);
+		return;
 
-	directconn = g_new0(MsnDirectConn, 1);
+	} else if (bytes_received == 0) {
+		/* EOF. Remote side closed connection. */
+		purple_debug_info("msn", "msn_dc_recv_cb: recv EOF\n");
+
+		if(dc->state != DC_STATE_ESTABLISHED)
+			msn_dc_fallback_to_p2p(dc);
+		else
+			msn_dc_destroy(dc);
+		return;
+	}
+
+	dc->progress = TRUE;
+
+	dc->in_pos += bytes_received;
+
+	/* Wait for packet length */
+	while (dc->in_pos >= 4) {
+		packet_length = GUINT32_FROM_LE(*((guint32*)dc->in_buffer));
+
+		if (packet_length > DC_MAX_PACKET_SIZE) {
+			/* Oversized packet */
+			purple_debug_warning("msn", "msn_dc_recv_cb: oversized packet received\n");
+			return;
+		}
 
-	directconn->slplink = slplink;
+		/* Wait for the whole packet to arrive */
+		if (dc->in_pos < 4 + packet_length)
+			return;
+
+		if (dc->state != DC_STATE_FOO) {
+			msn_dc_parse_binary_header(dc);
+		}
+
+		switch (msn_dc_process_packet(dc, packet_length)) {
+		case DC_PROCESS_CLOSE:
+			return;
+
+		case DC_PROCESS_FALLBACK:
+			purple_debug_warning("msn", "msn_dc_recv_cb: packet processing error, fall back to p2p\n");
+			msn_dc_fallback_to_p2p(dc);
+			return;
+
+		}
+
+		if (dc->in_pos > packet_length + 4) {
+			g_memmove(dc->in_buffer, dc->in_buffer + 4 + packet_length, dc->in_pos - packet_length - 4);
+		}
+
+		dc->in_pos -= packet_length + 4;
+	}
+}
 
-	if (slplink->directconn != NULL)
-		purple_debug_info("msn", "got_transresp: LEAK\n");
+static gboolean
+msn_dc_timeout(gpointer data)
+{
+	MsnDirectConn *dc = data;
+
+	g_return_val_if_fail(dc != NULL, FALSE);
 
-	slplink->directconn = directconn;
+	if (dc->progress) {
+		dc->progress = FALSE;
+		return TRUE;
+	} else {
+		dc->timeout_handle = 0;
+		msn_dc_destroy(dc);
+		return FALSE;
+	}
+}
 
-	return directconn;
+static void
+msn_dc_init(MsnDirectConn *dc)
+{
+	g_return_if_fail(dc != NULL);
+
+	dc->in_size = DC_MAX_PACKET_SIZE + 4;
+	dc->in_pos = 0;
+	dc->in_buffer = g_malloc(dc->in_size);
+
+	dc->recv_handle = purple_input_add(dc->fd, PURPLE_INPUT_READ, msn_dc_recv_cb, dc);
+	dc->send_handle = purple_input_add(dc->fd, PURPLE_INPUT_WRITE, msn_dc_send_cb, dc);
+
+	dc->timeout_handle = purple_timeout_add_seconds(DC_TIMEOUT, msn_dc_timeout, dc);
 }
 
 void
-msn_directconn_destroy(MsnDirectConn *directconn)
+msn_dc_connected_to_peer_cb(gpointer data, gint fd, const gchar *error_msg)
 {
-	if (directconn->connect_data != NULL)
-		purple_proxy_connect_cancel(directconn->connect_data);
+	MsnDirectConn *dc = data;
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_connected_to_peer_cb %p\n", dc);
+
+	g_return_if_fail(dc != NULL);
+
+	dc->connect_data = NULL;
+	purple_timeout_remove(dc->connect_timeout_handle);
+	dc->connect_timeout_handle = 0;
+
+	dc->fd = fd;
+	if (dc->fd != -1) {
+		msn_dc_init(dc);
+		msn_dc_send_foo(dc);
+		msn_dc_send_handshake(dc);
+		dc->state = DC_STATE_HANDSHAKE_REPLY;
+	}
+}
+
+/*
+ * This callback will be called when we're the server
+ * and nobody has connected us in DC_INCOMING_TIMEOUT seconds
+ */
+static gboolean
+msn_dc_incoming_connection_timeout_cb(gpointer data) {
+	MsnDirectConn *dc = data;
+	MsnSlpCall *slpcall;
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_incoming_connection_timeout_cb %p\n", dc);
+
+	g_return_val_if_fail(dc != NULL, FALSE);
+
+	slpcall = dc->slpcall;
+
+	if (dc->listen_data != NULL) {
+		purple_network_listen_cancel(dc->listen_data);
+		dc->listen_data = NULL;
+	}
+
+	if (dc->listenfd_handle != 0) {
+		purple_input_remove(dc->listenfd_handle);
+		dc->listenfd_handle = 0;
+	}
+
+	if (dc->listenfd != -1) {
+		purple_network_remove_port_mapping(dc->listenfd);
+		close(dc->listenfd);
+		dc->listenfd = -1;
+	}
+
+	dc->connect_timeout_handle = 0;
+	msn_dc_fallback_to_p2p(dc);
 
-	if (directconn->inpa != 0)
-		purple_input_remove(directconn->inpa);
+	return FALSE;
+}
+
+/*
+ * This callback will be called when we're unable to connect to
+ * the remote host in DC_OUTGOING_TIMEOUT seconds.
+ */
+gboolean
+msn_dc_outgoing_connection_timeout_cb(gpointer data)
+{
+	MsnDirectConn *dc = data;
+
+	purple_debug_info("msn", "msn_dc_outgoing_connection_timeout_cb %p\n", dc);
+
+	g_return_val_if_fail(dc != NULL, FALSE);
+
+	dc->connect_timeout_handle = 0;
+
+	if (dc->connect_data != NULL) {
+		purple_proxy_connect_cancel(dc->connect_data);
+		dc->connect_data = NULL;
+	}
+
+	if (dc->ext_ip && dc->ext_port) {
+		/* Try external IP/port if available. */
+		dc->connect_data = purple_proxy_connect(
+			NULL,
+			dc->slpcall->slplink->session->account,
+			dc->ext_ip,
+			dc->ext_port,
+			msn_dc_connected_to_peer_cb,
+			dc
+		);
+
+		g_free(dc->ext_ip);
+		dc->ext_ip = NULL;
+
+		if (dc->connect_data) {
+			dc->connect_timeout_handle = purple_timeout_add_seconds(
+				DC_OUTGOING_TIMEOUT,
+				msn_dc_outgoing_connection_timeout_cb,
+				dc
+			);
+		} else {
+			/*
+			 * Connection failed
+			 * Fall back to P2P transfer
+			 */
+			msn_dc_outgoing_connection_timeout_cb(dc);
+		}
+
+	} else {
+		/*
+		 * Both internal and external connection attempts failed.
+		 * Fall back to p2p transfer.
+		 */
+		msn_dc_fallback_to_p2p(dc);
+	}
 
-	if (directconn->fd >= 0)
-		close(directconn->fd);
+	return FALSE;
+}
+
+/*
+ * This callback will be called when we're the server
+ * and somebody has connected to us in DC_INCOMING_TIMEOUT seconds.
+ */
+static void
+msn_dc_incoming_connection_cb(gpointer data, gint listenfd, PurpleInputCondition cond)
+{
+	MsnDirectConn *dc = data;
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_incoming_connection_cb %p\n", dc);
+
+	g_return_if_fail(dc != NULL);
+
+	if (dc->connect_timeout_handle != 0) {
+		purple_timeout_remove(dc->connect_timeout_handle);
+		dc->connect_timeout_handle = 0;
+	}
+
+	if (dc->listenfd_handle != 0) {
+		purple_input_remove(dc->listenfd_handle);
+		dc->listenfd_handle = 0;
+	}
+
+	dc->fd = accept(listenfd, NULL, 0);
+
+	purple_network_remove_port_mapping(dc->listenfd);
+	close(dc->listenfd);
+	dc->listenfd = -1;
+
+	if (dc->fd != -1) {
+		msn_dc_init(dc);
+		dc->state = DC_STATE_FOO;
+	}
+}
+
+void
+msn_dc_listen_socket_created_cb(int listenfd, gpointer data)
+{
+	MsnDirectConn *dc = data;
+
+	if (purple_debug_is_verbose())
+		purple_debug_info("msn", "msn_dc_listen_socket_created_cb %p\n", dc);
+
+	g_return_if_fail(dc != NULL);
+
+	dc->listen_data = NULL;
+
+	if (listenfd != -1) {
+		const char *ext_ip;
+		const char *int_ip;
+		int port;
 
-	if (directconn->nonce != NULL)
-		g_free(directconn->nonce);
+		ext_ip = purple_network_get_my_ip(listenfd);
+		int_ip = purple_network_get_local_system_ip(listenfd);
+		port = purple_network_get_port_from_fd(listenfd);
+
+		dc->listenfd = listenfd;
+		dc->listenfd_handle = purple_input_add(
+			listenfd,
+			PURPLE_INPUT_READ,
+			msn_dc_incoming_connection_cb,
+			dc
+		);
+		dc->connect_timeout_handle = purple_timeout_add_seconds(
+			DC_INCOMING_TIMEOUT,
+			msn_dc_incoming_connection_timeout_cb,
+			dc
+		);
+
+		if (strcmp(int_ip, ext_ip) != 0) {
+			dc->msg_body = g_strdup_printf(
+				"Bridge: TCPv1\r\n"
+				"Listening: true\r\n"
+				"%sNonce: {%s}\r\n"
+				"IPv4External-Addrs: %s\r\n"
+				"IPv4External-Port: %d\r\n"
+				"IPv4Internal-Addrs: %s\r\n"
+				"IPv4Internal-Port: %d\r\n"
+				"\r\n",
 
-	directconn->slplink->directconn = NULL;
+				dc->nonce_type != DC_NONCE_PLAIN ? "Hashed-" : "",
+				dc->nonce_hash,
+				ext_ip,
+				port,
+				int_ip,
+				port
+			);
+
+		} else {
+			dc->msg_body = g_strdup_printf(
+				"Bridge: TCPv1\r\n"
+				"Listening: true\r\n"
+				"%sNonce: {%s}\r\n"
+				"IPv4External-Addrs: %s\r\n"
+				"IPv4External-Port: %d\r\n"
+				"\r\n",
 
-	g_free(directconn);
+				dc->nonce_type != DC_NONCE_PLAIN ? "Hashed-" : "",
+				dc->nonce_hash,
+				ext_ip,
+				port
+			);
+		}
+
+		if (dc->slpcall->wait_for_socket) {
+			if (dc->send_connection_info_msg_cb != NULL)
+				dc->send_connection_info_msg_cb(dc);
+
+			dc->slpcall->wait_for_socket = FALSE;
+		}
+	}
 }
+
--- a/libpurple/protocols/msn/directconn.h	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/directconn.h	Sun May 23 17:22:51 2010 +0000
@@ -26,36 +26,174 @@
 
 typedef struct _MsnDirectConn MsnDirectConn;
 
+#include "network.h"
+#include "proxy.h"
+#include "circbuffer.h"
+
 #include "msg.h"
 #include "slp.h"
 #include "slplink.h"
+#include "slpmsg.h"
+
+typedef enum
+{
+	DC_STATE_CLOSED,            /*< No socket opened yet */
+	DC_STATE_FOO,               /*< Waiting for FOO message */
+	DC_STATE_HANDSHAKE,         /*< Waiting for handshake message */
+	DC_STATE_HANDSHAKE_REPLY,   /*< Waiting for handshake reply message */
+	DC_STATE_ESTABLISHED        /*< Handshake complete */
+} MsnDirectConnState;
+
+typedef enum
+{
+	DC_PROCESS_OK = 0,
+	DC_PROCESS_ERROR,
+	DC_PROCESS_FALLBACK,
+	DC_PROCESS_CLOSE
+
+} MsnDirectConnProcessResult;
+
+typedef enum
+{
+	DC_NONCE_UNKNOWN,	/**< Invalid scheme */
+	DC_NONCE_PLAIN,     /**< No hashing */
+	DC_NONCE_SHA1       /**< First 16 bytes of SHA1 of nonce */
+
+} MsnDirectConnNonceType;
+
+typedef struct _MsnDirectConnPacket MsnDirectConnPacket;
+
+struct _MsnDirectConnPacket {
+	guint32     length;
+	guchar      *data;
+
+	void        (*sent_cb)(struct _MsnDirectConnPacket*);
+	MsnMessage  *msg;
+};
 
 struct _MsnDirectConn
 {
-	MsnSlpLink *slplink;
-	MsnSlpCall *initial_call;
+	MsnDirectConnState  state;      /**< Direct connection status */
+	MsnSlpLink          *slplink;   /**< The slplink using this direct connection */
+	MsnSlpCall          *slpcall;   /**< The slpcall which initiated the direct connection */
+	char                *msg_body;  /**< The body of message sent by send_connection_info_msg_cb */
+	MsnSlpMessage       *prev_ack;  /**< The saved SLP ACK message */
 
-	PurpleProxyConnectData *connect_data;
+	MsnDirectConnNonceType nonce_type;         /**< The type of nonce hashing */
+	guchar                 nonce[16];          /**< The nonce used for handshake */
+	gchar                  nonce_hash[37];     /**< The hash of nonce */
+	gchar                  remote_nonce[37];   /**< The remote side's nonce */
 
-	gboolean acked;
+	PurpleNetworkListenData *listen_data;           /**< The pending socket creation request */
+	PurpleProxyConnectData  *connect_data;          /**< The pending connection attempt */
+	int                     listenfd;               /**< The socket we're listening for incoming connections */
+	guint                   listenfd_handle;        /**< The timeout handle for incoming connection */
+	guint                   connect_timeout_handle; /**< The timeout handle for outgoing connection */
 
-	char *nonce;
+	int     fd;             /**< The direct connection socket */
+	guint   recv_handle;    /**< The incoming data callback handle */
+	guint   send_handle;    /**< The outgoing data callback handle */
 
-	int fd;
+	gchar   *in_buffer; /**< The receive buffer */
+	int     in_size;    /**< The receive buffer size */
+	int     in_pos;     /**< The first free position in receive buffer */
+	GQueue  *out_queue; /**< The outgoing packet queue */
+	int     msg_pos;    /**< The position of next byte to be sent in the actual packet */
 
-	int port;
-	int inpa;
+	MsnSlpHeader    header; /**< SLP header for parsing / serializing */
+
+	/** The callback used for sending information to the peer about the opened socket */
+	void (*send_connection_info_msg_cb)(MsnDirectConn *);
 
-	int c;
+	gchar   *ext_ip;    /**< Our external IP address */
+	int     ext_port;   /**< Our external port */
+
+	guint       timeout_handle;
+	gboolean    progress;
+
+	/*int   num_calls;*/  /**< The number of slpcalls using this direct connection */
 };
 
-MsnDirectConn *msn_directconn_new(MsnSlpLink *slplink);
-gboolean msn_directconn_connect(MsnDirectConn *directconn,
-								const char *host, int port);
-void msn_directconn_listen(MsnDirectConn *directconn);
-void msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg);
-void msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce);
-void msn_directconn_destroy(MsnDirectConn *directconn);
-void msn_directconn_send_handshake(MsnDirectConn *directconn);
+/* Outgoing attempt */
+#define DC_OUTGOING_TIMEOUT (5)
+/* Time for internal + external connection attempts */
+#define DC_INCOMING_TIMEOUT (DC_OUTGOING_TIMEOUT * 3)
+/* Timeout for lack of activity */
+#define DC_TIMEOUT          (60)
+
+/*
+ * Queues an MSN message to be sent via direct connection.
+ */
+void
+msn_dc_enqueue_msg(MsnDirectConn *dc, MsnMessage *msg);
+
+/*
+ * Creates, initializes, and returns a new MsnDirectConn structure.
+ */
+MsnDirectConn *
+msn_dc_new(MsnSlpCall *slplink);
+
+/*
+ * Destroys an MsnDirectConn structure. Frees every buffer allocated earlier
+ * restores saved callbacks, etc.
+ */
+void
+msn_dc_destroy(MsnDirectConn *dc);
+
+/*
+ * Fallback to switchboard connection. Used when neither side is able to
+ * create a listening socket.
+ */
+void
+msn_dc_fallback_to_p2p(MsnDirectConn *dc);
+
+/*
+ * Increases the slpcall counter in DC. The direct connection remains open
+ * until all slpcalls using it are destroyed.
+ */
+void
+msn_dc_ref(MsnDirectConn *dc);
+
+/*
+ * Decrease the slpcall counter in DC. The direct connection remains open
+ * until all slpcalls using it are destroyed.
+ */
+void
+msn_dc_unref(MsnDirectConn *dc);
+
+/*
+ * Sends a direct connect INVITE message on the associated slplink
+ * with the corresponding connection type and information.
+ */
+void
+msn_dc_send_invite(MsnDirectConn *dc);
+
+/*
+ * Sends a direct connect OK message as a response to an INVITE received earliaer
+ * on the corresponding slplink.
+ */
+void
+msn_dc_send_ok(MsnDirectConn *dc);
+
+/*
+ * This callback will be called when we're successfully connected to
+ * the remote host.
+ */
+void
+msn_dc_connected_to_peer_cb(gpointer data, gint fd, const gchar *error_msg);
+
+/*
+ * This callback will be called when we're unable to connect to
+ * the remote host in DC_CONNECT_TIMEOUT seconds.
+ */
+gboolean
+msn_dc_outgoing_connection_timeout_cb(gpointer data);
+
+/*
+ * This callback will be called when the listening socket is successfully
+ * created and its parameters (IP/port) are available.
+ */
+void
+msn_dc_listen_socket_created_cb(int listenfd, gpointer data);
 
 #endif /* MSN_DIRECTCONN_H */
--- a/libpurple/protocols/msn/msg.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/msg.c	Sun May 23 17:22:51 2010 +0000
@@ -1117,7 +1117,8 @@
 msn_invite_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
 {
 	GHashTable *body;
-	const gchar *guid;
+	const gchar *command;
+	const gchar *cookie;
 	gboolean accepted = FALSE;
 
 	g_return_if_fail(cmdproc != NULL);
@@ -1130,59 +1131,64 @@
 				"Unable to parse invite msg body.\n");
 		return;
 	}
-
-	guid = g_hash_table_lookup(body, "Application-GUID");
-
-	if (guid == NULL) {
-		const gchar *cmd = g_hash_table_lookup(
-				body, "Invitation-Command");
+	
+	/*
+	 * GUID is NOT always present but Invitation-Command and Invitation-Cookie
+	 * are mandatory.
+	 */
+	command = g_hash_table_lookup(body, "Invitation-Command");
+	cookie = g_hash_table_lookup(body, "Invitation-Cookie");
 
-		if (cmd && !strcmp(cmd, "CANCEL")) {
-			const gchar *code = g_hash_table_lookup(
-					body, "Cancel-Code");
-			purple_debug_info("msn",
-					"MSMSGS invitation cancelled: %s.\n",
-					code ? code : "no reason given");
-		} else
-			purple_debug_warning("msn", "Invite msg missing "
-					"Application-GUID.\n");
+	if (command == NULL || cookie == NULL) {
+		purple_debug_warning("msn",
+			"Invalid invitation message: either Invitation-Command "
+			"or Invitation-Cookie is missing or invalid.\n"
+		);
+		return;
 
-		accepted = TRUE;
-
-	} else if (!strcmp(guid, "{02D3C01F-BF30-4825-A83A-DE7AF41648AA}")) {
-		purple_debug_info("msn", "Computer call\n");
+	} else if (!strcmp(command, "INVITE")) {
+		const gchar	*guid = g_hash_table_lookup(body, "Application-GUID");
+	
+		if (guid == NULL) {
+			purple_debug_warning("msn",
+			                     "Invite msg missing Application-GUID.\n");
 
-		if (cmdproc->session) {
-			PurpleConversation *conv = NULL;
-			gchar *from = msg->remote_user;
-			gchar *buf = NULL;
+			accepted = TRUE;
+
+		} else if (!strcmp(guid, MSN_FT_GUID)) {
+
+		} else if (!strcmp(guid, "{02D3C01F-BF30-4825-A83A-DE7AF41648AA}")) {
+			purple_debug_info("msn", "Computer call\n");
 
-			if (from)
-				conv = purple_find_conversation_with_account(
-						PURPLE_CONV_TYPE_IM, from,
-						cmdproc->session->account);
-			if (conv)
-				buf = g_strdup_printf(
-						_("%s sent you a voice chat "
-						"invite, which is not yet "
-						"supported."), from);
-			if (buf) {
-				purple_conversation_write(conv, NULL, buf,
-						PURPLE_MESSAGE_SYSTEM |
-						PURPLE_MESSAGE_NOTIFY,
-						time(NULL));
-				g_free(buf);
+			if (cmdproc->session) {
+				PurpleConversation *conv = NULL;
+				gchar *from = msg->remote_user;
+				gchar *buf = NULL;
+
+				if (from)
+					conv = purple_find_conversation_with_account(
+							PURPLE_CONV_TYPE_IM, from,
+							cmdproc->session->account);
+				if (conv)
+					buf = g_strdup_printf(
+							_("%s sent you a voice chat "
+							"invite, which is not yet "
+							"supported."), from);
+				if (buf) {
+					purple_conversation_write(conv, NULL, buf,
+							PURPLE_MESSAGE_SYSTEM |
+							PURPLE_MESSAGE_NOTIFY,
+							time(NULL));
+					g_free(buf);
+				}
 			}
+		} else {
+			const gchar *application = g_hash_table_lookup(body, "Application-Name");
+			purple_debug_warning("msn", "Unhandled invite msg with GUID %s: %s.\n",
+			                     guid, application ? application : "(null)");
 		}
-	} else {
-		const gchar *application = g_hash_table_lookup(body, "Application-Name");
-		purple_debug_warning("msn", "Unhandled invite msg with GUID %s: %s.\n",
-		                     guid, application ? application : "(null)");
-	}
-
-	if (!accepted) {
-		const gchar *cookie = g_hash_table_lookup(body, "Invitation-Cookie");
-		if (cookie) {
+		
+		if (!accepted) {
 			MsnSwitchBoard *swboard = cmdproc->data;
 			char *text;
 			MsnMessage *cancel;
@@ -1202,6 +1208,17 @@
 			msn_switchboard_send_msg(swboard, cancel, TRUE);
 			msn_message_destroy(cancel);
 		}
+
+	} else if (!strcmp(command, "CANCEL")) {
+		const gchar *code = g_hash_table_lookup(body, "Cancel-Code");
+		purple_debug_info("msn", "MSMSGS invitation cancelled: %s.\n",
+		                  code ? code : "no reason given");
+
+	} else {
+		/*
+		 * Some other already established invitation session.
+		 * Can be retrieved by Invitation-Cookie.
+		 */
 	}
 
 	g_hash_table_destroy(body);
--- a/libpurple/protocols/msn/msn.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/msn.c	Sun May 23 17:22:51 2010 +0000
@@ -2936,6 +2936,11 @@
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
 											   option);
 
+	option = purple_account_option_bool_new(_("Allow direct connections"),
+										  "direct_connect", TRUE);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+											   option);
+
 	purple_cmd_register("nudge", "", PURPLE_CMD_P_PRPL,
 	                  PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
 	                 "prpl-msn", msn_cmd_nudge,
--- a/libpurple/protocols/msn/slp.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/slp.c	Sun May 23 17:22:51 2010 +0000
@@ -25,23 +25,20 @@
 #include "slp.h"
 #include "slpcall.h"
 #include "slpmsg.h"
+#include "msnutils.h"
 
 #include "object.h"
 #include "user.h"
 #include "switchboard.h"
+#include "directconn.h"
 
 #include "smiley.h"
 
-/* ms to delay between sending buddy icon requests to the server. */
+/* seconds to delay between sending buddy icon requests to the server. */
 #define BUDDY_ICON_DELAY 20
 
-static void send_ok(MsnSlpCall *slpcall, const char *branch,
-					const char *type, const char *content);
+static void request_user_display(MsnUser *user);
 
-static void send_decline(MsnSlpCall *slpcall, const char *branch,
-						 const char *type, const char *content);
-
-static void request_user_display(MsnUser *user);
 
 /**************************************************************************
  * Util
@@ -91,7 +88,7 @@
 	content = g_strdup_printf("SessionID: %lu\r\n\r\n",
 							  slpcall->session_id);
 
-	send_ok(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody",
+	msn_slp_send_ok(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody",
 			content);
 
 	g_free(content);
@@ -120,7 +117,7 @@
 			content = g_strdup_printf("SessionID: %lu\r\n\r\n",
 									slpcall->session_id);
 
-			send_decline(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody",
+			msn_slp_send_decline(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody",
 						content);
 
 			g_free(content);
@@ -199,6 +196,7 @@
 					  gsize size)
 {
 	PurpleXfer *xfer = slpcall->xfer;
+
 	purple_xfer_set_completed(xfer, TRUE);
 	purple_xfer_end(xfer);
 }
@@ -207,36 +205,8 @@
  * SLP Control
  **************************************************************************/
 
-#if 0
-static void
-got_transresp(MsnSlpCall *slpcall, const char *nonce,
-			  const char *ips_str, int port)
-{
-	MsnDirectConn *directconn;
-	char **ip_addrs, **c;
-
-	directconn = msn_directconn_new(slpcall->slplink);
-
-	directconn->initial_call = slpcall;
-
-	/* msn_directconn_parse_nonce(directconn, nonce); */
-	directconn->nonce = g_strdup(nonce);
-
-	ip_addrs = g_strsplit(ips_str, " ", -1);
-
-	for (c = ip_addrs; *c != NULL; c++)
-	{
-		purple_debug_info("msn", "ip_addr = %s\n", *c);
-		if (msn_directconn_connect(directconn, *c, port))
-			break;
-	}
-
-	g_strfreev(ip_addrs);
-}
-#endif
-
-static void
-send_ok(MsnSlpCall *slpcall, const char *branch,
+void
+msn_slp_send_ok(MsnSlpCall *slpcall, const char *branch,
 		const char *type, const char *content)
 {
 	MsnSlpLink *slplink;
@@ -253,12 +223,10 @@
 	slpmsg->text_body = TRUE;
 
 	msn_slplink_queue_slpmsg(slplink, slpmsg);
-
-	msn_slpcall_session_init(slpcall);
 }
 
-static void
-send_decline(MsnSlpCall *slpcall, const char *branch,
+void
+msn_slp_send_decline(MsnSlpCall *slpcall, const char *branch,
 			 const char *type, const char *content)
 {
 	MsnSlpLink *slplink;
@@ -309,6 +277,190 @@
 	return NULL;
 }
 
+static char *
+parse_dc_nonce(const char *content, MsnDirectConnNonceType *ntype)
+{
+	char *nonce;
+
+	*ntype = DC_NONCE_UNKNOWN;
+
+	nonce = get_token(content, "Hashed-Nonce: {", "}\r\n");
+	if (nonce) {
+		*ntype = DC_NONCE_SHA1;
+	} else {
+		guint32 n1, n5;
+		guint16 n2, n3, n4, n6;
+		nonce = get_token(content, "Nonce: {", "}\r\n");
+		if (nonce
+		 && sscanf(nonce, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
+		           &n1, &n2, &n3, &n4, &n5, &n6) == 6) {
+			*ntype = DC_NONCE_PLAIN;
+			g_free(nonce);
+			nonce = g_malloc(16);
+			*(guint32 *)(nonce +  0) = GUINT32_TO_LE(n1);
+			*(guint16 *)(nonce +  4) = GUINT16_TO_LE(n2);
+			*(guint16 *)(nonce +  6) = GUINT16_TO_LE(n3);
+			*(guint16 *)(nonce +  8) = GUINT16_TO_BE(n4);
+			*(guint32 *)(nonce + 10) = GUINT32_TO_BE(n5);
+			*(guint16 *)(nonce + 14) = GUINT16_TO_BE(n6);
+		} else {
+			/* Invalid nonce, so ignore request */
+			g_free(nonce);
+			nonce = NULL;
+		}
+	}
+
+	return nonce;
+}
+
+static void
+msn_slp_process_transresp(MsnSlpCall *slpcall, const char *content)
+{
+	/* A direct connection negotiation response */
+	char *bridge;
+	char *nonce;
+	char *listening;
+	MsnDirectConn *dc = slpcall->slplink->dc;
+	MsnDirectConnNonceType ntype;
+
+	purple_debug_info("msn", "process_transresp\n");
+
+	/* Direct connections are disabled. */
+	if (!purple_account_get_bool(slpcall->slplink->session->account, "direct_connect", TRUE))
+		return;
+
+	g_return_if_fail(dc != NULL);
+	g_return_if_fail(dc->state == DC_STATE_CLOSED);
+
+	bridge = get_token(content, "Bridge: ", "\r\n");
+	nonce = parse_dc_nonce(content, &ntype);
+	listening = get_token(content, "Listening: ", "\r\n");
+	if (listening && bridge && !strcmp(bridge, "TCPv1")) {
+		/* Ok, the client supports direct TCP connection */
+
+		/* We always need this. */
+		if (ntype == DC_NONCE_SHA1) {
+			strncpy(dc->remote_nonce, nonce, 36);
+			dc->remote_nonce[36] = '\0';
+		}
+
+		if (!strcasecmp(listening, "false")) {
+			if (dc->listen_data != NULL) {
+				/*
+				 * We'll listen for incoming connections but
+				 * the listening socket isn't ready yet so we cannot
+				 * send the INVITE packet now. Put the slpcall into waiting mode
+				 * and let the callback send the invite.
+				 */
+				slpcall->wait_for_socket = TRUE;
+
+			} else if (dc->listenfd != -1) {
+				/* The listening socket is ready. Send the INVITE here. */
+				msn_dc_send_invite(dc);
+
+			} else {
+				/* We weren't able to create a listener either. Use SB. */
+				msn_dc_fallback_to_p2p(dc);
+			}
+
+		} else {
+			/*
+			 * We should connect to the client so parse
+			 * IP/port from response.
+			 */
+			char *ip, *port_str;
+			int port = 0;
+
+			if (ntype == DC_NONCE_PLAIN) {
+				/* Only needed for listening side. */
+				memcpy(dc->nonce, nonce, 16);
+			}
+
+			/* Cancel any listen attempts because we don't need them. */
+			if (dc->listenfd_handle != 0) {
+				purple_input_remove(dc->listenfd_handle);
+				dc->listenfd_handle = 0;
+			}
+			if (dc->connect_timeout_handle != 0) {
+				purple_timeout_remove(dc->connect_timeout_handle);
+				dc->connect_timeout_handle = 0;
+			}
+			if (dc->listenfd != -1) {
+				purple_network_remove_port_mapping(dc->listenfd);
+				close(dc->listenfd);
+				dc->listenfd = -1;
+			}
+			if (dc->listen_data != NULL) {
+				purple_network_listen_cancel(dc->listen_data);
+				dc->listen_data = NULL;
+			}
+
+			/* Save external IP/port for later use. We'll try local connection first. */
+			dc->ext_ip = get_token(content, "IPv4External-Addrs: ", "\r\n");
+			port_str = get_token(content, "IPv4External-Port: ", "\r\n");
+			if (port_str) {
+				dc->ext_port = atoi(port_str);
+				g_free(port_str);
+			}
+
+			ip = get_token(content, "IPv4Internal-Addrs: ", "\r\n");
+			port_str = get_token(content, "IPv4Internal-Port: ", "\r\n");
+			if (port_str) {
+				port = atoi(port_str);
+				g_free(port_str);
+			}
+
+			if (ip && port) {
+				/* Try internal address first */
+				dc->connect_data = purple_proxy_connect(
+					NULL,
+					slpcall->slplink->session->account,
+					ip,
+					port,
+					msn_dc_connected_to_peer_cb,
+					dc
+				);
+
+				if (dc->connect_data) {
+					/* Add connect timeout handle */
+					dc->connect_timeout_handle = purple_timeout_add_seconds(
+						DC_OUTGOING_TIMEOUT,
+						msn_dc_outgoing_connection_timeout_cb,
+						dc
+					);
+				} else {
+					/*
+					 * Connection failed
+					 * Try external IP/port (if specified)
+					 */
+					msn_dc_outgoing_connection_timeout_cb(dc);
+				}
+
+			} else {
+				/*
+				 * Omitted or invalid internal IP address / port
+				 * Try external IP/port (if specified)
+				 */
+				msn_dc_outgoing_connection_timeout_cb(dc);
+			}
+
+			g_free(ip);
+		}
+
+	} else {
+		/*
+		 * Invalid direct connect invitation or
+		 * TCP connection is not supported
+		 */
+	}
+
+	g_free(listening);
+	g_free(nonce);
+	g_free(bridge);
+
+	return;
+}
+
 static void
 got_sessionreq(MsnSlpCall *slpcall, const char *branch,
 			   const char *euf_guid, const char *context)
@@ -331,7 +483,7 @@
 		content = g_strdup_printf("SessionID: %lu\r\n\r\n",
 								  slpcall->session_id);
 
-		send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody",
+		msn_slp_send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody",
 				content);
 
 		g_free(content);
@@ -486,7 +638,7 @@
 	if (!accepted) {
 		char *content = g_strdup_printf("SessionID: %lu\r\n\r\n",
 		                                slpcall->session_id);
-		send_decline(slpcall, branch, "application/x-msnmsgr-sessionreqbody", content);
+		msn_slp_send_decline(slpcall, branch, "application/x-msnmsgr-sessionreqbody", content);
 		g_free(content);
 	}
 }
@@ -555,92 +707,105 @@
 	}
 	else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
 	{
-		/* A direct connection? */
-
-		char *listening, *nonce;
-		char *content;
+		/* A direct connection negotiation request */
+		char *bridges;
+		char *nonce;
+		MsnDirectConnNonceType ntype;
 
-		if (FALSE)
-		{
-#if 0
-			MsnDirectConn *directconn;
-			/* const char *ip_addr; */
-			char *ip_port;
-			int port;
-
-			/* ip_addr = purple_prefs_get_string("/purple/ft/public_ip"); */
-			ip_port = "5190";
-			listening = "true";
-			nonce = rand_guid();
-
-			directconn = msn_directconn_new(slplink);
-
-			/* msn_directconn_parse_nonce(directconn, nonce); */
-			directconn->nonce = g_strdup(nonce);
-
-			msn_directconn_listen(directconn);
+		purple_debug_info("msn", "got_invite: transreqbody received\n");
 
-			port = directconn->port;
-
-			content = g_strdup_printf(
+		/* Direct connections may be disabled. */
+		if (!purple_account_get_bool(slplink->session->account, "direct_connect", TRUE)) {
+			msn_slp_send_ok(slpcall, branch,
+				"application/x-msnmsgr-transrespbody",
 				"Bridge: TCPv1\r\n"
-				"Listening: %s\r\n"
-				"Nonce: {%s}\r\n"
-				"Ipv4Internal-Addrs: 192.168.0.82\r\n"
-				"Ipv4Internal-Port: %d\r\n"
-				"\r\n",
-				listening,
-				nonce,
-				port);
-#endif
-		}
-		else
-		{
-			listening = "false";
-			nonce = g_strdup("00000000-0000-0000-0000-000000000000");
+				"Listening: false\r\n"
+				"Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
+				"\r\n");
+			msn_slpcall_session_init(slpcall);
 
-			content = g_strdup_printf(
-				"Bridge: TCPv1\r\n"
-				"Listening: %s\r\n"
-				"Nonce: {%s}\r\n"
-				"\r\n",
-				listening,
-				nonce);
+			return;
 		}
 
-		send_ok(slpcall, branch,
-				"application/x-msnmsgr-transrespbody", content);
+		/* Don't do anything if we already have a direct connection */
+		if (slplink->dc != NULL)
+			return;
+
+		bridges = get_token(content, "Bridges: ", "\r\n");
+		nonce = parse_dc_nonce(content, &ntype);
+		if (bridges && strstr(bridges, "TCPv1") != NULL) {
+			/*
+			 * Ok, the client supports direct TCP connection
+			 * Try to create a listening port
+			 */
+			MsnDirectConn *dc;
+
+			dc = msn_dc_new(slpcall);
+			if (ntype == DC_NONCE_PLAIN) {
+				/* There is only one nonce for plain auth. */
+				dc->nonce_type = ntype;
+				memcpy(dc->nonce, nonce, 16);
+			} else if (ntype == DC_NONCE_SHA1) {
+				/* Each side has a nonce in SHA1 auth. */
+				dc->nonce_type = ntype;
+				strncpy(dc->remote_nonce, nonce, 36);
+				dc->remote_nonce[36] = '\0';
+			}
+
+			dc->listen_data = purple_network_listen_range(
+				0, 0,
+				SOCK_STREAM,
+				msn_dc_listen_socket_created_cb,
+				dc
+			);
+
+			if (dc->listen_data == NULL) {
+				/* Listen socket creation failed */
+
+				purple_debug_info("msn", "got_invite: listening failed\n");
 
-		g_free(content);
+				if (dc->nonce_type != DC_NONCE_PLAIN)
+					msn_slp_send_ok(slpcall, branch,
+						"application/x-msnmsgr-transrespbody",
+						"Bridge: TCPv1\r\n"
+						"Listening: false\r\n"
+						"Hashed-Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
+						"\r\n");
+				else
+					msn_slp_send_ok(slpcall, branch,
+						"application/x-msnmsgr-transrespbody",
+						"Bridge: TCPv1\r\n"
+						"Listening: false\r\n"
+						"Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
+						"\r\n");
+
+			} else {
+				/*
+				 * Listen socket created successfully.
+				 * Don't send anything here because we don't know the parameters
+				 * of the created socket yet. msn_dc_send_ok will be called from
+				 * the callback function: dc_listen_socket_created_cb
+				 */
+				purple_debug_info("msn", "got_invite: listening socket created\n");
+
+				dc->send_connection_info_msg_cb = msn_dc_send_ok;
+				slpcall->wait_for_socket = TRUE;
+			}
+
+		} else {
+			/*
+			 * Invalid direct connect invitation or
+			 * TCP connection is not supported.
+			 */
+		}
+
 		g_free(nonce);
+		g_free(bridges);
 	}
 	else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
 	{
-#if 0
-		char *ip_addrs;
-		char *temp;
-		char *nonce;
-		int port;
-
-		nonce = get_token(content, "Nonce: {", "}\r\n");
-		if (ip_addrs == NULL)
-			return;
-
-		ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n");
-
-		temp = get_token(content, "IPv4Internal-Port: ", "\r\n");
-		if (temp != NULL)
-			port = atoi(temp);
-		else
-			port = -1;
-		g_free(temp);
-
-		if (port > 0)
-			got_transresp(slpcall, nonce, ip_addrs, port);
-
-		g_free(nonce);
-		g_free(ip_addrs);
-#endif
+		/* A direct connection negotiation response */
+		msn_slp_process_transresp(slpcall, content);
 	}
 }
 
@@ -653,52 +818,104 @@
 
 	if (!strcmp(type, "application/x-msnmsgr-sessionreqbody"))
 	{
-#if 0
-		if (slpcall->type == MSN_SLPCALL_DC)
-		{
-			/* First let's try a DirectConnection. */
+		char *content;
+		char *header;
+		char *nonce = NULL;
+		MsnSession *session = slpcall->slplink->session;
+		MsnSlpMessage *msg;
+		MsnDirectConn *dc;
+		MsnUser *user;
+
+		if (!purple_account_get_bool(session->account, "direct_connect", TRUE)) {
+			/* Don't attempt a direct connection if disabled. */
+			msn_slpcall_session_init(slpcall);
+			return;
+		}
+
+		if (slpcall->slplink->dc != NULL) {
+			/* If we already have an established direct connection
+			 * then just start the transfer.
+			 */
+			msn_slpcall_session_init(slpcall);
+			return;
+		}
 
-			MsnSlpLink *slplink;
-			MsnSlpMessage *slpmsg;
-			char *header;
-			char *content;
-			char *branch;
+		user = msn_userlist_find_user(session->userlist,
+		                              slpcall->slplink->remote_user);
+		if (!user || !(user->clientid & 0xF0000000))	{
+			/* Just start a normal SB transfer. */
+			msn_slpcall_session_init(slpcall);
+			return;
+		}
+
+		/* Try direct file transfer by sending a second INVITE */
+		dc = msn_dc_new(slpcall);
+		slpcall->branch = rand_guid();
 
-			slplink = slpcall->slplink;
+		dc->listen_data = purple_network_listen_range(
+			0, 0,
+			SOCK_STREAM,
+			msn_dc_listen_socket_created_cb,
+			dc
+		);
 
-			branch = rand_guid();
+		header = g_strdup_printf(
+			"INVITE MSNMSGR:%s MSNSLP/1.0",
+			slpcall->slplink->remote_user
+		);
+
+		if (dc->nonce_type == DC_NONCE_SHA1)
+			nonce = g_strdup_printf("Hashed-Nonce: {%s}\r\n", dc->nonce_hash);
+
+		if (dc->listen_data == NULL) {
+			/* Listen socket creation failed */
+			purple_debug_info("msn", "got_ok: listening failed\n");
 
 			content = g_strdup_printf(
-				"Bridges: TRUDPv1 TCPv1\r\n"
+				"Bridges: TCPv1\r\n"
+				"NetID: %u\r\n"
+				"Conn-Type: IP-Restrict-NAT\r\n"
+				"UPnPNat: false\r\n"
+				"ICF: false\r\n"
+				"%s"
+				"\r\n",
+
+				rand() % G_MAXUINT32,
+				nonce ? nonce : ""
+			);
+
+		} else {
+			/* Listen socket created successfully. */
+			purple_debug_info("msn", "got_ok: listening socket created\n");
+
+			content = g_strdup_printf(
+				"Bridges: TCPv1\r\n"
 				"NetID: 0\r\n"
 				"Conn-Type: Direct-Connect\r\n"
 				"UPnPNat: false\r\n"
 				"ICF: false\r\n"
-			);
-
-			header = g_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0",
-									 slplink->remote_user);
+				"%s"
+				"\r\n",
 
-			slpmsg = msn_slp_sipmsg_new(slpcall, 0, header, branch,
-										"application/x-msnmsgr-transreqbody",
-										content);
-
-			slpmsg->info = "SLP INVITE";
-			slpmsg->text_body = TRUE;
-			msn_slplink_send_slpmsg(slplink, slpmsg);
+				nonce ? nonce : ""
+			);
+		}
 
-			g_free(header);
-			g_free(content);
+		msg = msn_slpmsg_sip_new(
+			slpcall,
+			0,
+			header,
+			slpcall->branch,
+			"application/x-msnmsgr-transreqbody",
+			content
+		);
+		msg->info = "DC INVITE";
+		msg->text_body = TRUE;
+		g_free(nonce);
+		g_free(header);
+		g_free(content);
 
-			g_free(branch);
-		}
-		else
-		{
-			msn_slpcall_session_init(slpcall);
-		}
-#else
-		msn_slpcall_session_init(slpcall);
-#endif
+		msn_slplink_queue_slpmsg(slpcall->slplink, msg);
 	}
 	else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
 	{
@@ -707,31 +924,7 @@
 	}
 	else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
 	{
-#if 0
-		char *ip_addrs;
-		char *temp;
-		char *nonce;
-		int port;
-
-		nonce = get_token(content, "Nonce: {", "}\r\n");
-		if (ip_addrs == NULL)
-			return;
-
-		ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n");
-
-		temp = get_token(content, "IPv4Internal-Port: ", "\r\n");
-		if (temp != NULL)
-			port = atoi(temp);
-		else
-			port = -1;
-		g_free(temp);
-
-		if (port > 0)
-			got_transresp(slpcall, nonce, ip_addrs, port);
-
-		g_free(nonce);
-		g_free(ip_addrs);
-#endif
+		msn_slp_process_transresp(slpcall, content);
 	}
 }
 
@@ -774,18 +967,25 @@
 
 		content = get_token(body, "\r\n\r\n", NULL);
 
-		if (branch && call_id && content_type && content)
+		slpcall = NULL;
+		if (branch && call_id)
 		{
-			slpcall = msn_slpcall_new(slplink);
-			slpcall->id = call_id;
-			got_invite(slpcall, branch, content_type, content);
-		}
-		else
-		{
-			g_free(call_id);
-			slpcall = NULL;
+			slpcall = msn_slplink_find_slp_call(slplink, call_id);
+			if (slpcall)
+			{
+				g_free(slpcall->branch);
+				slpcall->branch = g_strdup(branch);
+				got_invite(slpcall, branch, content_type, content);
+			}
+			else if (content_type && content)
+			{
+				slpcall = msn_slpcall_new(slplink);
+				slpcall->id = g_strdup(call_id);
+				got_invite(slpcall, branch, content_type, content);
+			}
 		}
 
+		g_free(call_id);
 		g_free(branch);
 		g_free(content_type);
 		g_free(content);
@@ -867,6 +1067,8 @@
 {
 	MsnSession *session;
 	MsnSlpLink *slplink;
+	const char *data;
+	gsize len;
 
 	session = cmdproc->servconn->session;
 	slplink = msn_session_get_slplink(session, msg->remote_user);
@@ -889,7 +1091,9 @@
 		}
 	}
 
-	msn_slplink_process_msg(slplink, msg);
+	data = msn_message_get_bin_data(msg, &len);
+
+	msn_slplink_process_msg(slplink, &msg->msnslp_header, data, len);
 }
 
 static void
--- a/libpurple/protocols/msn/slp.h	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/slp.h	Sun May 23 17:22:51 2010 +0000
@@ -51,6 +51,14 @@
 
 MsnSlpCall * msn_slp_sip_recv(MsnSlpLink *slplink,
 							  const char *body);
+void
+msn_slp_send_ok(MsnSlpCall *slpcall, const char *branch,
+		const char *type, const char *content);
+
+void
+msn_slp_send_decline(MsnSlpCall *slpcall, const char *branch,
+			 const char *type, const char *content);
+
 
 void send_bye(MsnSlpCall *slpcall, const char *type);
 
--- a/libpurple/protocols/msn/slpcall.h	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/slpcall.h	Sun May 23 17:22:51 2010 +0000
@@ -64,6 +64,8 @@
 	gboolean started; /**< A flag that states if this slpcall's session has
 						been initiated. */
 
+	gboolean wait_for_socket;
+
 	void (*progress_cb)(MsnSlpCall *slpcall,
 						gsize total_length, gsize len, gsize offset);
 	void (*session_init_cb)(MsnSlpCall *slpcall);
--- a/libpurple/protocols/msn/slplink.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/slplink.c	Sun May 23 17:22:51 2010 +0000
@@ -101,10 +101,8 @@
 
 	session = slplink->session;
 
-#if 0
-	if (slplink->directconn != NULL)
-		msn_directconn_destroy(slplink->directconn);
-#endif
+	if (slplink->dc != NULL)
+		msn_dc_destroy(slplink->dc);
 
 	while (slplink->slp_calls != NULL)
 		msn_slpcall_destroy(slplink->slp_calls->data);
@@ -185,11 +183,21 @@
 		slplink->swboard->flag |= MSN_SB_FLAG_FT;
 
 	slplink->slp_calls = g_list_append(slplink->slp_calls, slpcall);
+
+	/*
+	if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED)
+		msn_dc_ref(slplink->dc);
+	*/
 }
 
 void
 msn_slplink_remove_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall)
 {
+	/*
+	if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED)
+		msn_dc_unref(slplink->dc);
+	*/
+
 	slplink->slp_calls = g_list_remove(slplink->slp_calls, slpcall);
 
 	/* The slplink has no slpcalls in it, release it from MSN_SB_FLAG_FT.
@@ -197,6 +205,10 @@
 	 * destroyed. */
 	if (slplink->slp_calls == NULL && slplink->swboard != NULL)
 		msn_switchboard_release(slplink->swboard, MSN_SB_FLAG_FT);
+
+	/* The slplink has no slpcalls in it, release it from the DC. */
+	if (slplink->slp_calls == NULL && slplink->dc != NULL)
+		msn_dc_destroy(slplink->dc);
 }
 
 MsnSlpCall *
@@ -236,16 +248,14 @@
 	return NULL;
 }
 
-static void
+void
 msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg)
 {
-#if 0
-	if (slplink->directconn != NULL)
+	if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED)
 	{
-		msn_directconn_send_msg(slplink->directconn, msg);
+		msn_dc_enqueue_msg(slplink->dc, msg);
 	}
 	else
-#endif
 	{
 		if (slplink->swboard == NULL)
 		{
@@ -464,21 +474,29 @@
 	}
 }
 
-static void
-msn_slplink_send_ack(MsnSlpLink *slplink, MsnMessage *msg)
+static MsnSlpMessage *
+msn_slplink_create_ack(MsnSlpLink *slplink, MsnSlpHeader *header)
 {
 	MsnSlpMessage *slpmsg;
 
 	slpmsg = msn_slpmsg_new(slplink);
 
-	slpmsg->session_id = msg->msnslp_header.session_id;
-	slpmsg->size       = msg->msnslp_header.total_size;
+	slpmsg->session_id = header->session_id;
+	slpmsg->size       = header->total_size;
 	slpmsg->flags      = 0x02;
-	slpmsg->ack_id     = msg->msnslp_header.id;
-	slpmsg->ack_sub_id = msg->msnslp_header.ack_id;
-	slpmsg->ack_size   = msg->msnslp_header.total_size;
+	slpmsg->ack_id     = header->id;
+	slpmsg->ack_sub_id = header->ack_id;
+	slpmsg->ack_size   = header->total_size;
 	slpmsg->info = "SLP ACK";
 
+	return slpmsg;
+}
+
+static void
+msn_slplink_send_ack(MsnSlpLink *slplink, MsnSlpHeader *header)
+{
+	MsnSlpMessage *slpmsg = msn_slplink_create_ack(slplink, header);
+
 	msn_slplink_send_slpmsg(slplink, slpmsg);
 	msn_slpmsg_destroy(slpmsg);
 }
@@ -490,6 +508,9 @@
 	PurpleXfer *xfer;
 
 	xfer = (PurpleXfer *)slpcall->xfer;
+	if (purple_xfer_get_status(xfer) >= PURPLE_XFER_STATUS_STARTED)
+		return;
+
 	purple_xfer_ref(xfer);
 	purple_xfer_start(xfer, -1, NULL, 0);
 	if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_STARTED) {
@@ -524,38 +545,27 @@
 }
 
 void
-msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg)
+msn_slplink_process_msg(MsnSlpLink *slplink, MsnSlpHeader *header, const char *data, gsize len)
 {
 	MsnSlpMessage *slpmsg;
-	const char *data;
 	guint64 offset;
-	gsize len;
 	PurpleXfer *xfer = NULL;
 
-	if (purple_debug_is_verbose())
-		msn_slpmsg_show(msg);
-
-#ifdef MSN_DEBUG_SLP_FILES
-	debug_msg_to_file(msg, FALSE);
-#endif
-
-	if (msg->msnslp_header.total_size < msg->msnslp_header.length)
+	if (header->total_size < header->length)
 	{
 		purple_debug_error("msn", "This can't be good\n");
 		g_return_if_reached();
 	}
 
-	data = msn_message_get_bin_data(msg, &len);
-
-	offset = msg->msnslp_header.offset;
+	offset = header->offset;
 
 	if (offset == 0)
 	{
 		slpmsg = msn_slpmsg_new(slplink);
-		slpmsg->id = msg->msnslp_header.id;
-		slpmsg->session_id = msg->msnslp_header.session_id;
-		slpmsg->size = msg->msnslp_header.total_size;
-		slpmsg->flags = msg->msnslp_header.flags;
+		slpmsg->id = header->id;
+		slpmsg->session_id = header->session_id;
+		slpmsg->size = header->total_size;
+		slpmsg->flags = header->flags;
 
 		if (slpmsg->session_id)
 		{
@@ -600,7 +610,7 @@
 	}
 	else
 	{
-		slpmsg = msn_slplink_message_find(slplink, msg->msnslp_header.session_id, msg->msnslp_header.id);
+		slpmsg = msn_slplink_message_find(slplink, header->session_id, header->id);
 		if (slpmsg == NULL)
 		{
 			/* Probably the transfer was canceled */
@@ -648,8 +658,7 @@
 		return;
 #endif
 
-	if (msg->msnslp_header.offset + msg->msnslp_header.length
-		>= msg->msnslp_header.total_size)
+	if (header->offset + header->length >= header->total_size)
 	{
 		/* All the pieces of the slpmsg have been received */
 		MsnSlpCall *slpcall;
@@ -661,32 +670,45 @@
 			return;
 		}
 
-		if (!slpcall->wasted) {
-			if (slpmsg->flags == 0x100)
-			{
-				MsnDirectConn *directconn;
+		purple_debug_info("msn", "msn_slplink_process_msg: slpmsg complete\n");
 
-				directconn = slplink->directconn;
+		if (/* !slpcall->wasted && */ slpmsg->flags == 0x100)
+		{
 #if 0
-				if (!directconn->acked)
-					msn_directconn_send_handshake(directconn);
+			MsnDirectConn *directconn;
+
+			directconn = slplink->directconn;
+			if (!directconn->acked)
+				msn_directconn_send_handshake(directconn);
 #endif
-			}
-			else if (slpmsg->flags == 0x00 || slpmsg->flags == 0x1000000 ||  
-			         slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 ||  
-			         slpmsg->flags == 0x1000030)
-			{
-				/* Release all the messages and send the ACK */
+		}
+		else if (slpmsg->flags == 0x00 || slpmsg->flags == 0x1000000 ||
+		         slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 ||
+		         slpmsg->flags == 0x1000030)
+		{
+			/* Release all the messages and send the ACK */
 
-				msn_slplink_send_ack(slplink, msg);
+			if (slpcall->wait_for_socket) {
+				/*
+				 * Save ack for later because we have to send
+				 * a 200 OK message to the previous direct connect
+				 * invitation before ACK but the listening socket isn't
+				 * created yet.
+				 */
+				purple_debug_info("msn", "msn_slplink_process_msg: save ACK\n");
+
+				slpcall->slplink->dc->prev_ack = msn_slplink_create_ack(slplink, header);
+			} else if (!slpcall->wasted) {
+				purple_debug_info("msn", "msn_slplink_process_msg: send ACK\n");
+
+				msn_slplink_send_ack(slplink, header);
 				msn_slplink_send_queued_slpmsgs(slplink);
 			}
-
 		}
 
 		msn_slpmsg_destroy(slpmsg);
 
-		if (slpcall->wasted)
+		if (!slpcall->wait_for_socket && slpcall->wasted)
 			msn_slpcall_destroy(slpcall);
 	}
 }
--- a/libpurple/protocols/msn/slplink.h	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/slplink.h	Sun May 23 17:22:51 2010 +0000
@@ -42,6 +42,7 @@
 {
 	MsnSession *session;
 	MsnSwitchBoard *swboard;
+	MsnDirectConn *dc;
 
 	int refs;
 
@@ -49,8 +50,6 @@
 
 	int slp_seq_id;
 
-	MsnDirectConn *directconn;
-
 	GList *slp_calls;
 	GList *slp_msgs;
 
@@ -84,9 +83,10 @@
 void msn_slplink_send_slpmsg(MsnSlpLink *slplink,
 							 MsnSlpMessage *slpmsg);
 void msn_slplink_send_queued_slpmsgs(MsnSlpLink *slplink);
-void msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg);
+void msn_slplink_process_msg(MsnSlpLink *slplink, MsnSlpHeader *header, const char *data, gsize len);
 void msn_slplink_request_ft(MsnSlpLink *slplink, PurpleXfer *xfer);
 
+void msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg);
 /* Only exported for msn_xfer_write */
 void msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
 
--- a/libpurple/protocols/msn/state.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/state.c	Sun May 23 17:22:51 2010 +0000
@@ -260,7 +260,7 @@
 
 	if (msnobj == NULL)
 	{
-		msn_cmdproc_send(cmdproc, "CHG", "%s %d", state_text, caps);
+		msn_cmdproc_send(cmdproc, "CHG", "%s %u", state_text, caps);
 	}
 	else
 	{
@@ -268,7 +268,7 @@
 
 		msnobj_str = msn_object_to_string(msnobj);
 
-		msn_cmdproc_send(cmdproc, "CHG", "%s %d %s", state_text,
+		msn_cmdproc_send(cmdproc, "CHG", "%s %u %s", state_text,
 						 caps, purple_url_encode(msnobj_str));
 
 		g_free(msnobj_str);
--- a/libpurple/protocols/msn/switchboard.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Sun May 23 17:22:51 2010 +0000
@@ -87,8 +87,17 @@
 		purple_timeout_remove(swboard->reconn_timeout_h);
 
 	/* If it linked us is because its looking for trouble */
-	while (swboard->slplinks != NULL)
-		msn_slplink_destroy(swboard->slplinks->data);
+	while (swboard->slplinks != NULL) {
+		MsnSlpLink *slplink = swboard->slplinks->data;
+
+		/* Destroy only those slplinks which use the switchboard */
+		if (slplink->dc == NULL)
+			msn_slplink_destroy(slplink);
+		else {
+			swboard->slplinks = g_list_remove(swboard->slplinks, slplink);
+			slplink->swboard = NULL;
+		}
+	}
 
 	/* Destroy the message queue */
 	while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL)
--- a/libpurple/protocols/mxit/actions.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/actions.c	Sun May 23 17:22:51 2010 +0000
@@ -225,6 +225,13 @@
 	group = purple_request_field_group_new( NULL );
 	purple_request_fields_add_group( fields, group );
 
+	/* mxitId (read-only) */
+	if ( session->mxitId ) {
+		field = purple_request_field_string_new( "mxitid", _( "Your MXitId" ), session->mxitId, FALSE );
+		purple_request_field_string_set_editable( field, FALSE );
+		purple_request_field_group_add_field( group, field );
+	}
+
 	/* pin */
 	field = purple_request_field_string_new( "pin", _( "PIN" ), session->acc->password, FALSE );
 	purple_request_field_string_set_masked( field, TRUE );
@@ -252,7 +259,7 @@
 	purple_request_field_group_add_field( group, field );
 
 	/* title */
-	field = purple_request_field_string_new( "title", _( "Job Title" ), profile->title, FALSE );
+	field = purple_request_field_string_new( "title", _( "Title" ), profile->title, FALSE );
 	purple_request_field_group_add_field( group, field );
 
 	/* first name */
@@ -304,11 +311,12 @@
 	char	version[256];
 
 	g_snprintf( version, sizeof( version ), "MXit libPurple Plugin v%s\n"
-											"MXit Client Protocol v%s\n\n"
+											"MXit Client Protocol v%i.%i\n\n"
 											"Author:\nPieter Loubser\n\n"
 											"Contributors:\nAndrew Victor\n\n"
 											"Testers:\nBraeme Le Roux\n\n",
-											MXIT_PLUGIN_VERSION, MXIT_CP_RELEASE );
+											MXIT_PLUGIN_VERSION,
+											( MXIT_CP_PROTO_VESION / 10 ), ( MXIT_CP_PROTO_VESION % 10 ) );
 
 	mxit_popup( PURPLE_NOTIFY_MSG_INFO, _( "About" ), version );
 }
--- a/libpurple/protocols/mxit/formcmds.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/formcmds.c	Sun May 23 17:22:51 2010 +0000
@@ -42,7 +42,7 @@
 typedef enum
 {
 	MXIT_CMD_UNKNOWN = 0,		/* Unknown command */
-	MXIT_CMD_CLRSCR,			/* Clear screen (clrmsgscreen) */
+	MXIT_CMD_CLEAR,				/* Clear (clear) */
 	MXIT_CMD_SENDSMS,			/* Send SMS (sendsms) */
 	MXIT_CMD_REPLY,				/* Reply (reply) */
 	MXIT_CMD_PLATREQ,			/* Platform Request (platreq) */
@@ -138,8 +138,8 @@
 			type = g_hash_table_lookup(hash, "type");
 			if (type == NULL)								/* no command provided */
 				return MXIT_CMD_UNKNOWN;
-			else if (strcmp(type, "clrmsgscreen") == 0)		/* clear the screen */
-				return MXIT_CMD_CLRSCR;
+			else if (strcmp(type, "clear") == 0)			/* clear */
+				return MXIT_CMD_CLEAR;
 			else if (strcmp(type, "sendsms") == 0)			/* send an SMS */
 				return MXIT_CMD_SENDSMS;
 			else if (strcmp(type, "reply") == 0)			/* list of options */
@@ -205,27 +205,38 @@
 
 
 /*------------------------------------------------------------------------
- * Process a ClearScreen MXit command.
+ * Process a Clear MXit command.
+ *  [::op=cmd|type=clear|clearmsgscreen=true|auto=true|id=12345:]
  *
- *  @param session			The MXit session object
- *  @param from				The sender of the message.
+ *  @param session		The MXit session object
+ *  @param from			The sender of the message.
+ *  @param hash			The MXit command <key,value> map
  */
-static void command_clearscreen(struct MXitSession* session, const char* from)
+static void command_clear(struct MXitSession* session, const char* from, GHashTable* hash)
 {
 	PurpleConversation *conv;
+	char* clearmsgscreen;
 
-    conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, session->acc);
-    if (conv == NULL) {
-        purple_debug_error(MXIT_PLUGIN_ID, _( "Conversation with '%s' not found\n" ), from);
-        return;
-    }
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, session->acc);
+	if (conv == NULL) {
+		purple_debug_error(MXIT_PLUGIN_ID, _( "Conversation with '%s' not found\n" ), from);
+		return;
+	}
 
-	purple_conversation_clear_message_history(conv);			// TODO: This doesn't actually clear the screen.
+	clearmsgscreen = g_hash_table_lookup(hash, "clearmsgscreen");
+	if ( (clearmsgscreen) && (strcmp(clearmsgscreen, "true") == 0) ) {
+		/* this is a command to clear the chat screen */
+		purple_debug_info(MXIT_PLUGIN_ID, "Clear the screen\n");
+
+		purple_conversation_clear_message_history(conv);			// TODO: This doesn't actually clear the screen.
+	}
 }
 
 
 /*------------------------------------------------------------------------
  * Process a Reply MXit command.
+ *  [::op=cmd|type=reply|replymsg=back|selmsg=b) Back|id=12345:]
+ *  [::op=cmd|nm=rep|type=reply|replymsg=back|selmsg=b) Back|id=12345:]
  *
  *  @param mx			The received message data object
  *  @param hash			The MXit command <key,value> map
@@ -234,10 +245,21 @@
 {
 	char* replymsg;
 	char* selmsg;
+	char* nm;
 
 	selmsg = g_hash_table_lookup(hash, "selmsg");			/* find the selection message */
 	replymsg = g_hash_table_lookup(hash, "replymsg");		/* find the reply message */
-	if ((selmsg) && (replymsg)) {
+	nm = g_hash_table_lookup(hash, "nm");					/* name parameter */
+	if ((selmsg) && (replymsg) && (nm)) {
+		gchar*	seltext = g_markup_escape_text(purple_url_decode(selmsg), -1);
+		gchar*	replycmd = g_strdup_printf("::type=reply|nm=%s|res=%s|err=0:", nm, replymsg);
+
+		mxit_add_html_link( mx, replycmd, seltext );
+
+		g_free(seltext);
+		g_free(replycmd);
+	}
+	else if ((selmsg) && (replymsg)) {
 		gchar*	seltext = g_markup_escape_text(purple_url_decode(selmsg), -1);
 
 		mxit_add_html_link( mx, purple_url_decode(replymsg), seltext );
@@ -366,8 +388,8 @@
 			MXitCommandType type = command_type(hash);
 
 			switch (type) {
-				case MXIT_CMD_CLRSCR :
-					command_clearscreen(mx->session, mx->from);
+				case MXIT_CMD_CLEAR :
+					command_clear(mx->session, mx->from, hash);
 					break;
 				case MXIT_CMD_REPLY :
 					command_reply(mx, hash);
--- a/libpurple/protocols/mxit/mxit.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/mxit.c	Sun May 23 17:22:51 2010 +0000
@@ -92,8 +92,8 @@
 		goto skip;
 	con = purple_account_get_connection( account );
 
-//	/* determine if it's a command-response to send */
-//	is_command = g_str_has_prefix( parts[4], "::type=reply|" );
+	/* determine if it's a command-response to send */
+	is_command = g_str_has_prefix( parts[4], "::type=reply|" );
 
 	/* send click message back to MXit */
 	mxit_send_message( con->proto_data, parts[3], parts[4], FALSE, is_command );
@@ -352,6 +352,10 @@
 	if ( contact->subtype != 0 )
 		purple_notify_user_info_add_pair( info, _( "Subscription" ), mxit_convert_subtype_to_name( contact->subtype ) );
 
+	/* rejection message */
+	if ( ( contact->subtype == MXIT_SUBTYPE_REJECTED ) && ( contact->msg != NULL ) )
+		purple_notify_user_info_add_pair( info, _( "Rejection Message" ), contact->msg );
+
 	/* hidden number */
 	if ( contact->flags & MXIT_CFLAG_HIDDEN )
 		purple_notify_user_info_add_pair( info, _( "Hidden Number" ), _( "Yes" ) );
@@ -491,6 +495,8 @@
 			g_free( contact->statusMsg );
 		if ( contact->avatarId )
 			g_free( contact->avatarId );
+		if ( contact->msg )
+			g_free( contact->msg );
 		g_free( contact );
 	}
 
@@ -552,8 +558,8 @@
 static void mxit_get_info( PurpleConnection *gc, const char *who )
 {
 	struct MXitSession*		session			= (struct MXitSession*) gc->proto_data;
-	const char*				profilelist[]	= { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_HIDENUMBER, CP_PROFILE_FULLNAME,
-												CP_PROFILE_TITLE, CP_PROFILE_FIRSTNAME, CP_PROFILE_LASTNAME, CP_PROFILE_EMAIL };
+	const char*				profilelist[]	= { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_FULLNAME,
+												CP_PROFILE_FIRSTNAME, CP_PROFILE_LASTNAME, CP_PROFILE_REGCOUNTRY };
 
 	purple_debug_info( MXIT_PLUGIN_ID, "mxit_get_info: '%s'\n", who );
 
--- a/libpurple/protocols/mxit/mxit.h	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/mxit.h	Sun May 23 17:22:51 2010 +0000
@@ -63,7 +63,7 @@
 /* Plugin details */
 #define		MXIT_PLUGIN_ID				"prpl-loubserp-mxit"
 #define		MXIT_PLUGIN_NAME			"MXit"
-#define		MXIT_PLUGIN_VERSION			"2.3.0"
+#define		MXIT_PLUGIN_VERSION			"2.4.0"
 #define		MXIT_PLUGIN_EMAIL			"Pieter Loubser <libpurple@mxit.com>"
 #define		MXIT_PLUGIN_WWW				"http://www.mxit.com"
 #define		MXIT_PLUGIN_SUMMARY			"MXit Protocol Plugin"
@@ -151,6 +151,7 @@
 
 	/* personal (profile) */
 	struct MXitProfile*	profile;					/* user's profile information */
+	char*				mxitId;						/* the user's MXitId */
 
 	/* libpurple */
 	PurpleAccount*		acc;						/* pointer to the libpurple internal account struct */
--- a/libpurple/protocols/mxit/profile.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/profile.c	Sun May 23 17:22:51 2010 +0000
@@ -123,15 +123,14 @@
 	purple_notify_user_info_add_pair( info, _( "Nick Name" ), profile->nickname );
 	purple_notify_user_info_add_pair( info, _( "Birthday" ), profile->birthday );
 	purple_notify_user_info_add_pair( info, _( "Gender" ), profile->male ? _( "Male" ) : _( "Female" ) );
-	purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) );
-
-	purple_notify_user_info_add_section_break( info );
+//	purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) );
 
 	/* optional information */
-	purple_notify_user_info_add_pair( info, _( "Job Title" ), profile->title );
+//	purple_notify_user_info_add_pair( info, _( "Title" ), profile->title );
 	purple_notify_user_info_add_pair( info, _( "First Name" ), profile->firstname );
 	purple_notify_user_info_add_pair( info, _( "Last Name" ), profile->lastname );
-	purple_notify_user_info_add_pair( info, _( "Email" ), profile->email );
+//	purple_notify_user_info_add_pair( info, _( "Email" ), profile->email );
+	purple_notify_user_info_add_pair( info, _( "Country" ), profile->regcountry );
 
 	purple_notify_user_info_add_section_break( info );
 
@@ -151,6 +150,10 @@
 
 		/* subscription type */
 		purple_notify_user_info_add_pair( info, _( "Subscription" ), mxit_convert_subtype_to_name( contact->subtype ) );
+
+		/* hidden number */
+		purple_notify_user_info_add_pair( info, _( "Hidden Number" ), ( contact->flags & MXIT_CFLAG_HIDDEN ) ? _( "Yes" ) : _( "No" ) );
+
 	}
 
 	purple_notify_userinfo( session->con, username, info, NULL, NULL );
--- a/libpurple/protocols/mxit/profile.h	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/profile.h	Sun May 23 17:22:51 2010 +0000
@@ -43,6 +43,7 @@
 	char		lastname[64];						/* user's last name (aka 'surname') */
 	char		email[64];							/* user's email address */
 	char		mobilenr[21];						/* user's mobile number */
+	char		regcountry[3];						/* user's registered country code */
 
 	gboolean	hidden;								/* set if the user's msisdn should remain hidden */
 };
--- a/libpurple/protocols/mxit/protocol.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/protocol.c	Sun May 23 17:22:51 2010 +0000
@@ -672,10 +672,12 @@
 	/* convert the packet to a byte stream */
 	datalen = sprintf( data,	"ms=%s%c%s%c%i%c"			/* "ms"=password\1version\1getContacts\1 */
 								"%s%c%s%c%i%c"				/* capabilities\1dc\1features\1 */
-								"%s%c%s",					/* dialingcode\1locale */
+								"%s%c%s%c"					/* dialingcode\1locale\1 */
+								"%i%c%i%c%i",				/* maxReplyLen\1protocolVer\1lastRosterUpdate */
 								session->encpwd, CP_FLD_TERM, MXIT_CP_VERSION, CP_FLD_TERM, 1, CP_FLD_TERM,
 								MXIT_CP_CAP, CP_FLD_TERM, session->distcode, CP_FLD_TERM, MXIT_CP_FEATURES, CP_FLD_TERM,
-								session->dialcode, CP_FLD_TERM, locale
+								session->dialcode, CP_FLD_TERM, locale, CP_FLD_TERM,
+								CP_MAX_FILESIZE, CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0
 	);
 
 	/* include "custom resource" information */
@@ -1300,6 +1302,10 @@
 		session->http_sesid = atoi( records[0]->fields[0]->data );
 	}
 
+	/* extract MXitId (from protocol 5.9) */
+	if ( records[1]->fcount >= 9 )
+		session->mxitId = g_strdup( records[1]->fields[8]->data );
+
 	/* display the current splash-screen */
 	if ( splash_popup_enabled( session ) )
 		splash_display( session );
@@ -1513,10 +1519,14 @@
 		contact->mood = atoi( rec->fields[5]->data );
 
 		if ( rec->fcount > 6 ) {
-			/* added in protocol 5.9.0 - flags & subtype */
+			/* added in protocol 5.9 - flags & subtype */
 			contact->flags = atoi( rec->fields[6]->data );
 			contact->subtype = rec->fields[7]->data[0];
 		}
+		if ( rec->fcount > 8 ) {
+			/* added in protocol 6.0 - reject message */
+			contact->msg = g_strdup( rec->fields[8]->data );
+		}
 
 		/* add the contact to the buddy list */
 		if ( contact-> type == MXIT_TYPE_MULTIMX )			/* contact is a MultiMX room */
@@ -1582,7 +1592,16 @@
 
 	purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_extprofile: profile for '%s'\n", mxitId );
 
-	profile = g_new0( struct MXitProfile, 1 );
+	if ( records[0]->fields[0]->len == 0 ) {
+		/* no MXitId provided, so this must be our own profile information */
+		if ( session->profile == NULL )
+			session->profile = g_new0( struct MXitProfile, 1 );
+		profile = session->profile;
+	}
+	else {
+		/* is a buddy's profile */
+		profile = g_new0( struct MXitProfile, 1 );
+	}
 
 	/* set the count for attributes */
 	count = atoi( records[0]->fields[1]->data );
@@ -1647,23 +1666,19 @@
 			/* mobile number */
 			g_strlcpy( profile->mobilenr, fvalue, sizeof( profile->mobilenr ) );
 		}
+		else if ( strcmp( CP_PROFILE_REGCOUNTRY, fname ) == 0 ) {
+			/* registered country */
+			g_strlcpy( profile->regcountry, fvalue, sizeof( profile->regcountry ) );
+		}
 		else {
 			/* invalid profile attribute */
 			purple_debug_error( MXIT_PLUGIN_ID, "Invalid profile attribute received '%s' \n", fname );
 		}
 	}
 
-	if ( records[0]->fields[0]->len == 0 ) {
-		/* no MXit id provided, so this must be our own profile information */
-		if ( session->profile )
-			g_free( session->profile );
-		session->profile = profile;
-	}
-	else {
-		/* display other user's profile */
+	/* if this is not our profile, just display it */
+	if ( profile != session->profile ) {
 		mxit_show_profile( session, mxitId, profile );
-
-		/* cleanup */
 		g_free( profile );
 	}
 }
@@ -2472,6 +2487,8 @@
 	mxit_free_emoticon_cache( session );
 
 	/* free allocated memory */
+	if ( session->mxitId )
+		g_free( session->mxitId );
 	g_free( session->encpwd );
 	session->encpwd = NULL;
 
--- a/libpurple/protocols/mxit/protocol.h	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/protocol.h	Sun May 23 17:22:51 2010 +0000
@@ -85,11 +85,12 @@
 
 /* MXit client version */
 #define		MXIT_CP_DISTCODE		"P"						/* client distribution code (magic, do not touch!) */
-#define		MXIT_CP_RELEASE			"5.9.0"					/* client protocol release version supported */
+#define		MXIT_CP_RELEASE			"5.9.0"					/* client version */
 #define		MXIT_CP_ARCH			"Y"						/* client architecture series (Y not for Yoda but for PC-client) */
 #define		MXIT_CLIENT_ID			"LP"					/* client ID as specified by MXit */
 #define		MXIT_CP_PLATFORM		"PURPLE"				/* client platform */
 #define		MXIT_CP_VERSION			MXIT_CP_DISTCODE"-"MXIT_CP_RELEASE"-"MXIT_CP_ARCH"-"MXIT_CP_PLATFORM
+#define		MXIT_CP_PROTO_VESION	60						/* client protocol version */
 
 /* set operating system name */
 #if defined( __APPLE__ )
@@ -188,6 +189,7 @@
 #define		CP_PROFILE_LASTNAME		"lastname"				/* Last name (UTF8 String) */
 #define		CP_PROFILE_EMAIL		"email"					/* Email address (UTF8 String) */
 #define		CP_PROFILE_MOBILENR		"mobilenumber"			/* Mobile Number (UTF8 String) */
+#define		CP_PROFILE_REGCOUNTRY	"registeredcountry"		/* Registered Country Code (UTF8 String) */
 
 /* extended profile field types */
 #define		CP_PROF_TYPE_BOOL		0x02					/* boolean profile attribute type */
--- a/libpurple/protocols/mxit/roster.h	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/mxit/roster.h	Sun May 23 17:22:51 2010 +0000
@@ -105,7 +105,7 @@
 	short		presence;							/* presence state */
 	short		subtype;							/* subscription type */
 
-	char*		msg;								/* invite message */
+	char*		msg;								/* invite/rejection message */
 
 	char		customMood[16];						/* custom mood */
 	char*		statusMsg;							/* status message */
--- a/libpurple/protocols/qq/qq_base.c	Thu May 20 13:51:24 2010 +0000
+++ b/libpurple/protocols/qq/qq_base.c	Sun May 23 17:22:51 2010 +0000
@@ -811,11 +811,11 @@
 static void captcha_input_cancel_cb(qq_captcha_request *captcha_req,
 		PurpleRequestFields *fields)
 {
-	captcha_request_destory(captcha_req);
-
 	purple_connection_error_reason(captcha_req->gc,
 			PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
 			_("Failed captcha verification"));
+
+	captcha_request_destory(captcha_req);
 }
 
 static void captcha_input_ok_cb(qq_captcha_request *captcha_req,
--- a/pidgin/Makefile.am	Thu May 20 13:51:24 2010 +0000
+++ b/pidgin/Makefile.am	Sun May 23 17:22:51 2010 +0000
@@ -22,6 +22,7 @@
 		win32/wspell.c \
 		win32/wspell.h \
 		win32/nsis/generate_gtk_zip.sh \
+		win32/nsis/rpm2zip.sh \
 		win32/nsis/pixmaps/pidgin-header.bmp \
 		win32/nsis/pixmaps/pidgin-intro.bmp \
 		win32/nsis/pixmaps/pidgin-install.ico \
--- a/pidgin/pixmaps/emotes/default/24/Makefile.am	Thu May 20 13:51:24 2010 +0000
+++ b/pidgin/pixmaps/emotes/default/24/Makefile.am	Sun May 23 17:22:51 2010 +0000
@@ -27,6 +27,7 @@
     car.png \
     cat.png \
     chicken.png \
+    chilli.png \
     cigarette.png \
     clap.png \
     clock.png \
@@ -109,6 +110,7 @@
     moneymouth.png \
     monkey.png \
     moon.png \
+    mrgreen.png \
     msn-away.png \
     msn-busy.png \
     msn_online.png \
Binary file pidgin/pixmaps/emotes/default/24/chilli.png has changed
--- a/pidgin/pixmaps/emotes/default/24/default.theme.in	Thu May 20 13:51:24 2010 +0000
+++ b/pidgin/pixmaps/emotes/default/24/default.theme.in	Sun May 23 17:22:51 2010 +0000
@@ -451,3 +451,41 @@
 ! monkey.png        :-(|)   :(|)    8-|)
 ! cyclops.png       O-)     o-)
 
+
+# MXit standard emoticons
+[MXit]
+happy.png           :-)     :)
+sad.png             :-(     :(
+wink.png            ;-)     ;)
+excited.png         :-D     :D     :->      :>
+neutral.png         :-|     :|
+shock.png           :-O     :O
+tongue.png          :-P     :P
+embarrassed.png     :-$     :$
+glasses-cool.png    8-)
+in_love.png         (H)
+rose.png            (F)
+### Added in v3.0
+boy.png             (m)
+girl.png            (f)
+star.png            (*)
+chilli.png          (c)
+kiss.png            (x)
+lamp.png            (i)
+pissed-off.png      :e      :-e
+shut-mouth.png      :-x     :x
+thunder.png         (z)
+coffee.png          (U)
+mrgreen.png         (G)
+### Added in v5.0
+sick.png            :o(
+excruciating.png    :-{     :{
+amorous.png         :-}     :}
+eyeroll.png         8-o     8o
+crying.png          :'(
+thinking.png        :-?     :?
+drool.png           :-~     :~
+sleeping.png        :-z     :z
+lying.png           :L)
+glasses-nerdy.png   8-|     8|
+pirate.png          P-)
Binary file pidgin/pixmaps/emotes/default/24/mrgreen.png has changed
--- a/pidgin/win32/nsis/generate_gtk_zip.sh	Thu May 20 13:51:24 2010 +0000
+++ b/pidgin/win32/nsis/generate_gtk_zip.sh	Sun May 23 17:22:51 2010 +0000
@@ -3,8 +3,8 @@
 
 PIDGIN_BASE=$1
 
-if [ ! -e $PIDGIN_BASE/ChangeLog.win32 ]; then
-	echo `basename $0` must must have the pidgin base dir specified as a parameter.
+if [ ! -e $PIDGIN_BASE/ChangeLog ]; then
+	echo $(basename $0) must must have the pidgin base dir specified as a parameter.
 	exit 1
 fi
 
@@ -42,12 +42,18 @@
 function download_and_extract {
 	URL=${1%%\ *}
 	NAME=${1#*\ }
-	FILE=`basename $URL`
+	FILE=$(basename $URL)
 	if [ ! -e $FILE ]; then
 		echo Downloading $NAME
-		wget $URL
+		wget $URL || return 1
 	fi
-	unzip -q $FILE -d $INSTALL_DIR
+	EXTENSION=${FILE##*.}
+	#This is an OpenSuSE build service RPM
+	if [ $EXTENSION == 'rpm' ]; then
+		echo "Generating zip from $FILE"
+		FILE=$(../rpm2zip.sh $FILE)
+	fi
+	unzip -q $FILE -d $INSTALL_DIR || exit 1
 	echo "$NAME" >> $CONTENTS_FILE
 }
 
@@ -63,9 +69,9 @@
 #Blow away translations that we don't have in Pidgin
 for LOCALE_DIR in $INSTALL_DIR/share/locale/*
 do
-	LOCALE=`basename $LOCALE_DIR`
+	LOCALE=$(basename $LOCALE_DIR)
 	if [ ! -e $PIDGIN_BASE/po/$LOCALE.po ]; then
-		echo Remove $LOCALE translation as it is missing from Pidgin
+		echo Removing $LOCALE translation as it is missing from Pidgin
 		rm -r $LOCALE_DIR
 	fi
 done
@@ -73,3 +79,5 @@
 #Generate zip file to be included in installer
 zip -9 -r ../gtk-runtime-$BUNDLE_VERSION.zip Gtk
 
+exit 0
+
--- a/pidgin/win32/nsis/nsis_translations.desktop.in	Thu May 20 13:51:24 2010 +0000
+++ b/pidgin/win32/nsis/nsis_translations.desktop.in	Sun May 23 17:22:51 2010 +0000
@@ -29,6 +29,8 @@
 _PIDGINDESKTOPSHORTCUTDESC=Create a shortcut to Pidgin on the Desktop
 #Installer Subsection Detailed Description
 _PIDGINSTARTMENUSHORTCUTDESC=Create a Start Menu entry for Pidgin
+#Installer Subsection Detailed Description
+_GTKSECTIONDESCRIPTION=A multi-platform GUI toolkit, used by Pidgin
 #Installer Subsection Text
 _DEBUGSYMBOLSSECTIONTITLE=Debug Symbols (for reporting crashes)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/win32/nsis/rpm2zip.sh	Sun May 23 17:22:51 2010 +0000
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+here=`pwd`
+for F in $*; do
+    case $F in
+        mingw32-*.noarch.rpm|mingw64-*.noarch.rpm|*/mingw32-*.noarch.rpm|*/mingw64-*.noarch.rpm)
+        package=`rpm -qp $F 2>/dev/null`
+        case $package in
+            mingw32-*|mingw64-*)
+            case $package in
+                mingw32-*)
+                cpu=i686
+                bits=32
+                ;;
+                mingw64-*)
+                cpu=x86_64
+                bits=64
+                ;;
+            esac
+            origname=`rpm -qp --queryformat='%{NAME}'  $F 2>/dev/null`
+            name=$origname
+            case $name in
+                *-devel)
+                name=${name%el}
+                ;;
+            esac
+            shortpackage="$name"_`rpm -qp --queryformat='%{VERSION}-%{RELEASE}'_win${bits} $F 2>/dev/null`
+            shortpackage=${shortpackage#mingw32-}
+            shortpackage=${shortpackage#mingw64-}
+            shortname=$name
+            shortname=${shortname#mingw32-}
+            shortname=${shortname#mingw64-}
+            tmp=`mktemp -d`
+            #rpm2cpio $F | lzcat | (cd $tmp && cpio --quiet -id)
+            rpm2cpio $F |  (cd $tmp && cpio --quiet -id)
+            (
+                cd $tmp
+                zipfile="$here/$shortpackage.zip"
+                rm -f $zipfile
+                (cd usr/${cpu}-pc-mingw32/sys-root/mingw && zip -q -r -D $zipfile .)
+                if [ -d usr/share/doc/packages/$origname ] ; then
+                    mv usr/share/doc/packages/$origname usr/share/doc/packages/$shortname
+                    (cd usr && zip -q -r -D $zipfile share/doc/packages/$shortname)
+                fi
+                mkdir -p manifest
+                unzip -l $zipfile >manifest/$shortpackage.mft
+                zip -q $zipfile manifest/$shortpackage.mft
+                N=`unzip -l $zipfile | wc -l | sed -e 's/^ *\([0-9]*\).*/\1/'`
+                Nm1=`expr $N - 1`
+                unzip -l $zipfile | sed -e "1,3 d" -e "$Nm1,$N d" | awk '{print $4}' | grep -v -E '/$' >manifest/$shortpackage.mft
+                zip -q $zipfile manifest/$shortpackage.mft
+                echo $zipfile
+            )
+            rm -rf $tmp
+            ;;
+            *)
+            echo $F is not a mingw32/64 RPM package >&2
+            ;;
+        esac
+        ;;
+        *)
+        echo $F is not a mingw32/64 RPM package >&2
+        ;;
+    esac
+done
--- a/po/ChangeLog	Thu May 20 13:51:24 2010 +0000
+++ b/po/ChangeLog	Sun May 23 17:22:51 2010 +0000
@@ -1,6 +1,7 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
 version 2.7.1
+	* Hebrew translation updated (Shalom Craimer)
 
 version 2.7.0
 	* Afrikaans translation updated (Friedel Wolff)
--- a/po/fr.po	Thu May 20 13:51:24 2010 +0000
+++ b/po/fr.po	Sun May 23 17:22:51 2010 +0000
@@ -21,8 +21,8 @@
 msgstr ""
 "Project-Id-Version: Pidgin\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-05-17 23:18-0400\n"
-"PO-Revision-Date: 2010-02-11 19:10+0100\n"
+"POT-Creation-Date: 2010-05-22 17:13+0200\n"
+"PO-Revision-Date: 2010-02-22 17:08+0200\n"
 "Last-Translator: Éric Boumaour <zongo_fr@users.sourceforge.net>\n"
 "Language-Team: fr <fr@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -1366,6 +1366,7 @@
 msgid "Saved Statuses"
 msgstr "États prédéfinis"
 
+#. title
 msgid "Title"
 msgstr "Titre"
 
@@ -1659,13 +1660,11 @@
 msgid "Set User Info"
 msgstr "Modifier les informations"
 
-#, fuzzy
 msgid "This protocol does not support setting a public alias."
-msgstr "Les salons de discussions ne sont pas supportés par ce protocole."
-
-#, fuzzy
+msgstr "Ce protocole ne permet pas de choisir un alias public."
+
 msgid "This protocol does not support fetching the public alias."
-msgstr "Les salons de discussions ne sont pas supportés par ce protocole."
+msgstr "Ce protocole ne permet pas de récupérer un alias public."
 
 msgid "Unknown"
 msgstr "Inconnu"
@@ -1924,7 +1923,6 @@
 msgid "Thread creation failure: %s"
 msgstr "Échec de la création de processus :%s"
 
-#. Data is assumed to be the destination bn
 msgid "Unknown reason"
 msgstr "Raison inconnue"
 
@@ -3216,6 +3214,9 @@
 msgstr "UIN"
 
 #. first name
+#. purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) );
+#. optional information
+#. purple_notify_user_info_add_pair( info, _( "Title" ), profile->title );
 msgid "First Name"
 msgstr "Prénom"
 
@@ -3867,38 +3868,36 @@
 msgid "SASL error: %s"
 msgstr "Erreur SASL : %s"
 
-#, fuzzy
 msgid "Invalid Encoding"
-msgstr "Condition de saisie non valide."
-
-#, fuzzy
+msgstr "Encodage non valide."
+
 msgid "Unsupported Extension"
-msgstr "Version non supportée"
+msgstr "Extension non supportée"
 
 msgid ""
 "Unexpected response from the server.  This may indicate a possible MITM "
 "attack"
 msgstr ""
+"Réponse inattendue du serveur. Ceci pourrait provenir d'une attaque MITM."
 
 msgid ""
 "The server does support channel binding, but did not appear to advertise "
 "it.  This indicates a likely MITM attack"
 msgstr ""
-
-#, fuzzy
+"Ce serveur ne supporte pas le \"channel binding\" alors qu'il dit le "
+"supporter. Ceci pourrait provenir d'une attaque MITM."
+
 msgid "Server does not support channel binding"
-msgstr "Le serveur ne supporte pas le blocage"
-
-#, fuzzy
+msgstr "Le serveur ne supporte pas le \"channel binding\"."
+
 msgid "Unsupported channel binding method"
-msgstr "Codage de caractère non supporté"
+msgstr "Méthode de \"channel binding\" non supportée"
 
 msgid "User not found"
 msgstr "Utilisateur non trouvé"
 
-#, fuzzy
 msgid "Invalid Username Encoding"
-msgstr "Nom d'utilisateur non valide"
+msgstr "Encodage du nom d'utilisateur non valide"
 
 msgid "Resource Constraint"
 msgstr "Limitation sur la ressource"
@@ -3966,6 +3965,7 @@
 msgid "Postal Code"
 msgstr "Code postal"
 
+#. purple_notify_user_info_add_pair( info, _( "Email" ), profile->email );
 msgid "Country"
 msgstr "Pays"
 
@@ -3980,8 +3980,6 @@
 msgid "Organization Unit"
 msgstr "Service"
 
-#. title
-#. optional information
 msgid "Job Title"
 msgstr "Position"
 
@@ -4222,9 +4220,8 @@
 msgid "Invalid XMPP ID"
 msgstr "Identifiant XMPP non valide."
 
-#, fuzzy
 msgid "Invalid XMPP ID. Username portion must be set."
-msgstr "Identifiant XMPP non valide. Le domaine doit être saisi."
+msgstr "Identifiant XMPP non valide. Le nom d'utilisateur doit être saisi."
 
 msgid "Invalid XMPP ID. Domain must be set."
 msgstr "Identifiant XMPP non valide. Le domaine doit être saisi."
@@ -4360,13 +4357,11 @@
 msgid "Allow Buzz"
 msgstr "Autoriser les Buzz"
 
-#, fuzzy
 msgid "Mood Name"
-msgstr "Deuxième prénom"
-
-#, fuzzy
+msgstr "Nom de l'humeur"
+
 msgid "Mood Comment"
-msgstr "Commentaire"
+msgstr "Commentaire de l'humeur"
 
 #. primitive
 #. ID
@@ -4661,9 +4656,8 @@
 msgid "Initiate Media"
 msgstr "Session média"
 
-#, fuzzy
 msgid "Account does not support PEP, can't set mood"
-msgstr "Les salons de discussions ne sont pas supportés par ce protocole."
+msgstr "Ce compte ne supporte pas PEP, impossible de changer l'humeur."
 
 msgid "config:  Configure a chat room."
 msgstr "config : Configurer un salon de discussions"
@@ -4721,9 +4715,8 @@
 msgid "buzz: Buzz a user to get their attention"
 msgstr "buzz : Faire sonner chez un contact pour attirer son attention."
 
-#, fuzzy
 msgid "mood: Set current user mood"
-msgstr "Choisissez un des utilisateurs"
+msgstr "mood : Changer d'humeur pour l'utilisateur"
 
 msgid "Extended Away"
 msgstr "Longue absence"
@@ -4807,13 +4800,13 @@
 "envoyée."
 
 msgid "XMPP stream header missing"
-msgstr ""
+msgstr "En-tête de flux XMPP manquante"
 
 msgid "XMPP Version Mismatch"
-msgstr ""
+msgstr "Version XMPP incorrecte"
 
 msgid "XMPP stream missing ID"
-msgstr ""
+msgstr "ID de flux XMPP manquant"
 
 msgid "XML Parse error"
 msgstr "Erreur de lecture du XML"
@@ -4894,31 +4887,26 @@
 "Veuillez sélectionner parmi les ressources de %s, à laquelle vous voulez "
 "envoyer un fichier"
 
-#, fuzzy
 msgid "Afraid"
-msgstr "Arabe"
-
-#, fuzzy
+msgstr "Apeuré"
+
 msgid "Amazed"
-msgstr "Honteux"
-
-#, fuzzy
+msgstr "Impressionné"
+
 msgid "Amorous"
-msgstr "Glorieux"
+msgstr "Amoureux"
 
 msgid "Angry"
 msgstr "En colère"
 
-#, fuzzy
 msgid "Annoyed"
-msgstr "Banni"
+msgstr "Ennuyé"
 
 msgid "Anxious"
 msgstr "Anxieux"
 
-#, fuzzy
 msgid "Aroused"
-msgstr "Vous envoyez"
+msgstr "Excité"
 
 msgid "Ashamed"
 msgstr "Honteux"
@@ -4926,152 +4914,125 @@
 msgid "Bored"
 msgstr "Ennuyé"
 
-#, fuzzy
 msgid "Brave"
-msgstr "Enregistrer"
-
-#, fuzzy
+msgstr "Courageux"
+
 msgid "Calm"
-msgstr "Domaine"
-
-#, fuzzy
+msgstr "Calme"
+
 msgid "Cautious"
-msgstr "Discussions"
-
-#, fuzzy
+msgstr "Prudent"
+
 msgid "Cold"
-msgstr "Gras"
-
-#, fuzzy
+msgstr "Froid"
+
 msgid "Confident"
-msgstr "Conflit"
-
-#, fuzzy
+msgstr "Confiant"
+
 msgid "Confused"
-msgstr "Continuer"
-
-#, fuzzy
+msgstr "Déconcerté"
+
 msgid "Contemplative"
-msgstr "Contact"
-
-#, fuzzy
+msgstr "Penseur"
+
 msgid "Contented"
-msgstr "Connecté"
-
-#, fuzzy
+msgstr "Content"
+
 msgid "Cranky"
-msgstr "Société"
+msgstr "À cran"
 
 msgid "Crazy"
-msgstr ""
-
-#, fuzzy
+msgstr "Fou"
+
 msgid "Creative"
-msgstr "Créer"
-
-#, fuzzy
+msgstr "Créatif"
+
 msgid "Curious"
-msgstr "Glorieux"
-
-#, fuzzy
+msgstr "Curieux"
+
 msgid "Dejected"
-msgstr "Refusé"
-
-#, fuzzy
+msgstr "Découragé"
+
 msgid "Depressed"
-msgstr "Supprimé"
-
-#, fuzzy
+msgstr "Déprimé"
+
 msgid "Disappointed"
-msgstr "Déconnecté"
+msgstr "Déçu"
 
 msgid "Disgusted"
-msgstr ""
-
-#, fuzzy
+msgstr "Dégouté"
+
 msgid "Dismayed"
-msgstr "Désactivé"
-
-#, fuzzy
+msgstr "Consterné"
+
 msgid "Distracted"
-msgstr "Détaché"
+msgstr "Distrait"
 
 msgid "Embarrassed"
-msgstr ""
-
-#, fuzzy
+msgstr "Embarrassé"
+
 msgid "Envious"
-msgstr "Anxieux"
+msgstr "Jaloux"
 
 msgid "Excited"
 msgstr "Excité"
 
-#, fuzzy
 msgid "Flirtatious"
-msgstr "Glorieux"
-
-#, fuzzy
+msgstr "Flirtant"
+
 msgid "Frustrated"
-msgstr "Prénom :"
+msgstr "Frustré"
 
 msgid "Grateful"
-msgstr ""
-
-#, fuzzy
+msgstr "Reconnaissant"
+
 msgid "Grieving"
-msgstr "Récupération en cours..."
+msgstr "Chagriné"
 
 msgid "Grumpy"
 msgstr "Grognon"
 
-#, fuzzy
 msgid "Guilty"
-msgstr "Localité"
+msgstr "Coupable"
 
 msgid "Happy"
 msgstr "Heureux"
 
 msgid "Hopeful"
-msgstr ""
+msgstr "Plein d'espoir"
 
 msgid "Hot"
 msgstr "Chaud"
 
 msgid "Humbled"
-msgstr ""
+msgstr "Humble"
 
 msgid "Humiliated"
-msgstr ""
-
-#, fuzzy
+msgstr "Humilié"
+
 msgid "Hungry"
-msgstr "En colère"
-
-#, fuzzy
+msgstr "Affamé"
+
 msgid "Hurt"
-msgstr "Humour"
+msgstr "Blessé"
 
 msgid "Impressed"
-msgstr ""
-
-#, fuzzy
+msgstr "Impressionné"
+
 msgid "In awe"
-msgstr "Amoureux"
+msgstr "Admiratif"
 
 msgid "In love"
 msgstr "Amoureux"
 
-#, fuzzy
 msgid "Indignant"
-msgstr "Indonésien"
-
-#, fuzzy
+msgstr "Indigné"
+
 msgid "Interested"
-msgstr "Intérêts"
-
-#, fuzzy
+msgstr "Intéressé"
+
 msgid "Intoxicated"
-msgstr "Invité"
+msgstr "Intoxiqué"
 
 msgid "Invincible"
 msgstr "Invincible"
@@ -5079,83 +5040,68 @@
 msgid "Jealous"
 msgstr "Jaloux"
 
-#, fuzzy
 msgid "Lonely"
-msgstr "Singe"
-
-#, fuzzy
+msgstr "Seul"
+
 msgid "Lost"
-msgstr "Le plus fort"
+msgstr "Perdu"
 
 msgid "Lucky"
-msgstr ""
-
-#, fuzzy
+msgstr "Chanceux"
+
 msgid "Mean"
-msgstr "Allemand"
-
-#, fuzzy
+msgstr "Méchant"
+
 msgid "Moody"
-msgstr "Humeur"
+msgstr "Morose"
 
 msgid "Nervous"
-msgstr ""
-
-#, fuzzy
+msgstr "Nerveux"
+
 msgid "Neutral"
-msgstr "Détail"
-
-#, fuzzy
+msgstr "Neutre"
+
 msgid "Offended"
-msgstr "Déconnecté"
+msgstr "Offensé"
 
 msgid "Outraged"
-msgstr ""
-
-#, fuzzy
+msgstr "Outragé"
+
 msgid "Playful"
-msgstr "Jouer"
-
-#, fuzzy
+msgstr "Joueur"
+
 msgid "Proud"
-msgstr "Fort"
-
-#, fuzzy
+msgstr "Fier"
+
 msgid "Relaxed"
-msgstr "Nom réel"
-
-#, fuzzy
+msgstr "Relaxé"
+
 msgid "Relieved"
-msgstr "Reçu"
-
-#, fuzzy
+msgstr "Soulagé"
+
 msgid "Remorseful"
-msgstr "Supprimer"
-
-#, fuzzy
+msgstr "Pris de remords"
+
 msgid "Restless"
-msgstr "S'enregistrer"
+msgstr "Agité"
 
 msgid "Sad"
 msgstr "Triste"
 
-#, fuzzy
 msgid "Sarcastic"
-msgstr "Marâthî"
+msgstr "Sarcastique"
 
 msgid "Satisfied"
-msgstr ""
-
-#, fuzzy
+msgstr "Satisfait"
+
 msgid "Serious"
-msgstr "Glorieux"
-
-#, fuzzy
+msgstr "Sérieux"
+
 msgid "Shocked"
-msgstr "Bloqué"
+msgstr "Choqué"
 
 msgid "Shy"
-msgstr ""
+msgstr "Timide"
 
 msgid "Sick"
 msgstr "Malade"
@@ -5165,40 +5111,34 @@
 msgstr "Somnolant"
 
 msgid "Spontaneous"
-msgstr ""
-
-#, fuzzy
+msgstr "Spontané"
+
 msgid "Stressed"
-msgstr "Vitesse"
-
-#, fuzzy
+msgstr "Stressé"
+
 msgid "Strong"
-msgstr "Chanson"
+msgstr "Fort"
 
 msgid "Surprised"
-msgstr ""
+msgstr "Surpris"
 
 msgid "Thankful"
-msgstr ""
+msgstr "Remerciant"
 
 msgid "Thirsty"
-msgstr ""
-
-#, fuzzy
+msgstr "Assoiffé"
+
 msgid "Tired"
-msgstr "Fire"
-
-#, fuzzy
+msgstr "Fatigué"
+
 msgid "Undefined"
-msgstr "Souligné"
-
-#, fuzzy
+msgstr "Indéfini"
+
 msgid "Weak"
-msgstr "Frapper"
-
-#, fuzzy
+msgstr "Faible"
+
 msgid "Worried"
-msgstr "Ennuyé"
+msgstr "Inquiet"
 
 msgid "Set User Nickname"
 msgstr "Changer de pseudo"
@@ -5800,6 +5740,9 @@
 msgid "Show custom smileys"
 msgstr "Afficher les frimousses personnalisées"
 
+msgid "Allow direct connections"
+msgstr "Autoriser les connexions directes"
+
 msgid "nudge: nudge a user to get their attention"
 msgstr "nudge : donner un « Nudge » à un contact pour attirer son attention."
 
@@ -6029,6 +5972,9 @@
 "Les informations de votre profil n'ont pu être récupérées. Veuillez "
 "réessayer plus tard."
 
+msgid "Your MXitId"
+msgstr "Votre MXitId"
+
 #. pin
 msgid "PIN"
 msgstr "Code"
@@ -6183,6 +6129,10 @@
 msgid "Status Message"
 msgstr "Messages d'état"
 
+msgid "Rejection Message"
+msgstr "Message de refus"
+
+#. hidden number
 msgid "Hidden Number"
 msgstr "Numéro caché"
 
@@ -6962,9 +6912,9 @@
 msgid "AOL does not allow your screen name to authenticate here"
 msgstr "AOL n'autorise pas votre nom d'utilisateur pour authentification ici."
 
-#, fuzzy, c-format
+#, c-format
 msgid "Error requesting %s"
-msgstr "Erreur à la demande de %s : %s"
+msgstr "Erreur à la demande de %s"
 
 msgid "Could not join chat room"
 msgstr "Impossible de rejoindre le salon de discussions"
@@ -6972,105 +6922,146 @@
 msgid "Invalid chat room name"
 msgstr "Nom de salon non valide"
 
+msgid "Invalid error"
+msgstr "Erreur non valide"
+
+msgid "Cannot receive IM due to parental controls"
+msgstr "Impossible de recevoir le message à cause du contrôle parental"
+
+msgid "Cannot send SMS without accepting terms"
+msgstr "Impossible d'envoyer de SMS sans accepter les termes"
+
+msgid "Cannot send SMS"
+msgstr "Impossible d'envoyer le SMS"
+
+#. SMS_WITHOUT_DISCLAIMER is weird
+msgid "Cannot send SMS to this country"
+msgstr "Impossible d'envoyer le SMS vers ce pays"
+
+#. Undocumented
+msgid "Cannot send SMS to unknown country"
+msgstr "Impossible d'envoyer le SMS vers un pays inconnu"
+
+msgid "Bot accounts cannot initiate IMs"
+msgstr "Les comptes Bot ne peuvent pas commencer les conversations"
+
+msgid "Bot account cannot IM this user"
+msgstr "Le compte Bot ne peut pas envoyer de message à cette personne"
+
+msgid "Bot account reached IM limit"
+msgstr "Le compte Bot a atteint sa limite de messages"
+
+msgid "Bot account reached daily IM limit"
+msgstr "Le compte Bot a atteint sa limite de messages quotidiens"
+
+msgid "Bot account reached monthly IM limit"
+msgstr "Le compte Bot a atteint sa limite de messages mensuels"
+
+msgid "Unable to receive offline messages"
+msgstr "Impossible de recevoir les messages déconnectés"
+
+msgid "Offline message store full"
+msgstr "Stockage des messages déconnectés plein"
+
+#, c-format
+msgid "Unable to send message: %s (%s)"
+msgstr "Impossible d'envoyer le message : %s (%s)"
+
+#, c-format
+msgid "Unable to send message: %s"
+msgstr "Impossible d'envoyer le message : %s"
+
+#, c-format
+msgid "Unable to send message to %s: %s (%s)"
+msgstr "Impossible d'envoyer le message vers %s : %s (%s)"
+
+#, c-format
+msgid "Unable to send message to %s: %s"
+msgstr "Impossible d'envoyer le message vers %s : %s"
+
 msgid "Thinking"
-msgstr ""
-
-#, fuzzy
+msgstr "En pleine réflexion"
+
 msgid "Shopping"
-msgstr "S'arrête d'écrire"
-
-#, fuzzy
+msgstr "En courses"
+
 msgid "Questioning"
-msgstr "Boite de message pour demande"
-
-#, fuzzy
+msgstr "En plein questionnement"
+
 msgid "Eating"
-msgstr "Bipeur"
-
-#, fuzzy
+msgstr "En train de manger"
+
 msgid "Watching a movie"
-msgstr "Joue"
+msgstr "Regarde un film"
 
 msgid "Typing"
 msgstr "En train d'écrire"
 
-#, fuzzy
 msgid "At the office"
-msgstr "Pas au travail"
+msgstr "Au travail"
 
 msgid "Taking a bath"
-msgstr ""
+msgstr "Prend un bain"
 
 msgid "Watching TV"
-msgstr ""
-
-#, fuzzy
+msgstr "Regarde la télé"
+
 msgid "Having fun"
-msgstr "Raccrocher"
-
-#, fuzzy
+msgstr "S'amuse"
+
 msgid "Sleeping"
-msgstr "Somnolant"
+msgstr "Dort"
 
 msgid "Using a PDA"
-msgstr ""
-
-#, fuzzy
+msgstr "Utilise un PDA"
+
 msgid "Meeting friends"
-msgstr "Amis de messagerie"
-
-#, fuzzy
+msgstr "Rencontre des amis"
+
 msgid "On the phone"
 msgstr "Au téléphone"
 
-#, fuzzy
 msgid "Surfing"
-msgstr "Récurrente"
+msgstr "Surf"
 
 #. "I am mobile." / "John is mobile."
 msgid "Mobile"
 msgstr "Téléphone portable"
 
 msgid "Searching the web"
-msgstr ""
+msgstr "Recherche sur internet"
 
 msgid "At a party"
-msgstr ""
+msgstr "À une fête"
 
 msgid "Having Coffee"
-msgstr ""
+msgstr "Prend un café"
 
 #. Playing video games
-#, fuzzy
 msgid "Gaming"
-msgstr "L'utilisateur joue"
+msgstr "Joue"
 
 msgid "Browsing the web"
-msgstr ""
-
-#, fuzzy
+msgstr "Surf le web"
+
 msgid "Smoking"
-msgstr "Chanson"
-
-#, fuzzy
+msgstr "Fume"
+
 msgid "Writing"
-msgstr "Travaille"
+msgstr "Écrit"
 
 #. Drinking [Alcohol]
-#, fuzzy
 msgid "Drinking"
-msgstr "Travaille"
+msgstr "Bois"
 
 msgid "Listening to music"
 msgstr "Écoute de la musique"
 
-#, fuzzy
 msgid "Studying"
-msgstr "Envoi en cours"
-
-#, fuzzy
+msgstr "Étudie"
+
 msgid "In the restroom"
-msgstr "Intérêts"
+msgstr "Aux toilettes"
 
 msgid "Received invalid data on connection with server"
 msgstr "Données non valides reçues à la connexion sur le serveur."
@@ -7140,116 +7131,6 @@
 msgstr ""
 "Le fichier %s fait %s, ce qui est plus gros que la taille maximale de %s."
 
-msgid "Invalid error"
-msgstr "Erreur non valide"
-
-msgid "Invalid SNAC"
-msgstr "SNAC non valide"
-
-msgid "Rate to host"
-msgstr "Fréquence vers l'hôte"
-
-msgid "Rate to client"
-msgstr "Fréquence vers le client"
-
-msgid "Service unavailable"
-msgstr "Service non disponible"
-
-msgid "Service not defined"
-msgstr "Service non défini"
-
-msgid "Obsolete SNAC"
-msgstr "SNAC obsolète"
-
-msgid "Not supported by host"
-msgstr "Non supporté par l'hôte"
-
-msgid "Not supported by client"
-msgstr "Non supporté par le client"
-
-msgid "Refused by client"
-msgstr "Refusé par le client"
-
-msgid "Reply too big"
-msgstr "Réponse trop grosse"
-
-msgid "Responses lost"
-msgstr "Réponses perdues"
-
-msgid "Request denied"
-msgstr "Requête refusée"
-
-msgid "Busted SNAC payload"
-msgstr "Charge SNAC incorrecte"
-
-msgid "Insufficient rights"
-msgstr "Droits insuffisants"
-
-msgid "In local permit/deny"
-msgstr "Dans l'autorisation/interdiction locale"
-
-msgid "Warning level too high (sender)"
-msgstr "Niveau d'avertissement trop élevé (émission)"
-
-msgid "Warning level too high (receiver)"
-msgstr "Niveau d'avertissement trop élevé (réception)"
-
-msgid "User temporarily unavailable"
-msgstr "L'utilisateur est temporairement indisponible."
-
-msgid "No match"
-msgstr "Aucun résultat"
-
-msgid "List overflow"
-msgstr "Dépassement de liste"
-
-msgid "Request ambiguous"
-msgstr "Requête ambiguë"
-
-msgid "Queue full"
-msgstr "File d'attente pleine"
-
-msgid "Not while on AOL"
-msgstr "Impossible sur AOL"
-
-msgid "Cannot receive IM due to parental controls"
-msgstr "Impossible de recevoir le message à cause du contrôle parental"
-
-msgid "Cannot send SMS without accepting terms"
-msgstr "Impossible d'envoyer de SMS sans accepter les termes"
-
-msgid "Cannot send SMS"
-msgstr "Impossible d'envoyer le SMS"
-
-#. SMS_WITHOUT_DISCLAIMER is weird
-msgid "Cannot send SMS to this country"
-msgstr "Impossible d'envoyer le SMS vers ce pays"
-
-#. Undocumented
-msgid "Cannot send SMS to unknown country"
-msgstr "Impossible d'envoyer le SMS vers un pays inconnu"
-
-msgid "Bot accounts cannot initiate IMs"
-msgstr "Les comptes Bot ne peuvent pas commencer les conversations"
-
-msgid "Bot account cannot IM this user"
-msgstr "Le compte Bot ne peut pas envoyer de message à cette personne"
-
-msgid "Bot account reached IM limit"
-msgstr "Le compte Bot a atteint sa limite de messages"
-
-msgid "Bot account reached daily IM limit"
-msgstr "Le compte Bot a atteint sa limite de messages quotidiens"
-
-msgid "Bot account reached monthly IM limit"
-msgstr "Le compte Bot a atteint sa limite de messages mensuels"
-
-msgid "Unable to receive offline messages"
-msgstr "Impossible de recevoir les messages déconnectés"
-
-msgid "Offline message store full"
-msgstr "Stockage des messages déconnectés plein"
-
 msgid ""
 "(There was an error receiving this message.  The buddy you are speaking with "
 "is probably using a different encoding than expected.  If you know what "
@@ -7286,7 +7167,7 @@
 msgstr "Jeux"
 
 msgid "ICQ Xtraz"
-msgstr ""
+msgstr "ICQ Xtraz"
 
 msgid "Add-Ins"
 msgstr "Modules"
@@ -7354,25 +7235,20 @@
 msgid "Invisible"
 msgstr "Invisible"
 
-#, fuzzy
 msgid "Evil"
-msgstr "Courriel"
-
-#, fuzzy
+msgstr "Méchant"
+
 msgid "Depression"
-msgstr "Profession"
-
-#, fuzzy
+msgstr "Dépression"
+
 msgid "At home"
-msgstr "À mon propos"
-
-#, fuzzy
+msgstr "À la maison"
+
 msgid "At work"
-msgstr "Réseau"
-
-#, fuzzy
+msgstr "Au travail"
+
 msgid "At lunch"
-msgstr "Parti manger"
+msgstr "Déjeuner"
 
 msgid "IP Address"
 msgstr "Adresse IP"
@@ -7614,28 +7490,9 @@
 msgstr[1] "Vous avez raté %hu messages de %s pour des raisons inconnues."
 
 #, c-format
-msgid "Unable to send message: %s (%s)"
-msgstr "Impossible d'envoyer le message : %s (%s)"
-
-#, c-format
-msgid "Unable to send message: %s"
-msgstr "Impossible d'envoyer le message : %s"
-
-#, c-format
-msgid "Unable to send message to %s: %s (%s)"
-msgstr "Impossible d'envoyer le message vers %s : %s (%s)"
-
-#, c-format
-msgid "Unable to send message to %s: %s"
-msgstr "Impossible d'envoyer le message vers %s : %s"
-
-#, c-format
 msgid "User information not available: %s"
 msgstr "Les informations ne sont pas disponibles : %s"
 
-msgid "Unknown reason."
-msgstr "Erreur inconnue"
-
 msgid "Online Since"
 msgstr "En ligne depuis"
 
@@ -7904,9 +7761,8 @@
 msgid "iTunes Music Store Link"
 msgstr "Lien de l'iTunes Music Store"
 
-#, fuzzy
 msgid "Lunch"
-msgstr "Finch"
+msgstr "Déjeuner"
 
 #, c-format
 msgid "Buddy Comment for %s"
@@ -7939,9 +7795,8 @@
 msgid "Edit Buddy Comment"
 msgstr "Modifier le commentaire"
 
-#, fuzzy
 msgid "Get X-Status Msg"
-msgstr "Obtenir le message d'état"
+msgstr "Obtenir le message X-Status"
 
 msgid "End Direct IM Session"
 msgstr "Terminer la connexion directe"
@@ -8352,9 +8207,8 @@
 msgstr "Admin"
 
 #. XXX: Should this be "Topic"?
-#, fuzzy
 msgid "Room Title"
-msgstr "Liste des salons de discussions"
+msgstr "Titre du salon"
 
 msgid "Notice"
 msgstr "Envoi d'infos"
@@ -10352,13 +10206,13 @@
 "corriger le problème."
 
 #. indicates a lock due to logging in too frequently
-#, fuzzy
 msgid ""
 "Account locked: You have been logging in too frequently.  Wait a few minutes "
 "before trying to connect again.  Logging into the Yahoo! website may help."
 msgstr ""
-"Compte bloqué : trop de mauvais mots de passe. Se connecter sur le site web "
-"Yahoo! peut corriger le problème."
+"Compte bloqué : vous vous êtes connectés trop rapidement. Veuillez attendre "
+"quelques minutes avant de réessayer de vous connecter. Se connecter sur le "
+"site web Yahoo! peut corriger le problème."
 
 #. username or password missing
 msgid "Username or password missing"
@@ -10441,16 +10295,15 @@
 msgid "Unable to establish a connection with %s: %s"
 msgstr "Impossible de se connecter à %s : %s"
 
-#, fuzzy
 msgid "Unable to connect: The server returned an empty response."
-msgstr ""
-"Impossible de se connecter au serveur MXit. Veuillez vérifier votre "
-"configuration."
+msgstr "Impossible de se connecter : le serveur a renvoyé une réponse vide."
 
 msgid ""
 "Unable to connect: The server's response did not contain the necessary "
 "information"
 msgstr ""
+"Impossible de se connecter : le serveur n'a pas renvoyé les informations "
+"nécessaires."
 
 msgid "Not at Home"
 msgstr "Pas à la maison"
@@ -10909,9 +10762,8 @@
 msgid "Extended away"
 msgstr "Longue absence"
 
-#, fuzzy
 msgid "Feeling"
-msgstr "Réception en cours"
+msgstr "Ressent"
 
 #, c-format
 msgid "%s (%s) changed status from %s to %s"
@@ -11450,13 +11302,11 @@
 msgid "Unknown node type"
 msgstr "Type de noeud inconnu"
 
-#, fuzzy
 msgid "Please select your mood from the list"
 msgstr "Veuillez choisir votre humeur dans la liste."
 
-#, fuzzy
 msgid "Message (optional)"
-msgstr "Alias (facultatif)`"
+msgstr "message (facultatif)`"
 
 msgid "Edit User Mood"
 msgstr "Modifier l'humeur"
@@ -11528,7 +11378,7 @@
 msgstr "/Outils/_Certificats"
 
 msgid "/Tools/Custom Smile_ys"
-msgstr "/Outils/Frimo_usses personnalisée"
+msgstr "/Outils/Frimo_usses personnalisées"
 
 msgid "/Tools/Plu_gins"
 msgstr "/Outils/Plu_gins"
@@ -11539,9 +11389,8 @@
 msgid "/Tools/Pr_ivacy"
 msgstr "/Outils/_Filtres"
 
-#, fuzzy
 msgid "/Tools/Set _Mood"
-msgstr "/Outils/Voir les archives s_ystème"
+msgstr "/Outils/Changer d'_humeur"
 
 msgid "/Tools/_File Transfers"
 msgstr "/Outils/_Transferts de fichier"
@@ -11560,22 +11409,19 @@
 msgstr "/Aid_e"
 
 msgid "/Help/Online _Help"
-msgstr "/Aide/Aid_e en ligne"
-
-#, fuzzy
+msgstr "/Aide/_Aide en ligne"
+
 msgid "/Help/_Build Information"
-msgstr "Informations sur le contact"
+msgstr "/Aide/_Informations sur le programme"
 
 msgid "/Help/_Debug Window"
 msgstr "/Aide/Fenêtre de _debug"
 
-#, fuzzy
 msgid "/Help/De_veloper Information"
-msgstr "Informations du serveur"
-
-#, fuzzy
+msgstr "/Aide/Liste des _développeurs"
+
 msgid "/Help/_Translator Information"
-msgstr "Informations personnelles"
+msgstr "/Aide/Liste des _traducteurs"
 
 msgid "/Help/_About"
 msgstr "/Aide/À _propos de"
@@ -11808,9 +11654,8 @@
 msgid "_Edit Account"
 msgstr "Modifier le c_ompte"
 
-#, fuzzy
 msgid "Set _Mood..."
-msgstr "Changer d'humeur..."
+msgstr "Changer d'_humeur..."
 
 msgid "No actions available"
 msgstr "Aucune action disponible"
@@ -11931,9 +11776,8 @@
 msgid "/Conversation/Se_nd File..."
 msgstr "/Conversation/Envoyer un _fichier..."
 
-#, fuzzy
 msgid "/Conversation/Get _Attention"
-msgstr "/Conversation/Voir les informations"
+msgstr "/Conversation/Attirer l'_attention"
 
 msgid "/Conversation/Add Buddy _Pounce..."
 msgstr "/Conversation/Ajouter une _alerte..."
@@ -12016,9 +11860,8 @@
 msgid "/Conversation/Send File..."
 msgstr "/Conversation/Envoyer un fichier..."
 
-#, fuzzy
 msgid "/Conversation/Get Attention"
-msgstr "/Conversation/Voir les informations"
+msgstr "/Conversation/Attirer l'attention"
 
 msgid "/Conversation/Add Buddy Pounce..."
 msgstr "/Conversation/Ajouter une alerte..."
@@ -12084,13 +11927,11 @@
 msgid "0 people in room"
 msgstr "Personne dans ce salon"
 
-#, fuzzy
 msgid "Close Find bar"
-msgstr "Fermer cet onglet"
-
-#, fuzzy
+msgstr "Fermer la barre de recherche"
+
 msgid "Find:"
-msgstr "Chercher"
+msgstr "Chercher :"
 
 #, c-format
 msgid "%d person in room"
@@ -12255,9 +12096,8 @@
 msgid "Arabic"
 msgstr "Arabe"
 
-#, fuzzy
 msgid "Assamese"
-msgstr "Honteux"
+msgstr "Assamais"
 
 msgid "Belarusian Latin"
 msgstr "Biélorusse latin"
@@ -12268,9 +12108,8 @@
 msgid "Bengali"
 msgstr "Bengalî"
 
-#, fuzzy
 msgid "Bengali-India"
-msgstr "Bengalî"
+msgstr "Bengalî indien"
 
 msgid "Bosnian"
 msgstr "Bosnien"
@@ -12386,9 +12225,8 @@
 msgid "Macedonian"
 msgstr "Macédonien"
 
-#, fuzzy
 msgid "Malayalam"
-msgstr "Malaisien"
+msgstr "Malayâlam"
 
 msgid "Mongolian"
 msgstr "Mongol"
@@ -12498,7 +12336,7 @@
 msgid "Lithuanian"
 msgstr "Lituanien"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "%s is a messaging client based on libpurple which is capable of connecting "
 "to multiple messaging services at once.  %s is written in C using GTK+.  %s "
@@ -12507,15 +12345,13 @@
 "copyrighted by its contributors, a list of whom is also distributed with %"
 "s.  There is no warranty for %s.<BR><BR>"
 msgstr ""
-"%s est un client graphique de messagerie modulaire basé sur libpurple "
-"compatible avec AIM, MSN, Yahoo!, XMPP, ICQ, IRC, SILC, SIP/SIMPLE, Novell "
-"GroupWise, Lotus Sametime, Bonjour, Zephyr, MySpaceIm, Gadu-Gadu et QQ. Il "
-"est écrit avec Gtk+.<BR><BR>Vous pouvez modifier et redistribuer ce "
-"programme sous les conditions énoncées par la licence GNU GPL (version 2 ou "
-"ultérieure). Une copie de la licence GPL est dans le fichier « COPYING » "
-"fourni avec %s. Tous droits réservés par les collaborateurs de %s. Consultez "
-"le fichier « COPYRIGHT » pour avoir la liste complète des collaborateurs. "
-"Aucune garantie n'est fournie pour l'utilisation de ce programme.<BR><BR>"
+"%s est un client de messagerie basé sur libpurple capable de se connecter à "
+"de multiples services de messageries instantanées. %s est écrit en C et "
+"utilise GTK+. %s est distribué, peut être modifié et redistribué sous les "
+"termes de la licence GPL version 2 ou ultérieure. Une copie de la licence "
+"GPL est fournie avec %s. Tous droits réservés par les collaborateurs de %s, "
+"dont une liste est aussi fournie avec %s. Aucune garantie n'est fournie pour "
+"l'utilisation de %s.<BR><BR>"
 
 #, c-format
 msgid ""
@@ -12524,8 +12360,11 @@
 "Channel: #pidgin on irc.freenode.net<BR>\tXMPP MUC: devel@conference.pidgin."
 "im<BR><BR>"
 msgstr ""
-
-#, fuzzy, c-format
+"<FONT SIZE=\"4\"><B>Liens utiles</B></FONT><BR>\t<A HREF=\"%s\">Site web</"
+"A><BR>\t<A HREF=\"%s\">Foire Aux Questions</A><BR>\tIRC Salon IRC : #pidgin "
+"sur irc.freenode.net<BR>\tSalon XMPP : devel@conference.pidgin.im<BR><BR>"
+
+#, c-format
 msgid ""
 "<font size=\"4\"><b>Help from other Pidgin users</b></font> is available by "
 "e-mailing <a href=\"mailto:support@pidgin.im\">support@pidgin.im</a><br/"
@@ -12547,14 +12386,13 @@
 msgid "About %s"
 msgstr "À propos de %s"
 
-#, fuzzy
 msgid "Build Information"
-msgstr "Informations sur le contact"
+msgstr "Informations sur le programme"
 
 #. End of not to be translated section
-#, fuzzy, c-format
+#, c-format
 msgid "%s Build Information"
-msgstr "Informations sur le contact"
+msgstr "Informations sur le programme %s"
 
 msgid "Current Developers"
 msgstr "Codeurs"
@@ -12568,9 +12406,9 @@
 msgid "Retired Crazy Patch Writers"
 msgstr "Patcheurs fous retraités"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s Developer Information"
-msgstr "Informations du serveur"
+msgstr "Liste des développeurs de %s"
 
 msgid "Current Translators"
 msgstr "Traducteurs"
@@ -12578,9 +12416,9 @@
 msgid "Past Translators"
 msgstr "Anciens traducteurs"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s Translator Information"
-msgstr "Plus d'informations"
+msgstr "Liste des traducteurs de %s"
 
 msgid "_Name"
 msgstr "_Nom"
@@ -12993,9 +12831,8 @@
 msgid "Insert Smiley"
 msgstr "Insérer une frimousse"
 
-#, fuzzy
 msgid "Send Attention"
-msgstr "Attention !"
+msgstr "Attirer l'attention"
 
 msgid "<b>_Bold</b>"
 msgstr "<b>_Gras</b>"
@@ -13042,9 +12879,8 @@
 msgid "_Smile!"
 msgstr "Sourie_z !"
 
-#, fuzzy
 msgid "_Attention!"
-msgstr "Attention !"
+msgstr "_Attention !"
 
 msgid "Log Deletion Failed"
 msgstr "Échec de suppression de l'archive"
@@ -13980,11 +13816,10 @@
 msgstr "Texte de raccourci"
 
 msgid "Custom Smiley Manager"
-msgstr "Gestionnaire de frimousses personnalisée"
-
-#, fuzzy
+msgstr "Gestionnaire de frimousses personnalisées"
+
 msgid "Attention received"
-msgstr "Activation nécessaire"
+msgstr "Demande d'attention reçue"
 
 msgid "Select Buddy Icon"
 msgstr "Choisir l'icône de contact"
@@ -15135,21 +14970,18 @@
 msgid "Timestamp Format Options"
 msgstr "Options d'affichage de l'horodatage"
 
-#, fuzzy, c-format
+#, c-format
 msgid "_Force timestamp format:"
-msgstr "_Forcer au format 24 heures"
-
-#, fuzzy
+msgstr "_Forcer le formatage des dates :"
+
 msgid "Use system default"
-msgstr "Paramètres par défaut du bureau"
-
-#, fuzzy
+msgstr "Utiliser les paramètres du système"
+
 msgid "12 hour time format"
-msgstr "_Forcer au format 24 heures"
-
-#, fuzzy
+msgstr "Format 12 heures"
+
 msgid "24 hour time format"
-msgstr "_Forcer au format 24 heures"
+msgstr "Format 24 heures"
 
 msgid "Show dates in..."
 msgstr "Afficher les dates dans..."
@@ -15349,10 +15181,10 @@
 msgstr "Envoyer et recevoir des blocs XMPP."
 
 #. *  description
-#, fuzzy
 msgid "This plugin is useful for debugging XMPP servers or clients."
 msgstr "Ce plugin est utile pour débugger les clients ou serveurs XMPP."
 
+#. $(^Name) is the current Version name (e.g. Pidgin 2.7.0).  $_CLICK will become a translated version of "Click Next to continue."
 msgid ""
 "$(^Name) is released under the GNU General Public License (GPL). The license "
 "is provided here for information purposes only. $_CLICK"
@@ -15360,6 +15192,7 @@
 "$(^Name) est disponible sous licence GNU General Public License (GPL). Le "
 "texte de licence suivant est fourni uniquement à titre informatif. $_CLICK"
 
+#. Installer Subsection Detailed Description
 msgid "A multi-platform GUI toolkit, used by Pidgin"
 msgstr ""
 "Un ensemble d'outils pour interfaces graphiques multi-plateforme, utilisé "
@@ -15372,75 +15205,100 @@
 "Une instance de Pidgin est en cours d'exécution. Veuillez quitter Pidgin et "
 "réessayer."
 
+#. Installer Subsection Detailed Description
 msgid "Core Pidgin files and dlls"
 msgstr "Fichiers et DLLs de base de Pidgin"
 
+#. Installer Subsection Detailed Description
 msgid "Create a Start Menu entry for Pidgin"
 msgstr "Créer un raccourci pour Pidgin dans le menu Démarrer"
 
+#. Installer Subsection Detailed Description
 msgid "Create a shortcut to Pidgin on the Desktop"
 msgstr "Créer un raccourci pour Pidgin sur le bureau"
 
+#. Installer Subsection Text
 msgid "Debug Symbols (for reporting crashes)"
-msgstr ""
-
+msgstr "Symboles de debug (pour soumettre des plantages)"
+
+#. Installer Subsection Text
 msgid "Desktop"
 msgstr "Bureau"
 
+#. $R2 will display the URL that the GTK+ Runtime failed to download from
 msgid ""
 "Error Downloading the GTK+ Runtime ($R2).$\\rThis is required for Pidgin to "
 "function; if retrying fails, you may need to use the 'Offline Installer' "
 "from http://pidgin.im/download/windows/ ."
 msgstr ""
-
+"Erreur au téléchargement des bibliothèques GTK+ ($R2).$\\rCeci est "
+"nécessaire au bon fonctionnement de Pidgin. Si une nouvelle tentative "
+"échoue, vous devrez peut-être utiliser l'installateur « Offline » disponible "
+"sur http://pidgin.im/download/windows/ ."
+
+#. $R2 will display the URL that the Debug Symbols failed to download from
 msgid ""
 "Error Installing Debug Symbols ($R2).$\\rIf retrying fails, you may need to "
 "use the 'Offline Installer' from http://pidgin.im/download/windows/ ."
 msgstr ""
-
+"Erreur lors de l'installation des symboles de debug GTK+ ($R2).$\\rSi une "
+"nouvelle tentative échoue, vous devrez peut-être utiliser l'installateur « "
+"Offline » disponible sur http://pidgin.im/download/windows/ ."
+
+#. $R3 will display the URL that the Dictionary failed to download from
 #, 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"
 msgstr ""
-
-#, fuzzy
+"Erreur lors de l'installation du correcteur orthographique ($R3).$\\rSi une "
+"nouvelle tentative échoue, veuillez suivre les instructions sur http://"
+"developer.pidgin.im/wiki/Installing%"
+"20Pidgin#manual_win32_spellcheck_installation"
+
+#. Installer Subsection Text
 msgid "GTK+ Runtime (required if not present)"
-msgstr "Bibliothèques GTK+ (obligatoire)"
-
-#, fuzzy
+msgstr "Bibliothèques GTK+ (obligatoires si pas déjà installées)"
+
+#. Installer Subsection Text
 msgid "Localizations"
-msgstr "Localisation"
-
-#. License Page
+msgstr "Traductions"
+
+#. "Next >" appears on a button on the License Page of the Installer
 msgid "Next >"
 msgstr "Suivant >"
 
-#. Components Page
+#. Installer Subsection Text
 msgid "Pidgin Instant Messaging Client (required)"
 msgstr "Pidgin client de messagerie instantanée (obligatoire)"
 
-#. GTK+ Section Prompts
 msgid ""
 "Pidgin requires a compatible GTK+ Runtime (which doesn't appear to be "
 "already present).$\\rAre you sure you want to skip installing the GTK+ "
 "Runtime?"
 msgstr ""
-
+"Pidgin a besoin d'une version compatible des bibliothèques GTK+ (qui n'a pas "
+"l'air d'être présente sur votre système).$\\Êtes-vous sûr de ne pas vouloir "
+"installer ces bibliothèques ?"
+
+#. Installer Subsection Text
 msgid "Shortcuts"
 msgstr "Raccourcis"
 
+#. Installer Subsection Detailed Description
 msgid "Shortcuts for starting Pidgin"
 msgstr "Raccourcis pour lancer Pidgin"
 
-#. Spellcheck Section Prompts
+#. Installer Subsection Text
 msgid "Spellchecking Support"
 msgstr "Correction orthographique"
 
+#. Installer Subsection Text
 msgid "Start Menu"
 msgstr "Menu Démarrer"
 
+#. Installer Subsection Detailed Description
 msgid ""
 "Support for Spellchecking.  (Internet connection required for installation)"
 msgstr ""
@@ -15450,7 +15308,6 @@
 msgid "The installer is already running."
 msgstr "Le programme d'installation est déjà en cours d'exécution."
 
-#. Uninstall Section Prompts
 msgid ""
 "The uninstaller could not find registry entries for Pidgin.$\\rIt is likely "
 "that another user installed this application."
@@ -15459,11 +15316,10 @@
 "la base de registres.$\\rL'application a peut-être été installée par un "
 "utilisateur différent."
 
-#. URL Handler section
+#. Installer Subsection Text
 msgid "URI Handlers"
 msgstr "Gestion des liens (URI)"
 
-#. Pidgin Section Prompts and Texts
 msgid ""
 "Unable to uninstall the currently installed version of Pidgin. The new "
 "version will be installed without removing the currently installed version."
@@ -15471,34 +15327,94 @@
 "Impossible de désinstaller la version de Pidgin en place. La nouvelle "
 "version sera installée sans supprimer la version en place."
 
-#. Installer Finish Page
+#. Text displayed on Installer Finish Page
 msgid "Visit the Pidgin Web Page"
 msgstr "Visitez la page web de Pidgin"
 
 msgid "You do not have permission to uninstall this application."
 msgstr "Vous n'avez pas les permissions pour supprimer cette application."
 
+#~ msgid "Rate to host"
+#~ msgstr "Fréquence vers l'hôte"
+
+#~ msgid "Rate to client"
+#~ msgstr "Fréquence vers le client"
+
+#~ msgid "Service unavailable"
+#~ msgstr "Service non disponible"
+
+#~ msgid "Service not defined"
+#~ msgstr "Service non défini"
+
+#~ msgid "Obsolete SNAC"
+#~ msgstr "SNAC obsolète"
+
+#~ msgid "Not supported by host"
+#~ msgstr "Non supporté par l'hôte"
+
+#~ msgid "Not supported by client"
+#~ msgstr "Non supporté par le client"
+
+#~ msgid "Refused by client"
+#~ msgstr "Refusé par le client"
+
+#~ msgid "Reply too big"
+#~ msgstr "Réponse trop grosse"
+
+#~ msgid "Responses lost"
+#~ msgstr "Réponses perdues"
+
+#~ msgid "Request denied"
+#~ msgstr "Requête refusée"
+
+#~ msgid "Busted SNAC payload"
+#~ msgstr "Charge SNAC incorrecte"
+
+#~ msgid "Insufficient rights"
+#~ msgstr "Droits insuffisants"
+
+#~ msgid "In local permit/deny"
+#~ msgstr "Dans l'autorisation/interdiction locale"
+
+#~ msgid "Warning level too high (sender)"
+#~ msgstr "Niveau d'avertissement trop élevé (émission)"
+
+#~ msgid "Warning level too high (receiver)"
+#~ msgstr "Niveau d'avertissement trop élevé (réception)"
+
+#~ msgid "User temporarily unavailable"
+#~ msgstr "L'utilisateur est temporairement indisponible."
+
+#~ msgid "No match"
+#~ msgstr "Aucun résultat"
+
+#~ msgid "List overflow"
+#~ msgstr "Dépassement de liste"
+
+#~ msgid "Request ambiguous"
+#~ msgstr "Requête ambiguë"
+
+#~ msgid "Queue full"
+#~ msgstr "File d'attente pleine"
+
+#~ msgid "Not while on AOL"
+#~ msgstr "Impossible sur AOL"
+
+#~ msgid "Unknown reason."
+#~ msgstr "Erreur inconnue"
+
+#~ msgid "Orientation"
+#~ msgstr "Disposition"
+
+#~ msgid "The orientation of the tray."
+#~ msgstr "Orientation de l'espace de notification"
+
 #~ msgid "Artist"
 #~ msgstr "Artiste"
 
 #~ msgid "Album"
 #~ msgstr "Album"
 
-#~ msgid "Current Mood"
-#~ msgstr "Humeur actuelle"
-
-#~ msgid "New Mood"
-#~ msgstr "Nouvelle humeur"
-
-#~ msgid "Change your Mood"
-#~ msgstr "Changer d'humeur"
-
-#~ msgid "How do you feel right now?"
-#~ msgstr "Comment vous sentez-vous ?"
-
-#~ msgid "Change Mood..."
-#~ msgstr "Changer d'humeur..."
-
 #~ msgid "Pager server"
 #~ msgstr "Serveur de texto"
 
@@ -15508,12 +15424,6 @@
 #~ msgid "Yahoo Chat port"
 #~ msgstr "Port Yahoo Chat"
 
-#~ msgid "Orientation"
-#~ msgstr "Disposition"
-
-#~ msgid "The orientation of the tray."
-#~ msgstr "Orientation de l'espace de notification"
-
 #~ msgid "Error creating conference."
 #~ msgstr "Erreur à la création de la conférence."
 
@@ -15577,22 +15487,6 @@
 #~ msgid "%s has removed you from his or her buddy list."
 #~ msgstr "L'utilisateur %s vous a supprimé de sa liste de contacts."
 
-#~ msgid ""
-#~ "<FONT SIZE=\"4\">FAQ:</FONT> <A HREF=\"http://developer.pidgin.im/wiki/FAQ"
-#~ "\">http://developer.pidgin.im/wiki/FAQ</A><BR/><BR/>"
-#~ msgstr ""
-#~ "<FONT SIZE=\"4\">FAQ :</FONT> <A HREF=\"http://developer.pidgin.im/wiki/"
-#~ "FAQ\">http://developer.pidgin.im/wiki/FAQ</A><BR/><BR/>"
-
-#~ msgid ""
-#~ "<FONT SIZE=\"4\">IRC Channel:</FONT> #pidgin on irc.freenode.net<BR><BR>"
-#~ msgstr ""
-#~ "<FONT SIZE=\"4\">Salon IRC :</FONT> #pidgin sur irc.freenode.net<BR><BR>"
-
-#~ msgid "<FONT SIZE=\"4\">XMPP MUC:</FONT> devel@conference.pidgin.im<BR><BR>"
-#~ msgstr ""
-#~ "<FONT SIZE=\"4\">Salon XMPP :</FONT> devel@conference.pidgin.im<BR><BR>"
-
 #~ msgid "Debugging Information"
 #~ msgstr "Informations de debug"
 
@@ -15670,6 +15564,9 @@
 #~ msgid "_User:"
 #~ msgstr "_Utilisateur :"
 
+#~ msgid "GTK+ Runtime Version"
+#~ msgstr "Version des bibliothèques GTK+"
+
 #~ msgid "Calling ... "
 #~ msgstr "Appel... "
 
--- a/po/he.po	Thu May 20 13:51:24 2010 +0000
+++ b/po/he.po	Sun May 23 17:22:51 2010 +0000
@@ -8,10 +8,11 @@
 msgstr ""
 "Project-Id-Version: he\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-05-17 23:18-0400\n"
-"PO-Revision-Date: 2010-02-15 19:51+0200\n"
-"Last-Translator: Shalom Craimer <scraimer at google's mail dot com>\n"
+"POT-Creation-Date: 2010-05-20 14:09-0700\n"
+"PO-Revision-Date: 2010-05-10 15:36+0200\n"
+"Last-Translator: Shalom Craimer <scraimer at g mail dot com>\n"
 "Language-Team: Hebrew <he@li.org>\n"
+"Language: he\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -1609,13 +1610,11 @@
 msgid "Set User Info"
 msgstr "מידע כללי על המשתמש"
 
-#, fuzzy
 msgid "This protocol does not support setting a public alias."
-msgstr "פרוטוקול זה אינו תומך בחדרי צ'אט"
-
-#, fuzzy
+msgstr "פרוטוקול זה אינו תומך בקביעת שמות נוספים פומביים."
+
 msgid "This protocol does not support fetching the public alias."
-msgstr "פרוטוקול זה אינו תומך בחדרי צ'אט"
+msgstr "פרוטוקול זה אינו תומך בשליפת שמות נוספים פומביים."
 
 msgid "Unknown"
 msgstr "לא ידוע"
@@ -1868,7 +1867,6 @@
 msgid "Thread creation failure: %s"
 msgstr "כשל בעת יצירת חוט-תהליך חדש: %s"
 
-#. Data is assumed to be the destination bn
 msgid "Unknown reason"
 msgstr "סיבה לא ידועה"
 
@@ -3735,38 +3733,35 @@
 msgid "SASL error: %s"
 msgstr "שגיאת SASL: %s"
 
-#, fuzzy
 msgid "Invalid Encoding"
-msgstr "תנאי קליטה שגוי"
-
-#, fuzzy
+msgstr "קידוד לא תקין"
+
 msgid "Unsupported Extension"
-msgstr "גירסא ללא תמיכה"
+msgstr "תוסף לא-נתמך"
 
 msgid ""
 "Unexpected response from the server.  This may indicate a possible MITM "
 "attack"
-msgstr ""
+msgstr "התקבלה תשובה לא-צפוייה מהשרת. ייתכן וזה מעיד על התקפת MITM."
 
 msgid ""
 "The server does support channel binding, but did not appear to advertise "
 "it.  This indicates a likely MITM attack"
 msgstr ""
-
-#, fuzzy
+"השרת תומך בלכידת ערוצים, אך נראה כי אינו מפרסם זאת. זה כנראה מעיד על תקיפת "
+"MITM."
+
 msgid "Server does not support channel binding"
-msgstr "השרת לא תומך בחסימה"
-
-#, fuzzy
+msgstr "השרת לא תומך בלכידת ערוצים"
+
 msgid "Unsupported channel binding method"
-msgstr "קידוד שלא נתמך"
+msgstr "אין תמיכה בתצורת הלכידה של ערוצים המבוקשת"
 
 msgid "User not found"
 msgstr "המשתמש לא נמצא"
 
-#, fuzzy
 msgid "Invalid Username Encoding"
-msgstr "שם משתמש לא חוקי"
+msgstr "קידוד לא חוקי של שם המשתמש"
 
 msgid "Resource Constraint"
 msgstr "הגבלת משאבים"
@@ -4082,9 +4077,8 @@
 msgid "Invalid XMPP ID"
 msgstr "מזהה XMPP לא תקין"
 
-#, fuzzy
 msgid "Invalid XMPP ID. Username portion must be set."
-msgstr "מזהה XMPP שגוי. יש להגדיר את הדומיין."
+msgstr "זיהוי XMPP שגוי. חובה לקבוע את ערך שם-המשתמש."
 
 msgid "Invalid XMPP ID. Domain must be set."
 msgstr "מזהה XMPP שגוי. יש להגדיר את הדומיין."
@@ -4216,13 +4210,11 @@
 msgid "Allow Buzz"
 msgstr "אפשר זימזום"
 
-#, fuzzy
 msgid "Mood Name"
-msgstr "שם אמצעי"
-
-#, fuzzy
+msgstr "שם מצב-הרוח"
+
 msgid "Mood Comment"
-msgstr "הערת איש קשר"
+msgstr "הערת מצב-הרוח"
 
 #. primitive
 #. ID
@@ -4509,9 +4501,8 @@
 msgid "Initiate Media"
 msgstr "יזום מדיה"
 
-#, fuzzy
 msgid "Account does not support PEP, can't set mood"
-msgstr "פרוטוקול זה אינו תומך בחדרי צ'אט"
+msgstr "חשבון זה אינו תומך PEP, לא ניתן לקבוע את מצב-הרוח"
 
 msgid "config:  Configure a chat room."
 msgstr "config:  קבע הגדרות חדר צ'אט."
@@ -4564,9 +4555,8 @@
 msgid "buzz: Buzz a user to get their attention"
 msgstr "buzz: שלח זימזום למשתמש כדי להשיג את תשומת ליבם"
 
-#, fuzzy
 msgid "mood: Set current user mood"
-msgstr "בחר/י משתמש נכון"
+msgstr "mood: לקביעת מצב-רוח המשתמש"
 
 msgid "Extended Away"
 msgstr "העדרות ממושכת"
@@ -4648,13 +4638,13 @@
 msgstr "החייכן שלך גדול מכדי להישלח בתוך ההודעה."
 
 msgid "XMPP stream header missing"
-msgstr ""
+msgstr "חסרה תחילית stream XMPP"
 
 msgid "XMPP Version Mismatch"
-msgstr ""
+msgstr "גירסא לא נכונה של XMPP"
 
 msgid "XMPP stream missing ID"
-msgstr ""
+msgstr "חסרה מספר-זיהוי של stream XMPP"
 
 msgid "XML Parse error"
 msgstr "שגיאת פיענוח XML"
@@ -4728,31 +4718,26 @@
 msgid "Please select the resource of %s to which you would like to send a file"
 msgstr "יש לבחור את המשאב של %s אליו ברצונך לשלוח קובץ"
 
-#, fuzzy
 msgid "Afraid"
-msgstr "ערבית"
-
-#, fuzzy
+msgstr "פחד"
+
 msgid "Amazed"
-msgstr "מבוייש"
-
-#, fuzzy
+msgstr "תדהמה"
+
 msgid "Amorous"
-msgstr "מרומם"
+msgstr "אהבה"
 
 msgid "Angry"
 msgstr "כועס"
 
-#, fuzzy
 msgid "Annoyed"
-msgstr "חסום"
+msgstr "עצבנות"
 
 msgid "Anxious"
 msgstr "לחוץ"
 
-#, fuzzy
 msgid "Aroused"
-msgstr "אתה שולח"
+msgstr "גירוי"
 
 msgid "Ashamed"
 msgstr "מבוייש"
@@ -4760,152 +4745,125 @@
 msgid "Bored"
 msgstr "משועמם"
 
-#, fuzzy
 msgid "Brave"
-msgstr "שמור"
-
-#, fuzzy
+msgstr "אומץ"
+
 msgid "Calm"
-msgstr "איזור"
-
-#, fuzzy
+msgstr "רוגע"
+
 msgid "Cautious"
-msgstr "שיחות"
-
-#, fuzzy
+msgstr "זהירות"
+
 msgid "Cold"
-msgstr "מודגש"
-
-#, fuzzy
+msgstr "קר"
+
 msgid "Confident"
-msgstr "התנגשות"
-
-#, fuzzy
+msgstr "מלא ביטחון"
+
 msgid "Confused"
-msgstr "המשך"
-
-#, fuzzy
+msgstr "בילבול"
+
 msgid "Contemplative"
-msgstr "איש הקשר"
-
-#, fuzzy
+msgstr "הירהורים"
+
 msgid "Contented"
-msgstr "מחובר"
-
-#, fuzzy
+msgstr "שביעות רצון"
+
 msgid "Cranky"
-msgstr "חברה"
+msgstr "קיטורים"
 
 msgid "Crazy"
-msgstr ""
-
-#, fuzzy
+msgstr "שיגעון"
+
 msgid "Creative"
-msgstr "צור"
-
-#, fuzzy
+msgstr "יצירתיות"
+
 msgid "Curious"
-msgstr "מרומם"
-
-#, fuzzy
+msgstr "סקרנות"
+
 msgid "Dejected"
-msgstr "נדחה"
-
-#, fuzzy
+msgstr "נידחיות"
+
 msgid "Depressed"
-msgstr "מחוק"
-
-#, fuzzy
+msgstr "דיכאון"
+
 msgid "Disappointed"
-msgstr "מנותק."
+msgstr "אכזבה"
 
 msgid "Disgusted"
-msgstr ""
-
-#, fuzzy
+msgstr "גועל"
+
 msgid "Dismayed"
-msgstr "כבוי"
-
-#, fuzzy
+msgstr "עצב לא צפוי"
+
 msgid "Distracted"
-msgstr "מנותק"
+msgstr "היסח הדעת"
 
 msgid "Embarrassed"
-msgstr ""
-
-#, fuzzy
+msgstr "מבוכה"
+
 msgid "Envious"
-msgstr "לחוץ"
+msgstr "קינאה"
 
 msgid "Excited"
 msgstr "נלהב"
 
-#, fuzzy
 msgid "Flirtatious"
-msgstr "מרומם"
-
-#, fuzzy
+msgstr "פלירטוט"
+
 msgid "Frustrated"
-msgstr "שם פרטי"
+msgstr "תיסכול"
 
 msgid "Grateful"
-msgstr ""
-
-#, fuzzy
+msgstr "מלא-תודה"
+
 msgid "Grieving"
-msgstr "שולף..."
+msgstr "אבל"
 
 msgid "Grumpy"
 msgstr "עצבני"
 
-#, fuzzy
 msgid "Guilty"
-msgstr "עיר"
+msgstr "אשמה"
 
 msgid "Happy"
 msgstr "שמח"
 
 msgid "Hopeful"
-msgstr ""
+msgstr "מלא-תקווה"
 
 msgid "Hot"
 msgstr "חם"
 
 msgid "Humbled"
-msgstr ""
+msgstr "צניעות"
 
 msgid "Humiliated"
-msgstr ""
-
-#, fuzzy
+msgstr "השפלה"
+
 msgid "Hungry"
-msgstr "כועס"
-
-#, fuzzy
+msgstr "רעב"
+
 msgid "Hurt"
-msgstr "הומור"
+msgstr "כאב"
 
 msgid "Impressed"
-msgstr ""
-
-#, fuzzy
+msgstr "התרשמות"
+
 msgid "In awe"
-msgstr "מאוהב"
+msgstr "פליאה"
 
 msgid "In love"
 msgstr "מאוהב"
 
-#, fuzzy
 msgid "Indignant"
-msgstr "אינדונזית"
-
-#, fuzzy
+msgstr "גאווה נפגעה"
+
 msgid "Interested"
-msgstr "תחומי עניין"
-
-#, fuzzy
+msgstr "עניין"
+
 msgid "Intoxicated"
-msgstr "הוזמן"
+msgstr "שיכרות"
 
 msgid "Invincible"
 msgstr "בלתי מנוצח"
@@ -4913,83 +4871,68 @@
 msgid "Jealous"
 msgstr "מקנא"
 
-#, fuzzy
 msgid "Lonely"
-msgstr "קוף"
-
-#, fuzzy
+msgstr "בדידות"
+
 msgid "Lost"
-msgstr "הכי רועש"
+msgstr "אבוד"
 
 msgid "Lucky"
-msgstr ""
-
-#, fuzzy
+msgstr "בר-מזל"
+
 msgid "Mean"
-msgstr "גרמנית"
-
-#, fuzzy
+msgstr "נבזיות"
+
 msgid "Moody"
-msgstr "מצב רוח"
+msgstr "אין מצב רוח"
 
 msgid "Nervous"
-msgstr ""
-
-#, fuzzy
+msgstr "עצבניות"
+
 msgid "Neutral"
-msgstr "פרטים"
-
-#, fuzzy
+msgstr "ניטרלי"
+
 msgid "Offended"
-msgstr "מנותק"
+msgstr "עלבון"
 
 msgid "Outraged"
-msgstr ""
-
-#, fuzzy
+msgstr "התלהמות"
+
 msgid "Playful"
-msgstr "נגן"
-
-#, fuzzy
+msgstr "משחקיות"
+
 msgid "Proud"
-msgstr "רועש"
-
-#, fuzzy
+msgstr "גאווה"
+
 msgid "Relaxed"
-msgstr "שם אמיתי"
-
-#, fuzzy
+msgstr "רגיעה"
+
 msgid "Relieved"
-msgstr "נתקבלו"
-
-#, fuzzy
+msgstr "הורדת לחץ"
+
 msgid "Remorseful"
-msgstr "הסר"
-
-#, fuzzy
+msgstr "חרטה"
+
 msgid "Restless"
-msgstr "הרשם"
+msgstr "חוסר-מנוחה"
 
 msgid "Sad"
 msgstr "עצוב"
 
-#, fuzzy
 msgid "Sarcastic"
-msgstr "מרטהי"
+msgstr "ציני"
 
 msgid "Satisfied"
-msgstr ""
-
-#, fuzzy
+msgstr "שבעות רצון"
+
 msgid "Serious"
-msgstr "מרומם"
-
-#, fuzzy
+msgstr "רצינות"
+
 msgid "Shocked"
-msgstr "חסום"
+msgstr "הלם"
 
 msgid "Shy"
-msgstr ""
+msgstr "ביישנות"
 
 msgid "Sick"
 msgstr "חולה"
@@ -4999,40 +4942,34 @@
 msgstr "ישנוני"
 
 msgid "Spontaneous"
-msgstr ""
-
-#, fuzzy
+msgstr "ספונטני"
+
 msgid "Stressed"
-msgstr "מהירות"
-
-#, fuzzy
+msgstr "לחץ"
+
 msgid "Strong"
-msgstr "שיר"
+msgstr "כוח"
 
 msgid "Surprised"
-msgstr ""
+msgstr "הפתעה"
 
 msgid "Thankful"
-msgstr ""
+msgstr "תודה"
 
 msgid "Thirsty"
-msgstr ""
-
-#, fuzzy
+msgstr "צימאון"
+
 msgid "Tired"
-msgstr "Fire"
-
-#, fuzzy
+msgstr "עייפות"
+
 msgid "Undefined"
-msgstr "קו תחתון"
-
-#, fuzzy
+msgstr "לא מוגדר"
+
 msgid "Weak"
-msgstr "כאפה"
-
-#, fuzzy
+msgstr "חולשה"
+
 msgid "Worried"
-msgstr "משועמם"
+msgstr "דאגה"
 
 msgid "Set User Nickname"
 msgstr "קבע כינוי משתמש"
@@ -6742,9 +6679,9 @@
 msgid "AOL does not allow your screen name to authenticate here"
 msgstr "AOL אינם מאפשרים לאמת את שם המשתמש שלך כאן"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Error requesting %s"
-msgstr "שגיאה בבקשת %s: %s"
+msgstr "שגיאה בבקשת %s"
 
 msgid "Could not join chat room"
 msgstr "לא ניתן להתחבר אל חדר הצ'אט"
@@ -6752,105 +6689,146 @@
 msgid "Invalid chat room name"
 msgstr "שם החדר אינו תקף"
 
+msgid "Invalid error"
+msgstr "מספר שגיאה לא תקף."
+
+msgid "Cannot receive IM due to parental controls"
+msgstr "לא ניתן לקבל הודעות עקב הגבלות הורים"
+
+msgid "Cannot send SMS without accepting terms"
+msgstr "לא ניתן לשלוח SMS ללא קבלת התנאים"
+
+msgid "Cannot send SMS"
+msgstr "לא מסוגל לשלוח SMS"
+
+#. SMS_WITHOUT_DISCLAIMER is weird
+msgid "Cannot send SMS to this country"
+msgstr "לא מסוגל לשלוח SMS לארץ זו"
+
+#. Undocumented
+msgid "Cannot send SMS to unknown country"
+msgstr "לא ניתן לשלוח SMS למדינה לא מוכרת"
+
+msgid "Bot accounts cannot initiate IMs"
+msgstr "חשבון רובוטי לא יכולים ליזום שיחות"
+
+msgid "Bot account cannot IM this user"
+msgstr "חשבון רובוטי לא יכולים לשלוח הודעה למשתמש זה"
+
+msgid "Bot account reached IM limit"
+msgstr "החשבון רובוטי עבר את מכסת ההודעות"
+
+msgid "Bot account reached daily IM limit"
+msgstr "החשבון רובוטי עבר את מכסת ההודעות היומית"
+
+msgid "Bot account reached monthly IM limit"
+msgstr "החשבון רובוטי עבר את מכסת ההודעות החודשית"
+
+msgid "Unable to receive offline messages"
+msgstr "לא ניתן לקבל הודעות לא-מקוונות"
+
+msgid "Offline message store full"
+msgstr "איזור אחסון ההודעות הלא-מקוונות הינו מלא"
+
+#, c-format
+msgid "Unable to send message: %s (%s)"
+msgstr "לא ניתן לשלוח הודעה %s (%s)"
+
+#, c-format
+msgid "Unable to send message: %s"
+msgstr "לא ניתן לשלוח הודעה: %s"
+
+#, c-format
+msgid "Unable to send message to %s: %s (%s)"
+msgstr "לא ניתן לשלוח הודעה אל %s: %s (%s)"
+
+#, c-format
+msgid "Unable to send message to %s: %s"
+msgstr "לא ניתן לשלוח הודעה אל %s: %s"
+
 msgid "Thinking"
-msgstr ""
-
-#, fuzzy
+msgstr "מחשבה"
+
 msgid "Shopping"
-msgstr "מפסיק/ה להקליד הודעה"
-
-#, fuzzy
+msgstr "קניות"
+
 msgid "Questioning"
-msgstr "חלון שאלה"
-
-#, fuzzy
+msgstr "תהייה"
+
 msgid "Eating"
-msgstr "מדפדף"
-
-#, fuzzy
+msgstr "אוכל"
+
 msgid "Watching a movie"
-msgstr "באמצע משחק"
+msgstr "באמצע סרט"
 
 msgid "Typing"
 msgstr "מקליד/ה"
 
-#, fuzzy
 msgid "At the office"
-msgstr "לא נמצא במשרד"
+msgstr "במשרד"
 
 msgid "Taking a bath"
-msgstr ""
+msgstr "רחצה באמבט"
 
 msgid "Watching TV"
-msgstr ""
-
-#, fuzzy
+msgstr "צפייה בטלויזיה"
+
 msgid "Having fun"
-msgstr "התנתק"
-
-#, fuzzy
+msgstr "בכיף"
+
 msgid "Sleeping"
-msgstr "ישנוני"
+msgstr "שינה"
 
 msgid "Using a PDA"
-msgstr ""
-
-#, fuzzy
+msgstr "שימוש במחשב כף-יד"
+
 msgid "Meeting friends"
-msgstr "חברי בהודעות מידיות"
-
-#, fuzzy
+msgstr "במפגש עם חברים"
+
 msgid "On the phone"
-msgstr "משוחח בטלפון"
-
-#, fuzzy
+msgstr "בטלפון"
+
 msgid "Surfing"
-msgstr "חוזר"
+msgstr "גלישה"
 
 #. "I am mobile." / "John is mobile."
 msgid "Mobile"
 msgstr "נייד"
 
 msgid "Searching the web"
-msgstr ""
+msgstr "חיפוש באינטרנט"
 
 msgid "At a party"
-msgstr ""
+msgstr "במסיבה"
 
 msgid "Having Coffee"
-msgstr ""
+msgstr "שתיית קפה"
 
 #. Playing video games
-#, fuzzy
 msgid "Gaming"
-msgstr "תאומים"
+msgstr "משחקים"
 
 msgid "Browsing the web"
-msgstr ""
-
-#, fuzzy
+msgstr "דפדוף באינטרנט"
+
 msgid "Smoking"
-msgstr "שיר"
-
-#, fuzzy
+msgstr "עישון"
+
 msgid "Writing"
-msgstr "עובד"
+msgstr "כתיבה"
 
 #. Drinking [Alcohol]
-#, fuzzy
 msgid "Drinking"
-msgstr "עובד"
+msgstr "שותה"
 
 msgid "Listening to music"
 msgstr "מקשיב/ה למוזיקה"
 
-#, fuzzy
 msgid "Studying"
-msgstr "שליחה"
-
-#, fuzzy
+msgstr "לימודים"
+
 msgid "In the restroom"
-msgstr "תחומי עניין"
+msgstr "בשירותים"
 
 msgid "Received invalid data on connection with server"
 msgstr "התקבל מידע שגוי בעת חיבור עם השרת."
@@ -6918,116 +6896,6 @@
 msgid "File %s is %s, which is larger than the maximum size of %s."
 msgstr "הקובץ %s הינו %s, שהוא גדול מהגודל המירבי של %s."
 
-msgid "Invalid error"
-msgstr "מספר שגיאה לא תקף."
-
-msgid "Invalid SNAC"
-msgstr "SNAC לא תקף"
-
-msgid "Rate to host"
-msgstr "דירוג למארח"
-
-msgid "Rate to client"
-msgstr "דירוג ללקוח"
-
-msgid "Service unavailable"
-msgstr "השירות אינו זמין"
-
-msgid "Service not defined"
-msgstr "שירות אינו מוגדר"
-
-msgid "Obsolete SNAC"
-msgstr "SNAC מיושן"
-
-msgid "Not supported by host"
-msgstr "לא נתמך על-ידי השרת"
-
-msgid "Not supported by client"
-msgstr "לא נתמך על-ידי הלקוח"
-
-msgid "Refused by client"
-msgstr "החיבור נדחה על ידי הלקוח."
-
-msgid "Reply too big"
-msgstr "המענה גדול מדיי"
-
-msgid "Responses lost"
-msgstr "אבדו המשובים"
-
-msgid "Request denied"
-msgstr "הבקשה נדחית"
-
-msgid "Busted SNAC payload"
-msgstr "מידע פגום ב-SNAC"
-
-msgid "Insufficient rights"
-msgstr "אין די הרשאות"
-
-msgid "In local permit/deny"
-msgstr "באישור/שלילה מקומיים"
-
-msgid "Warning level too high (sender)"
-msgstr "רמת אזהרה גבוהה מדי (שולח("
-
-msgid "Warning level too high (receiver)"
-msgstr "רמת אזהרה גבוהה מדי (מקבל)"
-
-msgid "User temporarily unavailable"
-msgstr "המשתמש אינו זמין כרגע"
-
-msgid "No match"
-msgstr "אין התאמה"
-
-msgid "List overflow"
-msgstr "גלישת מגבולות הרשימה"
-
-msgid "Request ambiguous"
-msgstr "בקשה לא ברורה"
-
-msgid "Queue full"
-msgstr "התור מלא"
-
-msgid "Not while on AOL"
-msgstr "לא בזמן שהות ב-AOL"
-
-msgid "Cannot receive IM due to parental controls"
-msgstr "לא ניתן לקבל הודעות עקב הגבלות הורים"
-
-msgid "Cannot send SMS without accepting terms"
-msgstr "לא ניתן לשלוח SMS ללא קבלת התנאים"
-
-msgid "Cannot send SMS"
-msgstr "לא מסוגל לשלוח SMS"
-
-#. SMS_WITHOUT_DISCLAIMER is weird
-msgid "Cannot send SMS to this country"
-msgstr "לא מסוגל לשלוח SMS לארץ זו"
-
-#. Undocumented
-msgid "Cannot send SMS to unknown country"
-msgstr "לא ניתן לשלוח SMS למדינה לא מוכרת"
-
-msgid "Bot accounts cannot initiate IMs"
-msgstr "חשבון רובוטי לא יכולים ליזום שיחות"
-
-msgid "Bot account cannot IM this user"
-msgstr "חשבון רובוטי לא יכולים לשלוח הודעה למשתמש זה"
-
-msgid "Bot account reached IM limit"
-msgstr "החשבון רובוטי עבר את מכסת ההודעות"
-
-msgid "Bot account reached daily IM limit"
-msgstr "החשבון רובוטי עבר את מכסת ההודעות היומית"
-
-msgid "Bot account reached monthly IM limit"
-msgstr "החשבון רובוטי עבר את מכסת ההודעות החודשית"
-
-msgid "Unable to receive offline messages"
-msgstr "לא ניתן לקבל הודעות לא-מקוונות"
-
-msgid "Offline message store full"
-msgstr "איזור אחסון ההודעות הלא-מקוונות הינו מלא"
-
 msgid ""
 "(There was an error receiving this message.  The buddy you are speaking with "
 "is probably using a different encoding than expected.  If you know what "
@@ -7063,7 +6931,7 @@
 msgstr "משחקים"
 
 msgid "ICQ Xtraz"
-msgstr ""
+msgstr "ICQ Xtraz"
 
 msgid "Add-Ins"
 msgstr "תוספות"
@@ -7131,25 +6999,20 @@
 msgid "Invisible"
 msgstr "בלתי נראה"
 
-#, fuzzy
 msgid "Evil"
-msgstr "דואר"
-
-#, fuzzy
+msgstr "רוע-לב"
+
 msgid "Depression"
-msgstr "מקצוע"
-
-#, fuzzy
+msgstr "דיכאון"
+
 msgid "At home"
-msgstr "אודותי"
-
-#, fuzzy
+msgstr "בבית"
+
 msgid "At work"
-msgstr "רשת"
-
-#, fuzzy
+msgstr "בעבודה"
+
 msgid "At lunch"
-msgstr "יצא לאכול"
+msgstr "בארוחת-צהריים"
 
 msgid "IP Address"
 msgstr "כתובת IP"
@@ -7370,28 +7233,9 @@
 msgstr[1] "פספסת %hu הודעות מאת %s מסיבה לא ידועה."
 
 #, c-format
-msgid "Unable to send message: %s (%s)"
-msgstr "לא ניתן לשלוח הודעה %s (%s)"
-
-#, c-format
-msgid "Unable to send message: %s"
-msgstr "לא ניתן לשלוח הודעה: %s"
-
-#, c-format
-msgid "Unable to send message to %s: %s (%s)"
-msgstr "לא ניתן לשלוח הודעה אל %s: %s (%s)"
-
-#, c-format
-msgid "Unable to send message to %s: %s"
-msgstr "לא ניתן לשלוח הודעה אל %s: %s"
-
-#, c-format
 msgid "User information not available: %s"
 msgstr "מידע על המשתמש אינו זמין: %s"
 
-msgid "Unknown reason."
-msgstr "סיבה לא ידועה."
-
 msgid "Online Since"
 msgstr "מחובר מאז"
 
@@ -7633,9 +7477,8 @@
 msgid "iTunes Music Store Link"
 msgstr "לינק לחנות המוזיקה iTunes"
 
-#, fuzzy
 msgid "Lunch"
-msgstr "פינץ'"
+msgstr "ארוחת-צהריים"
 
 #, c-format
 msgid "Buddy Comment for %s"
@@ -7668,9 +7511,8 @@
 msgid "Edit Buddy Comment"
 msgstr "ערוך הערת איש קשר"
 
-#, fuzzy
 msgid "Get X-Status Msg"
-msgstr "הורד הודעת מצב"
+msgstr "שלוף הודעת X-Status"
 
 msgid "End Direct IM Session"
 msgstr "סיים חיבור IM ישיר"
@@ -8079,9 +7921,8 @@
 msgstr "מנהל"
 
 #. XXX: Should this be "Topic"?
-#, fuzzy
 msgid "Room Title"
-msgstr "רשימת חדרים"
+msgstr "כותרת החדר"
 
 msgid "Notice"
 msgstr "הודעה"
@@ -10039,13 +9880,12 @@
 msgstr "החשבון נעול: סיבה לא ידועה. התחברות באתר Yahoo! אולי תתקן את זה."
 
 #. indicates a lock due to logging in too frequently
-#, fuzzy
 msgid ""
 "Account locked: You have been logging in too frequently.  Wait a few minutes "
 "before trying to connect again.  Logging into the Yahoo! website may help."
 msgstr ""
-"החשבון נעול: יותר מדי ניסיון התחברות כושלים. התחברות באתר Yahoo! אולי תתקן "
-"את זה."
+"החשבון ננעל: ניסית להתחבר בתדירות גבוהה מדי.  יש לחכות כמה דקות לפני ניסיון "
+"ההתחברות הבא.  כניסה לאתר של Yahoo! אולי תועיל."
 
 #. username or password missing
 msgid "Username or password missing"
@@ -10121,14 +9961,13 @@
 msgid "Unable to establish a connection with %s: %s"
 msgstr "לא ניתן ליצור חיבור עם %s: %s"
 
-#, fuzzy
 msgid "Unable to connect: The server returned an empty response."
-msgstr "לא ניתן להתחבר לשרת ה-MXit. יש לוודא את הגדרות השרת שלך."
+msgstr "לא ניתן להתחבר: השרת השיב בתשובה ריקה."
 
 msgid ""
 "Unable to connect: The server's response did not contain the necessary "
 "information"
-msgstr ""
+msgstr "לא ניתן להתחבר: תשובת השרת לא הכילה את הנתונים הנחוצים"
 
 msgid "Not at Home"
 msgstr "לא נמצא בבית"
@@ -10568,9 +10407,8 @@
 msgid "Extended away"
 msgstr "העדרות ממושכת"
 
-#, fuzzy
 msgid "Feeling"
-msgstr "קבלה"
+msgstr "ההרגשה שלי"
 
 #, c-format
 msgid "%s (%s) changed status from %s to %s"
@@ -11101,13 +10939,11 @@
 msgid "Unknown node type"
 msgstr "נקודה-ברשת מסוג לא מוכר"
 
-#, fuzzy
 msgid "Please select your mood from the list"
-msgstr "יש לבחור את מצב הרוח שלך מהרשימה."
-
-#, fuzzy
+msgstr "יש לבחור את מצב הרוח שלך מהרשימה"
+
 msgid "Message (optional)"
-msgstr "שם נוסף (לא חובה)"
+msgstr "הודעה (לא חובה)"
 
 msgid "Edit User Mood"
 msgstr "קבע מצב-רוח משתמש"
@@ -11190,9 +11026,8 @@
 msgid "/Tools/Pr_ivacy"
 msgstr "/כלים/_פרטיות"
 
-#, fuzzy
 msgid "/Tools/Set _Mood"
-msgstr "/כלים/דו\"ח המערכת"
+msgstr "/כלים/קבע מצב-ר_וח"
 
 msgid "/Tools/_File Transfers"
 msgstr "/כלים/העברת _קבצים..."
@@ -11213,20 +11048,17 @@
 msgid "/Help/Online _Help"
 msgstr "/עזרה/עזרה מקוונת"
 
-#, fuzzy
 msgid "/Help/_Build Information"
-msgstr "מידע עבור איש הקשר"
+msgstr "/עזרה/_גירסת תוכנה"
 
 msgid "/Help/_Debug Window"
 msgstr "/עזרה/_חלון ניפוי באגים"
 
-#, fuzzy
 msgid "/Help/De_veloper Information"
-msgstr "מידע על השרת"
-
-#, fuzzy
+msgstr "/עזרה/פרטי מפת_חים"
+
 msgid "/Help/_Translator Information"
-msgstr "מידע אישי"
+msgstr "/עזרה/פרטי מתר_גמים"
 
 msgid "/Help/_About"
 msgstr "/עזרה/_אודות"
@@ -11451,7 +11283,6 @@
 msgid "_Edit Account"
 msgstr "_ערוך חשבון"
 
-#, fuzzy
 msgid "Set _Mood..."
 msgstr "קבע מצב-רוח..."
 
@@ -11573,9 +11404,8 @@
 msgid "/Conversation/Se_nd File..."
 msgstr "/שיחה/ש_לח קובץ..."
 
-#, fuzzy
 msgid "/Conversation/Get _Attention"
-msgstr "/שיחה/הצג מידע"
+msgstr "/שיחה/הסב תשומת _לב"
 
 msgid "/Conversation/Add Buddy _Pounce..."
 msgstr "/שיחה/הוסף פ_עולת תגובה..."
@@ -11658,9 +11488,8 @@
 msgid "/Conversation/Send File..."
 msgstr "/שיחה/שלח קובץ..."
 
-#, fuzzy
 msgid "/Conversation/Get Attention"
-msgstr "/שיחה/הצג מידע"
+msgstr "/שיחה/הסב תשומת לב"
 
 msgid "/Conversation/Add Buddy Pounce..."
 msgstr "/שיחה/הוסף פעולת תגובה לאירועי איש קשר..."
@@ -11726,13 +11555,11 @@
 msgid "0 people in room"
 msgstr "0 אנשים בחדר זה"
 
-#, fuzzy
 msgid "Close Find bar"
-msgstr "סגור טאב זה"
-
-#, fuzzy
+msgstr "סגור סרגל חיפוש"
+
 msgid "Find:"
-msgstr "חפש"
+msgstr "חפש:"
 
 #, c-format
 msgid "%d person in room"
@@ -11908,9 +11735,8 @@
 msgid "Bengali"
 msgstr "בנגאלית"
 
-#, fuzzy
 msgid "Bengali-India"
-msgstr "בנגאלית"
+msgstr "בנגאלית-הודו"
 
 msgid "Bosnian"
 msgstr "בוסנית"
@@ -12138,23 +11964,20 @@
 msgid "Lithuanian"
 msgstr "ליטואנית"
 
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "%s is a messaging client based on libpurple which is capable of connecting "
 "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>"
-msgstr ""
-"%s הינה תוכנת שליחת הודעות מיידיות גרפית מודולרית מבוססת libpurple אשר לבצע "
-"חיבורים אל AIM, MSN, Yahoo!, XMPP, ICQ, IRC, SILC, SIP/SIMPLE, Novel "
-"GroupWise, Lotus Sametime, Bonjour, Zephyr, MySpaceIM, Gadu-Gadu, QQ ובכולם "
-"בו- זמנית. התוכנה נכתבה בעזרת GTK+.<BR><BR>מותר לערוך שינויים ולהפיץ את "
-"התוכנה תחת הנחיות רישיון הGPL (גרסא 2 והלאה). יותר). העתק של ה-GPL מוכל בתוך "
-"הקובץ 'COPYING' המופץ עם %s. %s היא תחת זכויות המפתחים והתורמים לפיתוח. ראה "
-"את הקובץ 'COPYRIGHT' לרשימה מלאה של התורמים. איננו מספקים שום אחריות לתוכנה "
-"זו.<BR><BR>"
+"copyrighted by its contributors, a list of whom is also distributed with "
+"%s.  There is no warranty for %s.<BR><BR>"
+msgstr ""
+"%s הינה תוכנת הודעות המבוססת על libpurple ומסוגלת להתחבר למספר שירותי הודעות "
+"בו-זמנית.  %s נכתבה בשפת C ובעזרת GTK+.  %s יצאה לאור, וניתן לערוך ולהפיץ "
+"אותה, תחת תנאי הרשיון GPL גרסה 2 (והלאה).  יש העתק של הרישיון GPL המופץ עם "
+"%s.  %s מוגנת תחת זכויות יוצריה, אשר רשימתם גם היא מופצת עם %s.  אין אחריות "
+"עבור %s.<BR><BR>"
 
 #, c-format
 msgid ""
@@ -12163,8 +11986,11 @@
 "Channel: #pidgin on irc.freenode.net<BR>\tXMPP MUC: devel@conference.pidgin."
 "im<BR><BR>"
 msgstr ""
-
-#, fuzzy, c-format
+"<FONT SIZE=\"4\"><B>משאבי ידע</B></FONT><BR>\t<A HREF=\"%s\">אתר אינטרנט</"
+"A><BR>\t<A HREF=\"%s\">שאלות נפוצות</A><BR>\tערוץ IRC: #pidgin on irc."
+"freenode.net<BR>\tXMPP MUC: devel@conference.pidgin.im<BR><BR>"
+
+#, c-format
 msgid ""
 "<font size=\"4\"><b>Help from other Pidgin users</b></font> is available by "
 "e-mailing <a href=\"mailto:support@pidgin.im\">support@pidgin.im</a><br/"
@@ -12174,24 +12000,24 @@
 "welcome to post in another language, but the responses may be less helpful."
 "<br/>"
 msgstr ""
-"<font size=\"4\">עזרה ממשתמשי פידג'ין אחרים:</font> <a href=\"mailto:"
-"support@pidgin.im\">support@pidgin.im</a><br/>זוהי רשימת תפוצה<b>פומבית</b>! "
-"(<a href=\"http://pidgin.im/pipermail/support/\">ארכיון</a>)<br/>אנחנו לא "
-"מסוגלים לעזור עם תוספים מצד-שלישי!<br/>השפה השולטת בה היא <b>אנגלית</b>.  "
-"מותר לשלוח הודעות גם בשפות אחרות, אבל ייתכן והתגובות יעזרו לך פחות.<br/><br/>"
+"<font size=\"4\"><b>עזרה ממשתמשי פידג'ין אחרים</b></font> ניתן לקבל באימייל "
+"<a href=\"mailto:support@pidgin.im\">support@pidgin.im</a><br/>זוהי רשימת "
+"תפוצה <b>פומבית</b>! (<a href=\"http://pidgin.im/pipermail/support/"
+"\">archive</a>)<br/>אנו לא מסוגלים לעזור עם בעיות בתוספים או בתוספים של צד "
+"שלישי!<br/> השפה השולטה כאן היא <b>אנגלית</b>. אתם מוזמנים לכתוב הודעות "
+"בשפות אחרות, אבל ייתכן והתשובות שתקבלו יהיו פחות משביעות-רצון.<br/>"
 
 #, c-format
 msgid "About %s"
 msgstr "אודות %s"
 
-#, fuzzy
 msgid "Build Information"
-msgstr "מידע עבור איש הקשר"
+msgstr "פרטי גרסת תוכנה"
 
 #. End of not to be translated section
-#, fuzzy, c-format
+#, c-format
 msgid "%s Build Information"
-msgstr "מידע עבור איש הקשר"
+msgstr "%s פרטי גרסת תוכנה"
 
 msgid "Current Developers"
 msgstr "מפתחים"
@@ -12205,9 +12031,9 @@
 msgid "Retired Crazy Patch Writers"
 msgstr "מחברי תיקונים מטורפים בדימוס"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s Developer Information"
-msgstr "מידע על השרת"
+msgstr "%s פרטי מפתח"
 
 msgid "Current Translators"
 msgstr "מתרגמים פעילים"
@@ -12215,9 +12041,9 @@
 msgid "Past Translators"
 msgstr "מתרגמים לשעבר"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%s Translator Information"
-msgstr "מידע נוסף"
+msgstr "%s פרטי מתרגם"
 
 msgid "_Name"
 msgstr "שם_"
@@ -12614,9 +12440,8 @@
 msgid "Insert Smiley"
 msgstr "הכנס חיוכון"
 
-#, fuzzy
 msgid "Send Attention"
-msgstr "כפתור שליחה"
+msgstr "שליחת בקשת תשומת-לב"
 
 msgid "<b>_Bold</b>"
 msgstr "<b>מ_ודגש:</b>"
@@ -12664,7 +12489,7 @@
 msgstr "חייך!"
 
 msgid "_Attention!"
-msgstr ""
+msgstr "תשומת-לב!"
 
 msgid "Log Deletion Failed"
 msgstr "מחיקת יומן-הרישום נכשלה"
@@ -12680,14 +12505,14 @@
 
 #, 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 "האם ברצונך למחוק את רישום השיחה ב- %s שהתחיל ב- %s?"
 
 #, 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 "האם ברצונך למחוק את רישום יומן המערכת שהחל ב- %s?"
 
 msgid "Delete Log?"
@@ -13588,9 +13413,8 @@
 msgid "Custom Smiley Manager"
 msgstr "מנהל החייכנים שלך"
 
-#, fuzzy
 msgid "Attention received"
-msgstr "נדרשת הפעלה"
+msgstr "תשומת-לב התקבלה"
 
 msgid "Select Buddy Icon"
 msgstr "בחירת תמונה עבור חבר"
@@ -14702,21 +14526,18 @@
 msgid "Timestamp Format Options"
 msgstr "אפשרויות חותמת-זמן"
 
-#, fuzzy, c-format
+#, c-format
 msgid "_Force timestamp format:"
-msgstr " אלץ שימוש בחותמת-זמן על בסיס 24-שעות"
-
-#, fuzzy
+msgstr " אלץ שימוש בחותמת-זמן:"
+
 msgid "Use system default"
-msgstr "ברירות המחדל בשולחן העבודה"
-
-#, fuzzy
+msgstr "השתמש בברירות המחדל של מערכת ההפעלה"
+
 msgid "12 hour time format"
-msgstr " אלץ שימוש בחותמת-זמן על בסיס 24-שעות"
-
-#, fuzzy
+msgstr "תצוגת שעה בתצורת 12 שעות"
+
 msgid "24 hour time format"
-msgstr " אלץ שימוש בחותמת-זמן על בסיס 24-שעות"
+msgstr "תצוגת שעה בתצורת 24 שעות"
 
 msgid "Show dates in..."
 msgstr "הצג תאריכים ב..."
@@ -14913,93 +14734,102 @@
 msgstr "שלח וקבל סטנזות XMPP גולמיות."
 
 #. *  description
-#, fuzzy
 msgid "This plugin is useful for debugging XMPP servers or clients."
 msgstr "תוסף זה שימושי לניפוי באגים בשרתים ולקוחות של XMPP."
 
+#. $(^Name) is the current Version name (e.g. Pidgin 2.7.0).  $_CLICK will become a translated version of "Click Next to continue."
 msgid ""
 "$(^Name) is released under the GNU General Public License (GPL). The license "
 "is provided here for information purposes only. $_CLICK"
 msgstr ""
 "$(^Name) .הרישיון נמצא כאן בשביל מידע בלבד .GPL משוחרר תחת רישיון $_CLICK"
 
-msgid "A multi-platform GUI toolkit, used by Pidgin"
-msgstr "מולטי-פלטפורמי, בו נעזר פידג'ין GUI כלי"
-
 msgid ""
 "An instance of Pidgin is currently running.  Please exit Pidgin and try "
 "again."
 msgstr "עותק של פידג'ין כבר רץ. יש לסגור את פידג'ין ולנסות שנית."
 
+#. Installer Subsection Detailed Description
 msgid "Core Pidgin files and dlls"
 msgstr ".בסיסיים DLL-ו Pidgin קבצי"
 
+#. Installer Subsection Detailed Description
 msgid "Create a Start Menu entry for Pidgin"
 msgstr "צור קיצור-דרך עבור פידג'ין בתפריט ההתחל"
 
+#. Installer Subsection Detailed Description
 msgid "Create a shortcut to Pidgin on the Desktop"
 msgstr "צור קיצור-דרך עבור פידג'ין על שולחן העבודה"
 
+#. Installer Subsection Text
 msgid "Debug Symbols (for reporting crashes)"
 msgstr ""
 
+#. Installer Subsection Text
 msgid "Desktop"
 msgstr "שולחן העבודה"
 
+#. $R2 will display the URL that the GTK+ Runtime failed to download from
 msgid ""
 "Error Downloading the GTK+ Runtime ($R2).$\\rThis is required for Pidgin to "
 "function; if retrying fails, you may need to use the 'Offline Installer' "
 "from http://pidgin.im/download/windows/ ."
 msgstr ""
 
+#. $R2 will display the URL that the Debug Symbols failed to download from
 msgid ""
 "Error Installing Debug Symbols ($R2).$\\rIf retrying fails, you may need to "
 "use the 'Offline Installer' from http://pidgin.im/download/windows/ ."
 msgstr ""
 
+#. $R3 will display the URL that the Dictionary failed to download from
 #, 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"
-msgstr ""
-
-#, fuzzy
+"installation instructions are at: http://developer.pidgin.im/wiki/Installing"
+"%20Pidgin#manual_win32_spellcheck_installation"
+msgstr ""
+
+#. Installer Subsection Text
 msgid "GTK+ Runtime (required if not present)"
 msgstr "(חובה) .GTK+ סביבת"
 
+#. Installer Subsection Text
 #, fuzzy
 msgid "Localizations"
 msgstr "מיקום"
 
-#. License Page
+#. "Next >" appears on a button on the License Page of the Installer
 msgid "Next >"
 msgstr "הבא >"
 
-#. Components Page
+#. Installer Subsection Text
 msgid "Pidgin Instant Messaging Client (required)"
 msgstr "(חובה) .Pidgin תוכנת"
 
-#. GTK+ Section Prompts
 msgid ""
 "Pidgin requires a compatible GTK+ Runtime (which doesn't appear to be "
 "already present).$\\rAre you sure you want to skip installing the GTK+ "
 "Runtime?"
 msgstr ""
 
+#. Installer Subsection Text
 msgid "Shortcuts"
 msgstr "קיצורי דרך"
 
+#. Installer Subsection Detailed Description
 msgid "Shortcuts for starting Pidgin"
 msgstr "קיצורי-דרך להפעלת פידג'ין"
 
-#. Spellcheck Section Prompts
+#. Installer Subsection Text
 msgid "Spellchecking Support"
 msgstr "תמיכה בבדיקות איות"
 
+#. Installer Subsection Text
 msgid "Start Menu"
 msgstr "תפריט ההתחל"
 
+#. Installer Subsection Detailed Description
 msgid ""
 "Support for Spellchecking.  (Internet connection required for installation)"
 msgstr "תמיכה עבור בדיקות איות (דורש חיבור אינטרנט להתקנה)"
@@ -15007,7 +14837,6 @@
 msgid "The installer is already running."
 msgstr "תוכנת ההתקנה כבר רצה."
 
-#. Uninstall Section Prompts
 msgid ""
 "The uninstaller could not find registry entries for Pidgin.$\\rIt is likely "
 "that another user installed this application."
@@ -15015,11 +14844,10 @@
 ".GTK+ ההתקנה לא מצאה את הרישומים של$\\r.יכול להיות שמשמתמש אחר התקין את "
 "התוכנה הזאת"
 
-#. URL Handler section
+#. Installer Subsection Text
 msgid "URI Handlers"
 msgstr "מנהלי URI"
 
-#. Pidgin Section Prompts and Texts
 msgid ""
 "Unable to uninstall the currently installed version of Pidgin. The new "
 "version will be installed without removing the currently installed version."
@@ -15027,18 +14855,15 @@
 "לא מסוגל להסיר את הגירסא המותקנת של פידג'ין. הגירסא החדשה תותקן ללא הסרת "
 "הגרסא המותקנת."
 
-#. Installer Finish Page
+#. Text displayed on Installer Finish Page
 msgid "Visit the Pidgin Web Page"
 msgstr ".Pidginבקרו באתר של "
 
 msgid "You do not have permission to uninstall this application."
 msgstr ".אין לך זכות למחוק תוכנה זאת"
 
-#~ msgid "Artist"
-#~ msgstr "אמן"
-
-#~ msgid "Album"
-#~ msgstr "אלבום"
+#~ msgid "A multi-platform GUI toolkit, used by Pidgin"
+#~ msgstr "מולטי-פלטפורמי, בו נעזר פידג'ין GUI כלי"
 
 #~ msgid "Current Mood"
 #~ msgstr "מצב הרוח הנוכחי"
@@ -15055,6 +14880,84 @@
 #~ msgid "Change Mood..."
 #~ msgstr "שינוי מצב-רוח..."
 
+#~ msgid "Invalid SNAC"
+#~ msgstr "SNAC לא תקף"
+
+#~ msgid "Rate to host"
+#~ msgstr "דירוג למארח"
+
+#~ msgid "Rate to client"
+#~ msgstr "דירוג ללקוח"
+
+#~ msgid "Service unavailable"
+#~ msgstr "השירות אינו זמין"
+
+#~ msgid "Service not defined"
+#~ msgstr "שירות אינו מוגדר"
+
+#~ msgid "Obsolete SNAC"
+#~ msgstr "SNAC מיושן"
+
+#~ msgid "Not supported by host"
+#~ msgstr "לא נתמך על-ידי השרת"
+
+#~ msgid "Not supported by client"
+#~ msgstr "לא נתמך על-ידי הלקוח"
+
+#~ msgid "Refused by client"
+#~ msgstr "החיבור נדחה על ידי הלקוח."
+
+#~ msgid "Reply too big"
+#~ msgstr "המענה גדול מדיי"
+
+#~ msgid "Responses lost"
+#~ msgstr "אבדו המשובים"
+
+#~ msgid "Request denied"
+#~ msgstr "הבקשה נדחית"
+
+#~ msgid "Busted SNAC payload"
+#~ msgstr "מידע פגום ב-SNAC"
+
+#~ msgid "Insufficient rights"
+#~ msgstr "אין די הרשאות"
+
+#~ msgid "In local permit/deny"
+#~ msgstr "באישור/שלילה מקומיים"
+
+#~ msgid "Warning level too high (sender)"
+#~ msgstr "רמת אזהרה גבוהה מדי (שולח("
+
+#~ msgid "Warning level too high (receiver)"
+#~ msgstr "רמת אזהרה גבוהה מדי (מקבל)"
+
+#~ msgid "User temporarily unavailable"
+#~ msgstr "המשתמש אינו זמין כרגע"
+
+#~ msgid "No match"
+#~ msgstr "אין התאמה"
+
+#~ msgid "List overflow"
+#~ msgstr "גלישת מגבולות הרשימה"
+
+#~ msgid "Request ambiguous"
+#~ msgstr "בקשה לא ברורה"
+
+#~ msgid "Queue full"
+#~ msgstr "התור מלא"
+
+#~ msgid "Not while on AOL"
+#~ msgstr "לא בזמן שהות ב-AOL"
+
+#~ msgid "Unknown reason."
+#~ msgstr "סיבה לא ידועה."
+
+#~ msgid "Artist"
+#~ msgstr "אמן"
+
+#~ msgid "Album"
+#~ msgstr "אלבום"
+
 #~ msgid "Pager server"
 #~ msgstr "שרת ה-Pager"