Zmiany względem v1:
- Przesunięcie jednej deklaracji z libgadu.h do internal.h.
- Usunięcie zapomnianego gg_debug_session z funkcji
gg_session_handle_userlist_100_reply.
---
include/internal.h | 1 +
include/libgadu.h.in | 33 +++++++++++++++++++
include/protocol.h | 10 ++++++
src/common.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/debug.c | 1 +
src/events.c | 4 ++
src/handlers.c | 31 ++++++++++++++++++
7 files changed, 167 insertions(+), 0 deletions(-)
diff --git a/include/internal.h b/include/internal.h
index dc753e0..8f0848f 100644
--- a/include/internal.h
+++ b/include/internal.h
@@ -38,6 +38,7 @@ 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);
+char *gg_inflate(const unsigned char *in, size_t length);
#ifdef HAVE_UINT64_T
uint64_t gg_fix64(uint64_t x);
diff --git a/include/libgadu.h.in b/include/libgadu.h.in
index ee231f4..7ba3286 100644
--- a/include/libgadu.h.in
+++ b/include/libgadu.h.in
@@ -698,6 +698,7 @@ enum gg_event_t {
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
@@ -995,6 +996,16 @@ struct gg_event_userlist100_version {
};
/**
+ * 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().
*
@@ -1029,6 +1040,7 @@ union gg_event_union {
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) */
};
/**
@@ -2124,6 +2136,27 @@ enum {
#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;
diff --git a/include/protocol.h b/include/protocol.h
index 2c2c06c..9e6cee6 100644
--- a/include/protocol.h
+++ b/include/protocol.h
@@ -309,6 +309,16 @@ struct gg_userlist100_request {
/* 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/src/common.c b/src/common.c
index 79fcbb0..9fb2743 100644
--- a/src/common.c
+++ b/src/common.c
@@ -671,6 +671,93 @@ fail:
}
/**
+ * \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)
+{
+ 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 = 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 = 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);
+ return NULL;
+}
+
+/**
* \internal Tablica pomocnicza do wyznaczania sumy kontrolnej.
*/
static const uint32_t gg_crc32_table[256] =
diff --git a/src/debug.c b/src/debug.c
index f253ec9..8eebf62 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -329,6 +329,7 @@ const char *gg_debug_event(enum gg_event_t event)
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 stany
diff --git a/src/events.c b/src/events.c
index 80be78c..47a4d84 100644
--- a/src/events.c
+++ b/src/events.c
@@ -165,6 +165,10 @@ void gg_event_free(struct gg_event *e)
break;
}
+
+ case GG_EVENT_USERLIST100_REPLY:
+ free(e->event.userlist100_reply.reply);
+ break;
}
free(e);
diff --git a/src/handlers.c b/src/handlers.c
index d2a18fc..ce33f39 100644
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -1712,6 +1712,36 @@ static int gg_session_handle_userlist_100_version(struct
gg_session *gs, uint32_
}
/**
+ * \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[] =
@@ -1752,6 +1782,7 @@ static const gg_packet_handler_t handlers[] =
{ 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 },
};
/**
--
1.7.5.rc1
_______________________________________________
libgadu-devel mailing list
[email protected]
http://lists.ziew.org/mailman/listinfo/libgadu-devel