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