# HG changeset patch # User SHiNE CsyFeK # Date 1224686626 0 # Node ID 619ac2303c46e6d83fdfc224dcf54e1e30e03b39 # Parent 832178d951ca290d0de6d2fd77ba265f6f5921a0 2009.10.02 - ccpaging * Added 'Captcha Display' function * Most functions from patch written by Emil Alexiev merged into trunk, except 'buddy operations' * 'online buddy status' and 'qun buddies' still have problems diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/ChangeLog --- a/libpurple/protocols/qq/ChangeLog Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/ChangeLog Wed Oct 22 14:43:46 2008 +0000 @@ -1,3 +1,8 @@ +2009.10.02 - ccpaging + * Added 'Captcha Display' function + * Most functions from patch written by Emil Alexiev merged into trunk, except 'buddy operations' + * 'online buddy status' and 'qun buddies' still have problems + 2008.09.30 - ccpaging * Successfully login using 2007/2008 protocols diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:43:46 2008 +0000 @@ -84,9 +84,12 @@ * server may return a position tag if list is too long for one packet */ void qq_request_get_buddies_list(PurpleConnection *gc, guint16 position, gint update_class) { + qq_data *qd; guint8 raw_data[16] = {0}; gint bytes = 0; + qd = (qq_data *) gc->proto_data; + /* 000-001 starting position, can manually specify */ bytes += qq_put16(raw_data + bytes, position); /* before Mar 18, 2004, any value can work, and we sent 00 @@ -95,7 +98,10 @@ * Now I tested that 00,00,00,00,00,01 work perfectly * March 22, found the 00,00,00 starts to work as well */ bytes += qq_put8(raw_data + bytes, 0x00); - + if (qd->client_version >= 2007) { + bytes += qq_put16(raw_data + bytes, 0x0000); + } + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_LIST, raw_data, bytes, update_class, 0); } @@ -177,7 +183,7 @@ count = 0; while (bytes < data_len) { if (data_len - bytes < QQ_ONLINE_BUDDY_ENTRY_LEN) { - purple_debug_error("QQ", "[buddies online] only %d, need %d", + purple_debug_error("QQ", "[buddies online] only %d, need %d\n", (data_len - bytes), QQ_ONLINE_BUDDY_ENTRY_LEN); break; } @@ -292,11 +298,18 @@ bytes += pascal_len; qq_filter_str(q_bud->nickname); + /* Fixme: merge following as 32bit flag */ bytes += qq_get16(&unknown, data + bytes); bytes += qq_get8(&q_bud->ext_flag, data + bytes); bytes += qq_get8(&q_bud->comm_flag, data + bytes); + + if (qd->client_version >= 2007) { + bytes += 4; /* skip 4 bytes */ + bytes_expected = 16 + pascal_len; + } else { + bytes_expected = 12 + pascal_len; + } - bytes_expected = 12 + pascal_len; if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) { purple_debug_info("QQ", @@ -390,6 +403,10 @@ purple_debug_info("QQ", "Not find room id %d in qq_process_get_buddies_and_rooms\n", uid); qq_set_pending_id(&qd->adding_groups_from_server, uid, TRUE); + //group = g_newa(qq_group, 1); + //group->id = uid; + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, uid, NULL, 0, + 0, 0); } else { group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); @@ -421,6 +438,7 @@ case QQ_BUDDY_ONLINE_NORMAL: case QQ_BUDDY_ONLINE_AWAY: case QQ_BUDDY_ONLINE_INVISIBLE: + case QQ_BUDDY_ONLINE_BUSY: return TRUE; case QQ_BUDDY_CHANGE_TO_OFFLINE: return FALSE; @@ -467,22 +485,29 @@ if (!qd->is_login) return; - if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) { - away_cmd = QQ_BUDDY_ONLINE_INVISIBLE; - } else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY) - || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY) - || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) { - away_cmd = QQ_BUDDY_ONLINE_AWAY; - } else { - away_cmd = QQ_BUDDY_ONLINE_NORMAL; - } - + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) { + away_cmd = QQ_BUDDY_ONLINE_INVISIBLE; + } else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) + { + if (qd->client_version >= 2007) { + away_cmd = QQ_BUDDY_ONLINE_BUSY; + } else { + away_cmd = QQ_BUDDY_ONLINE_INVISIBLE; + } + } else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY) + || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY) + || purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) { + away_cmd = QQ_BUDDY_ONLINE_AWAY; + } else { + away_cmd = QQ_BUDDY_ONLINE_NORMAL; + } + misc_status = 0x00000000; fake_video = purple_prefs_get_bool("/plugins/prpl/qq/show_fake_video"); if (fake_video) misc_status |= QQ_MISC_STATUS_HAVING_VIIDEO; - if (qd->client_version > 2005) { + if (qd->client_version >= 2007) { bytes = 0; bytes += qq_put8(raw_data + bytes, away_cmd); /* status version */ @@ -625,6 +650,9 @@ case QQ_BUDDY_ONLINE_INVISIBLE: status_id = "invisible"; break; + case QQ_BUDDY_ONLINE_BUSY: + status_id = "busy"; + break; default: status_id = "invisible"; purple_debug_error("QQ", "unknown status: %x\n", q_bud->status); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/buddy_list.h --- a/libpurple/protocols/qq/buddy_list.h Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.h Wed Oct 22 14:43:46 2008 +0000 @@ -45,7 +45,8 @@ QQ_BUDDY_ONLINE_NORMAL = 10, QQ_BUDDY_CHANGE_TO_OFFLINE = 20, QQ_BUDDY_ONLINE_AWAY = 30, - QQ_BUDDY_ONLINE_INVISIBLE = 40 + QQ_BUDDY_ONLINE_INVISIBLE = 40, + QQ_BUDDY_ONLINE_BUSY = 50, }; void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, gint update_class); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/char_conv.c --- a/libpurple/protocols/qq/char_conv.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.c Wed Oct 22 14:43:46 2008 +0000 @@ -141,7 +141,7 @@ } /* convert QQ formatted msg to Purple formatted msg (and UTF-8) */ -gchar *qq_encode_to_purple(guint8 *data, gint len, const gchar *msg) +gchar *qq_encode_to_purple(guint8 *data, gint len, const gchar *msg, const gint client_version) { GString *encoded; guint8 font_attr, font_size, color[3], bar; @@ -153,6 +153,9 @@ /* checked qq_show_packet OK */ /* qq_show_packet("QQ_MESG recv for font style", data, len); */ + if (client_version >= 2007) { + bytes += 1; + } bytes += qq_get8(&font_attr, data + bytes); bytes += qq_getdata(color, 3, data + bytes); /* red,green,blue */ color_code = g_strdup_printf("#%02x%02x%02x", color[0], color[1], color[2]); @@ -232,8 +235,10 @@ converted = g_string_new(""); segments = split_data((guint8 *) text, strlen(text), "\x14\x15", 0); + if(segments == NULL) + return NULL; + g_string_append(converted, segments[0]); - while ((*(++segments)) != NULL) { cur_seg = *segments; qq_smiley = cur_seg[0]; diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/char_conv.h --- a/libpurple/protocols/qq/char_conv.h Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.h Wed Oct 22 14:43:46 2008 +0000 @@ -37,7 +37,7 @@ gchar *utf8_to_qq(const gchar *str, const gchar *to_charset); gchar *qq_to_utf8(const gchar *str, const gchar *from_charset); -gchar *qq_encode_to_purple(guint8 *font_attr_data, gint len, const gchar *msg); +gchar *qq_encode_to_purple(guint8 *font_attr_data, gint len, const gchar *msg, const gint client_version); gchar *qq_im_filter_html(const gchar *text); void qq_filter_str(gchar *str); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/group_im.c --- a/libpurple/protocols/qq/group_im.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/group_im.c Wed Oct 22 14:43:46 2008 +0000 @@ -401,12 +401,12 @@ /* group im_group has no flag to indicate whether it has font_attr or not */ msg_with_purple_smiley = qq_smiley_to_purple(packet.msg); - if (packet.font_attr_len > 0) + if (packet.font_attr_len > 0) { msg_utf8_encoded = qq_encode_to_purple(packet.font_attr, - packet.font_attr_len, msg_with_purple_smiley); - else + packet.font_attr_len, msg_with_purple_smiley, qd->client_version); + } else { msg_utf8_encoded = qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); - + } group = qq_room_search_id(gc, id); qq_room_got_chat_in(gc, group, packet.member_uid, msg_utf8_encoded, packet.send_time); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/im.c --- a/libpurple/protocols/qq/im.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/im.c Wed Oct 22 14:43:46 2008 +0000 @@ -390,7 +390,8 @@ msg_utf8_encoded = im_text->is_there_font_attr ? qq_encode_to_purple(im_text->font_attr, im_text->font_attr_len, - msg_with_purple_smiley) : qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); + msg_with_purple_smiley, qd->client_version) + : qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); /* send encoded to purple, note that we use im_text->send_time, * not the time we receive the message diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/packet_parse.c --- a/libpurple/protocols/qq/packet_parse.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.c Wed Oct 22 14:43:46 2008 +0000 @@ -151,6 +151,9 @@ * return the number of bytes packed, otherwise return -1 */ gint qq_put32(guint8 *buf, guint32 dw) { + guint32 dw_dest; + memcpy(&dw_dest, buf, sizeof(dw_dest)); + guint32 dw_porter; dw_porter = g_htonl(dw); #ifdef PARSER_DEBUG @@ -161,6 +164,19 @@ return sizeof(dw_porter); } +gint qq_putime(guint8 *buf, time_t *t) +{ + guint32 dw, dw_porter; + memcpy(&dw, t, sizeof(dw)); + dw_porter = g_htonl(dw); +#ifdef PARSER_DEBUG + purple_debug_info("QQ", "[DBG][put32] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter); +#endif + memcpy(buf, &dw_porter, sizeof(dw_porter)); + return sizeof(dw_porter); +} + gint qq_putIP(guint8* buf, struct in_addr *ip) { memcpy(buf, ip, sizeof(struct in_addr)); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/packet_parse.h --- a/libpurple/protocols/qq/packet_parse.h Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.h Wed Oct 22 14:43:46 2008 +0000 @@ -54,6 +54,7 @@ gint qq_put16(guint8 *buf, guint16 w); gint qq_put32(guint8 *buf, guint32 dw); gint qq_putIP(guint8* buf, struct in_addr *ip); +gint qq_putime(guint8 *buf, time_t *t); gint qq_putdata(guint8 *buf, const guint8 *data, const int datalen); /* diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Wed Oct 22 14:43:46 2008 +0000 @@ -267,6 +267,9 @@ case QQ_BUDDY_ONLINE_INVISIBLE: g_string_append(status, _("Invisible")); break; + case QQ_BUDDY_ONLINE_BUSY: + g_string_append(status, _("Busy")); + break; default: g_string_printf(status, _("Unknown-%d"), q_bud->status); } @@ -405,6 +408,10 @@ "invisible", _("Invisible"), FALSE, TRUE, FALSE); types = g_list_append(types, status); + status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, + "busy", _("Busy"), TRUE, TRUE, FALSE); + types = g_list_append(types, status); + status = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, "offline", _("Offline"), FALSE, TRUE, FALSE); types = g_list_append(types, status); @@ -898,7 +905,9 @@ GList *server_list = NULL; GList *server_kv_list = NULL; GList *it; +//#ifdef DEBUG GList *version_kv_list = NULL; +//#endif server_list = server_list_build('A'); @@ -927,7 +936,7 @@ option = purple_account_option_list_new(_("Select Server"), "server", server_kv_list); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); -#ifdef DEBUG +//#ifdef DEBUG kvp = g_new0(PurpleKeyValuePair, 1); kvp->key = g_strdup(_("QQ2005")); kvp->value = g_strdup("qq2005"); @@ -945,7 +954,7 @@ option = purple_account_option_list_new(_("Client Version"), "client_version", version_kv_list); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); -#endif +//#endif option = purple_account_option_bool_new(_("Connect by TCP"), "use_tcp", TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/qq_base.c --- a/libpurple/protocols/qq/qq_base.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.c Wed Oct 22 14:43:46 2008 +0000 @@ -460,11 +460,10 @@ * with this command, server return the same result including * the amount of online QQ users, my ip and port */ bytes += qq_put32(raw_data + bytes, qd->uid); - - qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, 4); + qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, bytes); } -/* parse the return of keep-alive packet, it includes some system information */ +/* parse the return ofqq_process_keep_alive keep-alive packet, it includes some system information */ gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; @@ -497,6 +496,107 @@ return TRUE; } +void qq_request_keep_alive_2007(PurpleConnection *gc) +{ + qq_data *qd; + guint8 raw_data[32] = {0}; + gint bytes= 0; + gchar *uid_str; + + qd = (qq_data *) gc->proto_data; + + /* In fact, we can send whatever we like to server + * with this command, server return the same result including + * the amount of online QQ users, my ip and port */ + uid_str = g_strdup_printf("%u", qd->uid); + bytes += qq_putdata(raw_data + bytes, (guint8 *)uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, bytes); + + g_free(uid_str); +} + +gboolean qq_process_keep_alive_2007(guint8 *data, gint data_len, PurpleConnection *gc) +{ + qq_data *qd; + gint bytes= 0; + guint8 ret; + + g_return_val_if_fail(data != NULL && data_len != 0, FALSE); + + qd = (qq_data *) gc->proto_data; + + /* qq_show_packet("Keep alive reply packet", data, len); */ + + bytes = 0; + bytes += qq_get8(&ret, data + bytes); + bytes += qq_get32(&qd->online_total, data + bytes); + if(0 == qd->online_total) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Keep alive error")); + } + + bytes += qq_getIP(&qd->my_ip, data + bytes); + bytes += qq_get16(&qd->my_port, data + bytes); + return TRUE; +} + +void qq_request_keep_alive_2008(PurpleConnection *gc) +{ + qq_data *qd; + guint8 raw_data[16] = {0}; + gint bytes= 0; + + qd = (qq_data *) gc->proto_data; + + /* In fact, we can send whatever we like to server + * with this command, server return the same result including + * the amount of online QQ users, my ip and port */ + bytes += qq_put32(raw_data + bytes, qd->uid); + bytes += qq_putime(raw_data + bytes, &qd->login_time); + qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, bytes); +} + +gboolean qq_process_keep_alive_2008(guint8 *data, gint data_len, PurpleConnection *gc) +{ + qq_data *qd; + gint bytes= 0; + guint8 ret; + time_t server_time; + struct tm *tm_local; + + g_return_val_if_fail(data != NULL && data_len != 0, FALSE); + + qd = (qq_data *) gc->proto_data; + + /* qq_show_packet("Keep alive reply packet", data, len); */ + + bytes = 0; + bytes += qq_get8(&ret, data + bytes); + bytes += qq_get32(&qd->online_total, data + bytes); + if(0 == qd->online_total) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Keep alive error")); + } + + bytes += qq_getIP(&qd->my_ip, data + bytes); + bytes += qq_get16(&qd->my_port, data + bytes); + /* skip 2 byytes, 0x(00 3c) */ + bytes += 2; + bytes += qq_getime(&server_time, data + bytes); + /* skip 5 bytes, all are 0 */ + + purple_debug_info("QQ", "keep alive, %s:%d\n", + inet_ntoa(qd->my_ip), qd->my_port); + + tm_local = localtime(&server_time); + purple_debug_info("QQ", "Server time: %d-%d-%d, %d:%d:%d\n", + (1900 +tm_local->tm_year), (1 + tm_local->tm_mon), tm_local->tm_mday, + tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec); + return TRUE; +} + /* For QQ2007/2008 */ void qq_request_get_server(PurpleConnection *gc) { @@ -681,8 +781,8 @@ bytes += qq_put32(raw_data + bytes, 0); bytes += qq_put16(raw_data + bytes, code_len); bytes += qq_putdata(raw_data + bytes, code, code_len); - bytes += qq_put16(raw_data + bytes, qd->captcha.token_len); /* captcha token */ - bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len); + bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len); /* login token ex */ + bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); @@ -811,7 +911,9 @@ bytes += qq_get16(&(qd->ld.token_ex_len), data + bytes); qd->ld.token_ex = g_realloc(qd->ld.token_ex, qd->ld.token_ex_len); - bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len , data + bytes); + bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len, data + bytes); + qq_show_packet("Get token ex", qd->ld.token_ex, qd->ld.token_ex_len); + if(reply != 1) { purple_debug_info("QQ", "Captcha verified, result %d\n", reply); @@ -828,9 +930,12 @@ bytes += qq_get8(&qd->captcha.next_index, data + bytes); bytes += qq_get16(&qd->captcha.token_len, data + bytes); - qd->captcha.token = g_new0(guint8, qd->captcha.token_len); + qd->captcha.token = g_realloc(qd->captcha.token, qd->captcha.token_len); bytes += qq_getdata(qd->captcha.token, qd->captcha.token_len, data + bytes); + qq_show_packet("Get captcha token", qd->captcha.token, qd->captcha.token_len); + purple_debug_info("QQ", "Request next captcha %d, new %d, total %d\n", + qd->captcha.next_index, captcha_len, qd->captcha.data_len); if(qd->captcha.next_index > 0) { return QQ_LOGIN_REPLY_NEXT_TOKEN_EX; @@ -894,7 +999,7 @@ g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; - g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0); + g_return_if_fail(qd->ld.token_ex != NULL && qd->ld.token_ex_len > 0); raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16); memset(raw_data, 0, MAX_PACKET_SIZE - 16); @@ -913,7 +1018,7 @@ bytes = 0; bytes += qq_putdata(raw_data + bytes, header, sizeof(header)); /* token get from qq_request_token_ex */ - bytes += qq_put8(raw_data + bytes, qd->ld.token_ex_len); + bytes += qq_put8(raw_data + bytes, (guint8)(qd->ld.token_ex_len & 0xff)); bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); /* password encrypted */ bytes += qq_put16(raw_data + bytes, encrypted_len); @@ -923,7 +1028,7 @@ bytes += qq_putdata(raw_data + bytes, unknown, sizeof(unknown)); bytes += qq_put32( raw_data + bytes, crc32(0xFFFFFFFF, unknown, sizeof(unknown))); - + /* put length into first 2 bytes */ qq_put8(raw_data + 1, bytes - 2); @@ -933,7 +1038,7 @@ bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[1]); bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[2]); - /* qq_show_packet("Check password", raw_data, bytes); */ + qq_show_packet("Check password", raw_data, bytes); /* Encrypted by random key*/ encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key); @@ -963,7 +1068,7 @@ g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR); qd = (qq_data *) gc->proto_data; - /* qq_show_packet("Check password reply", data, data_len); */ + qq_show_packet("Check password reply", data, data_len); bytes = 0; bytes += qq_get16(&unknow_token_len, data + bytes); /* maybe total length */ @@ -1097,11 +1202,12 @@ memset(raw_data + bytes, 0, 10); bytes += 10; /* redirect data, 15 bytes */ + qq_show_packet("Redirect", qd->redirect, qd->redirect_len); bytes += qq_putdata(raw_data + bytes, qd->redirect, qd->redirect_len); /* unknow fill */ bytes += qq_putdata(raw_data + bytes, login_2_16, sizeof(login_2_16)); /* captcha token get from qq_process_token_ex */ - bytes += qq_put8(raw_data + bytes, qd->ld.token_ex_len); + bytes += qq_put8(raw_data + bytes, (guint8)(qd->ld.token_ex_len & 0xff)); bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); /* unknow fill */ bytes += qq_putdata(raw_data + bytes, login_3_83, sizeof(login_3_83)); @@ -1130,8 +1236,10 @@ qq_data *qd; gint bytes; guint8 ret; + guint32 uid; gchar *error; - guint32 uid; + gchar *msg; + gchar *msg_utf8; g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR); @@ -1140,15 +1248,34 @@ bytes = 0; bytes += qq_get8(&ret, data + bytes); if (ret != 0) { - qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, - ">>> [default] decrypt and dump"); - error = g_strdup_printf( - _("Unknow reply code when login (0x%02X)"), - ret ); + msg = g_strndup((gchar *)data + bytes, data_len - bytes); + msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + + switch (ret) { + case 0x05: + error = g_strdup_printf( + _("Server is busy now, Please try later\n%s"), + ret, msg_utf8); + break; + case 0x0A: + /* 0a 2d 9a 4b 9a 01 01 00 00 00 05 00 00 00 00 79 0e 5f fd */ + default: + error = g_strdup_printf( + _("Unknow reply code when login (0x%02X):\n%s"), + ret, msg_utf8); + break; + } + + purple_debug_error("QQ", "%s\n", error); purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, error); + + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, error); + g_free(error); + g_free(msg_utf8); + g_free(msg); return QQ_LOGIN_REPLY_ERR; } @@ -1262,7 +1389,7 @@ /* unknow fill */ bytes += qq_putdata(raw_data + bytes, login_2_16, sizeof(login_2_16)); /* captcha token get from qq_process_token_ex */ - bytes += qq_put8(raw_data + bytes, qd->ld.token_ex_len); + bytes += qq_put8(raw_data + bytes, (guint8)(qd->ld.token_ex_len & 0xff)); bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); /* unknow fill */ bytes += qq_putdata(raw_data + bytes, login_3_18, sizeof(login_3_18)); @@ -1301,8 +1428,10 @@ qq_data *qd; gint bytes; guint8 ret; + guint32 uid; gchar *error; - guint32 uid; + gchar *msg; + gchar *msg_utf8; g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR); @@ -1311,15 +1440,32 @@ bytes = 0; bytes += qq_get8(&ret, data + bytes); if (ret != 0) { - qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, - ">>> [default] decrypt and dump"); - error = g_strdup_printf( - _("Unknow reply code when login (0x%02X)"), - ret ); + msg = g_strndup((gchar *)data + bytes, data_len - bytes); + msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + + switch (ret) { + case 0x05: + error = g_strdup_printf( + _("Server is busy now, Please try later\n%s"), + ret, msg_utf8); + break; + default: + error = g_strdup_printf( + _("Unknow reply code when login (0x%02X):\n%s"), + ret, msg_utf8); + break; + } + + purple_debug_error("QQ", "%s\n", error); purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, error); + + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, error); + g_free(error); + g_free(msg_utf8); + g_free(msg); return QQ_LOGIN_REPLY_ERR; } diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/qq_base.h --- a/libpurple/protocols/qq/qq_base.h Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.h Wed Oct 22 14:43:46 2008 +0000 @@ -52,6 +52,12 @@ void qq_request_keep_alive(PurpleConnection *gc); gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc); +void qq_request_keep_alive_2007(PurpleConnection *gc); +gboolean qq_process_keep_alive_2007(guint8 *data, gint data_len, PurpleConnection *gc); + +void qq_request_keep_alive_2008(PurpleConnection *gc); +gboolean qq_process_keep_alive_2008(guint8 *data, gint data_len, PurpleConnection *gc); + /* for QQ2007/2008 */ void qq_request_get_server(PurpleConnection *gc); guint16 qq_process_get_server(PurpleConnection *gc, guint8 *rcved, gint rcved_len); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/qq_network.c --- a/libpurple/protocols/qq/qq_network.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.c Wed Oct 22 14:43:46 2008 +0000 @@ -667,7 +667,13 @@ qd->itv_count.keep_alive--; if (qd->itv_count.keep_alive <= 0) { qd->itv_count.keep_alive = qd->itv_config.keep_alive; - qq_request_keep_alive(gc); + if (qd->client_version >= 2008) { + qq_request_keep_alive_2008(gc); + } else if (qd->client_version >= 2007) { + qq_request_keep_alive_2007(gc); + } else { + qq_request_keep_alive(gc); + } return TRUE; } @@ -691,7 +697,9 @@ const gchar *passwd; guint8 *dest; int dest_len = QQ_KEY_LENGTH; - +#ifndef DEBUG + int bytes; +#endif /* _qq_show_socket("Got login socket", source); */ g_return_if_fail(gc != NULL && gc->proto_data != NULL); @@ -771,7 +779,7 @@ set_all_keys( gc ); - if (qd->client_version > 2005) { + if (qd->client_version >= 2007) { purple_connection_update_progress(gc, _("Get server ..."), 2, QQ_CONNECT_STEPS); qq_request_get_server(gc); return; diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/qq_network.h --- a/libpurple/protocols/qq/qq_network.h Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.h Wed Oct 22 14:43:46 2008 +0000 @@ -30,7 +30,7 @@ #include "qq.h" -#define QQ_CONNECT_STEPS 3 /* steps in connection */ +#define QQ_CONNECT_STEPS 4 /* steps in connection */ gboolean qq_connect_later(gpointer data); void qq_disconnect(PurpleConnection *gc); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/qq_process.c --- a/libpurple/protocols/qq/qq_process.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Wed Oct 22 14:43:46 2008 +0000 @@ -589,7 +589,7 @@ switch (cmd) { case QQ_CMD_TOKEN: if (qq_process_token(gc, rcved, rcved_len) == QQ_LOGIN_REPLY_OK) { - if (qd->client_version > 2005) { + if (qd->client_version >= 2007) { qq_request_token_ex(gc); } else { qq_request_login(gc); @@ -615,7 +615,7 @@ break; case QQ_CMD_LOGIN: default: - if (qd->client_version > 2005) { + if (qd->client_version >= 2007) { data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.pwd_twice_md5); if (data_len >= 0) { purple_debug_warning("QQ", "Decrypt login packet by pwd_twice_md5\n"); @@ -696,6 +696,7 @@ return ret_8; } + purple_connection_update_progress(gc, _("Logined"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS); purple_debug_info("QQ", "Login repliess OK; everything is fine\n"); purple_connection_set_state(gc, PURPLE_CONNECTED); qd->is_login = TRUE; /* must be defined after sev_finish_login */ @@ -776,7 +777,13 @@ qq_process_send_im_reply(data, data_len, gc); break; case QQ_CMD_KEEP_ALIVE: - qq_process_keep_alive(data, data_len, gc); + if (qd->client_version >= 2008) { + qq_process_keep_alive_2008(data, data_len, gc); + } else if (qd->client_version >= 2007) { + qq_process_keep_alive_2007(data, data_len, gc); + } else { + qq_process_keep_alive(data, data_len, gc); + } break; case QQ_CMD_GET_BUDDIES_ONLINE: ret_8 = qq_process_get_buddies_online_reply(data, data_len, gc); diff -r 832178d951ca -r 619ac2303c46 libpurple/protocols/qq/send_file.c --- a/libpurple/protocols/qq/send_file.c Wed Oct 22 14:42:23 2008 +0000 +++ b/libpurple/protocols/qq/send_file.c Wed Oct 22 14:43:46 2008 +0000 @@ -121,11 +121,8 @@ sin.sin_port = g_htons(info->remote_minor_port); sin.sin_addr.s_addr = g_htonl(info->remote_real_ip); } - purple_debug_info("QQ", "sending to channel: %d.%d.%d.%d:%d\n", - (int)sin.sin_addr.s_addr & 0xff, - (int)(sin.sin_addr.s_addr >> 8) & 0xff, - (int)(sin.sin_addr.s_addr >> 16) & 0xff, - (int)sin.sin_addr.s_addr >> 24, + purple_debug_info("QQ", "sending to channel: %s:%d\n", + inet_ntoa(sin.sin_addr), (int)g_ntohs(sin.sin_port) ); return sendto(info->sender_fd, buf, len, 0, (struct sockaddr *) &sin, sizeof(sin));