Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: include/internal.h
- ===================================================================
- --- include/internal.h (wersja 1323)
- +++ include/internal.h (kopia robocza)
- @@ -40,6 +40,8 @@
- int gg_login_hash_sha1_2(const char *password, uint32_t seed, uint8_t *result);
- +int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version, const uin_t *participants, int participants_count);
- +
- #ifdef HAVE_UINT64_T
- uint64_t gg_fix64(uint64_t x);
- #endif
- Index: include/libgadu.h.in
- ===================================================================
- --- include/libgadu.h.in (wersja 1323)
- +++ include/libgadu.h.in (kopia robocza)
- @@ -179,6 +179,8 @@
- struct gg_dcc7_relay;
- +struct gg_chat_list;
- +
- /**
- * Sposób rozwiązywania nazw serwerów.
- */
- @@ -310,6 +312,8 @@
- char *connect_host; /**< Adres serwera Gadu-Gadu, z którym się łączymy */
- gg_ssl_t ssl_flag; /**< Flaga połączenia szyfrowanego */
- +
- + struct gg_chat_list *chat_list;
- };
- /**
- @@ -676,6 +680,11 @@
- 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);
- +uin_t gg_str_to_uin(const char *str, int len);
- +int gg_packed_int_read(const char *data, uint16_t *dst);
- +int gg_packed_int_write(uint8_t dst[2], uint16_t val);
- +int gg_packed_uin_read(uin_t *dst, const char *data, int length);
- +int gg_packed_uin_write(uint8_t *dst, int size, uin_t uin, int variant_long);
- int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type);
- gg_resolver_t gg_session_get_resolver(struct gg_session *gs);
- @@ -691,6 +700,11 @@
- int gg_multilogon_disconnect(struct gg_session *gs, gg_multilogon_id_t conn_id);
- +int gg_chat_create(struct gg_session *gs);
- +int gg_chat_invite(struct gg_session *gs, uint64_t id, uin_t *participants, int participants_count);
- +int gg_chat_leave(struct gg_session *gs, uint64_t id);
- +int gg_chat_send_message(struct gg_session *gs, uint64_t id, const char *message, int is_html);
- +
- /**
- * Rodzaj zdarzenia.
- *
- @@ -746,6 +760,16 @@
- 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) */
- +
- + GG_EVENT_IMTOKEN /* = 43 */,
- + GG_EVENT_PONG110,
- + GG_EVENT_JSON_EVENT,
- +
- + GG_EVENT_CHAT_INFO,
- + GG_EVENT_CHAT_INFO_UPDATE,
- + GG_EVENT_CHAT_CREATED,
- + GG_EVENT_CHAT_INVITE_ACK,
- + GG_EVENT_CHAT_SEND_MSG_ACK,
- };
- #define GG_EVENT_SEARCH50_REPLY GG_EVENT_PUBDIR50_SEARCH_REPLY
- @@ -849,6 +873,7 @@
- uint32_t seq; /**< Numer sekwencyjny wiadomości */
- char *xhtml_message; /**< Treść wiadomości w formacie XHTML */
- + uint64_t chat_id;
- };
- /**
- @@ -957,6 +982,14 @@
- };
- /**
- + * Opis zdarzenia \c GG_EVENT_JSON_EVENT.
- + */
- +struct gg_event_json_event {
- + char *data; /**< Bufor z komunikatem */
- + char *type; /**< Bufor z typem komunikatu */
- +};
- +
- +/**
- * Opis zdarzenia \c GG_EVENT_DCC7_CONNECTED.
- */
- struct gg_event_dcc7_connected {
- @@ -1071,6 +1104,45 @@
- char *reply; /**< Treść listy kontaktów w przesyłanej wersji i formacie */
- };
- +struct gg_event_imtoken {
- + char *imtoken;
- +};
- +
- +struct gg_event_pong110 {
- + time_t time;
- +};
- +
- +struct gg_event_chat_info {
- + uint64_t id;
- + uint32_t version;
- + uint32_t participants_count;
- + uin_t *participants;
- +};
- +
- +struct gg_event_chat_info_update {
- + uint64_t id;
- + uint32_t type;
- + uin_t participant;
- + uin_t inviter;
- + uint32_t version;
- + uint32_t time;
- +};
- +
- +struct gg_event_chat_created {
- + uint64_t id;
- + uint32_t seq;
- +};
- +
- +struct gg_event_chat_invite_ack {
- + uint64_t id;
- + uint32_t seq;
- +};
- +
- +struct gg_event_chat_send_msg_ack {
- + uint32_t seq;
- + uint32_t time;
- +};
- +
- /**
- * Unia wszystkich zdarzeń zwracanych przez funkcje \c gg_watch_fd(),
- * \c gg_dcc_watch_fd() i \c gg_dcc7_watch_fd().
- @@ -1091,6 +1163,7 @@
- struct gg_event_userlist userlist; /**< Odpowiedź listy kontaktów (\c GG_EVENT_USERLIST) */
- gg_pubdir50_t pubdir50; /**< Odpowiedź katalogu publicznego (\c GG_EVENT_PUBDIR50_*) */
- struct gg_event_xml_event xml_event; /**< Zdarzenie systemowe (\c GG_EVENT_XML_EVENT) */
- + struct gg_event_json_event json_event; /**< Zdarzenie systemowe (\c GG_EVENT_JSON_EVENT) */
- struct gg_dcc *dcc_new; /**< Nowe połączenie bezpośrednie (\c GG_EVENT_DCC_NEW) */
- enum gg_error_t dcc_error; /**< Błąd połączenia bezpośredniego (\c GG_EVENT_DCC_ERROR) */
- struct gg_event_dcc_voice_data dcc_voice_data; /**< Dane połączenia głosowego (\c GG_EVENT_DCC_VOICE_DATA) */
- @@ -1107,6 +1180,13 @@
- 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) */
- + struct gg_event_imtoken imtoken;
- + struct gg_event_pong110 pong110;
- + struct gg_event_chat_info chat_info;
- + struct gg_event_chat_info_update chat_info_update;
- + struct gg_event_chat_created chat_created;
- + struct gg_event_chat_invite_ack chat_invite_ack;
- + struct gg_event_chat_send_msg_ack chat_send_msg_ack;
- };
- /**
- @@ -1573,8 +1653,8 @@
- #define GG_HTTPS_PORT 443
- #define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)"
- -#define GG_DEFAULT_CLIENT_VERSION "10.1.0.11070"
- -#define GG_DEFAULT_PROTOCOL_VERSION 0x2e
- +#define GG_DEFAULT_CLIENT_VERSION "11.0.0.8255"
- +#define GG_DEFAULT_PROTOCOL_VERSION 0x2f
- #define GG_DEFAULT_TIMEOUT 30
- #define GG_HAS_AUDIO_MASK 0x40000000
- #define GG_HAS_AUDIO7_MASK 0x20000000
- @@ -1944,6 +2024,8 @@
- #define GG_ADD_NOTIFY 0x000d
- #define GG_REMOVE_NOTIFY 0x000e
- +#define GG_ADD_NOTIFY105 0x007b
- +#define GG_REMOVE_NOTIFY105 0x007c
- struct gg_add_remove {
- uint32_t uin; /* numerek */
- @@ -2085,6 +2167,17 @@
- /* char image[]; */
- } GG_PACKED;
- +struct gg_chat_list {
- + uint64_t id;
- + uint32_t version;
- + uint32_t participants_count;
- + uin_t *participants;
- +
- + struct gg_chat_list *next;
- +};
- +
- +struct gg_chat_list * gg_chat_find(struct gg_session *sess, uint64_t id);
- +
- #define GG_SEND_MSG_ACK 0x0005
- #ifndef DOXYGEN
- @@ -2137,6 +2230,7 @@
- #define GG_USERLIST_REQUEST 0x0016
- #define GG_XML_EVENT 0x0027
- +#define GG_EVENT110 0x0084
- #ifndef DOXYGEN
- @@ -2355,6 +2449,15 @@
- #define GG_DCC7_TIMEOUT_FILE_ACK 300 /* 5 minut */
- #define GG_DCC7_TIMEOUT_VOICE_ACK 300 /* 5 minut */
- +#define GG_IMTOKEN 0x008c
- +#define GG_NOTIFY105_FIRST 0x0077
- +#define GG_NOTIFY105_LAST 0x0078
- +#define GG_NOTIFY105_LIST_EMPTY 0x0079
- +#define GG_PONG110 0x00a1
- +
- +#define GG_CHAT_INFO_UPDATE_ENTERED 0x01
- +#define GG_CHAT_INFO_UPDATE_EXITED 0x03
- +
- #ifdef __cplusplus
- }
- #endif
- Index: include/protocol.h
- ===================================================================
- --- include/protocol.h (wersja 1323)
- +++ include/protocol.h (kopia robocza)
- @@ -32,6 +32,7 @@
- #define GG_LOGIN80BETA 0x0029
- #define GG_LOGIN80 0x0031
- +#define GG_LOGIN105 0x0083
- #undef GG_FEATURE_STATUS80BETA
- #undef GG_FEATURE_MSG80
- @@ -42,6 +43,8 @@
- #define GG8_LANG "pl"
- #define GG8_VERSION "Gadu-Gadu Client Build "
- +#define GG11_VERSION "GG "
- +#define GG11_TARGET " WINNT"
- struct gg_login80 {
- uint32_t uin; /* mój numerek */
- @@ -63,6 +66,8 @@
- #define GG_LOGIN80_OK 0x0035
- +#define GG_LOGIN110_OK 0x009d
- +
- /**
- * Logowanie powiodło się (pakiet \c GG_LOGIN80_OK)
- */
- @@ -92,6 +97,8 @@
- uint32_t description_size; /**< rozmiar opisu */
- } GG_PACKED;
- +#define GG_NEW_STATUS105 0x0063
- +
- #define GG_STATUS80BETA 0x002a
- #define GG_NOTIFY_REPLY80BETA 0x002b
- @@ -319,6 +326,37 @@
- /* char reply[]; */
- } GG_PACKED;
- +struct gg_pong110 {
- + uint8_t dummy;
- + uint32_t time;
- +} GG_PACKED;
- +
- +#define GG_SEND_MSG110 0x007d
- +#define GG_RECV_MSG110 0x007e
- +#define GG_RECV_OWN_MSG110 0x0082
- +#define GG_ACK110 0x0086
- +
- +#define GG_ACK110_MSG 0x01
- +#define GG_ACK110_CHAT 0x02
- +#define GG_ACK110_CHAT_INFO 0x03
- +#define GG_ACK110_MPA 0x06
- +
- +#define GG_EVENT110_XML 0x00
- +#define GG_EVENT110_JSON 0x02
- +
- +#define GG_CHAT_INFO 0x0093
- +#define GG_CHAT_INFO_UPDATE 0x009e
- +#define GG_CHAT_CREATED 0x0045
- +#define GG_CHAT_INVITE_ACK 0x0047
- +#define GG_CHAT_RECV_MSG 0x0088
- +#define GG_CHAT_RECV_OWN_MSG 0x008e
- +#define GG_CHAT_CREATE 0x0047
- +#define GG_CHAT_INVITE 0x0090
- +#define GG_CHAT_LEAVE 0x0052
- +#define GG_CHAT_LEFT 0x0066
- +#define GG_CHAT_SEND_MSG 0x008d
- +#define GG_CHAT_SEND_MSG_ACK 0x0087
- +
- #ifdef _WIN32
- #pragma pack(pop)
- #endif
- Index: include/message.h
- ===================================================================
- --- include/message.h (wersja 1323)
- +++ include/message.h (kopia robocza)
- @@ -52,4 +52,7 @@
- size_t gg_message_html_to_text(char *dst, unsigned char *format, size_t *format_len, const char *html, gg_encoding_t encoding);
- size_t gg_message_text_to_html(char *dst, const char *src, gg_encoding_t encoding, const unsigned char *format, size_t format_len);
- +char * gg_message_html_to_text_gg11(const char *html);
- +char * gg_message_text_to_html_gg11(const char *text);
- +
- #endif /* LIBGADU_MESSAGE_H */
- Index: src/handlers.c
- ===================================================================
- --- src/handlers.c (wersja 1323)
- +++ src/handlers.c (kopia robocza)
- @@ -61,6 +61,239 @@
- int (*handler)(struct gg_session *, uint32_t, const char *, size_t, struct gg_event *);
- } gg_packet_handler_t;
- +static int gg_ack_gg11(struct gg_session *gs, uint8_t type, uint16_t seq, struct gg_event *ge)
- +{
- + uint8_t dunno1 = 0x08;
- + uint8_t dunno2 = 0x10;
- + uint8_t seq_b[2];
- + int seq_len;
- + uint8_t dunno3[2] = { 0x18, 0x01 };
- + int ret;
- +
- + seq_len = gg_packed_int_write(seq_b, seq);
- +
- + ret = gg_send_packet(gs,
- + GG_ACK110,
- + &dunno1, sizeof(dunno1),
- + &type, sizeof(type),
- + &dunno2, sizeof(dunno2),
- + seq_b, seq_len,
- + dunno3, sizeof(dunno3),
- + NULL);
- +
- + if (ret == -1) {
- + int errno_copy;
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
- + errno_copy = errno;
- + close(gs->fd);
- + errno = errno_copy;
- + gs->fd = -1;
- + ge->type = GG_EVENT_CONN_FAILED;
- + ge->event.failure = GG_FAILURE_WRITING;
- + gs->state = GG_STATE_IDLE;
- + return -1;
- + }
- +
- + return 0;
- +}
- +
- +static int gg_session_handle_welcome_gg11(struct gg_session *gs, uint32_t seed, struct gg_event *ge)
- +{
- + const uint8_t section_headers[6] = {0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a};
- + const uint8_t lang_length = 2;
- + const char *lang = GG8_LANG;
- + const uint8_t dunno1 = 0x12;
- + int uin_len;
- + uint8_t uin_s[20];
- + uint8_t hash_len = 20;
- + uint8_t hash[64];
- + const uint8_t dunno2[9] = {0x20, 0x02, 0x2d, 0x77, 0xff, 0xae, 0x01, 0x35, 0x14};
- + uint8_t privacy;
- + const uint8_t dunno3[2] = {0x03, 0x00};
- + uint8_t client_len;
- + const char *client_name = GG11_VERSION;
- + const char *client_version = GG_DEFAULT_CLIENT_VERSION;
- + const char *client_target = GG11_TARGET;
- + const uint8_t dunno4 = 0x45;
- + uint32_t status;
- + uint8_t descr_len;
- + const char *descr;
- + const uint8_t dunno5[6] = {0x52, 0x04, 0x00, 0x00, 0x00, 0x00};
- + uint8_t userdata_len;
- + const char *userdata;
- + const uint8_t dunno6[15] = {0x60, 0xff, 0x01, 0x68, 0x64, 0x75, 0x7f,
- + 0x00, 0x00, 0x00, 0x78, 0x00, 0x88, 0x01, 0x00};
- +
- + uint8_t client_name_len;
- + uint8_t client_version_len;
- + uint8_t client_target_len;
- + int ret;
- +
- + if (gs->hash_type != GG_LOGIN_HASH_SHA1) {
- + gg_debug_session(gs, GG_DEBUG_MISC, "// Unsupported hash type for this protocol version\n");
- + return -1;
- + }
- +
- + if (gg_login_hash_sha1_2(gs->password, seed, hash) == -1) {
- + int errno_copy;
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() gg_login_hash_sha1_2() failed, probably out of memory\n");
- + errno_copy = errno;
- + close(gs->fd);
- + errno = errno_copy;
- + gs->fd = -1;
- + ge->type = GG_EVENT_CONN_FAILED;
- + ge->event.failure = GG_FAILURE_INTERNAL;
- + gs->state = GG_STATE_IDLE;
- + return -1;
- + }
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending GG_LOGIN105 packet\n");
- +
- + /*
- + zmienia format pakietu
- + dunno2[3] == 0x37 dla gg10.5
- + dunno2[3] == 0x77 dla gg11.0
- + */
- +
- + uin_len = gg_packed_uin_write(uin_s, sizeof(uin_s), gs->uin, 1);
- +
- + privacy = 0x00; /* 0x06 - pokazuj kamerkę znajomym */
- +
- + /* flagi gg8 są różne od tych dla gg11 */
- + status = gg_fix32(gs->initial_status ? (gs->initial_status & 0xFF) : GG_STATUS_AVAIL);
- +
- + if (gs->client_version != NULL && !isdigit(gs->client_version[0])) {
- + client_name = "";
- + client_target = "";
- + }
- + if (gs->client_version != NULL)
- + client_version = gs->client_version;
- + client_name_len = strlen(client_name);
- + client_version_len = strlen(client_version);
- + client_target_len = strlen(client_target);
- + client_len = client_name_len + client_version_len + client_target_len;
- +
- + descr = (gs->initial_descr != NULL) ? gs->initial_descr : "";
- + descr_len = (gs->initial_descr != NULL) ? strlen(gs->initial_descr) : 0;
- +
- + userdata = "avatar,StatusComments,gg_account_sdp,edisc,bot,fanpage,"
- + "pubdir,botCaps";
- + userdata_len = strlen(userdata);
- +
- + ret = gg_send_packet(gs,
- + GG_LOGIN105,
- + §ion_headers[0], 1,
- + &lang_length, sizeof(lang_length),
- + lang, lang_length,
- + &dunno1, sizeof(dunno1),
- + uin_s, uin_len,
- +
- + §ion_headers[1], 1,
- + &hash_len, sizeof(hash_len),
- + hash, hash_len,
- + dunno2, sizeof(dunno2),
- + &privacy, sizeof(privacy),
- + dunno3, sizeof(dunno3),
- +
- + §ion_headers[3], 1,
- + &client_len, sizeof(client_len),
- + client_name, client_name_len,
- + client_version, client_version_len,
- + client_target, client_target_len,
- + &dunno4, sizeof(dunno4),
- + &status, sizeof(status),
- +
- + §ion_headers[4], 1,
- + &descr_len, sizeof(descr_len),
- + descr, descr_len,
- + dunno5, sizeof(dunno5),
- +
- + §ion_headers[5], 1,
- + &userdata_len, sizeof(userdata_len),
- + userdata, userdata_len,
- +
- + dunno6, sizeof(dunno6),
- + NULL);
- +
- + if (ret == -1) {
- + int errno_copy;
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
- + errno_copy = errno;
- + close(gs->fd);
- + errno = errno_copy;
- + gs->fd = -1;
- + ge->type = GG_EVENT_CONN_FAILED;
- + ge->event.failure = GG_FAILURE_WRITING;
- + gs->state = GG_STATE_IDLE;
- + return -1;
- + }
- +
- + gs->state = GG_STATE_READING_REPLY;
- + gs->check = GG_CHECK_READ;
- +
- + return 0;
- +}
- +
- +static int gg_session_handle_login110_ok(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + uint8_t somehash_len;
- + char *somehash = NULL;
- + uint32_t server_time;
- + int offset = 0;
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n");
- + ge->type = GG_EVENT_CONN_SUCCESS;
- + gs->state = GG_STATE_CONNECTED;
- + gs->check = GG_CHECK_READ;
- + gs->timeout = -1;
- + gs->status = (gs->initial_status) ? gs->initial_status : GG_STATUS_AVAIL;
- +#if 0
- + free(gs->status_descr);
- + gs->status_descr = gs->initial_descr;
- +#else
- + free(gs->initial_descr);
- +#endif
- + gs->initial_descr = NULL;
- +
- + if (offset + 3 > len)
- + goto fail;
- + /* 0x08 01 12 */
- + offset += 3;
- +
- + if (offset + 1 > len)
- + goto fail;
- + somehash_len = ptr[offset];
- + offset++;
- + if (offset + somehash_len > len)
- + goto fail;
- + somehash = malloc(somehash_len + 1);
- + if (somehash == NULL)
- + goto fail;
- + memcpy(somehash, ptr + offset, somehash_len);
- + somehash[somehash_len] = '\0';
- + offset += somehash_len;
- +
- + if (offset + 6 > len)
- + goto fail;
- + /* 0x18 _f __ __ __ 25 */
- + offset += 6;
- +
- + if (offset + 4 > len)
- + goto fail;
- + server_time = gg_fix32(*((uint32_t*)(ptr + offset)));
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// login110_ok: some hash=%s, server time=%u\n", somehash, server_time);
- + free(somehash);
- +
- + return 0;
- +fail:
- + free(somehash);
- + return -1;
- +}
- +
- /**
- * \internal Obsługuje pakiet GG_WELCOME.
- *
- @@ -92,6 +325,9 @@
- w = (const struct gg_welcome*) ptr;
- seed = gg_fix32(w->key);
- + if (gs->protocol_version >= 0x2f)
- + return gg_session_handle_welcome_gg11(gs, seed, ge);
- +
- memset(hash_buf, 0, sizeof(hash_buf));
- switch (gs->hash_type) {
- @@ -347,6 +583,75 @@
- return 0;
- }
- +static int gg_session_handle_event110(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + int offset = 0;
- + uint16_t seq, data_len;
- + uint8_t event_type;
- + char *data = NULL;
- + char *json_type = NULL;
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received GG11 event\n");
- +
- + if (offset + 3 > len)
- + goto fail;
- + /* 0x08 xx 10 */
- + offset++;
- + event_type = ptr[offset++];
- + offset++;
- +
- + if (offset + 2 > len)
- + goto fail;
- + offset += gg_packed_int_read(ptr + offset, &seq);
- +
- + if (offset + 1 > len)
- + goto fail;
- + /* 0x1a */
- + offset++;
- +
- + if (offset + 2 > len)
- + goto fail;
- + offset += gg_packed_int_read(ptr + offset, &data_len);
- +
- + data = malloc(data_len + 1);
- + if (data == NULL)
- + goto fail;
- + memcpy(data, ptr + offset, data_len);
- + data[data_len] = '\0';
- + offset += data_len;
- +
- + if (event_type == GG_EVENT110_XML) {
- + ge->type = GG_EVENT_XML_EVENT;
- + ge->event.xml_event.data = data;
- + } else if (event_type == GG_EVENT110_JSON) {
- + if (offset + 3 > len)
- + goto fail;
- + offset++; /* 0x22 */
- + offset += gg_packed_int_read(ptr + offset, &data_len);
- +
- + json_type = malloc(data_len + 1);
- + if (json_type == NULL)
- + goto fail;
- + memcpy(json_type, ptr + offset, data_len);
- + json_type[data_len] = '\0';
- + offset += data_len;
- +
- + ge->type = GG_EVENT_JSON_EVENT;
- + ge->event.json_event.data = data;
- + ge->event.json_event.type = json_type;
- + } else {
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() unsupported GG11 event type: %d\n", event_type);
- + gg_ack_gg11(gs, GG_ACK110_MPA, seq, ge);
- + goto fail;
- + }
- +
- + return gg_ack_gg11(gs, GG_ACK110_MPA, seq, ge);
- +fail:
- + free(json_type);
- + free(data);
- + return -1;
- +}
- +
- /**
- * \internal Obsługuje pakiet GG_PUBDIR50_REPLY.
- *
- @@ -990,6 +1295,172 @@
- return 0;
- }
- +static int gg_session_handle_recv_msg_110(struct gg_session *sess, uint32_t type, const char *packet, size_t length, struct gg_event *e)
- +{
- + int offset = 0;
- + uint16_t seq = 0;
- + uint16_t msg_len;
- + uint8_t ack_type;
- +
- + uint32_t dummy_time1, dummy_time2;
- +
- + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg110(%p, %d, %p);\n", packet, length, e);
- +
- + if (type == GG_CHAT_RECV_MSG || type == GG_CHAT_RECV_OWN_MSG)
- + ack_type = GG_ACK110_CHAT;
- + else
- + ack_type = GG_ACK110_MSG;
- +
- + if (offset + 1 > length)
- + goto fail;
- + /* nieobecne w GG_CHAT_RECV_OWN_MSG */
- + if (packet[offset] == 0x0a)
- + {
- + offset++;
- +
- + offset += gg_packed_uin_read(&e->event.msg.sender, packet + offset, length - offset);
- + if (e->event.msg.sender == 0)
- + goto fail;
- + }
- + else if (type == GG_CHAT_RECV_OWN_MSG)
- + e->event.msg.sender = sess->uin;
- +
- + if (offset + 3 > length)
- + goto fail;
- + /* 0x10 08 18 -> ustawiany przez nadawcę? */
- + /* 0x10 09 18 -> archiwalna wiadomość? */
- + /* 0x10 04 18 -> własna wiadomość w czacie */
- + offset += 3;
- +
- + if (offset + 2 > length)
- + goto fail;
- + offset += gg_packed_int_read(packet + offset, &seq);
- + e->event.msg.seq = seq;
- +
- + if (offset + 1 > length)
- + goto fail;
- + /* 0x25 */
- + offset++;
- +
- + if (offset + 4 > length)
- + goto fail;
- + e->event.msg.time = gg_fix32(*((uint32_t*)(packet + offset)));
- + offset += 4;
- +
- + if (offset + 1 > length)
- + goto fail;
- + /* 0x2a */
- + offset++;
- +
- + if (offset + 2 > length)
- + goto fail;
- + offset += gg_packed_int_read(packet + offset, &msg_len);
- + if (offset + msg_len > length)
- + goto fail;
- + e->event.msg.message = (unsigned char*)gg_encoding_convert(packet + offset, GG_ENCODING_UTF8, sess->encoding, msg_len, -1);
- + if (e->event.msg.message == NULL)
- + goto fail;
- + offset += msg_len;
- +
- + if (offset + 1 > length)
- + goto fail;
- + /* 0x32 */
- + offset++;
- +
- + if (offset + 2 > length)
- + goto fail;
- + offset += gg_packed_int_read(packet + offset, &msg_len);
- + if (offset + msg_len > length)
- + goto fail;
- + e->event.msg.xhtml_message = gg_encoding_convert(packet + offset, GG_ENCODING_UTF8, sess->encoding, msg_len, -1);
- + if (e->event.msg.xhtml_message == NULL)
- + goto fail;
- + offset += msg_len;
- +
- + if (offset + 1 > length)
- + goto fail;
- + /* otrzymywane tylko od gg <= 10.5 */
- + if (packet[offset] == 0x3a)
- + {
- + uint8_t formats_length;
- +
- + offset++;
- + if (offset + 1 > length)
- + goto fail;
- + formats_length = packet[offset++];
- + if (offset + formats_length > length)
- + goto fail;
- + e->event.msg.formats_length = formats_length;
- +
- + e->event.msg.formats = malloc(formats_length);
- + if (e->event.msg.formats == NULL)
- + goto fail;
- + memcpy(e->event.msg.formats, packet + offset, formats_length);
- + offset += formats_length;
- + }
- +
- + /* 49 xx xx xx 00 */
- + if (offset + 5 > length)
- + goto fail;
- + offset += 5;
- +
- + if (offset + 4 > length)
- + goto fail;
- + /* taki sam czas jak czas wiadomości lub o jeden mniej */
- + dummy_time1 = gg_fix32(*((uint32_t*)(packet + offset)));
- + offset += 4;
- +
- + /* type == GG_CHAT_RECV_MSG || type == GG_CHAT_RECV_OWN_MSG */
- + if (packet[offset] == 0x51) {
- + struct gg_chat_list *chat;
- +
- + offset++;
- +
- + if (offset + 8 > length)
- + goto fail;
- + e->event.msg.chat_id = gg_fix64(*((uint64_t*)(packet + offset)));
- + offset += 8;
- +
- + chat = gg_chat_find(sess, e->event.msg.chat_id);
- + if (chat) {
- + e->event.msg.recipients = malloc(chat->participants_count * sizeof(uin_t));
- + if (e->event.msg.recipients == NULL)
- + goto fail;
- + memcpy(e->event.msg.recipients, chat->participants, chat->participants_count * sizeof(uin_t));
- + e->event.msg.recipients_count = chat->participants_count;
- + }
- + }
- +
- + if (offset + 5 > length)
- + goto fail;
- + /* id rozmówcy? konwersacji? */
- + /* 0x59 __ __ 0_ 00 */
- + offset += 5;
- +
- + if (offset + 4 > length)
- + goto fail;
- + /* czas początku konwersacji? */
- + dummy_time2 = gg_fix32(*((uint32_t*)(packet + offset)));
- +
- + if (type == GG_RECV_OWN_MSG110 || type == GG_CHAT_RECV_OWN_MSG)
- + e->type = GG_EVENT_MULTILOGON_MSG;
- + else
- + e->type = GG_EVENT_MSG;
- + e->event.msg.msgclass = GG_CLASS_CHAT;
- + e->event.msg.seq = seq;
- +
- + return gg_ack_gg11(sess, ack_type, seq, e);
- +
- +fail:
- + free(e->event.msg.message);
- + free(e->event.msg.xhtml_message);
- + free(e->event.msg.recipients);
- + free(e->event.msg.formats);
- + if (seq)
- + gg_ack_gg11(sess, ack_type, seq, e);
- + return -1;
- +}
- +
- /**
- * \internal Obsługuje pakiet GG_STATUS.
- *
- @@ -1764,6 +2235,388 @@
- return 0;
- }
- +static int gg_session_handle_imtoken(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + uint8_t imtoken_len;
- + char *imtoken = NULL;
- + int offset = 0;
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received imtoken\n");
- +
- + if (offset + 1 > len)
- + goto fail;
- + /* 0x0a */
- + offset++;
- +
- + if (offset + 1 > len)
- + goto fail;
- + imtoken_len = ptr[offset];
- + offset++;
- + if (offset + imtoken_len > len)
- + goto fail;
- + if (imtoken_len > 0) {
- + imtoken = malloc(imtoken_len + 1);
- + if (imtoken == NULL)
- + goto fail;
- + memcpy(imtoken, ptr + offset, imtoken_len);
- + imtoken[imtoken_len] = '\0';
- + }
- +
- + ge->type = GG_EVENT_IMTOKEN;
- + ge->event.imtoken.imtoken = imtoken;
- +
- + return 0;
- +fail:
- + free(imtoken);
- + return -1;
- +}
- +
- +static int gg_session_handle_pong110(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + const struct gg_pong110 *pong = (const struct gg_pong110*)ptr;
- +
- + gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received pong110\n");
- +
- + ge->type = GG_EVENT_PONG110;
- + ge->event.pong110.time = gg_fix32(pong->time);
- +
- + return 0;
- +}
- +
- +static int gg_session_handle_chat_info(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + uint64_t id;
- + uint32_t version;
- + uint32_t dummy1;
- + uint32_t name_length;
- + uint32_t participants_count;
- + uin_t *participants = NULL;
- +
- + int i;
- +
- + int offset = 0;
- +
- + if (offset + 8 > len)
- + goto fail;
- + id = gg_fix64(*((uint64_t*)(ptr + offset)));
- + offset += 8;
- +
- + if (id == 0) {
- + ge->type = GG_EVENT_NONE;
- + return 0;
- + }
- +
- + if (offset + 4 > len)
- + goto fail;
- + /* 0x00 00 00 00 */
- + offset += 4;
- +
- + if (offset + 4 > len)
- + goto fail;
- + version = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + if (offset + 4 > len)
- + goto fail;
- + /* 0 lub 1 */
- + dummy1 = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + if (dummy1 == 1) {
- + if (offset + 4 > len)
- + goto fail;
- + name_length = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- + if (offset + name_length > len)
- + goto fail;
- + offset += name_length;
- +
- + if (offset + 4 > len)
- + goto fail;
- + /* 0x00 00 00 00 */
- + offset += 4;
- +
- + if (offset + 4 > len)
- + goto fail;
- + /* 0x02 00 00 00 */
- + offset += 4;
- + }
- +
- + if (offset + 4 > len)
- + goto fail;
- + participants_count = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + if (offset + 8 * participants_count > len)
- + goto fail;
- +
- + participants = malloc(sizeof(uin_t) * participants_count);
- + if (participants == NULL)
- + goto fail;
- +
- + for (i = 0; i < participants_count; i++)
- + {
- + participants[i] = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + /* 0x1e 00 00 00 lub 0x18 00 00 00 */
- + offset += 4;
- + }
- +
- + if (0 != gg_chat_update(gs, id, version, participants, participants_count))
- + goto fail;
- +
- + ge->type = GG_EVENT_CHAT_INFO;
- + ge->event.chat_info.id = id;
- + ge->event.chat_info.version = version;
- + ge->event.chat_info.participants_count = participants_count;
- + ge->event.chat_info.participants = participants;
- +
- + return 0;
- +fail:
- + free(participants);
- + return -1;
- +}
- +
- +static int gg_session_handle_chat_info_update(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + uint64_t id;
- + uint32_t update_type;
- + uin_t participant, inviter;
- + uint16_t version;
- + uint32_t time;
- +
- + int offset = 0;
- + struct gg_chat_list *chat;
- +
- + if (offset + 1 > len)
- + goto fail;
- + /* 0x0a */
- + offset++;
- +
- + offset += gg_packed_uin_read(&participant, ptr + offset, len - offset);
- + if (participant == 0)
- + goto fail;
- +
- + if (offset + 1 > len)
- + goto fail;
- + /* 0x12 */
- + offset++;
- +
- + offset += gg_packed_uin_read(&inviter, ptr + offset, len - offset);
- + if (inviter == 0)
- + goto fail;
- +
- + if (offset + 1 > len)
- + goto fail;
- + /* 0x1d */
- + offset++;
- +
- + if (offset + 4 > len)
- + goto fail;
- + update_type = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + if (offset + 1 > len)
- + goto fail;
- + /* 0x25 */
- + offset++;
- +
- + if (offset + 4 > len)
- + goto fail;
- + time = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + if (offset + 6 > len)
- + goto fail;
- + /* 0x2d xx 00 00 00 30 */
- + offset += 6;
- +
- + if (offset + 2 > len)
- + goto fail;
- + offset += gg_packed_int_read(ptr + offset, &version);
- +
- + if (offset + 7 + 4 + 1 > len)
- + goto fail;
- + /* 0x38 xx 49 0x 10 */
- + offset += 7;
- + /* time again */
- + offset += 4;
- + /* 0x51 */
- + offset++;
- +
- + if (offset + 8 > len)
- + goto fail;
- + id = gg_fix64(*((uint64_t*)(ptr + offset)));
- + offset += 8;
- +
- + /* 0x59 0x 10 00 00 */
- + offset += 5;
- + /* time again */
- + offset += 4;
- +
- + chat = gg_chat_find(gs, id);
- + if (chat) {
- + chat->version = version;
- + if (update_type == GG_CHAT_INFO_UPDATE_ENTERED) {
- + chat->participants_count++;
- + chat->participants = realloc(chat->participants, sizeof(uin_t) * chat->participants_count);
- + chat->participants[chat->participants_count - 1] = participant;
- + } else if (update_type == GG_CHAT_INFO_UPDATE_EXITED) {
- + int idx;
- + for (idx = 0; idx < chat->participants_count; idx++)
- + if (chat->participants[idx] == participant)
- + break;
- + if (chat->participants_count > 1 && idx < chat->participants_count)
- + chat->participants[idx] = chat->participants[chat->participants_count - 1];
- + if (idx < chat->participants_count) {
- + chat->participants_count--;
- + chat->participants = realloc(chat->participants, sizeof(uin_t) * chat->participants_count);
- + }
- + }
- + }
- +
- + ge->type = GG_EVENT_CHAT_INFO_UPDATE;
- + ge->event.chat_info_update.id = id;
- + ge->event.chat_info_update.type = update_type;
- + ge->event.chat_info_update.participant = participant;
- + ge->event.chat_info_update.inviter = inviter;
- + ge->event.chat_info_update.version = version;
- + ge->event.chat_info_update.time = time;
- +
- + return 0;
- +fail:
- + return -1;
- +}
- +
- +static int gg_session_handle_chat_created(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + uint64_t id;
- + uint32_t seq;
- +
- + int offset = 0;
- +
- + if (offset + 8 > len)
- + goto fail;
- + id = gg_fix64(*((uint64_t*)(ptr + offset)));
- + offset += 8;
- +
- + if (offset + 4 > len)
- + goto fail;
- + seq = gg_fix32(*((uint64_t*)(ptr + offset)));
- + offset += 4;
- +
- + if (0 != gg_chat_update(gs, id, 0, &gs->uin, 1))
- + goto fail;
- +
- + ge->type = GG_EVENT_CHAT_CREATED;
- + ge->event.chat_created.id = id;
- + ge->event.chat_created.seq = seq;
- +
- + return 0;
- +fail:
- + return -1;
- +}
- +
- +static int gg_session_handle_chat_invite_ack(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + uint64_t id;
- + uint32_t seq;
- +
- + int offset = 0;
- +
- + if (offset + 8 > len)
- + goto fail;
- + id = gg_fix64(*((uint64_t*)(ptr + offset)));
- + offset += 8;
- +
- + if (offset + 4 > len)
- + goto fail;
- + seq = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + ge->type = GG_EVENT_CHAT_INVITE_ACK;
- + ge->event.chat_invite_ack.id = id;
- + ge->event.chat_invite_ack.seq = seq;
- +
- + /* 0x10 00 00 00 00 00 00 00 */
- + offset += 8;
- +
- + return 0;
- +fail:
- + return -1;
- +}
- +
- +static int gg_session_handle_chat_send_msg_ack(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + uint16_t seq;
- + uint32_t time;
- +
- + int offset = 0;
- +
- + if (offset + 3 > len)
- + goto fail;
- + /* 0x08 02 10 */
- + offset += 3;
- +
- + if (offset + 2 > len)
- + goto fail;
- + offset += gg_packed_int_read(ptr + offset, &seq);
- +
- + if (offset + 1 > len)
- + goto fail;
- + /* 0x1d */
- + offset += 1;
- +
- + if (offset + 4 > len)
- + goto fail;
- + time = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + ge->type = GG_EVENT_CHAT_SEND_MSG_ACK;
- + ge->event.chat_send_msg_ack.seq = seq;
- + ge->event.chat_send_msg_ack.time = time;
- +
- + /* 0x21 02 10 xx 00 <time:4> 29 xx 10 00 00 <time:4> 38 00 */
- + offset += 5 + 4 + 5 + 4 + 2;
- +
- + return 0;
- +fail:
- + return -1;
- +}
- +
- +static int gg_session_handle_chat_left(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
- +{
- + uint64_t id;
- + uint32_t uin;
- +
- + int offset = 0;
- +
- + if (offset + 8 > len)
- + goto fail;
- + id = gg_fix64(*((uint64_t*)(ptr + offset)));
- + offset += 8;
- +
- + /* Właściwie, to nie wiadomo, czy to jest "osoba wychodząca", czy
- + * "osoba wyrzucająca nas" z konferencji. */
- + if (offset + 4 > len)
- + goto fail;
- + uin = gg_fix32(*((uint32_t*)(ptr + offset)));
- + offset += 4;
- +
- + ge->type = GG_EVENT_CHAT_INFO_UPDATE;
- + ge->event.chat_info_update.id = id;
- + ge->event.chat_info_update.type = GG_CHAT_INFO_UPDATE_EXITED;
- + ge->event.chat_info_update.participant = uin;
- + ge->event.chat_info_update.inviter = uin;
- + ge->event.chat_info_update.version = 0;
- + ge->event.chat_info_update.time = time(NULL);
- +
- + return 0;
- +fail:
- + return -1;
- +}
- +
- /**
- * \internal Tablica obsługiwanych pakietów
- */
- @@ -1772,6 +2625,7 @@
- { GG_WELCOME, GG_STATE_READING_KEY, 0, gg_session_handle_welcome },
- { GG_LOGIN_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
- { GG_LOGIN80_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
- + { GG_LOGIN110_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login110_ok },
- { GG_NEED_EMAIL, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
- { GG_LOGIN_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed },
- { GG_LOGIN80_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed },
- @@ -1780,6 +2634,7 @@
- { GG_DISCONNECTING, GG_STATE_CONNECTED, 0, gg_session_handle_disconnecting },
- { GG_DISCONNECT_ACK, GG_STATE_DISCONNECTING, 0, gg_session_handle_disconnect_ack },
- { GG_XML_EVENT, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event },
- + { GG_EVENT110, GG_STATE_CONNECTED, 0, gg_session_handle_event110 },
- { GG_PUBDIR50_REPLY, GG_STATE_CONNECTED, 0, gg_session_handle_pubdir50_reply },
- { GG_USERLIST_REPLY, GG_STATE_CONNECTED, 0, gg_session_handle_userlist_reply },
- { GG_DCC7_ID_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_id_reply), gg_session_handle_dcc7_id_reply },
- @@ -1789,6 +2644,8 @@
- { GG_DCC7_INFO, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_info), gg_session_handle_dcc7_info },
- { GG_RECV_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg), gg_session_handle_recv_msg },
- { GG_RECV_MSG80, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
- + { GG_RECV_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
- + { GG_RECV_OWN_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
- { GG_STATUS, GG_STATE_CONNECTED, sizeof(struct gg_status), gg_session_handle_status },
- { GG_STATUS60, GG_STATE_CONNECTED, sizeof(struct gg_status60), gg_session_handle_status_60_77_80beta },
- { GG_STATUS77, GG_STATE_CONNECTED, sizeof(struct gg_status77), gg_session_handle_status_60_77_80beta },
- @@ -1806,6 +2663,16 @@
- { 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 },
- + { GG_IMTOKEN, GG_STATE_CONNECTED, 0, gg_session_handle_imtoken },
- + { GG_PONG110, GG_STATE_CONNECTED, sizeof(struct gg_pong110), gg_session_handle_pong110 },
- + { GG_CHAT_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_chat_info },
- + { GG_CHAT_INFO_UPDATE, GG_STATE_CONNECTED, 0, gg_session_handle_chat_info_update },
- + { GG_CHAT_CREATED, GG_STATE_CONNECTED, 0, gg_session_handle_chat_created },
- + { GG_CHAT_INVITE_ACK, GG_STATE_CONNECTED, 0, gg_session_handle_chat_invite_ack },
- + { GG_CHAT_SEND_MSG_ACK, GG_STATE_CONNECTED, 0, gg_session_handle_chat_send_msg_ack },
- + { GG_CHAT_RECV_MSG, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
- + { GG_CHAT_RECV_OWN_MSG, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
- + { GG_CHAT_LEFT, GG_STATE_CONNECTED, 0, gg_session_handle_chat_left },
- };
- /**
- Index: src/events.c
- ===================================================================
- --- src/events.c (wersja 1323)
- +++ src/events.c (kopia robocza)
- @@ -133,6 +133,11 @@
- free(e->event.xml_event.data);
- break;
- + case GG_EVENT_JSON_EVENT:
- + free(e->event.json_event.data);
- + free(e->event.json_event.type);
- + break;
- +
- case GG_EVENT_USER_DATA:
- {
- unsigned int i, j;
- @@ -166,6 +171,14 @@
- case GG_EVENT_USERLIST100_REPLY:
- free(e->event.userlist100_reply.reply);
- break;
- +
- + case GG_EVENT_IMTOKEN:
- + free(e->event.imtoken.imtoken);
- + break;
- +
- + case GG_EVENT_CHAT_INFO:
- + free(e->event.chat_info.participants);
- + break;
- }
- free(e);
- Index: src/libgadu.c
- ===================================================================
- --- src/libgadu.c (wersja 1323)
- +++ src/libgadu.c (kopia robocza)
- @@ -954,6 +954,7 @@
- void gg_free_session(struct gg_session *sess)
- {
- struct gg_dcc7 *dcc;
- + struct gg_chat_list *chat;
- gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_free_session(%p);\n", sess);
- @@ -1003,6 +1004,14 @@
- for (dcc = sess->dcc7_list; dcc; dcc = dcc->next)
- dcc->sess = NULL;
- + chat = sess->chat_list;
- + while (chat) {
- + struct gg_chat_list *next = chat->next;
- + free(chat->participants);
- + free(chat);
- + chat = next;
- + }
- +
- free(sess);
- }
- @@ -1074,10 +1083,28 @@
- p.status = gg_fix32(status);
- p.flags = gg_fix32(sess->status_flags);
- p.description_size = gg_fix32(descr_len);
- - res = gg_send_packet(sess, GG_NEW_STATUS80,
- - &p, sizeof(p),
- - (new_descr) ? new_descr : descr, descr_len,
- +
- + if (sess->protocol_version >= 0x2f) {
- + uint8_t dummy1[4] = { 0x00, 0x00, 0x00, 0x00 };
- + const char *set_descr = "";
- +
- + if (new_descr)
- + set_descr = new_descr;
- + else if (descr)
- + set_descr = descr;
- +
- + p.flags = gg_fix32(0x00000014);
- + res = gg_send_packet(sess, GG_NEW_STATUS105,
- + &p, sizeof(p),
- + set_descr, descr_len,
- + dummy1, sizeof(dummy1),
- NULL);
- + } else {
- + res = gg_send_packet(sess, GG_NEW_STATUS80,
- + &p, sizeof(p),
- + new_descr ? new_descr : descr, descr_len,
- + NULL);
- + }
- free(new_descr);
- @@ -1137,6 +1164,87 @@
- #ifndef DOXYGEN
- +static int gg_send_message_gg11(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const char *message, const char *html_message)
- +{
- + uint8_t dummy1 = 0x0a;
- + uint8_t uin_len;
- + uint8_t uin_s[20];
- + uint8_t dummy2[3] = { 0x10, 0x08, 0x18 };
- + uint8_t seq_b[2];
- + int seq_len;
- + uint8_t dummy3 = 0x2a;
- + uint8_t message_len_b[2];
- + int message_len_len;
- + uint8_t dummy4 = 0x32;
- + uint8_t html_message_len_b[2];
- + int html_message_len_len;
- +
- + int message_len, html_message_len;
- + int seq = ++sess->seq;
- + char *html_message_gen = NULL, *plain_message_gen = NULL;
- +
- + if (message == NULL && html_message == NULL)
- + goto fail;
- +
- +
- + if (html_message) {
- + if (sess->encoding != GG_ENCODING_UTF8) {
- + html_message = html_message_gen = gg_encoding_convert(html_message, sess->encoding, GG_ENCODING_UTF8, -1, -1);
- + if (html_message_gen == NULL)
- + goto fail;
- + }
- +
- + message = plain_message_gen = gg_message_html_to_text_gg11(html_message);
- + if (plain_message_gen == NULL)
- + goto fail;
- + } else {
- + if (sess->encoding != GG_ENCODING_UTF8) {
- + message = plain_message_gen = gg_encoding_convert(message, sess->encoding, GG_ENCODING_UTF8, -1, -1);
- + if (plain_message_gen == NULL)
- + goto fail;
- + }
- +
- + html_message = html_message_gen = gg_message_text_to_html_gg11(message);
- + if (html_message_gen == NULL)
- + goto fail;
- + }
- +
- + uin_len = gg_packed_uin_write(uin_s, sizeof(uin_s), recipients[0], 1);
- + if (uin_len <= 0)
- + goto fail;
- +
- + message_len = strlen(message);
- + html_message_len = strlen(html_message);
- + seq_len = gg_packed_int_write(seq_b, seq);
- + message_len_len = gg_packed_int_write(message_len_b, message_len);
- + html_message_len_len = gg_packed_int_write(html_message_len_b, html_message_len);
- +
- + if (gg_send_packet(sess,
- + GG_SEND_MSG110,
- + &dummy1, sizeof(dummy1),
- + uin_s, uin_len,
- + dummy2, sizeof(dummy2),
- + seq_b, seq_len,
- + &dummy3, sizeof(dummy3),
- + message_len_b, message_len_len,
- + message, message_len,
- + &dummy4, sizeof(dummy4),
- + html_message_len_b, html_message_len_len,
- + html_message, html_message_len,
- + NULL) == -1)
- + {
- + goto fail;
- + }
- +
- + free(html_message_gen);
- + free(plain_message_gen);
- + return seq;
- +fail:
- + free(html_message_gen);
- + free(plain_message_gen);
- + return -1;
- +}
- +
- /**
- * \internal Wysyła wiadomość.
- *
- @@ -1181,6 +1289,12 @@
- return -1;
- }
- + if (sess->protocol_version >= 0x2f && recipients_count <= 1)
- + {
- + seq_no = gg_send_message_gg11(sess, msgclass, recipients_count, recipients, (const char*)message, (const char*)html_message);
- + goto cleanup;
- + }
- +
- if (message == NULL) {
- char *tmp_msg;
- size_t len, fmt_len;
- @@ -1277,6 +1391,12 @@
- }
- }
- + if (sess->protocol_version >= 0x2f && recipients_count <= 1)
- + {
- + seq_no = gg_send_message_gg11(sess, msgclass, recipients_count, recipients, recoded_msg, recoded_html_msg);
- + goto cleanup;
- + }
- +
- /* Drobne odchylenie od protokołu. Jeśli wysyłamy kilka
- * wiadomości w ciągu jednej sekundy, zwiększamy poprzednią
- * wartość, żeby każda wiadomość miała unikalny numer.
- @@ -1697,6 +1817,43 @@
- return res;
- }
- +static int gg_notify105_ex(struct gg_session *sess, uin_t *userlist, char *types, int count)
- +{
- + int res = 0;
- +
- + if (!userlist || !count)
- + return gg_send_packet(sess, GG_NOTIFY105_LIST_EMPTY, NULL);
- +
- + gg_debug_session(sess, GG_DEBUG_FUNCTION, "TOMO: gg_notify105_ex\n");
- +
- + while (count > 0) {
- + uint8_t buff[2048];
- + int offset = 0;
- + uint8_t uin_len;
- + int packet_type;
- +
- + while (count > 0) {
- + uin_len = gg_packed_uin_write(buff + offset, sizeof(buff) - offset - 1, *userlist, 0);
- + if (uin_len <= 0)
- + break;
- + offset += uin_len;
- + buff[offset++] = *types;
- +
- + userlist++;
- + types++;
- + count--;
- + }
- +
- + packet_type = (count > 0) ? GG_NOTIFY105_FIRST : GG_NOTIFY105_LAST;
- + if (gg_send_packet(sess, packet_type, buff, offset, NULL) == -1) {
- + res = -1;
- + break;
- + }
- + }
- +
- + return res;
- +}
- +
- /**
- * Wysyła do serwera listę kontaktów.
- *
- @@ -1736,6 +1893,9 @@
- return -1;
- }
- + if (sess->protocol_version >= 0x2f)
- + return gg_notify105_ex(sess, userlist, types, count);
- +
- if (!userlist || !count)
- return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
- @@ -1790,57 +1950,19 @@
- */
- int gg_notify(struct gg_session *sess, uin_t *userlist, int count)
- {
- - struct gg_notify *n;
- - uin_t *u;
- - int i, res = 0;
- + char *types;
- + int ret;
- - gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count);
- -
- - if (!sess) {
- - errno = EFAULT;
- + types = malloc(count);
- + memset(types, GG_USER_NORMAL, count);
- + if (sess->recv_buf == NULL)
- return -1;
- - }
- - if (sess->state != GG_STATE_CONNECTED) {
- - errno = ENOTCONN;
- - return -1;
- - }
- + ret = gg_notify_ex(sess, userlist, types, count);
- - if (!userlist || !count)
- - return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
- + free(types);
- - while (count > 0) {
- - int part_count, packet_type;
- -
- - if (count > 400) {
- - part_count = 400;
- - packet_type = GG_NOTIFY_FIRST;
- - } else {
- - part_count = count;
- - packet_type = GG_NOTIFY_LAST;
- - }
- -
- - if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count)))
- - return -1;
- -
- - for (u = userlist, i = 0; i < part_count; u++, i++) {
- - n[i].uin = gg_fix32(*u);
- - n[i].dunno1 = GG_USER_NORMAL;
- - }
- -
- - if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) {
- - res = -1;
- - free(n);
- - break;
- - }
- -
- - free(n);
- -
- - userlist += part_count;
- - count -= part_count;
- - }
- -
- - return res;
- + return ret;
- }
- /**
- @@ -1860,8 +1982,6 @@
- */
- int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type)
- {
- - struct gg_add_remove a;
- -
- gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type);
- if (!sess) {
- @@ -1874,10 +1994,26 @@
- return -1;
- }
- - a.uin = gg_fix32(uin);
- - a.dunno1 = type;
- + if (sess->protocol_version >= 0x2f) {
- + uint8_t uin_len;
- + uint8_t uin_s[15];
- - return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
- + uin_len = gg_packed_uin_write(uin_s, sizeof(uin_s), uin, 0);
- + if (uin_len <= 0)
- + return -1;
- +
- + return gg_send_packet(sess, GG_ADD_NOTIFY105,
- + uin_s, uin_len,
- + &type, sizeof(type),
- + NULL);
- + } else {
- + struct gg_add_remove a;
- +
- + a.uin = gg_fix32(uin);
- + a.dunno1 = type;
- +
- + return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
- + }
- }
- /**
- @@ -1913,8 +2049,6 @@
- */
- int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type)
- {
- - struct gg_add_remove a;
- -
- gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type);
- if (!sess) {
- @@ -1927,10 +2061,26 @@
- return -1;
- }
- - a.uin = gg_fix32(uin);
- - a.dunno1 = type;
- + if (sess->protocol_version >= 0x2f) {
- + uint8_t uin_len;
- + uint8_t uin_s[15];
- - return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL);
- + uin_len = gg_packed_uin_write(uin_s, sizeof(uin_s), uin, 0);
- + if (uin_len <= 0)
- + return -1;
- +
- + return gg_send_packet(sess, GG_REMOVE_NOTIFY105,
- + uin_s, uin_len,
- + &type, sizeof(type),
- + NULL);
- + } else {
- + struct gg_add_remove a;
- +
- + a.uin = gg_fix32(uin);
- + a.dunno1 = type;
- +
- + return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL);
- + }
- }
- /**
- @@ -2118,6 +2268,163 @@
- return gg_send_packet(gs, GG_MULTILOGON_DISCONNECT, &pkt, sizeof(pkt), NULL);
- }
- +int gg_chat_create(struct gg_session *gs)
- +{
- + int seq = ++gs->seq;
- + uint32_t raw_seq = gg_fix32(seq);
- + uint32_t dummy = 0x00;
- +
- + if (gg_send_packet(gs,
- + GG_CHAT_CREATE,
- + &raw_seq, sizeof(raw_seq),
- + &dummy, sizeof(dummy),
- + NULL) == -1)
- + {
- + return -1;
- + }
- +
- + return seq;
- +}
- +
- +int gg_chat_invite(struct gg_session *gs, uint64_t id, uin_t *participants, int participants_count)
- +{
- + uint8_t *participants_list = NULL;
- + int seq = ++gs->seq;
- + uint32_t raw_seq = gg_fix32(seq);
- + uint32_t raw_participants_count = gg_fix32(participants_count);
- +
- + int i, offset;
- +
- + if (participants_count <= 0)
- + goto fail;
- +
- + participants_list = malloc(8 * participants_count);
- + if (participants_list == NULL)
- + goto fail;
- +
- + id = gg_fix64(id);
- +
- + offset = 0;
- + for (i = 0; i < participants_count; i++)
- + {
- + uint32_t *participant = (uint32_t*)(participants_list + offset);
- + offset += 8;
- +
- + participant[0] = gg_fix32(participants[i]);
- + participant[1] = gg_fix32(0x1e);
- + }
- +
- + if (gg_send_packet(gs,
- + GG_CHAT_INVITE,
- + &id, sizeof(id),
- + &raw_seq, sizeof(raw_seq),
- + &raw_participants_count, sizeof(raw_participants_count),
- + participants_list, 8 * participants_count,
- + NULL) == -1)
- + {
- + goto fail;
- + }
- +
- + free(participants_list);
- + return seq;
- +
- +fail:
- + free(participants_list);
- + return -1;
- +}
- +
- +int gg_chat_leave(struct gg_session *gs, uint64_t id)
- +{
- + int seq = ++gs->seq;
- + uint32_t raw_seq = gg_fix32(seq);
- +
- + id = gg_fix64(id);
- +
- + return gg_send_packet(gs,
- + GG_CHAT_LEAVE,
- + &id, sizeof(id),
- + &raw_seq, sizeof(raw_seq),
- + NULL);
- +}
- +
- +int gg_chat_send_message(struct gg_session *gs, uint64_t id, const char *message, int is_html)
- +{
- + uint8_t dummy1[3] = { 0x10, 0x08, 0x18 };
- + uint8_t seq_b[2];
- + int seq_len;
- + uint8_t dummy2 = 0x2a;
- + uint8_t message_plain_len_b[2];
- + int message_plain_len_len;
- + uint8_t dummy3 = 0x32;
- + uint8_t message_html_len_b[2];
- + int message_html_len_len;
- + uint8_t dummy4[3] = { 0x3a, 0x00, 0x51 };
- +
- + int seq = ++gs->seq;
- + const char *message_plain, *message_html;
- + char *message_html_gen = NULL, *message_plain_gen = NULL;
- + size_t message_plain_len, message_html_len;
- +
- + seq_len = gg_packed_int_write(seq_b, seq);
- + id = gg_fix64(id);
- +
- + if (is_html) {
- + message_html = message;
- +
- + if (gs->encoding != GG_ENCODING_UTF8) {
- + message_html = message_html_gen = gg_encoding_convert(message_html, gs->encoding, GG_ENCODING_UTF8, -1, -1);
- + if (message_html_gen == NULL)
- + goto fail;
- + }
- +
- + message_plain = message_plain_gen = gg_message_html_to_text_gg11(message_html);
- + if (message_plain_gen == NULL)
- + goto fail;
- + } else {
- + message_plain = message;
- +
- + if (gs->encoding != GG_ENCODING_UTF8) {
- + message_plain = message_plain_gen = gg_encoding_convert(message_plain, gs->encoding, GG_ENCODING_UTF8, -1, -1);
- + if (message_plain_gen == NULL)
- + goto fail;
- + }
- +
- + message_html = message_html_gen = gg_message_text_to_html_gg11(message_plain);
- + if (message_html_gen == NULL)
- + goto fail;
- + }
- +
- + message_html_len = strlen(message_html);
- + message_html_len_len = gg_packed_int_write(message_html_len_b, message_html_len);
- + message_plain_len = strlen(message_plain);
- + message_plain_len_len = gg_packed_int_write(message_plain_len_b, message_plain_len);
- +
- + if (gg_send_packet(gs,
- + GG_CHAT_SEND_MSG,
- + dummy1, sizeof(dummy1),
- + seq_b, seq_len,
- + &dummy2, sizeof(dummy2),
- + message_plain_len_b, message_plain_len_len,
- + message_plain, message_plain_len,
- + &dummy3, sizeof(dummy3),
- + message_html_len_b, message_html_len_len,
- + message_html, message_html_len,
- + dummy4, sizeof(dummy4),
- + &id, sizeof(id),
- + NULL) == -1)
- + {
- + goto fail;
- + }
- +
- + free(message_html_gen);
- + free(message_plain_gen);
- + return 0;
- +fail:
- + free(message_html_gen);
- + free(message_plain_gen);
- + return -1;
- +}
- +
- /* @} */
- /**
- Index: src/message.c
- ===================================================================
- --- src/message.c (wersja 1323)
- +++ src/message.c (kopia robocza)
- @@ -896,3 +896,80 @@
- return len;
- }
- +
- +static size_t gg_message_html_to_text_gg11_buff(char *dst, const char *html)
- +{
- + return gg_message_html_to_text(dst, NULL, NULL, html, GG_ENCODING_UTF8) + 1;
- +}
- +
- +static size_t gg_message_text_to_html_gg11_buff(char *dst, const char *text)
- +{
- + size_t i, dst_len, src_len;
- +
- + src_len = strlen(text);
- + dst_len = 0;
- +
- + gg_append(dst, &dst_len, "<span>", 6);
- +
- + for (i = 0; i < src_len; i++)
- + {
- + char c = text[i];
- + if (c == '<')
- + gg_append(dst, &dst_len, "<", 4);
- + else if (c == '>')
- + gg_append(dst, &dst_len, ">", 4);
- + else if (c == '&')
- + gg_append(dst, &dst_len, "&", 5);
- + else if (c == '"')
- + gg_append(dst, &dst_len, """, 6);
- + else if (c == '\'')
- + gg_append(dst, &dst_len, "'", 6);
- + else if (c == '\n')
- + gg_append(dst, &dst_len, "<br>", 4);
- + else if (c == '\r')
- + continue;
- + else if (c == '\xc2' && text[i + 1] == '\xa0') {
- + gg_append(dst, &dst_len, " ", 6);
- + i++;
- + } else {
- + if (dst)
- + dst[dst_len] = c;
- + dst_len++;
- + }
- + }
- +
- + gg_append(dst, &dst_len, "</span>", 7);
- +
- + if (dst)
- + dst[dst_len] = '\0';
- + dst_len++;
- + return dst_len;
- +}
- +
- +char * gg_message_html_to_text_gg11(const char *html)
- +{
- + size_t dst_len;
- + char *dst;
- +
- + dst_len = gg_message_html_to_text_gg11_buff(NULL, html);
- + dst = malloc(dst_len);
- + if (!dst)
- + return NULL;
- + gg_message_html_to_text_gg11_buff(dst, html);
- +
- + return dst;
- +}
- +
- +char * gg_message_text_to_html_gg11(const char *text)
- +{
- + size_t dst_len;
- + char *dst;
- +
- + dst_len = gg_message_text_to_html_gg11_buff(NULL, text);
- + dst = malloc(dst_len);
- + if (!dst)
- + return NULL;
- + gg_message_text_to_html_gg11_buff(dst, text);
- +
- + return dst;
- +}
- Index: src/debug.c
- ===================================================================
- --- src/debug.c (wersja 1323)
- +++ src/debug.c (kopia robocza)
- @@ -349,6 +349,7 @@
- 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_JSON_EVENT)
- GG_DEBUG_EVENT(GG_EVENT_DISCONNECT_ACK)
- GG_DEBUG_EVENT(GG_EVENT_TYPING_NOTIFICATION)
- GG_DEBUG_EVENT(GG_EVENT_USER_DATA)
- @@ -356,6 +357,13 @@
- GG_DEBUG_EVENT(GG_EVENT_MULTILOGON_INFO)
- GG_DEBUG_EVENT(GG_EVENT_USERLIST100_VERSION)
- GG_DEBUG_EVENT(GG_EVENT_USERLIST100_REPLY)
- + GG_DEBUG_EVENT(GG_EVENT_IMTOKEN)
- + GG_DEBUG_EVENT(GG_EVENT_PONG110)
- + GG_DEBUG_EVENT(GG_EVENT_CHAT_INFO)
- + GG_DEBUG_EVENT(GG_EVENT_CHAT_INFO_UPDATE)
- + GG_DEBUG_EVENT(GG_EVENT_CHAT_CREATED)
- + GG_DEBUG_EVENT(GG_EVENT_CHAT_INVITE_ACK)
- + GG_DEBUG_EVENT(GG_EVENT_CHAT_SEND_MSG_ACK)
- #undef GG_DEBUG_EVENT
- /* Celowo nie ma default, żeby kompilator wyłapał brakujące zdarzenia */
- Index: src/common.c
- ===================================================================
- --- src/common.c (wersja 1323)
- +++ src/common.c (kopia robocza)
- @@ -38,6 +38,7 @@
- #include "config.h"
- #include "libgadu.h"
- +#include "internal.h"
- #ifndef GG_CONFIG_HAVE_VA_COPY
- # ifdef GG_CONFIG_HAVE___VA_COPY
- @@ -680,6 +681,151 @@
- return crc ^ 0xffffffffL;
- }
- +uin_t gg_str_to_uin(const char *str, int len)
- +{
- + char buff[11];
- + char *endptr;
- + uin_t uin;
- +
- + if (len < 0)
- + len = strlen(str);
- + if (len > 10)
- + return 0;
- + memcpy(buff, str, len);
- + buff[len] = '\0';
- +
- + errno = 0;
- + uin = strtoul(buff, &endptr, 10);
- + if (errno == ERANGE || endptr[0] != '\0')
- + return 0;
- +
- + return uin;
- +}
- +
- +int gg_packed_int_read(const char *data, uint16_t *dst)
- +{
- + uint16_t val;
- + uint8_t raw;
- +
- + raw = *data;
- + data++;
- + if (!(raw & 0x80))
- + {
- + *dst = raw;
- + return 1;
- + }
- +
- + val = raw & ~0x80;
- + raw = *data;
- + val |= (uint16_t)raw << 7;
- + *dst = val;
- + return 2;
- +}
- +
- +int gg_packed_int_write(uint8_t dst[2], uint16_t val)
- +{
- + if (val < 0x80)
- + {
- + dst[0] = val;
- + return 1;
- + }
- +
- + dst[0] = (val & 0x7F) | 0x80;
- + dst[1] = (val >> 7);
- + return 2;
- +}
- +
- +int gg_packed_uin_read(uin_t *dst, const char *data, int length)
- +{
- + uint8_t full_len, uin_len;
- + uint8_t uin_type;
- +
- + int offset = 0;
- + *dst = 0;
- +
- + if (length < 1)
- + return 0;
- + full_len = data[offset++] + 1;
- + if (full_len > length)
- + return full_len;
- + uin_type = data[offset++];
- + if (uin_type != 0)
- + return full_len;
- + uin_len = data[offset++];
- + if (offset + uin_len > length)
- + return full_len;
- +
- + *dst = gg_str_to_uin(data + offset, uin_len);
- + return full_len;
- +}
- +
- +int gg_packed_uin_write(uint8_t *dst, int size, uin_t uin, int variant_long)
- +{
- + char buff[20];
- + int uin_len;
- + int buff_len;
- + int offset = 0;
- +
- + snprintf(buff, sizeof(buff), "%u", uin);
- + uin_len = strlen(buff);
- + buff_len = uin_len + 2;
- + if (variant_long)
- + buff_len++;
- + if (buff_len > size)
- + return 0;
- + if (variant_long)
- + dst[offset++] = uin_len + 2;
- + dst[offset++] = 0x00;
- + dst[offset++] = uin_len;
- + memcpy(dst + offset, buff, uin_len);
- +
- + return buff_len;
- +}
- +
- +struct gg_chat_list * gg_chat_find(struct gg_session *sess, uint64_t id)
- +{
- + struct gg_chat_list * chat_list = sess->chat_list;
- + while (chat_list)
- + {
- + if (chat_list->id == id)
- + return chat_list;
- + chat_list = chat_list->next;
- + }
- + return NULL;
- +}
- +
- +int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version, const uin_t *participants, int participants_count)
- +{
- + struct gg_chat_list *chat;
- +
- + chat = gg_chat_find(sess, id);
- + if (!chat) {
- + struct gg_chat_list *last = sess->chat_list;
- + chat = malloc(sizeof(struct gg_chat_list));
- + if (!chat)
- + return -1;
- + memset(chat, 0, sizeof(struct gg_chat_list));
- + if (last == NULL)
- + sess->chat_list = chat;
- + else {
- + while (last->next != NULL)
- + last = last->next;
- + last->next = chat;
- + }
- + chat->id = id;
- + }
- + chat->version = version;
- + chat->participants_count = participants_count;
- + chat->participants = realloc(chat->participants, sizeof(uin_t) * participants_count);
- + if (chat->participants == NULL) {
- + chat->participants_count = 0;
- + return -1;
- + }
- + memcpy(chat->participants, participants, sizeof(uin_t) * participants_count);
- +
- + return 0;
- +}
- +
- /*
- * Local variables:
- * c-indentation-style: k&r
- Index: src/libgadu.sym
- ===================================================================
- --- src/libgadu.sym (wersja 1323)
- +++ src/libgadu.sym (kopia robocza)
- @@ -13,6 +13,10 @@
- gg_change_status_descr
- gg_change_status_descr_time
- gg_change_status_flags
- +gg_chat_create
- +gg_chat_invite
- +gg_chat_leave
- +gg_chat_send_message
- gg_chomp
- gg_connect
- gg_crc32
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement