Sprawdzanie zlib w configure.ac wymaga poprawki. 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ć.

Zmiany względem v1:
- Kilka deklaracji przesuniętych z libgadu.h do internal.h i protocol.h.
---
 configure.ac         |    4 ++
 include/internal.h   |    2 +
 include/libgadu.h.in |   41 +++++++++++++++++++++
 include/protocol.h   |   10 +++++
 src/common.c         |   95 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/libgadu.c        |   64 +++++++++++++++++++++++++++++++++
 src/libgadu.sym      |    1 +
 7 files changed, 217 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/internal.h b/include/internal.h
index c70326b..dc753e0 100644
--- a/include/internal.h
+++ b/include/internal.h
@@ -37,6 +37,8 @@ int gg_resolve(int *fd, int *pid, const char *hostname);
 int gg_resolve_pthread(int *fd, void **resolver, const char *hostname);
 void gg_resolve_pthread_cleanup(void *resolver, int kill);
 
+unsigned char *gg_deflate(const char *in, size_t *out_lenp);
+
 #ifdef HAVE_UINT64_T
 uint64_t gg_fix64(uint64_t x);
 #endif
diff --git a/include/libgadu.h.in b/include/libgadu.h.in
index fb1d5ef..ee231f4 100644
--- a/include/libgadu.h.in
+++ b/include/libgadu.h.in
@@ -623,6 +623,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);
@@ -2083,6 +2084,46 @@ 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_dcc_tiny_packet {
        uint8_t type;           /* rodzaj pakietu */
 } GG_PACKED;
diff --git a/include/protocol.h b/include/protocol.h
index b0b4fde..2c2c06c 100644
--- a/include/protocol.h
+++ b/include/protocol.h
@@ -299,6 +299,16 @@ 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;
+
 #ifdef _WIN32
 #pragma pack(pop)
 #endif
diff --git a/src/common.c b/src/common.c
index 55e77d9..79fcbb0 100644
--- a/src/common.c
+++ b/src/common.c
@@ -42,6 +42,9 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <zlib.h>
+
+#include "internal.h"
 #include "libgadu.h"
 
 /**
@@ -576,6 +579,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
libgadu-devel@lists.ziew.org
http://lists.ziew.org/mailman/listinfo/libgadu-devel

Reply via email to