--- a/libpurple/protocols/gg/lib/dcc7.c Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/dcc7.c Sun Jun 05 01:28:53 2011 +0000
@@ -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@irc.pl>
* Tomasz Chiliński <chilek@chilan.com>
* Adam Wysocki <gophi@ekg.chmurka.net>
* Bartłomiej Zimoń <uzi18@o2.pl>
* Thanks to Jakub Zawadzki <darkjames@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-internal.h"
-#include "libgadu-debug.h"
@@ -45,7 +40,6 @@
@@ -58,8 +52,11 @@
+#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 @@
* \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) + socklen_t sin_len = sizeof(sin); gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen(%p, %d)\n", dcc, port);
@@ -245,45 +245,40 @@
- port = GG_DEFAULT_DCC_PORT;
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(port);
+ sin.sin_family = AF_INET; + sin.sin_addr.s_addr = addr; + 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)))
+ 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);
- gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() no free port found\n");
+ 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);
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to listen (%s)\n", strerror(errno));
- 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;
@@ -297,38 +292,34 @@
+ uint32_t external_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;
- 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) - if (!dcc->sess->external_port || dcc->local_port != local_port)
+ if (dcc->sess->external_port != 0) + external_port = dcc->sess->external_port; external_port = dcc->local_port;
- external_port = dcc->sess->external_port;
- if (!dcc->sess->external_addr || dcc->local_port != local_port)
- dcc->local_addr = dcc->sess->client_addr;
- dcc->local_addr = dcc->sess->external_addr;
+ if (dcc->sess->external_addr != 0) + external_addr = dcc->sess->external_addr; + 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;
- 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 @@
memset(&pkt, 0, sizeof(pkt));
pkt.type = gg_fix32(type);
@@ -649,7 +640,7 @@
if (tmp->state != GG_STATE_REQUESTING_ID || tmp->dcc_type != gg_fix32(p->type))
@@ -708,9 +699,9 @@
e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE;
// 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 @@
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; @@ -809,7 +802,7 @@
gg_send_packet(dcc->sess, GG_DCC7_INFO, payload, len, NULL);
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unhandled transfer type (%d)\n", p->type);
@@ -877,7 +870,7 @@
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() unknown dcc session\n");
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 @@
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() not enough memory\n");
memset(dcc, 0, sizeof(struct gg_dcc7));
dcc->type = GG_SESSION_DCC7_GET;
dcc->dcc_type = GG_DCC7_TYPE_FILE;
@@ -949,7 +942,7 @@
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_packet() not enough memory\n");
memset(dcc, 0, sizeof(struct gg_dcc7));
dcc->type = GG_SESSION_DCC7_VOICE;
@@ -984,7 +977,7 @@
* \internal Ustawia odpowiednie stany wewnętrzne w zależności od rodzaju
* \param dcc Struktura połączenia
* \return 0 jeśli się powiodło, -1 w przypadku błędu.
@@ -1382,6 +1375,9 @@
dcc->check = GG_CHECK_WRITE;
dcc->timeout = GG_DEFAULT_TIMEOUT;
+ e->type = GG_EVENT_DCC7_PENDING; + e->event.dcc7_pending.dcc7 = dcc; --- a/libpurple/protocols/gg/lib/events.c Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/events.c Sun Jun 05 01:28:53 2011 +0000
@@ -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@irc.pl>
@@ -27,22 +27,22 @@
-#include "libgadu-internal.h"
-#include "libgadu-debug.h"
+#include "libgadu-config.h" +#include "libgadu-internal.h" +#include "libgadu-debug.h" @@ -156,7 +156,7 @@
case GG_EVENT_MULTILOGON_INFO:
@@ -168,6 +168,10 @@
+ case GG_EVENT_USERLIST100_REPLY: + free(e->event.userlist100_reply.reply); @@ -258,9 +262,9 @@
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)
+ e->event.failure = GG_FAILURE_CONNECTING; if (res == sess->send_left) {
@@ -299,7 +303,7 @@
/* jeśli jesteśmy w resolverze i mamy ustawiony port
@@ -326,7 +330,7 @@
/* 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));
/* jeśli podano serwer i łączmy się przez proxy,
@@ -357,19 +361,20 @@
/* 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));
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s)\n", res, strerror(res));
+ 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)); 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); + client = gg_urlencode(GG_DEFAULT_CLIENT_VERSION); gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n");
if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port)
@@ -407,13 +412,7 @@
* 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;
sess->state = GG_STATE_READING_DATA;
@@ -439,7 +438,7 @@
/* 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");
/* ignorujemy resztę nagłówka. */
@@ -447,7 +446,10 @@
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"); /* jeśli pierwsza liczba w linii nie jest równa zeru,
@@ -479,6 +481,7 @@
gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf);
@@ -503,10 +506,16 @@
+ if (strcmp(host, "") == 0) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid response\n"); + e->event.failure = GG_FAILURE_HUB; if (!strcmp(host, "notoperating")) {
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n", errno, strerror(errno));
+ e->event.failure = GG_FAILURE_UNAVAILABLE; addr.s_addr = inet_addr(host);
@@ -517,7 +526,8 @@
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));
+ e->event.failure = GG_FAILURE_PROXY; sess->state = GG_STATE_CONNECTING_GG;
@@ -533,7 +543,7 @@
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));
sess->state = GG_STATE_RESOLVING_GG;
@@ -553,7 +563,8 @@
/* 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));
+ e->event.failure = GG_FAILURE_CONNECTING; @@ -585,7 +596,8 @@
+ e->event.failure = GG_FAILURE_RESOLVING; sess->server_addr = addr.s_addr;
@@ -601,7 +613,8 @@
/* 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));
+ e->event.failure = GG_FAILURE_CONNECTING; @@ -628,7 +641,8 @@
* 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));
+ e->event.failure = GG_FAILURE_PROXY; @@ -648,21 +662,25 @@
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res));
+ e->event.failure = GG_FAILURE_CONNECTING; 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)
+ if (sess->port == GG_HTTPS_PORT) { + e->event.failure = GG_FAILURE_CONNECTING; 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));
+ e->event.failure = GG_FAILURE_CONNECTING; sess->state = GG_STATE_CONNECTING_GG;
@@ -698,7 +716,8 @@
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");
+ e->event.failure = GG_FAILURE_PROXY; @@ -706,7 +725,8 @@
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");
+ e->event.failure = GG_FAILURE_PROXY; @@ -714,7 +734,8 @@
if (write(sess->fd, "\r\n", 2) < 2) {
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
+ e->event.failure = GG_FAILURE_PROXY; @@ -904,7 +925,14 @@
- 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 @@
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() gg_recv_packet failed (errno=%d, %s)\n", errno, strerror(errno));
- e->type = GG_EVENT_NONE;
+ if (gg_session_handle_packet(sess, gh->type, (const char *) gh + sizeof(struct gg_header), gh->length, e) == -1) {
- if (gg_session_handle_packet(sess, gh->type, (const char *) gh + sizeof(struct gg_header), gh->length, e) == -1) {
sess->check = GG_CHECK_READ;
- 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;
+ e->event.failure = GG_FAILURE_PROXY; + e->event.failure = GG_FAILURE_HUB; + sess->resolver_cleanup(&sess->resolver, 1); + sess->state = GG_STATE_IDLE; - e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_CONNECTING;
- sess->state = GG_STATE_IDLE;
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_RESOLVING;
- sess->state = GG_STATE_IDLE;
- e->type = GG_EVENT_CONN_FAILED;
- e->event.failure = GG_FAILURE_UNAVAILABLE;
- sess->state = GG_STATE_IDLE;
+ if (e->event.failure != 0) { + e->type = GG_EVENT_CONN_FAILED; --- a/libpurple/protocols/gg/lib/handlers.c Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/handlers.c Sun Jun 05 01:28:53 2011 +0000
@@ -27,11 +27,13 @@
@@ -39,12 +41,14 @@
+#include "libgadu-config.h" #include "libgadu-internal.h"
@@ -87,6 +91,8 @@
+ struct sockaddr_in sin; + unsigned int sin_len = sizeof(sin); if (len < sizeof(struct gg_welcome)) {
ge->type = GG_EVENT_CONN_FAILED;
@@ -145,28 +151,21 @@
- if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) {
- struct sockaddr_in sin;
- unsigned int sin_len = sizeof(sin);
- 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;
- gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
- gs->client_addr = local_ip;
+ 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; + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n"); if (GG_SESSION_IS_PROTOCOL_8_0(gs)) {
- 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");
@@ -180,8 +179,16 @@
l80.image_size = gs->image_size;
+ if (gs->client_version != NULL && !isdigit(gs->client_version[0])) { + 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 @@
&version_len, sizeof(version_len),
- GG8_VERSION, strlen(GG8_VERSION),
+ client_name, client_name_len, version, strlen(version),
&descr_len, sizeof(descr_len),
@@ -198,6 +205,11 @@
+ if (gg_dcc_ip != (unsigned long) inet_addr("255.255.255.255")) + 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 @@
* \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 @@
* \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 @@
* \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 @@
* \internal Analizuje informacje rozszerzone wiadomości.
* \param sess Struktura sesji.
* \param e Struktura zdarzenia.
* \param sender Numer nadawcy.
@@ -756,10 +768,11 @@
* \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 @@
if ((gs->protocol_features & GG_FEATURE_MSG_ACK) == 0)
+ /* Kiedyś zdawało nam się, że mamy wysyłać liczbę odebranych + * wiadomości, ale okazało się, że numer sekwencyjny. */ - 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 @@
options = memchr(payload, 0, (size_t) (payload_end - payload));
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() malformed packet, message out of bounds (0)\n");
length = (size_t) (options - payload);
switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), options + 1, payload_end)) {
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq)); @@ -833,7 +849,7 @@
e->event.msg.message = (unsigned char*) tmp;
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq)); @@ -848,13 +864,13 @@
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)); * \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 @@
switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), packet + offset_attr, packet + length)) {
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq)); @@ -940,7 +956,7 @@
e->event.msg.xhtml_message = NULL;
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq)); @@ -956,13 +972,13 @@
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)); * \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 @@
* \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 @@
* \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 @@
* \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 @@
* \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 @@
* \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 @@
length -= sizeof(struct gg_notify_reply77) + descr_len + 1;
n = (void*) ((char*) n + sizeof(struct gg_notify_reply77) + descr_len + 1);
@@ -1314,7 +1330,7 @@
* \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 @@
ge->event.notify60[i].descr = descr;
length -= sizeof(struct gg_notify_reply60) + descr_len + 1;
n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1);
@@ -1395,7 +1411,7 @@
* \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 @@
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 @@
* \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 @@
* \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 @@
gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() out of memory (%d*%d)\n", count, sizeof(struct gg_multilogon_session));
ge->type = GG_EVENT_MULTILOGON_INFO;
ge->event.multilogon_info.count = count;
ge->event.multilogon_info.sessions = sessions;
@@ -1687,6 +1703,53 @@
+ * \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); + * \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; + 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)); + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_userlist_100_reply() gg_inflate() failed\n"); + 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; * \internal Tablica obsługiwanych pakietów
static const gg_packet_handler_t handlers[] =
@@ -1726,6 +1789,8 @@
{ 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 }, --- a/libpurple/protocols/gg/lib/libgadu.c Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/libgadu.c Sun Jun 05 01:28:53 2011 +0000
@@ -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@irc.pl>
@@ -28,13 +28,7 @@
* \brief Główny moduł biblioteki
-#include "libgadu-config.h"
-#include "libgadu-internal.h"
-#include "libgadu-debug.h"
@@ -50,16 +44,21 @@
+#include "libgadu-config.h" +#include "libgadu-internal.h" +#include "libgadu-debug.h" # include <errno.h> /* on Win32 this is included above */
@@ -75,11 +74,11 @@
# include <openssl/rand.h>
-#define GG_LIBGADU_VERSION "1.10.1"
+#define GG_LIBGADU_VERSION "1.11.0" * Port gniazda nasłuchującego dla połączeń bezpośrednich.
@@ -147,7 +146,7 @@
-= "$Id: libgadu.c 1062 2011-03-13 18:10:24Z wojtekka $";
+= "$Id: libgadu.c 1102 2011-05-05 21:17:57Z wojtekka $"; @@ -290,11 +289,11 @@
int gg_read(struct gg_session *sess, char *buf, int length)
#ifdef GG_CONFIG_HAVE_GNUTLS
res = gnutls_record_recv(GG_SESSION_GNUTLS(sess), buf, length);
@@ -317,7 +316,7 @@
#ifdef GG_CONFIG_HAVE_OPENSSL
res = SSL_read(sess->ssl, buf, length);
@@ -340,7 +339,14 @@
- return read(sess->fd, buf, length);
+ res = read(sess->fd, buf, length); + if (res == -1 && errno == EINTR) @@ -361,11 +367,11 @@
static int gg_write_common(struct gg_session *sess, const char *buf, int length)
#ifdef GG_CONFIG_HAVE_GNUTLS
res = gnutls_record_send(GG_SESSION_GNUTLS(sess), buf, length);
@@ -388,7 +394,7 @@
#ifdef GG_CONFIG_HAVE_OPENSSL
res = SSL_write(sess->ssl, buf, length);
@@ -411,7 +417,14 @@
- return write(sess->fd, buf, length);
+ res = write(sess->fd, buf, length); + if (res == -1 && errno == EINTR) @@ -489,7 +502,7 @@
void *gg_recv_packet(struct gg_session *sess)
unsigned int offset, size = 0;
@@ -542,7 +555,6 @@
sess->header_done += ret;
h.type = gg_fix32(h.type);
@@ -561,26 +573,25 @@
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n");
offset = sess->recv_done;
- 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");
- memcpy(buf, &h, sizeof(h));
+ memcpy(sess->recv_buf, &h, sizeof(h)); - 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); gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n");
if (ret > -1 && ret <= size) {
@@ -590,23 +601,30 @@
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size);
sess->recv_done = offset;
+ packet = sess->recv_buf; 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);
@@ -735,7 +753,10 @@
* 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,
@@ -796,6 +817,7 @@
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 @@
gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n");
// 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 != GG_SSL_DISABLED) { #ifdef GG_CONFIG_HAVE_GNUTLS
gg_session_gnutls_t *tmp;
@@ -912,6 +934,11 @@
gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n");
+ if (p->tls == GG_SSL_REQUIRED) { @@ -1141,6 +1168,7 @@
free(sess->initial_descr);
free(sess->client_version);
#ifdef GG_CONFIG_HAVE_OPENSSL
@@ -1277,8 +1305,10 @@
sess->state = GG_STATE_DISCONNECTING;
+ sess->timeout = GG_TIMEOUT_DISCONNECT; @@ -1436,208 +1466,6 @@
- * \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)
- memcpy(&dst[*pos], src, 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;
- unsigned char old_attr = 0;
- const unsigned char *color = (const unsigned char*) "\x00\x00\x00";
- /* 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)) {
- sprintf(&dst[len], span_fmt, 0, 0, 0);
- /* Pętla przechodzi też przez kończące \0, żeby móc dokleić obrazek
- /* Analizuj atrybuty tak długo jak dotyczą aktualnego znaku. */
- if (format_idx + 3 > format_len)
- attr_pos = format[format_idx] | (format[format_idx + 1] << 8);
- if (attr_pos != char_pos)
- attr = format[format_idx + 2];
- /* Nie doklejaj atrybutów na końcu, co najwyżej obrazki. */
- attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR);
- if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0 || (attr == 0 && old_attr != 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);
- gg_append(dst, &len, "</span>", 7);
- if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) {
- color = &format[format_idx];
- color = (const unsigned char*) "\x00\x00\x00";
- sprintf(&dst[len], span_fmt, color[0], color[1], color[2]);
- } else if (char_pos == 0 && src[0] != 0) {
- sprintf(&dst[len], span_fmt, 0, 0, 0);
- 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)) {
- 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]);
- /* Doklej znak zachowując htmlowe escapowanie. */
- gg_append(dst, &len, "&", 5);
- gg_append(dst, &len, "<", 4);
- gg_append(dst, &len, ">", 4);
- gg_append(dst, &len, "'", 6);
- gg_append(dst, &len, """, 6);
- gg_append(dst, &len, "<br>", 4);
- /* Sprawdź, czy bajt nie jest kontynuacją znaku unikodowego. */
- if ((src[i] & 0xc0) != 0xc0)
- 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);
- gg_append(dst, &len, "</span>", 7);
* Wysyła wiadomość formatowaną w ramach konferencji.
* Zwraca losowy numer sekwencyjny, który można zignorować albo wykorzystać
@@ -1652,7 +1480,7 @@
* \param formatlen Długość informacji o formatowaniu
* \return Numer sekwencyjny wiadomości lub -1 w przypadku błędu.
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 @@
s.seq = gg_fix32(seq_no);
// 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 @@
- 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 @@
- 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 @@
+ * 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; + if (sess->state != GG_STATE_CONNECTED) { + pkt.version = gg_fix32(version); + pkt.format_type = format_type; + 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"); + ret = gg_send_packet(sess, GG_USERLIST100_REQUEST, &pkt, sizeof(pkt), zrequest, zrequest_len, NULL); * Informuje rozmówcę o pisaniu wiadomości.
* \param sess Struktura sesji
@@ -2377,6 +2269,47 @@
+ * Sprawdza czy biblioteka obsługuje daną funkcję. + * \param feature Identyfikator funkcji. + * \return Wartość niezerowa jeśli funkcja jest obsłgiwana. +int gg_libgadu_check_feature(gg_libgadu_feature_t feature) + case GG_LIBGADU_FEATURE_SSL: +#if defined(GG_CONFIG_HAVE_OPENSSL) || defined(GG_CONFIG_HAVE_GNUTLS) + case GG_LIBGADU_FEATURE_PTHREAD: +#ifdef GG_CONFIG_HAVE_PTHREAD + case GG_LIBGADU_FEATURE_USERLIST100: +#ifdef GG_CONFIG_HAVE_ZLIB + /* Celowo nie ma default, żeby kompilator wyłapał brakujące funkcje */ * c-indentation-style: k&r
--- a/libpurple/protocols/gg/lib/libgadu.h Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/libgadu.h Sun Jun 05 01:28:53 2011 +0000
@@ -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@irc.pl>
@@ -57,7 +57,7 @@
#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 @@
#undef GG_CONFIG_HAVE_LONG_LONG
/* Defined if libgadu was compiled and linked with GnuTLS support. */
-# define GG_CONFIG_HAVE_GNUTLS
-# undef GG_CONFIG_HAVE_GNUTLS
+#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 @@
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 @@
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 @@
+ * Flaga połączenia szyfrowanego. + 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 */ * 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 @@
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) */
- uint32_t client_addr; /**< Adres połączeń bezpośrednich (nieaktualne) */
- uint16_t client_port; /**< Port połączeń bezpośrednich (nieaktualne) */
+ 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) */
- int tls; /**< Flaga połączenia szyfrowanego (nieaktualna) */
+ 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 */
int era_omnix; /**< Flaga udawania klienta Era Omnix (nieaktualna) */
@@ -633,6 +639,7 @@
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 @@
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 @@
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 @@
- * 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().
@@ -1028,6 +1057,8 @@
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 @@
@@ -1158,7 +1189,7 @@
* Token autoryzacji niektórych operacji HTTP.
@@ -1257,6 +1288,19 @@
const char *gg_libgadu_version(void);
+ * Lista funkcji biblioteki, które zależą od zewnętrznych bibliotek. + 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 */ +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 @@
* Rodzaj zapytania lub odpowiedzi katalogu publicznego.
@@ -1362,10 +1406,6 @@
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 {
@@ -1427,8 +1467,8 @@
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); char *gg_proxy_auth(void) GG_DEPRECATED;
@@ -1506,7 +1546,7 @@
@@ -2087,6 +2127,67 @@
+#define GG_USERLIST100_PUT 0x00 +#define GG_USERLIST100_GET 0x02 + * \ingroup importexport + * Rodzaj zapytania (10.0). + GG_USERLIST100_PUT, /**< Eksport listy kontaktów. */ + GG_USERLIST100_GET, /**< Import listy kontaktów. */ +#define GG_USERLIST100_FORMAT_TYPE_NONE 0x00 +#define GG_USERLIST100_FORMAT_TYPE_GG70 0x01 +#define GG_USERLIST100_FORMAT_TYPE_GG100 0x02 + * \ingroup importexport + * Typ formatu listy kontaktów (10.0). + 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. */ +#define GG_USERLIST100_REPLY_LIST 0x00 +#define GG_USERLIST100_REPLY_ACK 0x10 +#define GG_USERLIST100_REPLY_REJECT 0x12 + * \ingroup importexport + * Typ odpowiedzi listy kontaktów (10.0). + 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. */ struct gg_dcc_tiny_packet {
uint8_t type; /* rodzaj pakietu */
--- a/libpurple/protocols/gg/lib/pubdir.c Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/pubdir.c Sun Jun 05 01:28:53 2011 +0000
@@ -26,9 +26,6 @@
* \brief Obsługa katalogu publicznego
-#include "libgadu-config.h"
@@ -37,6 +34,9 @@
+#include "libgadu-config.h" * Rejestruje nowego użytkownika.
@@ -122,10 +122,10 @@
h->callback = gg_pubdir_watch_fd;
h->destroy = gg_pubdir_free;
@@ -193,7 +193,7 @@
__pwd = gg_saprintf("%ld", random());
__fmpwd = gg_urlencode(password);
__tokenid = gg_urlencode(tokenid);
@@ -251,10 +251,10 @@
h->callback = gg_pubdir_watch_fd;
h->destroy = gg_pubdir_free;
@@ -324,7 +324,7 @@
__fmpwd = gg_urlencode(passwd);
__pwd = gg_urlencode(newpasswd);
__email = gg_urlencode(email);
@@ -340,7 +340,7 @@
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");
@@ -351,13 +351,13 @@
gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form);
@@ -460,7 +460,7 @@
__tokenid = gg_urlencode(tokenid);
__tokenval = gg_urlencode(tokenval);
__email = gg_urlencode(email);
@@ -484,7 +484,7 @@
gg_debug(GG_DEBUG_MISC, "=> remind, %s\n", form);
@@ -588,7 +588,7 @@
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 @@
if (h->state != GG_STATE_PARSING)
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");
@@ -609,7 +609,7 @@
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 @@
@@ -674,10 +674,10 @@
h->callback = gg_token_watch_fd;
h->destroy = gg_token_free;
@@ -706,7 +706,7 @@
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 @@
if (h->state != GG_STATE_PARSING)
/* 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 @@
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");
@@ -743,7 +743,7 @@
/* dostaliśmy tokenid i wszystkie niezbędne informacje,
* więc pobierzmy obrazek z tokenem */
@@ -779,7 +779,7 @@
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 @@
h->callback = gg_token_watch_fd;
h->destroy = gg_token_free;
@@ -821,7 +821,7 @@
/* obrazek mamy w h->body */
h->state = GG_STATE_DONE;
@@ -841,7 +841,7 @@
--- a/libpurple/protocols/gg/lib/pubdir50.c Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/pubdir50.c Sun Jun 05 01:28:53 2011 +0000
@@ -31,6 +31,7 @@
+#include "libgadu-config.h" #include "libgadu-internal.h"
@@ -94,7 +95,7 @@
if (!(dupfield = strdup(field))) {
gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
@@ -149,7 +150,7 @@
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);
gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_seq_set() invalid arguments\n");
@@ -174,7 +175,7 @@
for (i = 0; i < s->entries_count; i++) {
free(s->entries[i].field);
free(s->entries[i].value);
@@ -202,7 +203,7 @@
struct gg_pubdir50_request *r;
gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req);
gg_debug_session(sess, GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n");
@@ -219,7 +220,7 @@
/* wyszukiwanie bierze tylko pierwszy wpis */
if (sess->encoding == GG_ENCODING_CP1250) {
size += strlen(req->entries[i].field) + 1;
size += strlen(req->entries[i].value) + 1;
@@ -327,7 +328,7 @@
struct gg_pubdir50_reply *r = (struct gg_pubdir50_reply*) packet;
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 @@
for (p = field; p < end; p++) {
/* jeśli mamy koniec tekstu... */
@@ -399,7 +400,7 @@
/* sprawdźmy, czy pole nie wychodzi poza pakiet, żeby nie
* mieć segfaultów, jeśli serwer przestanie zakańczać pakietów
@@ -436,10 +437,10 @@
--- a/libpurple/protocols/gg/lib/resolver.c Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/resolver.c Sun Jun 05 01:28:53 2011 +0000
@@ -29,17 +29,19 @@
+#include "libgadu-config.h" @@ -212,7 +214,6 @@
if (result == NULL || count == NULL) {
@@ -256,7 +257,7 @@
* \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;
@@ -595,7 +596,7 @@
* 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 @@
+#if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) type = GG_RESOLVER_WIN32;
-#if defined(GG_CONFIG_HAVE_PTHREAD) || defined(GG_CONFIG_PTHREAD_DEFAULT)
type = GG_RESOLVER_PTHREAD;
@@ -936,7 +937,7 @@
* - \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 @@
+#if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) type = GG_RESOLVER_WIN32;
-#if defined(GG_CONFIG_HAVE_PTHREAD) || defined(GG_CONFIG_PTHREAD_DEFAULT)
type = GG_RESOLVER_PTHREAD;
@@ -1082,20 +1083,18 @@
gg_global_resolver_cleanup = NULL;
- gg_global_resolver_type = type;
- gg_global_resolver_start = gg_resolver_fork_start;
- gg_global_resolver_cleanup = gg_resolver_fork_cleanup;
gg_global_resolver_type = type;
gg_global_resolver_start = gg_resolve_win32thread;
gg_global_resolver_cleanup = gg_resolve_win32thread_cleanup;
+ gg_global_resolver_type = type; + gg_global_resolver_start = gg_resolver_fork_start; + gg_global_resolver_cleanup = gg_resolver_fork_cleanup; #ifdef GG_CONFIG_HAVE_PTHREAD