Advertisement
tomkiewicz

gg11-2

Sep 11th, 2012
284
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 55.16 KB | None | 0 0
  1. Index: include/internal.h
  2. ===================================================================
  3. --- include/internal.h  (wersja 1323)
  4. +++ include/internal.h  (kopia robocza)
  5. @@ -40,6 +40,8 @@
  6.  
  7.  int gg_login_hash_sha1_2(const char *password, uint32_t seed, uint8_t *result);
  8.  
  9. +int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version, const uin_t *participants, int participants_count);
  10. +
  11.  #ifdef HAVE_UINT64_T
  12.  uint64_t gg_fix64(uint64_t x);
  13.  #endif
  14. Index: include/libgadu.h.in
  15. ===================================================================
  16. --- include/libgadu.h.in    (wersja 1323)
  17. +++ include/libgadu.h.in    (kopia robocza)
  18. @@ -179,6 +179,8 @@
  19.  
  20.  struct gg_dcc7_relay;
  21.  
  22. +struct gg_chat_list;
  23. +
  24.  /**
  25.   * Sposób rozwiązywania nazw serwerów.
  26.   */
  27. @@ -310,6 +312,8 @@
  28.  
  29.     char *connect_host;         /**< Adres serwera Gadu-Gadu, z którym się łączymy */
  30.     gg_ssl_t ssl_flag;          /**< Flaga połączenia szyfrowanego */
  31. +
  32. +   struct gg_chat_list *chat_list;
  33.  };
  34.  
  35.  /**
  36. @@ -676,6 +680,11 @@
  37.  int gg_typing_notification(struct gg_session *sess, uin_t recipient, int length);
  38.  
  39.  uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len);
  40. +uin_t gg_str_to_uin(const char *str, int len);
  41. +int gg_packed_int_read(const char *data, uint16_t *dst);
  42. +int gg_packed_int_write(uint8_t dst[2], uint16_t val);
  43. +int gg_packed_uin_read(uin_t *dst, const char *data, int length);
  44. +int gg_packed_uin_write(uint8_t *dst, int size, uin_t uin, int variant_long);
  45.  
  46.  int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type);
  47.  gg_resolver_t gg_session_get_resolver(struct gg_session *gs);
  48. @@ -691,6 +700,11 @@
  49.  
  50.  int gg_multilogon_disconnect(struct gg_session *gs, gg_multilogon_id_t conn_id);
  51.  
  52. +int gg_chat_create(struct gg_session *gs);
  53. +int gg_chat_invite(struct gg_session *gs, uint64_t id, uin_t *participants, int participants_count);
  54. +int gg_chat_leave(struct gg_session *gs, uint64_t id);
  55. +int gg_chat_send_message(struct gg_session *gs, uint64_t id, const char *message, int is_html);
  56. +
  57.  /**
  58.   * Rodzaj zdarzenia.
  59.   *
  60. @@ -746,6 +760,16 @@
  61.  
  62.     GG_EVENT_USERLIST100_VERSION,   /**< Otrzymano numer wersji listy kontaktów na serwerze (10.0) */
  63.     GG_EVENT_USERLIST100_REPLY, /**< Wynik importu lub eksportu listy kontaktów (10.0) */
  64. +
  65. +   GG_EVENT_IMTOKEN /* = 43 */,
  66. +   GG_EVENT_PONG110,
  67. +   GG_EVENT_JSON_EVENT,
  68. +  
  69. +   GG_EVENT_CHAT_INFO,
  70. +   GG_EVENT_CHAT_INFO_UPDATE,
  71. +   GG_EVENT_CHAT_CREATED,
  72. +   GG_EVENT_CHAT_INVITE_ACK,
  73. +   GG_EVENT_CHAT_SEND_MSG_ACK,
  74.  };
  75.  
  76.  #define GG_EVENT_SEARCH50_REPLY GG_EVENT_PUBDIR50_SEARCH_REPLY
  77. @@ -849,6 +873,7 @@
  78.     uint32_t seq;       /**< Numer sekwencyjny wiadomości */
  79.  
  80.     char *xhtml_message;    /**< Treść wiadomości w formacie XHTML */
  81. +   uint64_t chat_id;
  82.  };
  83.  
  84.  /**
  85. @@ -957,6 +982,14 @@
  86.  };
  87.  
  88.  /**
  89. + * Opis zdarzenia \c GG_EVENT_JSON_EVENT.
  90. + */
  91. +struct gg_event_json_event {
  92. +   char *data;     /**< Bufor z komunikatem */
  93. +   char *type;     /**< Bufor z typem komunikatu */
  94. +};
  95. +
  96. +/**
  97.   * Opis zdarzenia \c GG_EVENT_DCC7_CONNECTED.
  98.   */
  99.  struct gg_event_dcc7_connected {
  100. @@ -1071,6 +1104,45 @@
  101.     char *reply;            /**< Treść listy kontaktów w przesyłanej wersji i formacie */
  102.  };
  103.  
  104. +struct gg_event_imtoken {
  105. +   char *imtoken;
  106. +};
  107. +
  108. +struct gg_event_pong110 {
  109. +   time_t time;
  110. +};
  111. +
  112. +struct gg_event_chat_info {
  113. +   uint64_t id;
  114. +   uint32_t version;
  115. +   uint32_t participants_count;
  116. +   uin_t *participants;
  117. +};
  118. +
  119. +struct gg_event_chat_info_update {
  120. +   uint64_t id;
  121. +   uint32_t type;
  122. +   uin_t participant;
  123. +   uin_t inviter;
  124. +   uint32_t version;
  125. +   uint32_t time;
  126. +};
  127. +
  128. +struct gg_event_chat_created {
  129. +   uint64_t id;
  130. +   uint32_t seq;
  131. +};
  132. +
  133. +struct gg_event_chat_invite_ack {
  134. +   uint64_t id;
  135. +   uint32_t seq;
  136. +};
  137. +
  138. +struct gg_event_chat_send_msg_ack {
  139. +   uint32_t seq;
  140. +   uint32_t time;
  141. +};
  142. +
  143.  /**
  144.   * Unia wszystkich zdarzeń zwracanych przez funkcje \c gg_watch_fd(),
  145.   * \c gg_dcc_watch_fd() i \c gg_dcc7_watch_fd().
  146. @@ -1091,6 +1163,7 @@
  147.     struct gg_event_userlist userlist;  /**< Odpowiedź listy kontaktów (\c GG_EVENT_USERLIST) */
  148.     gg_pubdir50_t pubdir50; /**< Odpowiedź katalogu publicznego (\c GG_EVENT_PUBDIR50_*) */
  149.     struct gg_event_xml_event xml_event;    /**< Zdarzenie systemowe (\c GG_EVENT_XML_EVENT) */
  150. +   struct gg_event_json_event json_event;  /**< Zdarzenie systemowe (\c GG_EVENT_JSON_EVENT) */
  151.     struct gg_dcc *dcc_new; /**< Nowe połączenie bezpośrednie (\c GG_EVENT_DCC_NEW) */
  152.     enum gg_error_t dcc_error;  /**< Błąd połączenia bezpośredniego (\c GG_EVENT_DCC_ERROR) */
  153.     struct gg_event_dcc_voice_data dcc_voice_data;  /**< Dane połączenia głosowego (\c GG_EVENT_DCC_VOICE_DATA) */
  154. @@ -1107,6 +1180,13 @@
  155.     struct gg_event_multilogon_info multilogon_info;    /**< Informacja o innych sesjach multilogowania (\c GG_EVENT_MULTILOGON_INFO) */
  156.     struct gg_event_userlist100_version userlist100_version;    /**< Informacja o numerze wersji listy kontaktów na serwerze (\c GG_EVENT_USERLIST100_VERSION) */
  157.     struct gg_event_userlist100_reply userlist100_reply;    /**< Odpowiedź listy kontaktów (10.0) (\c GG_EVENT_USERLIST100_REPLY) */
  158. +   struct gg_event_imtoken imtoken;
  159. +   struct gg_event_pong110 pong110;
  160. +   struct gg_event_chat_info chat_info;
  161. +   struct gg_event_chat_info_update chat_info_update;
  162. +   struct gg_event_chat_created chat_created;
  163. +   struct gg_event_chat_invite_ack chat_invite_ack;
  164. +   struct gg_event_chat_send_msg_ack chat_send_msg_ack;
  165.  };
  166.  
  167.  /**
  168. @@ -1573,8 +1653,8 @@
  169.  #define GG_HTTPS_PORT 443
  170.  #define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)"
  171.  
  172. -#define GG_DEFAULT_CLIENT_VERSION "10.1.0.11070"
  173. -#define GG_DEFAULT_PROTOCOL_VERSION 0x2e
  174. +#define GG_DEFAULT_CLIENT_VERSION "11.0.0.8255"
  175. +#define GG_DEFAULT_PROTOCOL_VERSION 0x2f
  176.  #define GG_DEFAULT_TIMEOUT 30
  177.  #define GG_HAS_AUDIO_MASK 0x40000000
  178.  #define GG_HAS_AUDIO7_MASK 0x20000000
  179. @@ -1944,6 +2024,8 @@
  180.  
  181.  #define GG_ADD_NOTIFY 0x000d
  182.  #define GG_REMOVE_NOTIFY 0x000e
  183. +#define GG_ADD_NOTIFY105 0x007b
  184. +#define GG_REMOVE_NOTIFY105 0x007c
  185.  
  186.  struct gg_add_remove {
  187.     uint32_t uin;           /* numerek */
  188. @@ -2085,6 +2167,17 @@
  189.     /* char image[]; */
  190.  } GG_PACKED;
  191.  
  192. +struct gg_chat_list {
  193. +   uint64_t id;
  194. +   uint32_t version;
  195. +   uint32_t participants_count;
  196. +   uin_t *participants;
  197. +
  198. +   struct gg_chat_list *next;
  199. +};
  200. +
  201. +struct gg_chat_list * gg_chat_find(struct gg_session *sess, uint64_t id);
  202. +
  203.  #define GG_SEND_MSG_ACK 0x0005
  204.  
  205.  #ifndef DOXYGEN
  206. @@ -2137,6 +2230,7 @@
  207.  #define GG_USERLIST_REQUEST 0x0016
  208.  
  209.  #define GG_XML_EVENT 0x0027
  210. +#define GG_EVENT110 0x0084
  211.  
  212.  #ifndef DOXYGEN
  213.  
  214. @@ -2355,6 +2449,15 @@
  215.  #define GG_DCC7_TIMEOUT_FILE_ACK 300   /* 5 minut */
  216.  #define GG_DCC7_TIMEOUT_VOICE_ACK 300  /* 5 minut */
  217.  
  218. +#define GG_IMTOKEN 0x008c
  219. +#define GG_NOTIFY105_FIRST 0x0077
  220. +#define GG_NOTIFY105_LAST 0x0078
  221. +#define GG_NOTIFY105_LIST_EMPTY 0x0079
  222. +#define GG_PONG110 0x00a1
  223. +
  224. +#define GG_CHAT_INFO_UPDATE_ENTERED 0x01
  225. +#define GG_CHAT_INFO_UPDATE_EXITED 0x03
  226. +
  227.  #ifdef __cplusplus
  228.  }
  229.  #endif
  230. Index: include/protocol.h
  231. ===================================================================
  232. --- include/protocol.h  (wersja 1323)
  233. +++ include/protocol.h  (kopia robocza)
  234. @@ -32,6 +32,7 @@
  235.  #define GG_LOGIN80BETA 0x0029
  236.  
  237.  #define GG_LOGIN80 0x0031
  238. +#define GG_LOGIN105 0x0083
  239.  
  240.  #undef GG_FEATURE_STATUS80BETA
  241.  #undef GG_FEATURE_MSG80
  242. @@ -42,6 +43,8 @@
  243.  
  244.  #define GG8_LANG   "pl"
  245.  #define GG8_VERSION    "Gadu-Gadu Client Build "
  246. +#define GG11_VERSION   "GG "
  247. +#define GG11_TARGET    " WINNT"
  248.  
  249.  struct gg_login80 {
  250.     uint32_t uin;           /* mój numerek */
  251. @@ -63,6 +66,8 @@
  252.  
  253.  #define GG_LOGIN80_OK 0x0035
  254.  
  255. +#define GG_LOGIN110_OK 0x009d
  256. +
  257.  /**
  258.   * Logowanie powiodło się (pakiet \c GG_LOGIN80_OK)
  259.   */
  260. @@ -92,6 +97,8 @@
  261.     uint32_t description_size;      /**< rozmiar opisu */
  262.  } GG_PACKED;
  263.  
  264. +#define GG_NEW_STATUS105 0x0063
  265. +
  266.  #define GG_STATUS80BETA 0x002a
  267.  #define GG_NOTIFY_REPLY80BETA 0x002b
  268.  
  269. @@ -319,6 +326,37 @@
  270.     /* char reply[]; */
  271.  } GG_PACKED;
  272.  
  273. +struct gg_pong110 {
  274. +   uint8_t dummy;
  275. +   uint32_t time;
  276. +} GG_PACKED;
  277. +
  278. +#define GG_SEND_MSG110 0x007d
  279. +#define GG_RECV_MSG110 0x007e
  280. +#define GG_RECV_OWN_MSG110 0x0082
  281. +#define GG_ACK110 0x0086
  282. +
  283. +#define GG_ACK110_MSG 0x01
  284. +#define GG_ACK110_CHAT 0x02
  285. +#define GG_ACK110_CHAT_INFO 0x03
  286. +#define GG_ACK110_MPA 0x06
  287. +
  288. +#define GG_EVENT110_XML 0x00
  289. +#define GG_EVENT110_JSON 0x02
  290. +
  291. +#define GG_CHAT_INFO 0x0093
  292. +#define GG_CHAT_INFO_UPDATE 0x009e
  293. +#define GG_CHAT_CREATED 0x0045
  294. +#define GG_CHAT_INVITE_ACK 0x0047
  295. +#define GG_CHAT_RECV_MSG 0x0088
  296. +#define GG_CHAT_RECV_OWN_MSG 0x008e
  297. +#define GG_CHAT_CREATE 0x0047
  298. +#define GG_CHAT_INVITE 0x0090
  299. +#define GG_CHAT_LEAVE 0x0052
  300. +#define GG_CHAT_LEFT 0x0066
  301. +#define GG_CHAT_SEND_MSG 0x008d
  302. +#define GG_CHAT_SEND_MSG_ACK 0x0087
  303. +
  304.  #ifdef _WIN32
  305.  #pragma pack(pop)
  306.  #endif
  307. Index: include/message.h
  308. ===================================================================
  309. --- include/message.h   (wersja 1323)
  310. +++ include/message.h   (kopia robocza)
  311. @@ -52,4 +52,7 @@
  312.  size_t gg_message_html_to_text(char *dst, unsigned char *format, size_t *format_len, const char *html, gg_encoding_t encoding);
  313.  size_t gg_message_text_to_html(char *dst, const char *src, gg_encoding_t encoding, const unsigned char *format, size_t format_len);
  314.  
  315. +char * gg_message_html_to_text_gg11(const char *html);
  316. +char * gg_message_text_to_html_gg11(const char *text);
  317. +
  318.  #endif /* LIBGADU_MESSAGE_H */
  319. Index: src/handlers.c
  320. ===================================================================
  321. --- src/handlers.c  (wersja 1323)
  322. +++ src/handlers.c  (kopia robocza)
  323. @@ -61,6 +61,239 @@
  324.     int (*handler)(struct gg_session *, uint32_t, const char *, size_t, struct gg_event *);
  325.  } gg_packet_handler_t;
  326.  
  327. +static int gg_ack_gg11(struct gg_session *gs, uint8_t type, uint16_t seq, struct gg_event *ge)
  328. +{
  329. +   uint8_t dunno1 = 0x08;
  330. +   uint8_t dunno2 = 0x10;
  331. +   uint8_t seq_b[2];
  332. +   int seq_len;
  333. +   uint8_t dunno3[2] = { 0x18, 0x01 };
  334. +   int ret;
  335. +
  336. +   seq_len = gg_packed_int_write(seq_b, seq);
  337. +
  338. +   ret = gg_send_packet(gs,
  339. +           GG_ACK110,
  340. +           &dunno1, sizeof(dunno1),
  341. +           &type, sizeof(type),
  342. +           &dunno2, sizeof(dunno2),
  343. +           seq_b, seq_len,
  344. +           dunno3, sizeof(dunno3),
  345. +           NULL);
  346. +
  347. +   if (ret == -1) {
  348. +       int errno_copy;
  349. +
  350. +       gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
  351. +       errno_copy = errno;
  352. +       close(gs->fd);
  353. +       errno = errno_copy;
  354. +       gs->fd = -1;
  355. +       ge->type = GG_EVENT_CONN_FAILED;
  356. +       ge->event.failure = GG_FAILURE_WRITING;
  357. +       gs->state = GG_STATE_IDLE;
  358. +       return -1;
  359. +   }
  360. +
  361. +   return 0;
  362. +}
  363. +
  364. +static int gg_session_handle_welcome_gg11(struct gg_session *gs, uint32_t seed, struct gg_event *ge)
  365. +{
  366. +   const uint8_t section_headers[6] = {0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a};
  367. +   const uint8_t lang_length = 2;
  368. +   const char *lang = GG8_LANG;
  369. +   const uint8_t dunno1 = 0x12;
  370. +   int uin_len;
  371. +   uint8_t uin_s[20];
  372. +   uint8_t hash_len = 20;
  373. +   uint8_t hash[64];
  374. +   const uint8_t dunno2[9] = {0x20, 0x02, 0x2d, 0x77, 0xff, 0xae, 0x01, 0x35, 0x14};
  375. +   uint8_t privacy;
  376. +   const uint8_t dunno3[2] = {0x03, 0x00};
  377. +   uint8_t client_len;
  378. +   const char *client_name = GG11_VERSION;
  379. +   const char *client_version = GG_DEFAULT_CLIENT_VERSION;
  380. +   const char *client_target = GG11_TARGET;
  381. +   const uint8_t dunno4 = 0x45;
  382. +   uint32_t status;
  383. +   uint8_t descr_len;
  384. +   const char *descr;
  385. +   const uint8_t dunno5[6] = {0x52, 0x04, 0x00, 0x00, 0x00, 0x00};
  386. +   uint8_t userdata_len;
  387. +   const char *userdata;
  388. +   const uint8_t dunno6[15] = {0x60, 0xff, 0x01, 0x68, 0x64, 0x75, 0x7f,
  389. +       0x00, 0x00, 0x00, 0x78, 0x00, 0x88, 0x01, 0x00};
  390. +
  391. +   uint8_t client_name_len;
  392. +   uint8_t client_version_len;
  393. +   uint8_t client_target_len;
  394. +   int ret;
  395. +
  396. +   if (gs->hash_type != GG_LOGIN_HASH_SHA1) {
  397. +       gg_debug_session(gs, GG_DEBUG_MISC, "// Unsupported hash type for this protocol version\n");
  398. +       return -1;
  399. +   }
  400. +  
  401. +   if (gg_login_hash_sha1_2(gs->password, seed, hash) == -1) {
  402. +       int errno_copy;
  403. +
  404. +       gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() gg_login_hash_sha1_2() failed, probably out of memory\n");
  405. +       errno_copy = errno;
  406. +       close(gs->fd);
  407. +       errno = errno_copy;
  408. +       gs->fd = -1;
  409. +       ge->type = GG_EVENT_CONN_FAILED;
  410. +       ge->event.failure = GG_FAILURE_INTERNAL;
  411. +       gs->state = GG_STATE_IDLE;
  412. +       return -1;
  413. +   }
  414. +
  415. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending GG_LOGIN105 packet\n");
  416. +  
  417. +   /*
  418. +   zmienia format pakietu
  419. +   dunno2[3] == 0x37 dla gg10.5
  420. +   dunno2[3] == 0x77 dla gg11.0
  421. +   */
  422. +  
  423. +   uin_len = gg_packed_uin_write(uin_s, sizeof(uin_s), gs->uin, 1);
  424. +  
  425. +   privacy = 0x00; /* 0x06 - pokazuj kamerkę znajomym */
  426. +  
  427. +   /* flagi gg8 są różne od tych dla gg11 */
  428. +   status = gg_fix32(gs->initial_status ? (gs->initial_status & 0xFF) : GG_STATUS_AVAIL);
  429. +
  430. +   if (gs->client_version != NULL && !isdigit(gs->client_version[0])) {
  431. +       client_name = "";
  432. +       client_target = "";
  433. +   }
  434. +   if (gs->client_version != NULL)
  435. +       client_version = gs->client_version;
  436. +   client_name_len = strlen(client_name);
  437. +   client_version_len = strlen(client_version);
  438. +   client_target_len = strlen(client_target);
  439. +   client_len = client_name_len + client_version_len + client_target_len;
  440. +
  441. +   descr = (gs->initial_descr != NULL) ? gs->initial_descr : "";
  442. +   descr_len = (gs->initial_descr != NULL) ? strlen(gs->initial_descr) : 0;
  443. +
  444. +   userdata = "avatar,StatusComments,gg_account_sdp,edisc,bot,fanpage,"
  445. +       "pubdir,botCaps";
  446. +   userdata_len = strlen(userdata);
  447. +
  448. +   ret = gg_send_packet(gs,
  449. +       GG_LOGIN105,
  450. +       &section_headers[0], 1,
  451. +       &lang_length, sizeof(lang_length),
  452. +       lang, lang_length,
  453. +       &dunno1, sizeof(dunno1),
  454. +       uin_s, uin_len,
  455. +      
  456. +       &section_headers[1], 1,
  457. +       &hash_len, sizeof(hash_len),
  458. +       hash, hash_len,
  459. +       dunno2, sizeof(dunno2),
  460. +       &privacy, sizeof(privacy),
  461. +       dunno3, sizeof(dunno3),
  462. +      
  463. +       &section_headers[3], 1,
  464. +       &client_len, sizeof(client_len),
  465. +       client_name, client_name_len,
  466. +       client_version, client_version_len,
  467. +       client_target, client_target_len,
  468. +       &dunno4, sizeof(dunno4),
  469. +       &status, sizeof(status),
  470. +      
  471. +       &section_headers[4], 1,
  472. +       &descr_len, sizeof(descr_len),
  473. +       descr, descr_len,
  474. +       dunno5, sizeof(dunno5),
  475. +      
  476. +       &section_headers[5], 1,
  477. +       &userdata_len, sizeof(userdata_len),
  478. +       userdata, userdata_len,
  479. +      
  480. +       dunno6, sizeof(dunno6),
  481. +       NULL);
  482. +
  483. +   if (ret == -1) {
  484. +       int errno_copy;
  485. +
  486. +       gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
  487. +       errno_copy = errno;
  488. +       close(gs->fd);
  489. +       errno = errno_copy;
  490. +       gs->fd = -1;
  491. +       ge->type = GG_EVENT_CONN_FAILED;
  492. +       ge->event.failure = GG_FAILURE_WRITING;
  493. +       gs->state = GG_STATE_IDLE;
  494. +       return -1;
  495. +   }
  496. +
  497. +   gs->state = GG_STATE_READING_REPLY;
  498. +   gs->check = GG_CHECK_READ;
  499. +
  500. +   return 0;
  501. +}
  502. +
  503. +static int gg_session_handle_login110_ok(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  504. +{
  505. +   uint8_t somehash_len;
  506. +   char *somehash = NULL;
  507. +   uint32_t server_time;
  508. +   int offset = 0;
  509. +
  510. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n");
  511. +   ge->type = GG_EVENT_CONN_SUCCESS;
  512. +   gs->state = GG_STATE_CONNECTED;
  513. +   gs->check = GG_CHECK_READ;
  514. +   gs->timeout = -1;
  515. +   gs->status = (gs->initial_status) ? gs->initial_status : GG_STATUS_AVAIL;
  516. +#if 0
  517. +   free(gs->status_descr);
  518. +   gs->status_descr = gs->initial_descr;
  519. +#else
  520. +   free(gs->initial_descr);
  521. +#endif
  522. +   gs->initial_descr = NULL;
  523. +
  524. +   if (offset + 3 > len)
  525. +       goto fail;
  526. +   /* 0x08 01 12 */
  527. +   offset += 3;
  528. +  
  529. +   if (offset + 1 > len)
  530. +       goto fail;
  531. +   somehash_len = ptr[offset];
  532. +   offset++;
  533. +   if (offset + somehash_len > len)
  534. +       goto fail;
  535. +   somehash = malloc(somehash_len + 1);
  536. +   if (somehash == NULL)
  537. +       goto fail;
  538. +   memcpy(somehash, ptr + offset, somehash_len);
  539. +   somehash[somehash_len] = '\0';
  540. +   offset += somehash_len;
  541. +
  542. +   if (offset + 6 > len)
  543. +       goto fail;
  544. +   /* 0x18 _f __ __ __ 25 */
  545. +   offset += 6;
  546. +
  547. +   if (offset + 4 > len)
  548. +       goto fail;
  549. +   server_time = gg_fix32(*((uint32_t*)(ptr + offset)));
  550. +
  551. +   gg_debug_session(gs, GG_DEBUG_MISC, "// login110_ok: some hash=%s, server time=%u\n", somehash, server_time);
  552. +   free(somehash);
  553. +
  554. +   return 0;
  555. +fail:
  556. +   free(somehash);
  557. +   return -1;
  558. +}
  559. +
  560.  /**
  561.   * \internal Obsługuje pakiet GG_WELCOME.
  562.   *
  563. @@ -92,6 +325,9 @@
  564.     w = (const struct gg_welcome*) ptr;
  565.     seed = gg_fix32(w->key);
  566.  
  567. +   if (gs->protocol_version >= 0x2f)
  568. +       return gg_session_handle_welcome_gg11(gs, seed, ge);
  569. +
  570.     memset(hash_buf, 0, sizeof(hash_buf));
  571.  
  572.     switch (gs->hash_type) {
  573. @@ -347,6 +583,75 @@
  574.     return 0;
  575.  }
  576.  
  577. +static int gg_session_handle_event110(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  578. +{
  579. +   int offset = 0;
  580. +   uint16_t seq, data_len;
  581. +   uint8_t event_type;
  582. +   char *data = NULL;
  583. +   char *json_type = NULL;
  584. +  
  585. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received GG11 event\n");
  586. +  
  587. +   if (offset + 3 > len)
  588. +       goto fail;
  589. +   /* 0x08 xx 10 */
  590. +   offset++;
  591. +   event_type = ptr[offset++];
  592. +   offset++;
  593. +  
  594. +   if (offset + 2 > len)
  595. +       goto fail;
  596. +   offset += gg_packed_int_read(ptr + offset, &seq);
  597. +  
  598. +   if (offset + 1 > len)
  599. +       goto fail;
  600. +   /* 0x1a */
  601. +   offset++;
  602. +
  603. +   if (offset + 2 > len)
  604. +       goto fail;
  605. +   offset += gg_packed_int_read(ptr + offset, &data_len);
  606. +  
  607. +   data = malloc(data_len + 1);
  608. +   if (data == NULL)
  609. +       goto fail;
  610. +   memcpy(data, ptr + offset, data_len);
  611. +   data[data_len] = '\0';
  612. +   offset += data_len;
  613. +  
  614. +   if (event_type == GG_EVENT110_XML) {
  615. +       ge->type = GG_EVENT_XML_EVENT;
  616. +       ge->event.xml_event.data = data;
  617. +   } else if (event_type == GG_EVENT110_JSON) {
  618. +       if (offset + 3 > len)
  619. +           goto fail;
  620. +       offset++; /* 0x22 */
  621. +       offset += gg_packed_int_read(ptr + offset, &data_len);
  622. +
  623. +       json_type = malloc(data_len + 1);
  624. +       if (json_type == NULL)
  625. +           goto fail;
  626. +       memcpy(json_type, ptr + offset, data_len);
  627. +       json_type[data_len] = '\0';
  628. +       offset += data_len;
  629. +  
  630. +       ge->type = GG_EVENT_JSON_EVENT;
  631. +       ge->event.json_event.data = data;
  632. +       ge->event.json_event.type = json_type;
  633. +   } else {
  634. +       gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() unsupported GG11 event type: %d\n", event_type);
  635. +       gg_ack_gg11(gs, GG_ACK110_MPA, seq, ge);
  636. +       goto fail;
  637. +   }
  638. +  
  639. +   return gg_ack_gg11(gs, GG_ACK110_MPA, seq, ge);
  640. +fail:
  641. +   free(json_type);
  642. +   free(data);
  643. +   return -1;
  644. +}
  645. +
  646.  /**
  647.   * \internal Obsługuje pakiet GG_PUBDIR50_REPLY.
  648.   *
  649. @@ -990,6 +1295,172 @@
  650.     return 0;
  651.  }
  652.  
  653. +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)
  654. +{
  655. +   int offset = 0;
  656. +   uint16_t seq = 0;
  657. +   uint16_t msg_len;
  658. +   uint8_t ack_type;
  659. +  
  660. +   uint32_t dummy_time1, dummy_time2;
  661. +  
  662. +   gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg110(%p, %d, %p);\n", packet, length, e);
  663. +
  664. +   if (type == GG_CHAT_RECV_MSG || type == GG_CHAT_RECV_OWN_MSG)
  665. +       ack_type = GG_ACK110_CHAT;
  666. +   else
  667. +       ack_type = GG_ACK110_MSG;
  668. +  
  669. +   if (offset + 1 > length)
  670. +       goto fail;
  671. +   /* nieobecne w GG_CHAT_RECV_OWN_MSG */
  672. +   if (packet[offset] == 0x0a)
  673. +   {
  674. +       offset++;
  675. +
  676. +       offset += gg_packed_uin_read(&e->event.msg.sender, packet + offset, length - offset);
  677. +       if (e->event.msg.sender == 0)
  678. +           goto fail;
  679. +   }
  680. +   else if (type == GG_CHAT_RECV_OWN_MSG)
  681. +       e->event.msg.sender = sess->uin;
  682. +
  683. +   if (offset + 3 > length)
  684. +       goto fail;
  685. +   /* 0x10 08 18 -> ustawiany przez nadawcę? */
  686. +   /* 0x10 09 18 -> archiwalna wiadomość? */
  687. +   /* 0x10 04 18 -> własna wiadomość w czacie */
  688. +   offset += 3;
  689. +
  690. +   if (offset + 2 > length)
  691. +       goto fail;
  692. +   offset += gg_packed_int_read(packet + offset, &seq);
  693. +   e->event.msg.seq = seq;
  694. +
  695. +   if (offset + 1 > length)
  696. +       goto fail;
  697. +   /* 0x25 */
  698. +   offset++;
  699. +
  700. +   if (offset + 4 > length)
  701. +       goto fail;
  702. +   e->event.msg.time = gg_fix32(*((uint32_t*)(packet + offset)));
  703. +   offset += 4;
  704. +
  705. +   if (offset + 1 > length)
  706. +       goto fail;
  707. +   /* 0x2a */
  708. +   offset++;
  709. +
  710. +   if (offset + 2 > length)
  711. +       goto fail;
  712. +   offset += gg_packed_int_read(packet + offset, &msg_len);
  713. +   if (offset + msg_len > length)
  714. +       goto fail;
  715. +   e->event.msg.message = (unsigned char*)gg_encoding_convert(packet + offset, GG_ENCODING_UTF8, sess->encoding, msg_len, -1);
  716. +   if (e->event.msg.message == NULL)
  717. +       goto fail;
  718. +   offset += msg_len;
  719. +  
  720. +   if (offset + 1 > length)
  721. +       goto fail;
  722. +   /* 0x32 */
  723. +   offset++;
  724. +  
  725. +   if (offset + 2 > length)
  726. +       goto fail;
  727. +   offset += gg_packed_int_read(packet + offset, &msg_len);
  728. +   if (offset + msg_len > length)
  729. +       goto fail;
  730. +   e->event.msg.xhtml_message = gg_encoding_convert(packet + offset, GG_ENCODING_UTF8, sess->encoding, msg_len, -1);
  731. +   if (e->event.msg.xhtml_message == NULL)
  732. +       goto fail;
  733. +   offset += msg_len;
  734. +  
  735. +   if (offset + 1 > length)
  736. +       goto fail;
  737. +   /* otrzymywane tylko od gg <= 10.5 */
  738. +   if (packet[offset] == 0x3a)
  739. +   {
  740. +       uint8_t formats_length;
  741. +      
  742. +       offset++;
  743. +       if (offset + 1 > length)
  744. +           goto fail;
  745. +       formats_length = packet[offset++];
  746. +       if (offset + formats_length > length)
  747. +           goto fail;
  748. +       e->event.msg.formats_length = formats_length;
  749. +      
  750. +       e->event.msg.formats = malloc(formats_length);
  751. +       if (e->event.msg.formats == NULL)
  752. +           goto fail;
  753. +       memcpy(e->event.msg.formats, packet + offset, formats_length);
  754. +       offset += formats_length;
  755. +   }
  756. +  
  757. +   /* 49 xx xx xx 00 */
  758. +   if (offset + 5 > length)
  759. +       goto fail;
  760. +   offset += 5;
  761. +
  762. +   if (offset + 4 > length)
  763. +       goto fail;
  764. +   /* taki sam czas jak czas wiadomości lub o jeden mniej */
  765. +   dummy_time1 = gg_fix32(*((uint32_t*)(packet + offset)));
  766. +   offset += 4;
  767. +  
  768. +   /* type == GG_CHAT_RECV_MSG || type == GG_CHAT_RECV_OWN_MSG */
  769. +   if (packet[offset] == 0x51) {
  770. +       struct gg_chat_list *chat;
  771. +  
  772. +       offset++;
  773. +
  774. +       if (offset + 8 > length)
  775. +           goto fail;
  776. +       e->event.msg.chat_id = gg_fix64(*((uint64_t*)(packet + offset)));
  777. +       offset += 8;
  778. +      
  779. +       chat = gg_chat_find(sess, e->event.msg.chat_id);
  780. +       if (chat) {
  781. +           e->event.msg.recipients = malloc(chat->participants_count * sizeof(uin_t));
  782. +           if (e->event.msg.recipients == NULL)
  783. +               goto fail;
  784. +           memcpy(e->event.msg.recipients, chat->participants, chat->participants_count * sizeof(uin_t));
  785. +           e->event.msg.recipients_count = chat->participants_count;
  786. +       }
  787. +   }
  788. +  
  789. +   if (offset + 5 > length)
  790. +       goto fail;
  791. +   /* id rozmówcy? konwersacji? */
  792. +   /* 0x59 __ __ 0_ 00 */
  793. +   offset += 5;
  794. +
  795. +   if (offset + 4 > length)
  796. +       goto fail;
  797. +   /* czas początku konwersacji? */
  798. +   dummy_time2 = gg_fix32(*((uint32_t*)(packet + offset)));
  799. +
  800. +   if (type == GG_RECV_OWN_MSG110 || type == GG_CHAT_RECV_OWN_MSG)
  801. +       e->type = GG_EVENT_MULTILOGON_MSG;
  802. +   else
  803. +       e->type = GG_EVENT_MSG;
  804. +   e->event.msg.msgclass = GG_CLASS_CHAT;
  805. +   e->event.msg.seq = seq;
  806. +
  807. +   return gg_ack_gg11(sess, ack_type, seq, e);
  808. +
  809. +fail:
  810. +   free(e->event.msg.message);
  811. +   free(e->event.msg.xhtml_message);
  812. +   free(e->event.msg.recipients);
  813. +   free(e->event.msg.formats);
  814. +   if (seq)
  815. +       gg_ack_gg11(sess, ack_type, seq, e);
  816. +   return -1;
  817. +}
  818. +
  819.  /**
  820.   * \internal Obsługuje pakiet GG_STATUS.
  821.   *
  822. @@ -1764,6 +2235,388 @@
  823.     return 0;
  824.  }
  825.  
  826. +static int gg_session_handle_imtoken(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  827. +{
  828. +   uint8_t imtoken_len;
  829. +   char *imtoken = NULL;
  830. +   int offset = 0;
  831. +
  832. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received imtoken\n");
  833. +  
  834. +   if (offset + 1 > len)
  835. +       goto fail;
  836. +   /* 0x0a */
  837. +   offset++;
  838. +  
  839. +   if (offset + 1 > len)
  840. +       goto fail;
  841. +   imtoken_len = ptr[offset];
  842. +   offset++;
  843. +   if (offset + imtoken_len > len)
  844. +       goto fail;
  845. +   if (imtoken_len > 0) {
  846. +       imtoken = malloc(imtoken_len + 1);
  847. +       if (imtoken == NULL)
  848. +           goto fail;
  849. +       memcpy(imtoken, ptr + offset, imtoken_len);
  850. +       imtoken[imtoken_len] = '\0';
  851. +   }
  852. +  
  853. +   ge->type = GG_EVENT_IMTOKEN;
  854. +   ge->event.imtoken.imtoken = imtoken;
  855. +  
  856. +   return 0;
  857. +fail:
  858. +   free(imtoken);
  859. +   return -1;
  860. +}
  861. +
  862. +static int gg_session_handle_pong110(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  863. +{
  864. +   const struct gg_pong110 *pong = (const struct gg_pong110*)ptr;
  865. +  
  866. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received pong110\n");
  867. +  
  868. +   ge->type = GG_EVENT_PONG110;
  869. +   ge->event.pong110.time = gg_fix32(pong->time);
  870. +  
  871. +   return 0;
  872. +}
  873. +
  874. +static int gg_session_handle_chat_info(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  875. +{
  876. +   uint64_t id;
  877. +   uint32_t version;
  878. +   uint32_t dummy1;
  879. +   uint32_t name_length;
  880. +   uint32_t participants_count;
  881. +   uin_t *participants = NULL;
  882. +  
  883. +   int i;
  884. +
  885. +   int offset = 0;
  886. +
  887. +   if (offset + 8 > len)
  888. +       goto fail;
  889. +   id = gg_fix64(*((uint64_t*)(ptr + offset)));
  890. +   offset += 8;
  891. +
  892. +   if (id == 0) {
  893. +       ge->type = GG_EVENT_NONE;
  894. +       return 0;
  895. +   }
  896. +
  897. +   if (offset + 4 > len)
  898. +       goto fail;
  899. +   /* 0x00 00 00 00 */
  900. +   offset += 4;
  901. +
  902. +   if (offset + 4 > len)
  903. +       goto fail;
  904. +   version = gg_fix32(*((uint32_t*)(ptr + offset)));
  905. +   offset += 4;
  906. +
  907. +   if (offset + 4 > len)
  908. +       goto fail;
  909. +   /* 0 lub 1 */
  910. +   dummy1 = gg_fix32(*((uint32_t*)(ptr + offset)));
  911. +   offset += 4;
  912. +
  913. +   if (dummy1 == 1) {
  914. +       if (offset + 4 > len)
  915. +           goto fail;
  916. +       name_length = gg_fix32(*((uint32_t*)(ptr + offset)));
  917. +       offset += 4;
  918. +       if (offset + name_length > len)
  919. +           goto fail;
  920. +       offset += name_length;
  921. +
  922. +       if (offset + 4 > len)
  923. +           goto fail;
  924. +       /* 0x00 00 00 00 */
  925. +       offset += 4;
  926. +
  927. +       if (offset + 4 > len)
  928. +           goto fail;
  929. +       /* 0x02 00 00 00 */
  930. +       offset += 4;
  931. +   }
  932. +
  933. +   if (offset + 4 > len)
  934. +       goto fail;
  935. +   participants_count = gg_fix32(*((uint32_t*)(ptr + offset)));
  936. +   offset += 4;
  937. +
  938. +   if (offset + 8 * participants_count > len)
  939. +       goto fail;
  940. +
  941. +   participants = malloc(sizeof(uin_t) * participants_count);
  942. +   if (participants == NULL)
  943. +       goto fail;
  944. +
  945. +   for (i = 0; i < participants_count; i++)
  946. +   {
  947. +       participants[i] = gg_fix32(*((uint32_t*)(ptr + offset)));
  948. +       offset += 4;
  949. +      
  950. +       /* 0x1e 00 00 00 lub 0x18 00 00 00 */
  951. +       offset += 4;
  952. +   }
  953. +
  954. +   if (0 != gg_chat_update(gs, id, version, participants, participants_count))
  955. +       goto fail;
  956. +
  957. +   ge->type = GG_EVENT_CHAT_INFO;
  958. +   ge->event.chat_info.id = id;
  959. +   ge->event.chat_info.version = version;
  960. +   ge->event.chat_info.participants_count = participants_count;
  961. +   ge->event.chat_info.participants = participants;
  962. +  
  963. +   return 0;
  964. +fail:
  965. +   free(participants);
  966. +   return -1;
  967. +}
  968. +
  969. +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)
  970. +{
  971. +   uint64_t id;
  972. +   uint32_t update_type;
  973. +   uin_t participant, inviter;
  974. +   uint16_t version;
  975. +   uint32_t time;
  976. +
  977. +   int offset = 0;
  978. +   struct gg_chat_list *chat;
  979. +
  980. +   if (offset + 1 > len)
  981. +       goto fail;
  982. +   /* 0x0a */
  983. +   offset++;
  984. +
  985. +   offset += gg_packed_uin_read(&participant, ptr + offset, len - offset);
  986. +   if (participant == 0)
  987. +       goto fail;
  988. +
  989. +   if (offset + 1 > len)
  990. +       goto fail;
  991. +   /* 0x12 */
  992. +   offset++;
  993. +
  994. +   offset += gg_packed_uin_read(&inviter, ptr + offset, len - offset);
  995. +   if (inviter == 0)
  996. +       goto fail;
  997. +
  998. +   if (offset + 1 > len)
  999. +       goto fail;
  1000. +   /* 0x1d */
  1001. +   offset++;
  1002. +
  1003. +   if (offset + 4 > len)
  1004. +       goto fail;
  1005. +   update_type = gg_fix32(*((uint32_t*)(ptr + offset)));
  1006. +   offset += 4;
  1007. +
  1008. +   if (offset + 1 > len)
  1009. +       goto fail;
  1010. +   /* 0x25 */
  1011. +   offset++;
  1012. +
  1013. +   if (offset + 4 > len)
  1014. +       goto fail;
  1015. +   time = gg_fix32(*((uint32_t*)(ptr + offset)));
  1016. +   offset += 4;
  1017. +
  1018. +   if (offset + 6 > len)
  1019. +       goto fail;
  1020. +   /* 0x2d xx 00 00 00 30 */
  1021. +   offset += 6;
  1022. +
  1023. +   if (offset + 2 > len)
  1024. +       goto fail;
  1025. +   offset += gg_packed_int_read(ptr + offset, &version);
  1026. +
  1027. +   if (offset + 7 + 4 + 1 > len)
  1028. +       goto fail;
  1029. +   /* 0x38 xx 49 0x 10  */
  1030. +   offset += 7;
  1031. +   /* time again */
  1032. +   offset += 4;
  1033. +   /* 0x51 */
  1034. +   offset++;
  1035. +
  1036. +   if (offset + 8 > len)
  1037. +       goto fail;
  1038. +   id = gg_fix64(*((uint64_t*)(ptr + offset)));
  1039. +   offset += 8;
  1040. +
  1041. +   /* 0x59 0x 10 00 00 */
  1042. +   offset += 5;
  1043. +   /* time again */
  1044. +   offset += 4;
  1045. +
  1046. +   chat = gg_chat_find(gs, id);
  1047. +   if (chat) {
  1048. +       chat->version = version;
  1049. +       if (update_type == GG_CHAT_INFO_UPDATE_ENTERED) {
  1050. +           chat->participants_count++;
  1051. +           chat->participants = realloc(chat->participants, sizeof(uin_t) * chat->participants_count);
  1052. +           chat->participants[chat->participants_count - 1] = participant;
  1053. +       } else if (update_type == GG_CHAT_INFO_UPDATE_EXITED) {
  1054. +           int idx;
  1055. +           for (idx = 0; idx < chat->participants_count; idx++)
  1056. +               if (chat->participants[idx] == participant)
  1057. +                   break;
  1058. +           if (chat->participants_count > 1 && idx < chat->participants_count)
  1059. +               chat->participants[idx] = chat->participants[chat->participants_count - 1];
  1060. +           if (idx < chat->participants_count) {
  1061. +               chat->participants_count--;
  1062. +               chat->participants = realloc(chat->participants, sizeof(uin_t) * chat->participants_count);
  1063. +           }
  1064. +       }
  1065. +   }
  1066. +
  1067. +   ge->type = GG_EVENT_CHAT_INFO_UPDATE;
  1068. +   ge->event.chat_info_update.id = id;
  1069. +   ge->event.chat_info_update.type = update_type;
  1070. +   ge->event.chat_info_update.participant = participant;
  1071. +   ge->event.chat_info_update.inviter = inviter;
  1072. +   ge->event.chat_info_update.version = version;
  1073. +   ge->event.chat_info_update.time = time;
  1074. +
  1075. +   return 0;
  1076. +fail:
  1077. +   return -1;
  1078. +}
  1079. +
  1080. +static int gg_session_handle_chat_created(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  1081. +{
  1082. +   uint64_t id;
  1083. +   uint32_t seq;
  1084. +  
  1085. +   int offset = 0;
  1086. +  
  1087. +   if (offset + 8 > len)
  1088. +       goto fail;
  1089. +   id = gg_fix64(*((uint64_t*)(ptr + offset)));
  1090. +   offset += 8;
  1091. +
  1092. +   if (offset + 4 > len)
  1093. +       goto fail;
  1094. +   seq = gg_fix32(*((uint64_t*)(ptr + offset)));
  1095. +   offset += 4;
  1096. +  
  1097. +   if (0 != gg_chat_update(gs, id, 0, &gs->uin, 1))
  1098. +       goto fail;
  1099. +  
  1100. +   ge->type = GG_EVENT_CHAT_CREATED;
  1101. +   ge->event.chat_created.id = id;
  1102. +   ge->event.chat_created.seq = seq;
  1103. +  
  1104. +   return 0;
  1105. +fail:
  1106. +   return -1;
  1107. +}
  1108. +
  1109. +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)
  1110. +{
  1111. +   uint64_t id;
  1112. +   uint32_t seq;
  1113. +  
  1114. +   int offset = 0;
  1115. +  
  1116. +   if (offset + 8 > len)
  1117. +       goto fail;
  1118. +   id = gg_fix64(*((uint64_t*)(ptr + offset)));
  1119. +   offset += 8;
  1120. +
  1121. +   if (offset + 4 > len)
  1122. +       goto fail;
  1123. +   seq = gg_fix32(*((uint32_t*)(ptr + offset)));
  1124. +   offset += 4;
  1125. +  
  1126. +   ge->type = GG_EVENT_CHAT_INVITE_ACK;
  1127. +   ge->event.chat_invite_ack.id = id;
  1128. +   ge->event.chat_invite_ack.seq = seq;
  1129. +  
  1130. +   /* 0x10 00 00 00  00 00 00 00 */
  1131. +   offset += 8;
  1132. +  
  1133. +   return 0;
  1134. +fail:
  1135. +   return -1;
  1136. +}
  1137. +
  1138. +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)
  1139. +{
  1140. +   uint16_t seq;
  1141. +   uint32_t time;
  1142. +
  1143. +   int offset = 0;
  1144. +
  1145. +   if (offset + 3 > len)
  1146. +       goto fail;
  1147. +   /* 0x08 02 10 */
  1148. +   offset += 3;
  1149. +
  1150. +   if (offset + 2 > len)
  1151. +       goto fail;
  1152. +   offset += gg_packed_int_read(ptr + offset, &seq);
  1153. +
  1154. +   if (offset + 1 > len)
  1155. +       goto fail;
  1156. +   /* 0x1d */
  1157. +   offset += 1;
  1158. +
  1159. +   if (offset + 4 > len)
  1160. +       goto fail;
  1161. +   time = gg_fix32(*((uint32_t*)(ptr + offset)));
  1162. +   offset += 4;
  1163. +
  1164. +   ge->type = GG_EVENT_CHAT_SEND_MSG_ACK;
  1165. +   ge->event.chat_send_msg_ack.seq = seq;
  1166. +   ge->event.chat_send_msg_ack.time = time;
  1167. +
  1168. +   /* 0x21 02 10 xx 00 <time:4> 29 xx 10 00 00 <time:4> 38 00 */
  1169. +   offset += 5 + 4 + 5 + 4 + 2;
  1170. +
  1171. +   return 0;
  1172. +fail:
  1173. +   return -1;
  1174. +}
  1175. +
  1176. +static int gg_session_handle_chat_left(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  1177. +{
  1178. +   uint64_t id;
  1179. +   uint32_t uin;
  1180. +
  1181. +   int offset = 0;
  1182. +
  1183. +   if (offset + 8 > len)
  1184. +       goto fail;
  1185. +   id = gg_fix64(*((uint64_t*)(ptr + offset)));
  1186. +   offset += 8;
  1187. +
  1188. +   /* Właściwie, to nie wiadomo, czy to jest "osoba wychodząca", czy
  1189. +    * "osoba wyrzucająca nas" z konferencji. */
  1190. +   if (offset + 4 > len)
  1191. +       goto fail;
  1192. +   uin = gg_fix32(*((uint32_t*)(ptr + offset)));
  1193. +   offset += 4;
  1194. +
  1195. +   ge->type = GG_EVENT_CHAT_INFO_UPDATE;
  1196. +   ge->event.chat_info_update.id = id;
  1197. +   ge->event.chat_info_update.type = GG_CHAT_INFO_UPDATE_EXITED;
  1198. +   ge->event.chat_info_update.participant = uin;
  1199. +   ge->event.chat_info_update.inviter = uin;
  1200. +   ge->event.chat_info_update.version = 0;
  1201. +   ge->event.chat_info_update.time = time(NULL);
  1202. +
  1203. +   return 0;
  1204. +fail:
  1205. +   return -1;
  1206. +}
  1207. +
  1208.  /**
  1209.   * \internal Tablica obsługiwanych pakietów
  1210.   */
  1211. @@ -1772,6 +2625,7 @@
  1212.     { GG_WELCOME, GG_STATE_READING_KEY, 0, gg_session_handle_welcome },
  1213.     { GG_LOGIN_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
  1214.     { GG_LOGIN80_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
  1215. +   { GG_LOGIN110_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login110_ok },
  1216.     { GG_NEED_EMAIL, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
  1217.     { GG_LOGIN_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed },
  1218.     { GG_LOGIN80_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed },
  1219. @@ -1780,6 +2634,7 @@
  1220.     { GG_DISCONNECTING, GG_STATE_CONNECTED, 0, gg_session_handle_disconnecting },
  1221.     { GG_DISCONNECT_ACK, GG_STATE_DISCONNECTING, 0, gg_session_handle_disconnect_ack },
  1222.     { GG_XML_EVENT, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event },
  1223. +   { GG_EVENT110, GG_STATE_CONNECTED, 0, gg_session_handle_event110 },
  1224.     { GG_PUBDIR50_REPLY, GG_STATE_CONNECTED, 0, gg_session_handle_pubdir50_reply },
  1225.     { GG_USERLIST_REPLY, GG_STATE_CONNECTED, 0, gg_session_handle_userlist_reply },
  1226.     { GG_DCC7_ID_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_id_reply), gg_session_handle_dcc7_id_reply },
  1227. @@ -1789,6 +2644,8 @@
  1228.     { GG_DCC7_INFO, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_info), gg_session_handle_dcc7_info },
  1229.     { GG_RECV_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg), gg_session_handle_recv_msg },
  1230.     { GG_RECV_MSG80, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
  1231. +   { GG_RECV_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
  1232. +   { GG_RECV_OWN_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
  1233.     { GG_STATUS, GG_STATE_CONNECTED, sizeof(struct gg_status), gg_session_handle_status },
  1234.     { GG_STATUS60, GG_STATE_CONNECTED, sizeof(struct gg_status60), gg_session_handle_status_60_77_80beta },
  1235.     { GG_STATUS77, GG_STATE_CONNECTED, sizeof(struct gg_status77), gg_session_handle_status_60_77_80beta },
  1236. @@ -1806,6 +2663,16 @@
  1237.     { GG_RECV_OWN_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
  1238.     { GG_USERLIST100_VERSION, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_version), gg_session_handle_userlist_100_version },
  1239.     { GG_USERLIST100_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_reply), gg_session_handle_userlist_100_reply },
  1240. +   { GG_IMTOKEN, GG_STATE_CONNECTED, 0, gg_session_handle_imtoken },
  1241. +   { GG_PONG110, GG_STATE_CONNECTED, sizeof(struct gg_pong110), gg_session_handle_pong110 },
  1242. +   { GG_CHAT_INFO, GG_STATE_CONNECTED, 0, gg_session_handle_chat_info },
  1243. +   { GG_CHAT_INFO_UPDATE, GG_STATE_CONNECTED, 0, gg_session_handle_chat_info_update },
  1244. +   { GG_CHAT_CREATED, GG_STATE_CONNECTED, 0, gg_session_handle_chat_created },
  1245. +   { GG_CHAT_INVITE_ACK, GG_STATE_CONNECTED, 0, gg_session_handle_chat_invite_ack },
  1246. +   { GG_CHAT_SEND_MSG_ACK, GG_STATE_CONNECTED, 0, gg_session_handle_chat_send_msg_ack },
  1247. +   { GG_CHAT_RECV_MSG, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
  1248. +   { GG_CHAT_RECV_OWN_MSG, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
  1249. +   { GG_CHAT_LEFT, GG_STATE_CONNECTED, 0, gg_session_handle_chat_left },
  1250.  };
  1251.  
  1252.  /**
  1253. Index: src/events.c
  1254. ===================================================================
  1255. --- src/events.c    (wersja 1323)
  1256. +++ src/events.c    (kopia robocza)
  1257. @@ -133,6 +133,11 @@
  1258.             free(e->event.xml_event.data);
  1259.             break;
  1260.  
  1261. +       case GG_EVENT_JSON_EVENT:
  1262. +           free(e->event.json_event.data);
  1263. +           free(e->event.json_event.type);
  1264. +           break;
  1265. +
  1266.         case GG_EVENT_USER_DATA:
  1267.         {
  1268.             unsigned int i, j;
  1269. @@ -166,6 +171,14 @@
  1270.         case GG_EVENT_USERLIST100_REPLY:
  1271.             free(e->event.userlist100_reply.reply);
  1272.             break;
  1273. +
  1274. +       case GG_EVENT_IMTOKEN:
  1275. +           free(e->event.imtoken.imtoken);
  1276. +           break;
  1277. +
  1278. +       case GG_EVENT_CHAT_INFO:
  1279. +           free(e->event.chat_info.participants);
  1280. +           break;
  1281.     }
  1282.  
  1283.     free(e);
  1284. Index: src/libgadu.c
  1285. ===================================================================
  1286. --- src/libgadu.c   (wersja 1323)
  1287. +++ src/libgadu.c   (kopia robocza)
  1288. @@ -954,6 +954,7 @@
  1289.  void gg_free_session(struct gg_session *sess)
  1290.  {
  1291.     struct gg_dcc7 *dcc;
  1292. +   struct gg_chat_list *chat;
  1293.  
  1294.     gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_free_session(%p);\n", sess);
  1295.  
  1296. @@ -1003,6 +1004,14 @@
  1297.     for (dcc = sess->dcc7_list; dcc; dcc = dcc->next)
  1298.         dcc->sess = NULL;
  1299.  
  1300. +   chat = sess->chat_list;
  1301. +   while (chat) {
  1302. +       struct gg_chat_list *next = chat->next;
  1303. +       free(chat->participants);
  1304. +       free(chat);
  1305. +       chat = next;
  1306. +   }
  1307. +
  1308.     free(sess);
  1309.  }
  1310.  
  1311. @@ -1074,10 +1083,28 @@
  1312.     p.status        = gg_fix32(status);
  1313.     p.flags         = gg_fix32(sess->status_flags);
  1314.     p.description_size  = gg_fix32(descr_len);
  1315. -   res = gg_send_packet(sess, GG_NEW_STATUS80,
  1316. -           &p, sizeof(p),
  1317. -           (new_descr) ? new_descr : descr, descr_len,
  1318. +
  1319. +   if (sess->protocol_version >= 0x2f) {
  1320. +       uint8_t dummy1[4] = { 0x00, 0x00, 0x00, 0x00 };
  1321. +       const char *set_descr = "";
  1322. +
  1323. +       if (new_descr)
  1324. +           set_descr = new_descr;
  1325. +       else if (descr)
  1326. +           set_descr = descr;
  1327. +
  1328. +       p.flags = gg_fix32(0x00000014);
  1329. +       res = gg_send_packet(sess, GG_NEW_STATUS105,
  1330. +           &p, sizeof(p),
  1331. +           set_descr, descr_len,
  1332. +           dummy1, sizeof(dummy1),
  1333.             NULL);
  1334. +   } else {
  1335. +       res = gg_send_packet(sess, GG_NEW_STATUS80,
  1336. +           &p, sizeof(p),
  1337. +           new_descr ? new_descr : descr, descr_len,
  1338. +           NULL);
  1339. +   }
  1340.  
  1341.     free(new_descr);
  1342.  
  1343. @@ -1137,6 +1164,87 @@
  1344.  
  1345.  #ifndef DOXYGEN
  1346.  
  1347. +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)
  1348. +{
  1349. +   uint8_t dummy1 = 0x0a;
  1350. +   uint8_t uin_len;
  1351. +   uint8_t uin_s[20];
  1352. +   uint8_t dummy2[3] = { 0x10, 0x08, 0x18 };
  1353. +   uint8_t seq_b[2];
  1354. +   int seq_len;
  1355. +   uint8_t dummy3 = 0x2a;
  1356. +   uint8_t message_len_b[2];
  1357. +   int message_len_len;
  1358. +   uint8_t dummy4 = 0x32;
  1359. +   uint8_t html_message_len_b[2];
  1360. +   int html_message_len_len;
  1361. +
  1362. +   int message_len, html_message_len;
  1363. +   int seq = ++sess->seq;
  1364. +   char *html_message_gen = NULL, *plain_message_gen = NULL;
  1365. +
  1366. +   if (message == NULL && html_message == NULL)
  1367. +       goto fail;
  1368. +
  1369. +
  1370. +   if (html_message) {
  1371. +       if (sess->encoding != GG_ENCODING_UTF8) {
  1372. +           html_message = html_message_gen = gg_encoding_convert(html_message, sess->encoding, GG_ENCODING_UTF8, -1, -1);
  1373. +           if (html_message_gen == NULL)
  1374. +               goto fail;
  1375. +       }
  1376. +      
  1377. +       message = plain_message_gen = gg_message_html_to_text_gg11(html_message);
  1378. +       if (plain_message_gen == NULL)
  1379. +           goto fail;
  1380. +   } else {
  1381. +       if (sess->encoding != GG_ENCODING_UTF8) {
  1382. +           message = plain_message_gen = gg_encoding_convert(message, sess->encoding, GG_ENCODING_UTF8, -1, -1);
  1383. +           if (plain_message_gen == NULL)
  1384. +               goto fail;
  1385. +       }
  1386. +      
  1387. +       html_message = html_message_gen = gg_message_text_to_html_gg11(message);
  1388. +       if (html_message_gen == NULL)
  1389. +           goto fail;
  1390. +   }
  1391. +
  1392. +   uin_len = gg_packed_uin_write(uin_s, sizeof(uin_s), recipients[0], 1);
  1393. +   if (uin_len <= 0)
  1394. +       goto fail;
  1395. +
  1396. +   message_len = strlen(message);
  1397. +   html_message_len = strlen(html_message);
  1398. +   seq_len = gg_packed_int_write(seq_b, seq);
  1399. +   message_len_len = gg_packed_int_write(message_len_b, message_len);
  1400. +   html_message_len_len = gg_packed_int_write(html_message_len_b, html_message_len);
  1401. +
  1402. +   if (gg_send_packet(sess,
  1403. +       GG_SEND_MSG110,
  1404. +       &dummy1, sizeof(dummy1),
  1405. +       uin_s, uin_len,
  1406. +       dummy2, sizeof(dummy2),
  1407. +       seq_b, seq_len,
  1408. +       &dummy3, sizeof(dummy3),
  1409. +       message_len_b, message_len_len,
  1410. +       message, message_len,
  1411. +       &dummy4, sizeof(dummy4),
  1412. +       html_message_len_b, html_message_len_len,
  1413. +       html_message, html_message_len,
  1414. +       NULL) == -1)
  1415. +   {
  1416. +       goto fail;
  1417. +   }
  1418. +
  1419. +   free(html_message_gen);
  1420. +   free(plain_message_gen);
  1421. +   return seq;
  1422. +fail:
  1423. +   free(html_message_gen);
  1424. +   free(plain_message_gen);
  1425. +   return -1;
  1426. +}
  1427. +
  1428.  /**
  1429.   * \internal Wysyła wiadomość.
  1430.   *
  1431. @@ -1181,6 +1289,12 @@
  1432.         return -1;
  1433.     }
  1434.  
  1435. +   if (sess->protocol_version >= 0x2f && recipients_count <= 1)
  1436. +   {
  1437. +       seq_no = gg_send_message_gg11(sess, msgclass, recipients_count, recipients, (const char*)message, (const char*)html_message);
  1438. +       goto cleanup;
  1439. +   }
  1440. +
  1441.     if (message == NULL) {
  1442.         char *tmp_msg;
  1443.         size_t len, fmt_len;
  1444. @@ -1277,6 +1391,12 @@
  1445.         }
  1446.     }
  1447.  
  1448. +   if (sess->protocol_version >= 0x2f && recipients_count <= 1)
  1449. +   {
  1450. +       seq_no = gg_send_message_gg11(sess, msgclass, recipients_count, recipients, recoded_msg, recoded_html_msg);
  1451. +       goto cleanup;
  1452. +   }
  1453. +
  1454.     /* Drobne odchylenie od protokołu. Jeśli wysyłamy kilka
  1455.      * wiadomości w ciągu jednej sekundy, zwiększamy poprzednią
  1456.      * wartość, żeby każda wiadomość miała unikalny numer.
  1457. @@ -1697,6 +1817,43 @@
  1458.     return res;
  1459.  }
  1460.  
  1461. +static int gg_notify105_ex(struct gg_session *sess, uin_t *userlist, char *types, int count)
  1462. +{
  1463. +   int res = 0;
  1464. +  
  1465. +   if (!userlist || !count)
  1466. +       return gg_send_packet(sess, GG_NOTIFY105_LIST_EMPTY, NULL);
  1467. +  
  1468. +   gg_debug_session(sess, GG_DEBUG_FUNCTION, "TOMO: gg_notify105_ex\n");
  1469. +  
  1470. +   while (count > 0) {
  1471. +       uint8_t buff[2048];
  1472. +       int offset = 0;
  1473. +       uint8_t uin_len;
  1474. +       int packet_type;
  1475. +      
  1476. +       while (count > 0) {
  1477. +           uin_len = gg_packed_uin_write(buff + offset, sizeof(buff) - offset - 1, *userlist, 0);
  1478. +           if (uin_len <= 0)
  1479. +               break;
  1480. +           offset += uin_len;
  1481. +           buff[offset++] = *types;
  1482. +
  1483. +           userlist++;
  1484. +           types++;
  1485. +           count--;
  1486. +       }
  1487. +      
  1488. +       packet_type = (count > 0) ? GG_NOTIFY105_FIRST : GG_NOTIFY105_LAST;
  1489. +       if (gg_send_packet(sess, packet_type, buff, offset, NULL) == -1) {
  1490. +           res = -1;
  1491. +           break;
  1492. +       }
  1493. +   }
  1494. +  
  1495. +   return res;
  1496. +}
  1497. +
  1498.  /**
  1499.   * Wysyła do serwera listę kontaktów.
  1500.   *
  1501. @@ -1736,6 +1893,9 @@
  1502.         return -1;
  1503.     }
  1504.  
  1505. +   if (sess->protocol_version >= 0x2f)
  1506. +       return gg_notify105_ex(sess, userlist, types, count);
  1507. +
  1508.     if (!userlist || !count)
  1509.         return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
  1510.  
  1511. @@ -1790,57 +1950,19 @@
  1512.   */
  1513.  int gg_notify(struct gg_session *sess, uin_t *userlist, int count)
  1514.  {
  1515. -   struct gg_notify *n;
  1516. -   uin_t *u;
  1517. -   int i, res = 0;
  1518. +   char *types;
  1519. +   int ret;
  1520.  
  1521. -   gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count);
  1522. -
  1523. -   if (!sess) {
  1524. -       errno = EFAULT;
  1525. +   types = malloc(count);
  1526. +   memset(types, GG_USER_NORMAL, count);
  1527. +   if (sess->recv_buf == NULL)
  1528.         return -1;
  1529. -   }
  1530.  
  1531. -   if (sess->state != GG_STATE_CONNECTED) {
  1532. -       errno = ENOTCONN;
  1533. -       return -1;
  1534. -   }
  1535. +   ret = gg_notify_ex(sess, userlist, types, count);
  1536.  
  1537. -   if (!userlist || !count)
  1538. -       return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
  1539. +   free(types);
  1540.  
  1541. -   while (count > 0) {
  1542. -       int part_count, packet_type;
  1543. -
  1544. -       if (count > 400) {
  1545. -           part_count = 400;
  1546. -           packet_type = GG_NOTIFY_FIRST;
  1547. -       } else {
  1548. -           part_count = count;
  1549. -           packet_type = GG_NOTIFY_LAST;
  1550. -       }
  1551. -
  1552. -       if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count)))
  1553. -           return -1;
  1554. -
  1555. -       for (u = userlist, i = 0; i < part_count; u++, i++) {
  1556. -           n[i].uin = gg_fix32(*u);
  1557. -           n[i].dunno1 = GG_USER_NORMAL;
  1558. -       }
  1559. -
  1560. -       if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) {
  1561. -           res = -1;
  1562. -           free(n);
  1563. -           break;
  1564. -       }
  1565. -
  1566. -       free(n);
  1567. -
  1568. -       userlist += part_count;
  1569. -       count -= part_count;
  1570. -   }
  1571. -
  1572. -   return res;
  1573. +   return ret;
  1574.  }
  1575.  
  1576.  /**
  1577. @@ -1860,8 +1982,6 @@
  1578.   */
  1579.  int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type)
  1580.  {
  1581. -   struct gg_add_remove a;
  1582. -
  1583.     gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type);
  1584.  
  1585.     if (!sess) {
  1586. @@ -1874,10 +1994,26 @@
  1587.         return -1;
  1588.     }
  1589.  
  1590. -   a.uin = gg_fix32(uin);
  1591. -   a.dunno1 = type;
  1592. +   if (sess->protocol_version >= 0x2f) {
  1593. +       uint8_t uin_len;
  1594. +       uint8_t uin_s[15];
  1595.  
  1596. -   return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
  1597. +       uin_len = gg_packed_uin_write(uin_s, sizeof(uin_s), uin, 0);
  1598. +       if (uin_len <= 0)
  1599. +           return -1;
  1600. +
  1601. +       return gg_send_packet(sess, GG_ADD_NOTIFY105,
  1602. +           uin_s, uin_len,
  1603. +           &type, sizeof(type),
  1604. +           NULL);
  1605. +   } else {
  1606. +       struct gg_add_remove a;
  1607. +
  1608. +       a.uin = gg_fix32(uin);
  1609. +       a.dunno1 = type;
  1610. +
  1611. +       return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
  1612. +   }
  1613.  }
  1614.  
  1615.  /**
  1616. @@ -1913,8 +2049,6 @@
  1617.   */
  1618.  int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type)
  1619.  {
  1620. -   struct gg_add_remove a;
  1621. -
  1622.     gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type);
  1623.  
  1624.     if (!sess) {
  1625. @@ -1927,10 +2061,26 @@
  1626.         return -1;
  1627.     }
  1628.  
  1629. -   a.uin = gg_fix32(uin);
  1630. -   a.dunno1 = type;
  1631. +   if (sess->protocol_version >= 0x2f) {
  1632. +       uint8_t uin_len;
  1633. +       uint8_t uin_s[15];
  1634.  
  1635. -   return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL);
  1636. +       uin_len = gg_packed_uin_write(uin_s, sizeof(uin_s), uin, 0);
  1637. +       if (uin_len <= 0)
  1638. +           return -1;
  1639. +
  1640. +       return gg_send_packet(sess, GG_REMOVE_NOTIFY105,
  1641. +           uin_s, uin_len,
  1642. +           &type, sizeof(type),
  1643. +           NULL);
  1644. +   } else {
  1645. +       struct gg_add_remove a;
  1646. +
  1647. +       a.uin = gg_fix32(uin);
  1648. +       a.dunno1 = type;
  1649. +
  1650. +       return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL);
  1651. +   }
  1652.  }
  1653.  
  1654.  /**
  1655. @@ -2118,6 +2268,163 @@
  1656.     return gg_send_packet(gs, GG_MULTILOGON_DISCONNECT, &pkt, sizeof(pkt), NULL);
  1657.  }
  1658.  
  1659. +int gg_chat_create(struct gg_session *gs)
  1660. +{
  1661. +   int seq = ++gs->seq;
  1662. +   uint32_t raw_seq = gg_fix32(seq);
  1663. +   uint32_t dummy = 0x00;
  1664. +  
  1665. +   if (gg_send_packet(gs,
  1666. +       GG_CHAT_CREATE,
  1667. +       &raw_seq, sizeof(raw_seq),
  1668. +       &dummy, sizeof(dummy),
  1669. +       NULL) == -1)
  1670. +   {
  1671. +       return -1;
  1672. +   }
  1673. +
  1674. +   return seq;
  1675. +}
  1676. +
  1677. +int gg_chat_invite(struct gg_session *gs, uint64_t id, uin_t *participants, int participants_count)
  1678. +{
  1679. +   uint8_t *participants_list = NULL;
  1680. +   int seq = ++gs->seq;
  1681. +   uint32_t raw_seq = gg_fix32(seq);
  1682. +   uint32_t raw_participants_count = gg_fix32(participants_count);
  1683. +
  1684. +   int i, offset;
  1685. +
  1686. +   if (participants_count <= 0)
  1687. +       goto fail;
  1688. +
  1689. +   participants_list = malloc(8 * participants_count);
  1690. +   if (participants_list == NULL)
  1691. +       goto fail;
  1692. +
  1693. +   id = gg_fix64(id);
  1694. +
  1695. +   offset = 0;
  1696. +   for (i = 0; i < participants_count; i++)
  1697. +   {
  1698. +       uint32_t *participant = (uint32_t*)(participants_list + offset);
  1699. +       offset += 8;
  1700. +      
  1701. +       participant[0] = gg_fix32(participants[i]);
  1702. +       participant[1] = gg_fix32(0x1e);
  1703. +   }
  1704. +
  1705. +   if (gg_send_packet(gs,
  1706. +       GG_CHAT_INVITE,
  1707. +       &id, sizeof(id),
  1708. +       &raw_seq, sizeof(raw_seq),
  1709. +       &raw_participants_count, sizeof(raw_participants_count),
  1710. +       participants_list, 8 * participants_count,
  1711. +       NULL) == -1)
  1712. +   {
  1713. +       goto fail;
  1714. +   }
  1715. +
  1716. +   free(participants_list);
  1717. +   return seq;
  1718. +
  1719. +fail:
  1720. +   free(participants_list);
  1721. +   return -1;
  1722. +}
  1723. +
  1724. +int gg_chat_leave(struct gg_session *gs, uint64_t id)
  1725. +{
  1726. +   int seq = ++gs->seq;
  1727. +   uint32_t raw_seq = gg_fix32(seq);
  1728. +
  1729. +   id = gg_fix64(id);
  1730. +
  1731. +   return gg_send_packet(gs,
  1732. +       GG_CHAT_LEAVE,
  1733. +       &id, sizeof(id),
  1734. +       &raw_seq, sizeof(raw_seq),
  1735. +       NULL);
  1736. +}
  1737. +
  1738. +int gg_chat_send_message(struct gg_session *gs, uint64_t id, const char *message, int is_html)
  1739. +{
  1740. +   uint8_t dummy1[3] = { 0x10, 0x08, 0x18 };
  1741. +   uint8_t seq_b[2];
  1742. +   int seq_len;
  1743. +   uint8_t dummy2 = 0x2a;
  1744. +   uint8_t message_plain_len_b[2];
  1745. +   int message_plain_len_len;
  1746. +   uint8_t dummy3 = 0x32;
  1747. +   uint8_t message_html_len_b[2];
  1748. +   int message_html_len_len;
  1749. +   uint8_t dummy4[3] = { 0x3a, 0x00, 0x51 };
  1750. +
  1751. +   int seq = ++gs->seq;
  1752. +   const char *message_plain, *message_html;
  1753. +   char *message_html_gen = NULL, *message_plain_gen = NULL;
  1754. +   size_t message_plain_len, message_html_len;
  1755. +
  1756. +   seq_len = gg_packed_int_write(seq_b, seq);
  1757. +   id = gg_fix64(id);
  1758. +
  1759. +   if (is_html) {
  1760. +       message_html = message;
  1761. +      
  1762. +       if (gs->encoding != GG_ENCODING_UTF8) {
  1763. +           message_html = message_html_gen = gg_encoding_convert(message_html, gs->encoding, GG_ENCODING_UTF8, -1, -1);
  1764. +           if (message_html_gen == NULL)
  1765. +               goto fail;
  1766. +       }
  1767. +      
  1768. +       message_plain = message_plain_gen = gg_message_html_to_text_gg11(message_html);
  1769. +       if (message_plain_gen == NULL)
  1770. +           goto fail;
  1771. +   } else {
  1772. +       message_plain = message;
  1773. +      
  1774. +       if (gs->encoding != GG_ENCODING_UTF8) {
  1775. +           message_plain = message_plain_gen = gg_encoding_convert(message_plain, gs->encoding, GG_ENCODING_UTF8, -1, -1);
  1776. +           if (message_plain_gen == NULL)
  1777. +               goto fail;
  1778. +       }
  1779. +      
  1780. +       message_html = message_html_gen = gg_message_text_to_html_gg11(message_plain);
  1781. +       if (message_html_gen == NULL)
  1782. +           goto fail;
  1783. +   }
  1784. +
  1785. +   message_html_len = strlen(message_html);
  1786. +   message_html_len_len = gg_packed_int_write(message_html_len_b, message_html_len);
  1787. +   message_plain_len = strlen(message_plain);
  1788. +   message_plain_len_len = gg_packed_int_write(message_plain_len_b, message_plain_len);
  1789. +
  1790. +   if (gg_send_packet(gs,
  1791. +       GG_CHAT_SEND_MSG,
  1792. +       dummy1, sizeof(dummy1),
  1793. +       seq_b, seq_len,
  1794. +       &dummy2, sizeof(dummy2),
  1795. +       message_plain_len_b, message_plain_len_len,
  1796. +       message_plain, message_plain_len,
  1797. +       &dummy3, sizeof(dummy3),
  1798. +       message_html_len_b, message_html_len_len,
  1799. +       message_html, message_html_len,
  1800. +       dummy4, sizeof(dummy4),
  1801. +       &id, sizeof(id),
  1802. +       NULL) == -1)
  1803. +   {
  1804. +       goto fail;
  1805. +   }
  1806. +
  1807. +   free(message_html_gen);
  1808. +   free(message_plain_gen);
  1809. +   return 0;
  1810. +fail:
  1811. +   free(message_html_gen);
  1812. +   free(message_plain_gen);
  1813. +   return -1;
  1814. +}
  1815. +
  1816.  /* @} */
  1817.  
  1818.  /**
  1819. Index: src/message.c
  1820. ===================================================================
  1821. --- src/message.c   (wersja 1323)
  1822. +++ src/message.c   (kopia robocza)
  1823. @@ -896,3 +896,80 @@
  1824.    
  1825.     return len;
  1826.  }
  1827. +
  1828. +static size_t gg_message_html_to_text_gg11_buff(char *dst, const char *html)
  1829. +{
  1830. +   return gg_message_html_to_text(dst, NULL, NULL, html, GG_ENCODING_UTF8) + 1;
  1831. +}
  1832. +
  1833. +static size_t gg_message_text_to_html_gg11_buff(char *dst, const char *text)
  1834. +{
  1835. +   size_t i, dst_len, src_len;
  1836. +
  1837. +   src_len = strlen(text);
  1838. +   dst_len = 0;
  1839. +
  1840. +   gg_append(dst, &dst_len, "<span>", 6);
  1841. +
  1842. +   for (i = 0; i < src_len; i++)
  1843. +   {
  1844. +       char c = text[i];
  1845. +       if (c == '<')
  1846. +           gg_append(dst, &dst_len, "&lt;", 4);
  1847. +       else if (c == '>')
  1848. +           gg_append(dst, &dst_len, "&gt;", 4);
  1849. +       else if (c == '&')
  1850. +           gg_append(dst, &dst_len, "&amp;", 5);
  1851. +       else if (c == '"')
  1852. +           gg_append(dst, &dst_len, "&quot;", 6);
  1853. +       else if (c == '\'')
  1854. +           gg_append(dst, &dst_len, "&apos;", 6);
  1855. +       else if (c == '\n')
  1856. +           gg_append(dst, &dst_len, "<br>", 4);
  1857. +       else if (c == '\r')
  1858. +           continue;
  1859. +       else if (c == '\xc2' && text[i + 1] == '\xa0') {
  1860. +           gg_append(dst, &dst_len, "&nbsp;", 6);
  1861. +           i++;
  1862. +       } else {
  1863. +           if (dst)
  1864. +               dst[dst_len] = c;
  1865. +           dst_len++;
  1866. +       }
  1867. +   }
  1868. +
  1869. +   gg_append(dst, &dst_len, "</span>", 7);
  1870. +
  1871. +   if (dst)
  1872. +       dst[dst_len] = '\0';
  1873. +   dst_len++;
  1874. +   return dst_len;
  1875. +}
  1876. +
  1877. +char * gg_message_html_to_text_gg11(const char *html)
  1878. +{
  1879. +   size_t dst_len;
  1880. +   char *dst;
  1881. +
  1882. +   dst_len = gg_message_html_to_text_gg11_buff(NULL, html);
  1883. +   dst = malloc(dst_len);
  1884. +   if (!dst)
  1885. +       return NULL;
  1886. +   gg_message_html_to_text_gg11_buff(dst, html);
  1887. +  
  1888. +   return dst;
  1889. +}
  1890. +
  1891. +char * gg_message_text_to_html_gg11(const char *text)
  1892. +{
  1893. +   size_t dst_len;
  1894. +   char *dst;
  1895. +
  1896. +   dst_len = gg_message_text_to_html_gg11_buff(NULL, text);
  1897. +   dst = malloc(dst_len);
  1898. +   if (!dst)
  1899. +       return NULL;
  1900. +   gg_message_text_to_html_gg11_buff(dst, text);
  1901. +  
  1902. +   return dst;
  1903. +}
  1904. Index: src/debug.c
  1905. ===================================================================
  1906. --- src/debug.c (wersja 1323)
  1907. +++ src/debug.c (kopia robocza)
  1908. @@ -349,6 +349,7 @@
  1909.     GG_DEBUG_EVENT(GG_EVENT_DCC7_DONE)
  1910.     GG_DEBUG_EVENT(GG_EVENT_DCC7_PENDING)
  1911.     GG_DEBUG_EVENT(GG_EVENT_XML_EVENT)
  1912. +   GG_DEBUG_EVENT(GG_EVENT_JSON_EVENT)
  1913.     GG_DEBUG_EVENT(GG_EVENT_DISCONNECT_ACK)
  1914.     GG_DEBUG_EVENT(GG_EVENT_TYPING_NOTIFICATION)
  1915.     GG_DEBUG_EVENT(GG_EVENT_USER_DATA)
  1916. @@ -356,6 +357,13 @@
  1917.     GG_DEBUG_EVENT(GG_EVENT_MULTILOGON_INFO)
  1918.     GG_DEBUG_EVENT(GG_EVENT_USERLIST100_VERSION)
  1919.     GG_DEBUG_EVENT(GG_EVENT_USERLIST100_REPLY)
  1920. +   GG_DEBUG_EVENT(GG_EVENT_IMTOKEN)
  1921. +   GG_DEBUG_EVENT(GG_EVENT_PONG110)
  1922. +   GG_DEBUG_EVENT(GG_EVENT_CHAT_INFO)
  1923. +   GG_DEBUG_EVENT(GG_EVENT_CHAT_INFO_UPDATE)
  1924. +   GG_DEBUG_EVENT(GG_EVENT_CHAT_CREATED)
  1925. +   GG_DEBUG_EVENT(GG_EVENT_CHAT_INVITE_ACK)
  1926. +   GG_DEBUG_EVENT(GG_EVENT_CHAT_SEND_MSG_ACK)
  1927.  #undef GG_DEBUG_EVENT
  1928.  
  1929.     /* Celowo nie ma default, żeby kompilator wyłapał brakujące zdarzenia */
  1930. Index: src/common.c
  1931. ===================================================================
  1932. --- src/common.c    (wersja 1323)
  1933. +++ src/common.c    (kopia robocza)
  1934. @@ -38,6 +38,7 @@
  1935.  
  1936.  #include "config.h"
  1937.  #include "libgadu.h"
  1938. +#include "internal.h"
  1939.  
  1940.  #ifndef GG_CONFIG_HAVE_VA_COPY
  1941.  #  ifdef GG_CONFIG_HAVE___VA_COPY
  1942. @@ -680,6 +681,151 @@
  1943.     return crc ^ 0xffffffffL;
  1944.  }
  1945.  
  1946. +uin_t gg_str_to_uin(const char *str, int len)
  1947. +{
  1948. +   char buff[11];
  1949. +   char *endptr;
  1950. +   uin_t uin;
  1951. +  
  1952. +   if (len < 0)
  1953. +       len = strlen(str);
  1954. +   if (len > 10)
  1955. +       return 0;
  1956. +   memcpy(buff, str, len);
  1957. +   buff[len] = '\0';
  1958. +  
  1959. +   errno = 0;
  1960. +   uin = strtoul(buff, &endptr, 10);
  1961. +   if (errno == ERANGE || endptr[0] != '\0')
  1962. +       return 0;
  1963. +  
  1964. +   return uin;
  1965. +}
  1966. +
  1967. +int gg_packed_int_read(const char *data, uint16_t *dst)
  1968. +{
  1969. +   uint16_t val;
  1970. +   uint8_t raw;
  1971. +  
  1972. +   raw = *data;
  1973. +   data++;
  1974. +   if (!(raw & 0x80))
  1975. +   {
  1976. +       *dst = raw;
  1977. +       return 1;
  1978. +   }
  1979. +  
  1980. +   val = raw & ~0x80;
  1981. +   raw = *data;
  1982. +   val |= (uint16_t)raw << 7;
  1983. +   *dst = val;
  1984. +   return 2;
  1985. +}
  1986. +
  1987. +int gg_packed_int_write(uint8_t dst[2], uint16_t val)
  1988. +{
  1989. +   if (val < 0x80)
  1990. +   {
  1991. +       dst[0] = val;
  1992. +       return 1;
  1993. +   }
  1994. +
  1995. +   dst[0] = (val & 0x7F) | 0x80;
  1996. +   dst[1] = (val >> 7);
  1997. +   return 2;
  1998. +}
  1999. +
  2000. +int gg_packed_uin_read(uin_t *dst, const char *data, int length)
  2001. +{
  2002. +   uint8_t full_len, uin_len;
  2003. +   uint8_t uin_type;
  2004. +  
  2005. +   int offset = 0;
  2006. +   *dst = 0;
  2007. +  
  2008. +   if (length < 1)
  2009. +       return 0;
  2010. +   full_len = data[offset++] + 1;
  2011. +   if (full_len > length)
  2012. +       return full_len;
  2013. +   uin_type = data[offset++];
  2014. +   if (uin_type != 0)
  2015. +       return full_len;
  2016. +   uin_len = data[offset++];
  2017. +   if (offset + uin_len > length)
  2018. +       return full_len;
  2019. +
  2020. +   *dst = gg_str_to_uin(data + offset, uin_len);
  2021. +   return full_len;
  2022. +}
  2023. +
  2024. +int gg_packed_uin_write(uint8_t *dst, int size, uin_t uin, int variant_long)
  2025. +{
  2026. +   char buff[20];
  2027. +   int uin_len;
  2028. +   int buff_len;
  2029. +   int offset = 0;
  2030. +  
  2031. +   snprintf(buff, sizeof(buff), "%u", uin);
  2032. +   uin_len = strlen(buff);
  2033. +   buff_len = uin_len + 2;
  2034. +   if (variant_long)
  2035. +       buff_len++;
  2036. +   if (buff_len > size)
  2037. +       return 0;
  2038. +   if (variant_long)
  2039. +       dst[offset++] = uin_len + 2;
  2040. +   dst[offset++] = 0x00;
  2041. +   dst[offset++] = uin_len;
  2042. +   memcpy(dst + offset, buff, uin_len);
  2043. +  
  2044. +   return buff_len;
  2045. +}
  2046. +
  2047. +struct gg_chat_list * gg_chat_find(struct gg_session *sess, uint64_t id)
  2048. +{
  2049. +   struct gg_chat_list * chat_list = sess->chat_list;
  2050. +   while (chat_list)
  2051. +   {
  2052. +       if (chat_list->id == id)
  2053. +           return chat_list;
  2054. +       chat_list = chat_list->next;
  2055. +   }
  2056. +   return NULL;
  2057. +}
  2058. +
  2059. +int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version, const uin_t *participants, int participants_count)
  2060. +{
  2061. +   struct gg_chat_list *chat;
  2062. +  
  2063. +   chat = gg_chat_find(sess, id);
  2064. +   if (!chat) {
  2065. +       struct gg_chat_list *last = sess->chat_list;
  2066. +       chat = malloc(sizeof(struct gg_chat_list));
  2067. +       if (!chat)
  2068. +           return -1;
  2069. +       memset(chat, 0, sizeof(struct gg_chat_list));
  2070. +       if (last == NULL)
  2071. +           sess->chat_list = chat;
  2072. +       else {
  2073. +           while (last->next != NULL)
  2074. +               last = last->next;
  2075. +           last->next = chat;
  2076. +       }
  2077. +       chat->id = id;
  2078. +   }
  2079. +   chat->version = version;
  2080. +   chat->participants_count = participants_count;
  2081. +   chat->participants = realloc(chat->participants, sizeof(uin_t) * participants_count);
  2082. +   if (chat->participants == NULL) {
  2083. +       chat->participants_count = 0;
  2084. +       return -1;
  2085. +   }
  2086. +   memcpy(chat->participants, participants, sizeof(uin_t) * participants_count);
  2087. +
  2088. +   return 0;
  2089. +}
  2090. +
  2091.  /*
  2092.   * Local variables:
  2093.   * c-indentation-style: k&r
  2094. Index: src/libgadu.sym
  2095. ===================================================================
  2096. --- src/libgadu.sym (wersja 1323)
  2097. +++ src/libgadu.sym (kopia robocza)
  2098. @@ -13,6 +13,10 @@
  2099.  gg_change_status_descr
  2100.  gg_change_status_descr_time
  2101.  gg_change_status_flags
  2102. +gg_chat_create
  2103. +gg_chat_invite
  2104. +gg_chat_leave
  2105. +gg_chat_send_message
  2106.  gg_chomp
  2107.  gg_connect
  2108.  gg_crc32
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement