comparison libpurple/protocols/qq/im.c @ 23683:1c50f12b1c52

2008.08.02 - csyfek <csyfek(at)gmail.com> * Commit to Pidgin * Tickets: Fixes #1861 Fixes #1902 References #5112 2008.08.02 - ccpaging <ecc_hy(at)hotmail.com> * Store all keys and md5 values of qq_data in char[QQ_KEY_LENGTH] * Use random value in inikey * TEA header padding in crypt.c * Rewrite login part of qq_process 2008.07.31 - ccpaging <ecc_hy(at)hotmail.com> * Fixed: send reply when get duplicate server command. The server may not get our reply before. * Tag custom picture as text "(Broken)" 2008.07.30 - ccpaging <ecc_hy(at)hotmail.com>, csyfek <csyfek(at)gmail.com> * Change some debug message * Modify buddy status flag according to eva for QQ2006 * Modify buddy status parse and correspond to eva2 * Add getIP/putIP functions to packet_parse.c, and replace some gen_ip_str * Replace guint32 *ip with struct in_addr, and reduce g_new/g_free operation * Source file changed: Merge buddy_status into buddy_list Change login_logout to qq_base Merge keep_alive into qq_base New qq_process extract from qq_network * Fixed: Byte alignment bug in crypt.c, tested in ARM PDA * Fixed: group chat message may get in before getting group info, and so group info is empty * Add qq_send_cmd_group_get_group_info when joined a group chat in group_im.c * Add some new group command identify according eva but further program * Add some new QQ client version identify * Fixed: Identify buddy's client version by IM packet, and not by status * Add some new info in buddy's tooltip text * Add video falg to buddy's emblem. But those flag in buddy status may not prasing correctly * Use new timeout function to handle send keep_alive, resend packet, update buddy status * Add new advanced options: The end user may change interval of keep_alive, resend packet, update buddy status to feed their need. For example, saving network flow when use mobile phone. Keep alive packet must be sent in 60-120 seconds whatever client rcved data of not. The intervals of keep alive and update status should be multiple of resend's interval, Since we use counter not time() in a single timeout function for efficiency. * Rewrite qq_trans.c, and use one g_list to manage: Store server packet before login, and prase all of them when get login Store client send packet for resend scanning, confirm server reply, filter duplicate server reply Store server packet for filter out duplicate * Add QQ_MSG_SYS_NOTICE = 0x06 in sys_msg.c * Rewrite qq_proc_cmd_reply and qq_proc_cmd_server: In QQ protocol, one packet reply may need a new packet send later. We may call it packet trigger. The triggers always is hided in every qq_process_reply. Now we try to extract those triggers and put into a single function, and then every trigger should be obviously and easy to manage.
author SHiNE CsyFeK <csyfek@gmail.com>
date Sat, 02 Aug 2008 15:00:46 +0000
parents ebad75b719f5
children 5f454b975a99
comparison
equal deleted inserted replaced
23682:21e591b55339 23683:1c50f12b1c52
77 struct _qq_recv_normal_im_common { 77 struct _qq_recv_normal_im_common {
78 /* this is the common part of normal_text */ 78 /* this is the common part of normal_text */
79 guint16 sender_ver; 79 guint16 sender_ver;
80 guint32 sender_uid; 80 guint32 sender_uid;
81 guint32 receiver_uid; 81 guint32 receiver_uid;
82 guint8 *session_md5; 82 guint8 session_md5[QQ_KEY_LENGTH];
83 guint16 normal_im_type; 83 guint16 normal_im_type;
84 }; 84 };
85 85
86 struct _qq_recv_normal_im_text { 86 struct _qq_recv_normal_im_text {
87 qq_recv_normal_im_common *common; 87 qq_recv_normal_im_common *common;
107 107
108 struct _qq_recv_im_header { 108 struct _qq_recv_im_header {
109 guint32 sender_uid; 109 guint32 sender_uid;
110 guint32 receiver_uid; 110 guint32 receiver_uid;
111 guint32 server_im_seq; 111 guint32 server_im_seq;
112 guint8 sender_ip[4]; 112 struct in_addr sender_ip;
113 guint16 sender_port; 113 guint16 sender_port;
114 guint16 im_type; 114 guint16 im_type;
115 }; 115 };
116 116
117 #define QQ_SEND_IM_AFTER_MSG_HEADER_LEN 8 117 #define QQ_SEND_IM_AFTER_MSG_HEADER_LEN 8
177 } 177 }
178 178
179 send_im_tail[5] = 0x00; 179 send_im_tail[5] = 0x00;
180 send_im_tail[6] = 0x86; 180 send_im_tail[6] = 0x86;
181 send_im_tail[7] = 0x22; /* encoding, 0x8622=GB, 0x0000=EN, define BIG5 support here */ 181 send_im_tail[7] = 0x22; /* encoding, 0x8622=GB, 0x0000=EN, define BIG5 support here */
182 qq_show_packet("QQ_MESG", send_im_tail, tail_len); 182 /* qq_show_packet("QQ_MESG", send_im_tail, tail_len); */
183 return (guint8 *) send_im_tail; 183 return (guint8 *) send_im_tail;
184 } 184 }
185 185
186 static const gchar *qq_get_recv_im_type_str(gint type) 186 static const gchar *qq_get_recv_im_type_str(gint type)
187 { 187 {
235 bytes = 0; 235 bytes = 0;
236 /* now push data into common header */ 236 /* now push data into common header */
237 bytes += qq_get16(&(common->sender_ver), data + bytes); 237 bytes += qq_get16(&(common->sender_ver), data + bytes);
238 bytes += qq_get32(&(common->sender_uid), data + bytes); 238 bytes += qq_get32(&(common->sender_uid), data + bytes);
239 bytes += qq_get32(&(common->receiver_uid), data + bytes); 239 bytes += qq_get32(&(common->receiver_uid), data + bytes);
240 240 bytes += qq_getdata(common->session_md5, QQ_KEY_LENGTH, data + bytes);
241 common->session_md5 = g_memdup(data + bytes, QQ_KEY_LENGTH);
242 bytes += QQ_KEY_LENGTH;
243
244 bytes += qq_get16(&(common->normal_im_type), data + bytes); 241 bytes += qq_get16(&(common->normal_im_type), data + bytes);
245 242
246 if (bytes != 28) { /* read common place fail */ 243 if (bytes != 28) { /* read common place fail */
247 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Expect 28 bytes, read %d bytes\n", bytes); 244 purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Expect 28 bytes, read %d bytes\n", bytes);
248 return -1; 245 return -1;
259 gchar *msg_with_purple_smiley; 256 gchar *msg_with_purple_smiley;
260 gchar *msg_utf8_encoded; 257 gchar *msg_utf8_encoded;
261 qq_data *qd; 258 qq_data *qd;
262 qq_recv_normal_im_text *im_text; 259 qq_recv_normal_im_text *im_text;
263 gint bytes = 0; 260 gint bytes = 0;
261 PurpleBuddy *b;
262 qq_buddy *qq_b;
264 263
265 g_return_if_fail(common != NULL); 264 g_return_if_fail(common != NULL);
266 qd = (qq_data *) gc->proto_data; 265 qd = (qq_data *) gc->proto_data;
267 266
268 /* now it is QQ_NORMAL_IM_TEXT */ 267 /* now it is QQ_NORMAL_IM_TEXT */
306 } else /* not im_text->is_there_font_attr */ 305 } else /* not im_text->is_there_font_attr */
307 im_text->msg = g_strndup((gchar *)(data + bytes), len - bytes); 306 im_text->msg = g_strndup((gchar *)(data + bytes), len - bytes);
308 } /* if im_text->msg_type */ 307 } /* if im_text->msg_type */
309 308
310 name = uid_to_purple_name(common->sender_uid); 309 name = uid_to_purple_name(common->sender_uid);
311 if (purple_find_buddy(gc->account, name) == NULL) 310 b = purple_find_buddy(gc->account, name);
311 if (b == NULL) {
312 qq_add_buddy_by_recv_packet(gc, common->sender_uid, FALSE, TRUE); 312 qq_add_buddy_by_recv_packet(gc, common->sender_uid, FALSE, TRUE);
313 313 b = purple_find_buddy(gc->account, name);
314 }
315 qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
316 if (qq_b != NULL) {
317 qq_b->client_version = common->sender_ver;
318 }
319
314 purple_msg_type = (im_text->msg_type == QQ_IM_AUTO_REPLY) ? PURPLE_MESSAGE_AUTO_RESP : 0; 320 purple_msg_type = (im_text->msg_type == QQ_IM_AUTO_REPLY) ? PURPLE_MESSAGE_AUTO_RESP : 0;
315 321
316 msg_with_purple_smiley = qq_smiley_to_purple(im_text->msg); 322 msg_with_purple_smiley = qq_smiley_to_purple(im_text->msg);
317 msg_utf8_encoded = im_text->is_there_font_attr ? 323 msg_utf8_encoded = im_text->is_there_font_attr ?
318 qq_encode_to_purple(im_text->font_attr, 324 qq_encode_to_purple(im_text->font_attr,
351 } 357 }
352 358
353 switch (common->normal_im_type) { 359 switch (common->normal_im_type) {
354 case QQ_NORMAL_IM_TEXT: 360 case QQ_NORMAL_IM_TEXT:
355 purple_debug (PURPLE_DEBUG_INFO, "QQ", 361 purple_debug (PURPLE_DEBUG_INFO, "QQ",
356 "Normal IM, text type:\n [%d] => [%d], src: %s\n", 362 "Normal IM, text type:\n [%d] => [%d], src: %s (%04X)\n",
357 common->sender_uid, common->receiver_uid, 363 common->sender_uid, common->receiver_uid,
358 qq_get_source_str (common->sender_ver)); 364 qq_get_ver_desc (common->sender_ver), common->sender_ver);
359 if (bytes >= len - 1) { 365 if (bytes >= len - 1) {
360 purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n"); 366 purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n");
361 return; 367 return;
362 } 368 }
363 _qq_process_recv_normal_im_text(data + bytes, len - bytes, common, gc); 369 _qq_process_recv_normal_im_text(data + bytes, len - bytes, common, gc);
385 /* a simple process here, maybe more later */ 391 /* a simple process here, maybe more later */
386 purple_debug (PURPLE_DEBUG_WARNING, "QQ", 392 purple_debug (PURPLE_DEBUG_WARNING, "QQ",
387 "Normal IM, unprocessed type [0x%04x], len %d\n", 393 "Normal IM, unprocessed type [0x%04x], len %d\n",
388 common->normal_im_type, im_unprocessed->length); 394 common->normal_im_type, im_unprocessed->length);
389 qq_show_packet ("QQ unk-im", im_unprocessed->unknown, im_unprocessed->length); 395 qq_show_packet ("QQ unk-im", im_unprocessed->unknown, im_unprocessed->length);
390 g_free (common->session_md5);
391 return; 396 return;
392 } 397 }
393
394 g_free (common->session_md5);
395 } 398 }
396 399
397 /* process im from system administrator */ 400 /* process im from system administrator */
398 static void _qq_process_recv_sys_im(guint8 *data, gint data_len, PurpleConnection *gc) 401 static void _qq_process_recv_sys_im(guint8 *data, gint data_len, PurpleConnection *gc)
399 { 402 {
601 im_header = g_newa(qq_recv_im_header, 1); 604 im_header = g_newa(qq_recv_im_header, 1);
602 bytes += qq_get32(&(im_header->sender_uid), data + bytes); 605 bytes += qq_get32(&(im_header->sender_uid), data + bytes);
603 bytes += qq_get32(&(im_header->receiver_uid), data + bytes); 606 bytes += qq_get32(&(im_header->receiver_uid), data + bytes);
604 bytes += qq_get32(&(im_header->server_im_seq), data + bytes); 607 bytes += qq_get32(&(im_header->server_im_seq), data + bytes);
605 /* if the message is delivered via server, it is server IP/port */ 608 /* if the message is delivered via server, it is server IP/port */
606 bytes += qq_getdata((guint8 *) & (im_header->sender_ip), 4, data + bytes); 609 bytes += qq_getIP(&(im_header->sender_ip), data + bytes);
607 bytes += qq_get16(&(im_header->sender_port), data + bytes); 610 bytes += qq_get16(&(im_header->sender_port), data + bytes);
608 bytes += qq_get16(&(im_header->im_type), data + bytes); 611 bytes += qq_get16(&(im_header->im_type), data + bytes);
609 /* im_header prepared */ 612 /* im_header prepared */
610 613
611 if (im_header->receiver_uid != qd->uid) { /* should not happen */ 614 if (im_header->receiver_uid != qd->uid) { /* should not happen */