changeset 24142:df699d739b8f

2008.10.03 - ccpaging <ccpaging(at)gmail.com> * 2007 protocol: 1. fixed 'get room info' 2. fixed 'get buddy level'
author SHiNE CsyFeK <csyfek@gmail.com>
date Wed, 22 Oct 2008 14:46:44 +0000
parents efd4a0e6dd86
children c2253c485728
files libpurple/protocols/qq/ChangeLog libpurple/protocols/qq/buddy_info.c libpurple/protocols/qq/buddy_info.h libpurple/protocols/qq/buddy_list.c libpurple/protocols/qq/buddy_opt.c libpurple/protocols/qq/buddy_opt.h libpurple/protocols/qq/char_conv.c libpurple/protocols/qq/char_conv.h libpurple/protocols/qq/group_find.c libpurple/protocols/qq/group_info.c libpurple/protocols/qq/qq.c libpurple/protocols/qq/qq_process.c libpurple/protocols/qq/utils.c
diffstat 13 files changed, 246 insertions(+), 131 deletions(-) [+]
line wrap: on
line diff
--- 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 <ccpaging(at)gmail.com>
+	* 2007 protocol:
+		1. fixed 'get room info'
+		2. fixed 'get buddy level'
+
 2008.10.02 - ccpaging <ccpaging(at)gmail.com>
 	* Added 'Captcha Display' function
 	* QQ2007 for openq, programed by Emil Alexiev:
--- 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;
+	}
+}
+
--- 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
--- 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");
--- 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)
 {
--- 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);
--- 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);
 }
-
-
--- 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);
--- 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);
 	}
--- 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 + <str content> */
 	bytes += convert_as_pascal_string(data + bytes, &(group->title_utf8), QQ_CHARSET_DEFAULT);
 	bytes += qq_get16(&unknown, data + bytes);	/* 0x0000 */
--- 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 */
--- 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);
--- 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;
 }