Advertisement
tomkiewicz

gg11-1

Aug 29th, 2012
264
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 28.79 KB | None | 0 0
  1. Index: include/libgadu.h.in
  2. ===================================================================
  3. --- include/libgadu.h.in    (wersja 1314)
  4. +++ include/libgadu.h.in    (kopia robocza)
  5. @@ -676,6 +676,9 @@
  6.  int gg_typing_notification(struct gg_session *sess, uin_t recipient, int length);
  7.  
  8.  uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len);
  9. +uin_t gg_str_to_uin(const char *str, int len);
  10. +int gg_packed_int_read(const char *data, uint16_t *dst);
  11. +int gg_packed_int_write(uint8_t dst[2], uint16_t val);
  12.  
  13.  int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type);
  14.  gg_resolver_t gg_session_get_resolver(struct gg_session *gs);
  15. @@ -746,6 +749,9 @@
  16.  
  17.     GG_EVENT_USERLIST100_VERSION,   /**< Otrzymano numer wersji listy kontaktów na serwerze (10.0) */
  18.     GG_EVENT_USERLIST100_REPLY, /**< Wynik importu lub eksportu listy kontaktów (10.0) */
  19. +
  20. +   GG_EVENT_IMTOKEN,
  21. +   GG_EVENT_PONG110,
  22.  };
  23.  
  24.  #define GG_EVENT_SEARCH50_REPLY GG_EVENT_PUBDIR50_SEARCH_REPLY
  25. @@ -1071,6 +1077,14 @@
  26.     char *reply;            /**< Treść listy kontaktów w przesyłanej wersji i formacie */
  27.  };
  28.  
  29. +struct gg_event_imtoken {
  30. +   char *imtoken;
  31. +};
  32. +
  33. +struct gg_event_pong110 {
  34. +   time_t time;
  35. +};
  36. +
  37.  /**
  38.   * Unia wszystkich zdarzeń zwracanych przez funkcje \c gg_watch_fd(),
  39.   * \c gg_dcc_watch_fd() i \c gg_dcc7_watch_fd().
  40. @@ -1107,6 +1121,8 @@
  41.     struct gg_event_multilogon_info multilogon_info;    /**< Informacja o innych sesjach multilogowania (\c GG_EVENT_MULTILOGON_INFO) */
  42.     struct gg_event_userlist100_version userlist100_version;    /**< Informacja o numerze wersji listy kontaktów na serwerze (\c GG_EVENT_USERLIST100_VERSION) */
  43.     struct gg_event_userlist100_reply userlist100_reply;    /**< Odpowiedź listy kontaktów (10.0) (\c GG_EVENT_USERLIST100_REPLY) */
  44. +   struct gg_event_imtoken imtoken;
  45. +   struct gg_event_pong110 pong110;
  46.  };
  47.  
  48.  /**
  49. @@ -1573,8 +1589,8 @@
  50.  #define GG_HTTPS_PORT 443
  51.  #define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)"
  52.  
  53. -#define GG_DEFAULT_CLIENT_VERSION "10.1.0.11070"
  54. -#define GG_DEFAULT_PROTOCOL_VERSION 0x2e
  55. +#define GG_DEFAULT_CLIENT_VERSION "11.0.0.8255"
  56. +#define GG_DEFAULT_PROTOCOL_VERSION 0x2f
  57.  #define GG_DEFAULT_TIMEOUT 30
  58.  #define GG_HAS_AUDIO_MASK 0x40000000
  59.  #define GG_HAS_AUDIO7_MASK 0x20000000
  60. @@ -1944,6 +1960,8 @@
  61.  
  62.  #define GG_ADD_NOTIFY 0x000d
  63.  #define GG_REMOVE_NOTIFY 0x000e
  64. +#define GG_ADD_NOTIFY105 0x007b
  65. +#define GG_REMOVE_NOTIFY105 0x007c
  66.  
  67.  struct gg_add_remove {
  68.     uint32_t uin;           /* numerek */
  69. @@ -2137,6 +2155,7 @@
  70.  #define GG_USERLIST_REQUEST 0x0016
  71.  
  72.  #define GG_XML_EVENT 0x0027
  73. +#define GG_XML_EVENT110 0x0084
  74.  
  75.  #ifndef DOXYGEN
  76.  
  77. @@ -2355,6 +2374,12 @@
  78.  #define GG_DCC7_TIMEOUT_FILE_ACK 300   /* 5 minut */
  79.  #define GG_DCC7_TIMEOUT_VOICE_ACK 300  /* 5 minut */
  80.  
  81. +#define GG_IMTOKEN 0x008c
  82. +#define GG_NOTIFY105_FIRST 0x0077
  83. +#define GG_NOTIFY105_LAST 0x0078
  84. +#define GG_NOTIFY105_LIST_EMPTY 0x0079
  85. +#define GG_PONG110 0x00a1
  86. +
  87.  #ifdef __cplusplus
  88.  }
  89.  #endif
  90. Index: include/protocol.h
  91. ===================================================================
  92. --- include/protocol.h  (wersja 1314)
  93. +++ include/protocol.h  (kopia robocza)
  94. @@ -32,6 +32,7 @@
  95.  #define GG_LOGIN80BETA 0x0029
  96.  
  97.  #define GG_LOGIN80 0x0031
  98. +#define GG_LOGIN105 0x0083
  99.  
  100.  #undef GG_FEATURE_STATUS80BETA
  101.  #undef GG_FEATURE_MSG80
  102. @@ -42,6 +43,8 @@
  103.  
  104.  #define GG8_LANG   "pl"
  105.  #define GG8_VERSION    "Gadu-Gadu Client Build "
  106. +#define GG11_VERSION   "GG "
  107. +#define GG11_TARGET    " WINNT"
  108.  
  109.  struct gg_login80 {
  110.     uint32_t uin;           /* mój numerek */
  111. @@ -63,6 +66,8 @@
  112.  
  113.  #define GG_LOGIN80_OK 0x0035
  114.  
  115. +#define GG_LOGIN110_OK 0x009d
  116. +
  117.  /**
  118.   * Logowanie powiodło się (pakiet \c GG_LOGIN80_OK)
  119.   */
  120. @@ -92,6 +97,8 @@
  121.     uint32_t description_size;      /**< rozmiar opisu */
  122.  } GG_PACKED;
  123.  
  124. +#define GG_NEW_STATUS105 0x0063
  125. +
  126.  #define GG_STATUS80BETA 0x002a
  127.  #define GG_NOTIFY_REPLY80BETA 0x002b
  128.  
  129. @@ -131,6 +138,8 @@
  130.     uint32_t offset_attr;
  131.  } GG_PACKED;
  132.  
  133. +#define GG_SEND_MSG110 0x007d
  134. +
  135.  #define GG_DISCONNECT_ACK 0x000d
  136.  
  137.  #define GG_RECV_MSG_ACK 0x0046
  138. @@ -319,6 +328,20 @@
  139.     /* char reply[]; */
  140.  } GG_PACKED;
  141.  
  142. +struct gg_pong110 {
  143. +   uint8_t dummy;
  144. +   uint32_t time;
  145. +} GG_PACKED;
  146. +
  147. +#define GG_RECV_MSG110 0x007e
  148. +#define GG_RECV_CHAT110 0x0088
  149. +#define GG_RECV_OWN_MSG110 0x0082
  150. +#define GG_ACK110 0x0086
  151. +
  152. +#define GG_ACK110_MSG 0x01
  153. +#define GG_ACK110_CHAT 0x02
  154. +#define GG_ACK110_MPA 0x06
  155. +
  156.  #ifdef _WIN32
  157.  #pragma pack(pop)
  158.  #endif
  159. Index: src/handlers.c
  160. ===================================================================
  161. --- src/handlers.c  (wersja 1314)
  162. +++ src/handlers.c  (kopia robocza)
  163. @@ -61,6 +61,247 @@
  164.     int (*handler)(struct gg_session *, uint32_t, const char *, size_t, struct gg_event *);
  165.  } gg_packet_handler_t;
  166.  
  167. +static int gg_ack_gg11(struct gg_session *gs, uint8_t type, uint16_t seq, struct gg_event *ge)
  168. +{
  169. +   uint8_t dunno1 = 0x08;
  170. +   uint8_t dunno2 = 0x10;
  171. +   uint8_t seq_b[2];
  172. +   int seq_len;
  173. +   uint8_t dunno3[2] = { 0x18, 0x01 };
  174. +   int ret;
  175. +
  176. +   seq_len = gg_packed_int_write(seq_b, seq);
  177. +
  178. +   ret = gg_send_packet(gs,
  179. +           GG_ACK110,
  180. +           &dunno1, sizeof(dunno1),
  181. +           &type, sizeof(type),
  182. +           &dunno2, sizeof(dunno2),
  183. +           seq_b, seq_len,
  184. +           dunno3, sizeof(dunno3),
  185. +           NULL);
  186. +
  187. +   if (ret == -1) {
  188. +       int errno_copy;
  189. +
  190. +       gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
  191. +       errno_copy = errno;
  192. +       close(gs->fd);
  193. +       errno = errno_copy;
  194. +       gs->fd = -1;
  195. +       ge->type = GG_EVENT_CONN_FAILED;
  196. +       ge->event.failure = GG_FAILURE_WRITING;
  197. +       gs->state = GG_STATE_IDLE;
  198. +       return -1;
  199. +   }
  200. +
  201. +   return 0;
  202. +}
  203. +
  204. +static int gg_session_handle_welcome_gg11(struct gg_session *gs, uint32_t seed, struct gg_event *ge)
  205. +{
  206. +   const uint8_t section_headers[6] = {0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a};
  207. +   const uint8_t lang_length = 2;
  208. +   const char *lang = GG8_LANG;
  209. +   const uint8_t dunno1 = 0x12;
  210. +   uint8_t uin_block_len;
  211. +   const uint8_t dunno2 = 0x00; /* uin type? */
  212. +   uint8_t uin_len;
  213. +   char *uin;
  214. +   uint8_t hash_len = 20;
  215. +   uint8_t hash[64];
  216. +   const uint8_t dunno3[9] = {0x20, 0x02, 0x2d, 0x77, 0xff, 0xae, 0x01, 0x35, 0x14};
  217. +   uint8_t privacy;
  218. +   const uint8_t dunno4[2] = {0x03, 0x00};
  219. +   uint8_t client_len;
  220. +   const char *client_name = GG11_VERSION;
  221. +   const char *client_version = GG_DEFAULT_CLIENT_VERSION;
  222. +   const char *client_target = GG11_TARGET;
  223. +   const uint8_t dunno5 = 0x45;
  224. +   uint32_t status;
  225. +   uint8_t descr_len;
  226. +   const char *descr;
  227. +   const uint8_t dunno6[6] = {0x52, 0x04, 0x00, 0x00, 0x00, 0x00};
  228. +   uint8_t userdata_len;
  229. +   const char *userdata;
  230. +   const uint8_t dunno7[15] = {0x60, 0xff, 0x01, 0x68, 0x64, 0x75, 0x7f,
  231. +       0x00, 0x00, 0x00, 0x78, 0x00, 0x88, 0x01, 0x00};
  232. +
  233. +   uint8_t client_name_len;
  234. +   uint8_t client_version_len;
  235. +   uint8_t client_target_len;
  236. +   int ret;
  237. +
  238. +   if (gs->hash_type != GG_LOGIN_HASH_SHA1) {
  239. +       gg_debug_session(gs, GG_DEBUG_MISC, "// Unsupported hash type for this protocol version\n");
  240. +       return -1;
  241. +   }
  242. +  
  243. +   if (gg_login_hash_sha1_2(gs->password, seed, hash) == -1) {
  244. +       int errno_copy;
  245. +
  246. +       gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() gg_login_hash_sha1_2() failed, probably out of memory\n");
  247. +       errno_copy = errno;
  248. +       close(gs->fd);
  249. +       errno = errno_copy;
  250. +       gs->fd = -1;
  251. +       ge->type = GG_EVENT_CONN_FAILED;
  252. +       ge->event.failure = GG_FAILURE_INTERNAL;
  253. +       gs->state = GG_STATE_IDLE;
  254. +       return -1;
  255. +   }
  256. +
  257. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending GG_LOGIN105 packet\n");
  258. +  
  259. +   /*
  260. +   zmienia format pakietu
  261. +   dunno2[3] == 0x37 dla gg10.5
  262. +   dunno2[3] == 0x77 dla gg11.0
  263. +   */
  264. +  
  265. +   uin = gg_saprintf("%u", gs->uin);
  266. +   uin_len = strlen(uin);
  267. +   uin_block_len = uin_len + 2;
  268. +  
  269. +   privacy = 0x00; /* 0x06 - pokazuj kamerkę znajomym */
  270. +  
  271. +   /* flagi gg8 są różne od tych dla gg11 */
  272. +   status = gg_fix32(gs->initial_status ? (gs->initial_status & 0xFF) : GG_STATUS_AVAIL);
  273. +
  274. +   if (gs->client_version != NULL && !isdigit(gs->client_version[0])) {
  275. +       client_name = "";
  276. +       client_target = "";
  277. +   }
  278. +   if (gs->client_version != NULL)
  279. +       client_version = gs->client_version;
  280. +   client_name_len = strlen(client_name);
  281. +   client_version_len = strlen(client_version);
  282. +   client_target_len = strlen(client_target);
  283. +   client_len = client_name_len + client_version_len + client_target_len;
  284. +
  285. +   descr = (gs->initial_descr != NULL) ? gs->initial_descr : "";
  286. +   descr_len = (gs->initial_descr != NULL) ? strlen(gs->initial_descr) : 0;
  287. +
  288. +   userdata = "avatar,StatusComments,gg_account_sdp,edisc,bot,fanpage,"
  289. +       "pubdir,botCaps";
  290. +   userdata_len = strlen(userdata);
  291. +
  292. +   ret = gg_send_packet(gs,
  293. +           GG_LOGIN105,
  294. +           &section_headers[0], 1,
  295. +           &lang_length, sizeof(lang_length),
  296. +           lang, lang_length,
  297. +           &dunno1, sizeof(dunno1),
  298. +           &uin_block_len, sizeof(uin_block_len),
  299. +           &dunno2, sizeof(dunno2),
  300. +           &uin_len, sizeof(uin_len),
  301. +           uin, uin_len,
  302. +          
  303. +           &section_headers[1], 1,
  304. +           &hash_len, sizeof(hash_len),
  305. +           hash, hash_len,
  306. +           dunno3, sizeof(dunno3),
  307. +           &privacy, sizeof(privacy),
  308. +           dunno4, sizeof(dunno4),
  309. +          
  310. +           &section_headers[3], 1,
  311. +           &client_len, sizeof(client_len),
  312. +           client_name, client_name_len,
  313. +           client_version, client_version_len,
  314. +           client_target, client_target_len,
  315. +           &dunno5, sizeof(dunno5),
  316. +           &status, sizeof(status),
  317. +          
  318. +           &section_headers[4], 1,
  319. +           &descr_len, sizeof(descr_len),
  320. +           descr, descr_len,
  321. +           dunno6, sizeof(dunno6),
  322. +          
  323. +           &section_headers[5], 1,
  324. +           &userdata_len, sizeof(userdata_len),
  325. +           userdata, userdata_len,
  326. +          
  327. +           dunno7, sizeof(dunno7),
  328. +           NULL);
  329. +   free(uin);
  330. +
  331. +   if (ret == -1) {
  332. +       int errno_copy;
  333. +
  334. +       gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
  335. +       errno_copy = errno;
  336. +       close(gs->fd);
  337. +       errno = errno_copy;
  338. +       gs->fd = -1;
  339. +       ge->type = GG_EVENT_CONN_FAILED;
  340. +       ge->event.failure = GG_FAILURE_WRITING;
  341. +       gs->state = GG_STATE_IDLE;
  342. +       return -1;
  343. +   }
  344. +
  345. +   gs->state = GG_STATE_READING_REPLY;
  346. +   gs->check = GG_CHECK_READ;
  347. +
  348. +   return 0;
  349. +}
  350. +
  351. +static int gg_session_handle_login110_ok(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  352. +{
  353. +   uint8_t somehash_len;
  354. +   char *somehash = NULL;
  355. +   uint32_t server_time;
  356. +   int offset = 0;
  357. +
  358. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n");
  359. +   ge->type = GG_EVENT_CONN_SUCCESS;
  360. +   gs->state = GG_STATE_CONNECTED;
  361. +   gs->check = GG_CHECK_READ;
  362. +   gs->timeout = -1;
  363. +   gs->status = (gs->initial_status) ? gs->initial_status : GG_STATUS_AVAIL;
  364. +#if 0
  365. +   free(gs->status_descr);
  366. +   gs->status_descr = gs->initial_descr;
  367. +#else
  368. +   free(gs->initial_descr);
  369. +#endif
  370. +   gs->initial_descr = NULL;
  371. +
  372. +   if (offset + 3 > len)
  373. +       goto fail;
  374. +   /* 0x08 01 12 */
  375. +   offset += 3;
  376. +  
  377. +   if (offset + 1 > len)
  378. +       goto fail;
  379. +   somehash_len = ptr[offset];
  380. +   offset++;
  381. +   if (offset + somehash_len > len)
  382. +       goto fail;
  383. +   somehash = malloc(somehash_len + 1);
  384. +   if (somehash == NULL)
  385. +       goto fail;
  386. +   memcpy(somehash, ptr + offset, somehash_len);
  387. +   somehash[somehash_len] = '\0';
  388. +   offset += somehash_len;
  389. +
  390. +   if (offset + 6 > len)
  391. +       goto fail;
  392. +   /* 0x18 _f __ __ __ 25 */
  393. +   offset += 6;
  394. +
  395. +   if (offset + 4 > len)
  396. +       goto fail;
  397. +   server_time = gg_fix32(*((uint32_t*)(ptr + offset)));
  398. +
  399. +   gg_debug_session(gs, GG_DEBUG_MISC, "// login110_ok: some hash=%s, server time=%u\n", somehash, server_time);
  400. +   free(somehash);
  401. +
  402. +   return 0;
  403. +fail:
  404. +   free(somehash);
  405. +   return -1;
  406. +}
  407. +
  408.  /**
  409.   * \internal Obsługuje pakiet GG_WELCOME.
  410.   *
  411. @@ -92,6 +333,9 @@
  412.     w = (const struct gg_welcome*) ptr;
  413.     seed = gg_fix32(w->key);
  414.  
  415. +   if (gs->protocol_version >= 0x2f)
  416. +       return gg_session_handle_welcome_gg11(gs, seed, ge);
  417. +
  418.     memset(hash_buf, 0, sizeof(hash_buf));
  419.  
  420.     switch (gs->hash_type) {
  421. @@ -347,6 +591,47 @@
  422.     return 0;
  423.  }
  424.  
  425. +static int gg_session_handle_xml_event110(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  426. +{
  427. +   int offset = 0;
  428. +   uint16_t seq, data_len;
  429. +   char *data;
  430. +  
  431. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received GG11 XML event\n");
  432. +  
  433. +   if (offset + 3 > len)
  434. +       goto fail;
  435. +   /* 0x08 00 10 */
  436. +   offset += 3;
  437. +  
  438. +   if (offset + 2 > len)
  439. +       goto fail;
  440. +   offset += gg_packed_int_read(ptr + offset, &seq);
  441. +  
  442. +   if (offset + 1 > len)
  443. +       goto fail;
  444. +   /* 0x1a */
  445. +   offset++;
  446. +
  447. +   if (offset + 2 > len)
  448. +       goto fail;
  449. +   offset += gg_packed_int_read(ptr + offset, &data_len);
  450. +  
  451. +   data = malloc(data_len + 1);
  452. +   if (data == NULL)
  453. +       goto fail;
  454. +   memcpy(data, ptr + offset, data_len);
  455. +   data[data_len] = '\0';
  456. +  
  457. +   ge->type = GG_EVENT_XML_EVENT;
  458. +   ge->event.xml_event.data = data;
  459. +  
  460. +   return gg_ack_gg11(gs, GG_ACK110_MPA, seq, ge);
  461. +fail:
  462. +   free(data);
  463. +   return -1;
  464. +}
  465. +
  466.  /**
  467.   * \internal Obsługuje pakiet GG_PUBDIR50_REPLY.
  468.   *
  469. @@ -990,6 +1275,156 @@
  470.     return 0;
  471.  }
  472.  
  473. +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)
  474. +{
  475. +   int offset = 0;
  476. +   uint8_t uin_len;
  477. +   uint16_t seq = 0;
  478. +   uint16_t msg_len;
  479. +  
  480. +   uint32_t dummy_time1, dummy_time2;
  481. +  
  482. +   gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg110(%p, %d, %p);\n", packet, length, e);
  483. +  
  484. +   if (offset + 3 > length)
  485. +       goto fail;
  486. +   /* 0x0a 0a 00 */
  487. +   offset += 3;
  488. +  
  489. +   if (offset + 1 > length)
  490. +       goto fail;
  491. +   uin_len = packet[offset++];
  492. +   if (offset + uin_len > length)
  493. +       goto fail;
  494. +   e->event.msg.sender = gg_str_to_uin(packet + offset, uin_len);
  495. +   offset += uin_len;
  496. +   if (e->event.msg.sender == 0)
  497. +       goto fail;
  498. +
  499. +   if (offset + 3 > length)
  500. +       goto fail;
  501. +   /* 0x10 08 18 -> ustawiany przez nadawcę? */
  502. +   /* 0x10 09 18 -> archiwalna wiadomość? */
  503. +   offset += 3;
  504. +
  505. +   if (offset + 2 > length)
  506. +       goto fail;
  507. +   offset += gg_packed_int_read(packet + offset, &seq);
  508. +   e->event.msg.seq = seq;
  509. +
  510. +   if (offset + 1 > length)
  511. +       goto fail;
  512. +   /* 0x25 */
  513. +   offset++;
  514. +
  515. +   if (offset + 4 > length)
  516. +       goto fail;
  517. +   e->event.msg.time = gg_fix32(*((uint32_t*)(packet + offset)));
  518. +   offset += 4;
  519. +
  520. +   if (offset + 1 > length)
  521. +       goto fail;
  522. +   /* 0x2a */
  523. +   offset++;
  524. +
  525. +   if (offset + 2 > length)
  526. +       goto fail;
  527. +   offset += gg_packed_int_read(packet + offset, &msg_len);
  528. +   if (offset + msg_len > length)
  529. +       goto fail;
  530. +   e->event.msg.message = malloc(msg_len + 1);
  531. +   if (e->event.msg.message == NULL)
  532. +       goto fail;
  533. +   /* TODO: kodowanie */
  534. +   memcpy(e->event.msg.message, packet + offset, msg_len);
  535. +   e->event.msg.message[msg_len] = '\0';
  536. +   offset += msg_len;
  537. +  
  538. +   if (offset + 1 > length)
  539. +       goto fail;
  540. +   /* 0x32 */
  541. +   offset++;
  542. +  
  543. +   if (offset + 2 > length)
  544. +       goto fail;
  545. +   offset += gg_packed_int_read(packet + offset, &msg_len);
  546. +   if (offset + msg_len > length)
  547. +       goto fail;
  548. +   e->event.msg.xhtml_message = malloc(msg_len + 1);
  549. +   if (e->event.msg.xhtml_message == NULL)
  550. +       goto fail;
  551. +   /* TODO: kodowanie */
  552. +   memcpy(e->event.msg.xhtml_message, packet + offset, msg_len);
  553. +   e->event.msg.xhtml_message[msg_len] = '\0';
  554. +   offset += msg_len;
  555. +  
  556. +   if (offset + 1 > length)
  557. +       goto fail;
  558. +   /* otrzymywane tylko od gg <= 10.5 */
  559. +   if (packet[offset] == 0x3a)
  560. +   {
  561. +       uint8_t formats_length;
  562. +      
  563. +       offset++;
  564. +       if (offset + 1 > length)
  565. +           goto fail;
  566. +       formats_length = packet[offset++];
  567. +       if (offset + formats_length > length)
  568. +           goto fail;
  569. +       e->event.msg.formats_length = formats_length;
  570. +      
  571. +       e->event.msg.formats = malloc(formats_length);
  572. +       if (e->event.msg.formats == NULL)
  573. +           goto fail;
  574. +       memcpy(e->event.msg.formats, packet + offset, formats_length);
  575. +       offset += formats_length;
  576. +   }
  577. +  
  578. +   if (type == GG_RECV_CHAT110) {
  579. +       /* 49 02 10 __ 00 __ 8_ 3a 50 51 8c 31 01 01 */
  580. +       if (offset + 14 > length)
  581. +           goto fail;
  582. +       offset += 14;
  583. +   } else {
  584. +       /* 49 __ 02 __ 00 */
  585. +       if (offset + 5 > length)
  586. +           goto fail;
  587. +       offset += 5;
  588. +   }
  589. +  
  590. +   if (offset + 4 > length)
  591. +       goto fail;
  592. +   /* taki sam czas jak czas wiadomości lub o jeden mniej */
  593. +   dummy_time1 = gg_fix32(*((uint32_t*)(packet + offset)));
  594. +   offset += 4;
  595. +  
  596. +   if (offset + 5 > length)
  597. +       goto fail;
  598. +   /* id rozmówcy? konwersacji? */
  599. +   /* 0x59 __ __ 0_ 00 */
  600. +   offset += 5;
  601. +
  602. +   if (offset + 4 > length)
  603. +       goto fail;
  604. +   /* czas początku konwersacji? */
  605. +   dummy_time2 = gg_fix32(*((uint32_t*)(packet + offset)));
  606. +  
  607. +   e->type = (type != GG_RECV_OWN_MSG110) ? GG_EVENT_MSG : GG_EVENT_MULTILOGON_MSG;
  608. +   e->event.msg.msgclass = GG_CLASS_CHAT;
  609. +   e->event.msg.seq = seq;
  610. +
  611. +   return gg_ack_gg11(sess, (type != GG_RECV_CHAT110) ? GG_ACK110_MSG : GG_ACK110_CHAT, seq, e);
  612. +
  613. +fail:
  614. +   free(e->event.msg.message);
  615. +   free(e->event.msg.xhtml_message);
  616. +   free(e->event.msg.recipients);
  617. +   free(e->event.msg.formats);
  618. +   if (seq)
  619. +       gg_ack_gg11(sess, (type != GG_RECV_CHAT110) ? GG_ACK110_MSG : GG_ACK110_CHAT, seq, e);
  620. +   return -1;
  621. +}
  622. +
  623.  /**
  624.   * \internal Obsługuje pakiet GG_STATUS.
  625.   *
  626. @@ -1764,6 +2199,54 @@
  627.     return 0;
  628.  }
  629.  
  630. +static int gg_session_handle_imtoken(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  631. +{
  632. +   uint8_t imtoken_len;
  633. +   char *imtoken = NULL;
  634. +   int offset = 0;
  635. +
  636. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received imtoken\n");
  637. +  
  638. +   if (offset + 1 > len)
  639. +       goto fail;
  640. +   /* 0x0a */
  641. +   offset++;
  642. +  
  643. +   if (offset + 1 > len)
  644. +       goto fail;
  645. +   imtoken_len = ptr[offset];
  646. +   offset++;
  647. +   if (offset + imtoken_len > len)
  648. +       goto fail;
  649. +   if (imtoken_len > 0) {
  650. +       imtoken = malloc(imtoken_len + 1);
  651. +       if (imtoken == NULL)
  652. +           goto fail;
  653. +       memcpy(imtoken, ptr + offset, imtoken_len);
  654. +       imtoken[imtoken_len] = '\0';
  655. +   }
  656. +  
  657. +   ge->type = GG_EVENT_IMTOKEN;
  658. +   ge->event.imtoken.imtoken = imtoken;
  659. +  
  660. +   return 0;
  661. +fail:
  662. +   free(imtoken);
  663. +   return -1;
  664. +}
  665. +
  666. +static int gg_session_handle_pong110(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
  667. +{
  668. +   const struct gg_pong110 *pong = (const struct gg_pong110*)ptr;
  669. +  
  670. +   gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received pong110\n");
  671. +  
  672. +   ge->type = GG_EVENT_PONG110;
  673. +   ge->event.pong110.time = gg_fix32(pong->time);
  674. +  
  675. +   return 0;
  676. +}
  677. +
  678.  /**
  679.   * \internal Tablica obsługiwanych pakietów
  680.   */
  681. @@ -1772,6 +2255,7 @@
  682.     { GG_WELCOME, GG_STATE_READING_KEY, 0, gg_session_handle_welcome },
  683.     { GG_LOGIN_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
  684.     { GG_LOGIN80_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
  685. +   { GG_LOGIN110_OK, GG_STATE_READING_REPLY, 0, gg_session_handle_login110_ok },
  686.     { GG_NEED_EMAIL, GG_STATE_READING_REPLY, 0, gg_session_handle_login_ok },
  687.     { GG_LOGIN_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed },
  688.     { GG_LOGIN80_FAILED, GG_STATE_READING_REPLY, 0, gg_session_handle_login_failed },
  689. @@ -1780,6 +2264,7 @@
  690.     { GG_DISCONNECTING, GG_STATE_CONNECTED, 0, gg_session_handle_disconnecting },
  691.     { GG_DISCONNECT_ACK, GG_STATE_DISCONNECTING, 0, gg_session_handle_disconnect_ack },
  692.     { GG_XML_EVENT, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event },
  693. +   { GG_XML_EVENT110, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event110 },
  694.     { GG_PUBDIR50_REPLY, GG_STATE_CONNECTED, 0, gg_session_handle_pubdir50_reply },
  695.     { GG_USERLIST_REPLY, GG_STATE_CONNECTED, 0, gg_session_handle_userlist_reply },
  696.     { GG_DCC7_ID_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_id_reply), gg_session_handle_dcc7_id_reply },
  697. @@ -1789,6 +2274,9 @@
  698.     { GG_DCC7_INFO, GG_STATE_CONNECTED, sizeof(struct gg_dcc7_info), gg_session_handle_dcc7_info },
  699.     { GG_RECV_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg), gg_session_handle_recv_msg },
  700.     { GG_RECV_MSG80, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
  701. +   { GG_RECV_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
  702. +   { GG_RECV_CHAT110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
  703. +   { GG_RECV_OWN_MSG110, GG_STATE_CONNECTED, 0, gg_session_handle_recv_msg_110 },
  704.     { GG_STATUS, GG_STATE_CONNECTED, sizeof(struct gg_status), gg_session_handle_status },
  705.     { GG_STATUS60, GG_STATE_CONNECTED, sizeof(struct gg_status60), gg_session_handle_status_60_77_80beta },
  706.     { GG_STATUS77, GG_STATE_CONNECTED, sizeof(struct gg_status77), gg_session_handle_status_60_77_80beta },
  707. @@ -1806,6 +2294,8 @@
  708.     { GG_RECV_OWN_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
  709.     { GG_USERLIST100_VERSION, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_version), gg_session_handle_userlist_100_version },
  710.     { GG_USERLIST100_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_reply), gg_session_handle_userlist_100_reply },
  711. +   { GG_IMTOKEN, GG_STATE_CONNECTED, 0, gg_session_handle_imtoken },
  712. +   { GG_PONG110, GG_STATE_CONNECTED, sizeof(struct gg_pong110), gg_session_handle_pong110 },
  713.  };
  714.  
  715.  /**
  716. Index: src/events.c
  717. ===================================================================
  718. --- src/events.c    (wersja 1314)
  719. +++ src/events.c    (kopia robocza)
  720. @@ -166,6 +166,10 @@
  721.         case GG_EVENT_USERLIST100_REPLY:
  722.             free(e->event.userlist100_reply.reply);
  723.             break;
  724. +
  725. +       case GG_EVENT_IMTOKEN:
  726. +           free(e->event.imtoken.imtoken);
  727. +           break;
  728.     }
  729.  
  730.     free(e);
  731. Index: src/libgadu.c
  732. ===================================================================
  733. --- src/libgadu.c   (wersja 1314)
  734. +++ src/libgadu.c   (kopia robocza)
  735. @@ -1074,10 +1074,28 @@
  736.     p.status        = gg_fix32(status);
  737.     p.flags         = gg_fix32(sess->status_flags);
  738.     p.description_size  = gg_fix32(descr_len);
  739. -   res = gg_send_packet(sess, GG_NEW_STATUS80,
  740. -           &p, sizeof(p),
  741. -           (new_descr) ? new_descr : descr, descr_len,
  742. +
  743. +   if (sess->protocol_version >= 0x2f) {
  744. +       uint8_t dummy1[4] = { 0x00, 0x00, 0x00, 0x00 };
  745. +       const char *set_descr = "";
  746. +
  747. +       if (new_descr)
  748. +           set_descr = new_descr;
  749. +       else if (descr)
  750. +           set_descr = descr;
  751. +
  752. +       p.flags = gg_fix32(0x00000014);
  753. +       res = gg_send_packet(sess, GG_NEW_STATUS105,
  754. +           &p, sizeof(p),
  755. +           set_descr, descr_len,
  756. +           dummy1, sizeof(dummy1),
  757.             NULL);
  758. +   } else {
  759. +       res = gg_send_packet(sess, GG_NEW_STATUS80,
  760. +           &p, sizeof(p),
  761. +           new_descr ? new_descr : descr, descr_len,
  762. +           NULL);
  763. +   }
  764.  
  765.     free(new_descr);
  766.  
  767. @@ -1137,6 +1155,54 @@
  768.  
  769.  #ifndef DOXYGEN
  770.  
  771. +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)
  772. +{
  773. +   uint8_t dummy1[3] = { 0x0a, 0x0a, 0x00 };
  774. +   uint8_t uin_len;
  775. +   char uin_s[15];
  776. +   uint8_t dummy2[3] = { 0x10, 0x08, 0x18 };
  777. +   uint8_t seq_b[2];
  778. +   int seq_len;
  779. +   uint8_t dummy3 = 0x2a;
  780. +   uint8_t message_len_b[2];
  781. +   int message_len_len;
  782. +   uint8_t dummy4 = 0x32;
  783. +   uint8_t html_message_len_b[2];
  784. +   int html_message_len_len;
  785. +
  786. +   int message_len, html_message_len;
  787. +   int seq = ++sess->seq;
  788. +
  789. +   sprintf(uin_s, "%u", recipients[0]);
  790. +   uin_len = strlen(uin_s);
  791. +  
  792. +   message_len = strlen(message);
  793. +   html_message_len = strlen(html_message);
  794. +   seq_len = gg_packed_int_write(seq_b, seq);
  795. +   message_len_len = gg_packed_int_write(message_len_b, message_len);
  796. +   html_message_len_len = gg_packed_int_write(html_message_len_b, html_message_len);
  797. +
  798. +   if (gg_send_packet(sess,
  799. +       GG_SEND_MSG110,
  800. +       dummy1, sizeof(dummy1),
  801. +       &uin_len, sizeof(uin_len),
  802. +       uin_s, uin_len,
  803. +       dummy2, sizeof(dummy2),
  804. +       seq_b, seq_len,
  805. +       &dummy3, sizeof(dummy3),
  806. +       message_len_b, message_len_len,
  807. +       message, message_len,
  808. +       &dummy4, sizeof(dummy4),
  809. +       html_message_len_b, html_message_len_len,
  810. +       html_message, html_message_len,
  811. +       NULL) == -1)
  812. +   {
  813. +       return -1;
  814. +   }
  815. +
  816. +   return seq;
  817. +}
  818. +
  819.  /**
  820.   * \internal Wysyła wiadomość.
  821.   *
  822. @@ -1235,6 +1301,7 @@
  823.         }
  824.     }
  825.  
  826. +   //TODO: dla gg11, domyślne formatowanie to <span></span>
  827.     if (html_message == NULL) {
  828.         size_t len;
  829.         char *tmp;
  830. @@ -1277,6 +1344,12 @@
  831.         }
  832.     }
  833.  
  834. +   if (sess->protocol_version >= 0x2f)
  835. +   {
  836. +       seq_no = gg_send_message_gg11(sess, msgclass, recipients_count, recipients, recoded_msg, recoded_html_msg);
  837. +       goto cleanup;
  838. +   }
  839. +
  840.     /* Drobne odchylenie od protokołu. Jeśli wysyłamy kilka
  841.      * wiadomości w ciągu jednej sekundy, zwiększamy poprzednią
  842.      * wartość, żeby każda wiadomość miała unikalny numer.
  843. @@ -1697,6 +1770,46 @@
  844.     return res;
  845.  }
  846.  
  847. +static int gg_notify105_ex(struct gg_session *sess, uin_t *userlist, char *types, int count)
  848. +{
  849. +   int res = 0;
  850. +  
  851. +   if (!userlist || !count)
  852. +       return gg_send_packet(sess, GG_NOTIFY105_LIST_EMPTY, NULL);
  853. +  
  854. +   while (count > 0) {
  855. +       uint8_t buff[2048];
  856. +       int offset = 0;
  857. +       char uin_s[15];
  858. +       uint8_t uin_len;
  859. +       int packet_type;
  860. +      
  861. +       while (count > 0) {
  862. +           sprintf(uin_s, "%u", *userlist);
  863. +           uin_len = strlen(uin_s);
  864. +           if (offset + uin_len + 3 >= 2048)
  865. +               break;
  866. +           buff[offset++] = 0x00;
  867. +           buff[offset++] = uin_len;
  868. +           memcpy(buff + offset, uin_s, uin_len);
  869. +           offset += uin_len;
  870. +           buff[offset++] = *types;
  871. +
  872. +           userlist++;
  873. +           types++;
  874. +           count--;
  875. +       }
  876. +      
  877. +       packet_type = (count > 0) ? GG_NOTIFY105_FIRST : GG_NOTIFY105_LAST;
  878. +       if (gg_send_packet(sess, packet_type, buff, offset, NULL) == -1) {
  879. +           res = -1;
  880. +           break;
  881. +       }
  882. +   }
  883. +  
  884. +   return res;
  885. +}
  886. +
  887.  /**
  888.   * Wysyła do serwera listę kontaktów.
  889.   *
  890. @@ -1736,6 +1849,9 @@
  891.         return -1;
  892.     }
  893.  
  894. +   if (sess->protocol_version >= 0x2f)
  895. +       return gg_notify105_ex(sess, userlist, types, count);
  896. +
  897.     if (!userlist || !count)
  898.         return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
  899.  
  900. @@ -1790,57 +1906,19 @@
  901.   */
  902.  int gg_notify(struct gg_session *sess, uin_t *userlist, int count)
  903.  {
  904. -   struct gg_notify *n;
  905. -   uin_t *u;
  906. -   int i, res = 0;
  907. +   char *types;
  908. +   int ret;
  909.  
  910. -   gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count);
  911. -
  912. -   if (!sess) {
  913. -       errno = EFAULT;
  914. +   types = malloc(count);
  915. +   memset(types, GG_USER_NORMAL, count);
  916. +   if (sess->recv_buf == NULL)
  917.         return -1;
  918. -   }
  919.  
  920. -   if (sess->state != GG_STATE_CONNECTED) {
  921. -       errno = ENOTCONN;
  922. -       return -1;
  923. -   }
  924. +   ret = gg_notify_ex(sess, userlist, types, count);
  925.  
  926. -   if (!userlist || !count)
  927. -       return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
  928. +   free(types);
  929.  
  930. -   while (count > 0) {
  931. -       int part_count, packet_type;
  932. -
  933. -       if (count > 400) {
  934. -           part_count = 400;
  935. -           packet_type = GG_NOTIFY_FIRST;
  936. -       } else {
  937. -           part_count = count;
  938. -           packet_type = GG_NOTIFY_LAST;
  939. -       }
  940. -
  941. -       if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count)))
  942. -           return -1;
  943. -
  944. -       for (u = userlist, i = 0; i < part_count; u++, i++) {
  945. -           n[i].uin = gg_fix32(*u);
  946. -           n[i].dunno1 = GG_USER_NORMAL;
  947. -       }
  948. -
  949. -       if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) {
  950. -           res = -1;
  951. -           free(n);
  952. -           break;
  953. -       }
  954. -
  955. -       free(n);
  956. -
  957. -       userlist += part_count;
  958. -       count -= part_count;
  959. -   }
  960. -
  961. -   return res;
  962. +   return ret;
  963.  }
  964.  
  965.  /**
  966. @@ -1860,8 +1938,6 @@
  967.   */
  968.  int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type)
  969.  {
  970. -   struct gg_add_remove a;
  971. -
  972.     gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type);
  973.  
  974.     if (!sess) {
  975. @@ -1874,10 +1950,28 @@
  976.         return -1;
  977.     }
  978.  
  979. -   a.uin = gg_fix32(uin);
  980. -   a.dunno1 = type;
  981. +   if (sess->protocol_version >= 0x2f) {
  982. +       uint8_t dunno1 = 0x00;
  983. +       uint8_t uin_len;
  984. +       char uin_s[15];
  985.  
  986. -   return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
  987. +       sprintf(uin_s, "%u", uin);
  988. +       uin_len = strlen(uin_s);
  989. +
  990. +       return gg_send_packet(sess, GG_ADD_NOTIFY105,
  991. +           &dunno1, sizeof(dunno1),
  992. +           &uin_len, sizeof(uin_len),
  993. +           uin_s, uin_len,
  994. +           &type, sizeof(type),
  995. +           NULL);
  996. +   } else {
  997. +       struct gg_add_remove a;
  998. +
  999. +       a.uin = gg_fix32(uin);
  1000. +       a.dunno1 = type;
  1001. +
  1002. +       return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
  1003. +   }
  1004.  }
  1005.  
  1006.  /**
  1007. @@ -1913,8 +2007,6 @@
  1008.   */
  1009.  int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type)
  1010.  {
  1011. -   struct gg_add_remove a;
  1012. -
  1013.     gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type);
  1014.  
  1015.     if (!sess) {
  1016. @@ -1927,10 +2019,28 @@
  1017.         return -1;
  1018.     }
  1019.  
  1020. -   a.uin = gg_fix32(uin);
  1021. -   a.dunno1 = type;
  1022. +   if (sess->protocol_version >= 0x2f) {
  1023. +       uint8_t dunno1 = 0x00;
  1024. +       uint8_t uin_len;
  1025. +       char uin_s[15];
  1026.  
  1027. -   return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL);
  1028. +       sprintf(uin_s, "%u", uin);
  1029. +       uin_len = strlen(uin_s);
  1030. +
  1031. +       return gg_send_packet(sess, GG_ADD_NOTIFY105,
  1032. +           &dunno1, sizeof(dunno1),
  1033. +           &uin_len, sizeof(uin_len),
  1034. +           uin_s, uin_len,
  1035. +           &type, sizeof(type),
  1036. +           NULL);
  1037. +   } else {
  1038. +       struct gg_add_remove a;
  1039. +
  1040. +       a.uin = gg_fix32(uin);
  1041. +       a.dunno1 = type;
  1042. +
  1043. +       return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL);
  1044. +   }
  1045.  }
  1046.  
  1047.  /**
  1048. Index: src/debug.c
  1049. ===================================================================
  1050. --- src/debug.c (wersja 1314)
  1051. +++ src/debug.c (kopia robocza)
  1052. @@ -356,6 +356,8 @@
  1053.     GG_DEBUG_EVENT(GG_EVENT_MULTILOGON_INFO)
  1054.     GG_DEBUG_EVENT(GG_EVENT_USERLIST100_VERSION)
  1055.     GG_DEBUG_EVENT(GG_EVENT_USERLIST100_REPLY)
  1056. +   GG_DEBUG_EVENT(GG_EVENT_IMTOKEN)
  1057. +   GG_DEBUG_EVENT(GG_EVENT_PONG110)
  1058.  #undef GG_DEBUG_EVENT
  1059.  
  1060.     /* Celowo nie ma default, żeby kompilator wyłapał brakujące zdarzenia */
  1061. Index: src/common.c
  1062. ===================================================================
  1063. --- src/common.c    (wersja 1314)
  1064. +++ src/common.c    (kopia robocza)
  1065. @@ -679,6 +679,60 @@
  1066.     return crc ^ 0xffffffffL;
  1067.  }
  1068.  
  1069. +uin_t gg_str_to_uin(const char *str, int len)
  1070. +{
  1071. +   char buff[11];
  1072. +   char *endptr;
  1073. +   uin_t uin;
  1074. +  
  1075. +   if (len < 0)
  1076. +       len = strlen(str);
  1077. +   if (len > 10)
  1078. +       return 0;
  1079. +   memcpy(buff, str, len);
  1080. +   buff[len] = '\0';
  1081. +  
  1082. +   errno = 0;
  1083. +   uin = strtoul(buff, &endptr, 10);
  1084. +   if (errno == ERANGE || endptr[0] != '\0')
  1085. +       return 0;
  1086. +  
  1087. +   return uin;
  1088. +}
  1089. +
  1090. +int gg_packed_int_read(const char *data, uint16_t *dst)
  1091. +{
  1092. +   uint16_t val;
  1093. +   uint8_t raw;
  1094. +  
  1095. +   raw = *data;
  1096. +   data++;
  1097. +   if (!(raw & 0x80))
  1098. +   {
  1099. +       *dst = raw;
  1100. +       return 1;
  1101. +   }
  1102. +  
  1103. +   val = raw & ~0x80;
  1104. +   raw = *data;
  1105. +   val |= (uint16_t)raw << 7;
  1106. +   *dst = val;
  1107. +   return 2;
  1108. +}
  1109. +
  1110. +int gg_packed_int_write(uint8_t dst[2], uint16_t val)
  1111. +{
  1112. +   if (val < 0x80)
  1113. +   {
  1114. +       dst[0] = val;
  1115. +       return 1;
  1116. +   }
  1117. +
  1118. +   dst[0] = (val & 0x7F) | 0x80;
  1119. +   dst[1] = (val >> 7);
  1120. +   return 2;
  1121. +}
  1122. +
  1123.  /*
  1124.   * Local variables:
  1125.   * c-indentation-style: k&r
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement