changeset 13989:16102b9c5c4a

[gaim-migrate @ 16562] *Eliminated all Gtk-related code from the prpl. Notably, this included the group ("Qun") administrative dialog and a dialog for setting and viewing personal information. Code for the latter now uses the gaim UI, while the former is currently disabled. *Disabled a few non-functional/non-essential menu actions. These included: IP lookup, system logging, about dialog, and qq_buddy_menu. committer: Tailor Script <tailor@pidgin.im>
author Mark Huetsch <markhuetsch>
date Mon, 24 Jul 2006 13:39:12 +0000
parents 4d5cc9e4cb12
children ff4ee4ac4408
files src/protocols/qq/Makefile.am src/protocols/qq/Makefile.mingw src/protocols/qq/TODO src/protocols/qq/buddy_info.c src/protocols/qq/buddy_info.h src/protocols/qq/buddy_list.c src/protocols/qq/buddy_status.c src/protocols/qq/buddy_status.h src/protocols/qq/group_admindlg.c src/protocols/qq/group_admindlg.h src/protocols/qq/group_opt.c src/protocols/qq/infodlg.c src/protocols/qq/infodlg.h src/protocols/qq/qq.c src/protocols/qq/qq_proxy.c src/protocols/qq/qq_proxy.h src/protocols/qq/show.c src/protocols/qq/show.h src/protocols/qq/utils.c src/protocols/qq/utils.h
diffstat 20 files changed, 625 insertions(+), 2694 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/qq/Makefile.am	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/Makefile.am	Mon Jul 24 13:39:12 2006 +0000
@@ -21,8 +21,6 @@
 	char_conv.h \
 	crypt.c \
 	crypt.h \
-	group_admindlg.c \
-	group_admindlg.h \
 	group.c \
 	group_conv.c \
 	group_conv.h \
@@ -52,8 +50,6 @@
 	header_info.h \
 	im.c \
 	im.h \
-	infodlg.c \
-	infodlg.h \
 	ip_location.c \
 	ip_location.h \
 	keep_alive.c \
@@ -68,8 +64,6 @@
 	send_core.h \
 	sendqueue.c \
 	sendqueue.h \
-	show.c \
-	show.h \
 	sys_msg.c \
 	sys_msg.h \
 	udp_proxy_s5.c \
@@ -104,6 +98,5 @@
 	-DLOCALEDIR=\"${datadir}/locale\" \
         -DVERSION=\"$(VERSION)\" \
         $(DEBUG_CFLAGS) \
-        $(GTK_CFLAGS) \
         $(GLIB_CFLAGS) \
 	$(GAIM_CFLAGS)
--- a/src/protocols/qq/Makefile.mingw	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/Makefile.mingw	Mon Jul 24 13:39:12 2006 +0000
@@ -82,7 +82,6 @@
 	crypt.c \
 	file_trans.c \
 	group.c \
-	group_admindlg.c \
 	group_conv.c \
 	group_find.c \
 	group_free.c \
@@ -96,7 +95,6 @@
 	group_search.c \
 	header_info.c \
 	im.c \
-	infodlg.c \
 	ip_location.c \
 	keep_alive.c \
 	login_logout.c \
--- a/src/protocols/qq/TODO	Mon Jul 24 09:25:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-* Decide how to handle QQ status icons, which are customizable and legion.
-* Give "Online Offline" and "My Offline" statuses appropriate titles.
-* Handle emoticon at beginning of message via passthrough_unknown_commands.
-* Fix file transfer.
-* QQ protocol currently breaks Chinese localization of Gaim. Fix this.
-* Fix ability to insert images into a conversation via the menubar.
-* Fix _qq_menu_block_buddy in qq.c
-* Eliminate all references to QQWry.dat and the geolocation lookup feature previously present OpenQ.
-* Give smileys verbal instead of numerical titles.
-* Clean up signedness warnings.
-* Clean up mixed declaration and code warnings.
-* Better decomposition: 
-** some of these functions are _really_ long
-** buddy_status.c has a helper function which seems to belong in buddy_status.c
-** consider cleaning up qq_encrypt (nested function declarations)
-** eliminate group_misc.c
-** investigate whether all of these externs are appropriate
-* Check for memory leaks.
--- a/src/protocols/qq/buddy_info.c	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/buddy_info.c	Mon Jul 24 13:39:12 2006 +0000
@@ -20,11 +20,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-// START OF FILE
-/*****************************************************************************/
 #include "internal.h"		// strlen, _("get_text)
 #include "debug.h"		// gaim_debug
 #include "notify.h"		// gaim_notify
+#include "request.h"		// gaim_request_fields_new
 
 #include "utils.h"		// uid_to_gaim_name
 #include "packet_parse.h"	// MAX_PACKET_SIZE
@@ -32,68 +31,295 @@
 #include "char_conv.h"		// qq_to_utf8
 #include "crypt.h"		// qq_crypt
 #include "header_info.h"	// cmd alias
-#include "infodlg.h"		// info_window
 #include "keep_alive.h"		// qq_update_buddy_contact
 #include "send_core.h"		// qq_send_cmd
 
-// amount of fiedls in user info
-#define QQ_CONTACT_FIELDS 				37
+// Below is all of the information necessary to reconstruct the various
+// information fields that one can set in the official client. When we need
+// to know about a specific field (e.g., should "city" be a choice
+// or text field?), we can simply look it up from the template. Note that
+// there are a number of unidentified fields.
+
+typedef struct _info_field {
+	gchar *title;
+	gchar *id;		// used by gaim_request fields
+	gint pos;
+	gchar *group;
+	gint group_pos;		// for display order in the UI
+	gint choice;		// indicates which character array contains the choices 
+	gboolean customizable;	// whether a user can enter any text as a value, regardless of choice arrays
+	gchar *value;
+} info_field;
+
+static const info_field info_template_data[] = {
+	{ N_("User ID"), "uid", 		0, QQ_MAIN_INFO, 0, QQ_NO_CHOICE, TRUE, NULL },	
+	{ N_("Nickname"), "nick",		1, QQ_MAIN_INFO, 1, QQ_NO_CHOICE, TRUE, NULL },	
+	{ N_("Country/Region"), "country",	2, QQ_MAIN_INFO, 5, QQ_COUNTRY, TRUE, NULL },
+	{ N_("Province/State"), "province",	3, QQ_MAIN_INFO, 6, QQ_PROVINCE, TRUE, NULL },
+	{ N_("Zipcode"), "zipcode",		4, QQ_EXTRA_INFO, 7, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Address"), "address",		5, QQ_EXTRA_INFO, 6, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Phone Number"), "tel",		6, QQ_EXTRA_INFO, 9, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Age"), "age",			7, QQ_MAIN_INFO, 3, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Gender"), "gender",		8, QQ_MAIN_INFO, 4, QQ_GENDER, FALSE, NULL },
+	{ N_("Name"), "name",			9, QQ_MAIN_INFO, 2, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Email"), "email",			10, QQ_EXTRA_INFO, 5, QQ_NO_CHOICE, TRUE, NULL },
+	{ "pager_sn", "pager_sn",		11, QQ_MISC, 0, QQ_NO_CHOICE, TRUE, NULL },
+	{ "pager_num", "pager_num",		12, QQ_MISC, 1, QQ_NO_CHOICE, TRUE, NULL },
+	{ "pager_sp", "pager_sp",		13, QQ_MISC, 2, QQ_NO_CHOICE, TRUE, NULL },
+	{ "pager_base_num", "pager_base_num",	14, QQ_MISC, 3, QQ_NO_CHOICE, TRUE, NULL },
+	{ "pager_type", "pager_type",		15, QQ_MISC, 4, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Occupation"), "occupation",	16, QQ_EXTRA_INFO, 1, QQ_OCCUPATION, TRUE, NULL },
+	{ N_("Homepage"), "homepage",		17, QQ_EXTRA_INFO, 10, QQ_NO_CHOICE, TRUE, NULL },
+	{ "auth_type", "auth_type",		18, QQ_MISC, 5, QQ_NO_CHOICE, TRUE, NULL },
+	{ "unknown1", "unknown1",		19, QQ_MISC, 6, QQ_NO_CHOICE, TRUE, NULL },
+	{ "unknown2", "unknown2",		20, QQ_MISC, 7, QQ_NO_CHOICE, TRUE, NULL },
+	{ "face", "face",			21, QQ_MISC, 8, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Cellphone Number"), "hp_num",	22, QQ_EXTRA_INFO, 8, QQ_NO_CHOICE, TRUE, NULL },
+	{ "hp_type", "hp_type",			23, QQ_MISC, 9, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Personal Introduction"), "intro",	24, QQ_PERSONAL_INTRO, 0, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("City"), "city",			25, QQ_MAIN_INFO, 7, QQ_NO_CHOICE, TRUE, NULL },
+	{ "unknown3", "unknown3",		26, QQ_MISC, 10, QQ_NO_CHOICE, TRUE, NULL },
+	{ "unknown4", "unknown4",		27, QQ_MISC, 11, QQ_NO_CHOICE, TRUE, NULL },
+	{ "unknown5", "unknown5",		28, QQ_MISC, 12, QQ_NO_CHOICE, TRUE, NULL },
+	{ "is_open_hp",	"is_open_hp",		29, QQ_MISC, 13, QQ_NO_CHOICE, TRUE, NULL },
+	{ "is_open_contact", "is_open_contact",	30, QQ_MISC, 14, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("College"), "college",		31, QQ_EXTRA_INFO, 4, QQ_NO_CHOICE, TRUE, NULL },
+	{ N_("Horoscope Symbol"), "horoscope",	32, QQ_EXTRA_INFO, 0, QQ_HOROSCOPE, FALSE, NULL },
+	{ N_("Zodiac Symbol"), "zodiac",	33, QQ_EXTRA_INFO, 2, QQ_ZODIAC, FALSE, NULL },
+	{ N_("Blood Type"), "blood",		34, QQ_EXTRA_INFO, 3, QQ_BLOOD, FALSE, NULL },
+	{ "qq_show", "qq_show",			35, QQ_MISC, 15, QQ_NO_CHOICE, TRUE, NULL },
+	{ "unknown6", "unknown6",		36, QQ_MISC, 16, QQ_NO_CHOICE, TRUE, NULL },
+	{ NULL,	NULL, 0, NULL, 0, 0, 0, NULL	}	//NULL termination
+};
+
+//TODO: translate these arrays to their English equivalents
+// and move these characters to the zh_CN po file
+static const gchar *horoscope_names[] = {
+	"-", "水瓶座", "双鱼座", "牡羊座", "金牛座",
+	"双子座", "巨蟹座", "狮子座", "处女座", "天秤座",
+        "天蝎座", "射手座", "魔羯座", NULL
+};
+
+static const gchar *zodiac_names[] = {
+	"-", "鼠", "牛", "虎", "兔",
+	"龙", "蛇", "马", "羊", "猴",
+	"鸡", "狗", "猪", NULL
+};
+
+static const gchar *blood_types[] = {
+	"其它", "A型", "B型", "O型", "AB型", NULL
+};
+
+static const gchar *genders[] = {
+	N_("Male"),
+	N_("Female"),
+	NULL
+};
+
+static const gchar *country_names[] = {
+        "中国", "中国香港", "中国澳门", "中国台湾",
+        "新加坡", "马来西亚", "美国", NULL
+};
+
+static const gchar *province_names[] = {
+        "北京", "天津", "上海", "重庆", "香港",
+        "河北", "山西", "内蒙古", "辽宁", "吉林",
+        "黑龙江", "江西", "浙江", "江苏", "安徽",
+        "福建", "山东", "河南", "湖北", "湖南",
+        "广东", "广西", "海南", "四川", "贵州",
+        "云南", "西藏", "陕西", "甘肃", "宁夏",
+        "青海", "新疆", "台湾", "澳门", NULL
+};
+
+static const gchar *occupation_names[] = {
+        "全职", "兼职", "制造业", "商业", "失业中",
+        "学生", "工程师", "政府部门", "教育业", "服务行业",
+        "老板", "计算机业", "退休", "金融业",
+        "销售/广告/市场", NULL
+};
+
+static const gint choice_sizes[] = { 0, 13, 13, 5, 2, 7, 34, 15 };
+
+
+static const gchar *info_group_headers[] = {
+       QQ_MAIN_INFO,
+       QQ_EXTRA_INFO,
+       QQ_PERSONAL_INTRO,
+       QQ_MISC
+};
 
-// There is no user id stored in the reply packet for information query
-// we have to manually store the query, so that we know the query source
-typedef struct _qq_info_query {
-	guint32 uid;
-	gboolean show_window;
-	contact_info *ret_info;
-} qq_info_query;
+static const gchar **choices[] = {
+        NULL,
+        horoscope_names,
+        zodiac_names,
+        blood_types,
+        genders,
+        country_names,
+        province_names,
+        occupation_names
+};
+
+/*************** info and info_field methods *****************/
+
+// Given an id, return the template for that field.
+// Returns NULL if the id is not found.
+static const info_field *info_field_get_template(const gchar *id)
+{
+	const info_field *cur_field;
+	const gchar *cur_id;
+	
+	cur_field = info_template_data;
+	cur_id = cur_field->id;
+	while(cur_id != NULL) {
+		if (g_ascii_strcasecmp(cur_id, id) == 0) return cur_field;
+		cur_field++;
+		cur_id = cur_field->id;
+	}
+	gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Info field with id %s not found!", id);
+	return NULL;
+}
+
+// info_fields are compared by their group positions
+static gint info_field_compare(gconstpointer a, gconstpointer b, gpointer unused)
+{
+	return ((info_field *) a)->group_pos - ((info_field *) b)->group_pos;
+}
+
+static void info_field_free(info_field *i)
+{
+	g_free(i->value);
+	g_free(i);
+}
+
+// Parses the info_template_data above and returns a newly-allocated list
+// containing the desired fields from segments. This list is ordered by
+// group_pos.
+static GList *info_get_group(const gchar **info, const gchar *group_name)
+{
+	const info_field *cur;
+       	info_field *entry;
+	GList *group = NULL;
+
+	cur = info_template_data;
+	while (cur->id != NULL) {
+		if (g_ascii_strcasecmp(group_name, cur->group) == 0) {
+			entry = g_memdup(cur, sizeof(info_field));
+			entry->value = g_strdup(info[entry->pos]);
+			group = g_list_insert_sorted_with_data(group, entry, info_field_compare, NULL);
+		}
+		cur++;
+	}
+
+	return group;
+}
 
-/*****************************************************************************/
-// send a packet to get detailed information of uid,
-// if show_window, a info window will be display upon receiving a reply
+// determines if the given text value and choice group require
+// a lookup from the choice arrays
+static gboolean is_valid_index(gchar *value, gint choice)
+{
+	gint len, i;
+
+	if (choice == 0) return FALSE;
+	len = strlen(value);
+	// the server sends us an ascii index and none of arrays has more than 99
+	// elements
+	if (len > 3 || len == 0) return FALSE;
+	for (i = 0; i < len; i++)
+		if (!g_ascii_isdigit(value[i])) return FALSE;
+	i = atoi(value);
+	if (i < 0 || i >= choice_sizes[choice]) return FALSE; 
+	return TRUE;
+}
+
+// formats a field for printing
+static void append_field_to_str(gpointer field, gpointer str)
+{
+	info_field *f;
+	gint choice;
+	gboolean valid_index;
+	gchar *value;
+
+	f = (info_field *) field;
+	choice = f->choice;
+	valid_index = is_valid_index(f->value, choice);
+	if (choice && valid_index) value = g_strdup(choices[choice][atoi(f->value)]);
+	else value = qq_to_utf8(f->value, QQ_CHARSET_DEFAULT);
+	g_string_append_printf((GString *) str, "<b>%s:</b> %s<br />",
+			f->title, value);
+	g_free(value);
+	info_field_free(f);
+}
+
+// formats a group of information for printing
+static void append_group_to_str(GString *str, const gchar *group_name, const gchar **info)
+{
+	GList *group;
+
+	group = info_get_group(info, group_name);
+	g_string_append_printf(str, "<b>%s</b><br /><br />", (*(info_field *) group->data).group);
+	g_list_foreach(group, append_field_to_str, str);
+	g_list_free(group);
+	g_string_append_printf(str, "<br />");
+}
+
+// takes a contact_info struct and outputs the appropriate fields in
+// a printable format for our upcoming call to gaim_notify_userinfo
+static GString *info_to_str(const gchar **info)
+{
+	GString *info_text;
+
+	info_text = g_string_new("");
+	append_group_to_str(info_text, QQ_MAIN_INFO, info);
+	append_group_to_str(info_text, QQ_EXTRA_INFO, info);
+	append_group_to_str(info_text, QQ_PERSONAL_INTRO, info);
+	//if (QQ_DEBUG) append_group_to_str(info_text, QQ_MISC, info);
+
+	return info_text;
+}
+
+/*************** packets and UI management *****************/
+
+// send a packet to get detailed information of uid
 void qq_send_packet_get_info(GaimConnection * gc, guint32 uid, gboolean show_window)
 {
 	qq_data *qd;
 	gchar *uid_str;
-	GList *list;
 	qq_info_query *query;
-	gboolean is_exist;
-	contact_info_window *info_window;
 
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL && uid != 0);
 
 	qd = (qq_data *) gc->proto_data;
 	uid_str = g_strdup_printf("%d", uid);
-	qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, TRUE, 0, TRUE, uid_str, strlen(uid_str));
-
-	if (show_window) {	// prepare the window
-		is_exist = FALSE;	// see if there is already a window for this uid
-		list = qd->contact_info_window;
-		while (list != NULL) {
-			info_window = (contact_info_window *) list->data;
-			if (uid == info_window->uid) {
-				is_exist = TRUE;
-				break;
-			} else
-				list = list->next;
-		}		// while list
-		if (!is_exist) {	// create a new one
-			info_window = g_new0(contact_info_window, 1);
-			info_window->uid = uid;
-			qd->contact_info_window = g_list_append(qd->contact_info_window, info_window);
-		}		// if !is_exist
-	}			// if show_window
+	qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, TRUE, 0, TRUE, (guint8 *) uid_str, strlen(uid_str));
 
 	query = g_new0(qq_info_query, 1);
 	query->uid = uid;
 	query->show_window = show_window;
+	query->modify_info = FALSE;
 	qd->info_query = g_list_append(qd->info_query, query);
 
 	g_free(uid_str);
-}				// qq_send_packet_get_info
+}
+
+// set up the fields requesting personal information and send a get_info packet
+// for myself
+void qq_prepare_modify_info(GaimConnection *gc)
+{
+	qq_data *qd;
+	GList *ql;
+	qq_info_query *query;
 
-/*****************************************************************************/
+	qd = (qq_data *) gc->proto_data;
+	qq_send_packet_get_info(gc, qd->uid, FALSE);
+	// traverse backwards so we get the most recent info_query
+	for (ql = g_list_last(qd->info_query); ql != NULL; ql = g_list_previous(ql)) {
+		query = ql->data;
+		if (query->uid == qd->uid) query->modify_info = TRUE;
+	}
+}
+
 // send packet to modify personal information, and/or change password
-void qq_send_packet_modify_info(GaimConnection * gc, contact_info * info, gchar * new_passwd)
+void qq_send_packet_modify_info(GaimConnection *gc, contact_info *info, gchar *new_passwd)
 {
 	GaimAccount *a;
 	gchar *old_passwd, *info_field[QQ_CONTACT_FIELDS];
@@ -112,26 +338,174 @@
 
 	if (new_passwd == NULL || strlen(new_passwd) == 0)
 		create_packet_b(raw_data, &cursor, bar);
-	else {			// we gonna change passwd
-		create_packet_data(raw_data, &cursor, old_passwd, strlen(old_passwd));
+	else {			// we're gonna change passwd
+		create_packet_data(raw_data, &cursor, (guint8 *) old_passwd, strlen(old_passwd));
 		create_packet_b(raw_data, &cursor, bar);
-		create_packet_data(raw_data, &cursor, new_passwd, strlen(new_passwd));
+		create_packet_data(raw_data, &cursor, (guint8 *) new_passwd, strlen(new_passwd));
 	}
 
 	// important!, skip the first uid entry
 	for (i = 1; i < QQ_CONTACT_FIELDS; i++) {
 		create_packet_b(raw_data, &cursor, bar);
-		create_packet_data(raw_data, &cursor, info_field[i], strlen(info_field[i]));
+		create_packet_data(raw_data, &cursor, (guint8 *) info_field[i], strlen(info_field[i]));
 	}
 	create_packet_b(raw_data, &cursor, bar);
 
 	qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, TRUE, 0, TRUE, raw_data, cursor - raw_data);
 
-}				// qq_send_packet_modify_info
+}
+
+static void modify_info_cancel_cb(modify_info_data *mid)
+{
+	g_list_free(mid->misc);
+	g_free(mid);
+}
+
+// runs through all of the fields in the modify info UI and put
+// their values into the outgoing packet
+static void parse_field(gpointer field, gpointer outgoing_info)
+{
+	GaimRequestField *f;
+	gchar **segments, *value;
+	const info_field *ft;
+	const gchar *id;
+
+	f = (GaimRequestField *) field;
+	segments = (gchar **) outgoing_info;
+	id = gaim_request_field_get_id(f);
+	ft = info_field_get_template(id);
+	if (ft->choice && !ft->customizable) 
+		value = g_strdup_printf("%d", gaim_request_field_choice_get_value(f));
+	else {
+		value = (gchar *) gaim_request_field_string_get_value(f);
+		if (value == NULL) value = g_strdup("");
+		else value = utf8_to_qq(value, QQ_CHARSET_DEFAULT);
+	}
+	segments[ft->pos] = value;
+}
+
+// dumps the uneditable information straight into the outgoing packet 
+static void parse_misc_field(gpointer field, gpointer outgoing_info)
+{
+	info_field *f;
+	gchar **segments;
+
+	f = (info_field *) field;
+	segments = (gchar **) outgoing_info;
+	segments[f->pos] = g_strdup(f->value);
+	info_field_free(f);
+}
+
+// runs through all of the information fields and copies them into an
+// outgoing packet, then sends that packet
+static void modify_info_ok_cb(modify_info_data *mid, GaimRequestFields *fields)
+{
+	GaimConnection *gc;
+	GList *list,  *groups, *group_node;
+	gchar *info_field[QQ_CONTACT_FIELDS];
+	contact_info *info;
+	gint i;
+
+	gc = mid->gc;
+	list = mid->misc;
+	g_list_foreach(list, parse_misc_field, info_field);
+	g_list_free(list);
+	groups = gaim_request_fields_get_groups(fields);
+	while(groups) {
+		group_node = groups;
+		list = gaim_request_field_group_get_fields(group_node->data);
+		g_list_foreach(list, parse_field, info_field);
+		groups = g_list_remove_link(groups, group_node);
+	}
+	info = (contact_info *) info_field;
+
+	qq_send_packet_modify_info(gc, info, NULL);
+	g_free(mid);
+	for (i = 0; i < QQ_CONTACT_FIELDS; i++)
+		g_free(info_field[i]);
+}
 
-/*****************************************************************************/
-// process the reply of modidy_info packet
-void qq_process_modify_info_reply(guint8 * buf, gint buf_len, GaimConnection * gc)
+// Sets up the display for one group of information. This includes
+// managing which fields in the UI should be textfields and
+// which choices, and also mapping ints to choice values when appropriate.
+static void setup_group(gpointer field, gpointer group)
+{
+	info_field *f;
+	GaimRequestFieldGroup *g;
+	GaimRequestField *rf;
+	gint choice, index, j;
+	gboolean customizable, valid_index, multiline;
+	gchar *id, *value;
+
+	f = (info_field *) field;
+	g = (GaimRequestFieldGroup *) group;
+	choice = f->choice;
+	customizable = f->customizable;
+	id = f->id;
+	valid_index = TRUE;
+
+	if (!choice || customizable) {
+		valid_index = is_valid_index(f->value, choice);
+		multiline = id == "intro";
+		if (valid_index) {
+			index = atoi(f->value);
+			value = (gchar *) choices[choice][index];
+		} else value = qq_to_utf8(f->value, QQ_CHARSET_DEFAULT);
+		rf = gaim_request_field_string_new(id, f->title, value, multiline);
+	} else {
+		index = atoi(f->value);
+		value = (gchar *) choices[choice][index];
+		rf = gaim_request_field_choice_new(id, f->title, index);
+		j = 0;
+		while(choices[choice][j] != NULL)
+			gaim_request_field_choice_add(rf, choices[choice][j++]);
+	}
+	gaim_request_field_group_add_field(g, rf);
+	if (!valid_index) g_free(value);
+	info_field_free(f);
+}
+
+// Takes the info returned by a get_info packet for the user and sets up
+// a form using those values and the info_template.
+static void create_modify_info_dialogue(GaimConnection *gc, const gchar **info)
+{
+	GaimRequestFields *fields;
+	GaimRequestFieldGroup *group;
+	GaimRequestField *field;
+	GList *group_list;
+	modify_info_data *mid;
+	gint i;
+
+	fields = gaim_request_fields_new();
+	
+	// we only care about the first 3 groups, not the miscellaneous stuff
+	for (i = 0; i < 3; i++) {
+		group = gaim_request_field_group_new(info_group_headers[i]);
+		gaim_request_fields_add_group(fields, group);
+		group_list = info_get_group(info, info_group_headers[i]);
+		g_list_foreach(group_list, setup_group, group);
+		g_list_free(group_list);
+	}
+
+	//set this manually here instead of generating a new template column
+	field = gaim_request_fields_get_field(fields, "uid");
+	gaim_request_field_string_set_editable(field, FALSE);
+
+	//we need to pass the info that doesn't get modified as aux data
+	//because we'll still need it when we send the modify_info packet
+	mid = g_new0(modify_info_data, 1);
+	mid->gc = gc;
+	mid->misc = info_get_group(info, info_group_headers[3]);
+	
+	gaim_request_fields(gc, _("Modify my information"),
+			_("Modify my information"), NULL, fields,
+			_("Update my information"), G_CALLBACK(modify_info_ok_cb),
+			_("Cancel"), G_CALLBACK(modify_info_cancel_cb),
+			mid);
+}
+
+// process the reply of modify_info packet
+void qq_process_modify_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc)
 {
 	qq_data *qd;
 	gint len;
@@ -145,18 +519,17 @@
 	data = g_newa(guint8, len);
 
 	if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
-		if (qd->uid == atoi(data)) {	// return should be my uid
+		if (qd->uid == atoi((gchar *) data)) {	// return should be my uid
 			gaim_debug(GAIM_DEBUG_INFO, "QQ", "Update info ACK OK\n");
-			gaim_notify_info(gc, NULL, _("You information have been updated"), NULL);
+			gaim_notify_info(gc, NULL, _("Your information has been updated"), NULL);
 		}
 	} else
 		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt modify info reply\n");
 
-}				// qq_process_modify_info_reply
+}
 
-/*****************************************************************************/
 // after getting info or modify myself, refresh the buddy list accordingly
-void qq_refresh_buddy_and_myself(contact_info * info, GaimConnection * gc)
+void qq_refresh_buddy_and_myself(contact_info *info, GaimConnection *gc)
 {
 	GaimBuddy *b;
 	qq_data *qd;
@@ -182,13 +555,16 @@
 		if (alias_utf8 != NULL)
 			q_bud->nickname = g_strdup(alias_utf8);
 		qq_update_buddy_contact(gc, q_bud);
-	}			// if q_bud
+	}
 	g_free(alias_utf8);
-}				// qq_refresh_buddy_and_myself
+}
 
-/*****************************************************************************/
+// XXX When we don't have any immediate response, we send duplicate get info packets 
+// to the server. If the server ends up responding to multiple packets, we get multiple
+// modify info dialogues, which is annoying. Fix this.
+
 // process reply to get_info packet
-void qq_process_get_info_reply(guint8 * buf, gint buf_len, GaimConnection * gc)
+void qq_process_get_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc)
 {
 	gint len;
 	guint8 *data;
@@ -196,9 +572,8 @@
 	qq_info_query *query;
 	qq_data *qd;
 	contact_info *info;
-	contact_info_window *info_window;
-	gboolean show_window;
 	GList *list, *query_list;
+	GString *info_text;
 
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
 	g_return_if_fail(buf != NULL && buf_len != 0);
@@ -217,42 +592,30 @@
 		qq_refresh_buddy_and_myself(info, gc);
 
 		query_list = qd->info_query;
-		show_window = FALSE;
-		while (query_list != NULL) {
+		// ensure we're processing the right query
+		while (query_list) {
 			query = (qq_info_query *) query_list->data;
 			if (query->uid == atoi(info->uid)) {
-				show_window = query->show_window;
+				if (query->show_window) {
+					info_text = info_to_str((const gchar **) segments);
+					gaim_notify_userinfo(gc, info->uid, info_text->str, NULL, NULL);
+					g_string_free(info_text, TRUE);
+				} else if (query->modify_info) {
+					create_modify_info_dialogue(gc, (const gchar **) segments);
+				}
 				qd->info_query = g_list_remove(qd->info_query, qd->info_query->data);
 				g_free(query);
 				break;
 			}
 			query_list = query_list->next;
-		}		// while query_list
+		}
 
-		if (!show_window) {
-			g_strfreev(segments);
-			return;
-		}
-		// if not show_window, we can not find the window here either
-		list = qd->contact_info_window;
-		while (list != NULL) {
-			info_window = (contact_info_window *) (list->data);
-			if (info_window->uid == atoi(info->uid)) {
-				if (info_window->window)
-					qq_refresh_contact_info_dialog(info, gc, info_window);
-				else
-					qq_show_contact_info_dialog(info, gc, info_window);
-				break;
-			} else
-				list = list->next;
-		}		// while list
 		g_strfreev(segments);
 	} else
 		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt get info reply\n");
 
-}				// qq_process_get_info_reply
+}
 
-/*****************************************************************************/
 void qq_info_query_free(qq_data * qd)
 {
 	gint i;
@@ -268,7 +631,4 @@
 		i++;
 	}
 	gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d info queries are freed!\n", i);
-}				// qq_add_buddy_request_free
-
-/*****************************************************************************/
-// END OF FILE
+}
--- a/src/protocols/qq/buddy_info.h	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/buddy_info.h	Mon Jul 24 13:39:12 2006 +0000
@@ -40,9 +40,7 @@
 #define QQ_BUDDY_GENDER_MM          0x01
 #define QQ_BUDDY_GENDER_UNKNOWN     0xff
 
-typedef struct _contact_info contact_info;
-
-struct _contact_info {
+typedef struct _contact_info {
 	gchar *uid;		//0
 	gchar *nick;		//1
 	gchar *country;		//2 
@@ -80,15 +78,46 @@
 	gchar *blood;		//34
 	gchar *qq_show;		//35
 	gchar *unknown6;	//36, always 0x2D
-};
+} contact_info;
+
+// There is no user id stored in the reply packet for information query
+// we have to manually store the query, so that we know the query source
+typedef struct _qq_info_query {
+	guint32 uid;
+	gboolean show_window;
+	gboolean modify_info;
+} qq_info_query;
+
+// We get an info packet on ourselves before we modify our information.
+// Even though not all of the information is currently modifiable, it still
+// all needs to be there when we send out the modify info packet
+typedef struct _modify_info_data {
+	GaimConnection *gc;
+	GList *misc, *node;
+} modify_info_data;
+
+#define QQ_CONTACT_FIELDS 				37
 
-void qq_refresh_buddy_and_myself(contact_info * info, GaimConnection * gc);
-void qq_send_packet_get_info(GaimConnection * gc, guint32 uid, gboolean show_window);
-void qq_send_packet_modify_info(GaimConnection * gc, contact_info * info, gchar * new_passwd);
-void qq_process_modify_info_reply(guint8 * buf, gint buf_len, GaimConnection * gc);
-void qq_process_get_info_reply(guint8 * buf, gint buf_len, GaimConnection * gc);
-void qq_info_query_free(qq_data * qd);
+#define QQ_MAIN_INFO		"Primary Information"
+#define QQ_EXTRA_INFO		"Detailed Information"
+#define QQ_PERSONAL_INTRO	"Personal Introduction"
+#define QQ_MISC			"Miscellaneous"
+
+#define QQ_NO_CHOICE		0
+#define QQ_HOROSCOPE		 1
+#define QQ_ZODIAC		 2
+#define QQ_BLOOD		 3
+#define QQ_GENDER		 4
+#define QQ_COUNTRY		 5
+#define QQ_PROVINCE		 6
+#define QQ_OCCUPATION		 7
+
+void qq_refresh_buddy_and_myself(contact_info *info, GaimConnection *gc);
+void qq_send_packet_get_info(GaimConnection *gc, guint32 uid, gboolean show_window);
+void qq_send_packet_modify_info(GaimConnection *gc, contact_info *info, gchar *new_passwd);
+void qq_prepare_modify_info(GaimConnection *gc);
+void qq_process_modify_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc);
+void qq_process_get_info_reply(guint8 *buf, gint buf_len, GaimConnection *gc);
+void qq_info_query_free(qq_data *qd);
 
 #endif
-/*****************************************************************************/
-// END OF FILE
--- a/src/protocols/qq/buddy_list.c	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/buddy_list.c	Mon Jul 24 13:39:12 2006 +0000
@@ -42,6 +42,8 @@
 #include "group_hash.h"         //qq_group_create_by_id
 #include "group_info.h"         //qq_send_cmd_group_get_group_info
 
+#include "qq_proxy.h"
+
 #define QQ_GET_ONLINE_BUDDY_02          0x02
 #define QQ_GET_ONLINE_BUDDY_03          0x03	// unknown function
 
@@ -56,13 +58,6 @@
 	guint8 ending;		//0x00
 } qq_friends_online_entry;
 
-//TODO: defined in qq_buddy_status.c, but only used here. Check decomposition.
-extern void			// defined in qq_buddy_status.c
- _qq_buddy_status_dump_unclear(qq_buddy_status * s);
-
-extern gint			// defined in qq_buddy_status.c
- _qq_buddy_status_read(guint8 * data, guint8 ** cursor, gint len, qq_buddy_status * s);
-
 /*****************************************************************************/
 // get a list of online_buddies
 void qq_send_packet_get_buddies_online(GaimConnection * gc, guint8 position)
@@ -148,7 +143,7 @@
 
 	g_return_if_fail(fe != NULL);
 
-	_qq_buddy_status_dump_unclear(fe->s);
+	qq_buddy_status_dump_unclear(fe->s);
 
 	dump = g_string_new("");
 	g_string_append_printf(dump, "unclear fields for [%d]:\n", fe->s->uid);
@@ -180,9 +175,14 @@
 	data = g_newa(guint8, len);
 	cursor = data;
 
+	gaim_debug(GAIM_DEBUG_INFO, "QQ", "processing get_buddies_online_reply\n");
+	
 	if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
 
+		_qq_show_packet("Get buddies online reply packet", data, len);
+
 		read_packet_b(data, &cursor, len, &position);
+
 		fe = g_newa(qq_friends_online_entry, 1);
 		fe->s = g_newa(qq_buddy_status, 1);
 
@@ -190,7 +190,7 @@
 			// based on one online buddy entry
 			bytes = 0;
 			// 000-030 qq_buddy_status
-			bytes += _qq_buddy_status_read(data, &cursor, len, fe->s);
+			bytes += qq_buddy_status_read(data, &cursor, len, fe->s);
 			// 031-032: unknown4
 			bytes += read_packet_w(data, &cursor, len, &fe->unknown1);
 			// 033-033: flag1
@@ -209,8 +209,8 @@
 				continue;
 			}	// check if it is a valid entry
 
-//			if (QQ_DEBUG)
-//				_qq_buddies_online_reply_dump_unclear(fe);
+			if (QQ_DEBUG)
+				_qq_buddies_online_reply_dump_unclear(fe);
 
 			// update buddy information
 			b = gaim_find_buddy(gaim_connection_get_account(gc), uid_to_gaim_name(fe->s->uid));
@@ -219,10 +219,10 @@
 			if (q_bud != NULL) {	// we find one and update qq_buddy
 				if(0 != fe->s->client_version)
 					q_bud->client_version = fe->s->client_version; //by gfhuang
-				if(0 != *((guint32 *)fe->s->ip)) { // by gfhuang
+			//	if(0 != *((guint32 *)fe->s->ip)) { // by gfhuang
 					g_memmove(q_bud->ip, fe->s->ip, 4);
 					q_bud->port = fe->s->port;
-				}
+		//		}
 				q_bud->status = fe->s->status;
 				q_bud->flag1 = fe->flag1;
 				q_bud->comm_flag = fe->comm_flag;
--- a/src/protocols/qq/buddy_status.c	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/buddy_status.c	Mon Jul 24 13:39:12 2006 +0000
@@ -34,6 +34,8 @@
 #include "keep_alive.h"		// qq_update_buddy_contact
 #include "send_core.h"		// qq_send_cmd
 
+#include "qq_proxy.h"
+
 #define QQ_MISC_STATUS_HAVING_VIIDEO      0x00000001
 
 #define QQ_ICON_SUFFIX_DEFAULT            QQ_ICON_SUFFIX_OFFLINE
@@ -46,7 +48,7 @@
 };
 
 /*****************************************************************************/
-static void _qq_buddy_status_dump_unclear(qq_buddy_status * s)
+void qq_buddy_status_dump_unclear(qq_buddy_status * s)
 {
 	GString *dump;
 
@@ -55,14 +57,23 @@
 	dump = g_string_new("");
 	g_string_append_printf(dump, "unclear fields for [%d]:\n", s->uid);
 	g_string_append_printf(dump, "004:     %02x   (unknown)\n", s->unknown1);
+	//g_string_append_printf(dump, "005-008:     %09x   (ip)\n", *(s->ip));
+	g_string_append_printf(dump, "009-010:     %04x   (port)\n", s->port);
 	g_string_append_printf(dump, "011:     %02x   (unknown)\n", s->unknown2);
+	g_string_append_printf(dump, "012:     %02x   (status)\n", s->status);
+	g_string_append_printf(dump, "013-014:     %04x   (client_version)\n", s->client_version);
+	//g_string_append_printf(dump, "015-030:     %s   (unknown key)\n", s->unknown_key);
 	gaim_debug(GAIM_DEBUG_INFO, "QQ", "Buddy status entry, %s", dump->str);
+	_qq_show_packet("Unknown key", s->unknown_key, QQ_KEY_LENGTH);
 	g_string_free(dump, TRUE);
-}				// _qq_buddy_status_dump_unclear
+}
 
 /*****************************************************************************/
+// TODO: figure out what's going on with the IP region. Sometimes I get things which
+// may be valid IP addresses, but the port number's weird, other times I get 0s. 
+// Note: I get these simultaneously on the same buddy, using different accounts to get info.
 // parse the data into qq_buddy_status
-gint _qq_buddy_status_read(guint8 * data, guint8 ** cursor, gint len, qq_buddy_status * s) {
+gint qq_buddy_status_read(guint8 * data, guint8 ** cursor, gint len, qq_buddy_status * s) {
 	gint bytes;
 
 	g_return_val_if_fail(data != NULL && *cursor != NULL && s != NULL, -1);
@@ -73,9 +84,12 @@
 	bytes += read_packet_dw(data, cursor, len, &s->uid);
 	// 004-004: 0x01
 	bytes += read_packet_b(data, cursor, len, &s->unknown1);
+	// this is no longer the IP, it seems QQ (as of 2006) no longer sends
+	// the buddy's IP in this packet. all 0s
 	// 005-008: ip
 	s->ip = g_new0(guint8, 4);
 	bytes += read_packet_data(data, cursor, len, s->ip, 4);
+	// port info is no longer here either
 	// 009-010: port
 	bytes += read_packet_w(data, cursor, len, &s->port);
 	// 011-011: 0x00
@@ -93,7 +107,7 @@
 
 	return bytes;
 
-}				// _qq_buddy_status_read
+}
 
 /*****************************************************************************/
 // check if status means online or offline
@@ -159,7 +173,7 @@
 		break;
 	default:
 		away_cmd = QQ_BUDDY_ONLINE_NORMAL;
-	}			// switch
+	}
 
 	raw_data = g_new0(guint8, 5);
 	cursor = raw_data;
@@ -175,7 +189,7 @@
 	qq_send_cmd(gc, QQ_CMD_CHANGE_ONLINE_STATUS, TRUE, 0, TRUE, raw_data, 5);
 
 	g_free(raw_data);
-}				// qq_send_packet_change_status
+}
 
 /*****************************************************************************/
 // parse the reply packet for change_status
@@ -201,7 +215,7 @@
 	} else
 		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt chg status reply\n");
 
-}				// qq_process_change_status_reply
+}
 
 /*****************************************************************************/
 // it is a server message 
@@ -228,7 +242,7 @@
 		s = g_new0(qq_buddy_status, 1);
 		bytes = 0;
 		// 000-030: qq_buddy_status;
-		bytes += _qq_buddy_status_read(data, &cursor, len, s);
+		bytes += qq_buddy_status_read(data, &cursor, len, s);
 		// 031-034: my uid
 		bytes += read_packet_dw(data, &cursor, len, &my_uid);
 
@@ -242,19 +256,19 @@
 //		if (QQ_DEBUG)						gfhuang
 //			_qq_buddy_status_dump_unclear(s);
 
-		name = uid_to_gaim_name(s->uid);	//by gfhuang
+		name = uid_to_gaim_name(s->uid);
 		b = gaim_find_buddy(gc->account, name);
 		g_free(name);
 		q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
 		if (q_bud) {
 			gaim_debug(GAIM_DEBUG_INFO, "QQ", "s->uid = %d, q_bud->uid = %d\n", s->uid , q_bud->uid);
-			if(0 != *((guint32 *)s->ip)) { //by gfhuang
+			if(0 != *((guint32 *)s->ip)) { 
 				g_memmove(q_bud->ip, s->ip, 4);
 				q_bud->port = s->port;
 			}
 			q_bud->status = s->status;
 			if(0 != s->client_version) 
-				q_bud->client_version = s->client_version;  //gfhuang
+				q_bud->client_version = s->client_version; 
 			qq_update_buddy_contact(gc, q_bud);
 		}
 		else 
@@ -265,8 +279,7 @@
 		g_free(s);
 	} else
 		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Error decrypt buddy status change packet\n");
-
-}				// qq_process_friend_change_status
+}
 
 /*****************************************************************************/
 // END OF FILE
--- a/src/protocols/qq/buddy_status.h	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/buddy_status.h	Mon Jul 24 13:39:12 2006 +0000
@@ -56,9 +56,11 @@
 	QQ_SELF_STATUS_CUSTOM = 0x14,
 	QQ_SELF_STATUS_IDLE = 0x15,
 };
-
+ 
+void qq_buddy_status_dump_unclear(qq_buddy_status * s);
 gboolean is_online(guint8 status);
 
+gint qq_buddy_status_read(guint8 * data, guint8 ** cursor, gint len, qq_buddy_status * s);
 gchar get_suffix_from_status(guint8 status);
 
 void qq_send_packet_change_status(GaimConnection * gc);
--- a/src/protocols/qq/group_admindlg.c	Mon Jul 24 09:25:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,659 +0,0 @@
-/**
-* The QQ2003C protocol plugin
- *
- * for gaim
- *
- * Copyright (C) 2004 Puzzlebird
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-// START OF FILE
-/*****************************************************************************/
-#include "debug.h"		// gaim_debug
-#include "blist.h"		// GAIM_BLIST_NODE_IS_BUDDY
-#include "notify.h"		// gaim_notify_warning
-
-#include "utils.h"		// gaim_name_to_uid
-#include "group_admindlg.h"
-#include "group_find.h"		// qq_group_find_by_internal_group_id
-#include "group_join.h"		// auth_type
-#include "group_opt.h"		// QQ_GROUP_TYPE_PERMANENT
-
-enum {
-	COLUMN_SELECTED = 0,
-	COLUMN_UID,
-	COLUMN_NICKNAME,
-	NUM_COLUMNS
-};
-
-enum {
-	PAGE_INFO = 0,
-	PAGE_MEMBER,
-};
-
-typedef struct _qun_info_window {
-	guint32 internal_group_id;
-	GaimConnection *gc;
-	GtkWidget *window;
-	GtkWidget *notebook;
-	GtkWidget *lbl_external_group_id;
-	GtkWidget *lbl_admin_uid;
-	GtkWidget *ent_group_name;
-	GtkWidget *cmb_group_category;
-	GtkWidget *txt_group_desc;
-	GtkWidget *txt_group_notice;
-	GtkWidget *rad_auth[3];
-	GtkWidget *btn_mod;
-	GtkWidget *btn_close;
-	GtkWidget *tre_members;
-} qun_info_window;
-
-const gchar *qq_group_category[] = {
-	"同学", "朋友", "同事", "其他",
-};				// qq_group_category
-
-const gchar *qq_group_auth_type_desc[] = {
-	"无须认证", "需要认证", "不可添加",
-};				// qq_group_auth_type_desc
-
-/*****************************************************************************/
-static void _qq_group_info_window_deleteevent(GtkWidget * widget, GdkEvent * event, gpointer data) {
-	gtk_widget_destroy(widget);	// this will call _window_destroy
-}				// _window_deleteevent
-
-/*****************************************************************************/
-static void _qq_group_info_window_close(GtkWidget * widget, gpointer data)
-{
-	// this will call _info_window_destroy if it is info-window
-	gtk_widget_destroy(GTK_WIDGET(data));
-}				// _window_close
-
-/*****************************************************************************/
-static void _qq_group_info_window_destroy(GtkWidget * widget, gpointer data)
-{
-	GaimConnection *gc;
-	GList *list;
-	qq_data *qd;
-	qun_info_window *info_window;
-
-	gc = (GaimConnection *) data;
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
-	gaim_debug(GAIM_DEBUG_INFO, "QQ", "Group info is destoryed\n");
-
-	qd = (qq_data *) gc->proto_data;
-	list = qd->qun_info_window;
-
-	while (list) {
-		info_window = (qun_info_window *) (list->data);
-		if (info_window->window != widget)
-			list = list->next;
-		else {
-			qd->qun_info_window = g_list_remove(qd->qun_info_window, info_window);
-			g_free(info_window);
-			break;
-		}		// if info_window
-	}			// while
-}				// _window_destroy
-
-/*****************************************************************************/
-void qq_qun_info_window_free(qq_data * qd)
-{
-	gint i;
-	qun_info_window *info_window;
-
-	i = 0;
-	while (qd->qun_info_window) {
-		info_window = (qun_info_window *) qd->qun_info_window->data;
-		qd->qun_info_window = g_list_remove(qd->qun_info_window, info_window);
-		if (info_window->window)
-			gtk_widget_destroy(info_window->window);
-		g_free(info_window);
-		i++;
-	}			// while
-
-	gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d Qun info windows are freed\n", i);
-}				// qq_qun_info_window_free
-
-/*****************************************************************************/
-static void _qq_group_info_window_modify(GtkWidget * widget, gpointer data)
-{
-	GaimConnection *gc;
-	qun_info_window *info_window;
-
-	g_return_if_fail(data != NULL);
-	info_window = (qun_info_window *) data;
-
-	gc = info_window->gc;
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
-
-	//henry: This function contains some codes only supported by gtk-2.4 or later
-//#if !GTK_CHECK_VERSION(2,4,0)
-//        gaim_notify_info(gc, _("QQ Qun Operation"),
-//                        _("This version of GTK-2 does not support this function"), NULL);
-//        return;
-//#else
-	gint page, group_category, i = 0;
-	qq_group *group;
-	qq_data *qd;
-	GtkTextIter start, end;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
-	GValue value = { 0, };
-	guint32 *new_members;
-	guint32 uid;
-	gboolean selected;
-
-	qd = (qq_data *) gc->proto_data;
-
-	// we assume the modification can succeed
-	// maybe it needs some tweak here
-	group = qq_group_find_by_internal_group_id(gc, info_window->internal_group_id);
-	g_return_if_fail(group != NULL);
-
-	new_members = g_newa(guint32, QQ_QUN_MEMBER_MAX);
-
-	page = gtk_notebook_get_current_page(GTK_NOTEBOOK(info_window->notebook));
-	switch (page) {
-	case PAGE_INFO:
-		gaim_debug(GAIM_DEBUG_INFO, "QQ", "Gonna change Qun detailed information\n");
-		// get the group_category
-#if GTK_CHECK_VERSION(2,4,0)
-		group_category = gtk_combo_box_get_active(GTK_COMBO_BOX(info_window->cmb_group_category));
-#else
-		group_category = gtk_option_menu_get_history(GTK_OPTION_MENU(info_window->cmb_group_category));
-#endif
-
-		if (group_category >= 0)
-			group->group_category = group_category;
-		else {
-			g_free(group);
-			gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Invalid group_category: %d\n", group_category);
-			return;
-		}		// if group_category
-		// get auth_type
-		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(info_window->rad_auth[0])))
-			group->auth_type = QQ_GROUP_AUTH_TYPE_NO_AUTH;
-		else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(info_window->rad_auth[1])))
-			group->auth_type = QQ_GROUP_AUTH_TYPE_NEED_AUTH;
-		else
-			group->auth_type = QQ_GROUP_AUTH_TYPE_NO_ADD;
-		// MUST use g_strdup, otherwise core dump after info_window is closed
-		group->group_name_utf8 = g_strdup(gtk_entry_get_text(GTK_ENTRY(info_window->ent_group_name)));
-		gtk_text_buffer_get_bounds(gtk_text_view_get_buffer
-					   (GTK_TEXT_VIEW(info_window->txt_group_desc)), &start, &end);
-		group->group_desc_utf8 =
-		    g_strdup(gtk_text_buffer_get_text
-			     (gtk_text_view_get_buffer
-			      (GTK_TEXT_VIEW(info_window->txt_group_desc)), &start, &end, FALSE));
-		gtk_text_buffer_get_bounds(gtk_text_view_get_buffer
-					   (GTK_TEXT_VIEW(info_window->txt_group_notice)), &start, &end);
-		group->notice_utf8 =
-		    g_strdup(gtk_text_buffer_get_text
-			     (gtk_text_view_get_buffer
-			      (GTK_TEXT_VIEW(info_window->txt_group_notice)), &start, &end, FALSE));
-		// finally we can modify it with new information
-		qq_group_modify_info(gc, group);
-		break;
-	case PAGE_MEMBER:
-		if (info_window->tre_members == NULL) {
-			gaim_debug(GAIM_DEBUG_INFO, "QQ", "Member list is not ready, cannot modify!\n");
-		} else {
-			gaim_debug(GAIM_DEBUG_INFO, "QQ", "Gonna change Qun member list\n");
-			model = gtk_tree_view_get_model(GTK_TREE_VIEW(info_window->tre_members));
-			if (gtk_tree_model_get_iter_first(model, &iter)) {
-				gtk_tree_model_get_value(model, &iter, COLUMN_UID, &value);
-				uid = g_value_get_uint(&value);
-				g_value_unset(&value);
-				gtk_tree_model_get_value(model, &iter, COLUMN_SELECTED, &value);
-				selected = g_value_get_boolean(&value);
-				g_value_unset(&value);
-				if (!selected)
-					new_members[i++] = uid;
-				while (gtk_tree_model_iter_next(model, &iter)) {
-					gtk_tree_model_get_value(model, &iter, COLUMN_UID, &value);
-					uid = g_value_get_uint(&value);
-					g_value_unset(&value);
-					gtk_tree_model_get_value(model, &iter, COLUMN_SELECTED, &value);
-					selected = g_value_get_boolean(&value);
-					g_value_unset(&value);
-					if (!selected)
-						new_members[i++] = uid;
-				}	// while
-				new_members[i] = 0xffffffff;	// this labels the end
-			} else
-				new_members[0] = 0xffffffff;
-			qq_group_modify_members(gc, group, new_members);
-		}		// if info_window->tre_members
-		break;
-	default:
-		gaim_debug(GAIM_DEBUG_INFO, "QQ", "Invalid page number: %d\n", page);
-	}			// switch
-
-	_qq_group_info_window_close(NULL, info_window->window);
-
-//#endif /* GTK_CHECK_VERSION */
-}				// _qq_group_info_window_modify
-
-/*****************************************************************************/
-static void _qq_group_member_list_deleted_toggled(GtkCellRendererToggle * cell, gchar * path_str, gpointer data) {
-	qun_info_window *info_window;
-	GaimConnection *gc;
-	qq_group *group;
-
-	info_window = (qun_info_window *) data;
-	g_return_if_fail(info_window != NULL);
-
-	gc = info_window->gc;
-	g_return_if_fail(gc != NULL);
-
-	group = qq_group_find_by_internal_group_id(gc, info_window->internal_group_id);
-	g_return_if_fail(group != NULL);
-
-	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(info_window->tre_members));
-	GtkTreeIter iter;
-	GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
-	gboolean selected;
-	guint32 uid;
-
-	gtk_tree_model_get_iter(model, &iter, path);
-	gtk_tree_model_get(model, &iter, COLUMN_SELECTED, &selected, -1);
-	gtk_tree_model_get(model, &iter, COLUMN_UID, &uid, -1);
-
-	if (uid != group->creator_uid) {	// do not allow delete admin
-		selected ^= 1;
-		gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_SELECTED, selected, -1);
-		gtk_tree_path_free(path);
-	} else
-		gaim_notify_error(gc, NULL, _("Qun creator cannot be removed"), NULL);
-}				// _qq_group_member_list_deleted_toggled
-
-/*****************************************************************************/
-static void _qq_group_member_list_drag_data_rcv_cb
-    (GtkWidget * widget, GdkDragContext * dc, guint x, guint y,
-     GtkSelectionData * sd, guint info, guint t, gpointer data) {
-
-	GaimConnection *gc;
-	GaimAccount *account;
-	GaimBlistNode *n = NULL;
-	GaimContact *c = NULL;
-	GaimBuddy *b = NULL;
-	GtkWidget *treeview;
-	GtkTreeModel *model;
-	GtkListStore *store;
-	GtkTreeIter iter;
-	GValue value = { 0, };
-	guint32 uid, input_uid;
-
-	treeview = widget;
-	gc = (GaimConnection *) data;
-	g_return_if_fail(gc != NULL);
-	account = gaim_connection_get_account(gc);
-
-	if (sd->target != gdk_atom_intern("GAIM_BLIST_NODE", FALSE) || sd->data == NULL) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Invalid drag data received, discard...\n");
-		return;
-	}			// if (sd->target
-
-	memcpy(&n, sd->data, sizeof(n));
-
-	// we expect GAIM_BLIST_CONTACT_NODE and GAIM_BLIST_BUDDY_NODE
-	if (GAIM_BLIST_NODE_IS_CONTACT(n)) {
-		c = (GaimContact *) n;
-		b = c->priority;	// we get the first buddy only
-	} else if (GAIM_BLIST_NODE_IS_BUDDY(n))
-		b = (GaimBuddy *) n;
-
-	if (b == NULL) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "No valid GaimBuddy is passed from DnD\n");
-		return;
-	}			// if b == NULL
-
-	gaim_debug(GAIM_DEBUG_INFO, "QQ", "We get a GaimBuddy: %s\n", b->name);
-	input_uid = gaim_name_to_uid(b->name);
-	g_return_if_fail(input_uid > 0);
-
-	model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
-	// we need to check if the user id in the member list is unique
-	// possibly a tree transverse is necessary to achieve this
-	if (gtk_tree_model_get_iter_first(model, &iter)) {
-		gtk_tree_model_get_value(model, &iter, COLUMN_UID, &value);
-		uid = g_value_get_uint(&value);
-		g_value_unset(&value);
-		while (uid != input_uid && gtk_tree_model_iter_next(model, &iter)) {
-			gtk_tree_model_get_value(model, &iter, COLUMN_UID, &value);
-			uid = g_value_get_uint(&value);
-			g_value_unset(&value);
-		}		// while
-	} else
-		uid = 0;	// if gtk_tree_model_get_iter_first
-
-	if (uid == input_uid) {
-		gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Qun already has this buddy %s\n", b->name);
-		return;
-	} else {		// we add it to list
-		store = GTK_LIST_STORE(model);
-		gtk_list_store_append(store, &iter);
-		gtk_list_store_set(store, &iter,
-				   COLUMN_SELECTED, FALSE, COLUMN_UID, input_uid, COLUMN_NICKNAME, b->alias, -1);
-		// re-sort the list
-		gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), COLUMN_UID, GTK_SORT_ASCENDING);
-	}			// if uid
-
-}				// _qq_group_member_list_drag_data_rcv_cb
-
-/*****************************************************************************/
-static GtkWidget *_create_page_info(GaimConnection * gc, qq_group * group, gboolean do_manage, qun_info_window * info_window) {
-	GtkWidget *vbox, *hbox;
-	GtkWidget *frame_info, *frame_auth;
-	GtkWidget *tbl_info;
-	GtkWidget *label, *entry, *combo, *text, *scrolled_window;
-	gint i;
-
-	g_return_val_if_fail(gc != NULL && group != NULL, NULL);
-
-	vbox = gtk_vbox_new(FALSE, 5);
-
-	frame_info = gtk_frame_new(NULL);
-	gtk_box_pack_start(GTK_BOX(vbox), frame_info, TRUE, TRUE, 0);
-
-	tbl_info = gtk_table_new(6, 4, FALSE);
-	gtk_table_set_row_spacings(GTK_TABLE(tbl_info), 4);
-	gtk_table_set_col_spacing(GTK_TABLE(tbl_info), 1, 10);
-	gtk_container_add(GTK_CONTAINER(frame_info), tbl_info);
-
-	label = gtk_label_new(_("Group ID: "));
-	gtk_table_attach(GTK_TABLE(tbl_info), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
-	label = gtk_label_new(g_strdup_printf("%d", group->external_group_id));
-	gtk_table_attach(GTK_TABLE(tbl_info), label, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
-	info_window->lbl_external_group_id = label;
-
-	label = gtk_label_new(_("Group Name"));
-	gtk_table_attach(GTK_TABLE(tbl_info), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
-	entry = gtk_entry_new();
-	gtk_widget_set_size_request(entry, 100, -1);
-	if (group->group_name_utf8 != NULL)
-		gtk_entry_set_text(GTK_ENTRY(entry), group->group_name_utf8);
-	gtk_table_attach(GTK_TABLE(tbl_info), entry, 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
-	info_window->ent_group_name = entry;
-
-	label = gtk_label_new(_("Admin: "));
-	gtk_table_attach(GTK_TABLE(tbl_info), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
-	label = gtk_label_new(g_strdup_printf("%d", group->creator_uid));
-	gtk_table_attach(GTK_TABLE(tbl_info), label, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
-	info_window->lbl_admin_uid = label;
-
-	label = gtk_label_new(_("Category"));
-	gtk_table_attach(GTK_TABLE(tbl_info), label, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
-
-	//henry: these codes are supported only in GTK-2.4 or later
-#if GTK_CHECK_VERSION(2, 4, 0)
-	combo = gtk_combo_box_new_text();
-	for (i = 0; i < 4; i++)
-		gtk_combo_box_append_text(GTK_COMBO_BOX(combo), qq_group_category[i]);
-	gtk_combo_box_set_active(GTK_COMBO_BOX(combo), group->group_category);
-#else
-	GtkWidget *menu;
-	GtkWidget *item;
-
-	combo = gtk_option_menu_new();
-	menu = gtk_menu_new();
-	for (i = 0; i < 4; i++) {
-		item = gtk_menu_item_new_with_label(qq_group_category[i]);
-		gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-		gtk_widget_show(item);
-	}
-	gtk_option_menu_set_menu(GTK_OPTION_MENU(combo), menu);
-	gtk_option_menu_set_history(GTK_OPTION_MENU(combo), group->group_category);
-#endif				/* GTK_CHECK_VERSION */
-
-	gtk_table_attach(GTK_TABLE(tbl_info), combo, 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
-	info_window->cmb_group_category = combo;
-
-	label = gtk_label_new(_("Description"));
-	gtk_table_attach(GTK_TABLE(tbl_info), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
-	text = gtk_text_view_new();
-	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
-	gtk_widget_set_size_request(text, -1, 50);
-	if (group->group_desc_utf8 != NULL)
-		gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), group->group_desc_utf8, -1);
-	info_window->txt_group_desc = text;
-
-	scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_container_add(GTK_CONTAINER(scrolled_window), text);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN);
-	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 2);
-	gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 2);
-	gtk_table_attach(GTK_TABLE(tbl_info), scrolled_window, 0, 4, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
-
-	label = gtk_label_new(_("Group Notice"));
-	gtk_table_attach(GTK_TABLE(tbl_info), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 0, 0);
-	text = gtk_text_view_new();
-	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
-	gtk_widget_set_size_request(text, -1, 50);
-	if (group->notice_utf8 != NULL)
-		gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)), group->notice_utf8, -1);
-	info_window->txt_group_notice = text;
-
-	scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_container_add(GTK_CONTAINER(scrolled_window), text);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN);
-	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 2);
-	gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 2);
-	gtk_table_attach(GTK_TABLE(tbl_info), scrolled_window, 0, 4, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
-
-	frame_auth = gtk_frame_new(_("Authentication"));
-	hbox = gtk_hbox_new(FALSE, 5);
-	gtk_container_add(GTK_CONTAINER(frame_auth), hbox);
-	info_window->rad_auth[0] = gtk_radio_button_new_with_label(NULL, qq_group_auth_type_desc[0]);
-	info_window->rad_auth[1] =
-	    gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON
-							(info_window->rad_auth[0]), qq_group_auth_type_desc[1]);
-	info_window->rad_auth[2] =
-	    gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON
-							(info_window->rad_auth[0]), qq_group_auth_type_desc[2]);
-	for (i = 0; i < 3; i++)
-		gtk_box_pack_start(GTK_BOX(hbox), info_window->rad_auth[i], FALSE, FALSE, 0);
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(info_window->rad_auth[group->auth_type - 1]), TRUE);
-	gtk_box_pack_start(GTK_BOX(vbox), frame_auth, FALSE, FALSE, 0);
-
-	if (!do_manage) {
-		gtk_widget_set_sensitive(frame_info, FALSE);
-		gtk_widget_set_sensitive(frame_auth, FALSE);
-	}			// if ! do_manage
-
-	return vbox;
-}				// _create_info_page
-
-/*****************************************************************************/
-static GtkWidget *_create_page_members
-    (GaimConnection * gc, qq_group * group, gboolean do_manage, qun_info_window * info_window) {
-	GtkWidget *vbox, *sw, *treeview;
-	GtkTreeModel *model;
-	GtkListStore *store;
-	GtkTreeIter iter;
-	GtkCellRenderer *renderer;
-	GtkTreeViewColumn *column;
-	GList *list;
-	qq_buddy *q_bud;
-	GtkTargetEntry gte = { "GAIM_BLIST_NODE", GTK_TARGET_SAME_APP, 0 };
-
-	g_return_val_if_fail(gc != NULL && group != NULL, NULL);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-
-	if (group->members == NULL) {	// if NULL, not ready
-		sw = gtk_label_new(_
-				   ("OpenQ is collecting member information.\nPlease close this window and open again"));
-		gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-		return vbox;
-	}			// if group->members
-
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-
-	store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_STRING);
-
-	list = group->members;
-	while (list != NULL) {
-		q_bud = (qq_buddy *) list->data;
-		gtk_list_store_append(store, &iter);
-		gtk_list_store_set(store, &iter,
-				   COLUMN_SELECTED, FALSE,
-				   COLUMN_UID, q_bud->uid, COLUMN_NICKNAME, q_bud->nickname, -1);
-		list = list->next;
-	}			// for
-
-	model = GTK_TREE_MODEL(store);
-	treeview = gtk_tree_view_new_with_model(model);
-	info_window->tre_members = treeview;
-
-	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
-	gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), COLUMN_UID);
-	g_object_unref(model);
-
-	// set up drag & drop ONLY for managable Qun
-	if (do_manage) {
-		gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(treeview), &gte, 1, GDK_ACTION_COPY);
-		g_signal_connect(G_OBJECT(treeview), "drag-data-received",
-				 G_CALLBACK(_qq_group_member_list_drag_data_rcv_cb), gc);
-	}			// if do manage
-
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
-
-	model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
-	renderer = gtk_cell_renderer_toggle_new();
-
-	// it seems this signal has to be handled
-	// otherwise, the checkbox in the column does not reponse to user action
-	if (do_manage)
-		g_signal_connect(renderer, "toggled", G_CALLBACK(_qq_group_member_list_deleted_toggled), info_window);
-
-	column = gtk_tree_view_column_new_with_attributes(_("Del"), renderer, "active", COLUMN_SELECTED, NULL);
-
-	gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), GTK_TREE_VIEW_COLUMN_FIXED);
-	gtk_tree_view_column_set_fixed_width(GTK_TREE_VIEW_COLUMN(column), 30);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
-
-	renderer = gtk_cell_renderer_text_new();
-	column = gtk_tree_view_column_new_with_attributes(_("UID"), renderer, "text", COLUMN_UID, NULL);
-	gtk_tree_view_column_set_sort_column_id(column, COLUMN_UID);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
-	// default sort by UID
-	gtk_tree_view_column_set_sort_order(column, GTK_SORT_ASCENDING);
-	gtk_tree_view_column_set_sort_indicator(column, TRUE);
-
-	renderer = gtk_cell_renderer_text_new();
-	column = gtk_tree_view_column_new_with_attributes(_("Nickname"), renderer, "text", COLUMN_NICKNAME, NULL);
-	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
-
-	return vbox;
-}				// _create_page_members
-
-/*****************************************************************************/
-void qq_group_detail_window_show(GaimConnection * gc, qq_group * group)
-{
-	GtkWidget *vbox, *notebook;
-	GtkWidget *label, *bbox;
-	GList *list;
-	qq_data *qd;
-	qun_info_window *info_window = NULL;
-	gboolean do_manage, do_show, do_exist;
-
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL && group != NULL);
-	qd = (qq_data *) gc->proto_data;
-
-	do_manage = group->my_status == QQ_GROUP_MEMBER_STATUS_IS_ADMIN;
-	do_show = do_manage || (group->my_status == QQ_GROUP_MEMBER_STATUS_IS_MEMBER);
-
-	if (!do_show) {
-		gaim_notify_error(gc, _("QQ Qun Operation"),
-				  _("You can not view Qun details"),
-				  _("Only Qun admin or Qun member can view details"));
-		return;
-	}			// if ! do_show
-
-	list = qd->qun_info_window;
-	do_exist = FALSE;
-	while (list != NULL) {
-		info_window = (qun_info_window *) list->data;
-		if (info_window->internal_group_id == group->internal_group_id) {
-			break;
-			do_exist = TRUE;
-		} else
-			list = list->next;
-	}			// while list
-
-	if (!do_exist) {
-		info_window = g_new0(qun_info_window, 1);
-		info_window->gc = gc;
-		info_window->internal_group_id = group->internal_group_id;
-		g_list_append(qd->qun_info_window, info_window);
-
-		info_window->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-		g_signal_connect(GTK_WINDOW(info_window->window),
-				 "delete_event", G_CALLBACK(_qq_group_info_window_deleteevent), NULL);
-		g_signal_connect(G_OBJECT(info_window->window), "destroy",
-				 G_CALLBACK(_qq_group_info_window_destroy), gc);
-
-		gtk_window_set_title(GTK_WINDOW(info_window->window), _("Manage Qun"));
-		gtk_window_set_resizable(GTK_WINDOW(info_window->window), FALSE);
-		gtk_container_set_border_width(GTK_CONTAINER(info_window->window), 5);
-
-		vbox = gtk_vbox_new(FALSE, 0);
-		gtk_container_add(GTK_CONTAINER(info_window->window), vbox);
-
-		notebook = gtk_notebook_new();
-		info_window->notebook = notebook;
-		gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
-		gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-
-		label = gtk_label_new(_("Qun Information"));
-		gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-					 _create_page_info(gc, group, do_manage, info_window), label);
-		label = gtk_label_new(_("Members"));
-		gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-					 _create_page_members(gc, group, do_manage, info_window), label);
-
-		bbox = gtk_hbutton_box_new();
-		gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
-		gtk_box_set_spacing(GTK_BOX(bbox), 10);
-
-		info_window->btn_mod = gtk_button_new_with_label(_("Modify"));
-		gtk_container_add(GTK_CONTAINER(bbox), info_window->btn_mod);
-		g_signal_connect(G_OBJECT(info_window->btn_mod), "clicked",
-				 G_CALLBACK(_qq_group_info_window_modify), info_window);
-
-		info_window->btn_close = gtk_button_new_with_label(_("Close"));
-		gtk_container_add(GTK_CONTAINER(bbox), info_window->btn_close);
-		g_signal_connect(G_OBJECT(info_window->btn_close),
-				 "clicked", G_CALLBACK(_qq_group_info_window_close), info_window->window);
-
-		if (!do_manage)
-			gtk_widget_set_sensitive(info_window->btn_mod, FALSE);
-		gtk_box_pack_start(GTK_BOX(vbox), bbox, TRUE, TRUE, 5);
-		gtk_widget_show_all(info_window->window);
-
-	} else			// we already have this
-		gtk_widget_grab_focus(info_window->window);
-
-}				// qq_group_manage_window_show
-
-/*****************************************************************************/
-// END OF FILE
--- a/src/protocols/qq/group_admindlg.h	Mon Jul 24 09:25:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/**
-* The QQ2003C protocol plugin
- *
- * for gaim
- *
- * Copyright (C) 2004 Puzzlebird
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-// START OF FILE
-/*****************************************************************************/
-#ifndef _QQ_GROUP_ADMINDLG_H_
-#define _QQ_GROUP_ADMINDLG_H_
-
-#include <glib.h>
-#include <gtk/gtk.h>
-#include "connection.h"
-#include "group.h"
-#include "qq.h"
-
-void qq_group_detail_window_show(GaimConnection * gc, qq_group * group);
-
-void qq_qun_info_window_free(qq_data * qd);
-#endif
-/*****************************************************************************/
-// END OF FILE
--- a/src/protocols/qq/group_opt.c	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/group_opt.c	Mon Jul 24 13:39:12 2006 +0000
@@ -30,7 +30,7 @@
 #include "packet_parse.h"	// create_packet_b
 #include "buddy_info.h"		// qq_send_packet_get_info
 #include "char_conv.h"		// utf8_to_qq
-#include "group_admindlg.h"	// qq_group_manage_window_show
+//#include "group_admindlg.h"	// qq_group_detail_window_show
 #include "group_find.h"		// qq_group_find_by_internal_group_id
 #include "group_hash.h"		// qq_group_refresh
 #include "group_info.h"		// qq_send_cmd_group_get_group_info
@@ -366,7 +366,8 @@
 	group = qq_group_find_by_internal_group_id(g->gc, g->uid);
 	g_return_if_fail(group != NULL);
 
-	qq_group_detail_window_show(g->gc, group);
+	//XXX insert UI code here
+	//qq_group_detail_window_show(g->gc, group);
 	g_free(g);
 }				// qq_group_setup_with_gc_and_uid
 
@@ -470,7 +471,8 @@
 	group = qq_group_find_by_internal_group_id(gc, internal_group_id);
 	g_return_if_fail(group != NULL);
 
-	qq_group_detail_window_show(gc, group);
+	//XXX insert UI code here
+	//qq_group_detail_window_show(gc, group);
 
 }				// qq_group_manage_members
 
--- a/src/protocols/qq/infodlg.c	Mon Jul 24 09:25:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1127 +0,0 @@
-/**
- * The QQ2003C protocol plugin
- *
- * for gaim
- *
- * Copyright (C) 2004 Puzzlebird
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-// START OF FILE
-/*****************************************************************************/
-#include "debug.h"		// gaim_debug
-#include "internal.h"		// strlen, _("get_text")
-#include "notify.h"		// gaim_notify_error
-
-#include "utils.h"		// get_face_gdkpixbuf
-#include "char_conv.h"		// qq_to_utf8
-#include "show.h"		// qq_show_get_image
-#include "infodlg.h"
-
-// must be defined after qq_infodlg.h to have <gtk/gtk.h>
-#include "gtkdialogs.h"		// GAIM_DIALOG, mainwindow
-
-
-// the follwoing definition is in UTF-8
-const gint blood_types_count = 5;
-const gchar *blood_types[] = {
-	"其它", "A", "B", "O", "AB",
-};
-
-const gint country_names_count = 6;
-const gchar *country_names[] = {
-	"中国", "中国香港", "中国澳门", "中国台湾",
-	"新加坡", "马来西亚", "美国",
-};
-
-const gint province_names_count = 34;
-const gchar *province_names[] = {
-	"北京", "天津", "上海", "重庆", "香港",
-	"河北", "山西", "内蒙古", "辽宁", "吉林",
-	"黑龙江", "江西", "浙江", "江苏", "安徽",
-	"福建", "山东", "河南", "湖北", "湖南",
-	"广东", "广西", "海南", "四川", "贵州",
-	"云南", "西藏", "陕西", "甘肃", "宁夏",
-	"青海", "新疆", "台湾", "澳门",
-};
-
-const gint zodiac_names_count = 13;
-const gchar *zodiac_names[] = {
-	"-", "鼠", "牛", "虎", "兔",
-	"龙", "蛇", "马", "羊", "猴",
-	"鸡", "狗", "猪",
-};
-
-const gint horoscope_names_count = 13;
-const gchar *horoscope_names[] = {
-	"-", "水瓶座", "双鱼座", "牡羊座", "金牛座",
-	"双子座", "巨蟹座", "狮子座", "处女座", "天秤座",
-	"天蝎座", "射手座", "魔羯座",
-};
-
-const gint occupation_names_count = 15;
-const gchar *occupation_names[] = {
-	"全职", "兼职", "制造业", "商业", "失业中",
-	"学生", "工程师", "政府部门", "教育业", "服务行业",
-	"老板", "计算机业", "退休", "金融业",
-	"销售/广告/市场",
-};
-
-enum {
-	QQ_CONTACT_OPEN = 0x00,
-	QQ_CONTACT_ONLY_FRIENDS = 0x01,
-	QQ_CONTACT_CLOSE = 0x02,
-};
-
-
-enum {
-	QQ_AUTH_NO_AUTH = 0x00,
-	QQ_AUTH_NEED_AUTH = 0x01,
-	QQ_AUTH_NO_ADD = 0x02,
-};
-
-typedef struct _change_icon_widgets change_icon_widgets;
-
-struct _change_icon_widgets {
-	GtkWidget *dialog;	// dialog that shows all icons
-	GtkWidget *face;	// the image widget we are going to change
-};
-
-/*****************************************************************************/
-static void _window_deleteevent(GtkWidget * widget, GdkEvent * event, gpointer data) {
-	gtk_widget_destroy(widget);	// this will call _window_destroy
-}				// _window_deleteevent
-
-/*****************************************************************************/
-static void _window_close(GtkWidget * widget, gpointer data)
-{
-	// this will call _info_window_destroy if it is info-window
-	gtk_widget_destroy(GTK_WIDGET(data));
-}				// _window_close
-
-/*****************************************************************************/
-static void _no_edit(GtkWidget * w)
-{
-	gtk_editable_set_editable(GTK_EDITABLE(w), FALSE);
-}				// _no_edit
-
-/*****************************************************************************/
-static GtkWidget *_qq_entry_new()
-{
-	GtkWidget *entry;
-	entry = gtk_entry_new();
-	gtk_entry_set_max_length(GTK_ENTRY(entry), 255);	// set the max length
-	return entry;
-}				// _qq_entry_new
-
-/*****************************************************************************/
-static void _qq_set_entry(GtkWidget * entry, gchar * text)
-{
-	gchar *text_utf8;
-
-	text_utf8 = qq_to_utf8(text, QQ_CHARSET_DEFAULT);
-	gtk_entry_set_text(GTK_ENTRY(entry), text_utf8);
-
-	g_free(text_utf8);
-}				// _qq_set_entry
-
-/*****************************************************************************/
-static gchar *_qq_get_entry(GtkWidget * entry)
-{
-	return utf8_to_qq(gtk_entry_get_text(GTK_ENTRY(entry)), QQ_CHARSET_DEFAULT);
-}				// _qq_get_entry
-
-/*****************************************************************************/
-static void _qq_set_text(GtkWidget * entry, gchar * text)
-{
-	gchar *text_utf8;
-
-	text_utf8 = qq_to_utf8(text, QQ_CHARSET_DEFAULT);
-	gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry)), text_utf8, -1);
-
-	g_free(text_utf8);
-}				// _qq_set_text
-
-/*****************************************************************************/
-static gchar *_qq_get_text(GtkWidget * entry)
-{
-	gchar *str, *ret;
-	GtkTextIter start, end;
-
-	gtk_text_buffer_get_bounds(gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry)), &start, &end);
-	str = gtk_text_buffer_get_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry)), &start, &end, FALSE);
-	ret = utf8_to_qq(str, QQ_CHARSET_DEFAULT);
-
-	return ret;
-}				// _qq_get_text
-
-/*****************************************************************************/
-static void _qq_set_image(GtkWidget * entry, gint index)
-{
-	GdkPixbuf *pixbuf;
-
-	g_return_if_fail(entry != NULL && index >= 0);
-
-	pixbuf = get_face_gdkpixbuf(index);
-	gtk_image_set_from_pixbuf(GTK_IMAGE(entry), pixbuf);
-	g_object_unref(pixbuf);
-	g_object_set_data(G_OBJECT(entry), "user_data", GINT_TO_POINTER(index));
-}				// _qq_set_image
-
-
-/*****************************************************************************/
-static void _qq_change_face(GtkWidget * w, gpointer * user_data)
-{
-	gint index;
-	change_icon_widgets *change_icon;
-
-	change_icon = (change_icon_widgets *) user_data;
-
-	index = (gint) g_object_get_data(G_OBJECT(w), "user_data");
-
-	_qq_set_image(change_icon->face, index);
-	_window_close(NULL, change_icon->dialog);
-
-	g_free(change_icon);
-
-}				// _qq_change_face
-
-/*****************************************************************************/
-static GList *_get_list_by_array(gchar ** array, gint size)
-{
-	gint i;
-	GList *cbitems;
-
-	cbitems = NULL;
-	for (i = 0; i < size; i++)
-		cbitems = g_list_append(cbitems, array[i]);
-	return cbitems;
-}				// _get_list_by_array
-
-/*****************************************************************************/
-static void _qq_set_open_contact_radio(contact_info_window * info_window, gchar * is_open_contact) {
-	gint open;
-	GtkWidget **radio;
-
-	open = atoi(is_open_contact);
-	radio = info_window->open_contact_radio;
-
-	if (open == QQ_CONTACT_OPEN)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[0]), TRUE);
-	else if (open == QQ_CONTACT_ONLY_FRIENDS)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[1]), TRUE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[2]), TRUE);
-}				// _qq_set_open_contact_radio
-
-/*****************************************************************************/
-static void _qq_set_auth_type_radio(contact_info_window * info_window, gchar * auth_type_str) {
-	gint auth_type;
-	GtkWidget **radio;
-
-	auth_type = atoi(auth_type_str);
-	radio = info_window->auth_radio;
-
-	if (auth_type == QQ_AUTH_NO_AUTH)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[0]), TRUE);
-	else if (auth_type == QQ_AUTH_NEED_AUTH)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[1]), TRUE);
-	else
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio[2]), TRUE);
-}				// _qq_set_auth_type_radio
-
-/*****************************************************************************/
-static void _info_window_destroy(GtkWidget * widget, gpointer data)
-{
-	GList *list;
-	qq_data *qd;
-	GaimConnection *gc;
-	contact_info_window *info_window;
-
-	gc = (GaimConnection *) data;
-
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
-
-	if (QQ_DEBUG)
-		gaim_debug(GAIM_DEBUG_INFO, "QQ", "Destroy info window.\n");
-	qd = (qq_data *) gc->proto_data;
-	list = qd->contact_info_window;
-
-	while (list) {
-		info_window = (contact_info_window *) (list->data);
-		if (info_window->window != widget)
-			list = list->next;
-		else {
-			if (info_window->old_info)
-				g_strfreev((gchar **) info_window->old_info);
-			qd->contact_info_window = g_list_remove(qd->contact_info_window, info_window);
-			g_free(info_window);
-			break;
-		}
-	}			// while
-}				// _info_window_destory
-
-/*****************************************************************************/
-void qq_contact_info_window_free(qq_data * qd)
-{
-	gint i;
-	contact_info_window *info;
-
-	g_return_if_fail(qd != NULL);
-
-	i = 0;
-	while (qd->contact_info_window) {
-		info = (contact_info_window *) qd->contact_info_window->data;
-		// remove the entry before free it
-		// in some rare cases, system might automatically (stupidly) 
-		// remove the entry from the list when user free the entry, 
-		// then, qd->contact_info_window becomes NULL and it causes crash
-		qd->contact_info_window = g_list_remove(qd->contact_info_window, info);
-		if (info->window)
-			gtk_widget_destroy(info->window);
-		g_free(info);
-		i++;
-	}
-	gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d conatct_info_window are freed\n", i);
-}				// qq_contact_info_window_free
-
-/*****************************************************************************/
-static void _info_window_refresh(GtkWidget * widget, gpointer data)
-{
-	GaimConnection *gc;
-	contact_info_window *info_window;
-
-	gc = (GaimConnection *) data;
-	info_window = (contact_info_window *)
-	    g_object_get_data(G_OBJECT(widget), "user_data");
-
-	qq_send_packet_get_info(gc, info_window->uid, TRUE);
-	gtk_widget_set_sensitive(info_window->refresh_button, FALSE);
-}				// _info_window_refresh
-
-/*****************************************************************************/
-static void _info_window_change(GtkWidget * widget, gpointer data)
-{
-	gchar *passwd[3];
-	gboolean is_modify_passwd;
-	guint8 icon, auth_type, open_contact;
-	qq_data *qd;
-	GaimAccount *a;
-	GaimConnection *gc;
-	contact_info *info;
-	contact_info_window *info_window;
-
-	gc = (GaimConnection *) data;
-	a = gc->account;
-	qd = gc->proto_data;
-	info_window = (contact_info_window *)
-	    g_object_get_data(G_OBJECT(widget), "user_data");
-	info = info_window->old_info;
-
-	is_modify_passwd = FALSE;
-	passwd[0] = passwd[1] = passwd[2] = NULL;
-
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(info_window->is_modify_passwd)))
-		is_modify_passwd = TRUE;
-
-	if (is_modify_passwd) {
-		passwd[0] = _qq_get_entry(info_window->old_password);
-		passwd[1] = _qq_get_entry(info_window->password[0]);
-		passwd[2] = _qq_get_entry(info_window->password[1]);
-
-		if (g_ascii_strcasecmp(a->password, passwd[0])) {
-			gaim_notify_error(gc, _("Error"), _("Old password is wrong"), NULL);
-			g_free(passwd[0]);
-			g_free(passwd[1]);
-			g_free(passwd[2]);
-			return;
-		}
-		if (passwd[1][0] == '\0') {
-			gaim_notify_error(gc, _("Error"), _("Password can not be empty"), NULL);
-			g_free(passwd[0]);
-			g_free(passwd[1]);
-			g_free(passwd[2]);
-			return;
-		}
-		if (g_ascii_strcasecmp(passwd[1], passwd[2])) {
-			gaim_notify_error(gc, _("Error"),
-					  _("Confirmed password is not the same as new password"), NULL);
-			g_free(passwd[0]);
-			g_free(passwd[1]);
-			g_free(passwd[2]);
-			return;
-		}
-		if (strlen(passwd[1]) > 16) {
-			gaim_notify_error(gc, _("Error"), _("Password can not longer than 16 characters"), NULL);
-			g_free(passwd[0]);
-			g_free(passwd[1]);
-			g_free(passwd[2]);
-			return;
-		}
-	}			// if (is_modify_passwd)
-
-	icon = (gint) g_object_get_data(G_OBJECT(info_window->face), "user_data");
-
-	info->face = g_strdup_printf("%d", icon);
-	info->nick = _qq_get_entry(info_window->nick);
-	info->age = _qq_get_entry(info_window->age);
-	info->gender = _qq_get_entry(info_window->gender);
-	info->country = _qq_get_entry(info_window->country);
-	info->province = _qq_get_entry(info_window->province);
-	info->city = _qq_get_entry(info_window->city);
-	info->email = _qq_get_entry(info_window->email);
-	info->address = _qq_get_entry(info_window->address);
-	info->zipcode = _qq_get_entry(info_window->zipcode);
-	info->tel = _qq_get_entry(info_window->tel);
-	info->name = _qq_get_entry(info_window->name);
-	info->college = _qq_get_entry(info_window->college);
-	info->occupation = _qq_get_entry(info_window->occupation);
-	info->homepage = _qq_get_entry(info_window->homepage);
-	info->intro = _qq_get_text(info_window->intro);
-
-	info->blood =
-	    get_index_str_by_name((gchar **) blood_types,
-				  gtk_entry_get_text(GTK_ENTRY(info_window->blood)), blood_types_count);
-	info->zodiac =
-	    get_index_str_by_name((gchar **) zodiac_names,
-				  gtk_entry_get_text(GTK_ENTRY(info_window->zodiac)), zodiac_names_count);
-	info->horoscope =
-	    get_index_str_by_name((gchar **) horoscope_names,
-				  gtk_entry_get_text(GTK_ENTRY(info_window->horoscope)), horoscope_names_count);
-
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(info_window->auth_radio[0])))
-		auth_type = QQ_AUTH_NO_AUTH;
-	else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(info_window->auth_radio[1])))
-		auth_type = QQ_AUTH_NEED_AUTH;
-	else
-		auth_type = QQ_AUTH_NO_ADD;
-
-	info->auth_type = g_strdup_printf("%d", auth_type);
-
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(info_window->open_contact_radio[0])))
-		open_contact = QQ_CONTACT_OPEN;
-	else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(info_window->open_contact_radio[1])))
-		open_contact = QQ_CONTACT_ONLY_FRIENDS;
-	else
-		open_contact = QQ_CONTACT_CLOSE;
-
-	info->is_open_contact = g_strdup_printf("%d", open_contact);
-
-	qq_send_packet_modify_info(gc, info, passwd[1]);
-	qq_refresh_buddy_and_myself(info, gc);
-
-	gtk_widget_destroy(info_window->window);	//close window
-}
-
-/*****************************************************************************/
-static void _info_window_change_face(GtkWidget * widget, GdkEvent * event, contact_info_window * info_window) {
-	gint i;
-	GdkPixbuf *pixbuf;
-	GtkWidget *dialog, *image, *button, *vbox, *smiley_box;
-	change_icon_widgets *change_icon;
-
-	change_icon = g_new0(change_icon_widgets, 1);
-
-	smiley_box = NULL;
-	GAIM_DIALOG(dialog);	// learned from gtkimhtmltoolbar.c
-	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
-	gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
-
-	g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(_window_deleteevent), NULL);
-
-	gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
-	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
-
-	change_icon->dialog = dialog;
-	change_icon->face = info_window->face;
-
-	vbox = gtk_vbox_new(TRUE, 5);
-
-	for (i = 0; i < 85; i++) {
-		if (i % 8 == 0) {
-			smiley_box = gtk_toolbar_new();
-			gtk_box_pack_start(GTK_BOX(vbox), smiley_box, TRUE, TRUE, 0);
-		}
-		pixbuf = get_face_gdkpixbuf(i * 3);
-		image = gtk_image_new_from_pixbuf(pixbuf);
-		g_object_unref(pixbuf);
-		button = gtk_toolbar_append_item(GTK_TOOLBAR(smiley_box),
-						 NULL, NULL, NULL, image, G_CALLBACK(_qq_change_face), change_icon);
-		g_object_set_data(G_OBJECT(button), "user_data", GINT_TO_POINTER(i * 3));
-		gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
-	}			// for i
-
-	gtk_container_add(GTK_CONTAINER(dialog), vbox);
-	gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
-	gtk_window_set_title(GTK_WINDOW(dialog), _("Choose my head icon"));
-	gtk_widget_show_all(dialog);
-}				// _info_window_change_face
-
-/*****************************************************************************/
-static void _change_passwd_checkbutton_callback(GtkWidget * widget, contact_info_window * info_window) {
-	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
-		gtk_widget_set_sensitive(info_window->old_password, TRUE);
-		gtk_widget_set_sensitive(info_window->password[0], TRUE);
-		gtk_widget_set_sensitive(info_window->password[1], TRUE);
-	} else {
-		gtk_widget_set_sensitive(info_window->old_password, FALSE);
-		gtk_widget_set_sensitive(info_window->password[0], FALSE);
-		gtk_widget_set_sensitive(info_window->password[1], FALSE);
-	}
-}				// _change_passwd_checkbutton_callback
-
-/*****************************************************************************/
-static GtkWidget *_create_page_basic
-    (gint is_myself, contact_info * info, GaimConnection * gc, contact_info_window * info_window) {
-	GdkPixbuf *pixbuf;
-	GList *cbitems;
-	GtkWidget *hbox, *pixmap, *frame, *label, *table;
-	GtkWidget *entry, *combo, *alignment;
-	GtkWidget *event_box, *qq_show;
-	GtkTooltips *tooltips;
-
-	tooltips = gtk_tooltips_new();
-
-	cbitems = NULL;
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	frame = gtk_frame_new("");
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
-	gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0);
-
-	table = gtk_table_new(7, 3, FALSE);
-	gtk_table_set_row_spacings(GTK_TABLE(table), 2);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
-	gtk_container_add(GTK_CONTAINER(frame), table);
-
-	pixbuf = get_face_gdkpixbuf((guint8) strtol(info->face, NULL, 10));
-	pixmap = gtk_image_new_from_pixbuf(pixbuf);
-	info_window->face = pixmap;
-
-	alignment = gtk_alignment_new(0.25, 0, 0, 0);
-
-	// set up icon
-	if (is_myself) {
-		g_object_set_data(G_OBJECT(info_window->face), "user_data",
-				  GINT_TO_POINTER(strtol(info->face, NULL, 10)));
-		event_box = gtk_event_box_new();
-		g_signal_connect(G_OBJECT(event_box), "button_press_event",
-				 G_CALLBACK(_info_window_change_face), info_window);
-		gtk_container_add(GTK_CONTAINER(event_box), pixmap);
-		gtk_container_add(GTK_CONTAINER(alignment), event_box);
-		gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), event_box, _("Click to change icon"), NULL);
-	} else
-		gtk_container_add(GTK_CONTAINER(alignment), pixmap);
-
-	gtk_table_attach(GTK_TABLE(table), alignment, 2, 3, 0, 2, GTK_FILL, 0, 0, 0);
-
-	// set up qq_show image and event
-	qq_show = qq_show_default(info);
-	g_object_set_data(G_OBJECT(qq_show), "user_data", GINT_TO_POINTER((gint) atoi(info->uid)));
-
-	frame = gtk_frame_new("");
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
-
-	if (strtol(info->qq_show, NULL, 10) != 0) {	// buddy has qq_show
-		event_box = gtk_event_box_new();
-		gtk_container_add(GTK_CONTAINER(frame), event_box);
-		gtk_container_add(GTK_CONTAINER(event_box), qq_show);
-		g_signal_connect(G_OBJECT(event_box), "button_press_event", G_CALLBACK(qq_show_get_image), qq_show);
-		gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), event_box, _("Click to refresh"), NULL);
-	} else			// no event_box
-		gtk_container_add(GTK_CONTAINER(frame), qq_show);
-
-	gtk_table_attach(GTK_TABLE(table), frame, 2, 3, 2, 7, GTK_EXPAND, 0, 0, 0);
-
-	label = gtk_label_new(_("QQid"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Nickname"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->uid_entry = entry;
-	_qq_set_entry(info_window->uid_entry, info->uid);
-	gtk_widget_set_size_request(entry, 120, -1);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->nick = entry;
-	_qq_set_entry(info_window->nick, info->nick);
-	gtk_widget_set_size_request(entry, 120, -1);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Age"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Gender"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Country/Region"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, 0, 0, 0);
-
-	combo = gtk_combo_new();
-	cbitems = _get_list_by_array((gchar **) country_names, country_names_count);
-	gtk_combo_set_popdown_strings(GTK_COMBO(combo), cbitems);
-	g_list_free(cbitems);
-	cbitems = NULL;
-	info_window->country = GTK_COMBO(combo)->entry;
-	_qq_set_entry(info_window->country, info->country);
-	gtk_widget_set_size_request(combo, 150, -1);
-	gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 4, 5, GTK_FILL, 0, 0, 0);
-	if (!is_myself)
-		gtk_widget_set_sensitive(combo, FALSE);
-
-	entry = _qq_entry_new();
-	info_window->age = entry;
-	_qq_set_entry(info_window->age, info->age);
-	gtk_widget_set_size_request(entry, 40, -1);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, GTK_FILL, 0, 0, 0);
-
-	combo = gtk_combo_new();
-	cbitems = g_list_append(cbitems, (char *)_("Male"));
-	cbitems = g_list_append(cbitems, (char *)_("Female"));
-	gtk_combo_set_popdown_strings(GTK_COMBO(combo), cbitems);
-	g_list_free(cbitems);
-	cbitems = NULL;
-	info_window->gender = GTK_COMBO(combo)->entry;
-	gtk_widget_set_size_request(combo, 60, -1);
-	_qq_set_entry(info_window->gender, info->gender);
-	gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(combo)->entry), FALSE);
-	gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, GTK_FILL, 0, 0, 0);
-	if (!is_myself)
-		gtk_widget_set_sensitive(combo, FALSE);
-
-	label = gtk_label_new(_("Province"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("City"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 6, 7, GTK_FILL, 0, 0, 0);
-
-	combo = gtk_combo_new();
-	cbitems = _get_list_by_array((gchar **) province_names, province_names_count);
-	gtk_combo_set_popdown_strings(GTK_COMBO(combo), cbitems);
-	g_list_free(cbitems);
-	cbitems = NULL;
-	info_window->province = GTK_COMBO(combo)->entry;
-	_qq_set_entry(info_window->province, info->province);
-	gtk_widget_set_size_request(combo, 150, -1);
-	gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 5, 6, GTK_FILL, 0, 0, 0);
-	if (!is_myself)
-		gtk_widget_set_sensitive(combo, FALSE);
-
-	entry = _qq_entry_new();
-	info_window->city = entry;
-	gtk_widget_set_size_request(entry, 120, -1);
-	_qq_set_entry(info_window->city, info->city);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 6, 7, GTK_FILL, 0, 0, 0);
-
-	return hbox;
-}				// _create_page_basic
-
-/*****************************************************************************/
-static GtkWidget *_create_page_contact
-    (int is_myself, contact_info * info, GaimConnection * gc, contact_info_window * info_window) {
-	GtkWidget *vbox1, *frame;
-	GtkWidget *hbox1, *entry, *label;
-	GtkWidget *hbox, *radio, *table;
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	vbox1 = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0);
-
-	frame = gtk_frame_new("");
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
-	gtk_box_pack_start(GTK_BOX(vbox1), frame, TRUE, TRUE, 0);
-
-	table = gtk_table_new(2, 5, FALSE);
-	gtk_table_set_row_spacings(GTK_TABLE(table), 2);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
-	gtk_container_add(GTK_CONTAINER(frame), table);
-
-	label = gtk_label_new(_("Email"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Address"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Zipcode"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Tel"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Homepage"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->email = entry;
-	gtk_widget_set_size_request(entry, 240, -1);
-	_qq_set_entry(info_window->email, info->email);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->address = entry;
-	_qq_set_entry(info_window->address, info->address);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->zipcode = entry;
-	_qq_set_entry(info_window->zipcode, info->zipcode);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->tel = entry;
-	_qq_set_entry(info_window->tel, info->tel);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 3, 4, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->homepage = entry;
-	_qq_set_entry(info_window->homepage, info->homepage);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 4, 5, GTK_FILL, 0, 0, 0);
-
-	frame = gtk_frame_new(_("Above infomation"));
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
-	if (!is_myself)
-		gtk_widget_set_sensitive(frame, FALSE);
-	gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
-
-	hbox1 = gtk_hbox_new(FALSE, 5);
-	gtk_container_add(GTK_CONTAINER(frame), hbox1);
-
-	radio = gtk_radio_button_new_with_label(NULL, _("Open to all"));
-	info_window->open_contact_radio[0] = radio;
-	gtk_box_pack_start(GTK_BOX(hbox1), radio, FALSE, FALSE, 0);
-
-	radio = gtk_radio_button_new_with_label_from_widget
-	    (GTK_RADIO_BUTTON(radio), _("Only accessible by my frineds"));
-	info_window->open_contact_radio[1] = radio;
-	gtk_box_pack_start(GTK_BOX(hbox1), radio, FALSE, FALSE, 0);
-
-	radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), _("Close to all"));
-	info_window->open_contact_radio[2] = radio;
-	gtk_box_pack_start(GTK_BOX(hbox1), radio, FALSE, FALSE, 0);
-
-	_qq_set_open_contact_radio(info_window, info->is_open_contact);
-
-	return hbox;
-}				// _create_page_contact
-
-/*****************************************************************************/
-static GtkWidget *_create_page_details
-    (int is_myself, contact_info * info, GaimConnection * gc, contact_info_window * info_window) {
-	GList *cbitems;
-	GtkWidget *text, *hbox, *frame;
-	GtkWidget *combo, *table, *label, *entry, *scrolled_window;
-
-	cbitems = NULL;
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	frame = gtk_frame_new("");
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
-	gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0);
-
-	table = gtk_table_new(4, 4, FALSE);
-	gtk_table_set_row_spacings(GTK_TABLE(table), 2);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
-	gtk_container_add(GTK_CONTAINER(frame), table);
-
-	label = gtk_label_new(_("Real Name"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_(" Zodiac"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_(" Blood Type"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_(" Horoscope"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 2, 3, 2, 3, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("College"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Career"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Intro"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->name = entry;
-	gtk_widget_set_size_request(entry, 120, -1);
-	_qq_set_entry(info_window->name, info->name);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	info_window->college = entry;
-	gtk_widget_set_size_request(entry, 120, -1);
-	_qq_set_entry(info_window->college, info->college);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
-
-	combo = gtk_combo_new();
-	cbitems = _get_list_by_array((gchar **) zodiac_names, zodiac_names_count);
-	gtk_combo_set_popdown_strings(GTK_COMBO(combo), cbitems);
-	g_list_free(cbitems);
-	cbitems = NULL;
-	info_window->zodiac = GTK_COMBO(combo)->entry;
-	gtk_entry_set_text(GTK_ENTRY(info_window->zodiac),
-			   get_name_by_index_str((gchar **) zodiac_names, info->zodiac, zodiac_names_count));
-	gtk_widget_set_size_request(combo, 70, -1);
-	gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(combo)->entry), FALSE);
-	gtk_table_attach(GTK_TABLE(table), combo, 3, 4, 0, 1, GTK_FILL, 0, 0, 0);
-	if (!is_myself)
-		gtk_widget_set_sensitive(combo, FALSE);
-
-	combo = gtk_combo_new();
-	cbitems = _get_list_by_array((gchar **) blood_types, blood_types_count);
-	gtk_combo_set_popdown_strings(GTK_COMBO(combo), cbitems);
-	g_list_free(cbitems);
-	cbitems = NULL;
-	info_window->blood = GTK_COMBO(combo)->entry;
-	gtk_entry_set_text(GTK_ENTRY(info_window->blood),
-			   get_name_by_index_str((gchar **) blood_types, info->blood, blood_types_count));
-	gtk_widget_set_size_request(combo, 70, -1);
-	gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(combo)->entry), FALSE);
-	gtk_table_attach(GTK_TABLE(table), combo, 3, 4, 1, 2, GTK_FILL, 0, 0, 0);
-	if (!is_myself)
-		gtk_widget_set_sensitive(combo, FALSE);
-
-	combo = gtk_combo_new();
-	cbitems = _get_list_by_array((gchar **) horoscope_names, horoscope_names_count);
-	gtk_combo_set_popdown_strings(GTK_COMBO(combo), cbitems);
-	g_list_free(cbitems);
-	cbitems = NULL;
-	info_window->horoscope = GTK_COMBO(combo)->entry;
-	gtk_entry_set_text(GTK_ENTRY(info_window->horoscope), get_name_by_index_str((gchar **)
-										    horoscope_names,
-										    info->horoscope,
-										    horoscope_names_count));
-	gtk_widget_set_size_request(combo, 70, -1);
-	gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(combo)->entry), FALSE);
-	gtk_table_attach(GTK_TABLE(table), combo, 3, 4, 2, 3, GTK_FILL, 0, 0, 0);
-	if (!is_myself)
-		gtk_widget_set_sensitive(combo, FALSE);
-
-	combo = gtk_combo_new();
-	cbitems = _get_list_by_array((gchar **) occupation_names, occupation_names_count);
-	gtk_combo_set_popdown_strings(GTK_COMBO(combo), cbitems);
-	g_list_free(cbitems);
-	cbitems = NULL;
-	info_window->occupation = GTK_COMBO(combo)->entry;
-	_qq_set_entry(info_window->occupation, info->occupation);
-	gtk_widget_set_size_request(combo, 120, -1);
-	gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, GTK_FILL, 0, 0, 0);
-	if (!is_myself)
-		gtk_widget_set_sensitive(combo, FALSE);
-
-	text = gtk_text_view_new();
-	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
-	info_window->intro = text;
-	gtk_widget_set_size_request(text, -1, 90);
-	_qq_set_text(info_window->intro, info->intro);
-
-	scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-	gtk_container_add(GTK_CONTAINER(scrolled_window), text);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN);
-	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 2);
-	gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 2);
-
-	gtk_table_attach(GTK_TABLE(table), scrolled_window, 1, 4, 3, 4, GTK_FILL, 0, 0, 0);
-	return hbox;
-}				// _create_page_details
-
-/*****************************************************************************/
-static GtkWidget *_create_page_security
-    (int is_myself, contact_info * info, GaimConnection * gc, contact_info_window * info_window) {
-	GtkWidget *hbox, *frame, *vbox1, *vbox2;
-	GtkWidget *entry, *table, *label, *check_button;
-	GtkWidget *radio, *alignment;
-
-	hbox = gtk_hbox_new(FALSE, 0);
-	vbox1 = gtk_vbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0);
-
-	frame = gtk_frame_new(_("Change Password"));
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
-	gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
-
-	table = gtk_table_new(3, 3, FALSE);
-	gtk_table_set_row_spacings(GTK_TABLE(table), 2);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
-	gtk_container_add(GTK_CONTAINER(frame), table);
-
-	label = gtk_label_new(_("Old Passwd"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-
-	check_button = gtk_check_button_new_with_label(_("I wanna change"));
-	info_window->is_modify_passwd = check_button;
-	g_signal_connect(G_OBJECT(check_button), "toggled",
-			 G_CALLBACK(_change_passwd_checkbutton_callback), info_window);
-	gtk_table_attach(GTK_TABLE(table), check_button, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("New Passwd"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("(less than 16 char)"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
-
-	label = gtk_label_new(_("Confirm"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
-	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-	gtk_widget_set_sensitive(entry, FALSE);
-	info_window->old_password = entry;
-	gtk_widget_set_size_request(entry, 160, -1);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-	gtk_widget_set_sensitive(entry, FALSE);
-	info_window->password[0] = entry;
-	gtk_widget_set_size_request(entry, 160, -1);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
-
-	entry = _qq_entry_new();
-	gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-	gtk_widget_set_sensitive(entry, FALSE);
-	info_window->password[1] = entry;
-	gtk_widget_set_size_request(entry, 160, -1);
-	gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, GTK_FILL, 0, 0, 0);
-
-	alignment = gtk_alignment_new(0, 0, 0, 0);
-	gtk_widget_set_size_request(alignment, -1, 5);
-	gtk_box_pack_start(GTK_BOX(vbox1), alignment, FALSE, FALSE, 0);
-
-	frame = gtk_frame_new(_("Authentication"));
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
-	gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
-
-	vbox2 = gtk_vbox_new(FALSE, 1);
-	gtk_container_add(GTK_CONTAINER(frame), vbox2);
-
-	radio = gtk_radio_button_new_with_label(NULL, _("Anyone can add me"));
-	info_window->auth_radio[0] = radio;
-	gtk_box_pack_start(GTK_BOX(vbox2), radio, FALSE, FALSE, 0);
-
-	radio = gtk_radio_button_new_with_label_from_widget
-	    (GTK_RADIO_BUTTON(radio), _("User needs to be authenticated to add me"));
-	info_window->auth_radio[1] = radio;
-	gtk_box_pack_start(GTK_BOX(vbox2), radio, FALSE, FALSE, 0);
-
-	radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), _("Nobody can add me"));
-	info_window->auth_radio[2] = radio;
-	gtk_box_pack_start(GTK_BOX(vbox2), radio, FALSE, FALSE, 0);
-
-	_qq_set_auth_type_radio(info_window, info->auth_type);
-
-	return hbox;
-}				// _create_page_security 
-
-/*****************************************************************************/
-void qq_show_contact_info_dialog(contact_info * info, GaimConnection * gc, contact_info_window * info_window) {
-
-	GaimAccount *a = gc->account;
-	gboolean is_myself;
-	GtkWidget *label, *window, *notebook, *vbox, *bbox, *button;
-
-	is_myself = (!strcmp(info->uid, a->username));
-	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-//	gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(mainwindow));  //by gfhuang
-	info_window->window = window;
-
-	// we need to duplicate here, 
-	// as the passed-in info structure will be freed in his function
-	info_window->old_info = (contact_info *) g_strdupv((gchar **) info);
-
-	/* When the window is given the "delete_event" signal (this is given
-	 * by the window manager, usually by the "close" option, or on the
-	 * titlebar), we ask it to call the delete_event () function
-	 * as defined above. The data passed to the callback  
-	 * function is NULL and is ignored in the callback function. 
-	 */
-	g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(_window_deleteevent), NULL);
-
-	/* Here we connect the "destroy" event to a signal handler.  
-	 * This event occurs when we call gtk_widget_destroy() on the window,
-	 * or if we return FALSE in the "delete_event" callback. 
-	 */
-	g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(_info_window_destroy), gc);
-
-	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
-
-	if (is_myself)
-		gtk_window_set_title(GTK_WINDOW(window), _("My Information"));
-	else
-		gtk_window_set_title(GTK_WINDOW(window), _("My Buddy's Information"));
-	gtk_container_set_border_width(GTK_CONTAINER(window), 5);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(window), vbox);
-
-	notebook = gtk_notebook_new();
-	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
-
-	label = gtk_label_new(_("Basic"));
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), _create_page_basic(is_myself, info, gc, info_window), label);
-
-	label = gtk_label_new(_("Contact"));
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), _create_page_contact(is_myself, info, gc, info_window), label);
-
-	label = gtk_label_new(_("Details"));
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), _create_page_details(is_myself, info, gc, info_window), label);
-
-	if (is_myself) {
-		label = gtk_label_new(_("Security"));
-		gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
-					 _create_page_security(is_myself, info, gc, info_window), label);
-	}
-
-	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-
-	bbox = gtk_hbutton_box_new();
-	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
-	gtk_box_set_spacing(GTK_BOX(bbox), 10);
-
-	button = gtk_button_new_with_label(_("Modify"));
-	g_object_set_data(G_OBJECT(button), "user_data", (gpointer) info_window);
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(_info_window_change), gc);
-	gtk_container_add(GTK_CONTAINER(bbox), button);
-
-	if (is_myself)
-		gtk_widget_set_sensitive(button, TRUE);
-	else
-		gtk_widget_set_sensitive(button, FALSE);
-
-	button = gtk_button_new_with_label(_("Refresh"));
-	info_window->refresh_button = button;
-	g_object_set_data(G_OBJECT(button), "user_data", (gpointer) info_window);
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(_info_window_refresh), gc);
-	gtk_container_add(GTK_CONTAINER(bbox), button);
-
-	button = gtk_button_new_with_label(_("Close"));
-	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(_window_close), info_window->window);
-	gtk_container_add(GTK_CONTAINER(bbox), button);
-
-	gtk_box_pack_start(GTK_BOX(vbox), bbox, TRUE, TRUE, 5);
-
-	_no_edit(info_window->uid_entry);	// uid entry cannot be changed
-	if (!is_myself) {
-		_no_edit(info_window->nick);
-		_no_edit(info_window->country);
-		_no_edit(info_window->age);
-		_no_edit(info_window->gender);
-		_no_edit(info_window->province);
-		_no_edit(info_window->city);
-		_no_edit(info_window->email);
-		_no_edit(info_window->address);
-		_no_edit(info_window->zipcode);
-		_no_edit(info_window->tel);
-		_no_edit(info_window->name);
-		_no_edit(info_window->blood);
-		_no_edit(info_window->college);
-		_no_edit(info_window->occupation);
-		_no_edit(info_window->zodiac);
-		_no_edit(info_window->horoscope);
-		_no_edit(info_window->homepage);
-		gtk_text_view_set_editable(GTK_TEXT_VIEW(info_window->intro), FALSE);
-	}
-	gtk_widget_show_all(window);
-}				// qq_show_contact_info_dialog
-
-/*****************************************************************************/
-void qq_refresh_contact_info_dialog(contact_info * new_info, GaimConnection * gc, contact_info_window * info_window) {
-	GaimAccount *a;
-	gboolean is_myself;
-	contact_info *info;
-	a = gc->account;
-
-	if (info_window->old_info)
-		g_strfreev((gchar **) info_window->old_info);
-
-	// we need to duplicate here, 
-	// as the passed-in info structure will be freed in his function
-	info = (contact_info *) g_strdupv((gchar **) new_info);
-	info_window->old_info = info;
-
-	is_myself = !(g_ascii_strcasecmp(info->uid, a->username));
-	gtk_widget_set_sensitive(info_window->refresh_button, TRUE);
-
-	if (is_myself) {
-		_qq_set_auth_type_radio(info_window, info->auth_type);
-		_qq_set_open_contact_radio(info_window, info->is_open_contact);
-	}
-
-	_qq_set_entry(info_window->uid_entry, info->uid);
-	_qq_set_entry(info_window->nick, info->nick);
-	_qq_set_entry(info_window->country, info->country);
-	_qq_set_entry(info_window->age, info->age);
-	_qq_set_entry(info_window->gender, info->gender);
-	_qq_set_entry(info_window->province, info->province);
-	_qq_set_entry(info_window->city, info->city);
-	_qq_set_entry(info_window->email, info->email);
-	_qq_set_entry(info_window->address, info->address);
-	_qq_set_entry(info_window->zipcode, info->zipcode);
-	_qq_set_entry(info_window->tel, info->tel);
-	_qq_set_entry(info_window->name, info->name);
-	gtk_entry_set_text(GTK_ENTRY(info_window->zodiac),
-			   get_name_by_index_str((gchar **) zodiac_names, info->zodiac, zodiac_names_count));
-	gtk_entry_set_text(GTK_ENTRY(info_window->horoscope), get_name_by_index_str((gchar **)
-										    horoscope_names,
-										    info->horoscope,
-										    horoscope_names_count));
-	gtk_entry_set_text(GTK_ENTRY(info_window->blood),
-			   get_name_by_index_str((gchar **) blood_types, info->blood, blood_types_count));
-	_qq_set_entry(info_window->college, info->college);
-	_qq_set_entry(info_window->occupation, info->occupation);
-	_qq_set_entry(info_window->homepage, info->homepage);
-
-	_qq_set_image(info_window->face, (guint8) atoi(info->face));
-
-	_qq_set_text(info_window->intro, info->intro);
-}				// qq_refresh_contact_info_dialog
-
-/*****************************************************************************/
-// END OF FILE
--- a/src/protocols/qq/infodlg.h	Mon Jul 24 09:25:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/**
- * The QQ2003C protocol plugin
- *
- * for gaim
- *
- * Copyright (C) 2004 Puzzlebird
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-// START OF FILE
-/*****************************************************************************/
-#ifndef _QQ_INFODLG_H_
-#define _QQ_INFODLG_H_
-
-#include <glib.h>
-#include <gtk/gtk.h>
-#include "connection.h"		// GaimConnection
-
-#include "buddy_info.h"		// contact_info
-#include "qq.h"			// qq_data
-
-typedef struct _contact_info_window contact_info_window;
-
-struct _contact_info_window {
-	guint32 uid;
-	GtkWidget *window;
-	GtkWidget *refresh_button;
-	GtkWidget *uid_entry,
-	    *face,
-	    *nick,
-	    *country,
-	    *age,
-	    *gender,
-	    *province,
-	    *city,
-	    *email,
-	    *address, *zipcode, *tel, *name, *blood, *college, *occupation, *zodiac, *horoscope, *homepage, *intro;
-	GtkWidget *open_contact_radio[3];
-	GtkWidget *auth_radio[3], *is_modify_passwd, *old_password, *password[2];
-	contact_info *old_info;
-};
-
-void qq_contact_info_window_free(qq_data * qd);
-
-void qq_show_contact_info_dialog(contact_info * info, GaimConnection * gc, contact_info_window * info_window);
-void qq_refresh_contact_info_dialog(contact_info * info, GaimConnection * gc, contact_info_window * info_window);
-
-#endif
-/*****************************************************************************/
-// END OF FILE
--- a/src/protocols/qq/qq.c	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/qq.c	Mon Jul 24 13:39:12 2006 +0000
@@ -32,10 +32,8 @@
 #include "request.h"
 #include "accountopt.h"
 #include "prpl.h"
-#include "gtkroomlist.h"
-#include "gtklog.h"
 #include "server.h"
-#include "util.h" 		/* GaimMenuAction, gaim_menu_action_new, gaim2beta2, gfhuang*/
+#include "util.h" 		/* GaimMenuAction, gaim_menu_action_new */
 
 #include "utils.h"
 #include "buddy_info.h"
@@ -50,7 +48,6 @@
 #include "group.h"		/* chat_info, etc */
 #include "header_info.h"	/* qq_get_cmd_desc */
 #include "im.h"
-#include "infodlg.h"
 #include "keep_alive.h"
 #include "ip_location.h"	/* qq_ip_get_location */
 #include "login_logout.h"
@@ -88,48 +85,12 @@
 };
 const gint tcp_server_amount = (sizeof(tcp_server_list) / sizeof(tcp_server_list[0]));
 
-/*********** Prototypes ***********/
-
-static void _qq_login(GaimAccount * account);
-static void _qq_close(GaimConnection * gc);
-static const gchar *_qq_list_icon(GaimAccount * a, GaimBuddy * b);
-static gchar *_qq_status_text(GaimBuddy *b);
-static void _qq_tooltip_text(GaimBuddy *b, GString *tooltip, gboolean full);
-static void _qq_list_emblems(GaimBuddy * b, const char **se, const char **sw, const char **nw, const char **ne);
-static GList *_qq_away_states(GaimAccount *ga);
-static void _qq_set_away(GaimAccount *account, GaimStatus *status);
-static gint _qq_send_im(GaimConnection * gc, const gchar * who, const gchar * message, GaimMessageFlags flags); 
-static int _qq_chat_send(GaimConnection *gc, int channel, const char *message, GaimMessageFlags flags);
-static void _qq_get_info(GaimConnection * gc, const gchar * who);
-static void _qq_menu_get_my_info(GaimPluginAction * action);
-//static void _qq_menu_block_buddy(GaimBlistNode * node);
-static void _qq_menu_show_login_info(GaimPluginAction * action);
-static void _qq_menu_show_about(GaimPluginAction * action);
-static void _qq_menu_any_cmd_send_cb(GaimConnection * gc, GaimRequestFields * fields);
-static void _qq_menu_any_cmd(GaimPluginAction * action);
-static void _qq_menu_locate_ip_cb(GaimConnection * gc, GaimRequestFields * fields);
-static void _qq_menu_locate_ip(GaimPluginAction *action);
-static void _qq_menu_search_or_add_permanent_group(GaimPluginAction * action);
-static void _qq_menu_create_permanent_group(GaimPluginAction * action);
-static void _qq_menu_unsubscribe_group(GaimBlistNode * node);
-static void _qq_menu_manage_group(GaimBlistNode * node);
-static void _qq_menu_show_system_message(GaimPluginAction *action);
-//static void _qq_menu_send_file(GaimBlistNode * node, gpointer ignored);
-static GList *_qq_actions(GaimPlugin * plugin, gpointer context);
-static GList *_qq_chat_menu(GaimBlistNode *node);
-static GList *_qq_buddy_menu(GaimBlistNode * node);
-static void _qq_keep_alive(GaimConnection * gc);
-static void _qq_get_chat_buddy_info(GaimConnection * gc, gint channel, const gchar * who);
-static gchar *_qq_get_chat_buddy_real_name(GaimConnection * gc, gint channel, const gchar * who);
-//static GaimPluginPrefFrame *get_plugin_pref_frame(GaimPlugin * plugin);
-static void init_plugin(GaimPlugin * plugin);
-
 static void _qq_login(GaimAccount * account)
 {
 	const gchar *qq_server, *qq_port;
 	qq_data *qd;
 	GaimConnection *gc;
-	GaimPresence *presence;				//gfhuang
+	GaimPresence *presence;	
 	gboolean login_hidden, use_tcp;
 
 	g_return_if_fail(account != NULL);
@@ -145,7 +106,6 @@
 	qq_server = gaim_account_get_string(account, "server", NULL);
 	qq_port = gaim_account_get_string(account, "port", NULL);
 	use_tcp = gaim_account_get_bool(account, "use_tcp", FALSE);
-//	login_hidden = gaim_account_get_bool(account, "hidden", FALSE);		gfhuang
         presence = gaim_account_get_presence(account);
         login_hidden = gaim_presence_is_status_primitive_active(presence, GAIM_STATUS_INVISIBLE);
 
@@ -183,19 +143,27 @@
 /* returns the icon name for a buddy or protocol */
 static const gchar *_qq_list_icon(GaimAccount * a, GaimBuddy * b)
 {
+	/* XXX temp commented out until we figure out what to do with
+	 * status icons */
+	/*
 	gchar *filename;
 	qq_buddy *q_bud;
 	gchar icon_suffix;
+	*/
 
 	/* do not use g_return_val_if_fail, as it is not assertion */
 	if (b == NULL || b->proto_data == NULL)
 		return "qq";
 
+	/*
 	q_bud = (qq_buddy *) b->proto_data;
+
 	icon_suffix = get_suffix_from_status(q_bud->status);
 	filename = get_icon_name(q_bud->icon / 3 + 1, icon_suffix);
 
 	return filename;
+	*/
+	return "qq";
 }
 
 
@@ -203,21 +171,15 @@
 static gchar *_qq_status_text(GaimBuddy *b)
 {
 	qq_buddy *q_bud;
-//	gboolean show_info;
 	GString *status;
 	gchar *ret;
 
-//	show_info = gaim_prefs_get_bool("/plugins/prpl/qq/show_status_by_icon");
-//	if (!show_info)
-//		return NULL;
-
 	q_bud = (qq_buddy *) b->proto_data;
 	if (q_bud == NULL)
 		return NULL;
 
 	status = g_string_new("");
 
-	//by gfhuang
 	switch(q_bud->status) {
 	case QQ_BUDDY_OFFLINE:
 		g_string_append(status, "My Offline");
@@ -270,19 +232,19 @@
 static void _qq_tooltip_text(GaimBuddy *b, GString *tooltip, gboolean full)
 {
 	qq_buddy *q_bud;
-	gchar *country, *country_utf8, *city, *city_utf8;
-	guint32 ip_value;
+	//gchar *country, *country_utf8, *city, *city_utf8;
+	//guint32 ip_value;
 	gchar *ip_str;
 
 	g_return_if_fail(b != NULL);
 
 	q_bud = (qq_buddy *) b->proto_data;
-	g_return_if_fail(q_bud != NULL);
+	//g_return_if_fail(q_bud != NULL);
 
-//	if (is_online(q_bud->status)) //disable by gfhuang
+	if (GAIM_BUDDY_IS_ONLINE(b) && q_bud != NULL)
 	{
+		/*
 		ip_value = ntohl(*(guint32 *) (q_bud->ip));
-//		tooltip = g_string_new("");                     beta2, gfhuang
 		if (qq_ip_get_location(ip_value, &country, &city)) {
 			country_utf8 = qq_to_utf8(country, QQ_CHARSET_DEFAULT);
 			city_utf8 = qq_to_utf8(city, QQ_CHARSET_DEFAULT);
@@ -292,12 +254,13 @@
 			g_free(country_utf8);
 			g_free(city_utf8);
 		}
-		//memory leak fixed by gfhuang
+		*/
 		ip_str = gen_ip_str(q_bud->ip);
-		g_string_append_printf(tooltip, "\n<b>%s Address:</b> %s:%d", (q_bud->comm_flag & QQ_COMM_FLAG_TCP_MODE)
+		if (strlen(ip_str) != 0) {
+			g_string_append_printf(tooltip, "\n<b>%s Address:</b> %s:%d", (q_bud->comm_flag & QQ_COMM_FLAG_TCP_MODE)
 				       ? "TCP" : "UDP", ip_str, q_bud->port);
+		}
 		g_free(ip_str);
-		//added by gfhuang
 		g_string_append_printf(tooltip, "\n<b>Age:</b> %d", q_bud->age);
         	switch (q_bud->gender) {
 	        case QQ_BUDDY_GENDER_GG:
@@ -319,25 +282,13 @@
 }
 
 /* we can show tiny icons on the four corners of buddy icon, */
-static void _qq_list_emblems(GaimBuddy * b, const char **se, const char **sw, const char **nw, const char **ne) {   //add const by gfhuang
+static void _qq_list_emblems(GaimBuddy * b, const char **se, const char **sw, const char **nw, const char **ne) { 
 	// each char ** are refering to filename in pixmaps/gaim/status/default/*png
 
 	qq_buddy *q_bud = b->proto_data;
-//        GaimPresence *presence;
         const char *emblems[4] = { NULL, NULL, NULL, NULL };
         int i = 0;
 
-/*        presence = gaim_buddy_get_presence(b);
-
-        if (!gaim_presence_is_online(presence))
-                emblems[i++] = "offline";
-        else if (gaim_presence_is_status_active(presence, "busy") ||
-                         gaim_presence_is_status_active(presence, "phone"))
-                emblems[i++] = "occupied";
-        else if (!gaim_presence_is_available(presence))
-                emblems[i++] = "away";
-*/
-
         if (q_bud == NULL)
         {
                 emblems[0] = "offline";
@@ -351,9 +302,6 @@
 		if (q_bud->comm_flag & QQ_COMM_FLAG_VIDEO)
 			emblems[i++] = "video";
 
-
-//                if (!(user->list_op & (1 << MSN_LIST_RL)))
-//                        emblems[i++] = "nr";
         }
 
         *se = emblems[0];
@@ -365,7 +313,6 @@
 }
 
 /* QQ away status (used to initiate QQ away packet) */
-//Rewritten by gfhuang
 static GList *_qq_away_states(GaimAccount *ga) 
 {
 	GaimStatusType *status;
@@ -379,7 +326,7 @@
 			"away", _("QQ: Away"), FALSE, TRUE, FALSE);
         types = g_list_append(types, status);
 
-        status = gaim_status_type_new_full(GAIM_STATUS_INVISIBLE, /* HIDDEN, change to gaim2beta2, gfhuang */ 
+        status = gaim_status_type_new_full(GAIM_STATUS_INVISIBLE, 
 			"invisible", _("QQ: Invisible"), FALSE, TRUE, FALSE);
         types = g_list_append(types, status);
 
@@ -389,29 +336,10 @@
 
 	return types;
 }
-/*
-GList *_qq_away_states(GaimConnection * gc)
-{
-	GList *m;
-
-	g_return_val_if_fail(gc != NULL, NULL);
-
-	m = NULL;
-	m = g_list_append(m, _("QQ: Available"));
-	m = g_list_append(m, _("QQ: Away"));
-	m = g_list_append(m, _("QQ: Invisible"));
-	m = g_list_append(m, GAIM_AWAY_CUSTOM);       
-	return m;
-}
-*/
-
-
 
 /* initiate QQ away with proper change_status packet */
-//void _qq_set_away(GaimConnection * gc, const char *state, const char *msg)
 static void _qq_set_away(GaimAccount *account, GaimStatus *status)
 {
-	// by gfhuang
 	GaimConnection *gc = gaim_account_get_connection(account);
 	const char *state = gaim_status_get_id(status);
 
@@ -422,7 +350,6 @@
 
 	qd = (qq_data *) gc->proto_data;
 
-	// by gfhuang
 	if(0 == strcmp(state, "available"))
 		qd->status = QQ_SELF_STATUS_AVAILABLE;
 	else if (0 == strcmp(state, "away"))
@@ -432,38 +359,11 @@
 	else
 		qd->status = QQ_SELF_STATUS_AVAILABLE;
 
-/*	if (gc->away) {                //disable by gfhuang, 1.2006
-		g_free(gc->away);
-		gc->away = NULL;
-	}
-
-	if (msg) {
-		qd->status = QQ_SELF_STATUS_CUSTOM;
-		gc->away = g_strdup(msg);
-	} else if (state) {
-		gc->away = g_strdup("");
-		if (g_ascii_strcasecmp(state, _("QQ: Available")) == 0)
-			qd->status = QQ_SELF_STATUS_AVAILABLE;
-		else if (g_ascii_strcasecmp(state, _("QQ: Away")) == 0)
-			qd->status = QQ_SELF_STATUS_AWAY;
-		else if (g_ascii_strcasecmp(state, _("QQ: Invisible")) == 0)
-			qd->status = QQ_SELF_STATUS_INVISIBLE;
-		else if (g_ascii_strcasecmp(state, GAIM_AWAY_CUSTOM) == 0) {
-			if (gc->is_idle)
-				qd->status = QQ_SELF_STATUS_IDLE;
-			else
-				qd->status = QQ_SELF_STATUS_AVAILABLE;
-		}
-	} else if (gc->is_idle)
-		qd->status = QQ_SELF_STATUS_IDLE; 
-	else
-		qd->status = QQ_SELF_STATUS_AVAILABLE;
-*/
 	qq_send_packet_change_status(gc);
 }
 
 
-// IMPORTANT: GaimConvImFlags -> GaimMessageFlags    //gfhuang
+// IMPORTANT: GaimConvImFlags -> GaimMessageFlags
 /* send an instance msg to a buddy */
 static gint _qq_send_im(GaimConnection * gc, const gchar * who, const gchar * message, GaimMessageFlags flags)
 {
@@ -495,7 +395,7 @@
 }
 
 /* send a chat msg to a QQ Qun */
-static int _qq_chat_send(GaimConnection *gc, int channel, const char *message, GaimMessageFlags flags/*gfhuang*/)
+static int _qq_chat_send(GaimConnection *gc, int channel, const char *message, GaimMessageFlags flags)
 {
 	gchar *msg, *msg_with_qq_smiley;
 	qq_group *group;
@@ -531,11 +431,11 @@
 		return;
 	}
 
-	qq_send_packet_get_info(gc, uid, TRUE);	/* need to show up info window */
+	qq_send_packet_get_info(gc, uid, TRUE);
 }
 
 /* get my own information */
-static void _qq_menu_get_my_info(GaimPluginAction * action)
+static void _qq_menu_modify_my_info(GaimPluginAction * action)
 {
 	GaimConnection *gc = (GaimConnection *) action->context;
 	qq_data *qd;
@@ -543,7 +443,8 @@
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
 
 	qd = (qq_data *) gc->proto_data;
-	_qq_get_info(gc, uid_to_gaim_name(qd->uid));
+	//_qq_get_info(gc, uid_to_gaim_name(qd->uid));
+	qq_prepare_modify_info(gc);
 }
 
 /* remove a buddy from my list and remove myself from his list */
@@ -615,136 +516,7 @@
 	g_string_free(info, TRUE);
 }
 
-/* show about page about QQ plugin */
-static void _qq_menu_show_about(GaimPluginAction * action)
-{
-	GaimConnection *gc = (GaimConnection *) action->context;
-	qq_data *qd;
-	GString *info;
-	gchar *head;
-
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
-
-	qd = (qq_data *) gc->proto_data;
-	info = g_string_new("<html><body>\n");
-
-	g_string_append_printf(info, _("<b>Author</b> : %s<br>\n"), OPENQ_AUTHOR);
-	g_string_append(info, "Copyright (c) 2004.  All rights reserved.<br><br>\n");
-
-	g_string_append(info, _("<p><b>Code Contributors</b><br>\n"));
-	g_string_append(info, "gfhuang   : patches for gaim 2.0.0beta2<br>\n");
-	g_string_append(info, "henryouly : file transfer, udp sock5 proxy and qq_show<br>\n");
-	g_string_append(info, "arfankai  : fixed bugs in char_conv.c<br>\n");
-	g_string_append(info, "rakescar  : provided filter for HTML tag<br>\n");
-	g_string_append(info, "yyw       : improved performance on PPC linux<br>\n");
-	g_string_append(info, "lvxiang   : provided ip to location original code<br><br>\n");
-
-	g_string_append(info, _("<p><b>Acknowledgement</b><br>\n"));
-	g_string_append(info, "Shufeng Tan : http://sf.net/projects/perl-oicq<br>\n");
-	g_string_append(info, "Jeff Ye : http://www.sinomac.com<br>\n");
-	g_string_append(info, "Hu Zheng : http://forlinux.yeah.net<br><br>\n");
-
-	g_string_append(info, "<p>And, my parents...\n");
-
-	g_string_append(info, "</body></html>");
-
-	head = g_strdup_printf("About QQ Plugin Ver %s", VERSION);
-	gaim_notify_formatted(gc, NULL, head, NULL, info->str, NULL, NULL);
-
-	g_free(head);
-	g_string_free(info, TRUE);
-}
-
-/* callback of sending any command to QQ server */
-static void _qq_menu_any_cmd_send_cb(GaimConnection * gc, GaimRequestFields * fields)
-{
-	GList *groups, *flds;
-	GaimRequestField *field;
-	const gchar *id, *value;
-	gchar *cmd_str, *data_str, **segments;
-	guint16 cmd;
-	guint8 *data;
-	gint i, data_len;
-
-	cmd_str = NULL;
-	data_str = NULL;
-	cmd = 0x00;
-	data = NULL;
-	data_len = 0;
-
-	for (groups = gaim_request_fields_get_groups(fields); groups; groups = groups->next) {
-		for (flds = gaim_request_field_group_get_fields(groups->data); flds; flds = flds->next) {
-			field = flds->data;
-			id = gaim_request_field_get_id(field);
-			value = gaim_request_field_string_get_value(field);
-
-			if (!g_ascii_strcasecmp(id, "cmd"))
-				cmd_str = g_strdup(value);
-			else if (!g_ascii_strcasecmp(id, "data"))
-				data_str = g_strdup(value);
-		}
-	}
-
-	if (cmd_str != NULL)
-		cmd = (guint16) strtol(cmd_str, NULL, 16);
-
-	if (data_str != NULL) {
-		if (NULL == (segments = split_data(data_str, strlen(data_str), ",", 0))) {
-			g_free(cmd_str);
-			g_free(data_str);
-			return;
-		}
-		for (data_len = 0; segments[data_len] != NULL; data_len++) {;
-		}
-		data = g_newa(guint8, data_len);
-		for (i = 0; i < data_len; i++)
-			data[i] = (guint8) strtol(segments[i], NULL, 16);
-		g_strfreev(segments);
-	}
-
-	if (cmd && data_len > 0) {
-		gaim_debug(GAIM_DEBUG_INFO, "QQ",
-			   "Send Any cmd: %s, data dump\n%s", qq_get_cmd_desc(cmd), hex_dump_to_str(data, data_len));
-		qq_send_cmd(gc, cmd, TRUE, 0, TRUE, data, data_len);
-	}
-
-	g_free(cmd_str);
-	g_free(data_str);
-}				
-
-/* send any command with data to QQ server, for testing and debuggin only */
-static void _qq_menu_any_cmd(GaimPluginAction * action)
-{
-	GaimConnection *gc = (GaimConnection *) action->context;
-	qq_data *qd;
-	const char *tips;
-	GaimRequestField *field;
-	GaimRequestFields *fields;
-	GaimRequestFieldGroup *group;
-
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
-	qd = (qq_data *) gc->proto_data;
-
-	tips = _("Separate the value with \",\"\nAllow \"0x\" before each value");
-	fields = gaim_request_fields_new();
-	group = gaim_request_field_group_new(NULL);
-	gaim_request_fields_add_group(fields, group);
-
-	/* sample: 0x22 */
-	field = gaim_request_field_string_new("cmd", _("CMD Code"), NULL, FALSE);
-	gaim_request_field_group_add_field(group, field);
-	/* sample: 0x00,0x15,0xAB */
-	/*     or: 00,15,AB */
-	/* the delimit is ",", allow 0x before the value */
-	field = gaim_request_field_string_new("data", _("Raw Data"), NULL, FALSE);
-	gaim_request_field_group_add_field(group, field);
-
-	gaim_request_fields(gc, _("QQ Any Command"),
-			    _("Send Arbitrary Command"), tips, fields,
-			    _("Send"), G_CALLBACK(_qq_menu_any_cmd_send_cb), _("Cancel"), NULL, gc);
-}
-
-/* added by gfhuang */
+/*
 static void _qq_menu_locate_ip_cb(GaimConnection * gc, GaimRequestFields * fields)
 {
         GList *groups, *flds;
@@ -790,7 +562,6 @@
 	}
 }
 
-/* added by gfhuang */
 static void _qq_menu_locate_ip(GaimPluginAction *action)
 {
         GaimConnection *gc = (GaimConnection *) action->context;
@@ -811,12 +582,16 @@
 			_("Locate an IP address"), NULL, fields,
 			 _("Check"), G_CALLBACK(_qq_menu_locate_ip_cb), _("Cancel"), NULL, gc);
 }
+*/
 
+/*
 static void _qq_menu_search_or_add_permanent_group(GaimPluginAction * action)
 {
 	gaim_gtk_roomlist_dialog_show();
 }
+*/
 
+/*
 static void _qq_menu_create_permanent_group(GaimPluginAction * action)
 {
 	GaimConnection *gc = (GaimConnection *) action->context;
@@ -827,49 +602,43 @@
 			   "OpenQ", FALSE, FALSE, NULL,
 			   _("Create"), G_CALLBACK(qq_group_create_with_name), _("Cancel"), NULL, gc);
 }
+*/
 
-static void _qq_menu_unsubscribe_group(GaimBlistNode * node) // by gfhuang, gpointer param_components)
+/* XXX re-enable this
+static void _qq_menu_unsubscribe_group(GaimBlistNode * node)
 {
-//	GaimBuddy *buddy;		by gfhuang
 	GaimChat *chat = (GaimChat *)node;
 	GaimConnection *gc = gaim_account_get_connection(chat->account);
 	GHashTable *components = chat -> components;
-//	GHashTable *components = (GHashTable *) param_components;
 
-//	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));	bug! found by gfhuang
 	g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
 
-//	buddy = (GaimBuddy *) node;
-//	gc = gaim_account_get_connection(buddy->account);
-
 	g_return_if_fail(gc != NULL && components != NULL);
 	qq_group_exit(gc, components);
 }
 
-static void _qq_menu_manage_group(GaimBlistNode * node) // by gfhuang, gpointer param_components)
+// XXX re-enable this
+static void _qq_menu_manage_group(GaimBlistNode * node)
 {
-//	GaimBuddy *buddy;		by gfhuang
 	GaimChat *chat = (GaimChat *)node;
 	GaimConnection *gc = gaim_account_get_connection(chat->account);
 	GHashTable *components = chat -> components;
-//	GHashTable *components = (GHashTable *) param_components;
 
-//	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));	bug! found by gfhuang
 	g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
 
-//	buddy = (GaimBuddy *) node;
-//	gc = gaim_account_get_connection(buddy->account);
-
 	g_return_if_fail(gc != NULL && components != NULL);
 	qq_group_manage_group(gc, components);
 }
+*/
 
+/*
 static void _qq_menu_show_system_message(GaimPluginAction *action)
 {
 	GaimConnection *gc = (GaimConnection *) action->context;
 	g_return_if_fail ( gc != NULL );
 	gaim_gtk_log_show(GAIM_LOG_IM, "systemim", gaim_connection_get_account(gc));
 }
+*/
 
 /* TODO: re-enable this
 static void _qq_menu_send_file(GaimBlistNode * node, gpointer ignored)
@@ -896,61 +665,61 @@
 	GaimPluginAction *act;
 
 	m = NULL;
-	act = gaim_plugin_action_new(_("Modify My Information"), _qq_menu_get_my_info);
+	act = gaim_plugin_action_new(_("Modify My Information"), _qq_menu_modify_my_info);
 	m = g_list_append(m, act);
 
 	act = gaim_plugin_action_new(_("Show Login Information"), _qq_menu_show_login_info);
 	m = g_list_append(m, act);
 
+	/* XXX consider re-enabling this
 	act = gaim_plugin_action_new(_("Show System Message"), _qq_menu_show_system_message);
 	m = g_list_append(m, act);
+	*/
 
-	act = gaim_plugin_action_new(_("Any QQ Command"), _qq_menu_any_cmd);
-	m = g_list_append(m, act);
-
+	/* XXX the old group gtk code needs to moved to the gaim UI before this can be used
 	act = gaim_plugin_action_new(_("Qun: Search a permanent Qun"), _qq_menu_search_or_add_permanent_group);
 	m = g_list_append(m, act);
 
 	act = gaim_plugin_action_new(_("Qun: Create a permanent Qun"), _qq_menu_create_permanent_group);
 	m = g_list_append(m, act);
+	*/
 
+	/* XXX consider re-enabling this
 	act = gaim_plugin_action_new(_("Locate an IP"), _qq_menu_locate_ip);
         m = g_list_append(m, act);
+	*/
 	
-	act = gaim_plugin_action_new(_("About QQ Plugin"), _qq_menu_show_about);
-	m = g_list_append(m, act);
-
 	return m;
 }
 
 /* chat-related (QQ Qun) menu shown up with right-click */
-static GList *_qq_chat_menu(GaimBlistNode *node)	//gfhuang
+/* XXX re-enable this
+static GList *_qq_chat_menu(GaimBlistNode *node)
 {
 	GList *m;
 	GaimMenuAction *act;
 
 	m = NULL;
-	act = gaim_menu_action_new(_("Exit this QQ Qun"), GAIM_CALLBACK(_qq_menu_unsubscribe_group), NULL, NULL);   //add NULL by gfhuang
+	act = gaim_menu_action_new(_("Exit this QQ Qun"), GAIM_CALLBACK(_qq_menu_unsubscribe_group), NULL, NULL);
 	m = g_list_append(m, act);
 
-	act = gaim_menu_action_new(_("Show Details"), GAIM_CALLBACK(_qq_menu_manage_group), NULL, NULL);  //add NULL by gfhuang
+	act = gaim_menu_action_new(_("Show Details"), GAIM_CALLBACK(_qq_menu_manage_group), NULL, NULL);
 	m = g_list_append(m, act);
 
 	return m;
 }
+*/
 /* buddy-related menu shown up with right-click */
+/* XXX re-enable this
 static GList *_qq_buddy_menu(GaimBlistNode * node)
 {
 	GList *m;
-	/*GaimBlistNodeAction->GaimMenuAction, gaim2beta2, gfhuang*/
-//	GaimMenuAction  *act;
 
-	if(GAIM_BLIST_NODE_IS_CHAT(node))		//by gfhuang
+	if(GAIM_BLIST_NODE_IS_CHAT(node))
 		return _qq_chat_menu(node);
 	
 	m = NULL;
-	/*gaim_blist_node_action_new -> gaim_menu_action_new, gaim2beta2, gfhuang */
-
+*/
 /* TODO : not working, temp commented out by gfhuang 
 
 	act = gaim_menu_action_new(_("Block this buddy"), GAIM_CALLBACK(_qq_menu_block_buddy), NULL, NULL); //add NULL by gfhuang
@@ -960,9 +729,10 @@
 		m = g_list_append(m, act);
 //	}
 */
-
+/*
 	return m;
 }
+*/
 
 
 static void _qq_keep_alive(GaimConnection * gc)
@@ -980,8 +750,7 @@
 		group = (qq_group *) list->data;
 		if (group->my_status == QQ_GROUP_MEMBER_STATUS_IS_MEMBER ||
 		    group->my_status == QQ_GROUP_MEMBER_STATUS_IS_ADMIN)
-// no need to get info time and time again, online members enough, gfhuang
-//			qq_send_cmd_group_get_group_info(gc, group);
+			// no need to get info time and time again, online members enough
 			qq_send_cmd_group_get_online_member(gc, group);
 	
 		list = list->next;
@@ -1018,49 +787,6 @@
 	gaim_notify_warning(gc, NULL, _("This function has not be implemented yet"), _("Please wait for new version"));
 }
 
-/*
-static GaimPluginPrefFrame *get_plugin_pref_frame(GaimPlugin * plugin)
-{
-	GaimPluginPrefFrame *frame;
-	GaimPluginPref *ppref;
-
-	frame = gaim_plugin_pref_frame_new();
-
-	ppref = gaim_plugin_pref_new_with_label(_("Convert IP to location"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	ppref = gaim_plugin_pref_new_with_name_and_label("/plugins/prpl/qq/ipfile", _("IP file"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	ppref = gaim_plugin_pref_new_with_label(_("Display Options"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	ppref = gaim_plugin_pref_new_with_name_and_label
-	    ("/plugins/prpl/qq/show_status_by_icon", _("Show gender/age information beside buddy icons"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	ppref = gaim_plugin_pref_new_with_name_and_label
-	    ("/plugins/prpl/qq/show_fake_video", _("Fake an video for GAIM QQ (re-login to activate)"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	ppref = gaim_plugin_pref_new_with_label(_("System Options"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	ppref = gaim_plugin_pref_new_with_name_and_label
-	    ("/plugins/prpl/qq/prompt_for_missing_packet", _("Prompt user for actions if there are missing packets"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	ppref = gaim_plugin_pref_new_with_name_and_label
-	    ("/plugins/prpl/qq/prompt_group_msg_on_recv", _("Pop up Qun chat window when receive Qun message"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	ppref = gaim_plugin_pref_new_with_name_and_label("/plugins/prpl/qq/datadir", _("OpenQ installed directory"));
-	gaim_plugin_pref_frame_add(frame, ppref);
-
-	return frame;
-}
-*/
-
 GaimPlugin *my_protocol = NULL;
 static GaimPluginProtocolInfo prpl_info	= {
 	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_USE_POINTSIZE,
@@ -1072,7 +798,7 @@
 	_qq_status_text,		/* status_text	*/
 	_qq_tooltip_text,		/* tooltip_text */
 	_qq_away_states,		/* away_states	*/
-	_qq_buddy_menu,			/* blist_node_menu */
+	NULL,				/* blist_node_menu */
 	qq_chat_info,			/* chat_info */
 	NULL,				/* chat_info_defaults */
 	_qq_login,			/* login */
@@ -1118,19 +844,13 @@
 	qq_roomlist_get_list,		/* roomlist_get_list */
 	qq_roomlist_cancel,		/* roomlist_cancel */
 	NULL,				/* roomlist_expand_category */
-	qq_can_receive_file,				/* can_receive_file */
-	qq_send_file,				/* send_file */
-	NULL,                           /* new xfer, by gfhuang */
-	NULL,				/* offline_message, gaim2beta2, gfhuang */
-	NULL,				/* GaimWhiteboardPrplOps, gaim2beta2, gfhuang */
+	NULL,				/* can_receive_file */
+	qq_send_file,			/* send_file */
+	NULL,                           /* new xfer */
+	NULL,				/* offline_message */
+	NULL,				/* GaimWhiteboardPrplOps */
 };
 
-/*
-static GaimPluginUiInfo prefs_info = {
-	get_plugin_pref_frame
-};
-*/
-
 static GaimPluginInfo info = {
 	GAIM_PLUGIN_MAGIC,
 	GAIM_MAJOR_VERSION,
--- a/src/protocols/qq/qq_proxy.c	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/qq_proxy.c	Mon Jul 24 13:39:12 2006 +0000
@@ -37,9 +37,8 @@
 #include "packet_parse.h"	// MAX_PACKET_SIZE
 #include "buddy_info.h"		// qq_info_query_free
 #include "buddy_opt.h"		// qq_add_buddy_request_free
-#include "group_admindlg.h"	// qq_qun_info_window_free
+#include "char_conv.h"		// qq_sending_im_msg_cb
 #include "group_free.h"		// qq_group_packets_free
-#include "infodlg.h"		// qq_contact_info_window_free
 #include "login_logout.h"	// qq_send_packet_login
 #include "qq_proxy.h"		//
 #include "recv_core.h"		// qq_pending, qq_b4_packets_free
@@ -126,6 +125,17 @@
 }				// _qq_fill_host
 
 /*****************************************************************************/
+// set up any finalizing start-up stuff
+static void _qq_start_services(GaimConnection *gc)
+{
+	/* start watching for IMs about to be sent */
+	/*
+	gaim_signal_connect(gaim_conversations_get_handle(),
+			"sending-im-msg", gc,
+			GAIM_CALLBACK(qq_sending_im_msg_cb), NULL);
+			*/
+}
+
 // the callback function after socket is built
 // we setup the qq protocol related configuration here
 static void _qq_got_login(gpointer data, gint source, GaimInputCondition cond)
@@ -171,6 +181,8 @@
 	gaim_connection_update_progress(gc, buf, 1, QQ_CONNECT_STEPS);
 	g_free(buf);
 
+	_qq_start_services(gc);
+
 //	qq_send_packet_login(gc);	// finally ready to fire
 	qq_send_packet_request_login_token(gc);
 }				// _qq_got_login
@@ -206,8 +218,6 @@
 	qq_group_free_all(qd);
 	qq_add_buddy_request_free(qd);
 	qq_info_query_free(qd);
-	qq_contact_info_window_free(qd);
-	qq_qun_info_window_free(qd);
 	qq_buddies_list_free(gc->account /* by gfhuang */, qd);
 
 }				// _qq_common_clean
--- a/src/protocols/qq/qq_proxy.h	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/qq_proxy.h	Mon Jul 24 13:39:12 2006 +0000
@@ -51,6 +51,7 @@
 gint qq_connect(GaimAccount * account, const gchar * host, guint16 port, gboolean use_tcp, gboolean is_redirect);
 
 void qq_disconnect(GaimConnection * gc);
+void _qq_show_packet(gchar * des, gchar * buf, gint len);
 
 #endif				//_QQ_PROXY_H
 /*****************************************************************************/
--- a/src/protocols/qq/show.c	Mon Jul 24 09:25:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-/**
-* The QQ2003C protocol plugin
- *
- * for gaim
- *
- * Copyright (C) 2004 Puzzlebird
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * This code is based on qq_show.c, kindly contributed by herryouly@linuxsir
- */
-
-// START OF FILE
-/*****************************************************************************/
-#include <sys/types.h>		// mkdir
-#include <sys/stat.h>
-
-#include "internal.h"		// _("get_text")
-#include "debug.h"		// gaim_debug
-#include "notify.h"		// gaim_notify_error
-#include "util.h"		// gaim_url_fetch
-
-#include "show.h"
-
-#define QQ_SHOW_SERVER          "http://qqshow-user.tencent.com"
-#define QQ_SHOW_IMAGE           "10/00/00.gif"
-
-#define QQ_SHOW_CACHE_DIR       "qqshow"
-#define QQ_SHOW_DEFAULT_IMAGE   "qqshow_default.gif"
-
-#define QQ_SHOW_DEST_X          0
-#define QQ_SHOW_DEST_Y          0
-#define QQ_SHOW_DEST_WIDTH      120
-#define QQ_SHOW_DEST_HEIGHT     180
-#define QQ_SHOW_OFFSET_X        -10
-#define QQ_SHOW_OFFSET_Y        -35
-#define QQ_SHOW_SCALE_X         0.68
-#define QQ_SHOW_SCALE_Y         0.68
-
-enum {
-	QQ_SHOW_READ,
-	QQ_SHOW_WRITE,
-};
-
-/*****************************************************************************/
-// return the local cached QQ show file name for uid
-static gchar *_qq_show_get_cache_name(guint32 uid, gint io)
-{
-	gchar *path, *file, *file_fullname;
-
-	g_return_val_if_fail(uid > 0, NULL);
-
-	path = g_build_filename(gaim_user_dir(), QQ_SHOW_CACHE_DIR, NULL);
-	if (!g_file_test(path, G_FILE_TEST_EXISTS))
-		g_mkdir(path, 0700);
-
-	file = g_strdup_printf("%d.gif", uid);
-	file_fullname = g_build_filename(path, file, NULL);
-
-	if (io == QQ_SHOW_READ) {
-		if (!g_file_test(file_fullname, G_FILE_TEST_EXISTS)) {
-			gaim_debug(GAIM_DEBUG_WARNING, "QQ", "No cached QQ show image for buddy %d\n", uid);
-			g_free(file_fullname);
-			file_fullname =
-			    g_build_filename(gaim_prefs_get_string
-					     ("/plugins/prpl/qq/datadir"),
-					     "pixmaps", "gaim", "status", "default", QQ_SHOW_DEFAULT_IMAGE, NULL);
-		}		// if g_file_test
-	}			// if io
-
-	g_free(path);
-	g_free(file);
-	return file_fullname;
-
-}				// _qq_show_get_cache_name
-
-/*****************************************************************************/
-// scale the image to suit my window
-static GdkPixbuf *_qq_show_scale_image(GdkPixbuf * pixbuf_src)
-{
-	GdkPixbuf *pixbuf_dst;
-
-	pixbuf_dst = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
-				    QQ_SHOW_DEST_WIDTH * QQ_SHOW_SCALE_X, QQ_SHOW_DEST_HEIGHT * QQ_SHOW_SCALE_Y);
-
-	gdk_pixbuf_scale(pixbuf_src, pixbuf_dst,
-			 QQ_SHOW_DEST_X * QQ_SHOW_SCALE_X,
-			 QQ_SHOW_DEST_Y * QQ_SHOW_SCALE_Y,
-			 QQ_SHOW_DEST_WIDTH * QQ_SHOW_SCALE_X,
-			 QQ_SHOW_DEST_HEIGHT * QQ_SHOW_SCALE_Y,
-			 QQ_SHOW_OFFSET_X * QQ_SHOW_SCALE_X,
-			 QQ_SHOW_OFFSET_Y * QQ_SHOW_SCALE_Y, QQ_SHOW_SCALE_X, QQ_SHOW_SCALE_Y, GDK_INTERP_BILINEAR);
-
-	g_object_unref(G_OBJECT(pixbuf_src));
-	return pixbuf_dst;
-}				// qq_show_scale_image
-
-/*****************************************************************************/
-// keep a local copy of QQ show image to speed up loading
-static void _qq_show_cache_image(const gchar * url_ret, size_t len, guint32 uid)
-{
-
-	GError *err;
-	GIOChannel *cache;
-	gchar *file;
-
-	g_return_if_fail(uid > 0);
-
-	err = NULL;
-	file = _qq_show_get_cache_name(uid, QQ_SHOW_WRITE);
-	cache = g_io_channel_new_file(file, "w", &err);
-
-	if (err != NULL) {	// file error
-		gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Error with QQ show file: %s\n", err->message);
-		g_error_free(err);
-		return;
-	} else {		// OK, go ahead
-		g_io_channel_set_encoding(cache, NULL, NULL);	// binary mode
-		g_io_channel_write_chars(cache, url_ret, len, NULL, &err);
-		if (err != NULL) {
-			gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Fail cache QQ show for %d: %s\n", uid, err->message);
-			g_error_free(err);
-		} else
-			gaim_debug(GAIM_DEBUG_INFO, "QQ", "Cache QQ show for %d, done\n", uid);
-		g_io_channel_shutdown(cache, TRUE, NULL);
-	}			// if err
-
-}				// _qq_show_cache_image
-
-/*****************************************************************************/
-// display the image for downloaded data
-static void qq_show_render_image(void *data, const gchar * url_ret, size_t len)
-{
-	guint32 uid;
-	GdkPixbufLoader *pixbuf_loader;
-	GdkPixbuf *pixbuf_src, *pixbuf_dst;
-	GtkWidget *qq_show;
-
-	g_return_if_fail(data != NULL && url_ret != NULL && len > 0);
-
-	qq_show = (GtkWidget *) data;
-
-	pixbuf_loader = gdk_pixbuf_loader_new();
-	gdk_pixbuf_loader_write(pixbuf_loader, url_ret, len, NULL);
-	gdk_pixbuf_loader_close(pixbuf_loader, NULL);	// finish loading
-
-	pixbuf_src = gdk_pixbuf_loader_get_pixbuf(pixbuf_loader);
-
-	if (pixbuf_src != NULL) {
-		uid = (guint32) g_object_get_data(G_OBJECT(qq_show), "user_data");
-		_qq_show_cache_image(url_ret, len, uid);
-		pixbuf_dst = _qq_show_scale_image(pixbuf_src);
-		gtk_image_set_from_pixbuf(GTK_IMAGE(qq_show), pixbuf_dst);
-	} else {
-		gaim_notify_error(NULL, NULL, _("Fail getting QQ show image"), NULL);
-	}			// if pixbuf_src
-
-}				// qq_show_render_image
-
-/*****************************************************************************/
-// show the default image (either local cache or default image)
-GtkWidget *qq_show_default(contact_info * info)
-{
-	guint32 uid;
-	GdkPixbuf *pixbuf_src;
-	GError *err;
-	gchar *file;
-
-	g_return_val_if_fail(info != NULL, NULL);
-
-	uid = strtol(info->uid, NULL, 10);
-	g_return_val_if_fail(uid != 0, NULL);
-
-	file = _qq_show_get_cache_name(uid, QQ_SHOW_READ);
-	gaim_debug(GAIM_DEBUG_INFO, "QQ", "Load QQ show image: %s\n", file);
-
-	err = NULL;
-	pixbuf_src = gdk_pixbuf_new_from_file(file, &err);
-
-	if (err != NULL) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail loaing QQ show: %s\n", err->message);
-		g_free(file);
-		return NULL;
-	}			// if err
-
-	g_free(file);
-	return gtk_image_new_from_pixbuf(_qq_show_scale_image(pixbuf_src));
-}				// qq_show_default
-
-/*****************************************************************************/
-// refresh the image
-void qq_show_get_image(GtkWidget * event_box, GdkEventButton * event, gpointer data)
-{
-	gchar *url;
-	gint uid;
-	GtkWidget *qq_show;
-
-	qq_show = (GtkWidget *) data;
-	g_return_if_fail(qq_show != NULL);
-
-	uid = (gint) g_object_get_data(G_OBJECT(qq_show), "user_data");
-	g_return_if_fail(uid != 0);
-
-	url = g_strdup_printf("%s/%d/%s", QQ_SHOW_SERVER, uid, QQ_SHOW_IMAGE);
-	gaim_url_fetch(url, FALSE, NULL, TRUE, qq_show_render_image, qq_show);
-
-	g_free(url);
-}				// qq_show_get_image
-
-/*****************************************************************************/
--- a/src/protocols/qq/show.h	Mon Jul 24 09:25:48 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/**
-* The QQ2003C protocol plugin
- *
- * for gaim
- *
- * Copyright (C) 2004 Puzzlebird
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-// START OF FILE
-/*****************************************************************************/
-#ifndef _QQ_SHOW_H_
-#define _QQ_SHOW_H_
-
-#include <glib.h>
-#include <gtk/gtk.h>
-
-#include "buddy_info.h"		// contact_info
-
-GtkWidget *qq_show_default(contact_info * info);
-
-void qq_show_get_image(GtkWidget * event_box, GdkEventButton * event, gpointer data);
-
-#endif
-/*****************************************************************************/
--- a/src/protocols/qq/utils.c	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/utils.c	Mon Jul 24 13:39:12 2006 +0000
@@ -125,8 +125,11 @@
 // the return needs to be freed
 gchar *gen_ip_str(guint8 * ip)
 {
-	return g_strdup_printf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
-}				// gen_ip_str
+	if (ip == NULL || ip[0] == 0)
+	       	return g_strdup_printf("");
+	else 
+		return g_strdup_printf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+}
 
 // by gfhuang
 guint8 *str_ip_gen(gchar *str) {
@@ -168,36 +171,7 @@
 	// atoi is not thread-safe and also not async-cancel safe
 	// atoi is deprecated by strtol() and should not be used in new code
 	return (p == NULL) ? 0 : strtol(p + strlen(QQ_NAME_PREFIX), NULL, 10);
-}				// gaim_name_to_uid
-
-/*****************************************************************************/
-// convert QQ icon index into its pixbuf
-GdkPixbuf *get_face_gdkpixbuf(guint8 index)
-{
-	gint set, suffix;
-	gchar *image_name, *file_name;
-	GdkPixbuf *pixbuf;
-	const gchar *datadir;
-
-	set = (index / 3) + 1;
-	suffix = (index % 3) + 1;
-
-	image_name = g_strdup_printf("%s.png", get_icon_name(set, suffix));
-	// we need to configure DATADIR in Makefile.am
-	// st = -DDATADIR=\"$(datadir)\"
-	datadir = gaim_prefs_get_string("/plugins/prpl/qq/datadir");
-	if (datadir == NULL || strlen(datadir) == 0)
-		file_name = g_build_filename(datadir, "pixmaps", "gaim", "status", "default", image_name, NULL);
-	else
-		file_name = g_build_filename(DATADIR, "pixmaps", "gaim", "status", "default", image_name, NULL);
-
-	pixbuf = gdk_pixbuf_new_from_file(file_name, NULL);
-
-	g_free(image_name);
-	g_free(file_name);
-
-	return pixbuf;
-}				// get_face_gdkpixbuf
+}
 
 /*****************************************************************************/
 // try to dump the data as GBK
@@ -227,6 +201,7 @@
 }				// try_dump_gbk
 
 /*****************************************************************************/
+
 // dump a chunk of raw data into hex string
 // the return should be freed later
 gchar *hex_dump_to_str(const guint8 * buffer, gint bytes)
@@ -255,16 +230,16 @@
 				g_string_append_c(str, '.');
 			else
 				g_string_append_c(str, ch);
-		}		// for j
+		}
 		g_string_append_c(str, '\n');
-	}			// for i
+	}
 
 	ret = str->str;
 	// GString can be freed without freeing it character data
 	g_string_free(str, FALSE);
 
 	return ret;
-}				// hex_dump_to_str
+}
 
 /*****************************************************************************/
 // ENF OF FILE
--- a/src/protocols/qq/utils.h	Mon Jul 24 09:25:48 2006 +0000
+++ b/src/protocols/qq/utils.h	Mon Jul 24 13:39:12 2006 +0000
@@ -20,13 +20,11 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-// START OF FILE
-/*****************************************************************************/
 #ifndef _QQ_MY_UTILS_H_
 #define _QQ_MY_UTILS_H_
 
+#include <stdio.h>
 #include <glib.h>
-#include <gtk/gtk.h>
 
 #define QQ_NAME_PREFIX    "qq-"
 
@@ -36,19 +34,15 @@
 
 gchar **split_data(guint8 * data, gint len, const gchar * delimit, gint expected_fields);
 gchar *gen_ip_str(guint8 * ip);
-guint8 *str_ip_gen(gchar *str); //by gfhuang
+guint8 *str_ip_gen(gchar *str);
 gchar *uid_to_gaim_name(guint32 uid);
 
 guint32 gaim_name_to_uid(const gchar * name);
 
 gchar *get_icon_name(gint set, gint suffix);
 
-GdkPixbuf *get_face_gdkpixbuf(guint8 index);
-
 void try_dump_as_gbk(guint8 * data, gint len);
 
 gchar *hex_dump_to_str(const guint8 * buf, gint buf_len);
 
 #endif
-/*****************************************************************************/
-// END OF FILE