changeset 24075:a95c7e71064c

2008.10.05 - ccpaging <ccpagint(at)gmail.com> * Add my uid into buddy list * Fixed a minor bug in qq_create_buddy. Not get new buddy's info. * There are 38 fields in protocol 2008, one more than 2005/2007. * The packet of Modifing buddy info is changed. Need sample to fix it.
author SHiNE CsyFeK <csyfek@gmail.com>
date Wed, 22 Oct 2008 14:48:46 +0000
parents c2253c485728
children ec3f7d3e0445
files libpurple/protocols/qq/ChangeLog libpurple/protocols/qq/buddy_info.c 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_conv.c libpurple/protocols/qq/group_im.c libpurple/protocols/qq/group_im.h libpurple/protocols/qq/group_info.c libpurple/protocols/qq/group_search.c libpurple/protocols/qq/im.h libpurple/protocols/qq/qq_process.c libpurple/protocols/qq/utils.c
diffstat 15 files changed, 299 insertions(+), 225 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/qq/ChangeLog	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/ChangeLog	Wed Oct 22 14:48:46 2008 +0000
@@ -1,3 +1,9 @@
+2008.10.05 - ccpaging <ccpagint(at)gmail.com>
+	* Add my uid into buddy list
+	* Fixed a minor bug in qq_create_buddy. Not get new buddy's info.
+	* There are 38 fields in protocol 2008, one more than 2005/2007.
+	* The packet of Modifing buddy info is changed. Need sample to fix it.
+
 2008.10.04 - ccpaging <ccpagint(at)gmail.com>
 	* Update protocol for 2007
 	* Code cleanup
--- a/libpurple/protocols/qq/buddy_info.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Wed Oct 22 14:48:46 2008 +0000
@@ -85,7 +85,7 @@
 	QQ_INFO_UNKNOW3, QQ_INFO_UNKNOW4, QQ_INFO_UNKNOW5,
 	QQ_INFO_IS_PUB_MOBILE, QQ_INFO_IS_PUB_CONTACT, QQ_INFO_COLLEGE, QQ_INFO_HOROSCOPE,
 	QQ_INFO_ZODIAC, QQ_INFO_BLOOD, QQ_INFO_SHOW, QQ_INFO_UNKNOW6,
-	QQ_INFO_LAST,
+	QQ_INFO_LAST_2007, QQ_INFO_LAST,
 };
 
 enum {
@@ -142,7 +142,8 @@
 	{ QQ_FIELD_EXT, 		QQ_FIELD_CHOICE, "zodiac",		N_("Zodiac"), zodiac_names, QQ_ZODIAC_SIZE },
 	{ QQ_FIELD_EXT, 		QQ_FIELD_CHOICE, "blood",			N_("Blood"), blood_types, QQ_BLOOD_SIZE },
 	{ QQ_FIELD_UNUSED, 	QQ_FIELD_STRING, "qq_show",	"QQ Show", NULL, 0 },
-	{ QQ_FIELD_UNUSED, 	QQ_FIELD_STRING, "unknow6",	"Unknow6", NULL, 0 }
+	{ QQ_FIELD_UNUSED, 	QQ_FIELD_STRING, "unknow6",	"Unknow6", NULL, 0 },
+	{ QQ_FIELD_UNUSED, 	QQ_FIELD_STRING, "LAST_2005",	"LAST_2005", NULL, 0 }
 };
 
 typedef struct _modify_info_request {
@@ -568,35 +569,53 @@
 }
 
 /* after getting info or modify myself, refresh the buddy list accordingly */
-static void qq_refresh_buddy_and_myself(gchar **segments, PurpleConnection *gc)
+static void qq_set_buddy_info(gchar **segments, PurpleConnection *gc)
 {
-	PurpleBuddy *b;
+	PurpleBuddy *purple_buddy;
 	qq_data *qd;
-	qq_buddy *q_bud;
+	guint32 uid;
+	qq_buddy *buddy;
 	gchar *alias_utf8;
 	gchar *purple_name;
 	PurpleAccount *account = purple_connection_get_account(gc);
 
 	qd = (qq_data *) gc->proto_data;
-	purple_name = uid_to_purple_name(strtol(segments[QQ_INFO_UID], NULL, 10));
+
+	uid = strtol(segments[QQ_INFO_UID], NULL, 10);
+	purple_name = uid_to_purple_name(uid);
 
 	alias_utf8 = qq_to_utf8(segments[QQ_INFO_NICK], QQ_CHARSET_DEFAULT);
 	if (qd->uid == strtol(segments[QQ_INFO_UID], NULL, 10)) {	/* it is me */
+		purple_debug_info("QQ", "Got my info\n");
 		qd->my_icon = strtol(segments[QQ_INFO_FACE], NULL, 10);
 		if (alias_utf8 != NULL)
 			purple_account_set_alias(account, alias_utf8);
+
+		/* add me to buddy list */
+		purple_buddy = purple_find_buddy(gc->account, purple_name);
+		if ( purple_buddy == NULL) {
+			purple_buddy = qq_create_buddy(gc, uid, TRUE, FALSE);
+		}
+		buddy = g_new0(qq_buddy, 1);
+		buddy->uid = uid;
+		buddy->status = QQ_BUDDY_ONLINE_NORMAL;
+		purple_buddy->proto_data = buddy;
+		qd->buddies = g_list_append(qd->buddies, buddy);
 	}
+
 	/* update buddy list (including myself, if myself is the buddy) */
-	b = purple_find_buddy(gc->account, purple_name);
-	q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
-	if (q_bud != NULL) {	/* I have this buddy */
-		q_bud->age = strtol(segments[QQ_INFO_AGE], NULL, 10);
-		q_bud->gender = strtol(segments[QQ_INFO_GENDER], NULL, 10);
-		q_bud->face = strtol(segments[QQ_INFO_FACE], NULL, 10);
+	purple_buddy = purple_find_buddy(gc->account, purple_name);
+	buddy = (purple_buddy == NULL) ? NULL : (qq_buddy *) purple_buddy->proto_data;
+	if (buddy != NULL) {	/* I have this buddy */
+		buddy->age = strtol(segments[QQ_INFO_AGE], NULL, 10);
+		buddy->gender = strtol(segments[QQ_INFO_GENDER], NULL, 10);
+		buddy->face = strtol(segments[QQ_INFO_FACE], NULL, 10);
 		if (alias_utf8 != NULL)
-			q_bud->nickname = g_strdup(alias_utf8);
-		qq_update_buddy_contact(gc, q_bud);
-		buddy_local_icon_upate(gc->account, purple_name, q_bud->face);
+			buddy->nickname = g_strdup(alias_utf8);
+		qq_update_buddy_contact(gc, buddy);
+		buddy_local_icon_upate(gc->account, purple_name, buddy->face);
+	} else {
+		purple_debug_info("QQ", "Can not find buddy data of %s\n", purple_name);
 	}
 	g_free(purple_name);
 	g_free(alias_utf8);
@@ -607,12 +626,18 @@
 {
 	qq_data *qd;
 	gchar **segments;
+	gint field_count;
 
 	g_return_if_fail(data != NULL && data_len != 0);
 
 	qd = (qq_data *) gc->proto_data;
 
-	if (NULL == (segments = split_data(data, data_len, "\x1e", QQ_INFO_LAST)))
+	if (qd->client_version >= 2008) {
+		field_count = QQ_INFO_LAST;
+	} else {
+		field_count = QQ_INFO_LAST_2007;
+	}
+	if (NULL == (segments = split_data(data, data_len, "\x1e", field_count)))
 		return;
 
 #ifdef DEBUG
@@ -627,13 +652,13 @@
 			segments[QQ_INFO_FACE] = icon;
 
 			request_modify_info(gc, segments);
-			qq_refresh_buddy_and_myself(segments, gc);
+			qq_set_buddy_info(segments, gc);
 		}
 		g_strfreev(segments);
 		return;
 	}
 
-	qq_refresh_buddy_and_myself(segments, gc);
+	qq_set_buddy_info(segments, gc);
 	switch (action) {
 		case QQ_BUDDY_INFO_DISPLAY:
 			info_display_only(gc, segments);
@@ -697,7 +722,7 @@
 	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);
@@ -721,7 +746,7 @@
 	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);
@@ -784,11 +809,11 @@
 	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) {
--- a/libpurple/protocols/qq/buddy_list.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/buddy_list.c	Wed Oct 22 14:48:46 2008 +0000
@@ -101,7 +101,7 @@
 	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);
 }
 
@@ -251,13 +251,13 @@
 guint16 qq_process_get_buddies_list_reply(guint8 *data, gint data_len, PurpleConnection *gc)
 {
 	qq_data *qd;
-	qq_buddy *q_bud;
+	qq_buddy *buddy;
 	gint bytes_expected, count;
 	gint bytes, buddy_bytes;
+	gint nickname_len;
 	guint16 position, unknown;
-	guint8 pascal_len;
-	gchar *name;
-	PurpleBuddy *b;
+	gchar *purple_name;
+	PurpleBuddy *purple_buddy;
 
 	g_return_val_if_fail(data != NULL && data_len != 0, -1);
 
@@ -273,40 +273,39 @@
 	/* the following data is buddy list in this packet */
 	count = 0;
 	while (bytes < data_len) {
-		q_bud = g_new0(qq_buddy, 1);
+		buddy = g_new0(qq_buddy, 1);
 		/* set flag */
 		buddy_bytes = bytes;
 		/* 000-003: uid */
-		bytes += qq_get32(&q_bud->uid, data + bytes);
+		bytes += qq_get32(&buddy->uid, data + bytes);
 		/* 004-005: icon index (1-255) */
-		bytes += qq_get16(&q_bud->face, data + bytes);
+		bytes += qq_get16(&buddy->face, data + bytes);
 		/* 006-006: age */
-		bytes += qq_get8(&q_bud->age, data + bytes);
+		bytes += qq_get8(&buddy->age, data + bytes);
 		/* 007-007: gender */
-		bytes += qq_get8(&q_bud->gender, data + bytes);
+		bytes += qq_get8(&buddy->gender, data + bytes);
 
-		pascal_len = convert_as_pascal_string(data + bytes, &q_bud->nickname, QQ_CHARSET_DEFAULT);
-		bytes += pascal_len;
-		qq_filter_str(q_bud->nickname);
+		nickname_len = qq_get_vstr(&buddy->nickname, QQ_CHARSET_DEFAULT, data + bytes);
+		bytes += nickname_len;
+		qq_filter_str(buddy->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);
-		
+		bytes += qq_get8(&buddy->ext_flag, data + bytes);
+		bytes += qq_get8(&buddy->comm_flag, data + bytes);
+
 		if (qd->client_version >= 2007) {
 			bytes += 4;		/* skip 4 bytes */
-			bytes_expected = 16 + pascal_len;
+			bytes_expected = 16 + nickname_len;
 		} else {
-			bytes_expected = 12 + pascal_len;
+			bytes_expected = 12 + nickname_len;
 		}
 
-
-		if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) {
+		if (buddy->uid == 0 || (bytes - buddy_bytes) != bytes_expected) {
 			purple_debug_info("QQ",
 					"Buddy entry, expect %d bytes, read %d bytes\n", bytes_expected, bytes - buddy_bytes);
-			g_free(q_bud->nickname);
-			g_free(q_bud);
+			g_free(buddy->nickname);
+			g_free(buddy);
 			continue;
 		} else {
 			count++;
@@ -314,20 +313,20 @@
 
 #if 1
 		purple_debug_info("QQ", "buddy [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n",
-				q_bud->uid, q_bud->ext_flag, q_bud->comm_flag, q_bud->nickname);
+				buddy->uid, buddy->ext_flag, buddy->comm_flag, buddy->nickname);
 #endif
 
-		name = uid_to_purple_name(q_bud->uid);
-		b = purple_find_buddy(gc->account, name);
-		g_free(name);
+		purple_name = uid_to_purple_name(buddy->uid);
+		purple_buddy = purple_find_buddy(gc->account, purple_name);
+		g_free(purple_name);
 
-		if (b == NULL) {
-			b = qq_create_buddy(gc, q_bud->uid, TRUE, FALSE);
+		if (purple_buddy == NULL) {
+			purple_buddy = qq_create_buddy(gc, buddy->uid, TRUE, FALSE);
 		}
 
-		b->proto_data = q_bud;
-		qd->buddies = g_list_append(qd->buddies, q_bud);
-		qq_update_buddy_contact(gc, q_bud);
+		purple_buddy->proto_data = buddy;
+		qd->buddies = g_list_append(qd->buddies, buddy);
+		qq_update_buddy_contact(gc, buddy);
 	}
 
 	if(bytes > data_len) {
@@ -361,7 +360,7 @@
 
 	bytes += qq_get8(&reply_code, data + bytes);
 	if(0 != reply_code) {
-		purple_debug_warning("QQ", "qq_process_get_buddies_and_rooms, %d", reply_code);
+		purple_debug_warning("QQ", "qq_process_get_buddies_and_rooms, %d\n", reply_code);
 	}
 
 	bytes += qq_get32(&unknown, data + bytes);
@@ -492,7 +491,7 @@
 	} 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)
--- a/libpurple/protocols/qq/buddy_opt.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/buddy_opt.c	Wed Oct 22 14:48:46 2008 +0000
@@ -346,7 +346,7 @@
 
 	uid = purple_name_to_uid(who);
 	g_return_if_fail(uid > 0);
-	
+
 	if (uid == qd->uid) {
 		return;
 	}
@@ -501,12 +501,13 @@
 
 /* we add new buddy, if the received packet is from someone not in my list
  * return the PurpleBuddy that is just created */
-PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create)
+PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid,
+		gboolean is_known, gboolean is_create_data)
 {
-	PurpleBuddy *buddy;
+	PurpleBuddy *purple_buddy;
 	PurpleGroup *group;
 	qq_data *qd;
-	qq_buddy *q_bud;
+	qq_buddy *buddy;
 	gchar *buddy_name, *group_name;
 
 	g_return_val_if_fail(gc->account != NULL && uid != 0, NULL);
@@ -522,13 +523,13 @@
 	group = qq_create_group(group_name);
 
 	buddy_name = uid_to_purple_name(uid);
-	buddy = purple_find_buddy(gc->account, buddy_name);
+	purple_buddy = purple_find_buddy(gc->account, buddy_name);
 	/* remove old, we can not simply return here
 	 * because there might be old local copy of this buddy */
-	if (buddy != NULL)
-		purple_blist_remove_buddy(buddy);
+	if (purple_buddy != NULL)
+		purple_blist_remove_buddy(purple_buddy);
 
-	buddy = purple_buddy_new(gc->account, buddy_name, NULL);
+	purple_buddy = purple_buddy_new(gc->account, buddy_name, NULL);
 	if ( !is_known) {
 		if (purple_privacy_check(gc->account, buddy_name)) {
 			purple_privacy_deny(gc->account, buddy_name, TRUE, FALSE);
@@ -537,29 +538,29 @@
 		}
 	}
 
-	if (!create)
-		buddy->proto_data = NULL;
+	if (!is_create_data)
+		purple_buddy->proto_data = NULL;
 	else {
-		q_bud = g_new0(qq_buddy, 1);
-		q_bud->uid = uid;
-		buddy->proto_data = q_bud;
-		qd->buddies = g_list_append(qd->buddies, q_bud);
-		qq_request_buddy_info(gc, qd->uid, 0, 0);
+		buddy = g_new0(qq_buddy, 1);
+		buddy->uid = uid;
+		purple_buddy->proto_data = buddy;
+		qd->buddies = g_list_append(qd->buddies, buddy);
+		qq_request_buddy_info(gc, uid, 0, 0);
 		qq_request_get_buddies_online(gc, 0, 0);
 		if (qd->client_version >= 2007) {
-			qq_request_get_level_2007(gc, q_bud->uid);
+			qq_request_get_level_2007(gc, uid);
 		} else {
-			qq_request_get_level(gc, q_bud->uid);
+			qq_request_get_level(gc, uid);
 		}
 	}
 
-	purple_blist_add_buddy(buddy, NULL, group, NULL);
+	purple_blist_add_buddy(purple_buddy, NULL, group, NULL);
 	purple_debug_warning("QQ", "Add new buddy: [%s]\n", buddy_name);
 
 	g_free(buddy_name);
 	g_free(group_name);
 
-	return buddy;
+	return purple_buddy;
 }
 
 qq_buddy *qq_get_buddy(PurpleConnection *gc, guint32 uid)
@@ -574,9 +575,9 @@
 	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);
+		purple_debug_error("QQ", "Can not find buddy data of %d\n", uid);
 		return NULL;
 	}
 	return (qq_buddy *) purple_buddy->proto_data;
--- a/libpurple/protocols/qq/buddy_opt.h	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/buddy_opt.h	Wed Oct 22 14:48:46 2008 +0000
@@ -36,7 +36,8 @@
 		const char *old_group, const char *new_group);
 void qq_remove_buddy_and_me(PurpleBlistNode * node);
 void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create);
+PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid,
+		gboolean is_known, gboolean is_create_data);
 void qq_buddies_list_free(PurpleAccount *account, qq_data *qd);
 
 void qq_process_buddy_remove(guint8 *buf, gint buf_len, PurpleConnection *gc);
--- a/libpurple/protocols/qq/char_conv.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/char_conv.c	Wed Oct 22 14:48:46 2008 +0000
@@ -98,7 +98,7 @@
 }
 
 /* convert a string from from_charset to to_charset, using g_convert */
-static gchar *_my_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset)
+static gchar *do_convert(const gchar *str, gssize len, const gchar *to_charset, const gchar *from_charset)
 {
 	GError *error = NULL;
 	gchar *ret;
@@ -128,14 +128,18 @@
  * returns the number of bytes read, return -1 if fatal error
  * the converted UTF-8 will be saved in ret
  */
-gint convert_as_pascal_string(guint8 *data, gchar **ret, const gchar *from_charset)
+gint qq_get_vstr(gchar **ret, const gchar *from_charset, guint8 *data)
 {
 	guint8 len;
 
 	g_return_val_if_fail(data != NULL && from_charset != NULL, -1);
 
 	len = data[0];
-	*ret = _my_convert((gchar *) (data + 1), (gssize) len, UTF8, from_charset);
+	if (len == 0) {
+		*ret = g_strdup("");
+		return 1;
+	}
+	*ret = do_convert((gchar *) (data + 1), (gssize) len, UTF8, from_charset);
 
 	return len + 1;
 }
@@ -214,15 +218,15 @@
 	return ret;
 }
 
-/* two convenience methods, using _my_convert */
+/* two convenience methods, using do_convert */
 gchar *utf8_to_qq(const gchar *str, const gchar *to_charset)
 {
-	return _my_convert(str, -1, to_charset, UTF8);
+	return do_convert(str, -1, to_charset, UTF8);
 }
 
 gchar *qq_to_utf8(const gchar *str, const gchar *from_charset)
 {
-	return _my_convert(str, -1, UTF8, from_charset);
+	return do_convert(str, -1, UTF8, from_charset);
 }
 
 /* QQ uses binary code for smiley, while purple uses strings.
--- a/libpurple/protocols/qq/char_conv.h	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/char_conv.h	Wed Oct 22 14:48:46 2008 +0000
@@ -29,7 +29,7 @@
 
 #define QQ_CHARSET_DEFAULT      "GB18030"
 
-gint convert_as_pascal_string(guint8 *data, gchar **ret, const gchar *from_charset);
+gint qq_get_vstr(gchar **ret, const gchar *from_charset, guint8 *data);
 
 gchar *qq_smiley_to_purple(gchar *text);
 gchar *purple_smiley_to_qq(gchar *text);
--- a/libpurple/protocols/qq/group_conv.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/group_conv.c	Wed Oct 22 14:48:46 2008 +0000
@@ -74,55 +74,64 @@
 	gchar *member_name, *member_uid;
 	PurpleConversation *conv;
 	gint flag;
+	gboolean is_find;
 	g_return_if_fail(group != NULL);
 
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
+			group->title_utf8, purple_connection_get_account(gc));
+
+	g_return_if_fail (conv != NULL && group->members != NULL);
+
 	names = NULL;
 	flags = NULL;
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
-			group->title_utf8, purple_connection_get_account(gc));
-	if (conv != NULL && group->members != NULL) {
-		list = group->members;
-		while (list != NULL) {
-			member = (qq_buddy *) list->data;
+
+	list = group->members;
+	while (list != NULL) {
+		member = (qq_buddy *) list->data;
 
-			/* we need unique identifiers for everyone in the chat or else we'll
-			 * run into problems with functions like get_cb_real_name from qq.c */
-			member_name =   (member->nickname != NULL && *(member->nickname) != '\0') ?
-					g_strdup_printf("%s (%u)", member->nickname, member->uid) :
-					g_strdup_printf("(%u)", member->uid);
-			member_uid = g_strdup_printf("(%u)", member->uid);
+		/* we need unique identifiers for everyone in the chat or else we'll
+		 * run into problems with functions like get_cb_real_name from qq.c */
+		member_name =   (member->nickname != NULL && *(member->nickname) != '\0') ?
+				g_strdup_printf("%s (%u)", member->nickname, member->uid) :
+				g_strdup_printf("(%u)", member->uid);
+		member_uid = g_strdup_printf("(%u)", member->uid);
 
-			flag = 0;
-			/* TYPING to put online above OP and FOUNDER */
-			if (is_online(member->status))
-				flag |= (PURPLE_CBFLAGS_TYPING | PURPLE_CBFLAGS_VOICE);
-			if(1 == (member->role & 1)) flag |= PURPLE_CBFLAGS_OP;
-			if(member->uid == group->creator_uid) flag |= PURPLE_CBFLAGS_FOUNDER;
+		flag = 0;
+		/* TYPING to put online above OP and FOUNDER */
+		if (is_online(member->status)) flag |= (PURPLE_CBFLAGS_TYPING | PURPLE_CBFLAGS_VOICE);
+		if(1 == (member->role & 1)) flag |= PURPLE_CBFLAGS_OP;
+		if(member->uid == group->creator_uid) flag |= PURPLE_CBFLAGS_FOUNDER;
 
-			if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_name))
-			{
-				purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(conv),
-						member_name,
-						flag);
-			} else if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_uid))
-			{
-				purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(conv),
-						member_uid,
-						flag);
-				purple_conv_chat_rename_user(PURPLE_CONV_CHAT(conv), member_uid, member_name);
-			} else {
-				/* always put it even offline */
-				names = g_list_append(names, member_name);
-				flags = g_list_append(flags, GINT_TO_POINTER(flag));
-			}
-			g_free(member_uid);
-			list = list->next;
+		is_find = TRUE;
+		if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_name))
+		{
+			purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(conv),
+					member_name,
+					flag);
+		} else if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_uid))
+		{
+			purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(conv),
+					member_uid,
+					flag);
+			purple_conv_chat_rename_user(PURPLE_CONV_CHAT(conv), member_uid, member_name);
+		} else {
+			is_find = FALSE;
 		}
+		if (!is_find) {
+			/* always put it even offline */
+			names = g_list_append(names, member_name);
+			flags = g_list_append(flags, GINT_TO_POINTER(flag));
+		} else {
+			g_free(member_name);
+		}
+		g_free(member_uid);
+		list = list->next;
+	}
 
-		if (names != NULL && flags != NULL) {
-			purple_conv_chat_add_users(PURPLE_CONV_CHAT(conv), names, NULL, flags, FALSE);
-		}
+	if (names != NULL && flags != NULL) {
+		purple_conv_chat_add_users(PURPLE_CONV_CHAT(conv), names, NULL, flags, FALSE);
 	}
+
 	/* clean up names */
 	while (names != NULL) {
 		member_name = (gchar *) names->data;
--- a/libpurple/protocols/qq/group_im.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/group_im.c	Wed Oct 22 14:48:46 2008 +0000
@@ -107,7 +107,7 @@
 
 	g_return_if_fail(ext_id > 0 && user_uid > 0);
 
-	bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT);
+	bytes += qq_get_vstr(&reason_utf8, QQ_CHARSET_DEFAULT, data + bytes);
 
 	msg = g_strdup_printf(_("%d request to join Qun %d"), user_uid, ext_id);
 	reason = g_strdup_printf(_("Message: %s"), reason_utf8);
@@ -161,7 +161,7 @@
 	if (uid_from != 0) {
 		buddy = qq_group_find_member_by_uid(group, uid_from);
 		if (buddy == NULL || buddy->nickname == NULL)
-			from = uid_to_purple_name(uid_from);
+			from = g_strdup_printf("%d", uid_from);
 		else
 			from = g_strdup(buddy->nickname);
 	} else {
@@ -192,7 +192,7 @@
 
 	g_return_if_fail(ext_id > 0 && admin_uid > 0);
 
-	bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT);
+	bytes += qq_get_vstr(&reason_utf8, QQ_CHARSET_DEFAULT, data + bytes);
 
 	msg = g_strdup_printf
 		(_("Failed to join Qun %d, operated by admin %d"), ext_id, admin_uid);
@@ -231,7 +231,7 @@
 
 	g_return_if_fail(ext_id > 0 && admin_uid > 0);
 	/* it is also a "无" here, so do not display */
-	bytes += convert_as_pascal_string(data + bytes, &reason, QQ_CHARSET_DEFAULT);
+	bytes += qq_get_vstr(&reason, QQ_CHARSET_DEFAULT, data + bytes);
 
 	group = qq_room_search_id(gc, id);
 	if (group != NULL) {
@@ -317,7 +317,7 @@
 }
 
 /* recv an IM from a group chat */
-void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type)
+void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type)
 {
 	gchar *msg_with_purple_smiley, *msg_utf8_encoded;
 	qq_data *qd;
@@ -353,7 +353,7 @@
 	bytes += qq_get32(&(packet.ext_id), data + bytes);
 	bytes += qq_get8(&(packet.type8), data + bytes);
 
-	if(QQ_RECV_IM_TEMP_QUN_IM == im_type) {
+	if(QQ_MSG_TEMP_QUN_IM == msg_type) {
 		bytes += qq_get32(&(id), data + bytes);
 	}
 
@@ -384,7 +384,7 @@
 	 *    buf.getInt();
 	 */
 
-	if(im_type != QQ_RECV_IM_UNKNOWN_QUN_IM)
+	if(msg_type != QQ_MSG_UNKNOWN_QUN_IM)
 		skip_len = 10;
 	else
 		skip_len = 0;
--- a/libpurple/protocols/qq/group_im.h	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/group_im.h	Wed Oct 22 14:48:46 2008 +0000
@@ -36,7 +36,7 @@
 
 void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc);
 
-void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type);
+void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 msg_type);
 
 void qq_process_room_msg_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc);
 
--- a/libpurple/protocols/qq/group_info.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/group_info.c	Wed Oct 22 14:48:46 2008 +0000
@@ -157,7 +157,7 @@
 	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);
@@ -197,10 +197,10 @@
 	}
 	/* 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_get_vstr(&(group->title_utf8), QQ_CHARSET_DEFAULT, data + bytes);
 	bytes += qq_get16(&unknown, data + bytes);	/* 0x0000 */
-	bytes += convert_as_pascal_string(data + bytes, &notice, QQ_CHARSET_DEFAULT);
-	bytes += convert_as_pascal_string(data + bytes, &(group->desc_utf8), QQ_CHARSET_DEFAULT);
+	bytes += qq_get_vstr(&notice, QQ_CHARSET_DEFAULT, data + bytes);
+	bytes += qq_get_vstr(&(group->desc_utf8), QQ_CHARSET_DEFAULT, data + bytes);
 
 	purple_debug_info("QQ", "room [%s] notice [%s] desc [%s] unknow 0x%04X\n",
 			group->title_utf8, notice, group->desc_utf8, unknown);
@@ -336,7 +336,7 @@
 		bytes += qq_get16(&(member->face), data + bytes);
 		bytes += qq_get8(&(member->age), data + bytes);
 		bytes += qq_get8(&(member->gender), data + bytes);
-		bytes += convert_as_pascal_string(data + bytes, &nick, QQ_CHARSET_DEFAULT);
+		bytes += qq_get_vstr(&nick, QQ_CHARSET_DEFAULT, data + bytes);
 		bytes += qq_get16(&unknown, data + bytes);
 		bytes += qq_get8(&(member->ext_flag), data + bytes);
 		bytes += qq_get8(&(member->comm_flag), data + bytes);
--- a/libpurple/protocols/qq/group_search.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/group_search.c	Wed Oct 22 14:48:46 2008 +0000
@@ -110,10 +110,10 @@
 	bytes += qq_get16(&(unknown), data + bytes);
 	bytes += qq_get16(&(unknown), data + bytes);
 	bytes += qq_get32(&(group.category), data + bytes);
-	bytes += convert_as_pascal_string(data + bytes, &(group.title_utf8), QQ_CHARSET_DEFAULT);
+	bytes += qq_get_vstr(&(group.title_utf8), QQ_CHARSET_DEFAULT, data + bytes);
 	bytes += qq_get16(&(unknown), data + bytes);
 	bytes += qq_get8(&(group.auth_type), data + bytes);
-	bytes += convert_as_pascal_string(data + bytes, &(group.desc_utf8), QQ_CHARSET_DEFAULT);
+	bytes += qq_get_vstr(&(group.desc_utf8), QQ_CHARSET_DEFAULT, data + bytes);
 	/* end of one qq_group */
 	if(bytes != len) {
 		purple_debug_error("QQ",
--- a/libpurple/protocols/qq/im.h	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/im.h	Wed Oct 22 14:48:46 2008 +0000
@@ -39,21 +39,22 @@
 };
 
 enum {
-	QQ_RECV_IM_TO_BUDDY = 0x0009,
-	QQ_RECV_IM_TO_UNKNOWN = 0x000a,
-	QQ_RECV_IM_NEWS = 0x0018,
-	QQ_RECV_IM_UNKNOWN_QUN_IM = 0x0020,
-	QQ_RECV_IM_ADD_TO_QUN = 0x0021,
-	QQ_RECV_IM_DEL_FROM_QUN = 0x0022,
-	QQ_RECV_IM_APPLY_ADD_TO_QUN = 0x0023,
-	QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN = 0x0024,
-	QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN = 0x0025,
-	QQ_RECV_IM_CREATE_QUN = 0x0026,
-	QQ_RECV_IM_TEMP_QUN_IM = 0x002A,
-	QQ_RECV_IM_QUN_IM = 0x002B,
-	QQ_RECV_IM_SYS_NOTIFICATION = 0x0030,
-	QQ_RECV_IM_EXTEND = 0x0084,
-	QQ_RECV_IM_EXTEND_85 = 0x0085,
+	QQ_MSG_TO_BUDDY = 0x0009,
+	QQ_MSG_TO_UNKNOWN = 0x000a,
+	QQ_MSG_NEWS = 0x0018,
+	QQ_MSG_UNKNOWN_QUN_IM = 0x0020,
+	QQ_MSG_ADD_TO_QUN = 0x0021,
+	QQ_MSG_DEL_FROM_QUN = 0x0022,
+	QQ_MSG_APPLY_ADD_TO_QUN = 0x0023,
+	QQ_MSG_APPROVE_APPLY_ADD_TO_QUN = 0x0024,
+	QQ_MSG_REJCT_APPLY_ADD_TO_QUN = 0x0025,
+	QQ_MSG_CREATE_QUN = 0x0026,
+	QQ_MSG_TEMP_QUN_IM = 0x002A,
+	QQ_MSG_QUN_IM = 0x002B,
+	QQ_MSG_SYS_30 = 0x0030,
+	QQ_MSG_SYS_4C = 0x004C,
+	QQ_MSG_EXTEND = 0x0084,
+	QQ_MSG_EXTEND_85 = 0x0085,
 };
 
 void qq_got_attention(PurpleConnection *gc, const gchar *msg);
--- a/libpurple/protocols/qq/qq_process.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/qq_process.c	Wed Oct 22 14:48:46 2008 +0000
@@ -95,7 +95,7 @@
 		purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL);
 		return;
 	}
-	
+
 	purple_debug_info("QQ", "OK sent IM\n");
 }
 
@@ -148,8 +148,7 @@
 	g_free(content_utf8);
 }
 
-/* process im from system administrator */
-static void do_server_im(guint8 *data, gint data_len, PurpleConnection *gc)
+static void do_msg_sys_30(PurpleConnection *gc, guint8 *data, gint data_len)
 {
 	gint len;
 	guint8 reply;
@@ -165,46 +164,79 @@
 	reply = strtol(segments[0], NULL, 10);
 	if (reply == 1)
 		purple_debug_warning("QQ", "We are kicked out by QQ server\n");
-		
+
 	msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT);
-	purple_notify_warning(gc, NULL, _("System Message"), msg_utf8);
+	qq_got_attention(gc, msg_utf8);
+}
+
+static void do_msg_sys_4c(PurpleConnection *gc, guint8 *data, gint data_len)
+{
+	gint bytes;
+	gint msg_len;
+	GString *content;
+	gchar *msg = NULL;
+
+	g_return_if_fail(data != NULL && data_len > 0);
+
+	bytes = 6; /* skip 0x(06 00 01 1e 01 1c)*/
+
+	content = g_string_new("");
+	while (bytes < data_len) {
+		msg_len = qq_get_vstr(&msg, QQ_CHARSET_DEFAULT, data + bytes);
+		g_string_append(content, msg);
+		g_string_append(content, "\n");
+		g_free(msg);
+
+		if (msg_len <= 1) {
+			break;
+		}
+		bytes += msg_len;
+	}
+	if (bytes != data_len) {
+		purple_debug_warning("QQ", "Failed to read QQ_MSG_SYS_4C\n");
+		qq_show_packet("do_msg_sys_4c", data, data_len);
+	}
+	qq_got_attention(gc, content->str);
+	g_string_free(content, FALSE);
 }
 
 static const gchar *get_im_type_desc(gint type)
 {
 	switch (type) {
-		case QQ_RECV_IM_TO_BUDDY:
-			return "QQ_RECV_IM_TO_BUDDY";
-		case QQ_RECV_IM_TO_UNKNOWN:
-			return "QQ_RECV_IM_TO_UNKNOWN";
-		case QQ_RECV_IM_UNKNOWN_QUN_IM:
-			return "QQ_RECV_IM_UNKNOWN_QUN_IM";
-		case QQ_RECV_IM_ADD_TO_QUN:
-			return "QQ_RECV_IM_ADD_TO_QUN";
-		case QQ_RECV_IM_DEL_FROM_QUN:
-			return "QQ_RECV_IM_DEL_FROM_QUN";
-		case QQ_RECV_IM_APPLY_ADD_TO_QUN:
-			return "QQ_RECV_IM_APPLY_ADD_TO_QUN";
-		case QQ_RECV_IM_CREATE_QUN:
-			return "QQ_RECV_IM_CREATE_QUN";
-		case QQ_RECV_IM_SYS_NOTIFICATION:
-			return "QQ_RECV_IM_SYS_NOTIFICATION";
-		case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN:
-			return "QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN";
-		case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN:
-			return "QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN";
-		case QQ_RECV_IM_TEMP_QUN_IM:
-			return "QQ_RECV_IM_TEMP_QUN_IM";
-		case QQ_RECV_IM_QUN_IM:
-			return "QQ_RECV_IM_QUN_IM";
-		case QQ_RECV_IM_NEWS:
-			return "QQ_RECV_IM_NEWS";
-		case QQ_RECV_IM_EXTEND:
-			return "QQ_RECV_IM_EXTEND";
-		case QQ_RECV_IM_EXTEND_85:
-			return "QQ_RECV_IM_EXTEND_85";
+		case QQ_MSG_TO_BUDDY:
+			return "QQ_MSG_TO_BUDDY";
+		case QQ_MSG_TO_UNKNOWN:
+			return "QQ_MSG_TO_UNKNOWN";
+		case QQ_MSG_UNKNOWN_QUN_IM:
+			return "QQ_MSG_UNKNOWN_QUN_IM";
+		case QQ_MSG_ADD_TO_QUN:
+			return "QQ_MSG_ADD_TO_QUN";
+		case QQ_MSG_DEL_FROM_QUN:
+			return "QQ_MSG_DEL_FROM_QUN";
+		case QQ_MSG_APPLY_ADD_TO_QUN:
+			return "QQ_MSG_APPLY_ADD_TO_QUN";
+		case QQ_MSG_CREATE_QUN:
+			return "QQ_MSG_CREATE_QUN";
+		case QQ_MSG_SYS_30:
+			return "QQ_MSG_SYS_30";
+		case QQ_MSG_SYS_4C:
+			return "QQ_MSG_SYS_4C";
+		case QQ_MSG_APPROVE_APPLY_ADD_TO_QUN:
+			return "QQ_MSG_APPROVE_APPLY_ADD_TO_QUN";
+		case QQ_MSG_REJCT_APPLY_ADD_TO_QUN:
+			return "QQ_MSG_REJCT_APPLY_ADD_TO_QUN";
+		case QQ_MSG_TEMP_QUN_IM:
+			return "QQ_MSG_TEMP_QUN_IM";
+		case QQ_MSG_QUN_IM:
+			return "QQ_MSG_QUN_IM";
+		case QQ_MSG_NEWS:
+			return "QQ_MSG_NEWS";
+		case QQ_MSG_EXTEND:
+			return "QQ_MSG_EXTEND";
+		case QQ_MSG_EXTEND_85:
+			return "QQ_MSG_EXTEND_85";
 		default:
-			return "QQ_RECV_IM_UNKNOWN";
+			return "QQ_MSG_UNKNOWN";
 	}
 }
 
@@ -221,7 +253,7 @@
 		guint32 seq;
 		struct in_addr ip_from;
 		guint16 port_from;
-		guint16 im_type;
+		guint16 msg_type;
 	} header;
 
 	g_return_if_fail(data != NULL && data_len != 0);
@@ -250,7 +282,7 @@
 	/* if the message is delivered via server, it is server IP/port */
 	bytes += qq_getIP(&(header.ip_from), data + bytes);
 	bytes += qq_get16(&(header.port_from), data + bytes);
-	bytes += qq_get16(&(header.im_type), data + bytes);
+	bytes += qq_get16(&(header.msg_type), data + bytes);
 	/* im_header prepared */
 
 	if (header.uid_to != qd->uid) {	/* should not happen */
@@ -264,63 +296,63 @@
 		return;
 	}
 
-	switch (header.im_type) {
-		case QQ_RECV_IM_NEWS:
+	switch (header.msg_type) {
+		case QQ_MSG_NEWS:
 			do_server_news(data + bytes, data_len - bytes, gc);
 			break;
-		case QQ_RECV_IM_EXTEND:
-		case QQ_RECV_IM_EXTEND_85:
+		case QQ_MSG_EXTEND:
+		case QQ_MSG_EXTEND_85:
 			purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from);
 			qq_process_extend_im(gc, data + bytes, data_len - bytes);
 			break;
-		case QQ_RECV_IM_TO_UNKNOWN:
-		case QQ_RECV_IM_TO_BUDDY:
+		case QQ_MSG_TO_UNKNOWN:
+		case QQ_MSG_TO_BUDDY:
 			purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from);
 			qq_process_im(gc, data + bytes, data_len - bytes);
 			break;
-		case QQ_RECV_IM_UNKNOWN_QUN_IM:
-		case QQ_RECV_IM_TEMP_QUN_IM:
-		case QQ_RECV_IM_QUN_IM:
+		case QQ_MSG_UNKNOWN_QUN_IM:
+		case QQ_MSG_TEMP_QUN_IM:
+		case QQ_MSG_QUN_IM:
 			purple_debug_info("QQ", "MSG from room [%d]\n", header.uid_from);
-			/* uid_from is in fact id */
-			qq_process_room_msg_normal(data + bytes, data_len - bytes, header.uid_from, gc, header.im_type);
+			qq_process_room_msg_normal(data + bytes, data_len - bytes, header.uid_from, gc, header.msg_type);
 			break;
-		case QQ_RECV_IM_ADD_TO_QUN:
+		case QQ_MSG_ADD_TO_QUN:
 			purple_debug_info("QQ", "Notice from [%d], Added\n", header.uid_from);
 			/* uid_from is group id
 			 * we need this to create a dummy group and add to blist */
 			qq_process_room_msg_been_added(data + bytes, data_len - bytes, header.uid_from, gc);
 			break;
-		case QQ_RECV_IM_DEL_FROM_QUN:
+		case QQ_MSG_DEL_FROM_QUN:
 			purple_debug_info("QQ", "Notice from room [%d], Removed\n", header.uid_from);
 			/* uid_from is group id */
 			qq_process_room_msg_been_removed(data + bytes, data_len - bytes, header.uid_from, gc);
 			break;
-		case QQ_RECV_IM_APPLY_ADD_TO_QUN:
+		case QQ_MSG_APPLY_ADD_TO_QUN:
 			purple_debug_info("QQ", "Notice from room [%d], Joined\n", header.uid_from);
 			/* uid_from is group id */
 			qq_process_room_msg_apply_join(data + bytes, data_len - bytes, header.uid_from, gc);
 			break;
-		case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN:
+		case QQ_MSG_APPROVE_APPLY_ADD_TO_QUN:
 			purple_debug_info("QQ", "Notice from room [%d], Confirm add in\n",
 					header.uid_from);
 			/* uid_from is group id */
 			qq_process_room_msg_been_approved(data + bytes, data_len - bytes, header.uid_from, gc);
 			break;
-		case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN:
+		case QQ_MSG_REJCT_APPLY_ADD_TO_QUN:
 			purple_debug_info("QQ", "Notice from room [%d], Refuse add in\n",
 					header.uid_from);
 			/* uid_from is group id */
 			qq_process_room_msg_been_rejected(data + bytes, data_len - bytes, header.uid_from, gc);
 			break;
-		case QQ_RECV_IM_SYS_NOTIFICATION:
-			purple_debug_info("QQ", "Admin notice from [%d]\n", header.uid_from);
-			do_server_im(data + bytes, data_len - bytes, gc);
+		case QQ_MSG_SYS_30:
+			do_msg_sys_30(gc, data + bytes, data_len - bytes);
+			break;
+		case QQ_MSG_SYS_4C:
+			do_msg_sys_4c(gc, data + bytes, data_len - bytes);
 			break;
 		default:
-			purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%02x]\n",
-					header.uid_from, get_im_type_desc(header.im_type),
-					header.im_type);
+			purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%04X]\n",
+					header.uid_from, get_im_type_desc(header.msg_type), header.msg_type);
 			qq_show_packet("Unknown MSG type", data, data_len);
 			break;
 	}
--- a/libpurple/protocols/qq/utils.c	Wed Oct 22 14:47:39 2008 +0000
+++ b/libpurple/protocols/qq/utils.c	Wed Oct 22 14:48:46 2008 +0000
@@ -104,7 +104,7 @@
 {
 	guint8 *input;
 	gchar **segments;
-	gint i, j;
+	gint count, j;
 
 	g_return_val_if_fail(data != NULL && len != 0 && delimit != 0, NULL);
 
@@ -118,22 +118,18 @@
 	if (expected_fields <= 0)
 		return segments;
 
-	for (i = 0; segments[i] != NULL; i++) {;
+	for (count = 0; segments[count] != NULL; count++) {;
 	}
-	if (i < expected_fields) {	/* not enough fields */
-		purple_debug_error("QQ", "Invalid data, expect %d fields, found only %d, discard\n",
-				expected_fields, i);
-		g_strfreev(segments);
+	if (count < expected_fields) {	/* not enough fields */
+		purple_debug_error("QQ", "Less fields %d then %d\n", count, expected_fields);
 		return NULL;
-	} else if (i > expected_fields) {	/* more fields, OK */
-		purple_debug_warning("QQ", "Dangerous data, expect %d fields, found %d, return all\n",
-				expected_fields, i);
+	} else if (count > expected_fields) {	/* more fields, OK */
+		purple_debug_warning("QQ", "More fields %d than %d\n", count, expected_fields);
 		/* free up those not used */
-		for (j = expected_fields; j < i; j++) {
+		for (j = expected_fields; j < count; j++) {
 			purple_debug_warning("QQ", "field[%d] is %s\n", j, segments[j]);
 			g_free(segments[j]);
 		}
-
 		segments[expected_fields] = NULL;
 	}
 
@@ -197,7 +193,7 @@
 	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;