diff -Npr openq-0.3.2/src/buddy_status.c openq-0.3.2.for1/src/buddy_status.c *** openq-0.3.2/src/buddy_status.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/buddy_status.c 2006-03-06 14:50:39.000000000 +0800 *************** void _qq_buddy_status_dump_unclear(qq_bu *** 56,62 **** g_string_append_printf(dump, "unclear fields for [%d]:\n", s->uid); g_string_append_printf(dump, "004: %02x (unknown)\n", s->unknown1); g_string_append_printf(dump, "011: %02x (unknown)\n", s->unknown2); - g_string_append_printf(dump, "013-014: %04x (unknown)\n", s->unknown3); gaim_debug(GAIM_DEBUG_INFO, "QQ", "Buddy status entry, %s", dump->str); g_string_free(dump, TRUE); --- 56,61 ---- *************** gint _qq_buddy_status_read(guint8 * data *** 84,91 **** bytes += read_packet_b(data, cursor, len, &s->unknown2); // 012-012: status bytes += read_packet_b(data, cursor, len, &s->status); ! // 013-014: ! bytes += read_packet_w(data, cursor, len, &s->unknown3); // 015-030: unknown key s->unknown_key = g_new0(guint8, QQ_KEY_LENGTH); bytes += read_packet_data(data, cursor, len, s->unknown_key, QQ_KEY_LENGTH); --- 83,90 ---- bytes += read_packet_b(data, cursor, len, &s->unknown2); // 012-012: status bytes += read_packet_b(data, cursor, len, &s->status); ! // 013-014: client_version ! bytes += read_packet_w(data, cursor, len, &s->client_version); // 015-030: unknown key s->unknown_key = g_new0(guint8, QQ_KEY_LENGTH); bytes += read_packet_data(data, cursor, len, s->unknown_key, QQ_KEY_LENGTH); *************** void qq_process_friend_change_status(gui *** 206,211 **** --- 205,211 ---- GaimBuddy *b; qq_buddy *q_bud; qq_buddy_status *s; + gchar *name; g_return_if_fail(gc != NULL && gc->proto_data != NULL); g_return_if_fail(buf != NULL && buf_len != 0); *************** void qq_process_friend_change_status(gui *** 232,243 **** if (QQ_DEBUG) _qq_buddy_status_dump_unclear(s); ! b = gaim_find_buddy(gc->account, uid_to_gaim_name(s->uid)); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud) { g_memmove(q_bud->ip, s->ip, 4); q_bud->port = s->port; q_bud->status = s->status; qq_update_buddy_contact(gc, q_bud); } g_free(s->ip); --- 232,250 ---- if (QQ_DEBUG) _qq_buddy_status_dump_unclear(s); ! name = uid_to_gaim_name(s->uid); //by gfhuang ! b = gaim_find_buddy(gc->account, name); ! g_free(name); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud) { + gaim_debug(GAIM_DEBUG_INFO, "QQ", "s->uid = %d, q_bud->uid = %d\n", s->uid , q_bud->uid); + if(0 != *((guint32 *)s->ip)) { //by gfhuang g_memmove(q_bud->ip, s->ip, 4); q_bud->port = s->port; + } q_bud->status = s->status; + if(0 != s->client_version) + q_bud->client_version = s->client_version; //gfhuang qq_update_buddy_contact(gc, q_bud); } g_free(s->ip); diff -Npr openq-0.3.2/src/buddy_status.h openq-0.3.2.for1/src/buddy_status.h *** openq-0.3.2/src/buddy_status.h 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/buddy_status.h 2006-03-06 14:47:23.000000000 +0800 *************** typedef struct _qq_buddy_status { *** 37,51 **** guint16 port; guint8 unknown2; guint8 status; ! guint16 unknown3; guint8 *unknown_key; } qq_buddy_status; enum { QQ_BUDDY_ONLINE_NORMAL = 0x0a, QQ_BUDDY_ONLINE_OFFLINE = 0x14, QQ_BUDDY_ONLINE_AWAY = 0x1e, ! QQ_BUDDY_ONLINE_INVISIBLE = 0x40, }; enum { --- 37,52 ---- guint16 port; guint8 unknown2; guint8 status; ! guint16 client_version; guint8 *unknown_key; } qq_buddy_status; enum { + QQ_BUDDY_OFFLINE = 0x00, // by gfhuang QQ_BUDDY_ONLINE_NORMAL = 0x0a, QQ_BUDDY_ONLINE_OFFLINE = 0x14, QQ_BUDDY_ONLINE_AWAY = 0x1e, ! QQ_BUDDY_ONLINE_INVISIBLE = 0x28, // 40 not 0x40!, bug by gfhuang }; enum { diff -Npr openq-0.3.2/src/char_conv.c openq-0.3.2.for1/src/char_conv.c *** openq-0.3.2/src/char_conv.c 2004-10-07 10:35:46.000000000 +0800 --- openq-0.3.2.for1/src/char_conv.c 2006-03-06 11:17:09.000000000 +0800 *************** gchar *_my_convert(const gchar * str, gs *** 129,134 **** --- 129,135 ---- // returns the number of bytes read, return -1 if fatal error // the converted UTF-8 will be save in ret, gint convert_as_pascal_string(guint8 * data, gchar ** ret, const gchar * from_charset) { + guint8 len; g_return_val_if_fail(data != NULL && from_charset != NULL, -1); diff -Npr openq-0.3.2/src/group_conv.c openq-0.3.2.for1/src/group_conv.c *** openq-0.3.2/src/group_conv.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/group_conv.c 2006-03-06 10:11:28.000000000 +0800 *************** void qq_group_conv_refresh_online_member *** 53,58 **** --- 53,59 ---- qq_buddy *member; gchar *member_name; GaimConversation *conv; + gint flag; g_return_if_fail(gc != NULL && group != NULL); names = NULL; *************** void qq_group_conv_refresh_online_member *** 87,92 **** --- 88,95 ---- flags = g_list_remove(flags, member_name); g_free(member_name); } + if (flags) + g_list_free(flags); } // qq_group_conv_show_window /*****************************************************************************/ diff -Npr openq-0.3.2/src/group.h openq-0.3.2.for1/src/group.h *** openq-0.3.2/src/group.h 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/group.h 2006-03-06 09:52:30.000000000 +0800 *************** typedef struct _qq_group { *** 48,54 **** guint32 external_group_id; guint8 group_type; // permanent or temporory guint32 creator_uid; ! guint16 group_category; guint8 auth_type; gchar *group_name_utf8; gchar *group_desc_utf8; --- 48,54 ---- guint32 external_group_id; guint8 group_type; // permanent or temporory guint32 creator_uid; ! guint32 group_category; guint8 auth_type; gchar *group_name_utf8; gchar *group_desc_utf8; diff -Npr openq-0.3.2/src/group_im.c openq-0.3.2.for1/src/group_im.c *** openq-0.3.2/src/group_im.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/group_im.c 2006-03-06 10:34:03.000000000 +0800 *************** void qq_process_recv_group_im_been_appro *** 208,214 **** read_packet_dw(data, cursor, len, &admin_uid); g_return_if_fail(external_group_id > 0 && admin_uid > 0); ! // it is also a "æ— " here, so do not display convert_as_pascal_string(*cursor, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf --- 208,214 ---- read_packet_dw(data, cursor, len, &admin_uid); g_return_if_fail(external_group_id > 0 && admin_uid > 0); ! // it is also a "æ—? here, so do not display convert_as_pascal_string(*cursor, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf *************** void qq_process_recv_group_im_been_added *** 304,310 **** /*****************************************************************************/ // recv an IM from a group chat void qq_process_recv_group_im ! (guint8 * data, guint8 ** cursor, gint data_len, guint32 internal_group_id, GaimConnection * gc) { gchar *msg_with_gaim_smiley, *msg_utf8_encoded, *im_src_name; guint16 unknown; GaimConversation *conv; --- 304,310 ---- /*****************************************************************************/ // recv an IM from a group chat void qq_process_recv_group_im ! (guint8 * data, guint8 ** cursor, gint data_len, guint32 internal_group_id, GaimConnection * gc, guint16 im_type /* gfhuang */) { gchar *msg_with_gaim_smiley, *msg_utf8_encoded, *im_src_name; guint16 unknown; GaimConversation *conv; *************** void qq_process_recv_group_im *** 312,317 **** --- 312,318 ---- qq_buddy *member; qq_group *group; qq_recv_group_im *im_group; + gint skip_len; g_return_if_fail(gc != NULL && gc->proto_data != NULL && data != NULL && data_len > 0); qd = (qq_data *) gc->proto_data; *************** void qq_process_recv_group_im *** 325,330 **** --- 326,336 ---- read_packet_dw(data, cursor, data_len, &(im_group->external_group_id)); read_packet_b(data, cursor, data_len, &(im_group->group_type)); + + if(QQ_RECV_IM_TEMP_GROUP_IM == im_type) { //by gfhuang, protocal changed + read_packet_dw(data, cursor, data_len, &(internal_group_id)); + } + read_packet_dw(data, cursor, data_len, &(im_group->member_uid)); read_packet_w(data, cursor, data_len, &unknown); // 0x00 read_packet_w(data, cursor, data_len, &(im_group->msg_seq)); *************** void qq_process_recv_group_im *** 333,345 **** read_packet_w(data, cursor, data_len, &unknown); // 0x00 // length includes font_attr // this msg_len includes msg and font_attr read_packet_w(data, cursor, data_len, &(im_group->msg_len)); g_return_if_fail(im_group->msg_len > 0); im_group->msg = g_strdup(*cursor); *cursor += strlen(im_group->msg) + 1; // there might not be any font_attr, check it ! im_group->font_attr_len = im_group->msg_len - strlen(im_group->msg) - 1; if (im_group->font_attr_len > 0) im_group->font_attr = g_memdup(*cursor, im_group->font_attr_len); else --- 339,370 ---- read_packet_w(data, cursor, data_len, &unknown); // 0x00 // length includes font_attr // this msg_len includes msg and font_attr + ////////////////// the format is + // length of all + // 1. unknown 10 bytes + // 2. 0-ended string + // 3. font_attr + read_packet_w(data, cursor, data_len, &(im_group->msg_len)); g_return_if_fail(im_group->msg_len > 0); + // 10 bytes from lumaqq + // contentType = buf.getChar(); + // totalFragments = buf.get() & 255; + // fragmentSequence = buf.get() & 255; + // messageId = buf.getChar(); + // buf.getInt(); + + if(im_type != QQ_RECV_IM_UNKNOWN_GROUP_IM) // gfhuang, protocal changed + skip_len = 10; + else + skip_len = 0; + *cursor += skip_len; + im_group->msg = g_strdup(*cursor); *cursor += strlen(im_group->msg) + 1; // there might not be any font_attr, check it ! im_group->font_attr_len = im_group->msg_len - strlen(im_group->msg) - 1 - skip_len /* gfhuang */; if (im_group->font_attr_len > 0) im_group->font_attr = g_memdup(*cursor, im_group->font_attr_len); else diff -Npr openq-0.3.2/src/group_im.h openq-0.3.2.for1/src/group_im.h *** openq-0.3.2/src/group_im.h 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/group_im.h 2006-03-06 10:33:11.000000000 +0800 *************** void qq_send_packet_group_im(GaimConnect *** 33,39 **** void qq_process_group_cmd_im(guint8 * data, guint8 ** cursor, gint len, GaimConnection * gc); void qq_process_recv_group_im(guint8 * data, ! guint8 ** cursor, gint data_len, guint32 internal_group_id, GaimConnection * gc); void qq_process_recv_group_im_apply_join(guint8 * data, guint8 ** cursor, gint len, guint32 internal_group_id, GaimConnection * gc); --- 33,39 ---- void qq_process_group_cmd_im(guint8 * data, guint8 ** cursor, gint len, GaimConnection * gc); void qq_process_recv_group_im(guint8 * data, ! guint8 ** cursor, gint data_len, guint32 internal_group_id, GaimConnection * gc, guint16 im_type /* gfhuang */); void qq_process_recv_group_im_apply_join(guint8 * data, guint8 ** cursor, gint len, guint32 internal_group_id, GaimConnection * gc); diff -Npr openq-0.3.2/src/group_info.c openq-0.3.2.for1/src/group_info.c *** openq-0.3.2/src/group_info.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/group_info.c 2006-03-06 10:41:02.000000000 +0800 *************** void qq_send_cmd_group_get_member_info(G *** 163,172 **** void qq_process_group_cmd_get_group_info(guint8 * data, guint8 ** cursor, gint len, GaimConnection * gc) { qq_group *group; qq_data *qd; ! guint8 bar; guint16 unknown; guint32 member_uid, internal_group_id; gint pascal_len, i; g_return_if_fail(gc != NULL && gc->proto_data != NULL); g_return_if_fail(data != NULL && len > 0); --- 163,174 ---- void qq_process_group_cmd_get_group_info(guint8 * data, guint8 ** cursor, gint len, GaimConnection * gc) { qq_group *group; qq_data *qd; ! guint8 bar, orgnization; guint16 unknown; guint32 member_uid, internal_group_id; gint pascal_len, i; + guint32 unknown4; + guint8 unknown1; g_return_if_fail(gc != NULL && gc->proto_data != NULL); g_return_if_fail(data != NULL && len > 0); *************** void qq_process_group_cmd_get_group_info *** 180,191 **** read_packet_dw(data, cursor, len, &(group->external_group_id)); read_packet_b(data, cursor, len, &(group->group_type)); read_packet_dw(data, cursor, len, &(group->creator_uid)); read_packet_b(data, cursor, len, &(group->auth_type)); read_packet_w(data, cursor, len, &(unknown)); // 0x00 ! read_packet_w(data, cursor, len, &(group->group_category)); ! read_packet_w(data, cursor, len, &(unknown)); // 0x00 read_packet_w(data, cursor, len, &(unknown)); // 0x00 pascal_len = convert_as_pascal_string(*cursor, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); *cursor += pascal_len; --- 182,196 ---- read_packet_dw(data, cursor, len, &(group->external_group_id)); read_packet_b(data, cursor, len, &(group->group_type)); + read_packet_dw(data, cursor, len, &unknown4); //unknown 4 bytes, protocal changed by gfhuang read_packet_dw(data, cursor, len, &(group->creator_uid)); read_packet_b(data, cursor, len, &(group->auth_type)); + read_packet_dw(data, cursor, len, &unknown4); // oldCategory, by gfhuang read_packet_w(data, cursor, len, &(unknown)); // 0x00 ! read_packet_dw(data, cursor, len, &(group->group_category)); read_packet_w(data, cursor, len, &(unknown)); // 0x00 + read_packet_b(data, cursor, len, &unknown1); + read_packet_dw(data, cursor, len, &(unknown4)); // versionID, by gfhuang pascal_len = convert_as_pascal_string(*cursor, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); *cursor += pascal_len; *************** void qq_process_group_cmd_get_group_info *** 200,205 **** --- 205,211 ---- while (*cursor < data + len) { read_packet_dw(data, cursor, len, &member_uid); i++; + read_packet_b(data, cursor, len, &orgnization); // protocal changed, gfhuang read_packet_b(data, cursor, len, &bar); // 0x00 qq_group_find_or_add_member(gc, group, member_uid); } // while *cursor diff -Npr openq-0.3.2/src/group_join.c openq-0.3.2.for1/src/group_join.c *** openq-0.3.2/src/group_join.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/group_join.c 2006-03-07 11:02:30.000000000 +0800 *************** void _qq_group_join_auth(GaimConnection *** 131,136 **** --- 131,141 ---- } // _qq_group_join_auth /*****************************************************************************/ + unsigned char unknown32[32] = {0x68, 0x12, 0x8c, 0xf1, 0x95, 0xdd, 0xbb, 0x47, + 0xf6, 0xb1, 0xb0, 0xf6, 0x86, 0xd7, 0x26, 0x6d, + 0x47, 0xe9, 0x22, 0x57, 0xc2, 0xde, 0x68, 0xa5, + 0xd7, 0x0b, 0x3b, 0xa8, 0x90, 0x2c, 0xca, 0x1c + }; void qq_send_cmd_group_auth(GaimConnection * gc, qq_group * group, guint8 opt, guint32 uid, const gchar * reason_utf8) { guint8 *raw_data, *cursor; gchar *reason_qq; *************** void qq_send_cmd_group_auth(GaimConnecti *** 149,155 **** uid = 0; } // if (opt == QQ_GROUP_AUTH_REQUEST_APPLY) ! data_len = 10 + strlen(reason_qq) + 1; raw_data = g_newa(guint8, data_len); cursor = raw_data; --- 154,160 ---- uid = 0; } // if (opt == QQ_GROUP_AUTH_REQUEST_APPLY) ! data_len = 44 + strlen(reason_qq) + 1; raw_data = g_newa(guint8, data_len); cursor = raw_data; *************** void qq_send_cmd_group_auth(GaimConnecti *** 157,162 **** --- 162,170 ---- bytes += create_packet_b(raw_data, &cursor, QQ_GROUP_CMD_JOIN_GROUP_AUTH); bytes += create_packet_dw(raw_data, &cursor, group->internal_group_id); bytes += create_packet_b(raw_data, &cursor, opt); + bytes += create_packet_b(raw_data, &cursor, 0); + bytes += create_packet_b(raw_data, &cursor, 32); + bytes += create_packet_data(raw_data, &cursor, unknown32, 32); bytes += create_packet_dw(raw_data, &cursor, uid); bytes += create_packet_b(raw_data, &cursor, strlen(reason_qq)); bytes += create_packet_data(raw_data, &cursor, reason_qq, strlen(reason_qq)); diff -Npr openq-0.3.2/src/group_search.c openq-0.3.2.for1/src/group_search.c *** openq-0.3.2/src/group_search.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/group_search.c 2006-03-06 15:01:03.000000000 +0800 *************** void qq_send_cmd_group_search_group(Gaim *** 62,69 **** /*****************************************************************************/ // process group cmd reply "search group" void qq_process_group_cmd_search_group(guint8 * data, guint8 ** cursor, gint len, GaimConnection * gc) { ! guint8 search_type; ! guint16 unknown; gint bytes, pascal_len, i; qq_data *qd; GaimRoomlistRoom *room; --- 62,69 ---- /*****************************************************************************/ // process group cmd reply "search group" void qq_process_group_cmd_search_group(guint8 * data, guint8 ** cursor, gint len, GaimConnection * gc) { ! guint8 search_type, *punknown=NULL, unknown1=0;//add by Yuan Qingyun ! guint16 unknown, unknownlen=0; gint bytes, pascal_len, i; qq_data *qd; GaimRoomlistRoom *room; *************** void qq_process_group_cmd_search_group(g *** 85,93 **** bytes += read_packet_dw(data, cursor, len, &(group->internal_group_id)); bytes += read_packet_dw(data, cursor, len, &(group->external_group_id)); bytes += read_packet_b(data, cursor, len, &(group->group_type)); bytes += read_packet_dw(data, cursor, len, &(group->creator_uid)); bytes += read_packet_w(data, cursor, len, &(unknown)); ! bytes += read_packet_w(data, cursor, len, &(group->group_category)); pascal_len = convert_as_pascal_string(*cursor, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); bytes += pascal_len; *cursor += pascal_len; --- 85,97 ---- bytes += read_packet_dw(data, cursor, len, &(group->internal_group_id)); bytes += read_packet_dw(data, cursor, len, &(group->external_group_id)); bytes += read_packet_b(data, cursor, len, &(group->group_type)); + bytes += read_packet_w(data, cursor, len, &(unknown)); + bytes += read_packet_w(data, cursor, len, &(unknown)); bytes += read_packet_dw(data, cursor, len, &(group->creator_uid)); bytes += read_packet_w(data, cursor, len, &(unknown)); ! bytes += read_packet_w(data, cursor, len, &(unknown)); ! bytes += read_packet_dw(data, cursor, len, &(group->group_category)); ! bytes += read_packet_w(data, cursor, len, &(unknown)); pascal_len = convert_as_pascal_string(*cursor, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); bytes += pascal_len; *cursor += pascal_len; *************** void qq_process_group_cmd_search_group(g *** 96,101 **** --- 100,112 ---- pascal_len = convert_as_pascal_string(*cursor, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); bytes += pascal_len; *cursor += pascal_len; + bytes += read_packet_b(data, cursor, len, &unknown1);//add by Yuan Qingyun + bytes += read_packet_b(data, cursor, len, &unknownlen);//add by Yuan Qingyun + punknown=g_new0(guint8, unknownlen);//add by Yuan Qingyun + gaim_debug(GAIM_DEBUG_WARNING, "QQ", + "Dump unknown text\n%s", hex_dump_to_str(*cursor, unknownlen));//add by Yuan Qingyun + bytes += read_packet_data(data, cursor, len, punknown, unknownlen);//add by Yuan Qingyun + g_free(punknown);//add by Yuan Qingyun // end of one qq_group room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, group->group_name_utf8, NULL); gaim_roomlist_room_add_field(qd->roomlist, room, g_strdup_printf("%d", group->external_group_id)); diff -Npr openq-0.3.2/src/header_info.c openq-0.3.2.for1/src/header_info.c *** openq-0.3.2/src/header_info.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/header_info.c 2006-03-06 09:44:33.000000000 +0800 *************** *** 33,39 **** #define QQ_CLIENT_0B35 0x0b35 // GB QQ2003iii build 0304 (offical release) #define QQ_CLIENT_0B37 0x0b37 // GB QQ2003iii build 0304 (April 05 updates) #define QQ_SERVER_0100 0x0100 // server ! /*****************************************************************************/ // given command alias, return the command name accordingly const gchar *qq_get_cmd_desc(gint type) --- 33,39 ---- #define QQ_CLIENT_0B35 0x0b35 // GB QQ2003iii build 0304 (offical release) #define QQ_CLIENT_0B37 0x0b37 // GB QQ2003iii build 0304 (April 05 updates) #define QQ_SERVER_0100 0x0100 // server ! #define QQ_SERVER_0000 0x0000 // server /*****************************************************************************/ // given command alias, return the command name accordingly const gchar *qq_get_cmd_desc(gint type) *************** const gchar *qq_get_cmd_desc(gint type) *** 77,82 **** --- 77,84 ---- return "QQ_CMD_RECV_MSG_SYS"; case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: return "QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS"; + case QQ_CMD_GET_LOGIN_TOKEN: + return "QQ_CMD_GET_LOGIN_TOKEN"; default: return "UNKNOWN_TYPE"; } // switch (type) *************** const gchar *qq_get_source_str(gint sour *** 105,110 **** --- 107,114 ---- return "GB QQ2003iii build 0304 (April 5 update)"; case QQ_SERVER_0100: return "QQ Server 0100"; + case QQ_SERVER_0000: + return "QQ Server 0000"; default: return "QQ unknown version"; } diff -Npr openq-0.3.2/src/header_info.h openq-0.3.2.for1/src/header_info.h *** openq-0.3.2/src/header_info.h 2004-10-23 23:22:50.000000000 +0800 --- openq-0.3.2.for1/src/header_info.h 2006-03-07 17:18:36.000000000 +0800 *************** *** 33,40 **** #define QQ_PACKET_TAG 0x02 // all QQ text packets starts with it #define QQ_PACKET_TAIL 0x03 // all QQ text packets end with it ! #define QQ_CLIENT 0x0b37 // QQ2003iii build 0304, Aprili 05 update ! // list of known QQ commands enum { QQ_CMD_LOGOUT = 0x0001, // log out --- 33,40 ---- #define QQ_PACKET_TAG 0x02 // all QQ text packets starts with it #define QQ_PACKET_TAIL 0x03 // all QQ text packets end with it ! //#define QQ_CLIENT 0x0b37 // QQ2003iii build 0304, Aprili 05 update ! #define QQ_CLIENT 0x0f15 // QQ2006 // list of known QQ commands enum { QQ_CMD_LOGOUT = 0x0001, // log out *************** enum { *** 57,62 **** --- 57,63 ---- QQ_CMD_GET_FRIENDS_ONLINE = 0x0027, // get my online friends list QQ_CMD_CELL_PHONE_2 = 0x0029, // cell phone 2 QQ_CMD_GROUP_CMD = 0x0030, // group command + QQ_CMD_GET_LOGIN_TOKEN = 0x0062, //get qq login token QQ_CMD_RECV_MSG_SYS = 0x0080, // receive a system message QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS = 0x0081, // friends change status }; diff -Npr openq-0.3.2/src/im.c openq-0.3.2.for1/src/im.c *** openq-0.3.2/src/im.c 2004-11-26 13:23:26.000000000 +0800 --- openq-0.3.2.for1/src/im.c 2006-03-06 10:42:14.000000000 +0800 *************** enum *** 64,82 **** }; enum { - QQ_RECV_IM_TO_BUDDY = 0x0009, - QQ_RECV_IM_TO_UNKNOWN = 0x000a, - QQ_RECV_IM_GROUP_IM = 0x0020, - QQ_RECV_IM_ADD_TO_GROUP = 0x0021, - QQ_RECV_IM_DEL_FROM_GROUP = 0x0022, - QQ_RECV_IM_APPLY_ADD_TO_GROUP = 0x0023, - QQ_RECV_IM_APPROVE_APPLY_ADD_TO_GROUP = 0x0024, - QQ_RECV_IM_REJCT_APPLY_ADD_TO_GROUP = 0x0025, - QQ_RECV_IM_CREATE_GROUP = 0x0026, - QQ_RECV_IM_SYS_NOTIFICATION = 0x0030, - }; - - enum { QQ_RECV_SYS_IM_KICK_OUT = 0x01, }; --- 64,69 ---- *************** const gchar *qq_get_recv_im_type_str(gin *** 209,216 **** return "QQ_RECV_IM_TO_BUDDY"; case QQ_RECV_IM_TO_UNKNOWN: return "QQ_RECV_IM_TO_UNKNOWN"; ! case QQ_RECV_IM_GROUP_IM: ! return "QQ_RECV_IM_GROUP_IM"; case QQ_RECV_IM_ADD_TO_GROUP: return "QQ_RECV_IM_ADD_TO_GROUP"; case QQ_RECV_IM_DEL_FROM_GROUP: --- 196,203 ---- return "QQ_RECV_IM_TO_BUDDY"; case QQ_RECV_IM_TO_UNKNOWN: return "QQ_RECV_IM_TO_UNKNOWN"; ! case QQ_RECV_IM_UNKNOWN_GROUP_IM: ! return "QQ_RECV_IM_UNKNOWN_GROUP_IM"; case QQ_RECV_IM_ADD_TO_GROUP: return "QQ_RECV_IM_ADD_TO_GROUP"; case QQ_RECV_IM_DEL_FROM_GROUP: *************** const gchar *qq_get_recv_im_type_str(gin *** 225,230 **** --- 212,221 ---- return "QQ_RECV_IM_APPROVE_APPLY_ADD_TO_GROUP"; case QQ_RECV_IM_REJCT_APPLY_ADD_TO_GROUP: return "QQ_RECV_IM_REJCT_APPLY_ADD_TO_GROUP"; + case QQ_RECV_IM_TEMP_GROUP_IM: + return "QQ_RECV_IM_TEMP_GROUP_IM"; + case QQ_RECV_IM_GROUP_IM: + return "QQ_RECV_IM_GROUP_IM"; default: return "QQ_RECV_IM_UNKNOWN"; } // switch type *************** void qq_process_recv_im(guint8 * buf, gi *** 718,727 **** "IM from buddy [%d], I am a stranger to him/her\n", im_header->sender_uid); _qq_process_recv_normal_im(data, &cursor, len, gc); break; case QQ_RECV_IM_GROUP_IM: gaim_debug(GAIM_DEBUG_INFO, "QQ", "IM from group, internal_id [%d]\n", im_header->sender_uid); // sender_uid is in fact internal_group_id ! qq_process_recv_group_im(data, &cursor, len, im_header->sender_uid, gc); break; case QQ_RECV_IM_ADD_TO_GROUP: gaim_debug(GAIM_DEBUG_INFO, "QQ", --- 709,720 ---- "IM from buddy [%d], I am a stranger to him/her\n", im_header->sender_uid); _qq_process_recv_normal_im(data, &cursor, len, gc); break; + case QQ_RECV_IM_UNKNOWN_GROUP_IM: + case QQ_RECV_IM_TEMP_GROUP_IM: case QQ_RECV_IM_GROUP_IM: gaim_debug(GAIM_DEBUG_INFO, "QQ", "IM from group, internal_id [%d]\n", im_header->sender_uid); // sender_uid is in fact internal_group_id ! qq_process_recv_group_im(data, &cursor, len, im_header->sender_uid, gc, im_header->im_type); break; case QQ_RECV_IM_ADD_TO_GROUP: gaim_debug(GAIM_DEBUG_INFO, "QQ", diff -Npr openq-0.3.2/src/im.h openq-0.3.2.for1/src/im.h *** openq-0.3.2/src/im.h 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/im.h 2006-03-06 10:47:40.000000000 +0800 *************** enum { *** 38,43 **** --- 38,57 ---- QQ_IM_AUTO_REPLY = 0x02, }; + enum { + QQ_RECV_IM_TO_BUDDY = 0x0009, + QQ_RECV_IM_TO_UNKNOWN = 0x000a, + QQ_RECV_IM_UNKNOWN_GROUP_IM = 0x0020, + QQ_RECV_IM_ADD_TO_GROUP = 0x0021, + QQ_RECV_IM_DEL_FROM_GROUP = 0x0022, + QQ_RECV_IM_APPLY_ADD_TO_GROUP = 0x0023, + QQ_RECV_IM_APPROVE_APPLY_ADD_TO_GROUP = 0x0024, + QQ_RECV_IM_REJCT_APPLY_ADD_TO_GROUP = 0x0025, + QQ_RECV_IM_TEMP_GROUP_IM = 0x002A, + QQ_RECV_IM_GROUP_IM = 0x002B, + QQ_RECV_IM_CREATE_GROUP = 0x0026, + QQ_RECV_IM_SYS_NOTIFICATION = 0x0030, + }; guint8 *qq_get_send_im_tail(const gchar * font_color, const gchar * font_size, const gchar * font_name, diff -Npr openq-0.3.2/src/keep_alive.c openq-0.3.2.for1/src/keep_alive.c *** openq-0.3.2/src/keep_alive.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/keep_alive.c 2006-03-06 09:44:33.000000000 +0800 *************** void qq_process_keep_alive_reply(guint8 *** 79,85 **** data = g_newa(guint8, len); if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { ! if (NULL == (segments = split_data(data, len, "\x1f", 5))) return; // segments[0] and segment[1] are all 0x30 ("0") qd->all_online = strtol(segments[2], NULL, 10); --- 79,85 ---- data = g_newa(guint8, len); if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) { ! if (NULL == (segments = split_data(data, len, "\x1f", 6))) return; // segments[0] and segment[1] are all 0x30 ("0") qd->all_online = strtol(segments[2], NULL, 10); diff -Npr openq-0.3.2/src/login_logout.c openq-0.3.2.for1/src/login_logout.c *** openq-0.3.2/src/login_logout.c 2004-10-04 01:37:36.000000000 +0800 --- openq-0.3.2.for1/src/login_logout.c 2006-03-06 09:44:33.000000000 +0800 *************** *** 40,46 **** #include "send_core.h" // qq_send_cmd #include "qq.h" // qq_data ! #define QQ_LOGIN_DATA_LENGTH 69 //length of plain login packet #define QQ_LOGIN_REPLY_OK_PACKET_LEN 139 #define QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN 11 --- 40,46 ---- #include "send_core.h" // qq_send_cmd #include "qq.h" // qq_data ! #define QQ_LOGIN_DATA_LENGTH 416 //69 //length of plain login packet #define QQ_LOGIN_REPLY_OK_PACKET_LEN 139 #define QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN 11 *************** *** 58,74 **** }; */ // for QQ 2003iii 0304, fixed value ! static const guint8 login_23_51[29] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x93, 0xfe, 0x85, 0xd3, 0xd9, 0x2a, 0x41, 0xc8, 0x0d, 0xff, 0xb6, 0x40, 0xb8, 0xac, 0x32, 0x01 }; // fixed value, not affected by version, or mac address ! static const guint8 login_53_68[16] = { 0x82, 0x2a, 0x91, 0xfd, 0xa5, 0xca, 0x67, 0x4c, 0xac, 0x81, 0x1f, 0x6f, 0x52, 0x05, 0xa7, 0xbf }; typedef struct _qq_login_reply_ok qq_login_reply_ok_packet; --- 58,93 ---- }; */ // for QQ 2003iii 0304, fixed value ! /*static const guint8 login_23_51[29] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x93, 0xfe, 0x85, 0xd3, 0xd9, 0x2a, 0x41, 0xc8, 0x0d, 0xff, 0xb6, 0x40, 0xb8, 0xac, 0x32, 0x01 + };*/ + // for QQ 2006 with sp1 modify by Yuan Qingyun + static const guint8 login_23_51[29] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x29, 0xc0, 0xf8, 0xc4, + 0x04, 0x3b, 0xee, 0x57, 0x92, 0xd2, 0x42, 0xa6, + 0xbe, 0x41, 0x98, 0x97, 0x9e }; // fixed value, not affected by version, or mac address ! /*static const guint8 login_53_68[16] = { 0x82, 0x2a, 0x91, 0xfd, 0xa5, 0xca, 0x67, 0x4c, 0xac, 0x81, 0x1f, 0x6f, 0x52, 0x05, 0xa7, 0xbf + };*/ + // for QQ 2006 with sp1 modify by Yuan Qingyun + static const guint8 login_53_68[16] = { + 0x2e, 0xda, 0x0c, 0x59, 0xa7, 0x1a, 0xd6, 0x4a, + 0xb1, 0x48, 0x5d, 0xba, 0x37, 0x1e, 0xac, 0xb9 + }; + // for QQ 2006 with sp1 add by Yuan Qingyun + static const guint8 login_94_118[25] = { + 0x01, 0x40, 0x01, 0xd7, 0x50, 0x72, 0xc8, 0x00, + 0x10, 0x4a, 0xc3, 0x1b, 0x6c, 0xf9, 0x85, 0xf5, + 0xd9, 0xa8, 0x05, 0xac, 0x95, 0xa0, 0xe2, 0x44, + 0x01 }; typedef struct _qq_login_reply_ok qq_login_reply_ok_packet; *************** void qq_send_packet_login(GaimConnection *** 279,285 **** qd = (qq_data *) gc->proto_data; buf = g_newa(guint8, MAX_PACKET_SIZE); ! raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH); encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); // 16 bytes more qd->inikey = _gen_login_key(); --- 298,304 ---- qd = (qq_data *) gc->proto_data; buf = g_newa(guint8, MAX_PACKET_SIZE); ! raw_data = g_new0(guint8, QQ_LOGIN_DATA_LENGTH); encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); // 16 bytes more qd->inikey = _gen_login_key(); *************** void qq_send_packet_login(GaimConnection *** 298,304 **** raw_data[52] = qd->login_mode; // 053-068, fixed value, maybe related to per machine g_memmove(raw_data + 53, login_53_68, 16); ! qq_crypt(ENCRYPT, raw_data, QQ_LOGIN_DATA_LENGTH, qd->inikey, encrypted_data, &encrypted_len); cursor = buf; --- 317,328 ---- raw_data[52] = qd->login_mode; // 053-068, fixed value, maybe related to per machine g_memmove(raw_data + 53, login_53_68, 16); ! // 069-069, login token length ! raw_data[69] = qd->token_len; ! // 070-093, login token ! g_memmove(raw_data + 70, qd->ptoken, qd->token_len); ! // 094-118, unknown ! g_memmove(raw_data + 70 + qd->token_len, login_94_118, 25); qq_crypt(ENCRYPT, raw_data, QQ_LOGIN_DATA_LENGTH, qd->inikey, encrypted_data, &encrypted_len); cursor = buf; *************** void qq_process_login_reply(guint8 * buf *** 359,365 **** len = buf_len; // reset len, decrypt will fail if len is too short if (qq_crypt(DECRYPT, buf, buf_len, qd->inikey, data, &len)) { // decrypt ok with inipwd, it might be password error ! gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Decrypt login reply packet with inikey, %d bytes\n", len); bytes = 0; switch (data[0]) { case QQ_LOGIN_REPLY_REDIRECT: --- 383,389 ---- len = buf_len; // reset len, decrypt will fail if len is too short if (qq_crypt(DECRYPT, buf, buf_len, qd->inikey, data, &len)) { // decrypt ok with inipwd, it might be password error ! gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Decrypt login reply packet with inikey, %d bytes data[0] is %x\n", len, data[0]); bytes = 0; switch (data[0]) { case QQ_LOGIN_REPLY_REDIRECT: *************** void qq_process_login_reply(guint8 * buf *** 396,400 **** --- 420,477 ---- } // switch ret } // qq_process_login_reply + //add by Yuan Qingyun to process login token + void qq_process_login_token_relay(guint8 * buf, gint buf_len, GaimConnection * gc) + { + gint bytes; + guint8 retCode = 0; + guint8 *cursor; + qq_data *qd; + if (NULL ==gc || NULL == gc->proto_data) + return; + qd = (qq_data *) gc->proto_data; + cursor = buf; + bytes = 0; + + // 000-000: reply code + bytes += read_packet_b(buf, &cursor, buf_len, &retCode); + if (retCode != 0) + { + gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail get login tocken from server\n"); + return; + } + bytes += read_packet_b(buf, &cursor, buf_len, &qd->token_len); + if (qd->ptoken != NULL) + g_free(qd->ptoken); + qd->ptoken = g_new0(guint8, qd->token_len); + bytes += read_packet_data(buf, &cursor, buf_len, qd->ptoken, qd->token_len); + qq_send_packet_login(gc); + + } + + //add by Yuan Qingyun for send login token + void qq_send_packet_login_token(GaimConnection * gc) + { + qq_data *qd; + guint8 *buf, *cursor; + gint bytes; + guint16 seq_ret; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + buf = g_newa(guint8, MAX_PACKET_SIZE); + cursor = buf; + qd->token_len = 0; + qd->ptoken = NULL; + bytes = 0; + bytes += _create_packet_head_seq(buf, &cursor, gc, QQ_CMD_GET_LOGIN_TOKEN, TRUE, &seq_ret); + bytes += create_packet_dw(buf, &cursor, qd->uid); + bytes += create_packet_b(buf, &cursor, 0x00); + bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL); + if (bytes == (cursor - buf)) // packet creation OK + _qq_send_packet(gc, buf, bytes, QQ_CMD_GET_LOGIN_TOKEN); + else + gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail create login tocken packet\n"); + } + /*****************************************************************************/ // END OF FILE diff -Npr openq-0.3.2/src/login_logout.h openq-0.3.2.for1/src/login_logout.h *** openq-0.3.2/src/login_logout.h 2004-10-04 01:37:36.000000000 +0800 --- openq-0.3.2.for1/src/login_logout.h 2006-03-06 09:44:33.000000000 +0800 *************** void qq_send_packet_logout(GaimConnectio *** 37,42 **** --- 37,45 ---- void qq_process_login_reply(guint8 * buf, gint buf_len, GaimConnection * gc); + void qq_send_packet_login_token(GaimConnection * gc); + + void qq_process_login_token_relay(guint8 * buf, gint buf_len, GaimConnection * gc); #endif /*****************************************************************************/ // END OF FILE diff -Npr openq-0.3.2/src/qq.h openq-0.3.2.for1/src/qq.h *** openq-0.3.2/src/qq.h 2004-10-23 23:22:52.000000000 +0800 --- openq-0.3.2.for1/src/qq.h 2006-03-07 13:49:11.000000000 +0800 *************** struct _qq_buddy { *** 48,53 **** --- 48,54 ---- guint8 status; guint8 flag1; guint8 comm_flag; // details in qq_buddy_list.c + guint16 client_version; // added by gfhuang time_t signon; time_t idle; time_t last_refresh; *************** struct _qq_data { *** 65,71 **** guint8 status; // gboolean logged_in; // used by qq-add_buddy gboolean use_tcp; // network in tcp or udp ! GaimProxyType proxy_type; // proxy type GaimXfer *xfer; // file transfer handler struct sockaddr_in dest_sin; --- 66,75 ---- guint8 status; // gboolean logged_in; // used by qq-add_buddy gboolean use_tcp; // network in tcp or udp ! //modify by Yuan Qingyun ! guint8 token_len; //login token length ! guint8 * ptoken; //login token ! guint8 * pGroupUnknown; GaimProxyType proxy_type; // proxy type GaimXfer *xfer; // file transfer handler struct sockaddr_in dest_sin; diff -Npr openq-0.3.2/src/qq_proxy.c openq-0.3.2.for1/src/qq_proxy.c *** openq-0.3.2/src/qq_proxy.c 2004-10-23 23:22:52.000000000 +0800 --- openq-0.3.2.for1/src/qq_proxy.c 2006-03-06 09:44:33.000000000 +0800 *************** void _qq_got_login(gpointer data, gint s *** 155,161 **** gaim_connection_update_progress(gc, buf, 1, QQ_CONNECT_STEPS); g_free(buf); ! qq_send_packet_login(gc); // finally ready to fire } // _qq_got_login /*****************************************************************************/ --- 155,162 ---- gaim_connection_update_progress(gc, buf, 1, QQ_CONNECT_STEPS); g_free(buf); ! //qq_send_packet_login(gc); // finally ready to fire ! qq_send_packet_login_token(gc); //Modify by Yuan Qingyun for get login token } // _qq_got_login /*****************************************************************************/ *************** void qq_disconnect(GaimConnection * gc) *** 357,364 **** g_free(qd->pwkey); g_free(qd->session_key); g_free(qd->my_ip); g_free(qd); - gc->proto_data = NULL; } // qq_disconnect --- 358,366 ---- g_free(qd->pwkey); g_free(qd->session_key); g_free(qd->my_ip); + g_free(qd->ptoken); //add by Yuan Qingyun + qd->ptoken = NULL; g_free(qd); gc->proto_data = NULL; } // qq_disconnect diff -Npr openq-0.3.2/src/recv_core.c openq-0.3.2.for1/src/recv_core.c *** openq-0.3.2/src/recv_core.c 2004-10-02 23:48:12.000000000 +0800 --- openq-0.3.2.for1/src/recv_core.c 2006-03-06 09:44:34.000000000 +0800 *************** void _qq_packet_process(guint8 * buf, gi *** 164,171 **** gaim_debug(GAIM_DEBUG_INFO, "QQ", "==> [%05d] %s, from (%s)\n", header.seq, qq_get_cmd_desc(header.cmd), qq_get_source_str(header.source_tag)); ! ! if (header.cmd != QQ_CMD_LOGIN) { if (!qd->logged_in) { // packets before login b4_packet = g_new0(packet_before_login, 1); // must duplicate, buffer will be freed after exiting this function --- 164,171 ---- gaim_debug(GAIM_DEBUG_INFO, "QQ", "==> [%05d] %s, from (%s)\n", header.seq, qq_get_cmd_desc(header.cmd), qq_get_source_str(header.source_tag)); ! //add "&& header.cmd != QQ_CMD_GET_LOGIN_TOKEN" by Yuan Qingyun for QQ 2006 with SP1 ! if (header.cmd != QQ_CMD_LOGIN && header.cmd != QQ_CMD_GET_LOGIN_TOKEN) { if (!qd->logged_in) { // packets before login b4_packet = g_new0(packet_before_login, 1); // must duplicate, buffer will be freed after exiting this function *************** void _qq_packet_process(guint8 * buf, gi *** 264,269 **** --- 264,272 ---- case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS: qq_process_friend_change_status(cursor, len, gc); break; + case QQ_CMD_GET_LOGIN_TOKEN://add by Yuan Qingyun for QQ 2006 with SP1 + qq_process_login_token_relay(cursor, len, gc); + break; default: _qq_process_packet_default(cursor, len, header.cmd, header.seq, gc); break;