pidgin: 881b33de: Update libgadu to 0.11.0 plus local chan...

elb at pidgin.im elb at pidgin.im
Sat Jun 4 21:35:49 EDT 2011


----------------------------------------------------------------------
Revision: 881b33de8dfacb184dd93982261548e418e4a5e7
Parent:   262d96720193c12bd137a8276fbe63a1280ac67c
Author:   elb at pidgin.im
Date:     06/04/11 21:28:53
Branch:   im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/881b33de8dfacb184dd93982261548e418e4a5e7

Changelog: 

Update libgadu to 0.11.0 plus local changes; thanks to Tomasz Wasilczyk.

Fixes 14248

Changes against parent 262d96720193c12bd137a8276fbe63a1280ac67c

  patched  configure.ac
  patched  libpurple/protocols/gg/Makefile.am
  patched  libpurple/protocols/gg/Makefile.mingw
  patched  libpurple/protocols/gg/lib/common.c
  patched  libpurple/protocols/gg/lib/dcc.c
  patched  libpurple/protocols/gg/lib/dcc7.c
  patched  libpurple/protocols/gg/lib/debug.c
  patched  libpurple/protocols/gg/lib/encoding.c
  patched  libpurple/protocols/gg/lib/events.c
  patched  libpurple/protocols/gg/lib/handlers.c
  patched  libpurple/protocols/gg/lib/http.c
  patched  libpurple/protocols/gg/lib/libgadu-config.h
  patched  libpurple/protocols/gg/lib/libgadu-debug.h
  patched  libpurple/protocols/gg/lib/libgadu.c
  patched  libpurple/protocols/gg/lib/libgadu.h
  patched  libpurple/protocols/gg/lib/obsolete.c
  patched  libpurple/protocols/gg/lib/protocol.h
  patched  libpurple/protocols/gg/lib/pubdir.c
  patched  libpurple/protocols/gg/lib/pubdir50.c
  patched  libpurple/protocols/gg/lib/resolver.c
  patched  libpurple/protocols/gg/lib/sha1.c

-------------- next part --------------
============================================================
--- configure.ac	9e8d31ae8a22c360fb6ccbd6b52c0f16cfeab139
+++ configure.ac	48582c1e1dd01bd327bfece6bd09af9f4211d085
@@ -1024,7 +1024,7 @@ if test "x$gadu_manual_check" = "xno"; t
 	gadu_manual_check="no"
 fi
 if test "x$gadu_manual_check" = "xno"; then
-	PKG_CHECK_MODULES(GADU, [libgadu >= 1.10.1], [
+	PKG_CHECK_MODULES(GADU, [libgadu >= 1.11.0], [
 		gadu_includes="yes"
 		gadu_libs="yes"
 	], [
@@ -1058,7 +1058,7 @@ if test "x$gadu_libs" = "xyes"; then
 	]])], [
 		AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libgadu.h>]], [[
 #if GG_DEFAULT_PROTOCOL_VERSION < 0x2e
-#error "Your libgadu version is too old. libpurple requires 1.10.1 or higher."
+#error "Your libgadu version is too old. libpurple requires 1.11.0 or higher."
 #endif
 		]])], [
 			AC_MSG_RESULT(yes)
@@ -1069,7 +1069,7 @@ if test "x$gadu_libs" = "xyes"; then
 			echo
 			echo
 			echo "Your supplied copy of libgadu is too old."
-			echo "Install version 1.10.1 or newer."
+			echo "Install version 1.11.0 or newer."
 			echo "Then rerun this ./configure"
 			echo
 			echo "Falling back to using our own copy of libgadu"
============================================================
--- libpurple/protocols/gg/Makefile.am	6d0f5a8f4326c56aebd1ed9b880893af58473fe1
+++ libpurple/protocols/gg/Makefile.am	a8b621a391172b10d7f3fc594124e87a5e15bba7
@@ -6,6 +6,7 @@ EXTRA_DIST = \
 	lib/dcc.c \
 	lib/dcc7.c \
 	lib/debug.c \
+	lib/deflate.c \
 	lib/encoding.c \
 	lib/encoding.h \
 	lib/events.c \
@@ -36,6 +37,7 @@ INTGGSOURCES = \
 	lib/dcc.c \
 	lib/dcc7.c \
 	lib/debug.c \
+	lib/deflate.c \
 	lib/encoding.c \
 	lib/encoding.h \
 	lib/events.c \
@@ -59,7 +61,6 @@ if USE_GNUTLS
 INTGG_CFLAGS = -I$(top_srcdir)/libpurple/protocols/gg/lib -DGG_IGNORE_DEPRECATED -DUSE_INTERNAL_LIBGADU
 
 if USE_GNUTLS
-INTGG_CFLAGS += -DUSE_GNUTLS
 GADU_LIBS += $(GNUTLS_LIBS)
 endif
 
============================================================
--- libpurple/protocols/gg/Makefile.mingw	e33eb81597dc966978da1b5c315e7406bde8594e
+++ libpurple/protocols/gg/Makefile.mingw	6365006701bdfeffbbb9264afc22116fd3cb23cf
@@ -44,6 +44,7 @@ C_SRC =	\
 	lib/dcc.c \
 	lib/dcc7.c \
 	lib/debug.c \
+	lib/deflate.c \
 	lib/encoding.c \
 	lib/events.c \
 	lib/handlers.c \
============================================================
--- libpurple/protocols/gg/lib/common.c	651ae02fdb9ee4f73262cc87594a427df87ada30
+++ libpurple/protocols/gg/lib/common.c	07308be3629d7b020ecad9cc87eb006d42802cff
@@ -1,4 +1,4 @@
-/* $Id: common.c 1037 2010-12-17 22:18:08Z wojtekka $ */
+/* $Id: common.c 1101 2011-05-05 21:17:28Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka at irc.pl>
@@ -24,10 +24,6 @@
  *
  * \brief Funkcje wykorzystywane przez r??ne modu?y biblioteki
  */
-
-#include "libgadu.h"
-#include "libgadu-internal.h"
-
 #ifndef _WIN32
 #  include <sys/types.h>
 #  include <sys/ioctl.h>
@@ -41,17 +37,16 @@
 
 #include <errno.h>
 #include <fcntl.h>
-
 #ifndef _WIN32
 #  include <netdb.h>
 #endif
-
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+#include "libgadu.h"
 
 /**
  * \internal Odpowiednik funkcji \c vsprintf alokuj?cy miejsce na wynik.
@@ -329,7 +324,7 @@ void gg_chomp(char *line)
  * Zamienia znaki niedrukowalne, spoza ASCII i maj?ce specjalne znaczenie
  * dla protoko?u HTTP na encje postaci \c %XX, gdzie \c XX jest szesnastkow?
  * warto?ci? znaku.
- *
+ * 
  * \param str Ci?g znak?w do zakodowania
  *
  * \return Zaalokowany bufor lub \c NULL w przypadku b??du.
============================================================
--- libpurple/protocols/gg/lib/dcc.c	e94581732817173257c4b449cb35b463b9ab5017
+++ libpurple/protocols/gg/lib/dcc.c	50362473e6df324ed3e566c5e72f2d2bc166bf94
@@ -25,11 +25,9 @@
  *
  * \brief Obs?uga po??cze? bezpo?rednich do wersji Gadu-Gadu 6.x
  */
-#include "libgadu.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
-
 #ifndef _WIN32
 #  include <sys/ioctl.h>
 #  include <sys/socket.h>
@@ -50,6 +48,7 @@
 #include <unistd.h>
 
 #include "compat.h"
+#include "libgadu.h"
 
 #ifndef GG_DEBUG_DISABLE
 
@@ -421,7 +420,7 @@ struct gg_dcc *gg_dcc_socket_create(uin_
 		return NULL;
 	}
 
-	if (port == 0 || port == -1)
+	if (port == 0 || port == (uint16_t)-1) /* XXX: port is unsigned */
 		port = GG_DEFAULT_DCC_PORT;
 
 	while (!bound) {
============================================================
--- libpurple/protocols/gg/lib/events.c	18feb4fdf3f78aaf6f0213d6341099dc1a258094
+++ libpurple/protocols/gg/lib/events.c	05da5230649347d4674632763e577b7ae6204075
@@ -1,4 +1,4 @@
-/* $Id: events.c 1062 2011-03-13 18:10:24Z wojtekka $ */
+/* $Id: events.c 1105 2011-05-25 21:34:50Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka at irc.pl>
@@ -27,22 +27,22 @@
  * \brief Obs?uga zdarze?
  */
 
-#include "libgadu.h"
-#include "libgadu-internal.h"
-#include "libgadu-debug.h"
-
 #include <sys/types.h>
-
 #ifndef _WIN32
 #  include <sys/ioctl.h>
 #  include <sys/socket.h>
 #  include <netinet/in.h>
 #  include <arpa/inet.h>
 #endif
+#include <ctype.h>
 
 #include "compat.h"
+#include "libgadu.h"
+#include "libgadu-config.h"
 #include "protocol.h"
+#include "libgadu-internal.h"
 #include "encoding.h"
+#include "libgadu-debug.h"
 #include "session.h"
 
 #include <errno.h>
@@ -156,7 +156,7 @@ void gg_event_free(struct gg_event *e)
 
 			break;
 		}
-
+	
 		case GG_EVENT_MULTILOGON_INFO:
 		{
 			int i;
@@ -168,6 +168,10 @@ void gg_event_free(struct gg_event *e)
 
 			break;
 		}
+
+		case GG_EVENT_USERLIST100_REPLY:
+			free(e->event.userlist100_reply.reply);
+			break;
 	}
 
 	free(e);
@@ -258,9 +262,9 @@ struct gg_event *gg_watch_fd(struct gg_s
 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno));
 
 			if (sess->state == GG_STATE_READING_REPLY)
-				goto fail_connecting;
-			else
-				goto done;
+				e->event.failure = GG_FAILURE_CONNECTING;
+
+			goto fail;
 		}
 
 		if (res == sess->send_left) {
@@ -299,7 +303,7 @@ struct gg_event *gg_watch_fd(struct gg_s
 
 			if (failed) {
 				errno = errno2;
-				goto fail_resolving;
+				goto fail_proxy_hub;
 			}
 
 			/* je?li jeste?my w resolverze i mamy ustawiony port
@@ -326,7 +330,7 @@ struct gg_event *gg_watch_fd(struct gg_s
 				/* je?li w trybie asynchronicznym gg_connect()
 				 * zwr?ci b??d, nie ma sensu pr?bowa? dalej. */
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), critical\n", errno, strerror(errno));
-				goto fail_connecting;
+				goto fail_proxy_hub;
 			}
 
 			/* je?li podano serwer i ??czmy si? przez proxy,
@@ -357,19 +361,20 @@ struct gg_event *gg_watch_fd(struct gg_s
 			/* je?li asynchroniczne, sprawdzamy, czy nie wyst?pi?
 			 * przypadkiem jaki? b??d. */
 			if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
-				if (sess->proxy_addr && sess->proxy_port)
-					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
-				else
-					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s)\n", res, strerror(res));
-
-				goto fail_connecting;
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to %s failed (errno=%d, %s)\n", (sess->proxy_addr && sess->proxy_port) ? "proxy" : "hub", res, strerror(res));
+				goto fail_proxy_hub;
 			}
 
 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n");
 
-			if (!(client = gg_urlencode((sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION))) {
+			if (sess->client_version != NULL && isdigit(sess->client_version[0]))
+				client = gg_urlencode(sess->client_version);
+			else
+				client = gg_urlencode(GG_DEFAULT_CLIENT_VERSION);
+
+			if (client == NULL) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n");
-				goto fail_connecting;
+				goto fail;
 			}
 
 			if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port)
@@ -407,13 +412,7 @@ struct gg_event *gg_watch_fd(struct gg_s
 			 * sta?o si? co? z?ego. */
 			if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n");
-
-				e->type = GG_EVENT_CONN_FAILED;
-				e->event.failure = GG_FAILURE_WRITING;
-				sess->state = GG_STATE_IDLE;
-				close(sess->fd);
-				sess->fd = -1;
-				break;
+				goto fail_proxy_hub;
 			}
 
 			sess->state = GG_STATE_READING_DATA;
@@ -439,7 +438,7 @@ struct gg_event *gg_watch_fd(struct gg_s
 			/* sprawdzamy, czy wszystko w porz?dku. */
 			if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid http reply, connection failed\n");
-				goto fail_connecting;
+				goto fail_proxy_hub;
 			}
 
 			/* ignorujemy reszt? nag??wka. */
@@ -447,7 +446,10 @@ struct gg_event *gg_watch_fd(struct gg_s
 				gg_read_line(sess->fd, buf, sizeof(buf) - 1);
 
 			/* czytamy pierwsz? lini? danych. */
-			gg_read_line(sess->fd, buf, sizeof(buf) - 1);
+			if (gg_read_line(sess->fd, buf, sizeof(buf) - 1) == NULL) {
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() read error\n");
+				goto fail_proxy_hub;
+			}
 			gg_chomp(buf);
 
 			/* je?li pierwsza liczba w linii nie jest r?wna zeru,
@@ -479,6 +481,7 @@ struct gg_event *gg_watch_fd(struct gg_s
 			}
 
 			close(sess->fd);
+			sess->fd = -1;
 
 			gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf);
 
@@ -503,10 +506,16 @@ struct gg_event *gg_watch_fd(struct gg_s
 				port = atoi(tmp + 1);
 			}
 
+			if (strcmp(host, "") == 0) {
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid response\n");
+				e->event.failure = GG_FAILURE_HUB;
+				goto fail;
+			}
+
 			if (!strcmp(host, "notoperating")) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n", errno, strerror(errno));
-				sess->fd = -1;
-				goto fail_unavailable;
+				e->event.failure = GG_FAILURE_UNAVAILABLE;
+				goto fail;
 			}
 
 			addr.s_addr = inet_addr(host);
@@ -517,7 +526,8 @@ struct gg_event *gg_watch_fd(struct gg_s
 				if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) {
 					/* nie wysz?o? trudno. */
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_PROXY;
+					goto fail;
 				}
 
 				sess->state = GG_STATE_CONNECTING_GG;
@@ -533,7 +543,7 @@ struct gg_event *gg_watch_fd(struct gg_s
 			if (sess->server_addr == INADDR_NONE) {
 				if (sess->resolver_start(&sess->fd, &sess->resolver, host) == -1) {
 					gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_resolving;
+					goto fail;
 				}
 
 				sess->state = GG_STATE_RESOLVING_GG;
@@ -553,7 +563,8 @@ struct gg_event *gg_watch_fd(struct gg_s
 					/* ostatnia deska ratunku zawiod?a?
 					 * w takim razie zwijamy manatki. */
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
 				}
 			}
 
@@ -585,7 +596,8 @@ struct gg_event *gg_watch_fd(struct gg_s
 
 			if (failed) {
 				errno = errno2;
-				goto fail_resolving;
+				e->event.failure = GG_FAILURE_RESOLVING;
+				goto fail;
 			}
 
 			sess->server_addr = addr.s_addr;
@@ -601,7 +613,8 @@ struct gg_event *gg_watch_fd(struct gg_s
 					/* ostatnia deska ratunku zawiod?a?
 					 * w takim razie zwijamy manatki. */
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
 				}
 			}
 
@@ -628,7 +641,8 @@ struct gg_event *gg_watch_fd(struct gg_s
 				 * nie mamy czego pr?bowa? wi?cej. */
 				if (sess->proxy_addr && sess->proxy_port) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_PROXY;
+					goto fail;
 				}
 
 				close(sess->fd);
@@ -648,21 +662,25 @@ struct gg_event *gg_watch_fd(struct gg_s
 
 				if (sess->ssl) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
 				}
 #endif
 
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", res, strerror(res));
 
-				if (sess->port == GG_HTTPS_PORT)
-					goto fail_connecting;
+				if (sess->port == GG_HTTPS_PORT) {
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
+				}
 
 				sess->port = GG_HTTPS_PORT;
 
 				/* pr?bujemy na port 443. */
 				if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
 				}
 
 				sess->state = GG_STATE_CONNECTING_GG;
@@ -698,7 +716,8 @@ struct gg_event *gg_watch_fd(struct gg_s
 				if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
 					free(auth);
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_PROXY;
+					goto fail;
 				}
 
 				if (auth) {
@@ -706,7 +725,8 @@ struct gg_event *gg_watch_fd(struct gg_s
 					if (write(sess->fd, auth, strlen(auth)) < (signed)strlen(auth)) {
 						gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
 						free(auth);
-						goto fail_connecting;
+						e->event.failure = GG_FAILURE_PROXY;
+						goto fail;
 					}
 
 					free(auth);
@@ -714,7 +734,8 @@ struct gg_event *gg_watch_fd(struct gg_s
 
 				if (write(sess->fd, "\r\n", 2) < 2) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_PROXY;
+					goto fail;
 				}
 			}
 
@@ -904,7 +925,14 @@ gnutls_handshake_repeat:
 		{
 			struct gg_header *gh;
 
-			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n");
+			if (sess->state == GG_STATE_READING_KEY)
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n");
+			else if (sess->state == GG_STATE_READING_REPLY)
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_REPLY\n");
+			else if (sess->state == GG_STATE_CONNECTED)
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n");
+			else if (sess->state == GG_STATE_DISCONNECTING)
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_DISCONNECTING\n");
 
 			/* XXX bardzo, bardzo, bardzo g?upi pomys? na pozbycie
 			 * si? tekstu wrzucanego przez proxy. */
@@ -936,64 +964,56 @@ gnutls_handshake_repeat:
 
 			if (gh == NULL) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() gg_recv_packet failed (errno=%d, %s)\n", errno, strerror(errno));
- 				if (errno == EAGAIN) {
-					e->type = GG_EVENT_NONE;
-					res = 0;
-				} else {
-					res = -1;
-				}
 
-				goto done;
-			}
+ 				if (errno != EAGAIN)
+					goto fail;
+			} else {
+				if (gg_session_handle_packet(sess, gh->type, (const char *) gh + sizeof(struct gg_header), gh->length, e) == -1) {
+					free(gh);
+					goto fail;
+				}
 
-			if (gg_session_handle_packet(sess, gh->type, (const char *) gh + sizeof(struct gg_header), gh->length, e) == -1) {
 				free(gh);
-				res = -1;
-				goto done;
 			}
 
-			free(gh);
-
 			sess->check = GG_CHECK_READ;
 
 			break;
 		}
 	}
 
-done:
-	if (res == -1) {
-		free(e);
-		e = NULL;
-	} else {
-		if (sess->send_buf && (sess->state == GG_STATE_READING_REPLY || sess->state == GG_STATE_CONNECTED))
-			sess->check |= GG_CHECK_WRITE;
-	}
+	if (sess->send_buf && (sess->state == GG_STATE_READING_REPLY || sess->state == GG_STATE_CONNECTED))
+		sess->check |= GG_CHECK_WRITE;
 
 	return e;
 
-fail_connecting:
+fail_proxy_hub:
+	if (sess->proxy_port)
+		e->event.failure = GG_FAILURE_PROXY;
+	else
+		e->event.failure = GG_FAILURE_HUB;
+
+fail:
+	sess->resolver_cleanup(&sess->resolver, 1);
+
+	sess->state = GG_STATE_IDLE;
+
 	if (sess->fd != -1) {
+		int errno2;
+
 		errno2 = errno;
 		close(sess->fd);
 		errno = errno2;
 		sess->fd = -1;
 	}
-	e->type = GG_EVENT_CONN_FAILED;
-	e->event.failure = GG_FAILURE_CONNECTING;
-	sess->state = GG_STATE_IDLE;
-	goto done;
 
-fail_resolving:
-	e->type = GG_EVENT_CONN_FAILED;
-	e->event.failure = GG_FAILURE_RESOLVING;
-	sess->state = GG_STATE_IDLE;
-	goto done;
-
-fail_unavailable:
-	e->type = GG_EVENT_CONN_FAILED;
-	e->event.failure = GG_FAILURE_UNAVAILABLE;
-	sess->state = GG_STATE_IDLE;
-	goto done;
+	if (e->event.failure != 0) {
+		e->type = GG_EVENT_CONN_FAILED;
+		return e;
+	} else {
+		free(e);
+		return NULL;
+	}
 }
 
 /*
============================================================
--- libpurple/protocols/gg/lib/http.c	4eb22f3b9f425682c528210152f621e8d8bf2d6b
+++ libpurple/protocols/gg/lib/http.c	f9c0de253c74a60682844fc563cb69551f65a16b
@@ -24,25 +24,22 @@
  * \brief Obs?uga po??cze? HTTP
  */
 
-#include "libgadu.h"
-
 #include <sys/types.h>
-
 #ifndef _WIN32
 #  include <sys/socket.h>
 #  include <netinet/in.h>
 #  include <arpa/inet.h>
 #endif
 
+#include "compat.h"
+#include "libgadu.h"
 #include "resolver.h"
 
 #include <ctype.h>
 #include <errno.h>
-
 #ifndef _WIN32
 #  include <netdb.h>
 #endif
-
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
============================================================
--- libpurple/protocols/gg/lib/libgadu-config.h	2db4e4eab8bfd99b6643d3269d422859786ba6a4
+++ libpurple/protocols/gg/lib/libgadu-config.h	bb5b8a51459d6647e400380ef06526ab3a75ad8b
@@ -27,6 +27,13 @@
 /* We don't like pthreads. */
 #undef __GG_LIBGADU_HAVE_PTHREAD
 
+/* Defined if libgadu was compiled and linked with GnuTLS encryption support. */
+#ifdef HAVE_GNUTLS
+#  define GG_CONFIG_HAVE_GNUTLS
+#else
+#  undef GG_CONFIG_HAVE_GNUTLS
+#endif
+
 /* Defined if libgadu was compiled and linked with TLS support. */
 /* Always undefined in Purple. */
 #undef __GG_LIBGADU_HAVE_OPENSSL
============================================================
--- libpurple/protocols/gg/lib/libgadu.c	8c8f877e3f72d0cadb86821d62fd8a235ccf44c9
+++ libpurple/protocols/gg/lib/libgadu.c	8513cccaeb9a844af5c923464197d2d0eeb76856
@@ -1,4 +1,4 @@
-/* $Id: libgadu.c 1062 2011-03-13 18:10:24Z wojtekka $ */
+/* $Id: libgadu.c 1102 2011-05-05 21:17:57Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka at irc.pl>
@@ -28,13 +28,7 @@
  * \brief G??wny modu? biblioteki
  */
 
-#include "libgadu.h"
-#include "libgadu-config.h"
-#include "libgadu-internal.h"
-#include "libgadu-debug.h"
-
 #include <sys/types.h>
-
 #ifdef _WIN32
 #  include <io.h>
 #  include <fcntl.h>
@@ -50,16 +44,21 @@
 #endif
 
 #include "compat.h"
+#include "libgadu.h"
+#include "libgadu-config.h"
 #include "protocol.h"
 #include "resolver.h"
+#include "libgadu-internal.h"
 #include "encoding.h"
+#include "libgadu-debug.h"
 #include "session.h"
+#include "message.h"
+#include "deflate.h"
 
 #ifndef _WIN32
 #  include <errno.h> /* on Win32 this is included above */
 #  include <netdb.h>
 #endif
-
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -75,11 +74,11 @@
 #  include <openssl/rand.h>
 #endif
 
-#define GG_LIBGADU_VERSION "1.10.1"
+#define GG_LIBGADU_VERSION "1.11.0"
 
 /**
  * Port gniazda nas?uchuj?cego dla po??cze? bezpo?rednich.
- *
+ * 
  * \ingroup ip
  */
 int gg_dcc_port = 0;
@@ -147,7 +146,7 @@ __attribute__ ((unused))
 #ifdef __GNUC__
 __attribute__ ((unused))
 #endif
-= "$Id: libgadu.c 1062 2011-03-13 18:10:24Z wojtekka $";
+= "$Id: libgadu.c 1102 2011-05-05 21:17:57Z wojtekka $";
 #endif
 
 #endif /* DOXYGEN */
@@ -290,11 +289,11 @@ int gg_read(struct gg_session *sess, cha
  */
 int gg_read(struct gg_session *sess, char *buf, int length)
 {
+	int res;
+
 #ifdef GG_CONFIG_HAVE_GNUTLS
 	if (sess->ssl != NULL) {
 		for (;;) {
-			int res;
-
 			res = gnutls_record_recv(GG_SESSION_GNUTLS(sess), buf, length);
 
 			if (res < 0) {
@@ -317,7 +316,7 @@ int gg_read(struct gg_session *sess, cha
 #ifdef GG_CONFIG_HAVE_OPENSSL
 	if (sess->ssl != NULL) {
 		for (;;) {
-			int res, err;
+			int err;
 
 			res = SSL_read(sess->ssl, buf, length);
 
@@ -340,7 +339,14 @@ int gg_read(struct gg_session *sess, cha
 	}
 #endif
 
-	return read(sess->fd, buf, length);
+	for (;;) {
+		res = read(sess->fd, buf, length);
+
+		if (res == -1 && errno == EINTR)
+			continue;
+
+		return res;
+	}
 }
 
 /**
@@ -361,11 +367,11 @@ static int gg_write_common(struct gg_ses
  */
 static int gg_write_common(struct gg_session *sess, const char *buf, int length)
 {
+	int res;
+
 #ifdef GG_CONFIG_HAVE_GNUTLS
 	if (sess->ssl != NULL) {
 		for (;;) {
-			int res;
-
 			res = gnutls_record_send(GG_SESSION_GNUTLS(sess), buf, length);
 
 			if (res < 0) {
@@ -388,7 +394,7 @@ static int gg_write_common(struct gg_ses
 #ifdef GG_CONFIG_HAVE_OPENSSL
 	if (sess->ssl != NULL) {
 		for (;;) {
-			int res, err;
+			int err;
 
 			res = SSL_write(sess->ssl, buf, length);
 
@@ -411,7 +417,14 @@ static int gg_write_common(struct gg_ses
 	}
 #endif
 
-	return write(sess->fd, buf, length);
+	for (;;) {
+		res = write(sess->fd, buf, length);
+
+		if (res == -1 && errno == EINTR)
+			continue;
+
+		return res;
+	}
 }
 
 
@@ -489,7 +502,7 @@ void *gg_recv_packet(struct gg_session *
 void *gg_recv_packet(struct gg_session *sess)
 {
 	struct gg_header h;
-	char *buf = NULL;
+	char *packet;
 	int ret = 0;
 	unsigned int offset, size = 0;
 
@@ -542,7 +555,6 @@ void *gg_recv_packet(struct gg_session *
 			}
 
 			sess->header_done += ret;
-
 		}
 
 		h.type = gg_fix32(h.type);
@@ -561,26 +573,25 @@ void *gg_recv_packet(struct gg_session *
 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n");
 		size = sess->recv_left;
 		offset = sess->recv_done;
-		buf = sess->recv_buf;
 	} else {
-		if (!(buf = malloc(sizeof(h) + h.length + 1))) {
+		if (!(sess->recv_buf = malloc(sizeof(h) + h.length + 1))) {
 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n");
 			return NULL;
 		}
 
-		memcpy(buf, &h, sizeof(h));
+		memcpy(sess->recv_buf, &h, sizeof(h));
 
 		offset = 0;
 		size = h.length;
 	}
 
 	while (size > 0) {
-		ret = gg_read(sess, buf + sizeof(h) + offset, size);
-		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret);
+		ret = gg_read(sess, sess->recv_buf + sizeof(h) + offset, size);
+		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, sess->recv_buf + sizeof(h) + offset, size, ret);
 		if (!ret) {
 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n");
 			errno = ECONNRESET;
-			return NULL;
+			goto fail;
 		}
 		if (ret > -1 && ret <= size) {
 			offset += ret;
@@ -590,23 +601,30 @@ void *gg_recv_packet(struct gg_session *
 
 			if (errno == EAGAIN) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size);
-				sess->recv_buf = buf;
 				sess->recv_left = size;
 				sess->recv_done = offset;
 				return NULL;
 			}
 
-			free(buf);
-			return NULL;
+			goto fail;
 		}
 	}
 
+	packet = sess->recv_buf;
+	sess->recv_buf = NULL;
 	sess->recv_left = 0;
 
 	gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_recv_packet(type=0x%.2x, length=%d)\n", h.type, h.length);
-	gg_debug_dump(sess, GG_DEBUG_DUMP, buf, sizeof(h) + h.length);
+	gg_debug_dump(sess, GG_DEBUG_DUMP, packet, sizeof(h) + h.length);
 
-	return buf;
+	return packet;
+
+fail:
+	free(sess->recv_buf);
+	sess->recv_buf = NULL;
+	sess->recv_left = 0;
+
+	return NULL;
 }
 
 /**
@@ -735,8 +753,11 @@ static int gg_session_callback(struct gg
  * serwera -- z tego powodu program musi poprawnie obs?u?y? sygna? SIGCHLD.
  *
  * \note Po nawi?zaniu po??czenia z serwerem nale?y wys?a? list? kontakt?w
- * za pomoc? funkcji \c gg_notify() lub \c gg_notify_ex().
+ *       za pomoc? funkcji \c gg_notify() lub \c gg_notify_ex().
  *
+ * \note Funkcja zwr?ci b??d ENOSYS je?li po??czenie SSL by?o wymagane, ale
+ *       obs?uga SSL nie jest wkompilowana.
+ *
  * \param p Struktura opisuj?ca parametry po??czenia. Wymagane pola: uin,
  *          password, async.
  *
@@ -796,6 +817,7 @@ struct gg_session *gg_login(const struct
 	sess->server_addr = p->server_addr;
 	sess->external_port = p->external_port;
 	sess->external_addr = p->external_addr;
+	sess->client_addr = p->client_addr;
 	sess->client_port = p->client_port;
 
 	if (p->protocol_features == 0) {
@@ -848,14 +870,14 @@ struct gg_session *gg_login(const struct
 			gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n");
 			goto fail;
 		}
-
+		
 		// XXX pami?ta?, ?eby nie ci?? w ?rodku znaku utf-8
-
+		
 		if (strlen(sess->initial_descr) > max_length)
 			sess->initial_descr[max_length] = 0;
 	}
 
-	if (p->tls == 1) {
+	if (p->tls != GG_SSL_DISABLED) {
 #ifdef GG_CONFIG_HAVE_GNUTLS
 		gg_session_gnutls_t *tmp;
 
@@ -912,6 +934,11 @@ struct gg_session *gg_login(const struct
 		}
 #else
 		gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n");
+
+		if (p->tls == GG_SSL_REQUIRED) {
+			errno = ENOSYS;
+			goto fail;
+		}
 #endif
 	}
 
@@ -1141,6 +1168,7 @@ void gg_free_session(struct gg_session *
 	free(sess->password);
 	free(sess->initial_descr);
 	free(sess->client_version);
+	free(sess->recv_buf);
 	free(sess->header_buf);
 
 #ifdef GG_CONFIG_HAVE_OPENSSL
@@ -1277,8 +1305,10 @@ static int gg_change_status_common(struc
 
 	free(new_descr);
 
-	if (GG_S_NA(status))
+	if (GG_S_NA(status)) {
 		sess->state = GG_STATE_DISCONNECTING;
+		sess->timeout = GG_TIMEOUT_DISCONNECT;
+	}
 
 	return res;
 }
@@ -1436,208 +1466,6 @@ int gg_send_message_confer(struct gg_ses
 }
 
 /**
- * \internal Dodaje tekst na koniec bufora.
- *
- * \param dst Wska?nik na bufor roboczy
- * \param pos Wska?nik na aktualne po?o?enie w buforze roboczym
- * \param src Dodawany tekst
- * \param len D?ugo?? dodawanego tekstu
- */
-static void gg_append(char *dst, int *pos, const void *src, int len)
-{
-	if (dst != NULL)
-		memcpy(&dst[*pos], src, len);
-
-	*pos += len;
-}
-
-/**
- * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML.
- *
- * \param dst Bufor wynikowy (mo?e by? \c NULL)
- * \param src Tekst ?r?d?owy w UTF-8
- * \param format Atrybuty tekstu ?r?d?owego
- * \param format_len D?ugo?? bloku atrybut?w tekstu ?r?d?owego
- *
- * \note Wynikowy tekst nie jest idealnym kodem HTML, poniewa? ma jak
- * dok?adniej odzwierciedla? to, co wygenerowa?by oryginalny klient.
- *
- * \note Dokleja \c \\0 na ko?cu bufora wynikowego.
- *
- * \return D?ugo?? tekstu wynikowego bez \c \\0 (nawet je?li \c dst to \c NULL).
- */
-static int gg_convert_to_html(char *dst, const char *src, const unsigned char *format, int format_len)
-{
-	const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">";
-	const int span_len = 75;
-	const char img_fmt[] = "<img name=\"%02x%02x%02x%02x%02x%02x%02x%02x\">";
-	const int img_len = 29;
-	int char_pos = 0;
-	int format_idx = 0;
-	unsigned char old_attr = 0;
-	const unsigned char *color = (const unsigned char*) "\x00\x00\x00";
-	int len, i;
-
-	len = 0;
-
-	/* Nie mamy atrybut?w dla pierwsze znaku, a tekst nie jest pusty, wi?c
-	 * tak czy inaczej trzeba otworzy? <span>. */
-
-	if (src[0] != 0 && (format_idx + 3 > format_len || (format[format_idx] | (format[format_idx + 1] << 8)) != 0)) {
-		if (dst != NULL)
-			sprintf(&dst[len], span_fmt, 0, 0, 0);
-
-		len += span_len;
-	}
-
-	/* P?tla przechodzi te? przez ko?cz?ce \0, ?eby m?c doklei? obrazek
-	 * na ko?cu tekstu. */
-
-	for (i = 0; ; i++) {
-		/* Analizuj atrybuty tak d?ugo jak dotycz? aktualnego znaku. */
-		for (;;) {
-			unsigned char attr;
-			int attr_pos;
-
-			if (format_idx + 3 > format_len)
-				break;
-
-			attr_pos = format[format_idx] | (format[format_idx + 1] << 8);
-
-			if (attr_pos != char_pos)
-				break;
-
-			attr = format[format_idx + 2];
-
-			/* Nie doklejaj atrybut?w na ko?cu, co najwy?ej obrazki. */
-
-			if (src[i] == 0)
-				attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR);
-
-			format_idx += 3;
-
-			if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0 || (attr == 0 && old_attr != 0)) {
-				if (char_pos != 0) {
-					if ((old_attr & GG_FONT_UNDERLINE) != 0)
-						gg_append(dst, &len, "</u>", 4);
-
-					if ((old_attr & GG_FONT_ITALIC) != 0)
-						gg_append(dst, &len, "</i>", 4);
-
-					if ((old_attr & GG_FONT_BOLD) != 0)
-						gg_append(dst, &len, "</b>", 4);
-
-					if (src[i] != 0)
-						gg_append(dst, &len, "</span>", 7);
-				}
-
-				if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) {
-					color = &format[format_idx];
-					format_idx += 3;
-				} else {
-					color = (const unsigned char*) "\x00\x00\x00";
-				}
-
-				if (src[i] != 0) {
-					if (dst != NULL)
-						sprintf(&dst[len], span_fmt, color[0], color[1], color[2]);
-					len += span_len;
-				}
-			} else if (char_pos == 0 && src[0] != 0) {
-				if (dst != NULL)
-					sprintf(&dst[len], span_fmt, 0, 0, 0);
-				len += span_len;
-			}
-
-			if ((attr & GG_FONT_BOLD) != 0)
-				gg_append(dst, &len, "<b>", 3);
-
-			if ((attr & GG_FONT_ITALIC) != 0)
-				gg_append(dst, &len, "<i>", 3);
-
-			if ((attr & GG_FONT_UNDERLINE) != 0)
-				gg_append(dst, &len, "<u>", 3);
-
-			if (((attr & GG_FONT_IMAGE) != 0) && (format_idx + 10 <= format_len)) {
-				if (dst != NULL) {
-					sprintf(&dst[len], img_fmt,
-						format[format_idx + 9],
-						format[format_idx + 8],
-						format[format_idx + 7],
-						format[format_idx + 6],
-						format[format_idx + 5],
-						format[format_idx + 4],
-						format[format_idx + 3],
-						format[format_idx + 2]);
-				}
-
-				len += img_len;
-				format_idx += 10;
-			}
-
-			old_attr = attr;
-		}
-
-		/* Doklej znak zachowuj?c htmlowe escapowanie. */
-
-		switch (src[i]) {
-			case '&':
-				gg_append(dst, &len, "&", 5);
-				break;
-			case '<':
-				gg_append(dst, &len, "<", 4);
-				break;
-			case '>':
-				gg_append(dst, &len, ">", 4);
-				break;
-			case '\'':
-				gg_append(dst, &len, "'", 6);
-				break;
-			case '\"':
-				gg_append(dst, &len, """, 6);
-				break;
-			case '\n':
-				gg_append(dst, &len, "<br>", 4);
-				break;
-			case '\r':
-			case 0:
-				break;
-			default:
-				if (dst != NULL)
-					dst[len] = src[i];
-				len++;
-		}
-
-		/* Sprawd?, czy bajt nie jest kontynuacj? znaku unikodowego. */
-
-		if ((src[i] & 0xc0) != 0xc0)
-			char_pos++;
-
-		if (src[i] == 0)
-			break;
-	}
-
-	/* Zamknij tagi. */
-
-	if ((old_attr & GG_FONT_UNDERLINE) != 0)
-		gg_append(dst, &len, "</u>", 4);
-
-	if ((old_attr & GG_FONT_ITALIC) != 0)
-		gg_append(dst, &len, "</i>", 4);
-
-	if ((old_attr & GG_FONT_BOLD) != 0)
-		gg_append(dst, &len, "</b>", 4);
-
-	if (src[0] != 0)
-		gg_append(dst, &len, "</span>", 7);
-
-	if (dst != NULL)
-		dst[len] = 0;
-
-	return len;
-}
-
-/**
  * Wysy?a wiadomo?? formatowan? w ramach konferencji.
  *
  * Zwraca losowy numer sekwencyjny, kt?ry mo?na zignorowa? albo wykorzysta?
@@ -1652,7 +1480,7 @@ static int gg_convert_to_html(char *dst,
  * \param formatlen D?ugo?? informacji o formatowaniu
  *
  * \return Numer sekwencyjny wiadomo?ci lub -1 w przypadku b??du.
- *
+ * 
  * \ingroup messages
  */
 int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message, const unsigned char *format, int formatlen)
@@ -1708,7 +1536,7 @@ int gg_send_message_confer_richtext(stru
 		s.seq = gg_fix32(seq_no);
 	} else {
 		int len;
-
+		
 		// Drobne odchylenie od protoko?u. Je?li wysy?amy kilka
 		// wiadomo?ci w ci?gu jednej sekundy, zwi?kszamy poprzedni?
 		// warto??, ?eby ka?da wiadomo?? mia?a unikalny numer.
@@ -1725,7 +1553,7 @@ int gg_send_message_confer_richtext(stru
 			formatlen = 9;
 		}
 
-		len = gg_convert_to_html(NULL, utf_msg, format + 3, formatlen - 3);
+		len = gg_message_text_to_html(NULL, utf_msg, (char*) format + 3, formatlen - 3);
 
 		html_msg = malloc(len + 1);
 
@@ -1734,7 +1562,7 @@ int gg_send_message_confer_richtext(stru
 			goto cleanup;
 		}
 
-		gg_convert_to_html(html_msg, utf_msg, format + 3, formatlen - 3);
+		gg_message_text_to_html(html_msg, utf_msg, (char*) format + 3, formatlen - 3);
 
 		s80.seq = gg_fix32(seq_no);
 		s80.msgclass = gg_fix32(msgclass);
@@ -2335,6 +2163,70 @@ int gg_userlist_request(struct gg_sessio
 }
 
 /**
+ * Wysy?a do serwera zapytanie dotycz?ce listy kontakt?w (10.0).
+ *
+ * Funkcja s?u?y do importu lub eksportu listy kontakt?w do serwera.
+ * W odr??nieniu od funkcji \c gg_notify(), ta lista kontakt?w jest przez
+ * serwer jedynie przechowywana i nie ma wp?ywu na po??czenie. Format
+ * listy kontakt?w jest jednak weryfikowany przez serwer, kt?ry stara si?
+ * synchronizowa? list? kontakt?w zapisan? w formatach GG 7.0 oraz GG 10.0.
+ * Serwer przyjmuje listy kontakt?w przys?ane w formacie niezgodnym z podanym
+ * jako \c format_type, ale nie zachowuje ich, a przes?anie takiej listy jest
+ * r?wnoznaczne z usuni?ciem listy kontakt?w.
+ *
+ * Program nie musi si? przejmowa? kompresj? listy kontakt?w zgodn?
+ * z protoko?em -- wysy?a i odbiera kompletn? list? zapisan? czystym tekstem.
+ *
+ * \param sess Struktura sesji
+ * \param type Rodzaj zapytania
+ * \param version Numer ostatniej znanej programowi wersji listy kontakt?w lub 0
+ * \param format_type Typ formatu listy kontakt?w
+ * \param request Tre?? zapytania (mo?e by? r?wne NULL)
+ *
+ * \return 0 je?li si? powiod?o, -1 w przypadku b??du
+ *
+ * \ingroup importexport
+ */
+int gg_userlist100_request(struct gg_session *sess, char type, unsigned int version, char format_type, const char *request)
+{
+	struct gg_userlist100_request pkt;
+	unsigned char *zrequest;
+	size_t zrequest_len;
+	int ret;
+
+	if (!sess) {
+		errno = EFAULT;
+		return -1;
+	}
+
+	if (sess->state != GG_STATE_CONNECTED) {
+		errno = ENOTCONN;
+		return -1;
+	}
+
+	pkt.type = type;
+	pkt.version = gg_fix32(version);
+	pkt.format_type = format_type;
+	pkt.unknown1 = 0x01;
+
+	if (request == NULL)
+		return gg_send_packet(sess, GG_USERLIST100_REQUEST, &pkt, sizeof(pkt), NULL);
+
+	zrequest = gg_deflate(request, &zrequest_len);
+
+	if (zrequest == NULL) {
+		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_userlist100_request() gg_deflate() failed");
+		return -1;
+	}
+
+	ret = gg_send_packet(sess, GG_USERLIST100_REQUEST, &pkt, sizeof(pkt), zrequest, zrequest_len, NULL);
+
+	free(zrequest);
+
+	return ret;
+}
+
+/**
  * Informuje rozm?wc? o pisaniu wiadomo?ci.
  *
  * \param sess Struktura sesji
@@ -2377,6 +2269,47 @@ int gg_multilogon_disconnect(struct gg_s
 
 /* @} */
 
+/**
+ * Sprawdza czy biblioteka obs?uguje dan? funkcj?.
+ *
+ * \param feature Identyfikator funkcji.
+ *
+ * \return Warto?? niezerowa je?li funkcja jest obs?giwana.
+ *
+ * \ingroup version
+ */
+int gg_libgadu_check_feature(gg_libgadu_feature_t feature)
+{
+	switch (feature)
+	{
+	case GG_LIBGADU_FEATURE_SSL:
+#if defined(GG_CONFIG_HAVE_OPENSSL) || defined(GG_CONFIG_HAVE_GNUTLS)
+		return 1;
+#else
+		return 0;
+#endif
+
+	case GG_LIBGADU_FEATURE_PTHREAD:
+#ifdef GG_CONFIG_HAVE_PTHREAD
+		return 1;
+#else
+		return 0;
+#endif
+
+	case GG_LIBGADU_FEATURE_USERLIST100:
+#ifdef GG_CONFIG_HAVE_ZLIB
+		return 1;
+#else
+		return 0;
+#endif
+
+	/* Celowo nie ma default, ?eby kompilator wy?apa? brakuj?ce funkcje */
+
+	}
+
+	return 0;
+}
+
 /*
  * Local variables:
  * c-indentation-style: k&r
============================================================
--- libpurple/protocols/gg/lib/libgadu.h	97bf09c52648c7690b85f4416e52905086ef2356
+++ libpurple/protocols/gg/lib/libgadu.h	f12d62503336c6615daee9fb9987877bcce046bc
@@ -1,4 +1,4 @@
-/* $Id: libgadu.h.in 1037 2010-12-17 22:18:08Z wojtekka $ */
+/* $Id: libgadu.h.in 1105 2011-05-25 21:34:50Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka at irc.pl>
@@ -57,7 +57,7 @@ extern "C" {
 #undef GG_CONFIG_HAVE_PTHREAD
 
 /* Defined if pthread resolver is the default one. */
-#undef GG_CONFIG_PTHREAD_DEFAULT
+#undef GG_CONFIG_PTHREAD_DEFAULT 
 
 /* Defined if this machine has C99-compiliant vsnprintf(). */
 #undef GG_CONFIG_HAVE_C99_VSNPRINTF
@@ -72,15 +72,14 @@ extern "C" {
 #undef GG_CONFIG_HAVE_LONG_LONG
 
 /* Defined if libgadu was compiled and linked with GnuTLS support. */
-#ifdef USE_GNUTLS
-#	define GG_CONFIG_HAVE_GNUTLS
-#else
-#	undef GG_CONFIG_HAVE_GNUTLS
-#endif
+#undef GG_CONFIG_HAVE_GNUTLS
 
 /* Defined if libgadu was compiled and linked with OpenSSL support. */
 #undef GG_CONFIG_HAVE_OPENSSL
 
+/* Defined if libgadu was compiled and linked with zlib support. */
+#undef GG_CONFIG_HAVE_ZLIB
+
 /* Defined if uintX_t types are defined in <stdint.h>. */
 #undef GG_CONFIG_HAVE_STDINT_H
 
@@ -235,11 +234,11 @@ struct gg_session {
 	uint32_t hub_addr;	/**< Adres huba po rozwi?zaniu nazwy */
 	uint32_t server_addr;	/**< Adres serwera otrzymany od huba */
 
-	uint32_t client_addr;	/**< Adres gniazda dla po??cze? bezpo?rednich do wersji Gadu-Gadu 6.x */
-	uint16_t client_port;	/**< Port gniazda dla po??cze? bezpo?rednich do wersji Gadu-Gadu 6.x */
+	uint32_t client_addr;	/**< Adres gniazda dla po??cze? bezpo?rednich */
+	uint16_t client_port;	/**< Port gniazda dla po??cze? bezpo?rednich */
 
-	uint32_t external_addr;	/**< Publiczny adres dla po??cze? bezpo?rednich do wersji Gadu-Gadu 6.x */
-	uint16_t external_port;	/**< Publiczny port dla po??cze? bezpo?rednich do wersji Gadu-Gadu 6.x */
+	uint32_t external_addr;	/**< Publiczny adres dla po??cze? bezpo?rednich */
+	uint16_t external_port;	/**< Publiczny port dla po??cze? bezpo?rednich */
 
 	uin_t uin;		/**< W?asny numer Gadu-Gadu */
 	char *password;		/**< Has?o (zwalniane po u?yciu) */
@@ -284,7 +283,7 @@ struct gg_session {
 	int send_left;		/**< Liczba bajt?w do wys?ania */
 
 	struct gg_dcc7 *dcc7_list;	/**< Lista po??cze? bezpo?rednich skojarzonych z sesj? */
-
+	
 	int soft_timeout;	/**< Flaga m?wi?ca, ?e po przekroczeniu \c timeout nale?y wywo?a? \c gg_watch_fd() */
 
 	int protocol_flags;	/**< Flagi protoko?u */
@@ -573,6 +572,17 @@ enum gg_check_t {
 };
 
 /**
+ * Flaga po??czenia szyfrowanego.
+ *
+ * \ingroup login
+ */
+typedef enum {
+	GG_SSL_DISABLED = 0,	/**< Po??czenie SSL wy??czone */
+	GG_SSL_ENABLED,		/**< Po??czenie SSL w??czone gdy dost?pne */
+	GG_SSL_REQUIRED		/**< Po??czenie SSL wymagane */
+} gg_ssl_t;
+
+/**
  * Parametry po??czenia z serwerem Gadu-Gadu. Parametry zosta?y przeniesione
  * do struktury, by unikn?? zmian API po rozszerzeniu protoko?u i dodaniu
  * kolejnych opcji po??czenia. Cz??? parametr?w, kt?re nie s? ju? aktualne
@@ -588,19 +598,15 @@ struct gg_login_params {
 	char *status_descr;		/**< Pocz?tkowy opis u?ytkownika (domy?lnie brak) */
 	uint32_t server_addr;		/**< Adres serwera Gadu-Gadu (domy?lnie pobierany automatycznie) */
 	uint16_t server_port;		/**< Port serwera Gadu-Gadu (domy?lnie pobierany automatycznie) */
-#ifndef DOXYGEN
-	uint32_t client_addr;		/**< Adres po??cze? bezpo?rednich (nieaktualne) */
-	uint16_t client_port;		/**< Port po??cze? bezpo?rednich (nieaktualne) */
-#endif
+	uint32_t client_addr;		/**< Adres po??cze? bezpo?rednich (domy?lnie dobierany automatycznie) */
+	uint16_t client_port;		/**< Port po??cze? bezpo?rednich (domy?lnie dobierany automatycznie) */
 	int protocol_version;		/**< Wersja protoko?u wysy?ana do serwera (domy?lnie najnowsza obs?ugiwana) */
 	char *client_version;		/**< Wersja klienta wysy?ana do serwera (domy?lnie najnowsza znana) */
 	int has_audio;			/**< Flaga obs?ugi po??cze? g?osowych */
 	int last_sysmsg;		/**< Numer ostatnio odebranej wiadomo?ci systemowej */
-	uint32_t external_addr;		/**< Adres publiczny dla po??cze? bezpo?rednich (6.x) */
-	uint16_t external_port;		/**< Port publiczny dla po??cze? bezpo?rednich (6.x) */
-#ifndef DOXYGEN
-	int tls;			/**< Flaga po??czenia szyfrowanego (nieaktualna) */
-#endif
+	uint32_t external_addr;		/**< Adres publiczny dla po??cze? bezpo?rednich (domy?lnie dobierany automatycznie) */
+	uint16_t external_port;		/**< Port publiczny dla po??cze? bezpo?rednich (domy?lnie dobierany automatycznie) */
+	int tls;			/**< Flaga po??czenia szyfrowanego (patrz \ref gg_ssl_t) */
 	int image_size;			/**< Maksymalny rozmiar obs?ugiwanych obrazk?w w kilobajtach */
 #ifndef DOXYGEN
 	int era_omnix;			/**< Flaga udawania klienta Era Omnix (nieaktualna) */
@@ -633,6 +639,7 @@ int gg_userlist_request(struct gg_sessio
 int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len);
 int gg_ping(struct gg_session *sess);
 int gg_userlist_request(struct gg_session *sess, char type, const char *request);
+int gg_userlist100_request(struct gg_session *sess, char type, unsigned int version, char format_type, const char *request);
 int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32);
 int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size);
 int gg_typing_notification(struct gg_session *sess, uin_t recipient, int length);
@@ -705,6 +712,9 @@ enum gg_event_t {
 	GG_EVENT_USER_DATA,		/**< Informacja o kontaktach */
 	GG_EVENT_MULTILOGON_MSG,	/**< Wiadomo?? wys?ana z innej sesji multilogowania */
 	GG_EVENT_MULTILOGON_INFO,	/**< Informacja o innych sesjach multilogowania */
+
+	GG_EVENT_USERLIST100_VERSION,	/**< Otrzymano numer wersji listy kontakt?w na serwerze (10.0) */
+	GG_EVENT_USERLIST100_REPLY,	/**< Wynik importu lub eksportu listy kontakt?w (10.0) */
 };
 
 #define GG_EVENT_SEARCH50_REPLY GG_EVENT_PUBDIR50_SEARCH_REPLY
@@ -723,7 +733,9 @@ enum gg_failure_t {
 	GG_FAILURE_TLS,			/**< B??d negocjacji szyfrowanego po??czenia */
 	GG_FAILURE_NEED_EMAIL, 		/**< Serwer roz??czy? nas z pro?b? o zmian? adresu e-mail */
 	GG_FAILURE_INTRUDER,		/**< Zbyt wiele pr?b po??czenia z nieprawid?owym has?em */
-	GG_FAILURE_UNAVAILABLE		/**< Serwery s? wy??czone */
+	GG_FAILURE_UNAVAILABLE,		/**< Serwery s? wy??czone */
+	GG_FAILURE_PROXY,		/**< B??d serwera po?rednicz?cego */
+	GG_FAILURE_HUB,			/**< B??d po??czenia z hubem */
 };
 
 /**
@@ -995,7 +1007,24 @@ struct gg_event_multilogon_info {
 };
 
 /**
- * Unia wszystkich zdarze? zwracanych przez funkcje \c gg_watch_fd(),
+ * Opis zdarzenia \c GG_EVENT_USERLIST100_VERSION.
+ */
+struct gg_event_userlist100_version {
+	uint32_t version;		/**< Numer wersji listy kontakt?w na serwerze */
+};
+
+/**
+ * Opis zdarzenia \c GG_EVENT_USERLIST100_REPLY.
+ */
+struct gg_event_userlist100_reply {
+	char type;			/**< Rodzaj odpowiedzi */
+	uint32_t version;		/**< Aktualna wersja listy kontakt?w na serwerze */
+	char format_type;		/**< Typ formatu listy kontakt?w (??dany w \c gg_userlist100_request.format_type) */
+	char *reply;			/**< Tre?? listy kontakt?w w przesy?anej wersji i formacie */
+};
+
+/**
+ * Unia wszystkich zdarze? zwracanych przez funkcje \c gg_watch_fd(), 
  * \c gg_dcc_watch_fd() i \c gg_dcc7_watch_fd().
  *
  * \ingroup events
@@ -1028,6 +1057,8 @@ union gg_event_union {
 	struct gg_event_user_data user_data;	/**< Informacje o kontaktach */
 	struct gg_event_msg multilogon_msg;	/**< Inna sesja wys?a?a wiadomo?? (\c GG_EVENT_MULTILOGON_MSG) */
 	struct gg_event_multilogon_info multilogon_info;	/**< Informacja o innych sesjach multilogowania (\c GG_EVENT_MULTILOGON_INFO) */
+	struct gg_event_userlist100_version userlist100_version;	/**< Informacja o numerze wersji listy kontakt?w na serwerze (\c GG_EVENT_USERLIST100_VERSION) */
+	struct gg_event_userlist100_reply userlist100_reply;	/**< Odpowied? listy kontakt?w (10.0) (\c GG_EVENT_USERLIST100_REPLY) */
 };
 
 /**
@@ -1092,7 +1123,7 @@ void gg_pubdir50_free(gg_pubdir50_t res)
 
 #else
 
-/**
+/** 
  * \ingroup pubdir50
  *
  * Rodzaj pola zapytania.
@@ -1158,7 +1189,7 @@ void gg_pubdir_free(struct gg_http *f);
 
 /**
  * Token autoryzacji niekt?rych operacji HTTP.
- *
+ * 
  * \ingroup token
  */
 struct gg_token {
@@ -1257,6 +1288,19 @@ const char *gg_libgadu_version(void);
 
 const char *gg_libgadu_version(void);
 
+/**
+ * Lista funkcji biblioteki, kt?re zale?? od zewn?trznych bibliotek.
+ *
+ * \ingroup version
+ */
+typedef enum {
+	GG_LIBGADU_FEATURE_SSL,		/**< Biblioteka obs?uguje po??czenia szyfrowane */
+	GG_LIBGADU_FEATURE_PTHREAD,	/**< Biblioteka obs?uguje rozwi?zywanie nazw za pomoc? w?tk?w */
+	GG_LIBGADU_FEATURE_USERLIST100,	/**< Biblioteka obs?uguje list? kontakt?w zgodn? z Gadu-Gadu 10 */
+} gg_libgadu_feature_t;
+
+int gg_libgadu_check_feature(gg_libgadu_feature_t feature);
+
 extern int gg_proxy_enabled;
 extern char *gg_proxy_host;
 extern int gg_proxy_port;
@@ -1281,7 +1325,7 @@ extern unsigned long gg_local_ip;
 
 /**
  * \ingroup pubdir50
- *
+ * 
  * Rodzaj zapytania lub odpowiedzi katalogu publicznego.
  */
 enum {
@@ -1362,10 +1406,6 @@ struct gg_http *gg_change_passwd3(uin_t 
 struct gg_http *gg_change_passwd2(uin_t uin, const char *passwd, const char *newpasswd, const char *email, const char *newemail, int async) GG_DEPRECATED;
 struct gg_http *gg_change_passwd3(uin_t uin, const char *passwd, const char *newpasswd, const char *qa, int async) GG_DEPRECATED;
 
-int gg_resolve(int *fd, int *pid, const char *hostname) GG_DEPRECATED;
-int gg_resolve_pthread(int *fd, void **resolver, const char *hostname) GG_DEPRECATED;
-void gg_resolve_pthread_cleanup(void *arg, int kill) GG_DEPRECATED;
-
 struct gg_change_info_request {
 	char *first_name;
 	char *last_name;
@@ -1427,8 +1467,8 @@ void gg_login_hash_sha1(const char *pass
 int gg_send_packet(struct gg_session *sess, int type, ...) GG_DEPRECATED;
 unsigned int gg_login_hash(const unsigned char *password, unsigned int seed) GG_DEPRECATED;
 void gg_login_hash_sha1(const char *password, uint32_t seed, uint8_t *result) GG_DEPRECATED;
-uint32_t gg_fix32(uint32_t x) GG_DEPRECATED;;
-uint16_t gg_fix16(uint16_t x) GG_DEPRECATED;;
+uint32_t gg_fix32(uint32_t x);
+uint16_t gg_fix16(uint16_t x);
 #define fix16 gg_fix16
 #define fix32 gg_fix32
 char *gg_proxy_auth(void) GG_DEPRECATED;
@@ -1506,7 +1546,7 @@ int gg_dcc7_handle_reject(struct gg_sess
 
 #else
 
-/**
+/** 
  * \ingroup login
  *
  * Flagi opcji protoko?u.
@@ -2087,6 +2127,67 @@ struct gg_userlist_reply {
 	uint8_t type;
 } GG_PACKED;
 
+#ifndef DOXYGEN
+
+#define GG_USERLIST100_PUT 0x00
+#define GG_USERLIST100_GET 0x02
+
+#else
+
+/**
+ * \ingroup importexport
+ *
+ * Rodzaj zapytania (10.0).
+ */
+enum {
+	GG_USERLIST100_PUT,	/**< Eksport listy kontakt?w. */
+	GG_USERLIST100_GET,	/**< Import listy kontakt?w. */
+};
+
+#endif	/* DOXYGEN */
+
+#ifndef DOXYGEN
+
+#define GG_USERLIST100_FORMAT_TYPE_NONE 0x00
+#define GG_USERLIST100_FORMAT_TYPE_GG70 0x01
+#define GG_USERLIST100_FORMAT_TYPE_GG100 0x02
+
+#else
+
+/**
+ * \ingroup importexport
+ *
+ * Typ formatu listy kontakt?w (10.0).
+ */
+enum {
+	GG_USERLIST100_FORMAT_TYPE_NONE,	/**< Brak tre?ci listy kontakt?w. */
+	GG_USERLIST100_FORMAT_TYPE_GG70,	/**< Format listy kontakt?w zgodny z Gadu-Gadu 7.0. */
+	GG_USERLIST100_FORMAT_TYPE_GG100,	/**< Format listy kontakt?w zgodny z Gadu-Gadu 10.0. */
+};
+
+#endif	/* DOXYGEN */
+
+#ifndef DOXYGEN
+
+#define GG_USERLIST100_REPLY_LIST 0x00
+#define GG_USERLIST100_REPLY_ACK 0x10
+#define GG_USERLIST100_REPLY_REJECT 0x12
+
+#else
+
+/**
+ * \ingroup importexport
+ *
+ * Typ odpowiedzi listy kontakt?w (10.0).
+ */
+enum {
+	GG_USERLIST100_REPLY_LIST,	/**< W odpowiedzi znajduje si? aktualna lista kontakt?w na serwerze. */
+	GG_USERLIST100_REPLY_ACK,	/**< Potwierdzenie odebrania nowej wersji listy kontakt?w. W polu \c gg_userlist100_reply.version znajduje si? numer nowej wersji listy kontakt?w. */
+	GG_USERLIST100_REPLY_REJECT,	/**< Odmowa przyj?cia nowej wersji listy kontakt?w. W polu \c gg_userlist100_reply.version znajduje si? numer wersji listy kontakt?w aktualnie przechowywanej przez serwer. */
+};
+
+#endif /* DOXYGEN */
+
 struct gg_dcc_tiny_packet {
 	uint8_t type;		/* rodzaj pakietu */
 } GG_PACKED;
============================================================
--- libpurple/protocols/gg/lib/obsolete.c	a1c79c2d8eb109dad526442edcab6d2b2ae28ff6
+++ libpurple/protocols/gg/lib/obsolete.c	b42b09a62dd26972bafcd0aaeb33bfa422b578cb
@@ -1,4 +1,4 @@
-/* $Id: obsolete.c 1036 2010-12-15 00:02:28Z wojtekka $ */
+/* $Id: obsolete.c 1082 2011-04-08 17:50:14Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka at irc.pl>
@@ -34,6 +34,7 @@
 #include <errno.h>
 
 #include "libgadu.h"
+#include "libgadu-internal.h"
 
 struct gg_http *gg_userlist_get(uin_t uin, const char *passwd, int async)
 {
============================================================
--- libpurple/protocols/gg/lib/pubdir.c	24c25104f0611f35aa2ddd6868ecb497d0e7ecb1
+++ libpurple/protocols/gg/lib/pubdir.c	ef0f7c330a64ee8eefc1272d76084befc5e6111d
@@ -26,9 +26,6 @@
  * \brief Obs?uga katalogu publicznego
  */
 
-#include "libgadu.h"
-#include "libgadu-config.h"
-
 #include <ctype.h>
 #include <errno.h>
 #include <stdarg.h>
@@ -37,6 +34,9 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "libgadu.h"
+#include "libgadu-config.h"
+
 /**
  * Rejestruje nowego u?ytkownika.
  *
@@ -122,10 +122,10 @@ struct gg_http *gg_register3(const char 
 
 	h->callback = gg_pubdir_watch_fd;
 	h->destroy = gg_pubdir_free;
-
+	
 	if (!async)
 		gg_pubdir_watch_fd(h);
-
+	
 	return h;
 }
 
@@ -193,7 +193,7 @@ struct gg_http *gg_unregister3(uin_t uin
 		errno = EFAULT;
 		return NULL;
 	}
-
+    
 	__pwd = gg_saprintf("%ld", random());
 	__fmpwd = gg_urlencode(password);
 	__tokenid = gg_urlencode(tokenid);
@@ -251,10 +251,10 @@ struct gg_http *gg_unregister3(uin_t uin
 
 	h->callback = gg_pubdir_watch_fd;
 	h->destroy = gg_pubdir_free;
-
+	
 	if (!async)
 		gg_pubdir_watch_fd(h);
-
+	
 	return h;
 }
 
@@ -324,7 +324,7 @@ struct gg_http *gg_change_passwd4(uin_t 
 		errno = EFAULT;
 		return NULL;
 	}
-
+	
 	__fmpwd = gg_urlencode(passwd);
 	__pwd = gg_urlencode(newpasswd);
 	__email = gg_urlencode(email);
@@ -340,7 +340,7 @@ struct gg_http *gg_change_passwd4(uin_t 
 		free(__tokenval);
 		return NULL;
 	}
-
+	
 	if (!(form = gg_saprintf("fmnumber=%d&fmpwd=%s&pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __email, __tokenid, __tokenval, gg_http_hash("ss", email, newpasswd)))) {
 		gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
 		free(__fmpwd);
@@ -351,13 +351,13 @@ struct gg_http *gg_change_passwd4(uin_t 
 
 		return NULL;
 	}
-
+	
 	free(__fmpwd);
 	free(__pwd);
 	free(__email);
 	free(__tokenid);
 	free(__tokenval);
-
+	
 	gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form);
 
 	query = gg_saprintf(
@@ -460,7 +460,7 @@ struct gg_http *gg_remind_passwd3(uin_t 
 		errno = EFAULT;
 		return NULL;
 	}
-
+	
 	__tokenid = gg_urlencode(tokenid);
 	__tokenval = gg_urlencode(tokenval);
 	__email = gg_urlencode(email);
@@ -484,7 +484,7 @@ struct gg_http *gg_remind_passwd3(uin_t 
 	free(__tokenid);
 	free(__tokenval);
 	free(__email);
-
+	
 	gg_debug(GG_DEBUG_MISC, "=> remind, %s\n", form);
 
 	query = gg_saprintf(
@@ -588,7 +588,7 @@ int gg_pubdir_watch_fd(struct gg_http *h
 		errno = EINVAL;
 		return -1;
 	}
-
+	
 	if (h->state != GG_STATE_PARSING) {
 		if (gg_http_watch_fd(h) == -1) {
 			gg_debug(GG_DEBUG_MISC, "=> pubdir, http failure\n");
@@ -599,9 +599,9 @@ int gg_pubdir_watch_fd(struct gg_http *h
 
 	if (h->state != GG_STATE_PARSING)
 		return 0;
-
+	
 	h->state = GG_STATE_DONE;
-
+	
 	if (!(h->data = p = malloc(sizeof(struct gg_pubdir)))) {
 		gg_debug(GG_DEBUG_MISC, "=> pubdir, not enough memory for results\n");
 		return -1;
@@ -609,7 +609,7 @@ int gg_pubdir_watch_fd(struct gg_http *h
 
 	p->success = 0;
 	p->uin = 0;
-
+	
 	gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body);
 
 	if ((tmp = strstr(h->body, "Tokens okregisterreply_packet.reg.dwUserId="))) {
@@ -636,7 +636,7 @@ void gg_pubdir_free(struct gg_http *h)
 {
 	if (!h)
 		return;
-
+	
 	free(h->data);
 	gg_http_free(h);
 }
@@ -674,10 +674,10 @@ struct gg_http *gg_token(int async)
 
 	h->callback = gg_token_watch_fd;
 	h->destroy = gg_token_free;
-
+	
 	if (!async)
 		gg_token_watch_fd(h);
-
+	
 	return h;
 }
 
@@ -706,7 +706,7 @@ int gg_token_watch_fd(struct gg_http *h)
 		errno = EINVAL;
 		return -1;
 	}
-
+	
 	if (h->state != GG_STATE_PARSING) {
 		if (gg_http_watch_fd(h) == -1) {
 			gg_debug(GG_DEBUG_MISC, "=> token, http failure\n");
@@ -717,7 +717,7 @@ int gg_token_watch_fd(struct gg_http *h)
 
 	if (h->state != GG_STATE_PARSING)
 		return 0;
-
+	
 	/* je?li h->data jest puste, to ?ci?gali?my tokenid i url do niego,
 	 * ale je?li co? tam jest, to znaczy, ?e mamy drugi etap polegaj?cy
 	 * na pobieraniu tokenu. */
@@ -735,7 +735,7 @@ int gg_token_watch_fd(struct gg_http *h)
 			free(url);
 			return -1;
 		}
-
+		
 		if (!h->body || sscanf(h->body, "%d %d %d\r\n%s\r\n%s", &width, &height, &length, tokenid, url) != 5) {
 			gg_debug(GG_DEBUG_MISC, "=> token, parsing failed\n");
 			free(url);
@@ -743,7 +743,7 @@ int gg_token_watch_fd(struct gg_http *h)
 			errno = EINVAL;
 			return -1;
 		}
-
+		
 		/* dostali?my tokenid i wszystkie niezb?dne informacje,
 		 * wi?c pobierzmy obrazek z tokenem */
 
@@ -779,7 +779,7 @@ int gg_token_watch_fd(struct gg_http *h)
 			free(url);
 			free(tokenid);
 			return -1;
-		}
+		}			
 
 		if (!(h2 = gg_http_connect(host, GG_REGISTER_PORT, h->async, "GET", path, headers))) {
 			gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
@@ -803,7 +803,7 @@ int gg_token_watch_fd(struct gg_http *h)
 
 		h->callback = gg_token_watch_fd;
 		h->destroy = gg_token_free;
-
+	
 		if (!h->async)
 			gg_token_watch_fd(h);
 
@@ -821,7 +821,7 @@ int gg_token_watch_fd(struct gg_http *h)
 		/* obrazek mamy w h->body */
 		h->state = GG_STATE_DONE;
 	}
-
+	
 	return 0;
 }
 
@@ -841,7 +841,7 @@ void gg_token_free(struct gg_http *h)
 
 	if ((t = h->data))
 		free(t->tokenid);
-
+	
 	free(h->data);
 	gg_http_free(h);
 }
============================================================
--- libpurple/protocols/gg/lib/pubdir50.c	9e7a2f14e62a3c54040951ad35370c2a8240eeba
+++ libpurple/protocols/gg/lib/pubdir50.c	947ddc5ce92d647a77cbd3d621f5d62125067419
@@ -31,6 +31,7 @@
 #include <time.h>
 
 #include "libgadu.h"
+#include "libgadu-config.h"
 #include "libgadu-internal.h"
 #include "encoding.h"
 
@@ -94,7 +95,7 @@ static int gg_pubdir50_add_n(gg_pubdir50
 
 		return 0;
 	}
-
+		
 	if (!(dupfield = strdup(field))) {
 		gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
 		free(dupvalue);
@@ -149,7 +150,7 @@ int gg_pubdir50_seq_set(gg_pubdir50_t re
 int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq)
 {
 	gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_seq_set(%p, %d);\n", req, seq);
-
+	
 	if (!req) {
 		gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_seq_set() invalid arguments\n");
 		errno = EFAULT;
@@ -174,7 +175,7 @@ void gg_pubdir50_free(gg_pubdir50_t s)
 
 	if (!s)
 		return;
-
+	
 	for (i = 0; i < s->entries_count; i++) {
 		free(s->entries[i].field);
 		free(s->entries[i].value);
@@ -202,7 +203,7 @@ uint32_t gg_pubdir50(struct gg_session *
 	struct gg_pubdir50_request *r;
 
 	gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req);
-
+	
 	if (!sess || !req) {
 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n");
 		errno = EFAULT;
@@ -219,7 +220,7 @@ uint32_t gg_pubdir50(struct gg_session *
 		/* wyszukiwanie bierze tylko pierwszy wpis */
 		if (req->entries[i].num)
 			continue;
-
+		
 		if (sess->encoding == GG_ENCODING_CP1250) {
 			size += strlen(req->entries[i].field) + 1;
 			size += strlen(req->entries[i].value) + 1;
@@ -327,7 +328,7 @@ int gg_pubdir50_handle_reply_sess(struct
 	struct gg_pubdir50_reply *r = (struct gg_pubdir50_reply*) packet;
 	gg_pubdir50_t res;
 	int num = 0;
-
+	
 	gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply_sess(%p, %p, %p, %d);\n", sess, e, packet, length);
 
 	if (!sess || !e || !packet) {
@@ -384,7 +385,7 @@ int gg_pubdir50_handle_reply_sess(struct
 		}
 
 		value = NULL;
-
+		
 		for (p = field; p < end; p++) {
 			/* je?li mamy koniec tekstu... */
 			if (!*p) {
@@ -399,7 +400,7 @@ int gg_pubdir50_handle_reply_sess(struct
 					break;
 			}
 		}
-
+		
 		/* sprawd?my, czy pole nie wychodzi poza pakiet, ?eby nie
 		 * mie? segfault?w, je?li serwer przestanie zaka?cza? pakiet?w
 		 * przez \0 */
@@ -436,10 +437,10 @@ int gg_pubdir50_handle_reply_sess(struct
 				free(tmp);
 			}
 		}
-	}
+	}	
 
 	res->count = num + 1;
-
+	
 	return 0;
 
 failure:
============================================================
--- libpurple/protocols/gg/lib/dcc7.c	a6c72f9b934bfa74119d5623b2903fe844825a05
+++ libpurple/protocols/gg/lib/dcc7.c	1e4298363bc0b0687e3044ef89a8cddf07bcc55f
@@ -1,11 +1,11 @@
-/* $Id: dcc7.c 1037 2010-12-17 22:18:08Z wojtekka $ */
+/* $Id: dcc7.c 1087 2011-04-14 20:53:25Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka at irc.pl>
  *                          Tomasz Chili?ski <chilek at chilan.com>
  *                          Adam Wysocki <gophi at ekg.chmurka.net>
  *                          Bart?omiej Zimo? <uzi18 at o2.pl>
- *
+ *  
  *  Thanks to Jakub Zawadzki <darkjames at darkjames.ath.cx>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -29,13 +29,8 @@
  * \brief Obs?uga po??cze? bezpo?rednich od wersji Gadu-Gadu 7.x
  */
 
-#include "libgadu.h"
-#include "libgadu-internal.h"
-#include "libgadu-debug.h"
-
 #include <sys/types.h>
 #include <sys/stat.h>
-
 #ifndef _WIN32
 #  include <sys/ioctl.h>
 #  include <sys/socket.h>
@@ -45,7 +40,6 @@
 #    include <sys/filio.h>
 #  endif
 #endif
-
 #include <time.h>
 
 #include <ctype.h>
@@ -58,8 +52,11 @@
 #include <unistd.h>
 
 #include "compat.h"
+#include "libgadu.h"
 #include "protocol.h"
 #include "resolver.h"
+#include "libgadu-internal.h"
+#include "libgadu-debug.h"
 
 #define gg_debug_dcc(dcc, level, fmt...) \
 	gg_debug_session(((dcc) != NULL) ? (dcc)->sess : NULL, level, fmt)
@@ -223,13 +220,16 @@ static int gg_dcc7_connect(struct gg_dcc
  * \internal Tworzy gniazdo nas?uchuj?ce dla po??czenia bezpo?redniego
  *
  * \param dcc Struktura po??czenia
- * \param port Preferowany port (je?li r?wny 0 lub -1, pr?buje si? domy?lnego)
+ * \param addr Preferowany adres (je?li r?wny 0, nas?uchujemy na wszystkich interfejsach)
+ * \param port Preferowany port (je?li r?wny 0, nas?uchujemy na losowym)
  *
  * \return 0 je?li si? powiod?o, -1 w przypadku b??du
  */
-static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint16_t port)
+static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint32_t addr, uint16_t port)
 {
 	struct sockaddr_in sin;
+	socklen_t sin_len = sizeof(sin);
+	int errsv;
 	int fd;
 
 	gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen(%p, %d)\n", dcc, port);
@@ -245,45 +245,40 @@ static int gg_dcc7_listen(struct gg_dcc7
 		return -1;
 	}
 
-	// XXX losowa? porty?
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = addr;
+	sin.sin_port = htons(port);
 
-	if (!port)
-		port = GG_DEFAULT_DCC_PORT;
+	if (bind(fd, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
+		gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to bind to %s:%d\n", inet_ntoa(sin.sin_addr), port);
+		goto fail;
+	}
 
-	while (1) {
-		sin.sin_family = AF_INET;
-		sin.sin_addr.s_addr = INADDR_ANY;
-		sin.sin_port = htons(port);
-
-		gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() trying port %d\n", port);
-
-		if (!bind(fd, (struct sockaddr*) &sin, sizeof(sin)))
-			break;
-
-		if (port++ == 65535) {
-			gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() no free port found\n");
-			close(fd);
-			errno = ENOENT;
-			return -1;
-		}
+	if (port == 0 && getsockname(fd, (struct sockaddr*) &sin, &sin_len) == -1) {
+		gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to bind to port %d\n", port);
+		goto fail;
 	}
 
 	if (listen(fd, 1)) {
-		int errsv = errno;
 		gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to listen (%s)\n", strerror(errno));
-		close(fd);
-		errno = errsv;
-		return -1;
+		goto fail;
 	}
 
 	dcc->fd = fd;
-	dcc->local_port = port;
-
+	dcc->local_addr = sin.sin_addr.s_addr;
+	dcc->local_port = ntohs(sin.sin_port);
+	
 	dcc->state = GG_STATE_LISTENING;
 	dcc->check = GG_CHECK_READ;
 	dcc->timeout = GG_DCC7_TIMEOUT_FILE_ACK;
 
 	return 0;
+
+fail:
+	errsv = errno;
+	close(fd);
+	errno = errsv;
+	return -1;
 }
 
 /**
@@ -297,38 +292,34 @@ static int gg_dcc7_listen_and_send_info(
 {
 	struct gg_dcc7_info pkt;
 	uint16_t external_port;
-	uint16_t local_port;
+	uint32_t external_addr;
+	struct in_addr addr;
 
 	gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen_and_send_info(%p)\n", dcc);
 
-	if (!dcc->sess->client_port)
-		local_port = dcc->sess->external_port;
-	else
-		local_port = dcc->sess->client_port;
-
-	if (gg_dcc7_listen(dcc, local_port) == -1)
+	if (gg_dcc7_listen(dcc, dcc->sess->client_addr, dcc->sess->client_port) == -1)
 		return -1;
 	
-	if (!dcc->sess->external_port || dcc->local_port != local_port)
+	if (dcc->sess->external_port != 0)
+		external_port = dcc->sess->external_port;
+	else
 		external_port = dcc->local_port;
-	else
-		external_port = dcc->sess->external_port;
 
-	if (!dcc->sess->external_addr || dcc->local_port != local_port)
-		dcc->local_addr = dcc->sess->client_addr;
-	else
-		dcc->local_addr = dcc->sess->external_addr;
+	if (dcc->sess->external_addr != 0)
+		external_addr = dcc->sess->external_addr;
+	else 
+		external_addr = dcc->local_addr;
 
-	gg_debug_dcc(dcc, GG_DEBUG_MISC, "// dcc7_listen_and_send_info() sending IP address %s and port %d\n", inet_ntoa(*((struct in_addr*) &dcc->local_addr)), external_port);
+	addr.s_addr = external_addr;
 
+	gg_debug_dcc(dcc, GG_DEBUG_MISC, "// dcc7_listen_and_send_info() sending IP address %s and port %d\n", inet_ntoa(addr), external_port);
+
 	memset(&pkt, 0, sizeof(pkt));
 	pkt.uin = gg_fix32(dcc->peer_uin);
 	pkt.type = GG_DCC7_TYPE_P2P;
 	pkt.id = dcc->cid;
-	snprintf((char*) pkt.info, sizeof(pkt.info), "%s %d", inet_ntoa(*((struct in_addr*) &dcc->local_addr)), external_port);
-	// TODO: implement hash count
-	// we MUST fill hash to recive from server request for server connection
-	snprintf((char*) pkt.hash, sizeof(pkt.hash), "0");
+	snprintf((char*) pkt.info, sizeof(pkt.info), "%s %d", inet_ntoa(addr), external_port);
+	snprintf((char*) pkt.hash, sizeof(pkt.hash), "%u", external_addr + external_port * rand());
 
 	return gg_send_packet(dcc->sess, GG_DCC7_INFO, &pkt, sizeof(pkt), NULL);
 }
@@ -388,7 +379,7 @@ static int gg_dcc7_request_id(struct gg_
 		errno = EINVAL;
 		return -1;
 	}
-
+	
 	memset(&pkt, 0, sizeof(pkt));
 	pkt.type = gg_fix32(type);
 
@@ -649,7 +640,7 @@ int gg_dcc7_handle_id(struct gg_session 
 
 		if (tmp->state != GG_STATE_REQUESTING_ID || tmp->dcc_type != gg_fix32(p->type))
 			continue;
-
+		
 		tmp->cid = p->id;
 
 		switch (tmp->dcc_type) {
@@ -708,9 +699,9 @@ int gg_dcc7_handle_accept(struct gg_sess
 		e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
 		return 0;
 	}
-
+	
 	// XXX czy dla odwrotnego po??czenia powinni?my wywo?a? ju? zdarzenie GG_DCC7_ACCEPT?
-
+	
 	dcc->offset = gg_fix32(p->offset);
 	dcc->state = GG_STATE_WAITING_FOR_INFO;
 
@@ -764,8 +755,10 @@ int gg_dcc7_handle_info(struct gg_sessio
 		}
 
 		if (dcc->state == GG_STATE_WAITING_FOR_INFO) {
-			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() wainting for info so send one\n");
+			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() waiting for info so send one\n");
 			gg_dcc7_listen_and_send_info(dcc);
+			e->type = GG_EVENT_DCC7_PENDING;
+			e->event.dcc7_pending.dcc7 = dcc;
 			return 0;
 		}
 
@@ -809,7 +802,7 @@ int gg_dcc7_handle_info(struct gg_sessio
 
 		gg_send_packet(dcc->sess, GG_DCC7_INFO, payload, len, NULL);
 
-		break;
+		return 0;
 
 	default:
 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unhandled transfer type (%d)\n", p->type);
@@ -877,7 +870,7 @@ int gg_dcc7_handle_reject(struct gg_sess
 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() unknown dcc session\n");
 		return 0;
 	}
-
+	
 	if (dcc->state != GG_STATE_WAITING_FOR_ACCEPT) {
 		gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() invalid state\n");
 		e->type = GG_EVENT_DCC7_ERROR;
@@ -917,7 +910,7 @@ int gg_dcc7_handle_new(struct gg_session
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() not enough memory\n");
 				return -1;
 			}
-
+			
 			memset(dcc, 0, sizeof(struct gg_dcc7));
 			dcc->type = GG_SESSION_DCC7_GET;
 			dcc->dcc_type = GG_DCC7_TYPE_FILE;
@@ -949,7 +942,7 @@ int gg_dcc7_handle_new(struct gg_session
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_packet() not enough memory\n");
 				return -1;
 			}
-
+			
 			memset(dcc, 0, sizeof(struct gg_dcc7));
 
 			dcc->type = GG_SESSION_DCC7_VOICE;
@@ -984,7 +977,7 @@ int gg_dcc7_handle_new(struct gg_session
 /**
  * \internal Ustawia odpowiednie stany wewn?trzne w zale?no?ci od rodzaju
  * po??czenia.
- *
+ * 
  * \param dcc Struktura po??czenia
  *
  * \return 0 je?li si? powiod?o, -1 w przypadku b??du.
@@ -1382,6 +1375,9 @@ struct gg_event *gg_dcc7_watch_fd(struct
 			dcc->check = GG_CHECK_WRITE;
 			dcc->timeout = GG_DEFAULT_TIMEOUT;
 
+			e->type = GG_EVENT_DCC7_PENDING;
+			e->event.dcc7_pending.dcc7 = dcc;
+
 			return e;
 		}
 
============================================================
--- libpurple/protocols/gg/lib/protocol.h	1962fb3d0dff7fb0a79d9042d69fe0dc208e8984
+++ libpurple/protocols/gg/lib/protocol.h	8c23f831e28640b26125ab8c14a3c99dd21548f5
@@ -136,7 +136,7 @@ struct gg_recv_msg_ack {
 #define GG_RECV_MSG_ACK 0x0046
 
 struct gg_recv_msg_ack {
-	uint32_t count;
+	uint32_t seq;
 } GG_PACKED;
 
 #define GG_USER_DATA 0x0044
@@ -192,6 +192,20 @@ struct gg_multilogon_disconnect {
 #define GG_MSG_OPTION_IMAGE_REPLY 0x05
 #define GG_MSG_OPTION_IMAGE_REPLY_MORE 0x06
 
+#define GG_DCC7_ABORT 0x0025
+
+struct gg_dcc7_abort {
+	gg_dcc7_id_t id;		/* identyfikator po??czenia */
+	uint32_t uin_from;		/* numer nadawcy */
+	uint32_t uin_to;		/* numer odbiorcy */
+} GG_PACKED;
+
+#define GG_DCC7_ABORTED 0x0025
+
+struct gg_dcc7_aborted {
+	gg_dcc7_id_t id;		/* identyfikator po??czenia */
+} GG_PACKED;
+
 #define GG_DCC7_VOICE_RETRIES 0x11	/* 17 powtorzen */
 
 #define GG_DCC7_RESERVED1		0xdeadc0de
@@ -277,6 +291,34 @@ struct gg_dcc7_welcome_p2p {
 	gg_dcc7_id_t id;		/* identyfikator po??czenia */
 } GG_PACKED;
 
+#define GG_TIMEOUT_DISCONNECT 5	/**< Maksymalny czas oczekiwania na roz??czenie */
+
+#define GG_USERLIST100_VERSION 0x5c
+
+struct gg_userlist100_version {
+	uint32_t version;		/* numer wersji listy kontakt?w */
+} GG_PACKED;
+
+#define GG_USERLIST100_REQUEST 0x0040
+
+struct gg_userlist100_request {
+	uint8_t type;			/* rodzaj ??dania */
+	uint32_t version;		/* numer ostatniej znanej wersji listy kontakt?w b?d? 0 */
+	uint8_t format_type;		/* rodzaj ??danego typu formatu listy kontakt?w */
+	uint8_t unknown1;		/* 0x01 */
+	/* char request[]; */
+} GG_PACKED;
+
+#define GG_USERLIST100_REPLY 0x41
+
+struct gg_userlist100_reply {
+	uint8_t type;			/* rodzaj odpowiedzi */
+	uint32_t version;		/* numer wersji listy kontakt?w aktualnie przechowywanej przez serwer */
+	uint8_t format_type;		/* rodzaj przesy?anego typu formatu listy kontakt?w */
+	uint8_t unknown1;		/* 0x01 */
+	/* char reply[]; */
+} GG_PACKED;
+
 #ifdef _WIN32
 #pragma pack(pop)
 #endif
============================================================
--- libpurple/protocols/gg/lib/resolver.c	377f2c18151ca0e00429029cf73fbbef305beeea
+++ libpurple/protocols/gg/lib/resolver.c	65df2bfb80d2e7b4790a26a85111907b3a4aa846
@@ -29,17 +29,19 @@
 #ifndef _WIN32
 #  include <sys/wait.h>
 #  include <netdb.h>
-#  include <signal.h>
-#  include <netinet/in.h>
-#  include <arpa/inet.h>
 #endif
-
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#ifndef _WIN32
+#  include <signal.h>
+#  include <netinet/in.h>
+#  include <arpa/inet.h>
+#endif
 
 #include "libgadu.h"
+#include "libgadu-config.h"
 #include "resolver.h"
 #include "compat.h"
 #include "session.h"
@@ -212,7 +214,6 @@ int gg_gethostbyname_real(const char *ho
 	struct hostent *he;
 	int i;
 
-
 	if (result == NULL || count == NULL) {
 		errno = EINVAL;
 		return -1;
@@ -256,7 +257,7 @@ int gg_gethostbyname_real(const char *ho
  *
  * \return 0 je?li si? powiod?o, -1 w przypadku b??du
  */
-int gg_resolver_run(int fd, const char *hostname)
+static int gg_resolver_run(int fd, const char *hostname)
 {
 	struct in_addr addr_ip[2], *addr_list;
 	int addr_count;
@@ -595,7 +596,7 @@ static void gg_resolve_win32thread_clean
  *
  * Po??czenia asynchroniczne nie mog? blokowa? procesu w trakcie rozwi?zywania
  * nazwy serwera. W tym celu tworzony jest potok, nowy proces i dopiero w nim
- * przeprowadzane jest rozwi?zywanie nazwy. Deskryptor strony do odczytu
+ * przeprowadzane jest rozwi?zywanie nazwy. Deskryptor strony do odczytu 
  * zapisuje si? w strukturze sieci i czeka na dane w postaci struktury
  * \c in_addr. Je?li nie znaleziono nazwy, zwracana jest \c INADDR_NONE.
  *
@@ -865,13 +866,13 @@ int gg_session_set_resolver(struct gg_se
 			return 0;
 		}
 
-#ifdef _WIN32
+#if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT)
+#  ifdef _WIN32
 		type = GG_RESOLVER_WIN32;
-#else
+#  else
 		type = GG_RESOLVER_FORK;
-#endif
-
-#if defined(GG_CONFIG_HAVE_PTHREAD) || defined(GG_CONFIG_PTHREAD_DEFAULT)
+#  endif
+#else
 		type = GG_RESOLVER_PTHREAD;
 #endif
 	}
@@ -936,7 +937,7 @@ gg_resolver_t gg_session_get_resolver(st
  *  - \c "int force" — flaga m?wi?ca o tym, ?e zasoby s? zwalniane przed zako?czeniem rozwi?zywania nazwy, np. z powodu zamkni?cia sesji.
  *
  * W?asny kod rozwi?zywania nazwy powinien stworzy? potok, par? gniazd lub
- * inny deskryptor pozwalaj?cy na co najmniej jednostronn? komunikacj? i
+ * inny deskryptor pozwalaj?cy na co najmniej jednostronn? komunikacj? i 
  * przekaza? go w parametrze \c fd. Po zako?czeniu rozwi?zywania nazwy,
  * powinien wys?a? otrzymany adres IP w postaci sieciowej (big-endian) do
  * deskryptora. Je?li rozwi?zywanie nazwy si? nie powiedzie, nale?y wys?a?
@@ -986,13 +987,13 @@ int gg_http_set_resolver(struct gg_http 
 			return 0;
 		}
 
-#ifdef _WIN32
+#if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT)
+#  ifdef _WIN32
 		type = GG_RESOLVER_WIN32;
-#else
+#  else
 		type = GG_RESOLVER_FORK;
-#endif
-
-#if defined(GG_CONFIG_HAVE_PTHREAD) || defined(GG_CONFIG_PTHREAD_DEFAULT)
+#  endif
+#else
 		type = GG_RESOLVER_PTHREAD;
 #endif
 	}
@@ -1082,20 +1083,18 @@ int gg_global_set_resolver(gg_resolver_t
 			gg_global_resolver_cleanup = NULL;
 			return 0;
 
-#ifndef _WIN32
-		case GG_RESOLVER_FORK:
-			gg_global_resolver_type = type;
-			gg_global_resolver_start = gg_resolver_fork_start;
-			gg_global_resolver_cleanup = gg_resolver_fork_cleanup;
-			return 0;
-#endif
-
 #ifdef _WIN32
 		case GG_RESOLVER_WIN32:
 			gg_global_resolver_type = type;
 			gg_global_resolver_start = gg_resolve_win32thread;
 			gg_global_resolver_cleanup = gg_resolve_win32thread_cleanup;
 			return 0;
+#else
+		case GG_RESOLVER_FORK:
+			gg_global_resolver_type = type;
+			gg_global_resolver_start = gg_resolver_fork_start;
+			gg_global_resolver_cleanup = gg_resolver_fork_cleanup;
+			return 0;
 #endif
 
 #ifdef GG_CONFIG_HAVE_PTHREAD
============================================================
--- libpurple/protocols/gg/lib/sha1.c	7000a9b21613434c8f9e4348959d4aea62c2961c
+++ libpurple/protocols/gg/lib/sha1.c	b56d79e98cedec6b8b3d8eb82649d400c209d8f9
@@ -1,4 +1,4 @@
-/* $Id: sha1.c 632 2008-07-30 18:40:06Z darkjames $ */
+/* $Id: sha1.c 1067 2011-03-15 18:57:16Z wojtekka $ */
 
 /*
  *  (C) Copyright 2007 Wojtek Kaniewski <wojtekka at irc.pl>
@@ -23,7 +23,7 @@
 /**
  * \file sha1.c
  *
- * \brief Funkcje wyznaczania skr??tu SHA1
+ * \brief Funkcje wyznaczania skr?tu SHA1
  */
 
 #include <string.h>
@@ -228,12 +228,12 @@ void gg_login_hash_sha1(const char *pass
 void gg_login_hash_sha1(const char *password, uint32_t seed, uint8_t *result)
 {
 	SHA_CTX ctx;
-
+	
 	SHA1_Init(&ctx);
 	SHA1_Update(&ctx, (const unsigned char*) password, strlen(password));
 	seed = gg_fix32(seed);
 	SHA1_Update(&ctx, (uint8_t*) &seed, 4);
-
+	
 	SHA1_Final(result, &ctx);
 }
 
============================================================
--- libpurple/protocols/gg/lib/debug.c	a5cfffc011e5557917bc9b64a2447d98ebe547dd
+++ libpurple/protocols/gg/lib/debug.c	9a87a0e803fcd57337fce35be982651ecbd8c6a1
@@ -32,7 +32,7 @@
 #include <string.h>
 
 #include "libgadu.h"
-#include "debug.h"
+#include "libgadu-debug.h"
 
 /**
  * Poziom rejestracji informacji odpluskwiaj?cych. Zmienna jest mask? bitow?
@@ -265,14 +265,80 @@ const char *gg_debug_state(enum gg_state
 	GG_DEBUG_STATE(GG_STATE_CONNECTING_RELAY)
 	GG_DEBUG_STATE(GG_STATE_READING_RELAY)
 	GG_DEBUG_STATE(GG_STATE_DISCONNECTING)
+#undef GG_DEBUG_STATE
 
-	// Celowo nie ma default, ?eby kompilator wy?apa? brakuj?ce stany
+	/* Celowo nie ma default, ?eby kompilator wy?apa? brakuj?ce stany */
 	
 	}
 
 	return NULL;
 }
 
+/**
+ * \internal Zwraca ci?g z nazw? podanego zdarzenia.
+ *
+ * \param event Zdarzenie.
+ *
+ * \return Ci?g z nazw? zdarzenia
+ *
+ * \ingroup debug
+ */
+const char *gg_debug_event(enum gg_event_t event)
+{
+	switch (event) {
+#define GG_DEBUG_EVENT(x) case x: return #x;
+	GG_DEBUG_EVENT(GG_EVENT_NONE)
+	GG_DEBUG_EVENT(GG_EVENT_MSG)
+	GG_DEBUG_EVENT(GG_EVENT_NOTIFY)
+	GG_DEBUG_EVENT(GG_EVENT_NOTIFY_DESCR)
+	GG_DEBUG_EVENT(GG_EVENT_STATUS)
+	GG_DEBUG_EVENT(GG_EVENT_ACK)
+	GG_DEBUG_EVENT(GG_EVENT_PONG)
+	GG_DEBUG_EVENT(GG_EVENT_CONN_FAILED)
+	GG_DEBUG_EVENT(GG_EVENT_CONN_SUCCESS)
+	GG_DEBUG_EVENT(GG_EVENT_DISCONNECT)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_NEW)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_ERROR)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_DONE)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_CLIENT_ACCEPT)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_CALLBACK)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_NEED_FILE_INFO)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_NEED_FILE_ACK)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_NEED_VOICE_ACK)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_VOICE_DATA)
+	GG_DEBUG_EVENT(GG_EVENT_PUBDIR50_SEARCH_REPLY)
+	GG_DEBUG_EVENT(GG_EVENT_PUBDIR50_READ)
+	GG_DEBUG_EVENT(GG_EVENT_PUBDIR50_WRITE)
+	GG_DEBUG_EVENT(GG_EVENT_STATUS60)
+	GG_DEBUG_EVENT(GG_EVENT_NOTIFY60)
+	GG_DEBUG_EVENT(GG_EVENT_USERLIST)
+	GG_DEBUG_EVENT(GG_EVENT_IMAGE_REQUEST)
+	GG_DEBUG_EVENT(GG_EVENT_IMAGE_REPLY)
+	GG_DEBUG_EVENT(GG_EVENT_DCC_ACK)
+	GG_DEBUG_EVENT(GG_EVENT_DCC7_NEW)
+	GG_DEBUG_EVENT(GG_EVENT_DCC7_ACCEPT)
+	GG_DEBUG_EVENT(GG_EVENT_DCC7_REJECT)
+	GG_DEBUG_EVENT(GG_EVENT_DCC7_CONNECTED)
+	GG_DEBUG_EVENT(GG_EVENT_DCC7_ERROR)
+	GG_DEBUG_EVENT(GG_EVENT_DCC7_DONE)
+	GG_DEBUG_EVENT(GG_EVENT_DCC7_PENDING)
+	GG_DEBUG_EVENT(GG_EVENT_XML_EVENT)
+	GG_DEBUG_EVENT(GG_EVENT_DISCONNECT_ACK)
+	GG_DEBUG_EVENT(GG_EVENT_TYPING_NOTIFICATION)
+	GG_DEBUG_EVENT(GG_EVENT_USER_DATA)
+	GG_DEBUG_EVENT(GG_EVENT_MULTILOGON_MSG)
+	GG_DEBUG_EVENT(GG_EVENT_MULTILOGON_INFO)
+	GG_DEBUG_EVENT(GG_EVENT_USERLIST100_VERSION)
+	GG_DEBUG_EVENT(GG_EVENT_USERLIST100_REPLY)
+#undef GG_DEBUG_EVENT
+
+	/* Celowo nie ma default, ?eby kompilator wy?apa? brakuj?ce zdarzenia */
+	
+	}
+
+	return NULL;
+}
+
 #else
 
 #undef gg_debug_common
@@ -291,7 +357,7 @@ void gg_debug_session(struct gg_session 
 }
 
 #undef gg_debug_dump
-void gg_debug_dump(struct gg_session *gs, int level, const char *buf, int len)
+void gg_debug_dump(struct gg_session *gs, int level, const char *buf, size_t len)
 {
 }
 
============================================================
--- libpurple/protocols/gg/lib/encoding.c	74fec37e5d7745c75f299ccbe386de951aeb888d
+++ libpurple/protocols/gg/lib/encoding.c	151c59ca64dc1c83755e882ab90f6e04ea35d952
@@ -22,6 +22,7 @@
 #include <errno.h>
 
 #include "libgadu.h"
+#include "encoding.h"
 
 /**
  * \file encoding.c
============================================================
--- libpurple/protocols/gg/lib/handlers.c	78554d359748d3761b1e80d7b0e83471b3ddea9e
+++ libpurple/protocols/gg/lib/handlers.c	87d66880d587b734d3016a4449b5dd2f782f025e
@@ -27,11 +27,13 @@
  */
 
 #include <sys/types.h>
-
 #ifndef _WIN32
 #  include <sys/socket.h>
 #  include <netinet/in.h>
 #  include <arpa/inet.h>
+#endif
+#include <ctype.h>
+#ifndef _WIN32
 #  ifdef sun
 #    include <sys/filio.h>
 #  endif
@@ -39,12 +41,14 @@
 
 #include "compat.h"
 #include "libgadu.h"
+#include "libgadu-config.h"
 #include "resolver.h"
 #include "session.h"
 #include "protocol.h"
 #include "encoding.h"
 #include "message.h"
 #include "libgadu-internal.h"
+#include "deflate.h"
 
 #include <errno.h>
 #ifndef _WIN32
@@ -87,6 +91,8 @@ static int gg_session_handle_welcome(str
 	int ret;
 	uint8_t hash_buf[64];
 	uint32_t local_ip;
+	struct sockaddr_in sin;
+	unsigned int sin_len = sizeof(sin);
 
 	if (len < sizeof(struct gg_welcome)) {
 		ge->type = GG_EVENT_CONN_FAILED;
@@ -145,29 +151,22 @@ static int gg_session_handle_welcome(str
 	}
 #endif
 
-	if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) {
-		struct sockaddr_in sin;
-		unsigned int sin_len = sizeof(sin);
+	if (!getsockname(gs->fd, (struct sockaddr*) &sin, &sin_len)) {
+		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
+		local_ip = sin.sin_addr.s_addr;
+	} else {
+		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
+		local_ip = 0;
+	}
 
-		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detecting address\n");
-
-		if (!getsockname(gs->fd, (struct sockaddr*) &sin, &sin_len)) {
-			gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
-			local_ip = sin.sin_addr.s_addr;
-		} else {
-			gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
-			local_ip = 0;
-		}
-	} else
-		local_ip = gg_dcc_ip;
-
-	gs->client_addr = local_ip;
-
 	if (GG_SESSION_IS_PROTOCOL_8_0(gs)) {
 		struct gg_login80 l80;
-		const char *version, *descr;
-		uint32_t version_len, descr_len;
+		const char *client_name, *version, *descr;
+		uint32_t client_name_len, version_len, descr_len;
 
+		if (gs->external_addr == 0)
+			gs->external_addr = local_ip;
+
 		memset(&l80, 0, sizeof(l80));
 		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending GG_LOGIN80 packet\n");
 		l80.uin = gg_fix32(gs->uin);
@@ -180,8 +179,16 @@ static int gg_session_handle_welcome(str
 		l80.image_size = gs->image_size;
 		l80.dunno2 = 0x64;
 
+		if (gs->client_version != NULL && !isdigit(gs->client_version[0])) {
+			client_name = "";
+			client_name_len = 0;
+		} else {
+			client_name = GG8_VERSION;
+			client_name_len = strlen(GG8_VERSION);
+		}
+
 		version = (gs->client_version != NULL) ? gs->client_version : GG_DEFAULT_CLIENT_VERSION;
-		version_len = gg_fix32(strlen(GG8_VERSION) + strlen(version));
+		version_len = gg_fix32(client_name_len + strlen(version));
 
 		descr = (gs->initial_descr != NULL) ? gs->initial_descr : "";
 		descr_len = (gs->initial_descr != NULL) ? gg_fix32(strlen(gs->initial_descr)) : 0;
@@ -190,7 +197,7 @@ static int gg_session_handle_welcome(str
 				GG_LOGIN80,
 				&l80, sizeof(l80),
 				&version_len, sizeof(version_len),
-				GG8_VERSION, strlen(GG8_VERSION),
+				client_name, client_name_len,
 				version, strlen(version),
 				&descr_len, sizeof(descr_len),
 				descr, strlen(descr),
@@ -198,6 +205,11 @@ static int gg_session_handle_welcome(str
 	} else {
 		struct gg_login70 l70;
 
+		if (gg_dcc_ip != (unsigned long) inet_addr("255.255.255.255"))
+			local_ip = gg_dcc_ip;
+
+		gs->client_addr = local_ip;
+
 		memset(&l70, 0, sizeof(l70));
 		l70.uin = gg_fix32(gs->uin);
 		l70.hash_type = gs->hash_type;
@@ -460,7 +472,7 @@ static int gg_session_handle_dcc7_accept
 
 /**
  * \internal Obs?uguje pakiet GG_DCC7_NEW.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_dcc7_new(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -472,7 +484,7 @@ static int gg_session_handle_dcc7_new(st
 
 /**
  * \internal Obs?uguje pakiet GG_DCC7_REJECT.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_dcc7_reject(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -484,7 +496,7 @@ static int gg_session_handle_dcc7_reject
 
 /**
  * \internal Obs?uguje pakiet GG_DCC7_INFO.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_dcc7_info(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -574,7 +586,7 @@ static void gg_image_queue_parse(struct 
 
 /**
  * \internal Analizuje informacje rozszerzone wiadomo?ci.
- *
+ * 
  * \param sess Struktura sesji.
  * \param e Struktura zdarzenia.
  * \param sender Numer nadawcy.
@@ -756,10 +768,11 @@ malformed:
  * \internal Wysy?a potwierdzenie odebrania wiadomo?ci.
  *
  * \param gs Struktura sesji
+ * \param seq Numer sekwencyjny odebranej wiadomo?ci
  *
  * \return 0 je?li si? powiod?o, -1 je?li wyst?pi? b??d
  */
-static int gg_session_send_msg_ack(struct gg_session *gs)
+static int gg_session_send_msg_ack(struct gg_session *gs, uint32_t seq)
 {
 	struct gg_recv_msg_ack pkt;
 
@@ -768,15 +781,18 @@ static int gg_session_send_msg_ack(struc
 	if ((gs->protocol_features & GG_FEATURE_MSG_ACK) == 0)
 		return 0;
 
+	/* Kiedy? zdawa?o nam si?, ?e mamy wysy?a? liczb? odebranych
+	 * wiadomo?ci, ale okaza?o si?, ?e numer sekwencyjny. */
 	gs->recv_msg_count++;
-	pkt.count = gg_fix32(gs->recv_msg_count);
 
+	pkt.seq = gg_fix32(seq);
+
 	return gg_send_packet(gs, GG_RECV_MSG_ACK, &pkt, sizeof(pkt), NULL);
 }
 
 /**
  * \internal Obs?uguje pakiet GG_RECV_MSG.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_recv_msg(struct gg_session *sess, uint32_t type, const char *packet, size_t length, struct gg_event *e)
@@ -799,19 +815,19 @@ static int gg_session_handle_recv_msg(st
 		length = 1;
 	} else {
 		const char *options;
-
+		
 		options = memchr(payload, 0, (size_t) (payload_end - payload));
 
 		if (options == NULL) {
 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() malformed packet, message out of bounds (0)\n");
 			goto malformed;
 		}
-
+		
 		length = (size_t) (options - payload);
 
 		switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), options + 1, payload_end)) {
 			case -1:	// handled
-				gg_session_send_msg_ack(sess);
+				gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 				return 0;
 
 			case -2:	// failed
@@ -833,7 +849,7 @@ static int gg_session_handle_recv_msg(st
 		goto fail;
 	e->event.msg.message = (unsigned char*) tmp;
 
-	gg_session_send_msg_ack(sess);
+	gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 	return 0;
 
 fail:
@@ -848,13 +864,13 @@ malformed:
 	free(e->event.msg.xhtml_message);
 	free(e->event.msg.recipients);
 	free(e->event.msg.formats);
-	gg_session_send_msg_ack(sess);
+	gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 	return 0;
 }
 
 /**
  * \internal Obs?uguje pakiet GG_RECV_MSG80.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_recv_msg_80(struct gg_session *sess, uint32_t type, const char *packet, size_t length, struct gg_event *e)
@@ -906,7 +922,7 @@ static int gg_session_handle_recv_msg_80
 	if (offset_attr != 0) {
 		switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), packet + offset_attr, packet + length)) {
 			case -1:	// handled
-				gg_session_send_msg_ack(sess);
+				gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 				return 0;
 
 			case -2:	// failed
@@ -940,7 +956,7 @@ static int gg_session_handle_recv_msg_80
 	else
 		e->event.msg.xhtml_message = NULL;
 
-	gg_session_send_msg_ack(sess);
+	gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 	return 0;
 
 fail:
@@ -956,13 +972,13 @@ malformed:
 	free(e->event.msg.xhtml_message);
 	free(e->event.msg.recipients);
 	free(e->event.msg.formats);
-	gg_session_send_msg_ack(sess);
+	gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 	return 0;
 }
 
 /**
  * \internal Obs?uguje pakiet GG_STATUS.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_status(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -990,7 +1006,7 @@ static int gg_session_handle_status(stru
 
 /**
  * \internal Obs?uguje pakiety GG_STATUS60, GG_STATUS77 i GG_STATUS80BETA.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_status_60_77_80beta(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1057,7 +1073,7 @@ static int gg_session_handle_status_60_7
 
 /**
  * \internal Obs?uguje pakiet GG_NOTIFY_REPLY.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_notify_reply(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1121,7 +1137,7 @@ static int gg_session_handle_notify_repl
 
 /**
  * \internal Obs?uguje pakiet GG_STATUS80.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_status_80(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1159,7 +1175,7 @@ static int gg_session_handle_status_80(s
 
 /**
  * \internal Obs?uguje pakiet GG_NOTIFY_REPLY80.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_notify_reply_80(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1235,7 +1251,7 @@ static int gg_session_handle_notify_repl
 
 /**
  * \internal Obs?uguje pakiety GG_NOTIFY_REPLY77 i GG_NOTIFY_REPLY80BETA.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_notify_reply_77_80beta(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1287,7 +1303,7 @@ static int gg_session_handle_notify_repl
 				}
 
 				/* XXX czas */
-
+					
 				length -= sizeof(struct gg_notify_reply77) + descr_len + 1;
 				n = (void*) ((char*) n + sizeof(struct gg_notify_reply77) + descr_len + 1);
 			} else {
@@ -1314,7 +1330,7 @@ static int gg_session_handle_notify_repl
 
 /**
  * \internal Obs?uguje pakiet GG_NOTIFY_REPLY60.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_notify_reply_60(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1368,7 +1384,7 @@ static int gg_session_handle_notify_repl
 				ge->event.notify60[i].descr = descr;
 
 				/* XXX czas */
-
+					
 				length -= sizeof(struct gg_notify_reply60) + descr_len + 1;
 				n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1);
 			} else {
@@ -1395,7 +1411,7 @@ static int gg_session_handle_notify_repl
 
 /**
  * \internal Obs?uguje pakiet GG_USER_DATA.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_user_data(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1441,7 +1457,7 @@ static int gg_session_handle_user_data(s
 	ge->event.user_data.type = d.type;
 	ge->event.user_data.user_count = d.user_count;
 	ge->event.user_data.users = users;
-
+	
 	gg_debug_session(gs, GG_DEBUG_DUMP, "type=%d, count=%d\n", d.type, d.user_count);
 
 	for (i = 0; i < d.user_count; i++) {
@@ -1577,7 +1593,7 @@ malformed:
 
 /**
  * \internal Obs?uguje pakiet GG_TYPING_NOTIFICATION.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_typing_notification(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1598,7 +1614,7 @@ static int gg_session_handle_typing_noti
 
 /**
  * \internal Obs?uguje pakiet GG_MULTILOGON_INFO.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_multilogon_info(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1626,7 +1642,7 @@ static int gg_session_handle_multilogon_
 		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() out of memory (%d*%d)\n", count, sizeof(struct gg_multilogon_session));
 		return -1;
 	}
-
+	
 	ge->type = GG_EVENT_MULTILOGON_INFO;
 	ge->event.multilogon_info.count = count;
 	ge->event.multilogon_info.sessions = sessions;
@@ -1687,6 +1703,53 @@ malformed:
 }
 
 /**
+ * \internal Obs?uguje pakiet GG_USERLIST100_VERSION.
+ *
+ * Patrz gg_packet_handler_t
+ */
+static int gg_session_handle_userlist_100_version(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
+{
+	struct gg_userlist100_version *version = (struct gg_userlist100_version*) ptr;
+
+	gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 version\n");
+
+	ge->type = GG_EVENT_USERLIST100_VERSION;
+	ge->event.userlist100_version.version = gg_fix32(version->version);
+
+	return 0;
+}
+
+/**
+ * \internal Obs?uguje pakiet GG_USERLIST100_REPLY.
+ *
+ * Patrz gg_packet_handler_t
+ */
+static int gg_session_handle_userlist_100_reply(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
+{
+	struct gg_userlist100_reply *reply = (struct gg_userlist100_reply*) ptr;
+	char *data = NULL;
+
+	gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 reply\n");
+
+	if (len > sizeof(*reply)) {
+		data = gg_inflate((const unsigned char*) ptr + sizeof(*reply), len - sizeof(*reply));
+		
+		if (data == NULL) {
+			gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_userlist_100_reply() gg_inflate() failed\n");
+			return -1;
+		}
+	}
+
+	ge->type = GG_EVENT_USERLIST100_REPLY;
+	ge->event.userlist100_reply.type = reply->type;
+	ge->event.userlist100_reply.version = gg_fix32(reply->version);
+	ge->event.userlist100_reply.format_type = reply->format_type;
+	ge->event.userlist100_reply.reply = data;
+
+	return 0;
+}
+
+/**
  * \internal Tablica obs?ugiwanych pakiet?w
  */
 static const gg_packet_handler_t handlers[] =
@@ -1726,6 +1789,8 @@ static const gg_packet_handler_t handler
 	{ GG_MULTILOGON_INFO, GG_STATE_CONNECTED, sizeof(struct gg_multilogon_info), gg_session_handle_multilogon_info },
 	{ GG_XML_ACTION, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event },
 	{ GG_RECV_OWN_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
+	{ GG_USERLIST100_VERSION, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_version), gg_session_handle_userlist_100_version },
+	{ GG_USERLIST100_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_reply), gg_session_handle_userlist_100_reply },
 };
 
 /**
============================================================
--- libpurple/protocols/gg/lib/libgadu-debug.h	e64b05646a3d40a9272eb370df1d2383c3ceb196
+++ libpurple/protocols/gg/lib/libgadu-debug.h	177c3b547283bdcd2152ba2853b5358210c14e13
@@ -22,6 +22,8 @@ const char *gg_debug_state(enum gg_state
 #include "libgadu.h"
 
 const char *gg_debug_state(enum gg_state_t state);
+const char *gg_debug_event(enum gg_event_t event);
 void gg_debug_dump(struct gg_session *sess, int level, const char *buf, size_t len);
+void gg_debug_common(struct gg_session *sess, int level, const char *format, va_list ap);
 
 #endif /* LIBGADU_DEBUG_H */


More information about the Commits mailing list