changeset 24080:818ab62006f5

2008.10.07 - ccpaging <ccpaging(at)gmail.com> * Update qq_buddy
author SHiNE CsyFeK <csyfek@gmail.com>
date Wed, 22 Oct 2008 14:59:55 +0000
parents 1bdf7b602684
children 119d85c40d75
files libpurple/protocols/qq/ChangeLog libpurple/protocols/qq/buddy_info.c libpurple/protocols/qq/buddy_list.c libpurple/protocols/qq/buddy_list.h libpurple/protocols/qq/buddy_opt.c libpurple/protocols/qq/buddy_opt.h libpurple/protocols/qq/group_find.c libpurple/protocols/qq/group_find.h libpurple/protocols/qq/group_free.c libpurple/protocols/qq/group_im.c libpurple/protocols/qq/group_info.c libpurple/protocols/qq/group_opt.c libpurple/protocols/qq/im.c libpurple/protocols/qq/qq.c libpurple/protocols/qq/qq.h libpurple/protocols/qq/qq_process.c libpurple/protocols/qq/send_file.c
diffstat 17 files changed, 337 insertions(+), 403 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/qq/ChangeLog	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/ChangeLog	Wed Oct 22 14:59:55 2008 +0000
@@ -1,3 +1,6 @@
+2008.10.07 - ccpaging <ccpaging(at)gmail.com>
+	* Update qq_buddy
+
 2008.10.07 - ccpaging <ccpaging(at)gmail.com>
 	* Update qun conversation
 
--- a/libpurple/protocols/qq/buddy_info.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/buddy_info.c	Wed Oct 22 14:59:55 2008 +0000
@@ -573,7 +573,7 @@
 {
 	PurpleBuddy *buddy;
 	qq_data *qd;
-	qq_buddy *bd;
+	qq_buddy_data *bd;
 	guint32 uid;
 	gchar *who;
 	gchar *alias_utf8;
@@ -583,7 +583,7 @@
 
 	uid = strtol(segments[QQ_INFO_UID], NULL, 10);
 	who = uid_to_purple_name(uid);
-	
+
 	alias_utf8 = qq_to_utf8(segments[QQ_INFO_NICK], QQ_CHARSET_DEFAULT);
 	if (uid == qd->uid) {	/* it is me */
 		purple_debug_info("QQ", "Got my info\n");
@@ -604,7 +604,7 @@
 	}
 
 	/* update buddy list (including myself, if myself is the buddy) */
-	bd = (qq_buddy *)buddy->proto_data;
+	bd = (qq_buddy_data *)buddy->proto_data;
 
 	bd->age = strtol(segments[QQ_INFO_AGE], NULL, 10);
 	bd->gender = strtol(segments[QQ_INFO_GENDER], NULL, 10);
@@ -715,7 +715,7 @@
 {
 	qq_data *qd = (qq_data *) gc->proto_data;
 	PurpleBuddy *buddy;
-	qq_buddy *buddy_data;
+	qq_buddy_data *bd;
 	guint8 *buf;
 	GSList *buddies, *it;
 	gint bytes;
@@ -730,12 +730,11 @@
 		buddy = it->data;
 		if (buddy == NULL) continue;
 		if (buddy->proto_data == NULL) continue;
-		buddy_data = (qq_buddy *)buddy->proto_data;
-		if (buddy_data->uid == 0) continue;
-		if (buddy_data->uid == qd->uid) continue;
-		bytes += qq_put32(buf + bytes, buddy_data->uid);
+		bd = (qq_buddy_data *)buddy->proto_data;
+		if (bd->uid == 0) continue;	/* keep me as end of packet*/
+		if (bd->uid == qd->uid) continue;
+		bytes += qq_put32(buf + bytes, bd->uid);
 	}
-	/* my uid must be the end if included */
 	bytes += qq_put32(buf + bytes, qd->uid);
 	qq_send_cmd_mess(gc, QQ_CMD_GET_LEVEL, buf, bytes, update_class, 0);
 }
@@ -745,7 +744,7 @@
 	gint bytes = 0;
 	guint32 uid, onlineTime;
 	guint16 level, timeRemainder;
-	qq_buddy *buddy;
+	qq_buddy_data *bd;
 
 	while (data_len - bytes >= 12) {
 		bytes += qq_get32(&uid, data + bytes);
@@ -755,15 +754,15 @@
 		purple_debug_info("QQ_LEVEL", "%d, tmOnline: %d, level: %d, tmRemainder: %d\n",
 				uid, onlineTime, level, timeRemainder);
 
-		buddy = qq_buddy_find(gc, uid);
-		if (buddy == NULL) {
+		bd = qq_buddy_data_find(gc, uid);
+		if (bd == NULL) {
 			purple_debug_error("QQ", "Got levels of %d not in my buddy list\n", uid);
 			continue;
 		}
 
-		buddy->onlineTime = onlineTime;
-		buddy->level = level;
-		buddy->timeRemainder = timeRemainder;
+		bd->onlineTime = onlineTime;
+		bd->level = level;
+		bd->timeRemainder = timeRemainder;
 	}
 
 	if (bytes != data_len) {
@@ -777,7 +776,7 @@
 	gint bytes;
 	guint32 uid, onlineTime;
 	guint16 level, timeRemainder;
-	qq_buddy *buddy;
+	qq_buddy_data *bd;
 	guint16 str_len;
 	gchar *str;
 	gchar *str_utf8;
@@ -790,15 +789,15 @@
 	purple_debug_info("QQ_LEVEL", "%d, tmOnline: %d, level: %d, tmRemainder: %d\n",
 			uid, onlineTime, level, timeRemainder);
 
-	buddy = qq_buddy_find(gc, uid);
-	if (buddy == NULL) {
+	bd = qq_buddy_data_find(gc, uid);
+	if (bd == NULL) {
 		purple_debug_error("QQ", "Got levels of %d not in my buddy list\n", uid);
 		return;
 	}
 
-	buddy->onlineTime = onlineTime;
-	buddy->level = level;
-	buddy->timeRemainder = timeRemainder;
+	bd->onlineTime = onlineTime;
+	bd->level = level;
+	bd->timeRemainder = timeRemainder;
 
 	/* extend bytes in qq2007*/
 	bytes += 4;	/* skip 8 bytes */
--- a/libpurple/protocols/qq/buddy_list.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/buddy_list.c	Wed Oct 22 14:59:55 2008 +0000
@@ -164,7 +164,7 @@
 	gint bytes, bytes_start;
 	gint count;
 	guint8  position;
-	qq_buddy *buddy;
+	qq_buddy_data *bd;
 	int entry_len = 38;
 
 	qq_buddy_status bs;
@@ -225,23 +225,24 @@
 		}
 
 		/* update buddy information */
-		buddy = qq_buddy_find(gc, bs.uid);
-		if (buddy == NULL) {
+		bd = qq_buddy_data_find(gc, bs.uid);
+		if (bd == NULL) {
 			purple_debug_error("QQ",
 					"Got an online buddy %d, but not in my buddy list\n", bs.uid);
 			continue;
 		}
-		/* we find one and update qq_buddy */
+		/* we find one and update qq_buddy_data */
 		/*
 		if(0 != fe->s->client_tag)
 			q_bud->client_tag = fe->s->client_tag;
 		*/
-		buddy->ip.s_addr = bs.ip.s_addr;
-		buddy->port = bs.port;
-		buddy->status = bs.status;
-		buddy->ext_flag = packet.ext_flag;
-		buddy->comm_flag = packet.comm_flag;
-		qq_update_buddy_status(gc, bs.uid, bs.status, packet.comm_flag);
+		bd->ip.s_addr = bs.ip.s_addr;
+		bd->port = bs.port;
+		bd->status = bs.status;
+		bd->ext_flag = packet.ext_flag;
+		bd->comm_flag = packet.comm_flag;
+		bd->last_update = time(NULL);
+		qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
 		count++;
 	}
 
@@ -260,7 +261,7 @@
 guint16 qq_process_get_buddies(guint8 *data, gint data_len, PurpleConnection *gc)
 {
 	qq_data *qd;
-	qq_buddy bd;
+	qq_buddy_data bd;
 	gint bytes_expected, count;
 	gint bytes, buddy_bytes;
 	gint nickname_len;
@@ -328,13 +329,13 @@
 			g_free(bd.nickname);
 			continue;
 		}
+		purple_blist_server_alias_buddy(buddy, bd.nickname);
 		bd.last_update = time(NULL);
-		purple_blist_server_alias_buddy(buddy, bd.nickname);
 		qq_update_buddy_status(gc, bd.uid, bd.status, bd.comm_flag);
 
-		g_memmove(buddy->proto_data, &bd, sizeof(qq_buddy));
+		g_memmove(buddy->proto_data, &bd, sizeof(qq_buddy_data));
 		/* nickname has been copy to buddy_data do not free
-		   g_free(bd.nickname); 
+		   g_free(bd.nickname);
 		*/
 	}
 
@@ -450,6 +451,36 @@
 	}
 }
 
+static guint8  get_status_from_purple(PurpleConnection *gc)
+{
+	qq_data *qd;
+	PurpleAccount *account;
+	PurplePresence *presence;
+	guint8 ret;
+
+	qd = (qq_data *) gc->proto_data;
+	account = purple_connection_get_account(gc);
+	presence = purple_account_get_presence(account);
+
+	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) {
+		ret = QQ_BUDDY_ONLINE_INVISIBLE;
+	} else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE))
+	{
+		if (qd->client_version >= 2007) {
+			ret = QQ_BUDDY_ONLINE_BUSY;
+		} else {
+			ret = QQ_BUDDY_ONLINE_INVISIBLE;
+		}
+	} else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY)
+			|| purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY)
+			|| purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) {
+		ret = QQ_BUDDY_ONLINE_AWAY;
+	} else {
+		ret = QQ_BUDDY_ONLINE_NORMAL;
+	}
+	return ret;
+}
+
 /* send a packet to change my online status */
 void qq_request_change_status(PurpleConnection *gc, gint update_class)
 {
@@ -469,22 +500,7 @@
 	if (!qd->is_login)
 		return;
 
-	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) {
-		away_cmd = QQ_BUDDY_ONLINE_INVISIBLE;
-	} else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE))
-	{
-		if (qd->client_version >= 2007) {
-			away_cmd = QQ_BUDDY_ONLINE_BUSY;
-		} else {
-			away_cmd = QQ_BUDDY_ONLINE_INVISIBLE;
-		}
-	} else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY)
-			|| purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY)
-			|| purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) {
-		away_cmd = QQ_BUDDY_ONLINE_AWAY;
-	} else {
-		away_cmd = QQ_BUDDY_ONLINE_NORMAL;
-	}
+	away_cmd = get_status_from_purple(gc);
 
 	misc_status = 0x00000000;
 	fake_video = purple_prefs_get_bool("/plugins/prpl/qq/show_fake_video");
@@ -514,7 +530,7 @@
 	qq_data *qd;
 	gint bytes;
 	guint8 reply;
-	qq_buddy *buddy;
+	qq_buddy_data *bd;
 
 	g_return_if_fail(data != NULL && data_len != 0);
 
@@ -528,9 +544,11 @@
 	}
 
 	/* purple_debug_info("QQ", "Change status OK\n"); */
-	buddy = qq_buddy_find(gc, qd->uid);
-	if (buddy != NULL) {
-		qq_update_buddy_contact(gc, buddy);
+	bd = qq_buddy_data_find(gc, qd->uid);
+	if (bd != NULL) {
+		bd->status = get_status_from_purple(gc);
+		bd->last_update = time(NULL);
+		qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
 	}
 }
 
@@ -540,7 +558,7 @@
 	qq_data *qd;
 	gint bytes;
 	guint32 my_uid;
-	qq_buddy *buddy;
+	qq_buddy_data *bd;
 	qq_buddy_status bs;
 
 	g_return_if_fail(data != NULL && data_len != 0);
@@ -561,26 +579,28 @@
 	 * QQ_BUDDY_ONLINE_INVISIBLE */
 	bytes += qq_get32(&my_uid, data + bytes);
 
-	buddy = qq_buddy_find(gc, bs.uid);
-	if (buddy == NULL) {
+	bd = qq_buddy_data_find(gc, bs.uid);
+	if (bd == NULL) {
 		purple_debug_warning("QQ", "Get status of unknown buddy %d\n", bs.uid);
 		return;
 	}
 
 	if(bs.ip.s_addr != 0) {
-		buddy->ip.s_addr = bs.ip.s_addr;
-		buddy->port = bs.port;
+		bd->ip.s_addr = bs.ip.s_addr;
+		bd->port = bs.port;
 	}
-	buddy->status =bs.status;
+	bd->status =bs.status;
 
-	if (buddy->status == QQ_BUDDY_ONLINE_NORMAL && buddy->level <= 0) {
+	bd->last_update = time(NULL);
+	qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
+
+	if (bd->status == QQ_BUDDY_ONLINE_NORMAL && bd->level <= 0) {
 		if (qd->client_version >= 2007) {
-			qq_request_get_level_2007(gc, buddy->uid);
+			qq_request_get_level_2007(gc, bd->uid);
 		} else {
-			qq_request_get_level(gc, buddy->uid);
+			qq_request_get_level(gc, bd->uid);
 		}
 	}
-	qq_update_buddy_contact(gc, buddy);
 }
 
 /*TODO: maybe this should be qq_update_buddy_status() ?*/
@@ -592,7 +612,7 @@
 	g_return_if_fail(uid != 0);
 
 	who = uid_to_purple_name(uid);
-	
+
 	/* purple supports signon and idle time
 	 * but it is not much use for QQ, I do not use them */
 	/* serv_got_update(gc, name, online, 0, q_bud->signon, q_bud->idle, bud->uc); */
@@ -628,86 +648,22 @@
 		purple_prpl_got_user_status(gc->account, who, "mobile", NULL);
 	else
 		purple_prpl_got_user_status_deactive(gc->account, who, "mobile");
-		
+
 	g_free(who);
 }
 
-/*TODO: maybe this should be qq_update_buddy_status() ?*/
-void qq_update_buddy_contact(PurpleConnection *gc, qq_buddy *buddy)
-{
-	gchar *purple_name;
-	PurpleBuddy *purple_buddy;
-	gchar *status_id;
-
-	g_return_if_fail(buddy != NULL);
-
-	purple_name = uid_to_purple_name(buddy->uid);
-	if (purple_name == NULL) {
-		purple_debug_error("QQ", "Not find purple name: %d\n", buddy->uid);
-		return;
-	}
-
-	purple_buddy = purple_find_buddy(gc->account, purple_name);
-	if (purple_buddy == NULL) {
-		purple_debug_error("QQ", "Not find buddy: %d\n", buddy->uid);
-		g_free(purple_name);
-		return;
-	}
-
-	purple_blist_server_alias_buddy(purple_buddy, buddy->nickname); /* server */
-	buddy->last_update = time(NULL);
-
-	/* purple supports signon and idle time
-	 * but it is not much use for QQ, I do not use them */
-	/* serv_got_update(gc, name, online, 0, q_bud->signon, q_bud->idle, bud->uc); */
-	status_id = "available";
-	switch(buddy->status) {
-	case QQ_BUDDY_OFFLINE:
-		status_id = "offline";
-		break;
-	case QQ_BUDDY_ONLINE_NORMAL:
-		status_id = "available";
-		break;
-	case QQ_BUDDY_CHANGE_TO_OFFLINE:
-		status_id = "offline";
-		break;
-	case QQ_BUDDY_ONLINE_AWAY:
-		status_id = "away";
-		break;
-	case QQ_BUDDY_ONLINE_INVISIBLE:
-		status_id = "invisible";
-		break;
-	case QQ_BUDDY_ONLINE_BUSY:
-		status_id = "busy";
-		break;
-	default:
-		status_id = "invisible";
-		purple_debug_error("QQ", "unknown status: %x\n", buddy->status);
-		break;
-	}
-	purple_debug_info("QQ", "buddy %d %s\n", buddy->uid, status_id);
-	purple_prpl_got_user_status(gc->account, purple_name, status_id, NULL);
-
-	if (buddy->comm_flag & QQ_COMM_FLAG_MOBILE && buddy->status != QQ_BUDDY_OFFLINE)
-		purple_prpl_got_user_status(gc->account, purple_name, "mobile", NULL);
-	else
-		purple_prpl_got_user_status_deactive(gc->account, purple_name, "mobile");
-
-	g_free(purple_name);
-}
-
 /* refresh all buddies online/offline,
  * after receiving reply for get_buddies_online packet */
 void qq_update_buddyies_status(PurpleConnection *gc)
 {
 	qq_data *qd;
 	PurpleBuddy *buddy;
-	qq_buddy *bd;
+	qq_buddy_data *bd;
 	GSList *buddies, *it;
 	time_t tm_limit = time(NULL);
 
 	qd = (qq_data *) (gc->proto_data);
-	
+
 	tm_limit -= QQ_UPDATE_ONLINE_INTERVAL;
 
 	buddies = purple_find_buddies(purple_connection_get_account(gc), NULL);
@@ -715,14 +671,15 @@
 		buddy = it->data;
 		if (buddy == NULL) continue;
 		if (buddy->proto_data == NULL) continue;
-		
-		bd = (qq_buddy *)buddy->proto_data;
+
+		bd = (qq_buddy_data *)buddy->proto_data;
 		if (bd->uid == 0) continue;
 		if (bd->uid == qd->uid) continue;	/* my status is always online in my buddy list */
 		if (tm_limit < bd->last_update) continue;
 		if (bd->status == QQ_BUDDY_ONLINE_INVISIBLE) continue;
-		
+
 		bd->status = QQ_BUDDY_CHANGE_TO_OFFLINE;
+		bd->last_update = time(NULL);
 		qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
 	}
 }
@@ -735,16 +692,16 @@
 	gint count = 0;
 
 	qd = (qq_data *) (gc->proto_data);
-	
+
 	buddies = purple_find_buddies(purple_connection_get_account(gc), NULL);
 	for (it = buddies; it; it = it->next) {
 		buddy = it->data;
 		if (buddy == NULL) continue;
 		if (buddy->proto_data == NULL) continue;
-		
+
 		qq_buddy_data_free(buddy->proto_data);
 		buddy->proto_data = NULL;
-		
+
 		count++;
 	}
 
--- a/libpurple/protocols/qq/buddy_list.h	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/buddy_list.h	Wed Oct 22 14:59:55 2008 +0000
@@ -57,6 +57,5 @@
 
 void qq_update_buddyies_status(PurpleConnection *gc);
 void qq_update_buddy_status(PurpleConnection *gc, guint32 uid, guint8 status, guint8 flag);
-void qq_update_buddy_contact(PurpleConnection *gc, qq_buddy *q_bud);
 void qq_buddy_data_free_all(PurpleConnection *gc);
 #endif
--- a/libpurple/protocols/qq/buddy_opt.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/buddy_opt.c	Wed Oct 22 14:59:55 2008 +0000
@@ -315,9 +315,9 @@
 		qq_buddy_data_free(buddy->proto_data);
 		buddy->proto_data = NULL;
 	} else {
-		purple_debug_warning("QQ", "We have no qq_buddy record for %s\n", buddy->name);
+		purple_debug_warning("QQ", "We have no qq_buddy_data record for %s\n", buddy->name);
 	}
-	
+
 	purple_blist_remove_buddy(buddy);
 	g_free(add_req);
 }
@@ -475,7 +475,14 @@
 		g_free(msg);
 		g_free(nombre);
 	} else {	/* add OK */
-		qq_create_buddy(gc, uid, TRUE, TRUE);
+		qq_buddy_find_or_new(gc, uid);
+		qq_request_buddy_info(gc, uid, 0, 0);
+		qq_request_get_buddies_online(gc, 0, 0);
+		if (qd->client_version >= 2007) {
+			qq_request_get_level_2007(gc, uid);
+		} else {
+			qq_request_get_level(gc, uid);
+		}
 
 		msg = g_strdup_printf(_("Successed adding into %d's buddy list"), uid);
 		qq_got_attention(gc, msg);
@@ -500,101 +507,39 @@
 	return g;
 }
 
-/* we add new buddy, if the received packet is from someone not in my list
- * return the PurpleBuddy that is just created */
-PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid,
-		gboolean is_known, gboolean is_create_data)
+static qq_buddy_data *qq_buddy_data_new(guint32 uid)
 {
-	PurpleBuddy *purple_buddy;
-	PurpleGroup *group;
-	qq_data *qd;
-	qq_buddy *buddy;
-	gchar *buddy_name, *group_name;
-
-	g_return_val_if_fail(gc->account != NULL && uid != 0, NULL);
-	qd = (qq_data *) gc->proto_data;
-
-	if (is_known) {
-		group_name = g_strdup_printf(PURPLE_GROUP_QQ_FORMAT,
-				purple_account_get_username(gc->account));
-	 } else {
-	 	group_name = g_strdup(PURPLE_GROUP_QQ_UNKNOWN);
-	}
-
-	group = qq_group_find_or_new(group_name);
-
-	buddy_name = uid_to_purple_name(uid);
-	purple_buddy = purple_find_buddy(gc->account, buddy_name);
-	/* remove old, we can not simply return here
-	 * because there might be old local copy of this buddy */
-	if (purple_buddy != NULL)
-		purple_blist_remove_buddy(purple_buddy);
-
-	purple_buddy = purple_buddy_new(gc->account, buddy_name, NULL);
-	if ( !is_known) {
-		if (purple_privacy_check(gc->account, buddy_name)) {
-			purple_privacy_deny(gc->account, buddy_name, TRUE, FALSE);
-		} else {
-			purple_privacy_deny_add(gc->account, buddy_name, TRUE);
-		}
-	}
-
-	if (!is_create_data)
-		purple_buddy->proto_data = NULL;
-	else {
-		buddy = g_new0(qq_buddy, 1);
-		buddy->uid = uid;
-		purple_buddy->proto_data = buddy;
-		qq_request_buddy_info(gc, uid, 0, 0);
-		qq_request_get_buddies_online(gc, 0, 0);
-		if (qd->client_version >= 2007) {
-			qq_request_get_level_2007(gc, uid);
-		} else {
-			qq_request_get_level(gc, uid);
-		}
-	}
-
-	purple_blist_add_buddy(purple_buddy, NULL, group, NULL);
-	purple_debug_info("QQ", "Add new buddy: [%s]\n", buddy_name);
-
-	g_free(buddy_name);
-	g_free(group_name);
-
-	return purple_buddy;
+	qq_buddy_data *bd = g_new0(qq_buddy_data, 1);
+	memset(bd, 0, sizeof(qq_buddy_data));
+	bd->uid = uid;
+	bd->status = QQ_BUDDY_ONLINE_NORMAL;
+	return bd;
 }
 
-static qq_buddy *qq_buddy_data_new(guint32 uid)
+qq_buddy_data *qq_buddy_data_find(PurpleConnection *gc, guint32 uid)
 {
-	qq_buddy *buddy = g_new0(qq_buddy, 1);
-	memset(buddy, 0, sizeof(qq_buddy));
-	buddy->uid = uid;
-	buddy->status = QQ_BUDDY_ONLINE_NORMAL;
-	return buddy;
-}
-
-qq_buddy *qq_buddy_find(PurpleConnection *gc, guint32 uid)
-{
-	gchar *purple_name;
-	PurpleBuddy *purple_buddy;
+	gchar *who;
+	PurpleBuddy *buddy;
 
 	g_return_val_if_fail(gc != NULL, NULL);
-	purple_name = uid_to_purple_name(uid);
-	if (purple_name == NULL)	return NULL;
 
-	purple_buddy = purple_find_buddy(purple_connection_get_account(gc), purple_name);
-	g_free(purple_name);
-	if (purple_buddy == NULL) {
+	who = uid_to_purple_name(uid);
+	if (who == NULL)	return NULL;
+	buddy = purple_find_buddy(purple_connection_get_account(gc), who);
+	g_free(who);
+
+	if (buddy == NULL) {
 		purple_debug_error("QQ", "Can not find purple buddy of %d\n", uid);
 		return NULL;
 	}
-	if (purple_buddy->proto_data == NULL) {
+	if (buddy->proto_data == NULL) {
 		purple_debug_error("QQ", "Can not find buddy data of %d\n", uid);
 		return NULL;
 	}
-	return (qq_buddy *)purple_buddy->proto_data;
+	return (qq_buddy_data *)buddy->proto_data;
 }
 
-void qq_buddy_data_free(qq_buddy *bd)
+void qq_buddy_data_free(qq_buddy_data *bd)
 {
 	g_return_if_fail(bd != NULL);
 
@@ -602,13 +547,15 @@
 	g_free(bd);
 }
 
-static PurpleBuddy *qq_buddy_new(PurpleConnection *gc, gchar *who)
+/* create purple buddy without data and display with no-auth icon */
+PurpleBuddy *qq_buddy_new(PurpleConnection *gc, guint32 uid)
 {
 	PurpleBuddy *buddy;
 	PurpleGroup *group;
+	gchar *who;
 	gchar *group_name;
 
-	g_return_val_if_fail(gc->account != NULL && who != NULL, NULL);
+	g_return_val_if_fail(gc->account != NULL && uid != 0, NULL);
 
 	group_name = g_strdup_printf(PURPLE_GROUP_QQ_FORMAT,
 			purple_account_get_username(gc->account));
@@ -618,7 +565,9 @@
 		return NULL;
 	}
 
+	who = uid_to_purple_name(uid);
 	buddy = purple_buddy_new(gc->account, who, NULL);	/* alias is NULL */
+	g_free(who);
 	buddy->proto_data = NULL;
 
 	purple_blist_add_buddy(buddy, NULL, group, NULL);
@@ -629,7 +578,7 @@
 	return buddy;
 }
 
-PurpleBuddy *qq_buddy_find_or_new(PurpleConnection *gc, guint32 uid)
+PurpleBuddy *qq_buddy_find(PurpleConnection *gc, guint32 uid)
 {
 	PurpleBuddy *buddy;
 	gchar *who;
@@ -637,24 +586,30 @@
 	g_return_val_if_fail(gc->account != NULL && uid != 0, NULL);
 
 	who = uid_to_purple_name(uid);
+	buddy = purple_find_buddy(gc->account, who);
+	g_free(who);
+	return buddy;
+}
 
-	buddy = purple_find_buddy(gc->account, who);
+PurpleBuddy *qq_buddy_find_or_new(PurpleConnection *gc, guint32 uid)
+{
+	PurpleBuddy *buddy;
+
+	g_return_val_if_fail(gc->account != NULL && uid != 0, NULL);
+
+	buddy = qq_buddy_find(gc, uid);
 	if (buddy == NULL) {
-		buddy = qq_buddy_new(gc, who);
+		buddy = qq_buddy_new(gc, uid);
 		if (buddy == NULL) {
-			g_free(who);
 			return NULL;
 		}
 	}
-	
+
 	if (buddy->proto_data != NULL) {
-		g_free(who);
 		return buddy;
 	}
 
 	buddy->proto_data = qq_buddy_data_new(uid);
-
-	g_free(who);
 	return buddy;
 }
 
@@ -680,9 +635,9 @@
 		qq_buddy_data_free(buddy->proto_data);
 		buddy->proto_data = NULL;
 	} else {
-		purple_debug_warning("QQ", "We have no qq_buddy record for %s\n", buddy->name);
+		purple_debug_warning("QQ", "We have no qq_buddy_data record for %s\n", buddy->name);
 	}
-	
+
 	/* Do not call purple_blist_remove_buddy,
 	 * otherwise purple segmentation fault */
 }
@@ -784,11 +739,23 @@
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
 	qq_data *qd;
+	guint32 uid;
 
 	g_return_if_fail(from != NULL && to != NULL);
 
 	qd = (qq_data *) gc->proto_data;
-	qq_create_buddy(gc, strtol(from, NULL, 10), TRUE, TRUE);
+	uid = strtol(from, NULL, 10);
+
+	g_return_if_fail(uid > 0);
+
+	qq_buddy_find_or_new(gc, uid);
+	qq_request_buddy_info(gc, uid, 0, 0);
+	qq_request_get_buddies_online(gc, 0, 0);
+	if (qd->client_version >= 2007) {
+		qq_request_get_level_2007(gc, uid);
+	} else {
+		qq_request_get_level(gc, uid);
+	}
 
 	purple_account_notify_added(account, from, to, NULL, msg_utf8);
 }
--- a/libpurple/protocols/qq/buddy_opt.h	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/buddy_opt.h	Wed Oct 22 14:59:55 2008 +0000
@@ -30,16 +30,11 @@
 
 #include "qq.h"
 
-void qq_buddy_data_free(qq_buddy *bd);
-
 void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-qq_buddy *qq_buddy_find(PurpleConnection *gc, guint32 uid);
 void qq_change_buddys_group(PurpleConnection *gc, const char *who,
 		const char *old_group, const char *new_group);
 void qq_remove_buddy_and_me(PurpleBlistNode * node);
 void qq_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-PurpleBuddy *qq_create_buddy(PurpleConnection *gc, guint32 uid,
-		gboolean is_known, gboolean is_create_data);
 
 void qq_process_buddy_remove(guint8 *buf, gint buf_len, PurpleConnection *gc);
 void qq_process_buddy_remove_me(guint8 *data, gint data_len, PurpleConnection *gc);
@@ -48,7 +43,11 @@
 void qq_process_buddy_from_server(PurpleConnection *gc, int funct,
 		gchar *from, gchar *to, gchar *msg_utf8);
 
-PurpleGroup *qq_group_find_or_new(const gchar *group_name);
+qq_buddy_data *qq_buddy_data_find(PurpleConnection *gc, guint32 uid);
+void qq_buddy_data_free(qq_buddy_data *bd);
+
+PurpleBuddy *qq_buddy_new(PurpleConnection *gc, guint32 uid);
 PurpleBuddy *qq_buddy_find_or_new(PurpleConnection *gc, guint32 uid);
-
+PurpleBuddy *qq_buddy_find(PurpleConnection *gc, guint32 uid);
+PurpleGroup *qq_group_find_or_new(const gchar *group_name);
 #endif
--- a/libpurple/protocols/qq/group_find.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/group_find.c	Wed Oct 22 14:59:55 2008 +0000
@@ -31,18 +31,18 @@
 #include "group_find.h"
 #include "utils.h"
 
-/* find a qq_buddy by uid, called by im.c */
-qq_buddy *qq_group_find_member_by_uid(qq_group *group, guint32 uid)
+/* find a qq_buddy_data by uid, called by im.c */
+qq_buddy_data *qq_group_find_member_by_uid(qq_group *group, guint32 uid)
 {
 	GList *list;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 	g_return_val_if_fail(group != NULL && uid > 0, NULL);
 
 	list = group->members;
 	while (list != NULL) {
-		member = (qq_buddy *) list->data;
-		if (member->uid == uid)
-			return member;
+		bd = (qq_buddy_data *) list->data;
+		if (bd->uid == uid)
+			return bd;
 		else
 			list = list->next;
 	}
@@ -50,18 +50,18 @@
 	return NULL;
 }
 
-/* remove a qq_buddy by uid, called by qq_group_opt.c */
+/* remove a qq_buddy_data by uid, called by qq_group_opt.c */
 void qq_group_remove_member_by_uid(qq_group *group, guint32 uid)
 {
 	GList *list;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 	g_return_if_fail(group != NULL && uid > 0);
 
 	list = group->members;
 	while (list != NULL) {
-		member = (qq_buddy *) list->data;
-		if (member->uid == uid) {
-			group->members = g_list_remove(group->members, member);
+		bd = (qq_buddy_data *) list->data;
+		if (bd->uid == uid) {
+			group->members = g_list_remove(group->members, bd);
 			return;
 		} else {
 			list = list->next;
@@ -69,23 +69,23 @@
 	}
 }
 
-qq_buddy *qq_group_find_or_add_member(PurpleConnection *gc, qq_group *group, guint32 member_uid)
+qq_buddy_data *qq_group_find_or_add_member(PurpleConnection *gc, qq_group *group, guint32 member_uid)
 {
-	qq_buddy *member, *q_bud;
-	PurpleBuddy *purple_buddy;
+	qq_buddy_data *member, *bd;
+	PurpleBuddy *buddy;
 	g_return_val_if_fail(group != NULL && member_uid > 0, NULL);
 
 	member = qq_group_find_member_by_uid(group, member_uid);
 	if (member == NULL) {	/* first appear during my session */
-		member = g_new0(qq_buddy, 1);
+		member = g_new0(qq_buddy_data, 1);
 		member->uid = member_uid;
-		purple_buddy = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(member_uid));
-		if (purple_buddy != NULL) {
-			q_bud = (qq_buddy *) purple_buddy->proto_data;
-			if (q_bud != NULL && q_bud->nickname != NULL)
-				member->nickname = g_strdup(q_bud->nickname);
-			else if (purple_buddy->alias != NULL)
-				member->nickname = g_strdup(purple_buddy->alias);
+		buddy = purple_find_buddy(purple_connection_get_account(gc), uid_to_purple_name(member_uid));
+		if (buddy != NULL) {
+			bd = (qq_buddy_data *) buddy->proto_data;
+			if (bd != NULL && bd->nickname != NULL)
+				member->nickname = g_strdup(bd->nickname);
+			else if (buddy->alias != NULL)
+				member->nickname = g_strdup(buddy->alias);
 		}
 		group->members = g_list_append(group->members, member);
 	}
@@ -174,17 +174,17 @@
 	qq_group *group;
 	qq_data *qd;
 	gboolean is_find = FALSE;
-	
+
 	qd = (qq_data *) gc->proto_data;
 
 	if (qd->groups == NULL) {
 		return NULL;
 	}
-	
+
 	 if (room_id <= 0) {
 		return (qq_group *) qd->groups->data;
 	}
-	
+
 	list = qd->groups;
 	while (list != NULL) {
 		group = (qq_group *) list->data;
@@ -227,7 +227,7 @@
 			return NULL;
 		}
 	}
-	
+
 	is_find = FALSE;
 	while (list != NULL) {
 		group = (qq_group *) list->data;
--- a/libpurple/protocols/qq/group_find.h	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/group_find.h	Wed Oct 22 14:59:55 2008 +0000
@@ -29,9 +29,9 @@
 #include "connection.h"
 #include "group.h"
 
-qq_buddy *qq_group_find_member_by_uid(qq_group *group, guint32 uid);
+qq_buddy_data *qq_group_find_member_by_uid(qq_group *group, guint32 uid);
 void qq_group_remove_member_by_uid(qq_group *group, guint32 uid);
-qq_buddy *qq_group_find_or_add_member(PurpleConnection *gc, qq_group *group, guint32 member_uid);
+qq_buddy_data *qq_group_find_or_add_member(PurpleConnection *gc, qq_group *group, guint32 member_uid);
 qq_group *qq_group_find_by_channel(PurpleConnection *gc, gint channel);
 
 qq_group *qq_room_search_ext_id(PurpleConnection *gc, guint32 ext_id);
--- a/libpurple/protocols/qq/group_free.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/group_free.c	Wed Oct 22 14:59:55 2008 +0000
@@ -26,7 +26,7 @@
 
 #include "debug.h"
 
-#include "buddy_list.h"
+#include "buddy_opt.h"
 #include "group_free.h"
 
 /* gracefully free all members in a group */
@@ -34,16 +34,15 @@
 {
 	gint i;
 	GList *list;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 
 	g_return_if_fail(group != NULL);
 	i = 0;
 	while (NULL != (list = group->members)) {
-		member = (qq_buddy *) list->data;
+		bd = (qq_buddy_data *) list->data;
 		i++;
-		group->members = g_list_remove(group->members, member);
-		g_free(member->nickname);
-		g_free(member);
+		group->members = g_list_remove(group->members, bd);
+		qq_buddy_data_free(bd);
 	}
 
 	group->members = NULL;
--- a/libpurple/protocols/qq/group_im.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/group_im.c	Wed Oct 22 14:59:55 2008 +0000
@@ -82,7 +82,7 @@
 void qq_room_conv_set_onlines(PurpleConnection *gc, qq_group *group)
 {
 	GList *names, *list, *flags;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 	gchar *member_name, *member_uid;
 	PurpleConversation *conv;
 	gint flag;
@@ -102,20 +102,20 @@
 
 	list = group->members;
 	while (list != NULL) {
-		member = (qq_buddy *) list->data;
+		bd = (qq_buddy_data *) list->data;
 
 		/* we need unique identifiers for everyone in the chat or else we'll
 		 * run into problems with functions like get_cb_real_name from qq.c */
-		member_name =   (member->nickname != NULL && *(member->nickname) != '\0') ?
-				g_strdup_printf("%s (%u)", member->nickname, member->uid) :
-				g_strdup_printf("(%u)", member->uid);
-		member_uid = g_strdup_printf("(%u)", member->uid);
+		member_name =   (bd->nickname != NULL && *(bd->nickname) != '\0') ?
+				g_strdup_printf("%s (%u)", bd->nickname, bd->uid) :
+				g_strdup_printf("(%u)", bd->uid);
+		member_uid = g_strdup_printf("(%u)", bd->uid);
 
 		flag = 0;
 		/* TYPING to put online above OP and FOUNDER */
-		if (is_online(member->status)) flag |= (PURPLE_CBFLAGS_TYPING | PURPLE_CBFLAGS_VOICE);
-		if(1 == (member->role & 1)) flag |= PURPLE_CBFLAGS_OP;
-		if(member->uid == group->creator_uid) flag |= PURPLE_CBFLAGS_FOUNDER;
+		if (is_online(bd->status)) flag |= (PURPLE_CBFLAGS_TYPING | PURPLE_CBFLAGS_VOICE);
+		if(1 == (bd->role & 1)) flag |= PURPLE_CBFLAGS_OP;
+		if(bd->uid == group->creator_uid) flag |= PURPLE_CBFLAGS_FOUNDER;
 
 		is_find = TRUE;
 		if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(conv), member_name))
@@ -254,7 +254,7 @@
 {
 	PurpleAccount *account = purple_connection_get_account(gc);
 	PurpleConversation *conv;
-	qq_buddy *buddy;
+	qq_buddy_data *bd;
 	gchar *from;
 
 	g_return_if_fail(group != NULL);
@@ -270,11 +270,11 @@
 	}
 
 	if (uid_from != 0) {
-		buddy = qq_group_find_member_by_uid(group, uid_from);
-		if (buddy == NULL || buddy->nickname == NULL)
+		bd = qq_group_find_member_by_uid(group, uid_from);
+		if (bd == NULL || bd->nickname == NULL)
 			from = g_strdup_printf("%d", uid_from);
 		else
-			from = g_strdup(buddy->nickname);
+			from = g_strdup(bd->nickname);
 	} else {
 		from = g_strdup("");
 	}
--- a/libpurple/protocols/qq/group_info.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/group_info.c	Wed Oct 22 14:59:55 2008 +0000
@@ -41,7 +41,7 @@
  * this interval determines if their member info is outdated */
 #define QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL  180
 
-static gboolean check_update_interval(qq_buddy *member)
+static gboolean check_update_interval(qq_buddy_data *member)
 {
 	g_return_val_if_fail(member != NULL, FALSE);
 	return (member->nickname == NULL) ||
@@ -53,13 +53,13 @@
 static void set_all_offline(qq_group *group)
 {
 	GList *list;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 	g_return_if_fail(group != NULL);
 
 	list = group->members;
 	while (list != NULL) {
-		member = (qq_buddy *) list->data;
-		member->status = QQ_BUDDY_CHANGE_TO_OFFLINE;
+		bd = (qq_buddy_data *) list->data;
+		bd->status = QQ_BUDDY_CHANGE_TO_OFFLINE;
 		list = list->next;
 	}
 }
@@ -70,12 +70,12 @@
 	guint8 *raw_data;
 	gint bytes, num;
 	GList *list;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 
 	g_return_val_if_fail(group != NULL, 0);
 	for (num = 0, list = group->members; list != NULL; list = list->next) {
-		member = (qq_buddy *) list->data;
-		if (check_update_interval(member))
+		bd = (qq_buddy_data *) list->data;
+		if (check_update_interval(bd))
 			num++;
 	}
 
@@ -90,9 +90,9 @@
 
 	list = group->members;
 	while (list != NULL) {
-		member = (qq_buddy *) list->data;
-		if (check_update_interval(member))
-			bytes += qq_put32(raw_data + bytes, member->uid);
+		bd = (qq_buddy_data *) list->data;
+		if (check_update_interval(bd))
+			bytes += qq_put32(raw_data + bytes, bd->uid);
 		list = list->next;
 	}
 
@@ -140,7 +140,7 @@
 void qq_process_room_cmd_get_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc)
 {
 	qq_group *group;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 	qq_data *qd;
 	PurpleConversation *conv;
 	guint8 organization, role;
@@ -219,9 +219,9 @@
 		}
 #endif
 
-		member = qq_group_find_or_add_member(gc, group, member_uid);
-		if (member != NULL)
-			member->role = role;
+		bd = qq_group_find_or_add_member(gc, group, member_uid);
+		if (bd != NULL)
+			bd->role = role;
 	}
 	if(bytes > data_len) {
 		purple_debug_error("QQ",
@@ -263,7 +263,7 @@
 	guint8 unknown;
 	gint bytes, num;
 	qq_group *group;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 
 	g_return_if_fail(data != NULL && len > 0);
 
@@ -289,9 +289,9 @@
 	while (bytes < len) {
 		bytes += qq_get32(&member_uid, data + bytes);
 		num++;
-		member = qq_group_find_or_add_member(gc, group, member_uid);
-		if (member != NULL)
-			member->status = QQ_BUDDY_ONLINE_NORMAL;
+		bd = qq_group_find_or_add_member(gc, group, member_uid);
+		if (bd != NULL)
+			bd->status = QQ_BUDDY_ONLINE_NORMAL;
 	}
 	if(bytes > len) {
 		purple_debug_error("QQ",
@@ -309,7 +309,7 @@
 	guint32 id, member_uid;
 	guint16 unknown;
 	qq_group *group;
-	qq_buddy *member;
+	qq_buddy_data *bd;
 	gchar *nick;
 
 	g_return_if_fail(data != NULL && len > 0);
@@ -328,30 +328,30 @@
 	while (bytes < len) {
 		bytes += qq_get32(&member_uid, data + bytes);
 		g_return_if_fail(member_uid > 0);
-		member = qq_group_find_member_by_uid(group, member_uid);
-		g_return_if_fail(member != NULL);
+		bd = qq_group_find_member_by_uid(group, member_uid);
+		g_return_if_fail(bd != NULL);
 
 		num++;
-		bytes += qq_get16(&(member->face), data + bytes);
-		bytes += qq_get8(&(member->age), data + bytes);
-		bytes += qq_get8(&(member->gender), data + bytes);
+		bytes += qq_get16(&(bd->face), data + bytes);
+		bytes += qq_get8(&(bd->age), data + bytes);
+		bytes += qq_get8(&(bd->gender), data + bytes);
 		bytes += qq_get_vstr(&nick, QQ_CHARSET_DEFAULT, data + bytes);
 		bytes += qq_get16(&unknown, data + bytes);
-		bytes += qq_get8(&(member->ext_flag), data + bytes);
-		bytes += qq_get8(&(member->comm_flag), data + bytes);
+		bytes += qq_get8(&(bd->ext_flag), data + bytes);
+		bytes += qq_get8(&(bd->comm_flag), data + bytes);
 
 		/* filter \r\n in nick */
 		qq_filter_str(nick);
-		member->nickname = g_strdup(nick);
+		bd->nickname = g_strdup(nick);
 		g_free(nick);
 
 #if 0
 		purple_debug_info("QQ",
 				"member [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n",
-				member_uid, member->ext_flag, member->comm_flag, member->nickname);
+				member_uid, bd->ext_flag, bd->comm_flag, bd->nickname);
 #endif
 
-		member->last_update = time(NULL);
+		bd->last_update = time(NULL);
 	}
 	if (bytes > len) {
 		purple_debug_error("QQ",
--- a/libpurple/protocols/qq/group_opt.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/group_opt.c	Wed Oct 22 14:59:55 2008 +0000
@@ -143,7 +143,7 @@
 void qq_group_modify_members(PurpleConnection *gc, qq_group *group, guint32 *new_members)
 {
 	guint32 *old_members, *del_members, *add_members;
-	qq_buddy *q_bud;
+	qq_buddy_data *bd;
 	qq_data *qd;
 	gint i = 0, old = 0, new = 0, del = 0, add = 0;
 	GList *list;
@@ -160,9 +160,9 @@
 	/* construct the old member list */
 	list = group->members;
 	while (list != NULL) {
-		q_bud = (qq_buddy *) list->data;
-		if (q_bud != NULL)
-			old_members[i++] = q_bud->uid;
+		bd = (qq_buddy_data *) list->data;
+		if (bd != NULL)
+			old_members[i++] = bd->uid;
 		list = list->next;
 	}
 	old_members[i] = 0xffffffff;	/* this is the end */
@@ -268,7 +268,7 @@
 	guint32 id;
 	qq_group *group;
 	time_t now = time(NULL);
-	
+
 	g_return_if_fail(data != NULL);
 
 	bytes = 0;
--- a/libpurple/protocols/qq/im.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/im.c	Wed Oct 22 14:59:55 2008 +0000
@@ -181,13 +181,13 @@
 static void process_im_text(PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header)
 {
 	guint16 purple_msg_type;
-	gchar *name;
+	gchar *who;
 	gchar *msg_with_purple_smiley;
 	gchar *msg_utf8_encoded;
 	qq_data *qd;
 	gint bytes = 0;
 	PurpleBuddy *b;
-	qq_buddy *qq_b;
+	qq_buddy_data *bd;
 
 	struct {
 		/* now comes the part for text only */
@@ -205,10 +205,10 @@
 
 	g_return_if_fail (data != NULL && len > 0);
 	g_return_if_fail(im_header != NULL);
-	
+
 	qd = (qq_data *) gc->proto_data;
 	memset(&im_text, 0, sizeof(im_text));
-	
+
 	/* push data into im_text */
 	bytes += qq_get16(&(im_text.msg_seq), data + bytes);
 	bytes += qq_get32(&(im_text.send_time), data + bytes);
@@ -240,15 +240,15 @@
 			im_text.msg = g_strndup((gchar *)(data + bytes), len - bytes);
 	}			/* if im_text.msg_type */
 
-	name = uid_to_purple_name(im_header->uid_from);
-	b = purple_find_buddy(gc->account, name);
+	who = uid_to_purple_name(im_header->uid_from);
+	b = purple_find_buddy(gc->account, who);
 	if (b == NULL) {
-		qq_create_buddy(gc, im_header->uid_from, FALSE, TRUE);
-		b = purple_find_buddy(gc->account, name);
+		/* create no-auth buddy */
+		b = qq_buddy_new(gc, im_header->uid_from);
 	}
-	qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
-	if (qq_b != NULL) {
-		qq_b->client_tag = im_header->version_from;
+	bd = (b == NULL) ? NULL : (qq_buddy_data *) b->proto_data;
+	if (bd != NULL) {
+		bd->client_tag = im_header->version_from;
 	}
 
 	purple_msg_type = (im_text.msg_type == QQ_IM_AUTO_REPLY) ? PURPLE_MESSAGE_AUTO_RESP : 0;
@@ -257,17 +257,17 @@
 	msg_utf8_encoded = im_text.is_there_font_attr ?
 		qq_encode_to_purple(im_text.font_attr,
 				im_text.font_attr_len,
-				msg_with_purple_smiley, qd->client_version) 
+				msg_with_purple_smiley, qd->client_version)
 		: qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT);
 
 	/* send encoded to purple, note that we use im_text.send_time,
 	 * not the time we receive the message
 	 * as it may have been delayed when I am not online. */
-	serv_got_im(gc, name, msg_utf8_encoded, purple_msg_type, (time_t) im_text.send_time);
+	serv_got_im(gc, who, msg_utf8_encoded, purple_msg_type, (time_t) im_text.send_time);
 
 	g_free(msg_utf8_encoded);
 	g_free(msg_with_purple_smiley);
-	g_free(name);
+	g_free(who);
 	g_free(im_text.msg);
 	if (im_text.font_attr)	g_free(im_text.font_attr);
 }
@@ -277,10 +277,12 @@
 		PurpleConnection *gc, guint8 *data, gint len, qq_im_header *im_header)
 {
 	guint16 purple_msg_type;
-	gchar *name;
+	gchar *who;
 	gchar *msg_with_purple_smiley;
 	gchar *msg_utf8_encoded;
 	qq_data *qd;
+	PurpleBuddy *b;
+	qq_buddy_data *bd;
 	gint bytes, text_len;
 
 	struct {
@@ -296,7 +298,7 @@
 		guint8 replyType;
 		gchar *msg;		/* no fixed length, ends with 0x00 */
 		guint8 fromMobileQQ;
-	
+
 		guint8 is_there_font_attr;
 		guint8 *font_attr;
 		gint8 font_attr_len;
@@ -314,16 +316,16 @@
 	bytes += qq_get32(&(im_text.send_time), data + bytes);
 	bytes += qq_get16(&(im_text.senderHead), data + bytes);
 	bytes += qq_get32(&(im_text.flag), data + bytes);
-	
+
 	bytes += qq_getdata(im_text.unknown2, 8, data + bytes);
 	bytes += qq_get8(&(im_text.fragmentCount), data + bytes);
 	bytes += qq_get8(&(im_text.fragmentIndex), data + bytes);
-		
+
 	bytes += qq_get16(&(im_text.messageId), data + bytes);
 	bytes += qq_get8(&(im_text.replyType), data + bytes);
-	
+
 	im_text.font_attr_len = data[len-1] & 0xff;
-	
+
 	text_len = len - bytes - im_text.font_attr_len;
 	im_text.msg = g_strndup((gchar *)(data + bytes), text_len);
 	bytes += text_len;
@@ -331,29 +333,36 @@
 		im_text.font_attr = g_memdup(data + bytes, im_text.font_attr_len);
 	else
 	{
-		purple_debug_error("QQ", "Failed to get IM's font attribute len %d\n", 
+		purple_debug_error("QQ", "Failed to get IM's font attribute len %d\n",
 			im_text.font_attr_len);
 		return;
 	}
 
 	if(im_text.fragmentCount == 0)
 		im_text.fragmentCount = 1;
-		
+
 	// Filter tail space
 	if(im_text.fragmentIndex == im_text.fragmentCount -1)
 	{
 		gint real_len = text_len;
 		while(real_len > 0 && im_text.msg[real_len - 1] == 0x20)
 			real_len --;
-		
+
 		text_len = real_len;
 		// Null string instaed of space
 		im_text.msg[text_len] = 0;
 	}
-	
-	name = uid_to_purple_name(im_header->uid_from);
-	if (purple_find_buddy(gc->account, name) == NULL)
-		qq_create_buddy(gc, im_header->uid_from, FALSE, TRUE);
+
+	who = uid_to_purple_name(im_header->uid_from);
+	b = purple_find_buddy(gc->account, who);
+	if (b == NULL) {
+		/* create no-auth buddy */
+		b = qq_buddy_new(gc, im_header->uid_from);
+	}
+	bd = (b == NULL) ? NULL : (qq_buddy_data *) b->proto_data;
+	if (bd != NULL) {
+		bd->client_tag = im_header->version_from;
+	}
 
 	purple_msg_type = 0;
 
@@ -361,17 +370,17 @@
 	msg_utf8_encoded = im_text.font_attr ?
 	    qq_encode_to_purple(im_text.font_attr,
 			      im_text.font_attr_len,
-			      msg_with_purple_smiley, qd->client_version) 
+			      msg_with_purple_smiley, qd->client_version)
 		: qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT);
 
 	/* send encoded to purple, note that we use im_text.send_time,
 	 * not the time we receive the message
 	 * as it may have been delayed when I am not online. */
-	serv_got_im(gc, name, msg_utf8_encoded, purple_msg_type, (time_t) im_text.send_time);
+	serv_got_im(gc, who, msg_utf8_encoded, purple_msg_type, (time_t) im_text.send_time);
 
 	g_free(msg_utf8_encoded);
 	g_free(msg_with_purple_smiley);
-	g_free(name);
+	g_free(who);
 	g_free(im_text.msg);
 	if (im_text.font_attr) g_free(im_text.font_attr);
 }
--- a/libpurple/protocols/qq/qq.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/qq.c	Wed Oct 22 14:59:55 2008 +0000
@@ -242,16 +242,16 @@
 /* a short status text beside buddy icon*/
 static gchar *qq_status_text(PurpleBuddy *b)
 {
-	qq_buddy *q_bud;
+	qq_buddy_data *bd;
 	GString *status;
 
-	q_bud = (qq_buddy *) b->proto_data;
-	if (q_bud == NULL)
+	bd = (qq_buddy_data *) b->proto_data;
+	if (bd == NULL)
 		return NULL;
 
 	status = g_string_new("");
 
-	switch(q_bud->status) {
+	switch(bd->status) {
 	case QQ_BUDDY_OFFLINE:
 		g_string_append(status, _("Offline"));
 		break;
@@ -272,7 +272,7 @@
 		g_string_append(status, _("Busy"));
 		break;
 	default:
-		g_string_printf(status, _("Unknown-%d"), q_bud->status);
+		g_string_printf(status, _("Unknown-%d"), bd->status);
 	}
 
 	return g_string_free(status, FALSE);
@@ -282,21 +282,21 @@
 /* a floating text when mouse is on the icon, show connection status here */
 static void qq_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
 {
-	qq_buddy *q_bud;
+	qq_buddy_data *bd;
 	gchar *tmp;
 	GString *str;
 
 	g_return_if_fail(b != NULL);
 
-	q_bud = (qq_buddy *) b->proto_data;
-	if (q_bud == NULL)
+	bd = (qq_buddy_data *) b->proto_data;
+	if (bd == NULL)
 		return;
 
-	/* if (PURPLE_BUDDY_IS_ONLINE(b) && q_bud != NULL) */
-	if (q_bud->ip.s_addr != 0) {
+	/* if (PURPLE_BUDDY_IS_ONLINE(b) && bd != NULL) */
+	if (bd->ip.s_addr != 0) {
 		str = g_string_new(NULL);
-		g_string_printf(str, "%s:%d", inet_ntoa(q_bud->ip), q_bud->port);
-		if (q_bud->comm_flag & QQ_COMM_FLAG_TCP_MODE) {
+		g_string_printf(str, "%s:%d", inet_ntoa(bd->ip), bd->port);
+		if (bd->comm_flag & QQ_COMM_FLAG_TCP_MODE) {
 			g_string_append(str, " TCP");
 		} else {
 			g_string_append(str, " UDP");
@@ -304,11 +304,11 @@
 		g_string_free(str, TRUE);
 	}
 
-	tmp = g_strdup_printf("%d", q_bud->age);
+	tmp = g_strdup_printf("%d", bd->age);
 	purple_notify_user_info_add_pair(user_info, _("Age"), tmp);
 	g_free(tmp);
 
-	switch (q_bud->gender) {
+	switch (bd->gender) {
 	case QQ_BUDDY_GENDER_GG:
 		purple_notify_user_info_add_pair(user_info, _("Gender"), _("Male"));
 		break;
@@ -319,38 +319,38 @@
 		purple_notify_user_info_add_pair(user_info, _("Gender"), _("Unknown"));
 		break;
 	default:
-		tmp = g_strdup_printf("Error (%d)", q_bud->gender);
+		tmp = g_strdup_printf("Error (%d)", bd->gender);
 		purple_notify_user_info_add_pair(user_info, _("Gender"), tmp);
 		g_free(tmp);
 	}
 
-	if (q_bud->level) {
-		tmp = g_strdup_printf("%d", q_bud->level);
+	if (bd->level) {
+		tmp = g_strdup_printf("%d", bd->level);
 		purple_notify_user_info_add_pair(user_info, _("Level"), tmp);
 		g_free(tmp);
 	}
 
 	str = g_string_new(NULL);
-	if (q_bud->comm_flag & QQ_COMM_FLAG_QQ_MEMBER) {
+	if (bd->comm_flag & QQ_COMM_FLAG_QQ_MEMBER) {
 		g_string_append( str, _("Member") );
 	}
-	if (q_bud->comm_flag & QQ_COMM_FLAG_QQ_VIP) {
+	if (bd->comm_flag & QQ_COMM_FLAG_QQ_VIP) {
 		g_string_append( str, _(" VIP") );
 	}
-	if (q_bud->comm_flag & QQ_COMM_FLAG_TCP_MODE) {
+	if (bd->comm_flag & QQ_COMM_FLAG_TCP_MODE) {
 		g_string_append( str, _(" TCP") );
 	}
-	if (q_bud->comm_flag & QQ_COMM_FLAG_MOBILE) {
+	if (bd->comm_flag & QQ_COMM_FLAG_MOBILE) {
 		g_string_append( str, _(" FromMobile") );
 	}
-	if (q_bud->comm_flag & QQ_COMM_FLAG_BIND_MOBILE) {
+	if (bd->comm_flag & QQ_COMM_FLAG_BIND_MOBILE) {
 		g_string_append( str, _(" BindMobile") );
 	}
-	if (q_bud->comm_flag & QQ_COMM_FLAG_VIDEO) {
+	if (bd->comm_flag & QQ_COMM_FLAG_VIDEO) {
 		g_string_append( str, _(" Video") );
 	}
 
-	if (q_bud->ext_flag & QQ_EXT_FLAG_ZONE) {
+	if (bd->ext_flag & QQ_EXT_FLAG_ZONE) {
 		g_string_append( str, _(" Zone") );
 	}
 	purple_notify_user_info_add_pair(user_info, _("Flag"), str->str);
@@ -359,13 +359,13 @@
 
 #ifdef DEBUG
 	tmp = g_strdup_printf( "%s (%04X)",
-										qq_get_ver_desc(q_bud->client_tag),
-										q_bud->client_tag );
+										qq_get_ver_desc(bd->client_tag),
+										bd->client_tag );
 	purple_notify_user_info_add_pair(user_info, _("Ver"), tmp);
 	g_free(tmp);
 
 	tmp = g_strdup_printf( "Ext 0x%X, Comm 0x%X",
-												q_bud->ext_flag, q_bud->comm_flag );
+												bd->ext_flag, bd->comm_flag );
 	purple_notify_user_info_add_pair(user_info, _("Flag"), tmp);
 	g_free(tmp);
 #endif
@@ -377,13 +377,13 @@
 	PurpleAccount *account;
 	PurpleConnection *gc;
 	qq_data *qd;
-	qq_buddy *buddy;
+	qq_buddy_data *buddy;
 
-	if (!b || !(account = b->account) || 
+	if (!b || !(account = b->account) ||
 		!(gc = purple_account_get_connection(account)) || !(qd = gc->proto_data))
 		return NULL;
 
-	buddy = (qq_buddy *)b->proto_data;
+	buddy = (qq_buddy_data *)b->proto_data;
 	if (!buddy) {
 		return "not-authorized";
 	}
@@ -595,7 +595,7 @@
 	g_string_append_printf(info, _("<b>Login time</b>: %d-%d-%d, %d:%d:%d<br>\n"),
 			(1900 +tm_local->tm_year), (1 + tm_local->tm_mon), tm_local->tm_mday,
 			tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec);
-	g_string_append_printf(info, _("<b>Online Buddies</b>: %d<br>\n"), qd->online_total);
+	g_string_append_printf(info, _("<b>Total Online Buddies</b>: %d<br>\n"), qd->online_total);
 	tm_local = localtime(&qd->online_last_update);
 	g_string_append_printf(info, _("<b>Last Refresh</b>: %d-%d-%d, %d:%d:%d<br>\n"),
 			(1900 +tm_local->tm_year), (1 + tm_local->tm_mon), tm_local->tm_mday,
@@ -606,7 +606,7 @@
 	g_string_append_printf(info, _("<b>Server</b>: %s<br>\n"), qd->curr_server);
 	g_string_append_printf(info, _("<b>Client Tag</b>: %s<br>\n"), qq_get_ver_desc(qd->client_tag));
 	g_string_append_printf(info, _("<b>Connection Mode</b>: %s<br>\n"), qd->use_tcp ? "TCP" : "UDP");
-	g_string_append_printf(info, _("<b>My Internet IP</b>: %s<br>\n"), inet_ntoa(qd->my_ip));
+	g_string_append_printf(info, _("<b>My Internet IP</b>: %s:%d<br>\n"), inet_ntoa(qd->my_ip), qd->my_port);
 
 	g_string_append(info, "<hr>");
 	g_string_append(info, "<i>Network Status</i><br>\n");
@@ -758,12 +758,12 @@
 {
 	PurpleBuddy *buddy;
 	PurpleConnection *gc;
-	qq_buddy *q_bud;
+	qq_buddy_data *bd;
 
 	g_return_if_fail (PURPLE_BLIST_NODE_IS_BUDDY (node));
 	buddy = (PurpleBuddy *) node;
-	q_bud = (qq_buddy *) buddy->proto_data;
-/*	if (is_online (q_bud->status)) { */
+	bd = (qq_buddy_data *) buddy->proto_data;
+/*	if (is_online (bd->status)) { */
 	gc = purple_account_get_connection (buddy->account);
 	g_return_if_fail (gc != NULL && gc->proto_data != NULL);
 	qq_send_file(gc, buddy->name, NULL);
@@ -843,7 +843,7 @@
 
 /* TODO : not working, temp commented out by gfhuang */
 #if 0
-/*	if (q_bud && is_online(q_bud->status)) { */
+/*	if (bd && is_online(bd->status)) { */
 		act = purple_menu_action_new(_("Send File"), PURPLE_CALLBACK(_qq_menu_send_file), NULL, NULL); /* add NULL by gfhuang */
 		m = g_list_append(m, act);
 /*	} */
--- a/libpurple/protocols/qq/qq.h	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/qq.h	Wed Oct 22 14:59:55 2008 +0000
@@ -37,7 +37,7 @@
 #define QQ_KEY_LENGTH       16
 
 typedef struct _qq_data qq_data;
-typedef struct _qq_buddy qq_buddy;
+typedef struct _qq_buddy_data qq_buddy_data;
 typedef struct _qq_interval qq_interval;
 typedef struct _qq_net_stat qq_net_stat;
 typedef struct _qq_add_request qq_add_request;
@@ -86,7 +86,7 @@
 	glong rcved_dup;
 };
 
-struct _qq_buddy {
+struct _qq_buddy_data {
 	guint32 uid;
 	guint16 face;		/* index: 0 - 299 */
 	guint8 age;
--- a/libpurple/protocols/qq/qq_process.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/qq_process.c	Wed Oct 22 14:59:55 2008 +0000
@@ -652,6 +652,7 @@
 		default:
 			break;
 	}
+	qd->online_last_update = time(NULL);
 }
 
 static void update_all_rooms_online(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
@@ -699,11 +700,11 @@
 		case QQ_CMD_GET_BUDDIES_ONLINE:
 			/* last command */
 			update_all_rooms_online(gc, 0, 0);
-			qd->online_last_update = time(NULL);
 			break;
 		default:
 			break;
 	}
+	qd->online_last_update = time(NULL);
 }
 
 void qq_proc_room_cmds(PurpleConnection *gc, guint16 seq,
--- a/libpurple/protocols/qq/send_file.c	Wed Oct 22 14:58:32 2008 +0000
+++ b/libpurple/protocols/qq/send_file.c	Wed Oct 22 14:59:55 2008 +0000
@@ -771,7 +771,7 @@
 	gchar *sender_name, **fileinfo;
 	ft_info *info;
 	PurpleBuddy *b;
-	qq_buddy *q_bud;
+	qq_buddy_data *bd;
 	gint bytes;
 
 	g_return_if_fail (data != NULL && data_len != 0);
@@ -804,20 +804,21 @@
 			    "Received a FACE ip detect from %d, so he/she must be online :)\n", sender_uid);
 
 		b = purple_find_buddy(gc->account, sender_name);
-		q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data;
-		if (q_bud) {
+		bd = (b == NULL) ? NULL : (qq_buddy_data *) b->proto_data;
+		if (bd) {
 			if(0 != info->remote_real_ip) {
-				g_memmove(&(q_bud->ip), &info->remote_real_ip, sizeof(q_bud->ip));
-				q_bud->port = info->remote_minor_port;
+				g_memmove(&(bd->ip), &info->remote_real_ip, sizeof(bd->ip));
+				bd->port = info->remote_minor_port;
 			}
 			else if (0 != info->remote_internet_ip) {
-				g_memmove(&(q_bud->ip), &info->remote_internet_ip, sizeof(q_bud->ip));
-				q_bud->port = info->remote_major_port;
+				g_memmove(&(bd->ip), &info->remote_internet_ip, sizeof(bd->ip));
+				bd->port = info->remote_major_port;
 			}
 
-			if(!is_online(q_bud->status)) {
-				q_bud->status = QQ_BUDDY_ONLINE_INVISIBLE;
-				qq_update_buddy_contact(gc, q_bud);
+			if(!is_online(bd->status)) {
+				bd->status = QQ_BUDDY_ONLINE_INVISIBLE;
+				bd->last_update = time(NULL);
+				qq_update_buddy_status(gc, bd->uid, bd->status, bd->comm_flag);
 			}
 			else
 				purple_debug_info("QQ", "buddy %d is already online\n", sender_uid);