pidgin.openq: ec4e796b: 2008.10.09 - ccpaging <ccpaging(at)gmail...

csyfek at gmail.com csyfek at gmail.com
Tue Oct 28 12:56:05 EDT 2008


-----------------------------------------------------------------
Revision: ec4e796b19f15f587ef3135f3f0c4da116d165e6
Ancestor: 5232f2ceb214e2a461afaae2dc613de5b4dc27cf
Author: csyfek at gmail.com
Date: 2008-10-28T16:38:16
Branch: im.pidgin.pidgin.openq
URL: http://d.pidgin.im/viewmtn/revision/info/ec4e796b19f15f587ef3135f3f0c4da116d165e6

Deleted entries:
        libpurple/protocols/qq/group_find.c
        libpurple/protocols/qq/group_find.h
        libpurple/protocols/qq/group_free.c
        libpurple/protocols/qq/group_free.h
        libpurple/protocols/qq/group_search.c
        libpurple/protocols/qq/group_search.h
Modified files:
        libpurple/protocols/qq/ChangeLog
        libpurple/protocols/qq/Makefile.am
        libpurple/protocols/qq/Makefile.mingw
        libpurple/protocols/qq/buddy_list.c
        libpurple/protocols/qq/group.c
        libpurple/protocols/qq/group.h
        libpurple/protocols/qq/group_im.c
        libpurple/protocols/qq/group_im.h
        libpurple/protocols/qq/group_info.c
        libpurple/protocols/qq/group_info.h
        libpurple/protocols/qq/group_internal.c
        libpurple/protocols/qq/group_internal.h
        libpurple/protocols/qq/group_join.c
        libpurple/protocols/qq/group_join.h
        libpurple/protocols/qq/group_opt.c
        libpurple/protocols/qq/group_opt.h
        libpurple/protocols/qq/qq.c
        libpurple/protocols/qq/qq_network.c
        libpurple/protocols/qq/qq_process.c

ChangeLog: 

2008.10.09 - ccpaging <ccpaging(at)gmail.com>
	* Update 'group' protocol
	* Functions of group_find, group_free, group_search merged into group_join and group_internal
	* Removed group_find.c/h, group_free.c/h, group_search.c/h

-------------- next part --------------
============================================================
--- libpurple/protocols/qq/ChangeLog	e2761b8cf01f1fbd7e0f1933b524fe39ec26d271
+++ libpurple/protocols/qq/ChangeLog	3b44a7e63becabc8b1db2dfb75b203e7fc36e826
@@ -1,3 +1,8 @@
+2008.10.09 - ccpaging <ccpaging(at)gmail.com>
+	* Update 'group' protocol
+	* Functions of group_find, group_free, group_search merged into group_join and group_internal 
+	* Removed group_find.c/h, group_free.c/h, group_search.c/h 
+
 2008.10.08 - ccpaging <ccpaging(at)gmail.com>
 	* Update 'group' protocol
 
============================================================
--- libpurple/protocols/qq/Makefile.am	a1dd9472927a1f3089b9ed4ecc3c47c6cfe0c584
+++ libpurple/protocols/qq/Makefile.am	4804c7503cd191513a246fcaca736b0f35372128
@@ -18,10 +18,6 @@ QQSOURCES = \
 	file_trans.h \
 	group.c \
 	group.h \
-	group_find.c \
-	group_find.h \
-	group_free.c \
-	group_free.h \
 	group_internal.c \
 	group_internal.h \
 	group_im.c \
@@ -32,8 +28,6 @@ QQSOURCES = \
 	group_join.h \
 	group_opt.c \
 	group_opt.h \
-	group_search.c \
-	group_search.h \
 	qq_define.c \
 	qq_define.h \
 	im.c \
============================================================
--- libpurple/protocols/qq/Makefile.mingw	363f7a6d01be9b7394fe77208737543b77e71593
+++ libpurple/protocols/qq/Makefile.mingw	23335c2ce20665a4e3b70375ddc43762ee4a301d
@@ -50,14 +50,11 @@ C_SRC = \
 	qq_crypt.c \
 	file_trans.c \
 	group.c \
-	group_find.c \
-	group_free.c \
 	group_internal.c \
 	group_im.c \
 	group_info.c \
 	group_join.c \
 	group_opt.c \
-	group_search.c \
 	qq_define.c \
 	im.c \
 	packet_parse.c \
============================================================
--- libpurple/protocols/qq/buddy_list.c	d568b55591339363a57d935b1985a02c812d6b9f
+++ libpurple/protocols/qq/buddy_list.c	12c9d165d2fbead6e9895f8cfb6a88d4f2613f30
@@ -37,7 +37,6 @@
 #include "qq_define.h"
 #include "qq_base.h"
 #include "group.h"
-#include "group_find.h"
 #include "group_internal.h"
 #include "group_info.h"
 
@@ -236,13 +235,15 @@ guint8 qq_process_get_buddies_online(gui
 		if(0 != fe->s->client_tag)
 			q_bud->client_tag = fe->s->client_tag;
 		*/
+		if (bd->status != bs.status || bd->comm_flag != packet.comm_flag) {
+			bd->status = bs.status;
+			bd->comm_flag = packet.comm_flag;
+			qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
+		}
 		bd->ip.s_addr = bs.ip.s_addr;
 		bd->port = bs.port;
-		bd->status = bs.status;
 		bd->ext_flag = packet.ext_flag;
-		bd->comm_flag = packet.comm_flag;
 		bd->last_update = time(NULL);
-		qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
 		count++;
 	}
 
@@ -358,7 +359,7 @@ guint32 qq_process_get_buddies_and_rooms
 	guint32 unknown, position;
 	guint32 uid;
 	guint8 type;
-	qq_group *group;
+	qq_room_data *rmd;
 
 	g_return_val_if_fail(data != NULL && data_len != 0, -1);
 
@@ -394,15 +395,12 @@ guint32 qq_process_get_buddies_and_rooms
 			 * qq_request_get_buddies */
 			++i;
 		} else { /* a group */
-			group = qq_room_search_id(gc, uid);
-			if(group == NULL) {
-				purple_debug_info("QQ",
-					"Not find room id %d in qq_process_get_buddies_and_rooms\n", uid);
-				qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, uid, NULL, 0,
-						0, QQ_ROOM_INFO_CREATE);
+			rmd = qq_room_data_find(gc, uid);
+			if(rmd == NULL) {
+				purple_debug_info("QQ", "Unknow room id %d", uid);
+				qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, uid);
 			} else {
-				group->my_role = QQ_ROOM_ROLE_YES;
-				qq_group_refresh(gc, group);
+				rmd->my_role = QQ_ROOM_ROLE_YES;
 			}
 			++j;
 		}
@@ -561,10 +559,11 @@ void qq_process_buddy_change_status(guin
 		bd->ip.s_addr = bs.ip.s_addr;
 		bd->port = bs.port;
 	}
-	bd->status =bs.status;
-
+	if (bd->status != bs.status) {
+		bd->status = bs.status;
+		qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
+	}
 	bd->last_update = time(NULL);
-	qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
 
 	if (bd->status == QQ_BUDDY_ONLINE_NORMAL && bd->level <= 0) {
 		if (qd->client_version >= 2007) {
@@ -649,6 +648,7 @@ void qq_update_buddyies_status(PurpleCon
 		if (bd->uid == qd->uid) continue;	/* my status is always online in my buddy list */
 		if (tm_limit < bd->last_update) continue;
 		if (bd->status == QQ_BUDDY_ONLINE_INVISIBLE) continue;
+		if (bd->status == QQ_BUDDY_CHANGE_TO_OFFLINE) continue;
 
 		bd->status = QQ_BUDDY_CHANGE_TO_OFFLINE;
 		bd->last_update = time(NULL);
============================================================
--- libpurple/protocols/qq/group.c	ae31aa68f560579659162480b64be92b29ac9398
+++ libpurple/protocols/qq/group.c	a5d2231dd96fd0d910dee9ab97c6254a51f7d8d3
@@ -30,11 +30,10 @@
 
 #include "group_internal.h"
 #include "group_info.h"
-#include "group_search.h"
+#include "group_join.h"
 #include "utils.h"
 #include "qq_network.h"
 #include "qq_define.h"
-#include "group_free.h"
 
 static void _qq_group_search_callback(PurpleConnection *gc, const gchar *input)
 {
@@ -130,44 +129,3 @@ void qq_roomlist_cancel(PurpleRoomlist *
 	purple_roomlist_set_in_progress(list, FALSE);
 	purple_roomlist_unref(list);
 }
-
-/* this should be called upon signin, even when we did not open group chat window */
-void qq_group_init(PurpleConnection *gc)
-{
-	PurpleAccount *account;
-	PurpleChat *chat;
-	PurpleGroup *purple_group;
-	PurpleBlistNode *node;
-	qq_group *group;
-	gint count;
-
-	account = purple_connection_get_account(gc);
-
-	purple_debug_info("QQ", "Initial QQ Qun configurations\n");
-	purple_group = purple_find_group(PURPLE_GROUP_QQ_QUN);
-	if (purple_group == NULL) {
-		purple_debug_info("QQ", "We have no QQ Qun\n");
-		return;
-	}
-
-	count = 0;
-	for (node = ((PurpleBlistNode *) purple_group)->child; node != NULL; node = node->next) {
-		if ( !PURPLE_BLIST_NODE_IS_CHAT(node)) {
-			continue;
-		}
-		/* got one */
-		chat = (PurpleChat *) node;
-		if (account != chat->account)	/* not qq account*/
-			continue;
-		group = qq_room_data_new_by_hashtable(gc, chat->components);
-		if (group == NULL)
-			continue;
-
-		if (group->id <= 0)
-			continue;
-
-		count++;
-	}
-
-	purple_debug_info("QQ", "Load %d QQ Qun configurations\n", count);
-}
============================================================
--- libpurple/protocols/qq/group.h	04b3c9fdfe214a2eac3f47e0663947ee2cce34ed
+++ libpurple/protocols/qq/group.h	65046d1ce1b7c1599ab024b9cfe372a6f5892cc8
@@ -40,7 +40,8 @@ typedef enum {
 	QQ_ROOM_ROLE_ADMIN,
 } qq_room_role;
 
-typedef struct _qq_group {
+typedef struct _qq_room_data qq_room_data;
+struct _qq_room_data {
 	/* all these will be saved when we exit Purple */
 	qq_room_role my_role;	/* my role for this room */
 	guint32 id;
@@ -56,13 +57,11 @@ typedef struct _qq_group {
 
 	gboolean is_got_buddies;
 	GList *members;
-} qq_group;
+};
 
 GList *qq_chat_info(PurpleConnection *gc);
 GHashTable *qq_chat_info_defaults(PurpleConnection *gc, const gchar *chat_name);
 
-void qq_group_init(PurpleConnection *gc);
-
 PurpleRoomlist *qq_roomlist_get_list(PurpleConnection *gc);
 
 void qq_roomlist_cancel(PurpleRoomlist *list);
============================================================
--- libpurple/protocols/qq/group_im.c	7eb3b8ee8216fdb987dca3f8f0de620b41709998
+++ libpurple/protocols/qq/group_im.c	5428b66ff658a43a93e7657bb4354aa3a7a4f958
@@ -32,7 +32,6 @@
 #include "util.h"
 
 #include "char_conv.h"
-#include "group_find.h"
 #include "group_internal.h"
 #include "group_info.h"
 #include "group_im.h"
@@ -45,41 +44,41 @@
 #include "utils.h"
 
 /* show group conversation window */
-PurpleConversation *qq_room_conv_open(PurpleConnection *gc, qq_group *group)
+PurpleConversation *qq_room_conv_open(PurpleConnection *gc, qq_room_data *rmd)
 {
 	PurpleConversation *conv;
 	qq_data *qd;
 	gchar *topic_utf8;
 
-	g_return_val_if_fail(group != NULL, NULL);
+	g_return_val_if_fail(rmd != NULL, NULL);
 	qd = (qq_data *) gc->proto_data;
 
 	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
-			group->title_utf8, purple_connection_get_account(gc));
+			rmd->title_utf8, purple_connection_get_account(gc));
 	if (conv != NULL)	{
-		/* show only one conversation per group */
+		/* show only one conversation per room */
 		return conv;
 	}
 
-	serv_got_joined_chat(gc, group->id, group->title_utf8);
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc));
+	serv_got_joined_chat(gc, rmd->id, rmd->title_utf8);
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, rmd->title_utf8, purple_connection_get_account(gc));
 	if (conv != NULL) {
-		topic_utf8 = g_strdup_printf("%d %s", group->ext_id, group->notice_utf8);
+		topic_utf8 = g_strdup_printf("%d %s", rmd->ext_id, rmd->notice_utf8);
 		purple_debug_info("QQ", "Set chat topic to %s\n", topic_utf8);
 		purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, topic_utf8);
 		g_free(topic_utf8);
 
-		if (group->is_got_buddies)
-			qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, group->id);
+		if (rmd->is_got_buddies)
+			qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, rmd->id);
 		else
-			qq_update_room(gc, 0, group->id);
+			qq_update_room(gc, 0, rmd->id);
 		return conv;
 	}
 	return NULL;
 }
 
 /* refresh online member in group conversation window */
-void qq_room_conv_set_onlines(PurpleConnection *gc, qq_group *group)
+void qq_room_conv_set_onlines(PurpleConnection *gc, qq_room_data *rmd)
 {
 	GList *names, *list, *flags;
 	qq_buddy_data *bd;
@@ -88,20 +87,20 @@ void qq_room_conv_set_onlines(PurpleConn
 	gint flag;
 	gboolean is_find;
 
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(rmd != NULL);
 
 	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
-			group->title_utf8, purple_connection_get_account(gc));
+			rmd->title_utf8, purple_connection_get_account(gc));
 	if (conv == NULL) {
-		purple_debug_warning("QQ", "Conversation \"%s\" is not opened\n", group->title_utf8);
+		purple_debug_warning("QQ", "Conversation \"%s\" is not opened\n", rmd->title_utf8);
 		return;
 	}
-	g_return_if_fail(group->members != NULL);
+	g_return_if_fail(rmd->members != NULL);
 
 	names = NULL;
 	flags = NULL;
 
-	list = group->members;
+	list = rmd->members;
 	while (list != NULL) {
 		bd = (qq_buddy_data *) list->data;
 
@@ -116,7 +115,7 @@ void qq_room_conv_set_onlines(PurpleConn
 		/* TYPING to put online above OP and FOUNDER */
 		if (is_online(bd->status)) flag |= (PURPLE_CBFLAGS_TYPING | PURPLE_CBFLAGS_VOICE);
 		if(1 == (bd->role & 1)) flag |= PURPLE_CBFLAGS_OP;
-		if(bd->uid == group->creator_uid) flag |= PURPLE_CBFLAGS_FOUNDER;
+		if(bd->uid == rmd->creator_uid) flag |= PURPLE_CBFLAGS_FOUNDER;
 
 		is_find = TRUE;
 		if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_name))
@@ -251,19 +250,21 @@ void qq_room_got_chat_in(PurpleConnectio
 }
 
 void qq_room_got_chat_in(PurpleConnection *gc,
-		qq_group *group, guint32 uid_from, const gchar *msg, time_t in_time)
+		guint32 room_id, guint32 uid_from, const gchar *msg, time_t in_time)
 {
-	PurpleAccount *account = purple_connection_get_account(gc);
 	PurpleConversation *conv;
 	qq_buddy_data *bd;
+	qq_room_data *rmd;
 	gchar *from;
 
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(gc != NULL && room_id != 0);
 
-	conv = purple_find_conversation_with_account(
-			PURPLE_CONV_TYPE_CHAT, group->title_utf8, account);
+	conv = purple_find_chat(gc, room_id);
+	rmd = qq_room_data_find(gc, room_id);
+	g_return_if_fail(rmd != NULL);
+
 	if (conv == NULL && purple_prefs_get_bool("/plugins/prpl/qq/show_room_when_newin")) {
-		conv = qq_room_conv_open(gc, group);
+		conv = qq_room_conv_open(gc, rmd);
 	}
 
 	if (conv == NULL) {
@@ -271,7 +272,8 @@ void qq_room_got_chat_in(PurpleConnectio
 	}
 
 	if (uid_from != 0) {
-		bd = qq_group_find_member_by_uid(group, uid_from);
+
+		bd = qq_room_buddy_find(rmd, uid_from);
 		if (bd == NULL || bd->nickname == NULL)
 			from = g_strdup_printf("%d", uid_from);
 		else
@@ -279,9 +281,7 @@ void qq_room_got_chat_in(PurpleConnectio
 	} else {
 		from = g_strdup("");
 	}
-	serv_got_chat_in(gc,
-			purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)),
-				from, 0, msg, in_time);
+	serv_got_chat_in(gc, room_id, from, 0, msg, in_time);
 	g_free(from);
 }
 
@@ -291,7 +291,7 @@ void qq_process_room_msg_been_rejected(g
 	guint32 ext_id, admin_uid;
 	guint8 type8;
 	gchar *reason_utf8, *msg, *reason;
-	qq_group *group;
+	qq_room_data *rmd;
 	gint bytes;
 
 	g_return_if_fail(data != NULL && len > 0);
@@ -312,10 +312,10 @@ void qq_process_room_msg_been_rejected(g
 
 	purple_notify_warning(gc, _("QQ Qun Operation"), msg, reason);
 
-	group = qq_room_search_id(gc, id);
-	if (group != NULL) {
-		group->my_role = QQ_ROOM_ROLE_NO;
-		qq_group_refresh(gc, group);
+	qq_room_find_or_new(gc, id, ext_id);
+	rmd = qq_room_data_find(gc, id);
+	if (rmd != NULL) {
+		rmd->my_role = QQ_ROOM_ROLE_NO;
 	}
 
 	g_free(msg);
@@ -329,7 +329,7 @@ void qq_process_room_msg_been_approved(g
 	guint32 ext_id, admin_uid;
 	guint8 type8;
 	gchar *msg, *reason;
-	qq_group *group;
+	qq_room_data *rmd;
 	gint bytes;
 	time_t now;
 
@@ -345,16 +345,16 @@ void qq_process_room_msg_been_approved(g
 	/* it is also a "?" here, so do not display */
 	bytes += qq_get_vstr(&reason, QQ_CHARSET_DEFAULT, data + bytes);
 
-	group = qq_room_search_id(gc, id);
-	if (group != NULL) {
-		group->my_role = QQ_ROOM_ROLE_YES;
-		qq_group_refresh(gc, group);
+	qq_room_find_or_new(gc, id, ext_id);
+	rmd = qq_room_data_find(gc, id);
+	if (rmd != NULL) {
+		rmd->my_role = QQ_ROOM_ROLE_YES;
 	}
 
 	msg = g_strdup_printf(_("<b>Joinning Qun %d is approved by Admin %d for %s</b>"),
 			ext_id, admin_uid, reason);
 	now = time(NULL);
-	qq_room_got_chat_in(gc, group, 0, msg, now);
+	qq_room_got_chat_in(gc, id, 0, msg, now);
 
 	g_free(msg);
 	g_free(reason);
@@ -366,7 +366,7 @@ void qq_process_room_msg_been_removed(gu
 	guint32 ext_id, uid;
 	guint8 type8;
 	gchar *msg;
-	qq_group *group;
+	qq_room_data *rmd;
 	gint bytes = 0;
 	time_t now = time(NULL);
 
@@ -380,14 +380,14 @@ void qq_process_room_msg_been_removed(gu
 
 	g_return_if_fail(ext_id > 0 && uid > 0);
 
-	group = qq_room_search_id(gc, id);
-	if (group != NULL) {
-		group->my_role = QQ_ROOM_ROLE_NO;
-		qq_group_refresh(gc, group);
+	qq_room_find_or_new(gc, id, ext_id);
+	rmd = qq_room_data_find(gc, id);
+	if (rmd != NULL) {
+		rmd->my_role = QQ_ROOM_ROLE_NO;
 	}
 
 	msg = g_strdup_printf(_("<b>Removed buddy %d.</b>"), uid);
-	qq_room_got_chat_in(gc, group, 0, msg, now);
+	qq_room_got_chat_in(gc, id, 0, msg, now);
 	g_free(msg);
 }
 
@@ -396,9 +396,9 @@ void qq_process_room_msg_been_added(guin
 {
 	guint32 ext_id, uid;
 	guint8 type8;
-	qq_group *group;
-	gchar *msg;
+	qq_room_data *rmd;
 	gint bytes;
+	gchar *msg;
 	time_t now = time(NULL);
 
 	g_return_if_fail(data != NULL && len > 0);
@@ -409,22 +409,18 @@ void qq_process_room_msg_been_added(guin
 	bytes += qq_get8(&type8, data + bytes);
 	bytes += qq_get32(&uid, data + bytes);
 
-	g_return_if_fail(ext_id > 0 && uid > 0);
+	g_return_if_fail(ext_id > 0 && id > 0);
 
-	group = qq_room_search_id(gc, id);
-	if (group != NULL) {
-		group->my_role = QQ_ROOM_ROLE_YES;
-		qq_group_refresh(gc, group);
-	} else {		/* no such group, try to create a dummy first, and then update */
-		group = qq_group_create_internal_record(gc, id, ext_id, NULL);
-		group->my_role = QQ_ROOM_ROLE_YES;
-		qq_group_refresh(gc, group);
-		qq_update_room(gc, 0, group->id);
-		/* the return of this cmd will automatically update the group in blist */
-	}
+	qq_room_find_or_new(gc, id, ext_id);
+	rmd = qq_room_data_find(gc, id);
+	g_return_if_fail(rmd != NULL);
 
+	rmd->my_role = QQ_ROOM_ROLE_YES;
+
+	qq_update_room(gc, 0, rmd->id);
+
 	msg = g_strdup_printf(_("<b>Added new buddy %d.</b>"), uid);
-	qq_room_got_chat_in(gc, group, 0, msg, now);
+	qq_room_got_chat_in(gc, id, 0, msg, now);
 	g_free(msg);
 }
 
@@ -433,7 +429,6 @@ void qq_process_room_msg_normal(guint8 *
 {
 	gchar *msg_with_purple_smiley, *msg_utf8_encoded;
 	qq_data *qd;
-	qq_group *group;
 	gint skip_len;
 	gint bytes ;
 	struct {
@@ -458,7 +453,7 @@ void qq_process_room_msg_normal(guint8 *
 	qd = (qq_data *) gc->proto_data;
 
 #if 1
-	qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", data, data_len, "group im hex dump");
+	qq_show_packet("Room IM", data, data_len);
 #endif
 	memset(&packet, 0, sizeof(packet));
 	bytes = 0;
@@ -519,8 +514,7 @@ void qq_process_room_msg_normal(guint8 *
 	} 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);
+ 	qq_room_got_chat_in(gc, id, packet.member_uid, msg_utf8_encoded, packet.send_time);
 
 	g_free(msg_with_purple_smiley);
 	g_free(msg_utf8_encoded);
============================================================
--- libpurple/protocols/qq/group_im.h	b0e2d1f8361b464094e98fb26e6e2e2deda64308
+++ libpurple/protocols/qq/group_im.h	2ddb6f690940c2112c80620b8e691541ab3f77c9
@@ -30,11 +30,11 @@
 #include "conversation.h"
 #include "group.h"
 
-PurpleConversation *qq_room_conv_open(PurpleConnection *gc, qq_group *group);
-void qq_room_conv_set_onlines(PurpleConnection *gc, qq_group *group);
+PurpleConversation *qq_room_conv_open(PurpleConnection *gc, qq_room_data *rmd);
+void qq_room_conv_set_onlines(PurpleConnection *gc, qq_room_data *rmd);
 
 void qq_room_got_chat_in(PurpleConnection *gc,
-		qq_group *group, guint32 uid_from, const gchar *msg, time_t in_time);
+		guint32 room_id, guint32 uid_from, const gchar *msg, time_t in_time);
 
 void qq_send_packet_group_im(PurpleConnection *gc, guint32 room_id, const gchar *msg);
 
============================================================
--- libpurple/protocols/qq/group_info.c	3f6d2d797116e49d1e9fa78f6d0a9246033e39ed
+++ libpurple/protocols/qq/group_info.c	fe4f3cd365955b009e167df30c506f2df910c8c4
@@ -29,7 +29,6 @@
 
 #include "char_conv.h"
 #include "group_im.h"
-#include "group_find.h"
 #include "group_internal.h"
 #include "group_info.h"
 #include "buddy_list.h"
@@ -51,13 +50,13 @@ static gboolean check_update_interval(qq
 
 /* this is done when we receive the reply to get_online_members sub_cmd
  * all member are set offline, and then only those in reply packets are online */
-static void set_all_offline(qq_group *group)
+static void set_all_offline(qq_room_data *rmd)
 {
 	GList *list;
 	qq_buddy_data *bd;
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(rmd != NULL);
 
-	list = group->members;
+	list = rmd->members;
 	while (list != NULL) {
 		bd = (qq_buddy_data *) list->data;
 		bd->status = QQ_BUDDY_CHANGE_TO_OFFLINE;
@@ -66,15 +65,20 @@ static void set_all_offline(qq_group *gr
 }
 
 /* send packet to get info for each group member */
-gint qq_request_room_get_buddies(PurpleConnection *gc, qq_group *group, gint update_class)
+gint qq_request_room_get_buddies(PurpleConnection *gc, guint32 room_id, gint update_class)
 {
 	guint8 *raw_data;
 	gint bytes, num;
 	GList *list;
+	qq_room_data *rmd;
 	qq_buddy_data *bd;
 
-	g_return_val_if_fail(group != NULL, 0);
-	for (num = 0, list = group->members; list != NULL; list = list->next) {
+	g_return_val_if_fail(room_id > 0, 0);
+
+	rmd  = qq_room_data_find(gc, room_id);
+	g_return_val_if_fail(rmd != NULL, 0);
+
+	for (num = 0, list = rmd->members; list != NULL; list = list->next) {
 		bd = (qq_buddy_data *) list->data;
 		if (check_update_interval(bd))
 			num++;
@@ -89,7 +93,7 @@ gint qq_request_room_get_buddies(PurpleC
 
 	bytes = 0;
 
-	list = group->members;
+	list = rmd->members;
 	while (list != NULL) {
 		bd = (qq_buddy_data *) list->data;
 		if (check_update_interval(bd))
@@ -97,7 +101,7 @@ gint qq_request_room_get_buddies(PurpleC
 		list = list->next;
 	}
 
-	qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_BUDDIES, group->id, raw_data, bytes,
+	qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_BUDDIES, rmd->id, raw_data, bytes,
 			update_class, 0);
 	return num;
 }
@@ -125,38 +129,38 @@ static gchar *get_role_desc(qq_room_role
 	return g_strdup(role_desc);
 }
 
-static void room_info_display(PurpleConnection *gc, qq_group *group)
+static void room_info_display(PurpleConnection *gc, qq_room_data *rmd)
 {
 	PurpleNotifyUserInfo *room_info;
 	gchar *utf8_value;
 
-	g_return_if_fail(group != NULL && group->id > 0);
+	g_return_if_fail(rmd != NULL && rmd->id > 0);
 
 	room_info = purple_notify_user_info_new();
 
-	purple_notify_user_info_add_pair(room_info, _("Title"), group->title_utf8);
-	purple_notify_user_info_add_pair(room_info, _("Notice"), group->notice_utf8);
-	purple_notify_user_info_add_pair(room_info, _("Detail"), group->desc_utf8);
+	purple_notify_user_info_add_pair(room_info, _("Title"), rmd->title_utf8);
+	purple_notify_user_info_add_pair(room_info, _("Notice"), rmd->notice_utf8);
+	purple_notify_user_info_add_pair(room_info, _("Detail"), rmd->desc_utf8);
 
 	purple_notify_user_info_add_section_break(room_info);
 
-	utf8_value = g_strdup_printf(("%d"), group->creator_uid);
+	utf8_value = g_strdup_printf(("%d"), rmd->creator_uid);
 	purple_notify_user_info_add_pair(room_info, _("Creator"), utf8_value);
 	g_free(utf8_value);
 
-	utf8_value = get_role_desc(group->my_role);
+	utf8_value = get_role_desc(rmd->my_role);
 	purple_notify_user_info_add_pair(room_info, _("About me"), utf8_value);
 	g_free(utf8_value);
 
-	utf8_value = g_strdup_printf(("%d"), group->category);
+	utf8_value = g_strdup_printf(("%d"), rmd->category);
 	purple_notify_user_info_add_pair(room_info, _("Category"), utf8_value);
 	g_free(utf8_value);
 
-	utf8_value = g_strdup_printf(("%d"), group->auth_type);
+	utf8_value = g_strdup_printf(("%d"), rmd->auth_type);
 	purple_notify_user_info_add_pair(room_info, _("Authorize"), utf8_value);
 	g_free(utf8_value);
 
-	utf8_value = g_strdup_printf(("%d"), group->ext_id);
+	utf8_value = g_strdup_printf(("%d"), rmd->ext_id);
 	purple_notify_userinfo(gc, utf8_value, room_info, NULL, NULL);
 	g_free(utf8_value);
 
@@ -165,9 +169,10 @@ void qq_process_room_cmd_get_info(guint8
 
 void qq_process_room_cmd_get_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc)
 {
-	qq_group *group;
+	qq_data *qd;
+	qq_room_data *rmd;
 	qq_buddy_data *bd;
-	qq_data *qd;
+	PurpleChat *chat;
 	PurpleConversation *conv;
 	guint8 organization, role;
 	guint16 unknown, max_members;
@@ -190,20 +195,18 @@ void qq_process_room_cmd_get_info(guint8
 	bytes += qq_get32(&ext_id, data + bytes);
 	g_return_if_fail(ext_id > 0);
 
-	if (action == QQ_ROOM_INFO_CREATE ) {
-		qq_group_create_internal_record(gc, id, ext_id, NULL);
-	}
+	chat = qq_room_find_or_new(gc, id, ext_id);
+	g_return_if_fail(chat != NULL);
+	rmd = qq_room_data_find(gc, id);
+	g_return_if_fail(rmd != NULL);
 
-	group = qq_room_search_id(gc, id);
-	g_return_if_fail(group != NULL);
-
-	bytes += qq_get8(&(group->type8), data + bytes);
+	bytes += qq_get8(&(rmd->type8), data + bytes);
 	bytes += qq_get32(&unknown4, data + bytes);	/* unknown 4 bytes */
-	bytes += qq_get32(&(group->creator_uid), data + bytes);
-	bytes += qq_get8(&(group->auth_type), data + bytes);
+	bytes += qq_get32(&(rmd->creator_uid), data + bytes);
+	bytes += qq_get8(&(rmd->auth_type), data + bytes);
 	bytes += qq_get32(&unknown4, data + bytes);	/* oldCategory */
 	bytes += qq_get16(&unknown, data + bytes);
-	bytes += qq_get32(&(group->category), data + bytes);
+	bytes += qq_get32(&(rmd->category), data + bytes);
 	bytes += qq_get16(&max_members, data + bytes);
 	bytes += qq_get8(&unknown1, data + bytes);
 	/* the following, while Eva:
@@ -212,7 +215,7 @@ void qq_process_room_cmd_get_info(guint8
 	 * qunDestLen(qunDestcontent)) */
 	bytes += qq_get8(&unknown1, data + bytes);
 	purple_debug_info("QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n",
-			group->type8, group->creator_uid, group->category, max_members);
+			rmd->type8, rmd->creator_uid, rmd->category, max_members);
 
 	if (qd->client_version >= 2007) {
 		/* skip 7 bytes unknow in qq2007 0x(00 00 01 00 00 00 fc)*/
@@ -220,13 +223,13 @@ void qq_process_room_cmd_get_info(guint8
 	}
 	/* qq_show_packet("Room Info", data + bytes, data_len - bytes); */
 	/* strlen + <str content> */
-	bytes += qq_get_vstr(&(group->title_utf8), QQ_CHARSET_DEFAULT, data + bytes);
+	bytes += qq_get_vstr(&(rmd->title_utf8), QQ_CHARSET_DEFAULT, data + bytes);
 	bytes += qq_get16(&unknown, data + bytes);	/* 0x0000 */
 	bytes += qq_get_vstr(&notice, QQ_CHARSET_DEFAULT, data + bytes);
-	bytes += qq_get_vstr(&(group->desc_utf8), QQ_CHARSET_DEFAULT, data + bytes);
+	bytes += qq_get_vstr(&(rmd->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);
+			rmd->title_utf8, notice, rmd->desc_utf8, unknown);
 
 	num = 0;
 	/* now comes the member list separated by 0x00 */
@@ -242,7 +245,7 @@ void qq_process_room_cmd_get_info(guint8
 		}
 #endif
 
-		bd = qq_group_find_or_add_member(gc, group, member_uid);
+		bd = qq_room_buddy_find_or_new(gc, rmd, member_uid);
 		if (bd != NULL)
 			bd->role = role;
 	}
@@ -251,30 +254,30 @@ void qq_process_room_cmd_get_info(guint8
 			"group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!");
 	}
 
-	purple_debug_info("QQ", "group \"%s\" has %d members\n", group->title_utf8, num);
+	purple_debug_info("QQ", "group \"%s\" has %d members\n", rmd->title_utf8, num);
 
-	if (group->creator_uid == qd->uid)
-		group->my_role = QQ_ROOM_ROLE_ADMIN;
+	if (rmd->creator_uid == qd->uid)
+		rmd->my_role = QQ_ROOM_ROLE_ADMIN;
 
 	/* filter \r\n in notice */
 	qq_filter_str(notice);
-	group->notice_utf8 = strdup(notice);
+	rmd->notice_utf8 = strdup(notice);
 	g_free(notice);
 
-	qq_group_refresh(gc, group);
+	qq_room_update_chat_info(chat, rmd);
 
 	if (action == QQ_ROOM_INFO_DISPLAY) {
-		room_info_display(gc, group);
+		room_info_display(gc, rmd);
 	}
 
 	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
-			group->title_utf8, purple_connection_get_account(gc));
+			rmd->title_utf8, purple_connection_get_account(gc));
 	if(NULL == conv) {
-		purple_debug_warning("QQ", "Conversation \"%s\" is not opened\n", group->title_utf8);
+		purple_debug_warning("QQ", "Conversation \"%s\" is not opened\n", rmd->title_utf8);
 		return;
 	}
 
-	topic_utf8 = g_strdup_printf("%d %s", group->ext_id, group->notice_utf8);
+	topic_utf8 = g_strdup_printf("%d %s", rmd->ext_id, rmd->notice_utf8);
 	purple_debug_info("QQ", "Set chat topic to %s\n", topic_utf8);
 	purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, topic_utf8);
 	g_free(topic_utf8);
@@ -285,7 +288,7 @@ void qq_process_room_cmd_get_onlines(gui
 	guint32 id, member_uid;
 	guint8 unknown;
 	gint bytes, num;
-	qq_group *group;
+	qq_room_data *rmd;
 	qq_buddy_data *bd;
 
 	g_return_if_fail(data != NULL && len > 0);
@@ -300,19 +303,19 @@ void qq_process_room_cmd_get_onlines(gui
 	bytes += qq_get8(&unknown, data + bytes);	/* 0x3c ?? */
 	g_return_if_fail(id > 0);
 
-	group = qq_room_search_id(gc, id);
-	if (group == NULL) {
+	rmd = qq_room_data_find(gc, id);
+	if (rmd == NULL) {
 		purple_debug_error("QQ", "We have no group info for internal id [%d]\n", id);
 		return;
 	}
 
 	/* set all offline first, then update those online */
-	set_all_offline(group);
+	set_all_offline(rmd);
 	num = 0;
 	while (bytes < len) {
 		bytes += qq_get32(&member_uid, data + bytes);
 		num++;
-		bd = qq_group_find_or_add_member(gc, group, member_uid);
+		bd = qq_room_buddy_find_or_new(gc, rmd, member_uid);
 		if (bd != NULL)
 			bd->status = QQ_BUDDY_ONLINE_NORMAL;
 	}
@@ -321,8 +324,8 @@ void qq_process_room_cmd_get_onlines(gui
 			"group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!");
 	}
 
-	purple_debug_info("QQ", "Group \"%s\" has %d online members\n", group->title_utf8, num);
-	qq_room_conv_set_onlines(gc, group);
+	purple_debug_info("QQ", "Group \"%s\" has %d online members\n", rmd->title_utf8, num);
+	qq_room_conv_set_onlines(gc, rmd);
 }
 
 /* process the reply to get_members_info packet */
@@ -332,7 +335,7 @@ void qq_process_room_cmd_get_buddies(gui
 	gint num;
 	guint32 id, member_uid;
 	guint16 unknown;
-	qq_group *group;
+	qq_room_data *rmd;
 	qq_buddy_data *bd;
 	gchar *nick;
 
@@ -344,15 +347,15 @@ void qq_process_room_cmd_get_buddies(gui
 	bytes += qq_get32(&id, data + bytes);
 	g_return_if_fail(id > 0);
 
-	group = qq_room_search_id(gc, id);
-	g_return_if_fail(group != NULL);
+	rmd = qq_room_data_find(gc, id);
+	g_return_if_fail(rmd != NULL);
 
 	num = 0;
 	/* now starts the member info, as get buddy list reply */
 	while (bytes < len) {
 		bytes += qq_get32(&member_uid, data + bytes);
 		g_return_if_fail(member_uid > 0);
-		bd = qq_group_find_member_by_uid(group, member_uid);
+		bd = qq_room_buddy_find_or_new(gc, rmd, member_uid);
 		g_return_if_fail(bd != NULL);
 
 		num++;
@@ -381,9 +384,9 @@ void qq_process_room_cmd_get_buddies(gui
 		purple_debug_error("QQ",
 				"group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!");
 	}
-	purple_debug_info("QQ", "Group \"%s\" obtained %d member info\n", group->title_utf8, num);
+	purple_debug_info("QQ", "Group \"%s\" obtained %d member info\n", rmd->title_utf8, num);
 
-	group->is_got_buddies = TRUE;
-	qq_room_conv_set_onlines(gc, group);
+	rmd->is_got_buddies = TRUE;
+	qq_room_conv_set_onlines(gc, rmd);
 }
 
============================================================
--- libpurple/protocols/qq/group_info.h	bfec409dfa2700caaa269dc64501420fcb7412b6
+++ libpurple/protocols/qq/group_info.h	d8ae739623bf70a09d61fe7f332fa852ef1c10b5
@@ -32,10 +32,9 @@ enum {
 enum {
 	QQ_ROOM_INFO_UPDATE_ONLY = 0,
 	QQ_ROOM_INFO_DISPLAY,
-	QQ_ROOM_INFO_CREATE,
 };
 
-gint qq_request_room_get_buddies(PurpleConnection *gc, qq_group *group, gint update_class);
+gint qq_request_room_get_buddies(PurpleConnection *gc, guint32 room_id, gint update_class);
 
 void qq_process_room_cmd_get_info(guint8 *data, gint len, guint32 action, PurpleConnection *gc);
 void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc);
============================================================
--- libpurple/protocols/qq/group_internal.c	cb893633d1550943da1932c27425014b4f20d4c7
+++ libpurple/protocols/qq/group_internal.c	5624623ac9a2fe3801602936da42687481d57db1
@@ -27,151 +27,395 @@
 #include "debug.h"
 
 #include "buddy_opt.h"
-#include "group_free.h"
 #include "group_internal.h"
 #include "utils.h"
 
-static void add_room_to_blist(PurpleConnection *gc, qq_group *group)
+static qq_room_data *room_data_new(guint32 id, guint32 ext_id, gchar *title)
 {
+	qq_room_data *rmd;
+
+	purple_debug_info("QQ", "Created room data: %s, ext id %d, id %d\n",
+			title, ext_id, id);
+	rmd = g_new0(qq_room_data, 1);
+	rmd->my_role = QQ_ROOM_ROLE_NO;
+	rmd->id = id;
+	rmd->ext_id = ext_id;
+	rmd->type8 = 0x01;       /* assume permanent Qun */
+	rmd->creator_uid = 10000;     /* assume by QQ admin */
+	rmd->category = 0x01;
+	rmd->auth_type = 0x02;        /* assume need auth */
+	rmd->title_utf8 = g_strdup(title == NULL ? "" : title);
+	rmd->desc_utf8 = g_strdup("");
+	rmd->notice_utf8 = g_strdup("");
+	rmd->members = NULL;
+	rmd->is_got_buddies = FALSE;
+	return rmd;
+}
+
+/* create a qq_room_data from hashtable */
+static qq_room_data *room_data_new_by_hashtable(PurpleConnection *gc, GHashTable *data)
+{
+	qq_room_data *rmd;
+	guint32 id, ext_id;
+	gchar *value;
+
+	value = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID);
+	id = value ? strtol(value, NULL, 10) : 0;
+	value= g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID);
+	ext_id = value ? strtol(value, NULL, 10) : 0;
+	value = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_TITLE_UTF8));
+
+	rmd = room_data_new(id, ext_id, value);
+	rmd->my_role = QQ_ROOM_ROLE_YES;
+	return rmd;
+}
+
+/* gracefully free all members in a room */
+static void room_buddies_free(qq_room_data *rmd)
+{
+	gint i;
+	GList *list;
+	qq_buddy_data *bd;
+
+	g_return_if_fail(rmd != NULL);
+	i = 0;
+	while (NULL != (list = rmd->members)) {
+		bd = (qq_buddy_data *) list->data;
+		i++;
+		rmd->members = g_list_remove(rmd->members, bd);
+		qq_buddy_data_free(bd);
+	}
+
+	rmd->members = NULL;
+}
+
+/* gracefully free the memory for one qq_room_data */
+static void room_data_free(qq_room_data *rmd)
+{
+	g_return_if_fail(rmd != NULL);
+	room_buddies_free(rmd);
+	g_free(rmd->title_utf8);
+	g_free(rmd->desc_utf8);
+	g_free(rmd->notice_utf8);
+	g_free(rmd);
+}
+
+void qq_room_update_chat_info(PurpleChat *chat, qq_room_data *rmd)
+{
+	if (rmd->title_utf8 != NULL && strlen(rmd->title_utf8) > 0) {
+		purple_blist_alias_chat(chat, rmd->title_utf8);
+	}
+	g_hash_table_replace(chat->components,
+		     g_strdup(QQ_ROOM_KEY_INTERNAL_ID),
+		     g_strdup_printf("%d", rmd->id));
+	g_hash_table_replace(chat->components,
+		     g_strdup(QQ_ROOM_KEY_EXTERNAL_ID),
+		     g_strdup_printf("%d", rmd->ext_id));
+	g_hash_table_replace(chat->components,
+		     g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(rmd->title_utf8));
+}
+
+static PurpleChat *chat_new(PurpleConnection *gc, qq_room_data *rmd)
+{
 	GHashTable *components;
 	PurpleGroup *g;
 	PurpleChat *chat;
-	components = qq_group_to_hashtable(group);
-	chat = purple_chat_new(purple_connection_get_account(gc), group->title_utf8, components);
+
+	purple_debug_info("QQ", "Add new chat: id %d, ext id %d, title %s\n",
+		rmd->id, rmd->ext_id, rmd->title_utf8);
+
+	components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	g_hash_table_insert(components,
+			    g_strdup(QQ_ROOM_KEY_INTERNAL_ID), g_strdup_printf("%d", rmd->id));
+	g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_EXTERNAL_ID),
+			    g_strdup_printf("%d", rmd->ext_id));
+	g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(rmd->title_utf8));
+
+	chat = purple_chat_new(purple_connection_get_account(gc), rmd->title_utf8, components);
 	g = qq_group_find_or_new(PURPLE_GROUP_QQ_QUN);
 	purple_blist_add_chat(chat, g, NULL);
-	purple_debug_info("QQ", "Added room \"%s\" to blist locally\n", group->title_utf8);
+
+	return chat;
 }
 
-/* Create a dummy qq_group, which includes only internal_id, ext_id,
- * and potentially title_utf8, in case we need to call group_conv_show_window
- * right after creation. All other attributes are set to empty.
- * We need to send a get_group_info to the QQ server to update it right away */
-qq_group *qq_group_create_internal_record(PurpleConnection *gc,
-                guint32 internal_id, guint32 ext_id, gchar *title_utf8)
+PurpleChat *qq_room_find_or_new(PurpleConnection *gc, guint32 id, guint32 ext_id)
 {
-        qq_group *group;
-        qq_data *qd;
+	qq_data *qd;
+	qq_room_data *rmd;
+	PurpleChat *chat;
+	gchar *num_str;
 
-        g_return_val_if_fail(internal_id > 0, NULL);
-        qd = (qq_data *) gc->proto_data;
+	g_return_val_if_fail (gc != NULL && gc->proto_data != NULL, NULL);
+	qd = (qq_data *) gc->proto_data;
 
-        group = g_new0(qq_group, 1);
-        group->my_role = QQ_ROOM_ROLE_NO;
-        group->id = internal_id;
-        group->ext_id = ext_id;
-        group->type8 = 0x01;       /* assume permanent Qun */
-        group->creator_uid = 10000;     /* assume by QQ admin */
-        group->category = 0x01;
-        group->auth_type = 0x02;        /* assume need auth */
-        group->title_utf8 = g_strdup(title_utf8 == NULL ? "" : title_utf8);
-        group->desc_utf8 = g_strdup("");
-        group->notice_utf8 = g_strdup("");
-        group->members = NULL;
+	g_return_val_if_fail(id != 0 && ext_id != 0, NULL);
 
-        qd->groups = g_list_append(qd->groups, group);
-        add_room_to_blist(gc, group);
+	purple_debug_info("QQ", "Find or add new room: id %d, ext id %d\n", id, ext_id);
 
-        return group;
+	rmd = qq_room_data_find(gc, id);
+	if (rmd == NULL) {
+		rmd = room_data_new(id, ext_id, NULL);
+		g_return_val_if_fail(rmd != NULL, NULL);
+		qd->groups = g_list_append(qd->groups, rmd);
+	}
+
+	num_str = g_strdup_printf("%d", ext_id);
+	chat = purple_blist_find_chat(purple_connection_get_account(gc), num_str);
+	g_free(num_str);
+	if (chat) {
+		return chat;
+	}
+
+	return chat_new(gc, rmd);
 }
 
-void qq_group_delete_internal_record(qq_data *qd, guint32 id)
+void qq_room_remove(PurpleConnection *gc, guint32 id)
 {
-        qq_group *group;
-        GList *list;
+	qq_data *qd;
+	PurpleChat *chat;
+	qq_room_data *rmd;
+	gchar *num_str;
+	guint32 ext_id;
 
-        list = qd->groups;
-        while (list != NULL) {
-                group = (qq_group *) qd->groups->data;
-                if (id == group->id) {
-                        qd->groups = g_list_remove(qd->groups, group);
-                        qq_group_free(group);
-                        break;
-                } else {
-                        list = list->next;
-                }
-        }
+	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
+	qd = (qq_data *) gc->proto_data;
+
+	purple_debug_info("QQ", "Find and remove room data, id %d", id);
+	rmd = qq_room_data_find(gc, id);
+	g_return_if_fail (rmd != NULL);
+
+	ext_id = rmd->ext_id;
+	qd->groups = g_list_remove(qd->groups, rmd);
+	room_data_free(rmd);
+
+	purple_debug_info("QQ", "Find and remove chat, ext_id %d", ext_id);
+	num_str = g_strdup_printf("%d", ext_id);
+	chat = purple_blist_find_chat(purple_connection_get_account(gc), num_str);
+	g_free(num_str);
+
+	g_return_if_fail (chat != NULL);
+
+	purple_blist_remove_chat(chat);
 }
 
-/* convert a qq_group to hash-table, which could be component of PurpleChat */
-GHashTable *qq_group_to_hashtable(qq_group *group)
+/* find a qq_buddy_data by uid, called by im.c */
+qq_buddy_data *qq_room_buddy_find(qq_room_data *rmd, guint32 uid)
 {
-	GHashTable *components;
-	components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	GList *list;
+	qq_buddy_data *bd;
+	g_return_val_if_fail(rmd != NULL && uid > 0, NULL);
 
-	g_hash_table_insert(components,
-			    g_strdup(QQ_ROOM_KEY_INTERNAL_ID), g_strdup_printf("%d", group->id));
-	g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_EXTERNAL_ID),
-			    g_strdup_printf("%d", group->ext_id));
-	g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(group->title_utf8));
-	return components;
+	list = rmd->members;
+	while (list != NULL) {
+		bd = (qq_buddy_data *) list->data;
+		if (bd->uid == uid)
+			return bd;
+		else
+			list = list->next;
+	}
+
+	return NULL;
 }
 
-static gint str2dec(const gchar *str)
+/* remove a qq_buddy_data by uid, called by qq_group_opt.c */
+void qq_room_buddy_remove(qq_room_data *rmd, guint32 uid)
 {
-	g_return_val_if_fail(str != NULL, 0);
-	return strtol(str, NULL, 10);
+	GList *list;
+	qq_buddy_data *bd;
+	g_return_if_fail(rmd != NULL && uid > 0);
+
+	list = rmd->members;
+	while (list != NULL) {
+		bd = (qq_buddy_data *) list->data;
+		if (bd->uid == uid) {
+			rmd->members = g_list_remove(rmd->members, bd);
+			return;
+		} else {
+			list = list->next;
+		}
+	}
 }
 
-/* create a qq_group from hashtable */
-qq_group *qq_room_data_new_by_hashtable(PurpleConnection *gc, GHashTable *data)
+qq_buddy_data *qq_room_buddy_find_or_new(PurpleConnection *gc, qq_room_data *rmd, guint32 member_uid)
 {
+	qq_buddy_data *member, *bd;
+	PurpleBuddy *buddy;
+	g_return_val_if_fail(rmd != NULL && member_uid > 0, NULL);
+
+	member = qq_room_buddy_find(rmd, member_uid);
+	if (member == NULL) {	/* first appear during my session */
+		member = g_new0(qq_buddy_data, 1);
+		member->uid = member_uid;
+		buddy = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(member_uid));
+		if (buddy != NULL) {
+			bd = (qq_buddy_data *) buddy->proto_data;
+			if (bd != NULL && bd->nickname != NULL)
+				member->nickname = g_strdup(bd->nickname);
+			else if (buddy->alias != NULL)
+				member->nickname = g_strdup(buddy->alias);
+		}
+		rmd->members = g_list_append(rmd->members, member);
+	}
+
+	return member;
+}
+
+qq_room_data *qq_room_data_find(PurpleConnection *gc, guint32 room_id)
+{
+	GList *list;
+	qq_room_data *rmd;
 	qq_data *qd;
-	qq_group *group;
 
-	g_return_val_if_fail(data != NULL, NULL);
 	qd = (qq_data *) gc->proto_data;
 
-	group = g_new0(qq_group, 1);
-	memset(group, 0, sizeof(qq_group));
-	group->my_role = QQ_ROOM_ROLE_YES;
-	group->id = str2dec(g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID));
-	group->ext_id = str2dec(g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID));
-	group->title_utf8 = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_TITLE_UTF8));
-    group->type8 = 0x01;       /* assume permanent Qun */
-    group->creator_uid = 10000;     /* assume by QQ admin */
-    group->category = 0x01;
-    group->auth_type = 0x02;        /* assume need auth */
-    group->desc_utf8 = g_strdup("");
-    group->notice_utf8 = g_strdup("");
-    group->members = NULL;
-	group->is_got_buddies = FALSE;
+	if (qd->groups == NULL || room_id <= 0)
+		return 0;
 
-	purple_debug_info("QQ", "Created room info from hashtable: %s, %d, id %d\n",
-			group->title_utf8, group->ext_id, group->id);
-	qd->groups = g_list_append(qd->groups, group);
-	return group;
+	list = qd->groups;
+	while (list != NULL) {
+		rmd = (qq_room_data *) list->data;
+		if (rmd->id == room_id) {
+			return rmd;
+		}
+		list = list->next;
+	}
+
+	return NULL;
 }
 
-/* refresh group local subscription */
-void qq_group_refresh(PurpleConnection *gc, qq_group *group)
+guint32 qq_room_get_next(PurpleConnection *gc, guint32 room_id)
 {
+	GList *list;
+	qq_room_data *rmd;
+	qq_data *qd;
+	gboolean is_find = FALSE;
+
+	qd = (qq_data *) gc->proto_data;
+
+	if (qd->groups == NULL) {
+		return 0;
+	}
+
+	 if (room_id <= 0) {
+	 	rmd = (qq_room_data *) qd->groups->data;
+		return rmd->id;
+	}
+
+	list = qd->groups;
+	while (list != NULL) {
+		rmd = (qq_room_data *) list->data;
+		list = list->next;
+		if (rmd->id == room_id) {
+			is_find = TRUE;
+			break;
+		}
+	}
+
+	g_return_val_if_fail(is_find, 0);
+	if (list == NULL) return 0;	/* be the end */
+ 	rmd = (qq_room_data *) list->data;
+	g_return_val_if_fail(rmd != NULL, 0);
+	return rmd->id;
+}
+
+guint32 qq_room_get_next_conv(PurpleConnection *gc, guint32 room_id)
+{
+	GList *list;
+	qq_room_data *rmd;
+	qq_data *qd;
+	gboolean is_find;
+
+	qd = (qq_data *) gc->proto_data;
+
+ 	list = qd->groups;
+	if (room_id > 0) {
+		/* search next room */
+		is_find = FALSE;
+		while (list != NULL) {
+			rmd = (qq_room_data *) list->data;
+			list = list->next;
+			if (rmd->id == room_id) {
+				is_find = TRUE;
+				break;
+			}
+		}
+		g_return_val_if_fail(is_find, 0);
+	}
+
+	while (list != NULL) {
+		rmd = (qq_room_data *) list->data;
+		g_return_val_if_fail(rmd != NULL, 0);
+
+		if (rmd->my_role == QQ_ROOM_ROLE_YES || rmd->my_role == QQ_ROOM_ROLE_ADMIN) {
+			if (NULL != purple_find_conversation_with_account(
+						PURPLE_CONV_TYPE_CHAT,rmd->title_utf8, purple_connection_get_account(gc))) {
+				/* In convseration*/
+				return rmd->id;
+			}
+		}
+		list = list->next;
+	}
+
+	return 0;
+}
+
+/* this should be called upon signin, even when we did not open group chat window */
+void qq_room_data_initial(PurpleConnection *gc)
+{
+	PurpleAccount *account;
 	PurpleChat *chat;
-	gchar *ext_id;
-	g_return_if_fail(group != NULL);
+	PurpleGroup *purple_group;
+	PurpleBlistNode *node;
+	qq_data *qd;
+	qq_room_data *rmd;
+	gint count;
 
-	ext_id = g_strdup_printf("%d", group->ext_id);
-	chat = purple_blist_find_chat(purple_connection_get_account(gc), ext_id);
-	g_free(ext_id);
-	if (chat == NULL && group->my_role != QQ_ROOM_ROLE_NO) {
-		add_room_to_blist(gc, group);
+	account = purple_connection_get_account(gc);
+	qd = (qq_data *) gc->proto_data;
+
+	purple_debug_info("QQ", "Initial QQ Qun configurations\n");
+	purple_group = purple_find_group(PURPLE_GROUP_QQ_QUN);
+	if (purple_group == NULL) {
+		purple_debug_info("QQ", "We have no QQ Qun\n");
 		return;
 	}
 
-	if (chat == NULL) {
-		return;
+	count = 0;
+	for (node = ((PurpleBlistNode *) purple_group)->child; node != NULL; node = node->next) {
+		if ( !PURPLE_BLIST_NODE_IS_CHAT(node)) {
+			continue;
+		}
+		/* got one */
+		chat = (PurpleChat *) node;
+		if (account != chat->account)	/* not qq account*/
+			continue;
+
+		rmd = room_data_new_by_hashtable(gc, chat->components);
+		qd->groups = g_list_append(qd->groups, rmd);
+		count++;
 	}
 
-	/* we have a local record, update its info */
-	/* if there is title_utf8, we update the group name */
-	if (group->title_utf8 != NULL && strlen(group->title_utf8) > 0)
-		purple_blist_alias_chat(chat, group->title_utf8);
-	g_hash_table_replace(chat->components,
-		     g_strdup(QQ_ROOM_KEY_INTERNAL_ID),
-		     g_strdup_printf("%d", group->id));
-	g_hash_table_replace(chat->components,
-		     g_strdup(QQ_ROOM_KEY_EXTERNAL_ID),
-		     g_strdup_printf("%d", group->ext_id));
-	g_hash_table_replace(chat->components,
-		     g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(group->title_utf8));
+	purple_debug_info("QQ", "Load %d QQ Qun configurations\n", count);
 }
+
+void qq_room_data_free_all(PurpleConnection *gc)
+{
+	qq_data *qd;
+	qq_room_data *rmd;
+	gint count;
+
+	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
+	qd = (qq_data *) gc->proto_data;
+
+	count = 0;
+	while (qd->groups != NULL) {
+		rmd = (qq_room_data *) qd->groups->data;
+		qd->groups = g_list_remove(qd->groups, rmd);
+		room_data_free(rmd);
+		count++;
+	}
+
+	if (count > 0) {
+		purple_debug_info("QQ", "%d rooms are freed\n", count);
+	}
+}
============================================================
--- libpurple/protocols/qq/group_internal.h	97ed82b122bb427cc12c99e225b8e65de775079b
+++ libpurple/protocols/qq/group_internal.h	9c5600be9b59c837680ffbbf85f18e5bd11430f9
@@ -32,13 +32,19 @@
 #define QQ_ROOM_KEY_EXTERNAL_ID					"ext_id"
 #define QQ_ROOM_KEY_TITLE_UTF8					"title_utf8"
 
-qq_group *qq_group_create_internal_record(PurpleConnection *gc,
-		guint32 internal_id, guint32 ext_id, gchar *group_name_utf8);
-void qq_group_delete_internal_record(qq_data *qd, guint32 id);
+PurpleChat *qq_room_find_or_new(PurpleConnection *gc, guint32 id, guint32 ext_id);
+void qq_room_remove(PurpleConnection *gc, guint32 id);
+void qq_room_update_chat_info(PurpleChat *chat, qq_room_data *rmd);
 
-GHashTable *qq_group_to_hashtable(qq_group *group);
-qq_group *qq_room_data_new_by_hashtable(PurpleConnection *gc, GHashTable *data);
+qq_buddy_data *qq_room_buddy_find(qq_room_data *rmd, guint32 uid);
+void qq_room_buddy_remove(qq_room_data *rmd, guint32 uid);
+qq_buddy_data *qq_room_buddy_find_or_new(PurpleConnection *gc, qq_room_data *rmd, guint32 member_uid);
 
-void qq_group_refresh(PurpleConnection *gc, qq_group *group);
+void qq_room_data_initial(PurpleConnection *gc);
+void qq_room_data_free_all(PurpleConnection *gc);
+qq_room_data *qq_room_data_find(PurpleConnection *gc, guint32 room_id);
 
+guint32 qq_room_get_next(PurpleConnection *gc, guint32 room_id);
+guint32 qq_room_get_next_conv(PurpleConnection *gc, guint32 room_id);
+
 #endif
============================================================
--- libpurple/protocols/qq/group_join.c	0ea4ef16afe1dec9f1d1473466d4778f4b334ef2
+++ libpurple/protocols/qq/group_join.c	800c716efc73d3ec800f32da7096110c9c7bb47c
@@ -31,12 +31,10 @@
 
 #include "char_conv.h"
 #include "im.h"
-#include "group_find.h"
 #include "group_internal.h"
 #include "group_info.h"
 #include "group_join.h"
 #include "group_opt.h"
-#include "group_search.h"
 #include "group_im.h"
 #include "qq_define.h"
 #include "packet_parse.h"
@@ -49,11 +47,16 @@ enum {
 	QQ_ROOM_JOIN_DENIED = 0x03,
 };
 
+enum {
+	QQ_ROOM_SEARCH_TYPE_BY_ID = 0x01,
+	QQ_ROOM_SEARCH_TYPE_DEMO = 0x02
+};
+
 static void group_quit_cb(qq_add_request *add_req)
 {
 	PurpleConnection *gc;
 	guint32 id;
-	qq_group *group;
+	qq_room_data *rmd;
 
 	if (add_req->gc == NULL || add_req->uid == 0) {
 		g_free(add_req);
@@ -63,48 +66,47 @@ static void group_quit_cb(qq_add_request
 	gc = add_req->gc;
 	id = add_req->uid;
 
-	group = qq_room_search_id(gc, id);
-	if (group == NULL) {
+	rmd = qq_room_data_find(gc, id);
+	if (rmd == NULL) {
 		g_free(add_req);
 		return;
 	}
 
-	qq_send_room_cmd_only(gc, QQ_ROOM_CMD_QUIT, group->id);
+	qq_send_room_cmd_only(gc, QQ_ROOM_CMD_QUIT, rmd->id);
 	g_free(add_req);
 }
 
 /* send packet to join a group without auth */
-void qq_request_room_join(PurpleConnection *gc, qq_group *group)
+void qq_request_room_join(PurpleConnection *gc, qq_room_data *rmd)
 {
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(rmd != NULL);
 
-	if (group->my_role == QQ_ROOM_ROLE_NO) {
-		group->my_role = QQ_ROOM_ROLE_REQUESTING;
-		qq_group_refresh(gc, group);
+	if (rmd->my_role == QQ_ROOM_ROLE_NO) {
+		rmd->my_role = QQ_ROOM_ROLE_REQUESTING;
 	}
 
-	switch (group->auth_type) {
+	switch (rmd->auth_type) {
 	case QQ_ROOM_AUTH_TYPE_NO_AUTH:
 	case QQ_ROOM_AUTH_TYPE_NEED_AUTH:
 		break;
 	case QQ_ROOM_AUTH_TYPE_NO_ADD:
-		if (group->my_role == QQ_ROOM_ROLE_NO
-				&& group->my_role == QQ_ROOM_ROLE_REQUESTING) {
+		if (rmd->my_role == QQ_ROOM_ROLE_NO
+				&& rmd->my_role == QQ_ROOM_ROLE_REQUESTING) {
 			purple_notify_warning(gc, NULL, _("The Qun does not allow others to join"), NULL);
 			return;
 		}
 		break;
 	default:
-		purple_debug_error("QQ", "Unknown room auth type: %d\n", group->auth_type);
+		purple_debug_error("QQ", "Unknown room auth type: %d\n", rmd->auth_type);
 		break;
 	}
 
-	qq_send_room_cmd_only(gc, QQ_ROOM_CMD_JOIN, group->id);
+	qq_send_room_cmd_only(gc, QQ_ROOM_CMD_JOIN, rmd->id);
 }
 
 static void group_join_cb(qq_add_request *add_req, const gchar *reason_utf8)
 {
-	qq_group *group;
+	qq_room_data *rmd;
 
 	g_return_if_fail(add_req != NULL);
 	if (add_req->gc == NULL || add_req->uid == 0) {
@@ -112,14 +114,14 @@ static void group_join_cb(qq_add_request
 		return;
 	}
 
-	group = qq_room_search_id(add_req->gc, add_req->uid);
-	if (group == NULL) {
-		purple_debug_error("QQ", "Can not find qq_group by internal_id: %d\n", add_req->uid);
+	rmd = qq_room_data_find(add_req->gc, add_req->uid);
+	if (rmd == NULL) {
+		purple_debug_error("QQ", "Can not find qq_room_data by internal_id: %d\n", add_req->uid);
 		g_free(add_req);
 		return;
 	}
 
-	qq_send_cmd_group_auth(add_req->gc, group, QQ_ROOM_AUTH_REQUEST_APPLY, 0, reason_utf8);
+	qq_send_cmd_group_auth(add_req->gc, rmd, QQ_ROOM_AUTH_REQUEST_APPLY, 0, reason_utf8);
 	g_free(add_req);
 }
 
@@ -129,36 +131,36 @@ void qq_group_cancel_cb(qq_add_request *
 	g_free(add_req);
 }
 
-static void _qq_group_join_auth(PurpleConnection *gc, qq_group *group)
+static void _qq_group_join_auth(PurpleConnection *gc, qq_room_data *rmd)
 {
 	gchar *msg;
 	qq_add_request *add_req;
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(rmd != NULL);
 
-	purple_debug_info("QQ", "Group (internal id: %d) needs authentication\n", group->id);
+	purple_debug_info("QQ", "Group (internal id: %d) needs authentication\n", rmd->id);
 
-	msg = g_strdup_printf("Group \"%s\" needs authentication\n", group->title_utf8);
+	msg = g_strdup_printf("Group \"%s\" needs authentication\n", rmd->title_utf8);
 	add_req = g_new0(qq_add_request, 1);
 	add_req->gc = gc;
-	add_req->uid = group->id;
+	add_req->uid = rmd->id;
 	purple_request_input(gc, NULL, msg,
 			   _("Input request here"),
 			   _("Would you be my friend?"), TRUE, FALSE, NULL,
 			   _("Send"),
 			   G_CALLBACK(group_join_cb),
 			   _("Cancel"), G_CALLBACK(qq_group_cancel_cb),
-			   purple_connection_get_account(gc), group->title_utf8, NULL,
+			   purple_connection_get_account(gc), rmd->title_utf8, NULL,
 			   add_req);
 	g_free(msg);
 }
 
-void qq_send_cmd_group_auth(PurpleConnection *gc, qq_group *group, guint8 opt, guint32 uid, const gchar *reason_utf8)
+void qq_send_cmd_group_auth(PurpleConnection *gc, qq_room_data *rmd, guint8 opt, guint32 uid, const gchar *reason_utf8)
 {
 	guint8 *raw_data;
 	gchar *reason_qq;
 	gint bytes;
 
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(rmd != NULL);
 
 	if (reason_utf8 == NULL || strlen(reason_utf8) == 0)
 		reason_qq = g_strdup("");
@@ -166,8 +168,7 @@ void qq_send_cmd_group_auth(PurpleConnec
 		reason_qq = utf8_to_qq(reason_utf8, QQ_CHARSET_DEFAULT);
 
 	if (opt == QQ_ROOM_AUTH_REQUEST_APPLY) {
-		group->my_role = QQ_ROOM_ROLE_REQUESTING;
-		qq_group_refresh(gc, group);
+		rmd->my_role = QQ_ROOM_ROLE_REQUESTING;
 		uid = 0;
 	}
 
@@ -179,18 +180,15 @@ void qq_send_cmd_group_auth(PurpleConnec
 	bytes += qq_put8(raw_data + bytes, strlen(reason_qq));
 	bytes += qq_putdata(raw_data + bytes, (guint8 *) reason_qq, strlen(reason_qq));
 
-	qq_send_room_cmd(gc, QQ_ROOM_CMD_AUTH, group->id, raw_data, bytes);
+	qq_send_room_cmd(gc, QQ_ROOM_CMD_AUTH, rmd->id, raw_data, bytes);
 }
 
 /* If comes here, cmd is OK already */
 void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc)
 {
+	qq_data *qd;
 	gint bytes;
 	guint32 id;
-	PurpleChat *chat;
-	qq_group *group;
-	qq_data *qd;
-	gchar *msg;
 
 	g_return_if_fail(data != NULL && len > 0);
 	qd = (qq_data *) gc->proto_data;
@@ -203,20 +201,7 @@ void qq_process_group_cmd_exit_group(gui
 	bytes = 0;
 	bytes += qq_get32(&id, data + bytes);
 
-	group = qq_room_search_id(gc, id);
-	if (group != NULL) {
-		msg = g_strdup_printf(_("Successed quit Qun %s (%d)"),
-				group->title_utf8, group->ext_id);
-		chat = purple_blist_find_chat
-			    (purple_connection_get_account(gc), g_strdup_printf("%d", group->ext_id));
-		if (chat != NULL)
-			purple_blist_remove_chat(chat);
-		qq_group_delete_internal_record(qd, id);
-	} else {
-		msg = g_strdup(_("Successed quit Qun"));
-	}
-	qq_got_attention(gc, msg);
-	g_free(msg);
+	qq_room_remove(gc, id);
 }
 
 /* Process the reply to group_auth subcmd */
@@ -225,7 +210,7 @@ void qq_process_group_cmd_join_group_aut
 	gint bytes;
 	guint32 id;
 	qq_data *qd;
-	qq_group *group;
+	qq_room_data *rmd;
 	gchar *msg;
 
 	g_return_if_fail(data != NULL && len > 0);
@@ -240,9 +225,9 @@ void qq_process_group_cmd_join_group_aut
 	bytes += qq_get32(&id, data + bytes);
 	g_return_if_fail(id > 0);
 
-	group = qq_room_search_id(gc, id);
-	if (group != NULL) {
-		msg = g_strdup_printf(_("Successed join to Qun %s (%d)"), group->title_utf8, group->ext_id);
+	rmd = qq_room_data_find(gc, id);
+	if (rmd != NULL) {
+		msg = g_strdup_printf(_("Successed join to Qun %s (%d)"), rmd->title_utf8, rmd->ext_id);
 		qq_got_attention(gc, msg);
 		g_free(msg);
 	} else {
@@ -256,14 +241,14 @@ void qq_process_group_cmd_join_group(gui
 	gint bytes;
 	guint32 id;
 	guint8 reply;
-	qq_group *group;
+	qq_room_data *rmd;
 	gchar *msg;
 
 	g_return_if_fail(data != NULL && len > 0);
 
 	if (len < 5) {
 		purple_debug_error("QQ",
-			   "Invalid join group reply, expect %d bytes, read %d bytes\n", 5, len);
+			   "Invalid join room reply, expect %d bytes, read %d bytes\n", 5, len);
 		return;
 	}
 
@@ -272,34 +257,32 @@ void qq_process_group_cmd_join_group(gui
 	bytes += qq_get8(&reply, data + bytes);
 
 	/* join group OK */
-	group = qq_room_search_id(gc, id);
+	rmd = qq_room_data_find(gc, id);
 	/* need to check if group is NULL or not. */
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(rmd != NULL);
 	switch (reply) {
 	case QQ_ROOM_JOIN_OK:
-		purple_debug_info("QQ", "Successed in joining group \"%s\"\n", group->title_utf8);
-		group->my_role = QQ_ROOM_ROLE_YES;
-		qq_group_refresh(gc, group);
+		purple_debug_info("QQ", "Successed in joining group \"%s\"\n", rmd->title_utf8);
+		rmd->my_role = QQ_ROOM_ROLE_YES;
 		/* this must be shown before getting online members */
-		qq_room_conv_open(gc, group);
+		qq_room_conv_open(gc, rmd);
 		break;
 	case QQ_ROOM_JOIN_NEED_AUTH:
 		purple_debug_info("QQ",
 			   "Fail joining group [%d] %s, needs authentication\n",
-			   group->ext_id, group->title_utf8);
-		group->my_role = QQ_ROOM_ROLE_NO;
-		qq_group_refresh(gc, group);
-		_qq_group_join_auth(gc, group);
+			   rmd->ext_id, rmd->title_utf8);
+		rmd->my_role = QQ_ROOM_ROLE_NO;
+		_qq_group_join_auth(gc, rmd);
 		break;
 	case QQ_ROOM_JOIN_DENIED:
-		msg = g_strdup_printf(_("Qun %d denied to join"), group->ext_id);
+		msg = g_strdup_printf(_("Qun %d denied to join"), rmd->ext_id);
 		purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), msg);
 		g_free(msg);
 		break;
 	default:
 		purple_debug_info("QQ",
 			   "Failed joining group [%d] %s, unknown reply: 0x%02x\n",
-			   group->ext_id, group->title_utf8, reply);
+			   rmd->ext_id, rmd->title_utf8, reply);
 
 		purple_notify_info(gc, _("QQ Qun Operation"), _("Failed:"), _("Join Qun, Unknow Reply"));
 	}
@@ -313,7 +296,7 @@ void qq_group_join(PurpleConnection *gc,
 	gchar *id_str;
 	guint32 ext_id;
 	guint32 id;
-	qq_group *group;
+	qq_room_data *rmd;
 
 	g_return_if_fail(data != NULL);
 	qd = (qq_data *) gc->proto_data;
@@ -325,9 +308,9 @@ void qq_group_join(PurpleConnection *gc,
 	if (id_str != NULL) {
 		id = strtol(id_str, NULL, 10);
 		if (id != 0) {
-			group = qq_room_search_id(gc, id);
-			if (group) {
-				qq_request_room_join(gc, group);
+			rmd = qq_room_data_find(gc, id);
+			if (rmd) {
+				qq_request_room_join(gc, rmd);
 				return;
 			}
 		}
@@ -362,3 +345,93 @@ void qq_room_quit(PurpleConnection *gc, 
 			    G_CALLBACK(qq_group_cancel_cb),
 			    _("Continue"), G_CALLBACK(group_quit_cb));
 }
+
+/* send packet to search for qq_group */
+void qq_request_room_search(PurpleConnection *gc, guint32 ext_id, int action)
+{
+	guint8 raw_data[16] = {0};
+	gint bytes = 0;
+	guint8 type;
+
+	purple_debug_info("QQ", "Search QQ Qun %d\n", ext_id);
+	type = (ext_id == 0x00000000) ? QQ_ROOM_SEARCH_TYPE_DEMO : QQ_ROOM_SEARCH_TYPE_BY_ID;
+
+	bytes = 0;
+	bytes += qq_put8(raw_data + bytes, type);
+	bytes += qq_put32(raw_data + bytes, ext_id);
+
+	qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_SEARCH, 0, raw_data, bytes, 0, action);
+}
+
+static void add_to_roomlist(qq_data *qd, qq_room_data *rmd)
+{
+	PurpleRoomlistRoom *room;
+	gchar field[11];
+
+	room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, rmd->title_utf8, NULL);
+	g_snprintf(field, sizeof(field), "%d", rmd->ext_id);
+	purple_roomlist_room_add_field(qd->roomlist, room, field);
+	g_snprintf(field, sizeof(field), "%d", rmd->creator_uid);
+	purple_roomlist_room_add_field(qd->roomlist, room, field);
+	purple_roomlist_room_add_field(qd->roomlist, room, rmd->desc_utf8);
+	g_snprintf(field, sizeof(field), "%d", rmd->id);
+	purple_roomlist_room_add_field(qd->roomlist, room, field);
+	g_snprintf(field, sizeof(field), "%d", rmd->type8);
+	purple_roomlist_room_add_field(qd->roomlist, room, field);
+	g_snprintf(field, sizeof(field), "%d", rmd->auth_type);
+	purple_roomlist_room_add_field(qd->roomlist, room, field);
+	g_snprintf(field, sizeof(field), "%d", rmd->category);
+	purple_roomlist_room_add_field(qd->roomlist, room, field);
+	purple_roomlist_room_add_field(qd->roomlist, room, rmd->title_utf8);
+	purple_roomlist_room_add(qd->roomlist, room);
+
+	purple_roomlist_set_in_progress(qd->roomlist, FALSE);
+}
+
+/* process group cmd reply "search group" */
+void qq_process_room_search(PurpleConnection *gc, guint8 *data, gint len, guint32 ship32)
+{
+	qq_data *qd;
+	qq_room_data rmd;
+	PurpleChat *chat;
+	gint bytes;
+	guint8 search_type;
+	guint16 unknown;
+
+	g_return_if_fail(data != NULL && len > 0);
+	qd = (qq_data *) gc->proto_data;
+
+	bytes = 0;
+	bytes += qq_get8(&search_type, data + bytes);
+
+	/* now it starts with group_info_entry */
+	bytes += qq_get32(&(rmd.id), data + bytes);
+	bytes += qq_get32(&(rmd.ext_id), data + bytes);
+	bytes += qq_get8(&(rmd.type8), data + bytes);
+	bytes += qq_get16(&(unknown), data + bytes);
+	bytes += qq_get16(&(unknown), data + bytes);
+	bytes += qq_get32(&(rmd.creator_uid), data + bytes);
+	bytes += qq_get16(&(unknown), data + bytes);
+	bytes += qq_get16(&(unknown), data + bytes);
+	bytes += qq_get16(&(unknown), data + bytes);
+	bytes += qq_get32(&(rmd.category), data + bytes);
+	bytes += qq_get_vstr(&(rmd.title_utf8), QQ_CHARSET_DEFAULT, data + bytes);
+	bytes += qq_get16(&(unknown), data + bytes);
+	bytes += qq_get8(&(rmd.auth_type), data + bytes);
+	bytes += qq_get_vstr(&(rmd.desc_utf8), QQ_CHARSET_DEFAULT, data + bytes);
+	/* end of one qq_group */
+	if(bytes != len) {
+		purple_debug_error("QQ",
+			"group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!");
+	}
+
+	if (ship32 == QQ_ROOM_SEARCH_FOR_JOIN) {
+		chat = qq_room_find_or_new(gc, rmd.id, rmd.ext_id);
+		g_return_if_fail(chat != NULL);
+
+		qq_room_update_chat_info(gc, &rmd);
+		qq_request_room_join(gc, &rmd);
+	} else {
+		add_to_roomlist(qd, &rmd);
+	}
+}
============================================================
--- libpurple/protocols/qq/group_join.h	d62ecf529569c417090801dcdb0ed53b90bfdce0
+++ libpurple/protocols/qq/group_join.h	1fe020878072d80baec186dcc9dfede449de2230
@@ -41,9 +41,17 @@ enum {
 	QQ_ROOM_AUTH_REQUEST_REJECT = 0x03
 };
 
-void qq_send_cmd_group_auth(PurpleConnection *gc, qq_group *group, guint8 opt, guint32 uid, const gchar *reason_utf8);
+enum {
+	QQ_ROOM_SEARCH_ONLY = 0,
+	QQ_ROOM_SEARCH_FOR_JOIN
+};
+
+void qq_request_room_search(PurpleConnection *gc, guint32 ext_id, int action);
+void qq_process_room_search(PurpleConnection *gc, guint8 *data, gint len, guint32 ship32);
+
+void qq_send_cmd_group_auth(PurpleConnection *gc, qq_room_data *rmd, guint8 opt, guint32 uid, const gchar *reason_utf8);
 void qq_group_join(PurpleConnection *gc, GHashTable *data);
-void qq_request_room_join(PurpleConnection *gc, qq_group *group);
+void qq_request_room_join(PurpleConnection *gc, qq_room_data *rmd);
 void qq_room_quit(PurpleConnection *gc, guint32 room_id);
 void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc);
 void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc);
============================================================
--- libpurple/protocols/qq/group_opt.c	cafb06b8361b36e8b863a404f175db03d747ae18
+++ libpurple/protocols/qq/group_opt.c	70dc3b0520a342a60c30aeca1fbf07200d825d0b
@@ -30,7 +30,6 @@
 
 #include "buddy_info.h"
 #include "char_conv.h"
-#include "group_find.h"
 #include "group_internal.h"
 #include "group_info.h"
 #include "group_join.h"
@@ -58,7 +57,7 @@ static void _sort(guint32 *list)
 	qsort (list, i, sizeof (guint32), _compare_guint32);
 }
 
-static void _qq_group_member_opt(PurpleConnection *gc, qq_group *group, gint operation, guint32 *members)
+static void _qq_group_member_opt(PurpleConnection *gc, qq_room_data *rmd, gint operation, guint32 *members)
 {
 	guint8 *data;
 	gint i, count, data_len;
@@ -75,7 +74,7 @@ static void _qq_group_member_opt(PurpleC
 	for (i = 0; i < count; i++)
 		bytes += qq_put32(data + bytes, members[i]);
 
-	qq_send_room_cmd(gc, QQ_ROOM_CMD_MEMBER_OPT, group->id, data, bytes);
+	qq_send_room_cmd(gc, QQ_ROOM_CMD_MEMBER_OPT, rmd->id, data, bytes);
 }
 
 static void _qq_group_do_nothing_with_struct(group_member_opt *g)
@@ -86,11 +85,11 @@ static void _qq_group_reject_application
 
 static void _qq_group_reject_application_real(group_member_opt *g, gchar *msg_utf8)
 {
-	qq_group *group;
+	qq_room_data *rmd;
 	g_return_if_fail(g != NULL && g->gc != NULL && g->id > 0 && g->member > 0);
-	group = qq_room_search_id(g->gc, g->id);
-	g_return_if_fail(group != NULL);
-	qq_send_cmd_group_auth(g->gc, group, QQ_ROOM_AUTH_REQUEST_REJECT, g->member, msg_utf8);
+	rmd = qq_room_data_find(g->gc, g->id);
+	g_return_if_fail(rmd != NULL);
+	qq_send_cmd_group_auth(g->gc, rmd, QQ_ROOM_AUTH_REQUEST_REJECT, g->member, msg_utf8);
 	g_free(g);
 }
 
@@ -131,16 +130,16 @@ void qq_group_approve_application_with_s
 
 void qq_group_approve_application_with_struct(group_member_opt *g)
 {
-	qq_group *group;
+	qq_room_data *rmd;
 	g_return_if_fail(g != NULL && g->gc != NULL && g->id > 0 && g->member > 0);
-	group = qq_room_search_id(g->gc, g->id);
-	g_return_if_fail(group != NULL);
-	qq_send_cmd_group_auth(g->gc, group, QQ_ROOM_AUTH_REQUEST_APPROVE, g->member, "");
-	qq_group_find_or_add_member(g->gc, group, g->member);
+	rmd = qq_room_data_find(g->gc, g->id);
+	g_return_if_fail(rmd != NULL);
+	qq_send_cmd_group_auth(g->gc, rmd, QQ_ROOM_AUTH_REQUEST_APPROVE, g->member, "");
+	qq_room_buddy_find_or_new(g->gc, rmd, g->member);
 	g_free(g);
 }
 
-void qq_group_modify_members(PurpleConnection *gc, qq_group *group, guint32 *new_members)
+void qq_group_modify_members(PurpleConnection *gc, qq_room_data *rmd, guint32 *new_members)
 {
 	guint32 *old_members, *del_members, *add_members;
 	qq_buddy_data *bd;
@@ -148,7 +147,7 @@ void qq_group_modify_members(PurpleConne
 	gint i = 0, old = 0, new = 0, del = 0, add = 0;
 	GList *list;
 
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(rmd != NULL);
 	qd = (qq_data *) gc->proto_data;
 	if (new_members[0] == 0xffffffff)
 		return;
@@ -158,7 +157,7 @@ void qq_group_modify_members(PurpleConne
 	add_members = g_newa(guint32, QQ_QUN_MEMBER_MAX);
 
 	/* construct the old member list */
-	list = group->members;
+	list = rmd->members;
 	while (list != NULL) {
 		bd = (qq_buddy_data *) list->data;
 		if (bd != NULL)
@@ -186,14 +185,14 @@ void qq_group_modify_members(PurpleConne
 	del_members[del] = add_members[add] = 0xffffffff;
 
 	for (i = 0; i < del; i++)
-		qq_group_remove_member_by_uid(group, del_members[i]);
+		qq_room_buddy_remove(rmd, del_members[i]);
 	for (i = 0; i < add; i++)
-		qq_group_find_or_add_member(gc, group, add_members[i]);
+		qq_room_buddy_find_or_new(gc, rmd, add_members[i]);
 
 	if (del > 0)
-		_qq_group_member_opt(gc, group, QQ_ROOM_MEMBER_DEL, del_members);
+		_qq_group_member_opt(gc, rmd, QQ_ROOM_MEMBER_DEL, del_members);
 	if (add > 0)
-		_qq_group_member_opt(gc, group, QQ_ROOM_MEMBER_ADD, add_members);
+		_qq_group_member_opt(gc, rmd, QQ_ROOM_MEMBER_ADD, add_members);
 }
 
 void qq_group_process_modify_members_reply(guint8 *data, gint len, PurpleConnection *gc)
@@ -201,7 +200,7 @@ void qq_group_process_modify_members_rep
 	gint bytes;
 	guint32 id;
 	time_t now = time(NULL);
-	qq_group *group;
+	qq_room_data *rmd;
 	g_return_if_fail(data != NULL);
 
 	bytes = 0;
@@ -209,26 +208,26 @@ void qq_group_process_modify_members_rep
 	g_return_if_fail(id > 0);
 
 	/* we should have its info locally */
-	group = qq_room_search_id(gc, id);
-	g_return_if_fail(group != NULL);
+	rmd = qq_room_data_find(gc, id);
+	g_return_if_fail(rmd != NULL);
 
-	purple_debug_info("QQ", "Succeed in modify members for room %d\n", group->ext_id);
+	purple_debug_info("QQ", "Succeed in modify members for room %d\n", rmd->ext_id);
 
-	qq_room_got_chat_in(gc, group, 0, _("Successed changing Qun member"), now);
+	qq_room_got_chat_in(gc, id, 0, _("Successed changing Qun member"), now);
 }
 
-void qq_room_change_info(PurpleConnection *gc, qq_group *group)
+void qq_room_change_info(PurpleConnection *gc, qq_room_data *rmd)
 {
 	guint8 *data;
 	gint data_len;
 	gint bytes;
 	gchar *group_name, *group_desc, *notice;
 
-	g_return_if_fail(group != NULL);
+	g_return_if_fail(rmd != NULL);
 
-	group_name = group->title_utf8 == NULL ? "" : utf8_to_qq(group->title_utf8, QQ_CHARSET_DEFAULT);
-	group_desc = group->desc_utf8 == NULL ? "" : utf8_to_qq(group->desc_utf8, QQ_CHARSET_DEFAULT);
-	notice = group->notice_utf8 == NULL ? "" : utf8_to_qq(group->notice_utf8, QQ_CHARSET_DEFAULT);
+	group_name = rmd->title_utf8 == NULL ? "" : utf8_to_qq(rmd->title_utf8, QQ_CHARSET_DEFAULT);
+	group_desc = rmd->desc_utf8 == NULL ? "" : utf8_to_qq(rmd->desc_utf8, QQ_CHARSET_DEFAULT);
+	notice = rmd->notice_utf8 == NULL ? "" : utf8_to_qq(rmd->notice_utf8, QQ_CHARSET_DEFAULT);
 
 	data_len = 64 + strlen(group_name) + strlen(group_desc) + strlen(notice);
 	data = g_newa(guint8, data_len);
@@ -236,11 +235,11 @@ void qq_room_change_info(PurpleConnectio
 	/* 005-005 */
 	bytes += qq_put8(data + bytes, 0x01);
 	/* 006-006 */
-	bytes += qq_put8(data + bytes, group->auth_type);
+	bytes += qq_put8(data + bytes, rmd->auth_type);
 	/* 007-008 */
 	bytes += qq_put16(data + bytes, 0x0000);
 	/* 009-010 */
-	bytes += qq_put16(data + bytes, group->category);
+	bytes += qq_put16(data + bytes, rmd->category);
 
 	bytes += qq_put8(data + bytes, strlen(group_name));
 	bytes += qq_putdata(data + bytes, (guint8 *) group_name, strlen(group_name));
@@ -259,14 +258,13 @@ void qq_room_change_info(PurpleConnectio
 			   data_len, bytes);
 		return;
 	}
-	qq_send_room_cmd(gc, QQ_ROOM_CMD_CHANGE_INFO, group->id, data, bytes);
+	qq_send_room_cmd(gc, QQ_ROOM_CMD_CHANGE_INFO, rmd->id, data, bytes);
 }
 
 void qq_group_process_modify_info_reply(guint8 *data, gint len, PurpleConnection *gc)
 {
 	gint bytes;
 	guint32 id;
-	qq_group *group;
 	time_t now = time(NULL);
 
 	g_return_if_fail(data != NULL);
@@ -275,17 +273,12 @@ void qq_group_process_modify_info_reply(
 	bytes += qq_get32(&id, data + bytes);
 	g_return_if_fail(id > 0);
 
-	/* we should have its info locally */
-	group = qq_room_search_id(gc, id);
-	g_return_if_fail(group != NULL);
+	purple_debug_info("QQ", "Succeed modify room info of %d\n", id);
 
-	purple_debug_info("QQ", "Succeed in modify info for Qun %d\n", group->ext_id);
-	qq_group_refresh(gc, group);
-
-	qq_room_got_chat_in(gc, group, 0, _("Successed changing Qun information"), now);
+	qq_room_got_chat_in(gc, id, 0, _("Successed changing Qun information"), now);
 }
 
-/* we create a very simple group first, and then let the user to modify */
+/* we create a very simple room first, and then let the user to modify */
 void qq_room_create_new(PurpleConnection *gc, const gchar *name)
 {
 	guint8 *data;
@@ -328,21 +321,21 @@ static void qq_group_setup_cb(qq_add_req
 
 static void qq_group_setup_cb(qq_add_request *add_req)
 {
-	qq_group *group;
+	qq_room_data *rmd;
 	g_return_if_fail(add_req != NULL);
 	if (add_req->gc == NULL || add_req->uid == 0) {
 		g_free(add_req);
 		return;
 	}
 
-	group = qq_room_search_id(add_req->gc, add_req->uid);
-	if (group == NULL) {
+	rmd = qq_room_data_find(add_req->gc, add_req->uid);
+	if (rmd == NULL) {
 		g_free(add_req);
 		return;
 	}
 
 	/* TODO insert UI code here */
-	/* qq_group_detail_window_show(g->gc, group); */
+	/* qq_group_detail_window_show(g->gc, rmd); */
 	g_free(add_req);
 }
 
@@ -350,7 +343,7 @@ void qq_group_process_create_group_reply
 {
 	gint bytes;
 	guint32 id, ext_id;
-	qq_group *group;
+	qq_room_data *rmd;
 	qq_add_request *add_req;
 	qq_data *qd;
 
@@ -363,15 +356,17 @@ void qq_group_process_create_group_reply
 	bytes += qq_get32(&ext_id, data + bytes);
 	g_return_if_fail(id > 0 && ext_id);
 
-	group = qq_group_create_internal_record(gc, id, ext_id, NULL);
-	group->my_role = QQ_ROOM_ROLE_ADMIN;
-	group->creator_uid = qd->uid;
-	qq_group_refresh(gc, group);
+	qq_room_find_or_new(gc, id, ext_id);
+	rmd = qq_room_data_find(gc, id);
+	g_return_if_fail(rmd != NULL);
 
+	rmd->my_role = QQ_ROOM_ROLE_ADMIN;
+	rmd->creator_uid = qd->uid;
+
 	qq_send_room_cmd_only(gc, QQ_ROOM_CMD_ACTIVATE, id);
-	qq_update_room(gc, 0, group->id);
+	qq_update_room(gc, 0, rmd->id);
 
-	purple_debug_info("QQ", "Succeed in create Qun, external ID %d\n", group->ext_id);
+	purple_debug_info("QQ", "Succeed in create Qun, external ID %d\n", rmd->ext_id);
 
 	add_req = g_new0(qq_add_request, 1);
 	add_req->gc = gc;
@@ -391,7 +386,7 @@ void qq_group_process_activate_group_rep
 {
 	gint bytes;
 	guint32 id;
-	qq_group *group;
+	qq_room_data *rmd;
 	g_return_if_fail(data != NULL);
 
 	bytes = 0;
@@ -399,17 +394,17 @@ void qq_group_process_activate_group_rep
 	g_return_if_fail(id > 0);
 
 	/* we should have its info locally */
-	group = qq_room_search_id(gc, id);
-	g_return_if_fail(group != NULL);
+	rmd = qq_room_data_find(gc, id);
+	g_return_if_fail(rmd != NULL);
 
-	purple_debug_info("QQ", "Succeed in activate Qun %d\n", group->ext_id);
+	purple_debug_info("QQ", "Succeed in activate Qun %d\n", rmd->ext_id);
 }
 
 void qq_group_manage_group(PurpleConnection *gc, GHashTable *data)
 {
 	gchar *id_ptr;
 	guint32 id;
-	qq_group *group;
+	qq_room_data *rmd;
 
 	g_return_if_fail(data != NULL);
 
@@ -417,9 +412,9 @@ void qq_group_manage_group(PurpleConnect
 	id = strtol(id_ptr, NULL, 10);
 	g_return_if_fail(id > 0);
 
-	group = qq_room_search_id(gc, id);
-	g_return_if_fail(group != NULL);
+	rmd = qq_room_data_find(gc, id);
+	g_return_if_fail(rmd != NULL);
 
 	/* XXX insert UI code here */
-	/* qq_group_detail_window_show(gc, group); */
+	/* qq_group_detail_window_show(gc, rmd); */
 }
============================================================
--- libpurple/protocols/qq/group_opt.h	59af741aa7f62b30f0697d841497bb2b6798c546
+++ libpurple/protocols/qq/group_opt.h	7e2d51c7fc054eef4755a6ffd0a580c790a79d82
@@ -47,8 +47,8 @@ enum {
 	QQ_ROOM_MEMBER_DEL
 };
 
-void qq_group_modify_members(PurpleConnection *gc, qq_group *group, guint32 *new_members);
-void qq_room_change_info(PurpleConnection *gc, qq_group *group);
+void qq_group_modify_members(PurpleConnection *gc, qq_room_data *rmd, guint32 *new_members);
+void qq_room_change_info(PurpleConnection *gc, qq_room_data *rmd);
 
 void qq_group_approve_application_with_struct(group_member_opt *g);
 void qq_group_reject_application_with_struct(group_member_opt *g);
============================================================
--- libpurple/protocols/qq/qq.c	139874e3355c73e9e65ce7c1989553b3defabf5d
+++ libpurple/protocols/qq/qq.c	b8139c1c047cb6f1e7ce5b914f4c96e5cce6ecfb
@@ -39,7 +39,6 @@
 #include "buddy_list.h"
 #include "char_conv.h"
 #include "group.h"
-#include "group_find.h"
 #include "group_im.h"
 #include "group_info.h"
 #include "group_join.h"
@@ -777,7 +776,7 @@ static void action_chat_get_info(PurpleB
 	g_return_if_fail(room_id != 0);
 
 	qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, room_id, NULL, 0,
-			QQ_CMD_CLASS_UPDATE_ROOM, QQ_ROOM_INFO_DISPLAY);
+			0, QQ_ROOM_INFO_DISPLAY);
 }
 
 #if 0
============================================================
--- libpurple/protocols/qq/qq_network.c	5cbfee0b21275af288a4f557f80ff08be9d8c430
+++ libpurple/protocols/qq/qq_network.c	fe598869feaa04ec752adfb630fd4c083d7c5042
@@ -28,7 +28,7 @@
 
 #include "buddy_info.h"
 #include "group_info.h"
-#include "group_free.h"
+#include "group_internal.h"
 #include "qq_crypt.h"
 #include "qq_define.h"
 #include "qq_base.h"
@@ -1039,7 +1039,7 @@ void qq_disconnect(PurpleConnection *gc)
 	qd->my_ip.s_addr = 0;
 	qd->my_port = 0;
 
-	qq_group_free_all(gc);
+	qq_room_data_free_all(gc);
 	qq_buddy_data_free_all(gc);
 }
 
============================================================
--- libpurple/protocols/qq/qq_process.c	95b0c1569168d0db3d1f1126b225abaa21096c55
+++ libpurple/protocols/qq/qq_process.c	9832150d77c01c2d340d259e876fc10fe9347709
@@ -33,8 +33,6 @@
 #include "char_conv.h"
 #include "qq_crypt.h"
 
-#include "group_search.h"
-#include "group_find.h"
 #include "group_internal.h"
 #include "group_im.h"
 #include "group_info.h"
@@ -529,36 +527,25 @@ void qq_update_room(PurpleConnection *gc
 void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
 {
 	qq_data *qd;
-	qq_group *group;
 	gint ret;
 
 	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
 	qd = (qq_data *) gc->proto_data;
 
-	group = qq_room_search_id(gc, room_id);
-	if (group == NULL && room_id <= 0) {
-		purple_debug_info("QQ", "No room, nothing update\n");
-		return;
-	}
-	if (group == NULL ) {
-		purple_debug_warning("QQ", "Failed search room id [%d]\n", room_id);
-		return;
-	}
-
 	switch (room_cmd) {
 		case 0:
-			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, group->id, NULL, 0,
+			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, room_id, NULL, 0,
 					QQ_CMD_CLASS_UPDATE_ROOM, 0);
 			break;
 		case QQ_ROOM_CMD_GET_INFO:
-			ret = qq_request_room_get_buddies(gc, group, QQ_CMD_CLASS_UPDATE_ROOM);
+			ret = qq_request_room_get_buddies(gc, room_id, QQ_CMD_CLASS_UPDATE_ROOM);
 			if (ret <= 0) {
-				qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, group->id, NULL, 0,
+				qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, room_id, NULL, 0,
 						QQ_CMD_CLASS_UPDATE_ROOM, 0);
 			}
 			break;
 		case QQ_ROOM_CMD_GET_BUDDIES:
-			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, group->id, NULL, 0,
+			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, room_id, NULL, 0,
 					QQ_CMD_CLASS_UPDATE_ROOM, 0);
 			break;
 		case QQ_ROOM_CMD_GET_ONLINES:
@@ -572,39 +559,42 @@ void qq_update_all_rooms(PurpleConnectio
 {
 	qq_data *qd;
 	gboolean is_new_turn = FALSE;
-	qq_group *next_group;
+	guint32 next_id;
 
 	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
 	qd = (qq_data *) gc->proto_data;
 
-	next_group = qq_room_get_next(gc, room_id);
-	if (next_group == NULL && room_id <= 0) {
-		purple_debug_info("QQ", "No room. Finished update\n");
-		return;
+	next_id = qq_room_get_next(gc, room_id);
+	purple_debug_info("QQ", "Update rooms, next id %d, prev id %d\n", next_id, room_id);
+
+	if (next_id <= 0) {
+		if (room_id > 0) {
+			is_new_turn = TRUE;
+			next_id = qq_room_get_next(gc, 0);
+			purple_debug_info("QQ", "new turn, id %d\n", next_id);
+		} else {
+			purple_debug_info("QQ", "No room. Finished update\n");
+			return;
+		}
 	}
-	if (next_group == NULL ) {
-		is_new_turn = TRUE;
-		next_group = qq_room_get_next(gc, 0);
-		g_return_if_fail(next_group != NULL);
-	}
 
 	switch (room_cmd) {
 		case 0:
-			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_group->id, NULL, 0,
+			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_id, NULL, 0,
 					QQ_CMD_CLASS_UPDATE_ALL, 0);
 			break;
 		case QQ_ROOM_CMD_GET_INFO:
 			if (!is_new_turn) {
-				qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_group->id, NULL, 0,
+				qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_id, NULL, 0,
 						QQ_CMD_CLASS_UPDATE_ALL, 0);
 			} else {
-				qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL);
+				qq_request_room_get_buddies(gc, next_id, QQ_CMD_CLASS_UPDATE_ALL);
 			}
 			break;
 		case QQ_ROOM_CMD_GET_BUDDIES:
 			/* last command */
 			if (!is_new_turn) {
-				qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL);
+				qq_request_room_get_buddies(gc, next_id, QQ_CMD_CLASS_UPDATE_ALL);
 			} else {
 				purple_debug_info("QQ", "Finished update\n");
 			}
@@ -658,28 +648,28 @@ static void update_all_rooms_online(Purp
 static void update_all_rooms_online(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
 {
 	qq_data *qd;
-	qq_group *next_group;
+	guint32 next_id;
 
 	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
 	qd = (qq_data *) gc->proto_data;
 
-	next_group = qq_room_get_next_conv(gc, room_id);
-	if (next_group == NULL && room_id <= 0) {
+	next_id = qq_room_get_next_conv(gc, room_id);
+	if (next_id <= 0 && room_id <= 0) {
 		purple_debug_info("QQ", "No room in conversation, no update online buddies\n");
 		return;
 	}
-	if (next_group == NULL ) {
+	if (next_id <= 0 ) {
 		purple_debug_info("QQ", "finished update rooms' online buddies\n");
 		return;
 	}
 
 	switch (room_cmd) {
 		case 0:
-			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_group->id, NULL, 0,
+			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_id, NULL, 0,
 					QQ_CMD_CLASS_UPDATE_ALL, 0);
 			break;
 		case QQ_ROOM_CMD_GET_ONLINES:
-			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_group->id, NULL, 0,
+			qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_id, NULL, 0,
 					QQ_CMD_CLASS_UPDATE_ALL, 0);
 			break;
 		default:
@@ -714,7 +704,7 @@ void qq_proc_room_cmds(PurpleConnection 
 	qq_data *qd;
 	guint8 *data;
 	gint data_len;
-	qq_group *group;
+	qq_room_data *rmd;
 	gint bytes;
 	guint8 reply_cmd, reply;
 
@@ -760,16 +750,15 @@ void qq_proc_room_cmds(PurpleConnection 
 	if (reply != QQ_ROOM_CMD_REPLY_OK) {
 		switch (reply) {	/* this should be all errors */
 		case QQ_ROOM_CMD_REPLY_NOT_MEMBER:
-			group = qq_room_search_id(gc, room_id);
-			if (group == NULL) {
+			rmd = qq_room_data_find(gc, room_id);
+			if (rmd == NULL) {
 				purple_debug_warning("QQ",
 						"Missing room id in [%05d], 0x%02X %s for %d, len %d\n",
 						seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len);
 			} else {
 				purple_debug_warning("QQ",
-					   _("You are not a member of QQ Qun \"%s\"\n"), group->title_utf8);
-				group->my_role = QQ_ROOM_ROLE_NO;
-				qq_group_refresh(gc, group);
+					   _("Not a member of room \"%s\"\n"), rmd->title_utf8);
+				rmd->my_role = QQ_ROOM_ROLE_NO;
 			}
 			break;
 		case QQ_ROOM_CMD_REPLY_SEARCH_ERROR:
@@ -972,7 +961,7 @@ guint8 qq_proc_login_cmds(PurpleConnecti
 			qd->is_login = TRUE;	/* must be defined after sev_finish_login */
 
 			/* now initiate QQ Qun, do it first as it may take longer to finish */
-			qq_group_init(gc);
+			qq_room_data_initial(gc);
 
 			/* is_login, but we have packets before login */
 			qq_trans_process_remained(gc);


More information about the Commits mailing list