summaryrefslogtreecommitdiff
path: root/protocols/Gadu-Gadu/src
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Gadu-Gadu/src')
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/common.cpp1
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/dcc.cpp1
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/dcc7.cpp74
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/debug.cpp70
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/debug.h2
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/deflate.cpp226
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/deflate.h29
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/encoding.cpp38
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/events.cpp162
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/handlers.cpp103
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/http.cpp9
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/internal.h1
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/libgadu.cpp356
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/libgadu.h143
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/message.cpp10
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/obsolete.cpp1
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/protocol.h28
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/resolver.cpp30
18 files changed, 877 insertions, 407 deletions
diff --git a/protocols/Gadu-Gadu/src/libgadu/common.cpp b/protocols/Gadu-Gadu/src/libgadu/common.cpp
index 07e6a2646b..3ca168abee 100644
--- a/protocols/Gadu-Gadu/src/libgadu/common.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/common.cpp
@@ -293,6 +293,7 @@ SOCKET gg_connect(void *addr, int port, int async)
}
}
+ memset(&sin, 0, sizeof(sin));
sin.sin_port = htons((uint16_t)port);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = a->s_addr;
diff --git a/protocols/Gadu-Gadu/src/libgadu/dcc.cpp b/protocols/Gadu-Gadu/src/libgadu/dcc.cpp
index 5c89476efc..3e65559964 100644
--- a/protocols/Gadu-Gadu/src/libgadu/dcc.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/dcc.cpp
@@ -442,6 +442,7 @@ struct gg_dcc *gg_dcc_socket_create(uin_t uin, uint16_t port)
port = GG_DEFAULT_DCC_PORT;
while (!bound) {
+ memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
diff --git a/protocols/Gadu-Gadu/src/libgadu/dcc7.cpp b/protocols/Gadu-Gadu/src/libgadu/dcc7.cpp
index 465a3cae4a..b9f6ef2faa 100644
--- a/protocols/Gadu-Gadu/src/libgadu/dcc7.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/dcc7.cpp
@@ -154,7 +154,7 @@ static struct gg_dcc7 *gg_dcc7_session_find(struct gg_session *sess, gg_dcc7_id_
for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) {
if (empty) {
- if (tmp->peer_uin == uin && !tmp->state == GG_STATE_WAITING_FOR_ACCEPT)
+ if (tmp->peer_uin == uin && tmp->state == GG_STATE_WAITING_FOR_ACCEPT)
return tmp;
} else {
if (!memcmp(&tmp->cid, &id, sizeof(id)))
@@ -228,11 +228,12 @@ static int gg_dcc7_connect(struct gg_dcc7 *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;
int sin_len = sizeof(sin);
@@ -252,12 +253,13 @@ static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint16_t port)
return -1;
}
+ memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_addr.s_addr = addr;
sin.sin_port = htons(port);
if (bind(fd, (struct sockaddr*) &sin, sizeof(sin)) == -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 bind to %s:%d\n", inet_ntoa(sin.sin_addr), port);
goto fail;
}
@@ -272,6 +274,7 @@ static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint16_t port)
}
dcc->fd = fd;
+ dcc->local_addr = sin.sin_addr.s_addr;
dcc->local_port = ntohs(sin.sin_port);
dcc->state = GG_STATE_LISTENING;
@@ -298,39 +301,36 @@ static int gg_dcc7_listen_and_send_info(struct gg_dcc7 *dcc)
{
struct gg_dcc7_info pkt;
uint16_t external_port;
- uint16_t local_port;
- uint32_t count;
+ 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 == NULL)
return -1;
- 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)
- external_port = dcc->local_port;
- else
+ if (dcc->sess->external_port != 0)
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;
+ external_port = dcc->local_port;
+
+ if (dcc->sess->external_addr != 0)
+ external_addr = dcc->sess->external_addr;
+ else
+ external_addr = dcc->local_addr;
+
+ 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(*((struct in_addr*) &dcc->local_addr)), external_port);
+ 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);
- snprintf((char*) pkt.hash, sizeof(pkt.hash), "%u", dcc->local_addr + external_port * rand());
+ 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);
}
@@ -446,7 +446,7 @@ static struct gg_dcc7 *gg_dcc7_send_file_common(struct gg_session *sess, uin_t r
dcc->size = (unsigned int)size;
dcc->seek = seek;
- strncpy((char*) dcc->filename, filename1250, GG_DCC7_FILENAME_LEN - 1);
+ strncpy((char*) dcc->filename, filename1250, GG_DCC7_FILENAME_LEN);
dcc->filename[GG_DCC7_FILENAME_LEN] = 0;
memcpy(dcc->hash, hash, GG_DCC7_HASH_LEN);
@@ -699,7 +699,9 @@ int gg_dcc7_handle_id(struct gg_session *sess, struct gg_event *e, const void *p
s.uin_to = gg_fix32(tmp->peer_uin);
s.size = gg_fix32(tmp->size);
- strncpy((char*) s.filename, (char*) tmp->filename, GG_DCC7_FILENAME_LEN);
+ /* Uwaga: To nie jest ciąg kończony zerem.
+ * Note: This is not a null-terminated string. */
+ strncpy((char*) s.filename, (char*) tmp->filename, sizeof(s.filename));
tmp->state = GG_STATE_WAITING_FOR_ACCEPT;
tmp->timeout = GG_DCC7_TIMEOUT_FILE_ACK;
@@ -805,6 +807,8 @@ int gg_dcc7_handle_info(struct gg_session *sess, struct gg_event *e, const void
if (dcc->state == GG_STATE_WAITING_FOR_INFO) {
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;
}
@@ -1025,7 +1029,7 @@ int gg_dcc7_handle_new(struct gg_session *sess, struct gg_event *e, const void *
}
dcc->size = gg_fix32(p->size);
- strncpy((char*) dcc->filename, (char*) p->filename, GG_DCC7_FILENAME_LEN - 1);
+ strncpy((char*) dcc->filename, (char*) p->filename, GG_DCC7_FILENAME_LEN);
dcc->filename[GG_DCC7_FILENAME_LEN] = 0;
memcpy(dcc->hash, p->hash, GG_DCC7_HASH_LEN);
@@ -1489,6 +1493,9 @@ struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *dcc)
dcc->check = GG_CHECK_WRITE;
dcc->timeout = GG_DEFAULT_TIMEOUT;
+ e->type = GG_EVENT_DCC7_PENDING;
+ e->event.dcc7_pending.dcc7 = dcc;
+
return e;
}
@@ -1538,6 +1545,7 @@ struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *dcc)
char buf[256];
struct gg_dcc7_relay_reply *pkt;
struct gg_dcc7_relay_reply_server srv;
+ size_t max_relay_count = (sizeof(buf) - sizeof(*pkt)) / sizeof(srv);
int res;
int i;
@@ -1555,7 +1563,7 @@ struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *dcc)
pkt = (struct gg_dcc7_relay_reply*) buf;
- if (gg_fix32(pkt->magic) != GG_DCC7_RELAY_REPLY || gg_fix32(pkt->rcount) < 1 || gg_fix32(pkt->rcount > 256) || gg_fix32(pkt->len) < sizeof(*pkt) + gg_fix32(pkt->rcount) * sizeof(srv)) {
+ if (gg_fix32(pkt->magic) != GG_DCC7_RELAY_REPLY || gg_fix32(pkt->rcount) < 1 || gg_fix32(pkt->rcount) > 256 || gg_fix32(pkt->len) < sizeof(*pkt) + gg_fix32(pkt->rcount) * sizeof(srv)) {
gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_wathc_fd() invalid reply\n");
errno = EINVAL;
e->type = GG_EVENT_DCC7_ERROR;
@@ -1571,6 +1579,18 @@ struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *dcc)
dcc->relay_index = 0;
dcc->relay_count = gg_fix32(pkt->rcount);
+
+ if (dcc->relay_count > 0xffff ||
+ (size_t)dcc->relay_count > max_relay_count)
+ {
+ gg_debug_dcc(dcc, GG_DEBUG_MISC,
+ "// gg_dcc7_watch_fd() relay_count out "
+ "of bounds (%d)\n", dcc->relay_count);
+ dcc->relay_count = 0;
+ free(e);
+ return NULL;
+ }
+
dcc->relay_list = (gg_dcc7_relay*)malloc(dcc->relay_count * sizeof(gg_dcc7_relay_t));
if (dcc->relay_list == NULL) {
diff --git a/protocols/Gadu-Gadu/src/libgadu/debug.cpp b/protocols/Gadu-Gadu/src/libgadu/debug.cpp
index 5b7c0c6577..fcadfe3ed1 100644
--- a/protocols/Gadu-Gadu/src/libgadu/debug.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/debug.cpp
@@ -268,8 +268,74 @@ const char *gg_debug_state(enum gg_state_t 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 */
}
@@ -294,7 +360,7 @@ void gg_debug_session(struct gg_session *gs, int level, const char *format, ...)
}
#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)
{
}
diff --git a/protocols/Gadu-Gadu/src/libgadu/debug.h b/protocols/Gadu-Gadu/src/libgadu/debug.h
index 8c51853b3e..917705eef9 100644
--- a/protocols/Gadu-Gadu/src/libgadu/debug.h
+++ b/protocols/Gadu-Gadu/src/libgadu/debug.h
@@ -22,6 +22,8 @@
#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 */
diff --git a/protocols/Gadu-Gadu/src/libgadu/deflate.cpp b/protocols/Gadu-Gadu/src/libgadu/deflate.cpp
new file mode 100644
index 0000000000..46f36f1e69
--- /dev/null
+++ b/protocols/Gadu-Gadu/src/libgadu/deflate.cpp
@@ -0,0 +1,226 @@
+/* $Id$ */
+
+/*
+ * (C) Copyright 2011 Bartosz Brachaczek <b.brachaczek@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License Version
+ * 2.1 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/**
+ * \file deflate.c
+ *
+ * \brief Funkcje kompresji Deflate
+ */
+
+#ifndef _WIN64
+#define _USE_32BIT_TIME_T
+#endif
+
+#ifdef _WIN32
+#include "win32.h"
+#endif /* _WIN32 */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "libgadu.h"
+#include "deflate.h"
+
+#ifdef GG_CONFIG_HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+/**
+ * \internal Kompresuje dane wejściowe algorytmem Deflate z najwyższym
+ * stopniem kompresji, tak samo jak oryginalny klient.
+ *
+ * Wynik funkcji należy zwolnić za pomocą \c free.
+ *
+ * \param in Ciąg znaków do skompresowania, zakończony \c \\0
+ * \param out_lenp Wskaźnik na zmienną, do której zostanie zapisana
+ * długość bufora wynikowego
+ *
+ * \return Skompresowany ciąg znaków lub \c NULL w przypadku niepowodzenia.
+ */
+unsigned char *gg_deflate(const char *in, size_t *out_lenp)
+{
+#ifdef GG_CONFIG_HAVE_ZLIB
+ int ret;
+ z_stream strm;
+ unsigned char *out, *out2;
+ size_t out_len;
+
+ if (in == NULL || out_lenp == NULL)
+ return NULL;
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = strlen(in);
+ strm.next_in = (unsigned char*) in;
+
+ ret = deflateInit(&strm, Z_BEST_COMPRESSION);
+ if (ret != Z_OK) {
+ gg_debug(GG_DEBUG_MISC, "// gg_deflate() deflateInit() failed (%d)\n", ret);
+ return NULL;
+ }
+
+ out_len = deflateBound(&strm, strm.avail_in);
+ out = (unsigned char*)malloc(out_len);
+
+ if (out == NULL) {
+ gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len);
+ goto fail;
+ }
+
+ strm.avail_out = out_len;
+ strm.next_out = out;
+
+ for (;;) {
+ ret = deflate(&strm, Z_FINISH);
+
+ if (ret == Z_STREAM_END)
+ break;
+
+ /* raczej nie powinno się zdarzyć przy Z_FINISH i out_len == deflateBound(),
+ * ale dokumentacja zlib nie wyklucza takiej możliwości */
+ if (ret == Z_OK) {
+ out_len *= 2;
+ out2 = (unsigned char*)realloc(out, out_len);
+
+ if (out2 == NULL) {
+ gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len);
+ goto fail;
+ }
+
+ out = out2;
+
+ strm.avail_out = out_len / 2;
+ strm.next_out = out + out_len / 2;
+ } else {
+ gg_debug(GG_DEBUG_MISC, "// gg_deflate() deflate() failed (ret=%d, msg=%s)\n", ret, strm.msg != NULL ? strm.msg : "no error message provided");
+ goto fail;
+ }
+ }
+
+ out_len = strm.total_out;
+ out2 = (unsigned char*)realloc(out, out_len);
+
+ if (out2 == NULL) {
+ gg_debug(GG_DEBUG_MISC, "// gg_deflate() not enough memory for output data (%d)\n", out_len);
+ goto fail;
+ }
+
+ *out_lenp = out_len;
+ deflateEnd(&strm);
+
+ return out2;
+
+fail:
+ *out_lenp = 0;
+ deflateEnd(&strm);
+ free(out);
+#endif
+ return NULL;
+}
+
+/**
+ * \internal Dekompresuje dane wejściowe w formacie Deflate.
+ *
+ * Wynik funkcji należy zwolnić za pomocą \c free.
+ *
+ * \param in Bufor danych skompresowanych algorytmem Deflate
+ * \param length Długość bufora wejściowego
+ *
+ * \note Dokleja \c \\0 na końcu bufora wynikowego.
+ *
+ * \return Zdekompresowany ciąg znaków, zakończony \c \\0,
+ * lub \c NULL w przypadku niepowodzenia.
+ */
+char *gg_inflate(const unsigned char *in, size_t length)
+{
+#ifdef GG_CONFIG_HAVE_ZLIB
+ int ret;
+ z_stream strm;
+ char *out = NULL, *out2;
+ size_t out_len = 1024;
+ int first = 1;
+
+ if (in == NULL)
+ return NULL;
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = length;
+ strm.next_in = (unsigned char*) in;
+
+ ret = inflateInit(&strm);
+ if (ret != Z_OK) {
+ gg_debug(GG_DEBUG_MISC, "// gg_inflate() inflateInit() failed (%d)\n", ret);
+ return NULL;
+ }
+
+ do {
+ out_len *= 2;
+ out2 = (char*)realloc(out, out_len);
+
+ if (out2 == NULL) {
+ gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough memory for output data (%d)\n", out_len);
+ goto fail;
+ }
+
+ out = out2;
+
+ if (first) {
+ strm.avail_out = out_len;
+ strm.next_out = (unsigned char*) out;
+ } else {
+ strm.avail_out = out_len / 2;
+ strm.next_out = (unsigned char*) out + out_len / 2;
+ }
+
+ ret = inflate(&strm, Z_NO_FLUSH);
+
+ if (ret != Z_OK && ret != Z_STREAM_END) {
+ gg_debug(GG_DEBUG_MISC, "// gg_inflate() inflate() failed (ret=%d, msg=%s)\n", ret, strm.msg != NULL ? strm.msg : "no error message provided");
+ goto fail;
+ }
+
+ first = 0;
+ } while (ret != Z_STREAM_END);
+
+ /* rezerwujemy ostatni znak na NULL-a */
+ out_len = strm.total_out + 1;
+ out2 = (char*)realloc(out, out_len);
+
+ if (out2 == NULL) {
+ gg_debug(GG_DEBUG_MISC, "// gg_inflate() not enough memory for output data (%d)\n", out_len);
+ goto fail;
+ }
+
+ out = out2;
+ out[out_len - 1] = '\0';
+
+ inflateEnd(&strm);
+
+ return out;
+
+fail:
+ inflateEnd(&strm);
+ free(out);
+#endif
+ return NULL;
+}
diff --git a/protocols/Gadu-Gadu/src/libgadu/deflate.h b/protocols/Gadu-Gadu/src/libgadu/deflate.h
new file mode 100644
index 0000000000..9e2f78053e
--- /dev/null
+++ b/protocols/Gadu-Gadu/src/libgadu/deflate.h
@@ -0,0 +1,29 @@
+/* $Id$ */
+
+/*
+ * (C) Copyright 2011 Bartosz Brachaczek <b.brachaczek@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License Version
+ * 2.1 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef LIBGADU_DEFLATE_H
+#define LIBGADU_DEFLATE_H
+
+#include "libgadu.h"
+
+unsigned char *gg_deflate(const char *in, size_t *out_lenp);
+char *gg_inflate(const unsigned char *in, size_t length);
+
+#endif /* LIBGADU_DEFLATE_H */
diff --git a/protocols/Gadu-Gadu/src/libgadu/encoding.cpp b/protocols/Gadu-Gadu/src/libgadu/encoding.cpp
index fa6af7eb6d..3d157573d1 100644
--- a/protocols/Gadu-Gadu/src/libgadu/encoding.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/encoding.cpp
@@ -26,6 +26,7 @@
#include <errno.h>
#include "libgadu.h"
+#include "encoding.h"
/**
* \file encoding.c
@@ -38,22 +39,22 @@
*/
static const uint16_t table_cp1250[] =
{
- 0x20ac, '?', 0x201a, '?', 0x201e, 0x2026, 0x2020, 0x2021,
- '?', 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
- '?', 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
- '?', 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
- 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
- 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
- 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
- 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
- 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
- 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
- 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
- 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
- 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
- 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
- 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
- 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
+ 0x20ac, '?', 0x201a, '?', 0x201e, 0x2026, 0x2020, 0x2021,
+ '?', 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
+ '?', 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
+ '?', 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
+ 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
+ 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
+ 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
+ 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
+ 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
+ 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
+ 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
+ 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
+ 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
+ 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
};
/**
@@ -139,11 +140,8 @@ static char *gg_encoding_convert_utf8_cp1250(const char *src, int src_length, in
uint32_t uc = 0, uc_min = 0;
for (i = 0, len = 0; (src[i] != 0) && (i < src_length); i++) {
- if ((src[i] & 0xc0) == 0xc0) {
+ if ((src[i] & 0xc0) != 0x80)
len++;
- } else if ((src[i] & 0x80) == 0x00) {
- len++;
- }
}
if ((dst_length != -1) && (len > dst_length))
diff --git a/protocols/Gadu-Gadu/src/libgadu/events.cpp b/protocols/Gadu-Gadu/src/libgadu/events.cpp
index 9cfd036730..2374ade04c 100644
--- a/protocols/Gadu-Gadu/src/libgadu/events.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/events.cpp
@@ -178,6 +178,10 @@ void gg_event_free(struct gg_event *e)
break;
}
+
+ case GG_EVENT_USERLIST100_REPLY:
+ free(e->event.userlist100_reply.reply);
+ break;
}
free(e);
@@ -268,9 +272,9 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
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) {
@@ -309,7 +313,7 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
if (failed) {
errno = errno2;
- goto fail_resolving;
+ goto fail_proxy_hub;
}
/* jeśli jesteśmy w resolverze i mamy ustawiony port
@@ -336,7 +340,7 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
/* 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,
@@ -367,12 +371,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
/* jeśli asynchroniczne, sprawdzamy, czy nie wystąpił
* przypadkiem jakiś błąd. */
if (sess->async && (gg_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");
@@ -384,7 +384,7 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
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)
@@ -431,13 +431,7 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
* stało się coś złego. */
if (gg_sock_write(sess->fd, buf, (int)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;
- gg_sock_close(sess->fd);
- sess->fd = -1;
- break;
+ goto fail_proxy_hub;
}
sess->state = GG_STATE_READING_DATA;
@@ -463,7 +457,7 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
/* 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. */
@@ -471,7 +465,10 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
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,
@@ -503,6 +500,7 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
}
gg_sock_close(sess->fd);
+ sess->fd = -1;
gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf);
@@ -527,10 +525,16 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
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);
@@ -541,7 +545,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
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;
@@ -557,7 +562,7 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
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;
@@ -577,7 +582,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
/* 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;
}
}
@@ -609,7 +615,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
if (failed) {
errno = errno2;
- goto fail_resolving;
+ e->event.failure = GG_FAILURE_RESOLVING;
+ goto fail;
}
sess->server_addr = addr.s_addr;
@@ -625,7 +632,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
/* 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;
}
}
@@ -652,7 +660,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
* 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;
}
gg_sock_close(sess->fd);
@@ -672,21 +681,25 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
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;
@@ -722,7 +735,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
if (gg_sock_write(sess->fd, buf, (int)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) {
@@ -730,7 +744,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
if (gg_sock_write(sess->fd, auth, (int)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);
@@ -738,7 +753,8 @@ struct gg_event *gg_watch_fd(struct gg_session *sess)
if (gg_sock_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;
}
}
@@ -850,14 +866,14 @@ gnutls_handshake_repeat:
const gnutls_datum_t *peers;
gnutls_x509_crt_t cert;
- if (gnutls_x509_crt_init(&cert) >= 0) {
+ if (gnutls_x509_crt_init(&cert) == 0) {
peers = gnutls_certificate_get_peers(GG_SESSION_GNUTLS(sess), &peer_count);
if (peers != NULL) {
char buf[256];
size_t size;
- if (gnutls_x509_crt_import(cert, &peers[0], GNUTLS_X509_FMT_DER) >= 0) {
+ if (gnutls_x509_crt_import(cert, &peers[0], GNUTLS_X509_FMT_DER) == 0) {
size = sizeof(buf);
gnutls_x509_crt_get_dn(cert, buf, &size);
gg_debug_session(sess, GG_DEBUG_MISC, "// cert subject: %s\n", buf);
@@ -866,6 +882,8 @@ gnutls_handshake_repeat:
gg_debug_session(sess, GG_DEBUG_MISC, "// cert issuer: %s\n", buf);
}
}
+
+ gnutls_x509_crt_deinit(cert);
}
}
@@ -999,23 +1017,17 @@ 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 (gg_session_handle_packet(sess, gh->type, (const char *) gh + sizeof(struct gg_header), gh->length, e) == -1) {
- free(gh);
- 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;
+ }
free(gh);
+ }
sess->check = GG_CHECK_READ;
@@ -1023,40 +1035,38 @@ gnutls_handshake_repeat:
}
}
-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;
gg_sock_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;
+ }
}
/*
diff --git a/protocols/Gadu-Gadu/src/libgadu/handlers.cpp b/protocols/Gadu-Gadu/src/libgadu/handlers.cpp
index da09c40b5f..3c0018c8c6 100644
--- a/protocols/Gadu-Gadu/src/libgadu/handlers.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/handlers.cpp
@@ -51,6 +51,7 @@
#include "encoding.h"
#include "message.h"
#include "internal.h"
+#include "deflate.h"
#include <errno.h>
#ifndef _WIN32
@@ -97,6 +98,8 @@ static int gg_session_handle_welcome(struct gg_session *gs, uint32_t type, const
int ret;
uint8_t hash_buf[64];
uint32_t local_ip;
+ struct sockaddr_in sin;
+ int sin_len = sizeof(sin);
if (len < sizeof(struct gg_welcome)) {
ge->type = GG_EVENT_CONN_FAILED;
@@ -155,29 +158,22 @@ static int gg_session_handle_welcome(struct gg_session *gs, uint32_t type, const
}
#endif
- if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) {
- struct sockaddr_in sin;
- 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;
- } 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 (!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;
+ }
if (GG_SESSION_IS_PROTOCOL_8_0(gs)) {
struct gg_login80 l80;
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);
@@ -216,6 +212,11 @@ static int gg_session_handle_welcome(struct gg_session *gs, uint32_t type, const
} 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;
@@ -777,7 +778,7 @@ malformed:
*
* \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;
@@ -786,8 +787,11 @@ static int gg_session_send_msg_ack(struct gg_session *gs)
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);
}
@@ -829,7 +833,7 @@ static int gg_session_handle_recv_msg(struct gg_session *sess, uint32_t type, co
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
@@ -851,7 +855,7 @@ static int gg_session_handle_recv_msg(struct gg_session *sess, uint32_t type, co
goto fail;
e->event.msg.message = tmp;
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq));
return 0;
fail:
@@ -866,7 +870,7 @@ 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;
}
@@ -924,7 +928,7 @@ static int gg_session_handle_recv_msg_80(struct gg_session *sess, uint32_t type,
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
@@ -958,7 +962,7 @@ static int gg_session_handle_recv_msg_80(struct gg_session *sess, uint32_t type,
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:
@@ -974,7 +978,7 @@ 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;
}
@@ -1705,6 +1709,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[] =
@@ -1744,6 +1795,8 @@ static const gg_packet_handler_t handlers[] =
{ 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 },
};
/**
diff --git a/protocols/Gadu-Gadu/src/libgadu/http.cpp b/protocols/Gadu-Gadu/src/libgadu/http.cpp
index 5b8549dc3b..b6e4b8a7fc 100644
--- a/protocols/Gadu-Gadu/src/libgadu/http.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/http.cpp
@@ -1,4 +1,4 @@
-/* $Id: http.c 11370 2010-03-13 16:17:54Z dezred $ */
+/* $Id$ */
/*
* (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
@@ -51,6 +51,8 @@
#include <unistd.h>
#endif /* _WIN32 */
+#define GG_HTTP_MAX_LENGTH 1000000000
+
/**
* Rozpoczyna połączenie HTTP.
*
@@ -368,6 +370,11 @@ int gg_http_watch_fd(struct gg_http *h)
h->body_size = left;
}
+ if (h->body_size > GG_HTTP_MAX_LENGTH) {
+ gg_debug(GG_DEBUG_MISC, "=> http, content-length too big\n");
+ h->body_size = GG_HTTP_MAX_LENGTH;
+ }
+
if (left > h->body_size) {
gg_debug(GG_DEBUG_MISC, "=> http, oversized reply (%d bytes needed, %d bytes left)\n", h->body_size, left);
h->body_size = left;
diff --git a/protocols/Gadu-Gadu/src/libgadu/internal.h b/protocols/Gadu-Gadu/src/libgadu/internal.h
index ba9655288a..7818cf7f31 100644
--- a/protocols/Gadu-Gadu/src/libgadu/internal.h
+++ b/protocols/Gadu-Gadu/src/libgadu/internal.h
@@ -22,6 +22,7 @@
#define LIBGADU_INTERNAL_H
#include "libgadu.h"
+// #include "config.h"
struct gg_dcc7_relay {
uint32_t addr;
diff --git a/protocols/Gadu-Gadu/src/libgadu/libgadu.cpp b/protocols/Gadu-Gadu/src/libgadu/libgadu.cpp
index be9c2499b6..edfc7fd034 100644
--- a/protocols/Gadu-Gadu/src/libgadu/libgadu.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/libgadu.cpp
@@ -52,6 +52,8 @@
#include "encoding.h"
#include "debug.h"
#include "session.h"
+#include "message.h"
+#include "deflate.h"
#include <errno.h>
#ifndef _WIN32
@@ -461,11 +463,11 @@ int gg_write(struct gg_session *sess, const char *buf, int length)
res = written;
}
} else {
- res = 0;
-
if (sess->send_buf == NULL) {
res = gg_write_common(sess, buf, length);
+ if (res == -1 && errno == EAGAIN)
+ res = 0;
if (res == -1)
return -1;
}
@@ -529,7 +531,7 @@ void *gg_recv_packet(struct gg_session *sess)
while (sess->header_done < sizeof(h)) {
ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done);
- gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret);
+ gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, (char*) &h + sess->header_done, sizeof(h) - sess->header_done, ret);
if (!ret) {
errno = ECONNRESET;
@@ -759,6 +761,9 @@ static int gg_session_callback(struct gg_session *sess)
* \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().
*
+ * \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.
*
@@ -822,6 +827,7 @@ struct gg_session *gg_login(const struct gg_login_params *p)
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) {
@@ -884,7 +890,7 @@ struct gg_session *gg_login(const struct gg_login_params *p)
#ifdef GG_CONFIG_MIRANDA
sess->tls = p->tls;
#endif
- if (p->tls == 1) {
+ if (p->tls != GG_SSL_DISABLED) {
#ifdef GG_CONFIG_HAVE_GNUTLS
gg_session_gnutls_t *tmp;
@@ -900,8 +906,7 @@ struct gg_session *gg_login(const struct gg_login_params *p)
gnutls_global_init();
gnutls_certificate_allocate_credentials(&tmp->xcred);
gnutls_init(&tmp->session, GNUTLS_CLIENT);
- gnutls_priority_set_direct(tmp->session, "NORMAL:-VERS-TLS", NULL);
-// gnutls_priority_set_direct(tmp->session, "NONE:+VERS-SSL3.0:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL", NULL);
+ gnutls_set_default_priority(tmp->session);
gnutls_credentials_set(tmp->session, GNUTLS_CRD_CERTIFICATE, tmp->xcred);
#elif defined(GG_CONFIG_HAVE_OPENSSL)
char buf[1024];
@@ -941,6 +946,11 @@ struct gg_session *gg_login(const struct gg_login_params *p)
}
#elif !defined(GG_CONFIG_MIRANDA)
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
}
@@ -1142,18 +1152,6 @@ void gg_logoff(struct gg_session *sess)
sess->fd = -1;
}
-#ifdef GG_CONFIG_HAVE_GNUTLS
- if (sess->ssl != NULL) {
- gg_session_gnutls_t *tmp;
-
- tmp = (gg_session_gnutls_t*) sess->ssl;
- gnutls_deinit(tmp->session);
- gnutls_certificate_free_credentials(tmp->xcred);
- gnutls_global_deinit();
- free(sess->ssl);
- }
-#endif
-
if (sess->send_buf) {
free(sess->send_buf);
sess->send_buf = NULL;
@@ -1188,6 +1186,16 @@ void gg_free_session(struct gg_session *sess)
#ifdef GG_CONFIG_MIRANDA
if (sess->ssl != NULL)
sslApi.sfree(sess->ssl);
+#elif GG_CONFIG_HAVE_GNUTLS
+ if (sess->ssl != NULL) {
+ gg_session_gnutls_t *tmp;
+
+ tmp = (gg_session_gnutls_t*) sess->ssl;
+ gnutls_deinit(tmp->session);
+ gnutls_certificate_free_credentials(tmp->xcred);
+ gnutls_global_deinit();
+ free(sess->ssl);
+ }
#elif GG_CONFIG_HAVE_OPENSSL
if (sess->ssl != NULL)
SSL_free(sess->ssl);
@@ -1483,209 +1491,6 @@ int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients
}
/**
- * \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;
- const unsigned char *format_ = (const unsigned char*) format;
-
- 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 = (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, "&amp;", 5);
- break;
- case '<':
- gg_append(dst, &len, "&lt;", 4);
- break;
- case '>':
- gg_append(dst, &len, "&gt;", 4);
- break;
- case '\'':
- gg_append(dst, &len, "&apos;", 6);
- break;
- case '\"':
- gg_append(dst, &len, "&quot;", 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ć
@@ -1773,7 +1578,7 @@ int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int r
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 = (char*)malloc(len + 1);
@@ -1782,7 +1587,7 @@ int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int r
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);
@@ -2383,6 +2188,70 @@ int gg_userlist_request(struct gg_session *sess, char type, const char *request)
}
/**
+ * 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
@@ -2425,6 +2294,47 @@ int gg_multilogon_disconnect(struct gg_session *gs, gg_multilogon_id_t conn_id)
/* @} */
+/**
+ * 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
diff --git a/protocols/Gadu-Gadu/src/libgadu/libgadu.h b/protocols/Gadu-Gadu/src/libgadu/libgadu.h
index 44e8318b8d..8c5e8e626a 100644
--- a/protocols/Gadu-Gadu/src/libgadu/libgadu.h
+++ b/protocols/Gadu-Gadu/src/libgadu/libgadu.h
@@ -1,4 +1,4 @@
-/* $Id: libgadu.h 13762 2011-08-09 12:35:16Z dezred $ */
+/* $Id$ */
/*
* (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl>
@@ -81,6 +81,9 @@
/* 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. */
+#define GG_CONFIG_HAVE_ZLIB
+
/* Defined if uintX_t types are defined in <stdint.h>. */
#undef GG_CONFIG_HAVE_STDINT_H
@@ -271,11 +274,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) */
@@ -624,6 +627,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
@@ -639,19 +653,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) */
@@ -688,6 +698,7 @@ int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int r
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);
@@ -759,7 +770,10 @@ enum gg_event_t {
GG_EVENT_TYPING_NOTIFICATION, /**< Powiadomienie o pisaniu */
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_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
@@ -778,7 +792,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 */
};
/**
@@ -1060,6 +1076,23 @@ struct gg_event_multilogon_info {
};
/**
+ * 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().
*
@@ -1094,6 +1127,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) */
};
/**
@@ -1324,6 +1359,19 @@ void gg_debug_session(struct gg_session *sess, int level, const char *format, ..
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;
@@ -2154,6 +2202,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;
@@ -2232,7 +2341,7 @@ struct gg_dcc7_reject {
// XXX API
#define GG_DCC7_REJECT_BUSY 0x00000001 /**< Połączenie bezpośrednie już trwa, nie umiem obsłużyć więcej */
#define GG_DCC7_REJECT_USER 0x00000002 /**< Użytkownik odrzucił połączenie */
-#define GG_DCC7_REJECT_HIDDEN 0x00000003 /* użytkownik ojest ukryty i nie możesz mu wysłać pliku */
+#define GG_DCC7_REJECT_HIDDEN 0x00000003 /* użytkownik jest ukryty i nie możesz mu wysłać pliku */
#define GG_DCC7_REJECT_VERSION 0x00000006 /**< Druga strona ma wersję klienta nieobsługującą połączeń bezpośrednich tego typu */
#define GG_DCC7_ID_REQUEST 0x23
diff --git a/protocols/Gadu-Gadu/src/libgadu/message.cpp b/protocols/Gadu-Gadu/src/libgadu/message.cpp
index d0872c32e9..2e81c6b0de 100644
--- a/protocols/Gadu-Gadu/src/libgadu/message.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/message.cpp
@@ -369,7 +369,7 @@ int gg_message_get_attributes(gg_message_t *gm, const char **attributes, size_t
* \param src Dodawany tekst
* \param len Długość dodawanego tekstu
*/
-static void gg_append(char *dst, int *pos, const void *src, int len)
+static void gg_append(char *dst, size_t *pos, const void *src, int len)
{
if (dst != NULL)
memcpy(&dst[*pos], src, len);
@@ -402,7 +402,8 @@ size_t gg_message_text_to_html(char *dst, const char *src, const char *format, s
int format_idx = 0;
unsigned char old_attr = 0;
const unsigned char *color = (const unsigned char*) "\x00\x00\x00";
- int len, i;
+ int i;
+ size_t len;
const unsigned char *format_ = (const unsigned char*) format;
len = 0;
@@ -592,6 +593,11 @@ size_t gg_message_html_to_text(char *dst, const char *html)
entity = NULL;
for (src = html; *src != 0; src++) {
+ if (in_entity && !(isalnum(*src) || *src == '#' || *src == ';')) {
+ in_entity = 0;
+ gg_append(dst, &len, entity, src - entity);
+ }
+
if (*src == '<') {
tag = src;
in_tag = 1;
diff --git a/protocols/Gadu-Gadu/src/libgadu/obsolete.cpp b/protocols/Gadu-Gadu/src/libgadu/obsolete.cpp
index 0f75fd2dd2..3fb2d917fb 100644
--- a/protocols/Gadu-Gadu/src/libgadu/obsolete.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/obsolete.cpp
@@ -34,6 +34,7 @@
#include <errno.h>
#include "libgadu.h"
+#include "internal.h"
struct gg_http *gg_userlist_get(uin_t uin, const char *passwd, int async)
{
diff --git a/protocols/Gadu-Gadu/src/libgadu/protocol.h b/protocols/Gadu-Gadu/src/libgadu/protocol.h
index 16bde0d424..09ec9e7cf9 100644
--- a/protocols/Gadu-Gadu/src/libgadu/protocol.h
+++ b/protocols/Gadu-Gadu/src/libgadu/protocol.h
@@ -136,7 +136,7 @@ struct gg_recv_msg80 {
#define GG_RECV_MSG_ACK 0x0046
struct gg_recv_msg_ack {
- uint32_t count;
+ uint32_t seq;
} GG_PACKED;
#define GG_USER_DATA 0x0044
@@ -293,6 +293,32 @@ struct gg_dcc7_welcome_p2p {
#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
diff --git a/protocols/Gadu-Gadu/src/libgadu/resolver.cpp b/protocols/Gadu-Gadu/src/libgadu/resolver.cpp
index 065169007f..b8972f26d1 100644
--- a/protocols/Gadu-Gadu/src/libgadu/resolver.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/resolver.cpp
@@ -63,7 +63,6 @@ static void (*gg_global_resolver_cleanup)(void **private_data, int force);
#include <pthread.h>
-#ifdef GG_CONFIG_HAVE_GETHOSTBYNAME_R
/**
* \internal Funkcja pomocnicza zwalniająca zasoby po rozwiązywaniu nazwy
* w wątku.
@@ -79,7 +78,7 @@ static void gg_gethostbyname_cleaner(void *data)
*buf_ptr = NULL;
}
}
-#endif
+
#endif /* GG_CONFIG_HAVE_PTHREAD */
/**
@@ -244,7 +243,7 @@ int gg_gethostbyname_real(const char *hostname, struct in_addr **result, int *co
/* Kopiuj */
for (i = 0; he->h_addr_list[i] != NULL; i++)
- memcpy(&((*result)[i]), he->h_addr_list[0], sizeof(struct in_addr));
+ memcpy(&((*result)[i]), he->h_addr_list[i], sizeof(struct in_addr));
(*result)[i].s_addr = INADDR_NONE;
@@ -257,22 +256,24 @@ int gg_gethostbyname_real(const char *hostname, struct in_addr **result, int *co
/**
* \internal Rozwiązuje nazwę i zapisuje wynik do podanego desktyptora.
*
+ * \note Użycie logowania w tej funkcji może mieć negatywny wpływ na
+ * aplikacje jednowątkowe korzystające.
+ *
* \param fd Deskryptor
* \param hostname Nazwa serwera
*
* \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;
int res = 0;
- gg_debug(GG_DEBUG_MISC, "// gg_resolver_run(%d, %s)\n", fd, hostname);
-
if ((addr_ip[0].s_addr = inet_addr(hostname)) == INADDR_NONE) {
if (gg_gethostbyname_real(hostname, &addr_list, &addr_count, 1) == -1) {
addr_list = addr_ip;
+ addr_count = 0;
/* addr_ip[0] już zawiera INADDR_NONE */
}
} else {
@@ -281,8 +282,6 @@ int gg_resolver_run(int fd, const char *hostname)
addr_count = 1;
}
- gg_debug(GG_DEBUG_MISC, "// gg_resolver_run() count = %d\n", addr_count);
-
if (write(fd, addr_list, (addr_count + 1) * sizeof(struct in_addr)) != (addr_count + 1) * sizeof(struct in_addr))
res = -1;
@@ -374,12 +373,17 @@ static int gg_resolver_fork_start(SOCKET *fd, void **priv_data, const char *host
}
if (data->pid == 0) {
+ int status;
+
gg_sock_close(pipes[0]);
- if (gg_resolver_run(pipes[1], hostname) == -1)
- exit(1);
- else
- exit(0);
+ status = (gg_resolver_run(pipes[1], hostname) == -1) ? 1 : 0;
+
+#ifdef HAVE__EXIT
+ _exit(status);
+#else
+ exit(status);
+#endif
}
gg_sock_close(pipes[1]);
@@ -411,7 +415,7 @@ cleanup:
* danych
* \param force Flaga usuwania zasobów przed zakończeniem działania
*/
-void gg_resolver_fork_cleanup(void **priv_data, int force)
+static void gg_resolver_fork_cleanup(void **priv_data, int force)
{
struct gg_resolver_fork_data *data;