Sprawdzanie zlib w configure.ac wymaga poprawki przez kogoś zaznajomionego z
autotools. Sam nie mam pojęcia o autotools i zrobiłem to tylko tak, żeby na
moim systemie libgadu w ogóle chciało się linkować ;).
---
configure.ac | 4 ++
include/libgadu.h.in | 53 ++++++++++++++++++++++++++++
src/common.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/libgadu.c | 64 ++++++++++++++++++++++++++++++++++
src/libgadu.sym | 1 +
5 files changed, 216 insertions(+), 0 deletions(-)
diff --git a/configure.ac b/configure.ac
index ec4d048..e83c1e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -194,6 +194,10 @@ if test "x$with_pthread" = "xyes"; then
AC_DEFINE([GG_CONFIG_PTHREAD_DEFAULT], [], [Defined if pthread resolver
is the default one.])
fi
+dnl zlib (TODO!)
+
+LIBS="$LIBS -lz"
+
dnl
dnl Sprawdzamy GnuTLS
dnl
diff --git a/include/libgadu.h.in b/include/libgadu.h.in
index fb1d5ef..a785809 100644
--- a/include/libgadu.h.in
+++ b/include/libgadu.h.in
@@ -623,12 +623,15 @@ 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);
uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len);
+unsigned char *gg_deflate(const char *in, size_t *out_lenp);
+
int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type);
gg_resolver_t gg_session_get_resolver(struct gg_session *gs);
int gg_session_set_custom_resolver(struct gg_session *gs, int
(*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**,
int));
@@ -2030,6 +2033,8 @@ struct gg_recv_msg {
#define GG_USERLIST_REQUEST 0x0016
+#define GG_USERLIST100_REQUEST 0x0040
+
#define GG_XML_EVENT 0x0027
#ifndef DOXYGEN
@@ -2083,6 +2088,54 @@ 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 */
+
+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;
+
struct gg_dcc_tiny_packet {
uint8_t type; /* rodzaj pakietu */
} GG_PACKED;
diff --git a/src/common.c b/src/common.c
index 55e77d9..3951c47 100644
--- a/src/common.c
+++ b/src/common.c
@@ -42,6 +42,8 @@
#include <string.h>
#include <unistd.h>
+#include <zlib.h>
+
#include "libgadu.h"
/**
@@ -576,6 +578,98 @@ char *gg_proxy_auth(void)
}
/**
+ * \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)
+{
+ 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 = 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 = 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 = 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);
+ return NULL;
+}
+
+/**
* \internal Tablica pomocnicza do wyznaczania sumy kontrolnej.
*/
static const uint32_t gg_crc32_table[256] =
diff --git a/src/libgadu.c b/src/libgadu.c
index 294ed85..de270dc 100644
--- a/src/libgadu.c
+++ b/src/libgadu.c
@@ -2344,6 +2344,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
diff --git a/src/libgadu.sym b/src/libgadu.sym
index 7e97f0f..8b00077 100644
--- a/src/libgadu.sym
+++ b/src/libgadu.sym
@@ -149,6 +149,7 @@ gg_userlist_remove
gg_userlist_remove_free
gg_userlist_remove_watch_fd
gg_userlist_request
+gg_userlist100_request
gg_vsaprintf
gg_watch_fd
gg_write
--
1.7.5.rc1
_______________________________________________
libgadu-devel mailing list
[email protected]
http://lists.ziew.org/mailman/listinfo/libgadu-devel