# HG changeset patch # User SHiNE CsyFeK # Date 1224686804 0 # Node ID df699d739b8f91346abbb9ff438b28823759f500 # Parent efd4a0e6dd869f0f8b0ef996aaae5e5eaf21353a 2008.10.03 - ccpaging * 2007 protocol: 1. fixed 'get room info' 2. fixed 'get buddy level' diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/ChangeLog --- a/libpurple/protocols/qq/ChangeLog Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/ChangeLog Wed Oct 22 14:46:44 2008 +0000 @@ -1,3 +1,8 @@ +2008.10.03 - ccpaging + * 2007 protocol: + 1. fixed 'get room info' + 2. fixed 'get buddy level' + 2008.10.02 - ccpaging * Added 'Captcha Display' function * QQ2007 for openq, programed by Emil Alexiev: diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/buddy_info.c --- a/libpurple/protocols/qq/buddy_info.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Wed Oct 22 14:46:44 2008 +0000 @@ -665,10 +665,23 @@ guint8 buf[16] = {0}; gint bytes = 0; - bytes += qq_put8(buf + bytes, 0x00); + if (qd->client_version >= 2007) { + bytes += qq_put8(buf + bytes, 0x02); + } else { + bytes += qq_put8(buf + bytes, 0x00); + } bytes += qq_put32(buf + bytes, uid); + qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); +} - qd = (qq_data *) gc->proto_data; +void qq_request_get_level_2007(PurpleConnection *gc, guint32 uid) +{ + guint8 buf[16] = {0}; + gint bytes = 0; + + bytes += qq_put8(buf + bytes, 0x08); + bytes += qq_put32(buf + bytes, uid); + bytes += qq_put8(buf + bytes, 0x00); qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); } @@ -684,11 +697,11 @@ if ( qd->buddies == NULL) { return; } + /* server only reply levels for online buddies */ size = 4 * g_list_length(qd->buddies) + 1 + 4; buf = g_newa(guint8, size); bytes += qq_put8(buf + bytes, 0x00); - while (NULL != node) { q_bud = (qq_buddy *) node->data; if (NULL != q_bud) { @@ -696,41 +709,24 @@ } node = node->next; } - /* my id should be the end if included */ bytes += qq_put32(buf + bytes, qd->uid); qq_send_cmd_mess(gc, QQ_CMD_GET_LEVEL, buf, size, update_class, 0); } -void qq_process_get_level_reply(guint8 *decr_buf, gint decr_len, PurpleConnection *gc) +static void process_level(PurpleConnection *gc, guint8 *data, gint data_len) { - guint32 uid, onlineTime; - guint16 level, timeRemainder; - gchar *purple_name; - PurpleBuddy *b; - qq_buddy *q_bud; - gint i; - PurpleAccount *account = purple_connection_get_account(gc); qq_data *qd = (qq_data *) gc->proto_data; gint bytes = 0; - - decr_len--; - if (decr_len % 12 != 0) { - purple_debug_error("QQ", - "Get levels list of abnormal length. Truncating last %d bytes.\n", decr_len % 12); - decr_len -= (decr_len % 12); - } - - bytes += 1; - /* this byte seems random */ - /* - purple_debug_info("QQ", "Byte one of get_level packet: %d\n", buf[0]); - */ - for (i = 0; i < decr_len; i += 12) { - bytes += qq_get32(&uid, decr_buf + bytes); - bytes += qq_get32(&onlineTime, decr_buf + bytes); - bytes += qq_get16(&level, decr_buf + bytes); - bytes += qq_get16(&timeRemainder, decr_buf + bytes); + guint32 uid, onlineTime; + guint16 level, timeRemainder; + qq_buddy *buddy; + + while (data_len - bytes >= 12) { + bytes += qq_get32(&uid, data + bytes); + bytes += qq_get32(&onlineTime, data + bytes); + bytes += qq_get16(&level, data + bytes); + bytes += qq_get16(&timeRemainder, data + bytes); purple_debug_info("QQ_LEVEL", "%d, tmOnline: %d, level: %d, tmRemainder: %d\n", uid, onlineTime, level, timeRemainder); if (uid == qd->uid) { @@ -738,27 +734,93 @@ purple_debug_warning("QQ", "Got my levels as %d\n", qd->my_level); } - purple_name = uid_to_purple_name(uid); - if (purple_name == NULL) { - continue; - } - - b = purple_find_buddy(account, purple_name); - g_free(purple_name); - - q_bud = NULL; - if (b != NULL) { - q_bud = (qq_buddy *) b->proto_data; - } - - if (q_bud == NULL) { + buddy = qq_get_buddy(gc, uid); + if (buddy == NULL) { purple_debug_error("QQ", "Got levels of %d not in my buddy list\n", uid); continue; } - q_bud->onlineTime = onlineTime; - q_bud->level = level; - q_bud->timeRemainder = timeRemainder; + buddy->onlineTime = onlineTime; + buddy->level = level; + buddy->timeRemainder = timeRemainder; + } + + if (bytes != data_len) { + purple_debug_error("QQ", + "Wrong format of Get levels. Truncate %d bytes.\n", data_len - bytes); } } +static void process_level_2007(PurpleConnection *gc, guint8 *data, gint data_len) +{ + qq_data *qd = (qq_data *) gc->proto_data; + gint bytes; + guint32 uid, onlineTime; + guint16 level, timeRemainder; + qq_buddy *buddy; + guint16 str_len; + gchar *str; + gchar *str_utf8; + + bytes = 0; + bytes += qq_get32(&uid, data + bytes); + bytes += qq_get32(&onlineTime, data + bytes); + bytes += qq_get16(&level, data + bytes); + bytes += qq_get16(&timeRemainder, data + bytes); + purple_debug_info("QQ_LEVEL", "%d, tmOnline: %d, level: %d, tmRemainder: %d\n", + uid, onlineTime, level, timeRemainder); + + if (uid == qd->uid) { + qd->my_level = level; + purple_debug_warning("QQ", "Got my levels as %d\n", qd->my_level); + } + + buddy = qq_get_buddy(gc, uid); + if (buddy == NULL) { + purple_debug_error("QQ", "Got levels of %d not in my buddy list\n", uid); + return; + } + + buddy->onlineTime = onlineTime; + buddy->level = level; + buddy->timeRemainder = timeRemainder; + + /* extend bytes in qq2007*/ + bytes += 4; /* skip 8 bytes */ + qq_show_packet("Buddies level", data + bytes, data_len - bytes); + + do { + bytes += qq_get16(&str_len, data + bytes); + if (str_len <= 0 || bytes + str_len > data_len) { + purple_debug_error("QQ", + "Wrong format of Get levels. Truncate %d bytes.\n", data_len - bytes); + break; + } + str = g_strndup((gchar *)data + bytes, str_len); + bytes += str_len; + str_utf8 = qq_to_utf8(str, QQ_CHARSET_DEFAULT); + purple_debug_info("QQ", "%s\n", str_utf8); + g_free(str_utf8); + g_free(str); + } while (bytes < data_len); +} + +void qq_process_get_level_reply(guint8 *data, gint data_len, PurpleConnection *gc) +{ + gint bytes; + guint8 sub_cmd; + + bytes = 0; + bytes += qq_get8(&sub_cmd, data + bytes); + switch (sub_cmd) { + case 0x08: + process_level_2007(gc, data + bytes, data_len - bytes); + break; + case 0x00: + case 0x02: + default: + process_level(gc, data + bytes, data_len - bytes); + break; + } +} + diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/buddy_info.h --- a/libpurple/protocols/qq/buddy_info.h Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Wed Oct 22 14:46:44 2008 +0000 @@ -84,6 +84,7 @@ void qq_process_get_buddy_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc); void qq_request_get_level(PurpleConnection *gc, guint32 uid); +void qq_request_get_level_2007(PurpleConnection *gc, guint32 uid); void qq_request_get_buddies_level(PurpleConnection *gc, gint update_class); void qq_process_get_level_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); #endif diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:46:44 2008 +0000 @@ -157,40 +157,38 @@ return bytes; } -#define QQ_ONLINE_BUDDY_ENTRY_LEN 38 - /* process the reply packet for get_buddies_online packet */ guint8 qq_process_get_buddies_online_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint bytes, bytes_buddy; + gint bytes, bytes_start; gint count; guint8 position; - PurpleBuddy *b; - qq_buddy *q_bud; + qq_buddy *buddy; qq_buddy_online bo; - gchar *purple_name; + int entry_len = 38; g_return_val_if_fail(data != NULL && data_len != 0, -1); qd = (qq_data *) gc->proto_data; /* qq_show_packet("Get buddies online reply packet", data, len); */ + if (qd->client_version >= 2007) entry_len += 4; bytes = 0; bytes += qq_get8(&position, data + bytes); count = 0; while (bytes < data_len) { - if (data_len - bytes < QQ_ONLINE_BUDDY_ENTRY_LEN) { + if (data_len - bytes < entry_len) { purple_debug_error("QQ", "[buddies online] only %d, need %d\n", - (data_len - bytes), QQ_ONLINE_BUDDY_ENTRY_LEN); + (data_len - bytes), entry_len); break; } memset(&bo, 0 ,sizeof(bo)); /* set flag */ - bytes_buddy = bytes; + bytes_start = bytes; /* based on one online buddy entry */ /* 000-030 qq_buddy_status */ bytes += get_buddy_status(&(bo.bs), data + bytes); @@ -204,10 +202,12 @@ bytes += qq_get16(&bo.unknown2, data + bytes); /* 037-037: */ bytes += qq_get8(&bo.ending, data + bytes); /* 0x00 */ + /* skip 4 bytes in qq2007 */ + if (qd->client_version >= 2007) bytes += 4; - if (bo.bs.uid == 0 || (bytes - bytes_buddy) != QQ_ONLINE_BUDDY_ENTRY_LEN) { + if (bo.bs.uid == 0 || (bytes - bytes_start) != entry_len) { purple_debug_error("QQ", "uid=0 or entry complete len(%d) != %d", - (bytes - bytes_buddy), QQ_ONLINE_BUDDY_ENTRY_LEN); + (bytes - bytes_start), entry_len); continue; } /* check if it is a valid entry */ @@ -216,17 +216,8 @@ } /* update buddy information */ - purple_name = uid_to_purple_name(bo.bs.uid); - if (purple_name == NULL) { - purple_debug_error("QQ", - "Got an online buddy %d, but not find purple name\n", bo.bs.uid); - continue; - } - b = purple_find_buddy(purple_connection_get_account(gc), purple_name); - g_free(purple_name); - - q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; - if (q_bud == NULL) { + buddy = qq_get_buddy(gc, bo.bs.uid); + if (buddy == NULL) { purple_debug_error("QQ", "Got an online buddy %d, but not in my buddy list\n", bo.bs.uid); continue; @@ -236,12 +227,12 @@ if(0 != fe->s->client_tag) q_bud->client_tag = fe->s->client_tag; */ - q_bud->ip.s_addr = bo.bs.ip.s_addr; - q_bud->port = bo.bs.port; - q_bud->status = bo.bs.status; - q_bud->ext_flag = bo.ext_flag; - q_bud->comm_flag = bo.comm_flag; - qq_update_buddy_contact(gc, q_bud); + buddy->ip.s_addr = bo.bs.ip.s_addr; + buddy->port = bo.bs.port; + buddy->status = bo.bs.status; + buddy->ext_flag = bo.ext_flag; + buddy->comm_flag = bo.comm_flag; + qq_update_buddy_contact(gc, buddy); count++; } @@ -530,9 +521,7 @@ qq_data *qd; gint bytes; guint8 reply; - PurpleBuddy *b; - qq_buddy *q_bud; - gchar *name; + qq_buddy *buddy; g_return_if_fail(data != NULL && data_len != 0); @@ -546,12 +535,9 @@ } /* purple_debug_info("QQ", "Change status OK\n"); */ - name = uid_to_purple_name(qd->uid); - b = purple_find_buddy(gc->account, name); - g_free(name); - q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; - if (q_bud != NULL) { - qq_update_buddy_contact(gc, q_bud); + buddy = qq_get_buddy(gc, qd->uid); + if (buddy != NULL) { + qq_update_buddy_contact(gc, buddy); } } @@ -561,10 +547,8 @@ qq_data *qd; gint bytes; guint32 my_uid; - PurpleBuddy *b; - qq_buddy *q_bud; + qq_buddy *buddy; qq_buddy_status bs; - gchar *name; g_return_if_fail(data != NULL && data_len != 0); @@ -584,57 +568,58 @@ * QQ_BUDDY_ONLINE_INVISIBLE */ bytes += qq_get32(&my_uid, data + bytes); - name = uid_to_purple_name(bs.uid); - b = purple_find_buddy(gc->account, name); - g_free(name); - q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; - if (q_bud == NULL) { + buddy = qq_get_buddy(gc, bs.uid); + if (buddy == NULL) { purple_debug_warning("QQ", "Get status of unknown buddy %d\n", bs.uid); return; } if(bs.ip.s_addr != 0) { - q_bud->ip.s_addr = bs.ip.s_addr; - q_bud->port = bs.port; + buddy->ip.s_addr = bs.ip.s_addr; + buddy->port = bs.port; } - q_bud->status =bs.status; + buddy->status =bs.status; - if (q_bud->status == QQ_BUDDY_ONLINE_NORMAL && q_bud->level <= 0) { - qq_request_get_level(gc, q_bud->uid); + if (buddy->status == QQ_BUDDY_ONLINE_NORMAL && buddy->level <= 0) { + if (qd->client_version >= 2007) { + qq_request_get_level_2007(gc, buddy->uid); + } else { + qq_request_get_level(gc, buddy->uid); + } } - qq_update_buddy_contact(gc, q_bud); + qq_update_buddy_contact(gc, buddy); } /*TODO: maybe this should be qq_update_buddy_status() ?*/ -void qq_update_buddy_contact(PurpleConnection *gc, qq_buddy *q_bud) +void qq_update_buddy_contact(PurpleConnection *gc, qq_buddy *buddy) { gchar *purple_name; - PurpleBuddy *bud; + PurpleBuddy *purple_buddy; gchar *status_id; - g_return_if_fail(q_bud != NULL); + g_return_if_fail(buddy != NULL); - purple_name = uid_to_purple_name(q_bud->uid); + purple_name = uid_to_purple_name(buddy->uid); if (purple_name == NULL) { - purple_debug_error("QQ", "Not find purple name: %d\n", q_bud->uid); + purple_debug_error("QQ", "Not find purple name: %d\n", buddy->uid); return; } - bud = purple_find_buddy(gc->account, purple_name); - if (bud == NULL) { - purple_debug_error("QQ", "Not find buddy: %d\n", q_bud->uid); + purple_buddy = purple_find_buddy(gc->account, purple_name); + if (purple_buddy == NULL) { + purple_debug_error("QQ", "Not find buddy: %d\n", buddy->uid); g_free(purple_name); return; } - purple_blist_server_alias_buddy(bud, q_bud->nickname); /* server */ - q_bud->last_update = time(NULL); + purple_blist_server_alias_buddy(purple_buddy, buddy->nickname); /* server */ + buddy->last_update = time(NULL); /* purple supports signon and idle time * but it is not much use for QQ, I do not use them */ /* serv_got_update(gc, name, online, 0, q_bud->signon, q_bud->idle, bud->uc); */ status_id = "available"; - switch(q_bud->status) { + switch(buddy->status) { case QQ_BUDDY_OFFLINE: status_id = "offline"; break; @@ -655,13 +640,13 @@ break; default: status_id = "invisible"; - purple_debug_error("QQ", "unknown status: %x\n", q_bud->status); + purple_debug_error("QQ", "unknown status: %x\n", buddy->status); break; } - purple_debug_info("QQ", "buddy %d %s\n", q_bud->uid, status_id); + purple_debug_info("QQ", "buddy %d %s\n", buddy->uid, status_id); purple_prpl_got_user_status(gc->account, purple_name, status_id, NULL); - if (q_bud->comm_flag & QQ_COMM_FLAG_MOBILE && q_bud->status != QQ_BUDDY_OFFLINE) + if (buddy->comm_flag & QQ_COMM_FLAG_MOBILE && buddy->status != QQ_BUDDY_OFFLINE) purple_prpl_got_user_status(gc->account, purple_name, "mobile", NULL); else purple_prpl_got_user_status_deactive(gc->account, purple_name, "mobile"); diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/buddy_opt.c --- a/libpurple/protocols/qq/buddy_opt.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Wed Oct 22 14:46:44 2008 +0000 @@ -546,7 +546,11 @@ qd->buddies = g_list_append(qd->buddies, q_bud); qq_request_buddy_info(gc, qd->uid, 0, 0); qq_request_get_buddies_online(gc, 0, 0); - qq_request_get_level(gc, qd->uid); + if (qd->client_version >= 2007) { + qq_request_get_level_2007(gc, q_bud->uid); + } else { + qq_request_get_level(gc, q_bud->uid); + } } purple_blist_add_buddy(buddy, NULL, group, NULL); @@ -558,6 +562,26 @@ return buddy; } +qq_buddy *qq_get_buddy(PurpleConnection *gc, guint32 uid) +{ + gchar *purple_name; + PurpleBuddy *purple_buddy; + + g_return_val_if_fail(gc != NULL, NULL); + purple_name = uid_to_purple_name(uid); + if (purple_name == NULL) return NULL; + + purple_buddy = purple_find_buddy(purple_connection_get_account(gc), purple_name); + g_free(purple_name); + if (purple_buddy == NULL) return NULL; + + if (purple_buddy->proto_data == NULL) { + purple_debug_error("QQ", "Null data of buddy %d\n", uid); + return NULL; + } + return (qq_buddy *) purple_buddy->proto_data; +} + /* remove a buddy and send packet to QQ server accordingly */ void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/buddy_opt.h --- a/libpurple/protocols/qq/buddy_opt.h Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.h Wed Oct 22 14:46:44 2008 +0000 @@ -31,6 +31,7 @@ #include "qq.h" void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); +qq_buddy *qq_get_buddy(PurpleConnection *gc, guint32 uid); void qq_change_buddys_group(PurpleConnection *gc, const char *who, const char *old_group, const char *new_group); void qq_remove_buddy_and_me(PurpleBlistNode * node); diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/char_conv.c --- a/libpurple/protocols/qq/char_conv.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.c Wed Oct 22 14:46:44 2008 +0000 @@ -296,5 +296,3 @@ } g_strstrip(str); } - - diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/char_conv.h --- a/libpurple/protocols/qq/char_conv.h Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.h Wed Oct 22 14:46:44 2008 +0000 @@ -32,7 +32,6 @@ gint convert_as_pascal_string(guint8 *data, gchar **ret, const gchar *from_charset); gchar *qq_smiley_to_purple(gchar *text); - gchar *purple_smiley_to_qq(gchar *text); gchar *utf8_to_qq(const gchar *str, const gchar *to_charset); diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/group_find.c --- a/libpurple/protocols/qq/group_find.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/group_find.c Wed Oct 22 14:46:44 2008 +0000 @@ -72,20 +72,20 @@ qq_buddy *qq_group_find_or_add_member(PurpleConnection *gc, qq_group *group, guint32 member_uid) { qq_buddy *member, *q_bud; - PurpleBuddy *buddy; + PurpleBuddy *purple_buddy; g_return_val_if_fail(group != NULL && member_uid > 0, NULL); member = qq_group_find_member_by_uid(group, member_uid); if (member == NULL) { /* first appear during my session */ member = g_new0(qq_buddy, 1); member->uid = member_uid; - buddy = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(member_uid)); - if (buddy != NULL) { - q_bud = (qq_buddy *) buddy->proto_data; + purple_buddy = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(member_uid)); + if (purple_buddy != NULL) { + q_bud = (qq_buddy *) purple_buddy->proto_data; if (q_bud != NULL && q_bud->nickname != NULL) member->nickname = g_strdup(q_bud->nickname); - else if (buddy->alias != NULL) - member->nickname = g_strdup(buddy->alias); + else if (purple_buddy->alias != NULL) + member->nickname = g_strdup(purple_buddy->alias); } group->members = g_list_append(group->members, member); } diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/group_info.c --- a/libpurple/protocols/qq/group_info.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/group_info.c Wed Oct 22 14:46:44 2008 +0000 @@ -156,6 +156,8 @@ g_return_if_fail(data != NULL && data_len > 0); qd = (qq_data *) gc->proto_data; + /* qq_show_packet("Room Info", data, data_len); */ + bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); @@ -189,6 +191,10 @@ purple_debug_info("QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", group->type8, group->creator_uid, group->category, max_members); + /* skip 7 bytes unknow in qq2007 0x(00 00 01 00 00 00 fc)*/ + bytes += 7; + + /* qq_show_packet("Room Info", data + bytes, data_len - bytes); */ /* strlen + */ bytes += convert_as_pascal_string(data + bytes, &(group->title_utf8), QQ_CHARSET_DEFAULT); bytes += qq_get16(&unknown, data + bytes); /* 0x0000 */ diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Wed Oct 22 14:46:44 2008 +0000 @@ -499,7 +499,11 @@ return; } - qq_request_get_level(gc, uid); + if (qd->client_version >= 2007) { + qq_request_get_level_2007(gc, uid); + } else { + qq_request_get_level(gc, uid); + } qq_request_buddy_info(gc, uid, 0, QQ_BUDDY_INFO_DISPLAY); } @@ -773,12 +777,31 @@ /* who is the nickname of buddy in QQ chat-room (Qun) */ static void qq_get_chat_buddy_info(PurpleConnection *gc, gint channel, const gchar *who) { - gchar *purple_name; + qq_data *qd; + gchar *uid_str; + guint32 uid; + g_return_if_fail(who != NULL); - purple_name = chat_name_to_purple_name(who); - if (purple_name != NULL) - qq_show_buddy_info(gc, purple_name); + uid_str = chat_name_to_purple_name(who); + if (uid_str == NULL) { + return; + } + + qd = gc->proto_data; + uid = purple_name_to_uid(uid_str); + g_free(uid_str); + + if (uid <= 0) { + purple_debug_error("QQ", "Not valid chat name: %s\n", who); + purple_notify_error(gc, NULL, _("Invalid name"), NULL); + return; + } + + if (qd->client_version < 2007) { + qq_request_get_level(gc, uid); + } + qq_request_buddy_info(gc, uid, 0, QQ_BUDDY_INFO_DISPLAY); } /* convert chat nickname to uid to invite individual IM to buddy */ diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/qq_process.c --- a/libpurple/protocols/qq/qq_process.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Wed Oct 22 14:46:44 2008 +0000 @@ -359,7 +359,12 @@ qq_request_get_buddies_and_rooms(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); break; case QQ_CMD_GET_BUDDIES_AND_ROOMS: - qq_request_get_buddies_level(gc, QQ_CMD_CLASS_UPDATE_ALL); + if (qd->client_version >= 2007) { + /* QQ2007/2008 can not get buddies level*/ + qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); + } else { + qq_request_get_buddies_level(gc, QQ_CMD_CLASS_UPDATE_ALL); + } break; case QQ_CMD_GET_LEVEL: qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); diff -r efd4a0e6dd86 -r df699d739b8f libpurple/protocols/qq/utils.c --- a/libpurple/protocols/qq/utils.c Wed Oct 22 14:45:26 2008 +0000 +++ b/libpurple/protocols/qq/utils.c Wed Oct 22 14:46:44 2008 +0000 @@ -186,13 +186,19 @@ /* convert name displayed in a chat channel to original QQ UID */ gchar *chat_name_to_purple_name(const gchar *const name) { - const gchar *tmp; + const char *start; + const char *end; gchar *ret; g_return_val_if_fail(name != NULL, NULL); - tmp = (gchar *) purple_strcasestr(name, "("); - ret = g_strndup(tmp + 4, strlen(name) - (tmp - name) - 4 - 1); + /* Sample: (1234567)*/ + start = strchr(name, '('); + g_return_val_if_fail(start != NULL, NULL); + end = strchr(start, ')'); + g_return_val_if_fail(end != NULL && (end - start) > 1, NULL); + + ret = g_strndup(start + 1, end - start - 1); return ret; }