pidgin.2.4.3: a6a8a0f2: patch-05-reconnect-and-code-cleanup

csyfek at gmail.com csyfek at gmail.com
Tue Jun 24 08:41:06 EDT 2008


-----------------------------------------------------------------
Revision: a6a8a0f2b45006944916446be22cb8e56f0fca3f
Ancestor: fcd04238bea0560e8077f1f3f052119c00305e5f
Author: csyfek at gmail.com
Date: 2008-06-24T12:28:38
Branch: im.pidgin.pidgin.2.4.3
URL: http://d.pidgin.im/viewmtn/revision/info/a6a8a0f2b45006944916446be22cb8e56f0fca3f

Deleted entries:
        libpurple/protocols/qq/sendqueue.c
        libpurple/protocols/qq/sendqueue.h
Added files:
        libpurple/protocols/qq/qq_trans.c
        libpurple/protocols/qq/qq_trans.h
Modified files:
        libpurple/protocols/qq/ChangeLog
        libpurple/protocols/qq/Makefile.am
        libpurple/protocols/qq/Makefile.mingw
        libpurple/protocols/qq/buddy_info.c
        libpurple/protocols/qq/buddy_list.c
        libpurple/protocols/qq/buddy_opt.c
        libpurple/protocols/qq/buddy_status.c
        libpurple/protocols/qq/group_im.c
        libpurple/protocols/qq/group_im.h
        libpurple/protocols/qq/group_network.c
        libpurple/protocols/qq/im.c
        libpurple/protocols/qq/keep_alive.c
        libpurple/protocols/qq/login_logout.c
        libpurple/protocols/qq/packet_parse.c
        libpurple/protocols/qq/packet_parse.h
        libpurple/protocols/qq/qq.c libpurple/protocols/qq/qq.h
        libpurple/protocols/qq/qq_network.c
        libpurple/protocols/qq/qq_network.h
        libpurple/protocols/qq/send_file.c
        libpurple/protocols/qq/sys_msg.c
        libpurple/protocols/qq/utils.c

ChangeLog: 

patch-05-reconnect-and-code-cleanup

-------------- next part --------------
============================================================
--- libpurple/protocols/qq/qq_trans.c	f88e7f28beaef9d40a60caac32d0eac9ab81730f
+++ libpurple/protocols/qq/qq_trans.c	f88e7f28beaef9d40a60caac32d0eac9ab81730f
@@ -0,0 +1,246 @@
+/**
+ * @file qq_trans.c
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "internal.h"
+
+#include "connection.h"
+#include "debug.h"
+#include "notify.h"
+#include "prefs.h"
+#include "request.h"
+
+#include "header_info.h"
+#include "qq_network.h"
+#include "qq_trans.h"
+
+#define QQ_RESEND_MAX               8	/* max resend per packet */
+
+typedef struct _transaction {
+	guint16 seq;
+	guint16 cmd;
+	guint8 *buf;
+	gint buf_len;
+
+	gint fd;
+	gint retries;
+	time_t create_time;
+} transaction;
+
+void qq_send_trans_append(qq_data *qd, guint8 *buf, gint buf_len, guint16 cmd, guint16 seq)
+{
+	transaction *trans = g_new0(transaction, 1);
+
+	g_return_if_fail(trans != NULL);
+
+	trans->fd = qd->fd;
+	trans->cmd = cmd;
+	trans->seq = seq;
+	trans->retries = QQ_RESEND_MAX;
+	trans->create_time = time(NULL);
+	trans->buf = g_memdup(buf, buf_len);	/* don't use g_strdup, may have 0x00 */
+	trans->buf_len = buf_len;
+
+	purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+			"Add to transaction, seq = %d, buf = %p, len = %d\n",
+			trans->seq, trans->buf, trans->buf_len);
+	qd->send_trans = g_list_append(qd->send_trans, trans);
+}
+
+/* Remove a packet with seq from send trans */
+void qq_send_trans_remove(qq_data *qd, gpointer data) 
+{
+	transaction *trans = (transaction *)data;
+
+	g_return_if_fail(qd != NULL && data != NULL);
+	
+	purple_debug(PURPLE_DEBUG_INFO, "QQ",
+				"ack [%05d] %s, remove from send tranactions\n",
+				trans->seq, qq_get_cmd_desc(trans->cmd));
+
+	if (trans->buf)	g_free(trans->buf);
+	qd->send_trans = g_list_remove(qd->send_trans, trans);
+	g_free(trans);
+}
+
+gpointer qq_send_trans_find(qq_data *qd, guint16 seq)
+{
+	GList *curr;
+	GList *next;
+	transaction *trans;
+
+	curr = qd->send_trans;
+	while(curr) {
+		next = curr->next;
+		trans = (transaction *) (curr->data);
+		if(trans->seq == seq) {
+			return trans;
+		}
+		curr = next;
+	}
+
+	return NULL;
+}
+
+/* clean up send trans and free all contents */
+void qq_send_trans_remove_all(qq_data *qd)
+{
+	GList *curr;
+	GList *next;
+	transaction *trans;
+	gint count = 0;
+
+	curr = qd->send_trans;
+	while(curr) {
+		next = curr->next;
+		
+		trans = (transaction *) (curr->data);
+		/*
+		purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+			"Remove to transaction, seq = %d, buf = %p, len = %d\n",
+			trans->seq, trans->buf, trans->len);
+		*/
+		qq_send_trans_remove(qd, trans);
+
+		count++;
+		curr = next;
+	}
+	g_list_free(qd->send_trans);
+
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d packets in send tranactions are freed!\n", count);
+}
+
+gint qq_send_trans_scan(qq_data *qd, gint *start,
+	guint8 *buf, gint maxlen, guint16 *cmd, gint *retries)
+{
+	GList *curr;
+	GList *next = NULL;
+	transaction *trans;
+	gint copylen;
+
+	g_return_val_if_fail(qd != NULL && *start >= 0 && maxlen > 0, -1);
+	
+	/* purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Scan from %d\n", *start); */
+	curr = g_list_nth(qd->send_trans, *start);
+	while(curr) {
+		next = curr->next;
+		*start = g_list_position(qd->send_trans, next);
+		
+		trans = (transaction *) (curr->data);
+		if (trans->buf == NULL || trans->buf_len <= 0) {
+			qq_send_trans_remove(qd, trans);
+			curr = next;
+			continue;
+		}
+
+		if (trans->retries < 0) {
+			purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+				"Remove transaction, seq %d, buf %p, len %d, retries %d, next %d\n",
+				trans->seq, trans->buf, trans->buf_len, trans->retries, *start);
+			qq_send_trans_remove(qd, trans);
+			curr = next;
+			continue;
+		}
+
+		purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+				"Resend transaction, seq %d, buf %p, len %d, retries %d, next %d\n",
+				trans->seq, trans->buf, trans->buf_len, trans->retries, *start);
+		copylen = MIN(trans->buf_len, maxlen);
+		g_memmove(buf, trans->buf, copylen);
+
+		*cmd = trans->cmd;
+		*retries = trans->retries;
+		trans->retries--;
+		return copylen;
+	}
+
+	/* purple_debug(PURPLE_DEBUG_INFO, "QQ", "Scan finished\n"); */
+	return -1;
+}
+
+void qq_rcv_trans_push(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len)
+{
+	transaction *trans = g_new0(transaction, 1);
+
+	g_return_if_fail(data != NULL && data_len > 0);
+	g_return_if_fail(trans != NULL);
+
+	trans->cmd = cmd;
+	trans->seq = seq;
+	trans->buf = g_memdup(data, data_len);
+	trans->buf_len = data_len;
+	trans->create_time = time(NULL);
+
+	if (qd->rcv_trans == NULL)
+		qd->rcv_trans = g_queue_new();
+
+	g_queue_push_head(qd->rcv_trans, trans);
+}
+
+gint qq_rcv_trans_pop(qq_data *qd, guint16 *cmd, guint16 *seq, guint8 *data, gint max_len)
+{
+	transaction *trans = NULL;
+	gint copy_len;
+
+	g_return_val_if_fail(data != NULL && max_len > 0, -1);
+
+	if (g_queue_is_empty(qd->rcv_trans)) {
+		return -1;
+	}
+	trans = (transaction *) g_queue_pop_head(qd->rcv_trans);
+	if (trans == NULL) {
+		return 0;
+	}
+	if (trans->buf == NULL || trans->buf_len <= 0) {
+		return 0;
+	}
+
+	copy_len = MIN(max_len, trans->buf_len);
+	g_memmove(data, trans->buf, copy_len);
+	*cmd = trans->cmd;
+	*seq = trans->seq;
+
+	g_free(trans->buf);
+	g_free(trans);
+	return copy_len;
+}
+
+/* clean up the packets before login */
+void qq_rcv_trans_remove_all(qq_data *qd)
+{
+	transaction *trans = NULL;
+	gint count = 0;
+
+	g_return_if_fail(qd != NULL);
+
+	/* now clean up my own data structures */
+	if (qd->rcv_trans != NULL) {
+		while (NULL != (trans = g_queue_pop_tail(qd->rcv_trans))) {
+			g_free(trans->buf);
+			g_free(trans);
+			count++;
+		}
+		g_queue_free(qd->rcv_trans);
+	}
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d packets in receive tranactions are freed!\n", count);
+}
============================================================
--- libpurple/protocols/qq/qq_trans.h	80f8f5efcf8181555ed864d4a9cf3ebcf93154c2
+++ libpurple/protocols/qq/qq_trans.h	80f8f5efcf8181555ed864d4a9cf3ebcf93154c2
@@ -0,0 +1,42 @@
+/**
+ * @file qq_trans.h
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef _QQ_SEND_QUEUE_H_
+#define _QQ_SEND_QUEUE_H_
+
+#include <glib.h>
+#include "qq.h"
+
+void qq_send_trans_append(qq_data *qd, guint8 *buf, gint bus_len, guint16 cmd, guint16 seq);
+void qq_send_trans_remove(qq_data *qd, gpointer data);
+gpointer qq_send_trans_find(qq_data *qd, guint16 seq);
+void qq_send_trans_remove_all(qq_data *qd);
+
+gint qq_send_trans_scan(qq_data *qd, gint *start, guint8 *buf, gint maxlen, guint16 *cmd, gint *retries);
+
+void qq_rcv_trans_push(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len);
+gint qq_rcv_trans_pop(qq_data *qd, guint16 *cmd, guint16* seq, guint8 *data, gint max_len);
+void qq_rcv_trans_remove_all(qq_data *qd);
+
+#endif
============================================================
--- libpurple/protocols/qq/ChangeLog	c71777eb23741e23437cac84a09b8bb0bd8692cb
+++ libpurple/protocols/qq/ChangeLog	00098aecec67a7c79feb8f74898b88d600da9a33
@@ -1,3 +1,13 @@
+2008.06.07 - ccpaging <ecc_hy(at)hotmail.com>, csyfek <csyfek(at)gmail.com>
+	* Clean code and apply patches from QuLogic
+
+2008.05.19 - ccpaging <ecc_hy(at)hotmail.com>, csyfek <csyfek(at)gmail.com>
+	* Reconnect server 5 time in 5000 ms, when connect failed
+	* Rename sendqueue.c/sendqueue.h to qq_trans.c/qq_trans.h
+	* Rewrite packet_process
+	* Rewrite qq_send_cmd
+	* Create server list, try to connect every server when failed
+
 2008.05.14 - ccpaging <ecc_hy(at)hotmail.com>
 	* Move function for before login packets storing to sendqueue
 	* Use transaction data structure to store before login packets
============================================================
--- libpurple/protocols/qq/Makefile.am	5f9cc460a8b169911e15ca4b55bbb68fd456acb7
+++ libpurple/protocols/qq/Makefile.am	a9b20ab3e91464d161b7c78ba9cfc9d25bd1bcdc
@@ -56,8 +56,8 @@ QQSOURCES = \
 	qq_network.h \
 	send_file.c \
 	send_file.h \
-	sendqueue.c \
-	sendqueue.h \
+	qq_trans.c \
+	qq_trans.h \
 	sys_msg.c \
 	sys_msg.h \
 	utils.c \
============================================================
--- libpurple/protocols/qq/Makefile.mingw	0cd549b5aa0bb7745db1f61f3aa19b223f7a6e6a
+++ libpurple/protocols/qq/Makefile.mingw	23928c33a77a8e87581e0641e317e9314a2279b6
@@ -65,7 +65,7 @@ C_SRC = \
 	qq.c \
 	qq_network.c \
 	send_file.c \
-	sendqueue.c \
+	qq_trans.c \
 	sys_msg.c \
 	utils.c
 
============================================================
--- libpurple/protocols/qq/buddy_info.c	b7646da7a807e77ea2391025491833f5a0b2df52
+++ libpurple/protocols/qq/buddy_info.c	504fbb2f1055b3d5f890990f0b85351596e51722
@@ -283,7 +283,7 @@ void qq_send_packet_get_info(PurpleConne
 
 	qd = (qq_data *) gc->proto_data;
 	g_snprintf(uid_str, sizeof(uid_str), "%d", uid);
-	qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, TRUE, 0, TRUE, (guint8 *) uid_str, strlen(uid_str));
+	qq_send_cmd(qd, QQ_CMD_GET_USER_INFO, (guint8 *) uid_str, strlen(uid_str));
 
 	query = g_new0(qq_info_query, 1);
 	query->uid = uid;
@@ -313,6 +313,7 @@ static void qq_send_packet_modify_info(P
 /* send packet to modify personal information */
 static void qq_send_packet_modify_info(PurpleConnection *gc, contact_info *info)
 {
+	qq_data *qd = (qq_data *) gc->proto_data;
 	gint bytes = 0;
 	guint8 raw_data[MAX_PACKET_SIZE - 128] = {0};
 	guint8 bar;
@@ -444,7 +445,7 @@ static void qq_send_packet_modify_info(P
 
 	bytes += qq_put8(raw_data + bytes, bar);
 
-	qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, TRUE, 0, TRUE, raw_data, bytes);
+	qq_send_cmd(qd, QQ_CMD_UPDATE_INFO, raw_data, bytes);
 
 }
 
@@ -932,13 +933,15 @@ void qq_send_packet_get_level(PurpleConn
 
 void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid)
 {
+	qq_data *qd = (qq_data *) gc->proto_data;
 	guint8 buf[16] = {0};
 	gint bytes = 0;
 
 	bytes += qq_put8(buf + bytes, 0x00);
 	bytes += qq_put32(buf + bytes, uid);
 
-	qq_send_cmd(gc, QQ_CMD_GET_LEVEL, TRUE, 0, TRUE, buf, bytes);
+	qd = (qq_data *) gc->proto_data;
+	qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, bytes);
 }
 
 void qq_send_packet_get_buddies_levels(PurpleConnection *gc)
@@ -964,7 +967,7 @@ void qq_send_packet_get_buddies_levels(P
 			}
 			node = node->next;
 		}
-		qq_send_cmd(gc, QQ_CMD_GET_LEVEL, TRUE, 0, TRUE, buf, size);
+		qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, size);
 		g_free(buf);
 	}
 }
============================================================
--- libpurple/protocols/qq/buddy_list.c	fd6a60ef4a37d22cd31438bde3f338ba290bd2b8
+++ libpurple/protocols/qq/buddy_list.c	5a74ee6ca079793e853a137df42d507aa9897523
@@ -81,7 +81,7 @@ void qq_send_packet_get_buddies_online(P
 	/* 003-004 */
 	bytes += qq_put16(raw_data + bytes, 0x0000);
 
-	qq_send_cmd(gc, QQ_CMD_GET_FRIENDS_ONLINE, TRUE, 0, TRUE, raw_data, 5);
+	qq_send_cmd(qd, QQ_CMD_GET_FRIENDS_ONLINE, raw_data, 5);
 	qd->last_get_online = time(NULL);
 }
 
@@ -89,6 +89,7 @@ void qq_send_packet_get_buddies_list(Pur
  * server may return a position tag if list is too long for one packet */
 void qq_send_packet_get_buddies_list(PurpleConnection *gc, guint16 position)
 {
+	qq_data *qd = (qq_data *) gc->proto_data;
 	guint8 raw_data[16] = {0};
 	gint bytes = 0;
 
@@ -101,12 +102,13 @@ void qq_send_packet_get_buddies_list(Pur
 	 * March 22, found the 00,00,00 starts to work as well */
 	bytes += qq_put8(raw_data + bytes, 0x00);
 
-	qq_send_cmd(gc, QQ_CMD_GET_FRIENDS_LIST, TRUE, 0, TRUE, raw_data, bytes);
+	qq_send_cmd(qd, QQ_CMD_GET_FRIENDS_LIST, raw_data, bytes);
 }
 
 /* get all list, buddies & Quns with groupsid support */
 void qq_send_packet_get_all_list_with_group(PurpleConnection *gc, guint32 position)
 {
+	qq_data *qd = (qq_data *) gc->proto_data;
 	guint8 raw_data[16] = {0};
 	gint bytes = 0;
 
@@ -118,7 +120,7 @@ void qq_send_packet_get_all_list_with_gr
 	bytes += qq_put32(raw_data + bytes, 0x00000000);
 	bytes += qq_put32(raw_data + bytes, position);
 
-	qq_send_cmd(gc, QQ_CMD_GET_ALL_LIST_WITH_GROUP, TRUE, 0, TRUE, raw_data, bytes);
+	qq_send_cmd(qd, QQ_CMD_GET_ALL_LIST_WITH_GROUP, raw_data, bytes);
 }
 
 static void _qq_buddies_online_reply_dump_unclear(qq_friends_online_entry *fe)
============================================================
--- libpurple/protocols/qq/buddy_opt.c	19e35c2fca88964688857a8d3b9d2501e3d7f503
+++ libpurple/protocols/qq/buddy_opt.c	146cf2fc1c753795a8600427c2ebf102594a087d
@@ -61,18 +61,19 @@ static void _qq_send_packet_remove_buddy
 /* send packet to remove a buddy from my buddy list */
 static void _qq_send_packet_remove_buddy(PurpleConnection *gc, guint32 uid)
 {
+	qq_data *qd = (qq_data *) gc->proto_data;
 	gchar uid_str[11];
 
 	g_return_if_fail(uid > 0);
 
 	g_snprintf(uid_str, sizeof(uid_str), "%d", uid);
-	qq_send_cmd(gc, QQ_CMD_DEL_FRIEND, TRUE, 0, 
-			TRUE, (guint8 *) uid_str, strlen(uid_str));
+	qq_send_cmd(qd, QQ_CMD_DEL_FRIEND, (guint8 *) uid_str, strlen(uid_str));
 }
 
 /* try to remove myself from someone's buddy list */
 static void _qq_send_packet_remove_self_from(PurpleConnection *gc, guint32 uid)
 {
+	qq_data *qd = (qq_data *) gc->proto_data;
 	guint8 raw_data[16] = {0};
 	gint bytes = 0;
 
@@ -80,13 +81,13 @@ static void _qq_send_packet_remove_self_
 
 	bytes += qq_put32(raw_data + bytes, uid);
 
-	qq_send_cmd(gc, QQ_CMD_REMOVE_SELF, TRUE, 0, TRUE, raw_data, bytes);
+	qq_send_cmd(qd, QQ_CMD_REMOVE_SELF, raw_data, bytes);
 }
 
 /* try to add a buddy without authentication */
 static void _qq_send_packet_add_buddy(PurpleConnection *gc, guint32 uid)
 {
-	qq_data *qd;
+	qq_data *qd = (qq_data *) gc->proto_data;
 	qq_add_buddy_request *req;
 	gchar uid_str[11];
 
@@ -94,11 +95,9 @@ static void _qq_send_packet_add_buddy(Pu
 
 	/* we need to send the ascii code of this uid to qq server */
 	g_snprintf(uid_str, sizeof(uid_str), "%d", uid);
-	qq_send_cmd(gc, QQ_CMD_ADD_FRIEND_WO_AUTH, TRUE, 0, 
-			TRUE, (guint8 *) uid_str, strlen(uid_str));
+	qq_send_cmd(qd, QQ_CMD_ADD_FRIEND_WO_AUTH, (guint8 *) uid_str, strlen(uid_str));
 
 	/* must be set after sending packet to get the correct send_seq */
-	qd = (qq_data *) gc->proto_data;
 	req = g_new0(qq_add_buddy_request, 1);
 	req->seq = qd->send_seq;
 	req->uid = uid;
@@ -108,6 +107,7 @@ static void _qq_send_packet_buddy_auth(P
 /* this buddy needs authentication, text conversion is done at lowest level */
 static void _qq_send_packet_buddy_auth(PurpleConnection *gc, guint32 uid, const gchar response, const gchar *text)
 {
+	qq_data *qd = (qq_data *) gc->proto_data;
 	gchar *text_qq, uid_str[11];
 	guint8 bar, *raw_data;
 	gint bytes = 0;
@@ -129,7 +129,7 @@ static void _qq_send_packet_buddy_auth(P
 		g_free(text_qq);
 	}
 
-	qq_send_cmd(gc, QQ_CMD_BUDDY_AUTH, TRUE, 0, TRUE, raw_data, bytes);
+	qq_send_cmd(qd, QQ_CMD_BUDDY_AUTH, raw_data, bytes);
 }
 
 static void _qq_send_packet_add_buddy_auth_with_gc_and_uid(gc_and_uid *g, const gchar *text)
============================================================
--- libpurple/protocols/qq/buddy_status.c	0632ad56e2f8b1700583f2bec90d4b2655036141
+++ libpurple/protocols/qq/buddy_status.c	515b95f95274e31f9956938e55f12998ebc0e9fc
@@ -171,7 +171,7 @@ void qq_send_packet_change_status(Purple
 	bytes += qq_put8(raw_data + bytes, away_cmd);
 	bytes += qq_put32(raw_data + bytes, misc_status);
 
-	qq_send_cmd(gc, QQ_CMD_CHANGE_ONLINE_STATUS, TRUE, 0, TRUE, raw_data, bytes);
+	qq_send_cmd(qd, QQ_CMD_CHANGE_ONLINE_STATUS, raw_data, bytes);
 }
 
 /* parse the reply packet for change_status */
============================================================
--- libpurple/protocols/qq/group_im.c	78175de05126d2650ef372a672f84bb81ec6e833
+++ libpurple/protocols/qq/group_im.c	49ed251aa1f57b3bc77d439219c5cd39d6f52495
@@ -110,7 +110,7 @@ void qq_process_recv_group_im_apply_join
 
 	g_return_if_fail(internal_group_id > 0 && data != NULL && len > 0);
 
-	// Fixme: check length here
+	/* FIXME: check length here */
 
 	bytes += qq_get32(&external_group_id, data + bytes);
 	bytes += qq_get8(&group_type, data + bytes);
@@ -160,7 +160,7 @@ void qq_process_recv_group_im_been_rejec
 
 	g_return_if_fail(data != NULL && len > 0);
 
-	// Fixme: check length here
+	/* FIXME: check length here */
 
 	bytes += qq_get32(&external_group_id, data + bytes);
 	bytes += qq_get8(&group_type, data + bytes);
@@ -198,7 +198,7 @@ void qq_process_recv_group_im_been_appro
 
 	g_return_if_fail(data != NULL && len > 0);
 
-	// Fixme: check length here
+	/* FIXME: check length here */
 
 	bytes += qq_get32(&external_group_id, data + bytes);
 	bytes += qq_get8(&group_type, data + bytes);
@@ -234,7 +234,7 @@ void qq_process_recv_group_im_been_remov
 
 	g_return_if_fail(data != NULL && len > 0);
 
-	// Fixme: check length here
+	/* FIXME: check length here */
 
 	bytes += qq_get32(&external_group_id, data + bytes);
 	bytes += qq_get8(&group_type, data + bytes);
@@ -265,7 +265,7 @@ void qq_process_recv_group_im_been_added
 
 	g_return_if_fail(data != NULL && len > 0);
 
-	// Fixme: check length here
+	/* FIXME: check length here */
 
 	bytes += qq_get32(&external_group_id, data + bytes);
 	bytes += qq_get8(&group_type, data + bytes);
@@ -307,7 +307,7 @@ void qq_process_recv_group_im(guint8 *da
 
 	g_return_if_fail(data != NULL && data_len > 0);
 
-	// Fixme: check length here
+	/* FIXME: check length here */
 
 	qd = (qq_data *) gc->proto_data;
 
============================================================
--- libpurple/protocols/qq/group_im.h	d5646d54d4a8ed98ecf599577163d475d0b4d66f
+++ libpurple/protocols/qq/group_im.h	7d1e2fc8b103b68c616a2e27ad10d129a052f1ad
@@ -31,30 +31,30 @@ void qq_send_packet_group_im(PurpleConne
 
 void qq_send_packet_group_im(PurpleConnection *gc, qq_group *group, const gchar *msg);
 
-//void qq_process_group_cmd_im(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc);
+/* void qq_process_group_cmd_im(guint8 *data, guint8 **cursor, gint len, PurpleConnection *gc); */
 void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc);
 
-//void qq_process_recv_group_im(guint8 *data, 
-//		guint8 **cursor, gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type);
+/* void qq_process_recv_group_im(guint8 *data, guint8 **cursor, 
+ * gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type); */
 void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type);
 
-//void qq_process_recv_group_im_apply_join(guint8 *data,
-//				    guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc);
+/* void qq_process_recv_group_im_apply_join(guint8 *data, guint8 **cursor, gint len, 
+ * guint32 internal_group_id, PurpleConnection *gc); */
 void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc);
 
-//void qq_process_recv_group_im_been_rejected(guint8 *data,
-//				       guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc);
+/* void qq_process_recv_group_im_been_rejected(guint8 *data, guint8 **cursor, gint len, 
+ * guint32 internal_group_id, PurpleConnection *gc); */
 void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc);
 
-//void qq_process_recv_group_im_been_approved(guint8 *data,
-//				       guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc);
+/* void qq_process_recv_group_im_been_approved(guint8 *data, guint8 **cursor, gint len, 
+ * guint32 internal_group_id, PurpleConnection *gc); */
 void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc);
 
-//void qq_process_recv_group_im_been_removed(guint8 *data,
-//				      guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc);
+/* void qq_process_recv_group_im_been_removed(guint8 *data, guint8 **cursor, gint len, 
+ * guint32 internal_group_id, PurpleConnection *gc); */
 void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc);
 
-//void qq_process_recv_group_im_been_added(guint8 *data,
-//				    guint8 **cursor, gint len, guint32 internal_group_id, PurpleConnection *gc);
+/* void qq_process_recv_group_im_been_added(guint8 *data,  guint8 **cursor, gint len, 
+ * guint32 internal_group_id, PurpleConnection *gc); */
 void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc);
 #endif
============================================================
--- libpurple/protocols/qq/group_network.c	80d18884793457839a0acb6771b7be36aacaa832
+++ libpurple/protocols/qq/group_network.c	7a8524aa1a8ffa073f272f1f14757f681784f18f
@@ -115,7 +115,7 @@ void qq_send_group_cmd(PurpleConnection 
 
 	qd = (qq_data *) gc->proto_data;
 
-	qq_send_cmd(gc, QQ_CMD_GROUP_CMD, TRUE, 0, TRUE, raw_data, data_len);
+	qq_send_cmd(qd, QQ_CMD_GROUP_CMD, raw_data, data_len);
 
 	p = g_new0(group_packet, 1);
 
============================================================
--- libpurple/protocols/qq/im.c	e91f72d83ec7c15b2f2680116206653e6c0507d1
+++ libpurple/protocols/qq/im.c	e0de1b7f4c8b8b66f0d4193fc0b5071f409b22bc
@@ -219,7 +219,10 @@ static void _qq_send_packet_recv_im_ack(
  * we send an ACK which is the first 16 bytes of incoming packet */
 static void _qq_send_packet_recv_im_ack(PurpleConnection *gc, guint16 seq, guint8 *data)
 {
-	qq_send_cmd(gc, QQ_CMD_RECV_IM, FALSE, seq, FALSE, data, 16);
+	qq_data *qd;
+
+	qd = (qq_data *) gc->proto_data;
+	qq_send_cmd_detail(qd, QQ_CMD_RECV_IM, seq, FALSE, data, 16);
 }
 
 /* read the common parts of the normal_im,
@@ -520,7 +523,7 @@ void qq_send_packet_im(PurpleConnection 
 	qq_show_packet("QQ_raw_data debug", raw_data, bytes);
 
 	if (bytes == raw_len)	/* create packet OK */
-		qq_send_cmd(gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, bytes);
+		qq_send_cmd(qd, QQ_CMD_SEND_IM, raw_data, bytes);
 	else
 		purple_debug(PURPLE_DEBUG_ERROR, "QQ",
 				"Fail creating send_im packet, expect %d bytes, build %d bytes\n", raw_len, bytes);
============================================================
--- libpurple/protocols/qq/keep_alive.c	8577d0e6e583940cb85a8e3162d2c297c16c6843
+++ libpurple/protocols/qq/keep_alive.c	19862c1e3f239c13a647e8034bcf54ddd3e455fa
@@ -59,7 +59,7 @@ void qq_send_packet_keep_alive(PurpleCon
 	 * the amount of online QQ users, my ip and port */
 	bytes += qq_put32(raw_data + bytes, qd->uid);
 
-	qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, TRUE, 0, TRUE, raw_data, 4);
+	qq_send_cmd(qd, QQ_CMD_KEEP_ALIVE, raw_data, 4);
 }
 
 /* parse the return of keep-alive packet, it includes some system information */
============================================================
--- libpurple/protocols/qq/login_logout.c	2aff209621bedc661e18371eb42f7aee94676f3a
+++ libpurple/protocols/qq/login_logout.c	22730060416dcfded5c391d85fb57ee4e6ac65c5
@@ -70,7 +70,7 @@ static const guint8 login_23_51[29] = {
 */
 
 /* for QQ 2005? copy from lumaqq */
-// Fixme: change to guint8
+/* FIXME: change to guint8 */
 static const guint8 login_23_51[29] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x86, 0xcc, 0x4c, 0x35,
@@ -150,8 +150,9 @@ static guint8 *gen_session_md5(gint uid,
 	PurpleCipherContext *context;
 
 	src = g_newa(guint8, 20);
-	memcpy(src, &uid, 4);
-	memcpy(src, session_key, QQ_KEY_LENGTH);
+	/* bug found by QuLogic */
+	memcpy(src, &uid, sizeof(uid));
+	memcpy(src + sizeof(uid), session_key, QQ_KEY_LENGTH);
 
 	cipher = purple_ciphers_find_cipher("md5");
 	context = purple_cipher_context_new(cipher, NULL);
@@ -170,6 +171,7 @@ static gint _qq_process_login_ok(PurpleC
 	qq_login_reply_ok_packet lrop;
 
 	qd = (qq_data *) gc->proto_data;
+	/* FIXME, check QQ_LOGIN_REPLY_OK_PACKET_LEN here */
 	bytes = 0;
 
 	/* 000-000: reply code */
@@ -281,8 +283,8 @@ static gint _qq_process_login_redirect(P
 			   QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN, bytes);
 		ret = QQ_LOGIN_REPLY_MISC_ERROR;
 	} else {
-		// redirect to new server, do not disconnect or connect here
-		// those connect should be called at packet_process
+		/* redirect to new server, do not disconnect or connect here
+		 * those connect should be called at packet_process */
 		if (qd->real_hostname) {
 			purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n");
 			g_free(qd->real_hostname);
@@ -327,7 +329,7 @@ void qq_send_packet_request_login_token(
 
 	bytes += qq_put8(buf + bytes, 0);
 	
-	qq_send_data(gc, QQ_CMD_REQUEST_LOGIN_TOKEN, buf, bytes);
+	qq_send_data(qd, QQ_CMD_REQUEST_LOGIN_TOKEN, buf, bytes);
 }
 
 /* send login packet to QQ server */
@@ -384,7 +386,7 @@ static void qq_send_packet_login(PurpleC
 	bytes += qq_putdata(buf + bytes, qd->inikey, QQ_KEY_LENGTH);
 	bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len);
 
-	qq_send_data(gc, QQ_CMD_LOGIN, buf, bytes);
+	qq_send_data(qd, QQ_CMD_LOGIN, buf, bytes);
 }
 
 void qq_process_request_login_token_reply(guint8 *buf, gint buf_len, PurpleConnection *gc)
@@ -431,7 +433,7 @@ void qq_send_packet_logout(PurpleConnect
 
 	qd = (qq_data *) gc->proto_data;
 	for (i = 0; i < 4; i++)
-		qq_send_cmd(gc, QQ_CMD_LOGOUT, FALSE, 0xffff, FALSE, qd->pwkey, QQ_KEY_LENGTH);
+		qq_send_cmd_detail(qd, QQ_CMD_LOGOUT, 0xffff, FALSE, qd->pwkey, QQ_KEY_LENGTH);
 
 	qd->logged_in = FALSE;	/* update login status AFTER sending logout packets */
 }
============================================================
--- libpurple/protocols/qq/packet_parse.c	6bd97b798f0597efd5d94216e7168874fbaa622d
+++ libpurple/protocols/qq/packet_parse.c	feec9428b30781aa23b804a7011a7923558de6a0
@@ -33,9 +33,7 @@
 /* note:
  * 1, in these functions, 'b' stands for byte, 'w' stands for word, 'dw' stands for double word.
  * 2, we use '*cursor' and 'buf' as two addresses to calculate the length.
- * 3, fixed obscure bugs, thanks ccpaging.
- * 4, change '0' to '1', if want to get more info about the packet parsing.
- * by s3e, 20070717 */
+ * 3, change '0' to '1', if want to get more info about the packet parsing. */
 
 #if 0
 #define PARSER_DEBUG
@@ -49,8 +47,8 @@ gint qq_get8(guint8 *b, guint8 *buf)
 	memcpy(&b_dest, buf, sizeof(b_dest));
 	*b = b_dest;
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get8] buf %lu\n", (void *)buf);
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get8] b_dest 0x%2x, *b 0x%02x\n", b_dest, *b);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get8] buf %p\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get8] b_dest 0x%2x, *b 0x%02x\n", b_dest, *b);
 #endif
 	return sizeof(b_dest);
 }
@@ -64,8 +62,8 @@ gint qq_get16(guint16 *w, guint8 *buf)
 	memcpy(&w_dest, buf, sizeof(w_dest));
 	*w = g_ntohs(w_dest);
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get16] buf %lu\n", (void *)buf);
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get16] w_dest 0x%04x, *w 0x%04x\n", w_dest, *w);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get16] buf %p\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get16] w_dest 0x%04x, *w 0x%04x\n", w_dest, *w);
 #endif
 	return sizeof(w_dest);
 }
@@ -79,8 +77,8 @@ gint qq_get32(guint32 *dw, guint8 *buf)
 	memcpy(&dw_dest, buf, sizeof(dw_dest));
 	*dw = g_ntohl(dw_dest);
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get32] buf %lu\n", (void *)buf);
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get32] dw_dest 0x%08x, *dw 0x%08x\n", dw_dest, *dw);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get32] buf %p\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][get32] dw_dest 0x%08x, *dw 0x%08x\n", dw_dest, *dw);
 #endif
 	return sizeof(dw_dest);
 }
@@ -92,7 +90,7 @@ gint qq_getdata(guint8 *data, gint datal
 {
     memcpy(data, buf, datalen);
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getdata] buf %lu\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getdata] buf %p\n", (void *)buf);
 #endif
     return datalen;
 }
@@ -106,12 +104,12 @@ gint qq_getime(time_t *t, guint8 *buf)
 	guint32 dw_dest;
 	memcpy(&dw_dest, buf, sizeof(dw_dest));
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] buf %lu\n", (void *)buf);
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] dw_dest before 0x%08x\n", dw_dest);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] buf %p\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] dw_dest before 0x%08x\n", dw_dest);
 #endif
 	dw_dest = g_ntohl(dw_dest);
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] dw_dest after 0x%08x\n", dw_dest);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getime] dw_dest after 0x%08x\n", dw_dest);
 #endif
 	memcpy(t, &dw_dest, sizeof(dw_dest));
 	return sizeof(dw_dest);
@@ -124,8 +122,8 @@ gint qq_put8(guint8 *buf, guint8 b)
 {
     memcpy(buf, &b, sizeof(b));
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put8] buf %lu\n", (void *)buf);
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put8] b 0x%02x\n", b);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put8] buf %p\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put8] b 0x%02x\n", b);
 #endif
     return sizeof(b);
 }
@@ -138,8 +136,8 @@ gint qq_put16(guint8 *buf, guint16 w)
     guint16 w_porter;
     w_porter = g_htons(w);
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put16] buf %lu\n", (void *)buf);
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put16] w 0x%04x, w_porter 0x%04x\n", w, w_porter);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put16] buf %p\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put16] w 0x%04x, w_porter 0x%04x\n", w, w_porter);
 #endif
     memcpy(buf, &w_porter, sizeof(w_porter));
     return sizeof(w_porter);
@@ -153,8 +151,8 @@ gint qq_put32(guint8 *buf, guint32 dw)
     guint32 dw_porter;
     dw_porter = g_htonl(dw);
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put32] buf %lu\n", (void *)buf);
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put32] buf %p\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter);
 #endif
     memcpy(buf, &dw_porter, sizeof(dw_porter));
     return sizeof(dw_porter);
@@ -167,7 +165,7 @@ gint qq_putdata(guint8 *buf, const guint
 {
     memcpy(buf, data, datalen);
 #ifdef PARSER_DEBUG
-	purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][putdata] buf %lu\n", (void *)buf);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][putdata] buf %p\n", (void *)buf);
 #endif
     return datalen;
 }
============================================================
--- libpurple/protocols/qq/packet_parse.h	a7e348bfde7cdd37680633be4c2746d684ca5aa1
+++ libpurple/protocols/qq/packet_parse.h	3da5208644cd48d00eb4f39622119a237a14d023
@@ -48,15 +48,17 @@ gint qq_putdata(guint8 *buf, const guint
 gint qq_put32(guint8 *buf, guint32 dw);
 gint qq_putdata(guint8 *buf, const guint8 *data, const int datalen);
 
-//gint read_packet_b(guint8 *buf, guint8 **cursor, gint buflen, guint8 *b);
-//gint read_packet_w(guint8 *buf, guint8 **cursor, gint buflen, guint16 *w);
-//gint read_packet_dw(guint8 *buf, guint8 **cursor, gint buflen, guint32 *dw);
-//gint read_packet_time(guint8 *buf, guint8 **cursor, gint buflen, time_t *t);
-//gint read_packet_data(guint8 *buf, guint8 **cursor, gint buflen, guint8 *data, gint datalen);
+/*
+gint read_packet_b(guint8 *buf, guint8 **cursor, gint buflen, guint8 *b);
+gint read_packet_w(guint8 *buf, guint8 **cursor, gint buflen, guint16 *w);
+gint read_packet_dw(guint8 *buf, guint8 **cursor, gint buflen, guint32 *dw);
+gint read_packet_time(guint8 *buf, guint8 **cursor, gint buflen, time_t *t);
+gint read_packet_data(guint8 *buf, guint8 **cursor, gint buflen, guint8 *data, gint datalen);
 
-//gint create_packet_b(guint8 *buf, guint8 **cursor, guint8 b);
-//gint create_packet_w(guint8 *buf, guint8 **cursor, guint16 w);
-//gint create_packet_dw(guint8 *buf, guint8 **cursor, guint32 dw);
-//gint create_packet_data(guint8 *buf, guint8 **cursor, guint8 *data, gint datalen);
+gint create_packet_b(guint8 *buf, guint8 **cursor, guint8 b);
+gint create_packet_w(guint8 *buf, guint8 **cursor, guint16 w);
+gint create_packet_dw(guint8 *buf, guint8 **cursor, guint32 dw);
+gint create_packet_data(guint8 *buf, guint8 **cursor, guint8 *data, gint datalen);
+*/
 
 #endif
============================================================
--- libpurple/protocols/qq/qq.c	9efff1f2f37bd0d7c71c21fb505b31ac76246e90
+++ libpurple/protocols/qq/qq.c	ec0c1145646c14c17ea491407e2cc6ac75adac39
@@ -62,47 +62,22 @@
 
 #define OPENQ_AUTHOR            "Puzzlebird"
 #define OPENQ_WEBSITE            "http://openq.sourceforge.net"
+
 #define QQ_TCP_PORT       		8000
 #define QQ_UDP_PORT             	8000
 
-const gchar *udp_server_list[] = {
-	"sz.tencent.com",
-	"sz2.tencent.com",
-	"sz3.tencent.com",
-	"sz4.tencent.com",
-	"sz5.tencent.com",
-	"sz6.tencent.com",
-	"sz7.tencent.com",
-	"sz8.tencent.com",
-	"sz9.tencent.com"
-};
-const gint udp_server_amount = (sizeof(udp_server_list) / sizeof(udp_server_list[0]));
-
-
-const gchar *tcp_server_list[] = {
-	"tcpconn.tencent.com",
-	"tcpconn2.tencent.com",
-	"tcpconn3.tencent.com",
-	"tcpconn4.tencent.com",
-	"tcpconn5.tencent.com",
-	"tcpconn6.tencent.com"
-};
-const gint tcp_server_amount = (sizeof(tcp_server_list) / sizeof(tcp_server_list[0]));
-
-static void srv_resolved(PurpleSrvResponse *resp, int results, gpointer account)
-{
+static void server_list_create(PurpleAccount *account) {
 	PurpleConnection *gc;
 	qq_data *qd;
-	gchar *hostname;
+	const gchar *user_server;
 	int port;
 
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "Create server list\n");
 	gc = purple_account_get_connection(account);
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
-	qd = (qq_data *) gc->proto_data;
+	g_return_if_fail(gc != NULL  && gc->proto_data != NULL);
+	qd = gc->proto_data;
 
-	qd->srv_query_data = NULL;
-
-	/* find the host to connect to */
+	qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE);
 	port = purple_account_get_int(account, "port", 0);
 	if (port == 0) {
 		if (qd->use_tcp) {
@@ -111,38 +86,62 @@ static void srv_resolved(PurpleSrvRespon
 			port = QQ_UDP_PORT;
 		}
 	}
+	qd->user_port = port;
 
-	if(results) {
-		hostname = g_strdup(resp->hostname);
-		if(!port)
-			port = resp->port;
-		g_free(resp);
-	} else {
-		if(!purple_account_get_bool(account, "useproxy", FALSE)) {
-			hostname = g_strdup(qd->server_name);
-		} else {
-			hostname = g_strdup(purple_account_get_string(account,
-				"proxy", qd->server_name));
-		}
+ 	g_return_if_fail(qd->user_server == NULL);
+	user_server = purple_account_get_string(account, "server", NULL);
+	if (user_server != NULL && strlen(user_server) > 0) {
+		qd->user_server = g_strdup(user_server);
 	}
 
-	/*
-	purple_debug(PURPLE_DEBUG_INFO, "QQ",
-		"using with server %s and port %d\n", hostname, port);
-	*/
-	qd->real_hostname = g_strdup(hostname);
-	qd->real_port = port;
-	qq_connect(account);
+	if (qd->user_server != NULL) {
+		qd->servers = g_list_append(qd->servers, qd->user_server);
+		return;
+	}
+	if (qd->use_tcp) {
+		qd->servers = g_list_append(qd->servers, "tcpconn.tencent.com");
+		qd->servers = g_list_append(qd->servers, "tcpconn2.tencent.com");
+		qd->servers = g_list_append(qd->servers, "tcpconn3.tencent.com");
+		qd->servers = g_list_append(qd->servers, "tcpconn4.tencent.com");
+		qd->servers = g_list_append(qd->servers, "tcpconn5.tencent.com");
+		qd->servers = g_list_append(qd->servers, "tcpconn6.tencent.com");
+		return;
+    }
+    
+	qd->servers = g_list_append(qd->servers, "sz.tencent.com");
+	qd->servers = g_list_append(qd->servers, "sz2.tencent.com");
+	qd->servers = g_list_append(qd->servers, "sz3.tencent.com");
+	qd->servers = g_list_append(qd->servers, "sz4.tencent.com");
+	qd->servers = g_list_append(qd->servers, "sz5.tencent.com");
+	qd->servers = g_list_append(qd->servers, "sz6.tencent.com");
+	qd->servers = g_list_append(qd->servers, "sz7.tencent.com");
+	qd->servers = g_list_append(qd->servers, "sz8.tencent.com");
+	qd->servers = g_list_append(qd->servers, "sz9.tencent.com");
+}
 
-	g_free(hostname);
+static void server_list_remove_all(qq_data *qd) {
+ 	g_return_if_fail(qd != NULL);
+
+	if (qd->real_hostname) {
+		purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n");
+		g_free(qd->real_hostname);
+		qd->real_hostname = NULL;
+	}
+	
+	if (qd->user_server != NULL) {
+		purple_debug(PURPLE_DEBUG_INFO, "QQ", "free user_server\n");
+		g_free(qd->user_server);
+		qd->user_server = NULL;
+	}
+
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "free server list\n");
+ 	g_list_free(qd->servers);
 }
 
 static void qq_login(PurpleAccount *account)
 {
-	const gchar *userserver;
+	PurpleConnection *gc;
 	qq_data *qd;
-	gchar *host2connect;
-	PurpleConnection *gc;
 	PurplePresence *presence;
 
 	g_return_if_fail(account != NULL);
@@ -166,30 +165,11 @@ static void qq_login(PurpleAccount *acco
 		qd->login_mode = QQ_LOGIN_MODE_NORMAL;
 	}
 
-	userserver = purple_account_get_string(account, "server", NULL);
-	qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE);
+	server_list_create(account);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ",
+		"Server list has %d\n", g_list_length(qd->servers));
 
-	if (userserver == NULL || strlen(userserver) == 0) {
-		if (qd->use_tcp) {
-			qd->server_name = g_strdup(tcp_server_list[random() % tcp_server_amount]);
-		} else {
-			qd->server_name = g_strdup(udp_server_list[random() % udp_server_amount]);
-		}
-	} else {
-		qd->server_name = g_strdup(userserver);
-	}
-
-	purple_connection_update_progress(gc, _("Connecting"), 0, QQ_CONNECT_STEPS);
-
-	if(!purple_account_get_bool(account, "useproxy", FALSE)) {
-		host2connect = g_strdup(qd->server_name);
-	} else {
-		host2connect = g_strdup(purple_account_get_string(account, "proxy", qd->server_name));
-	}
-
-	qd->srv_query_data = purple_srv_resolve("QQ",
-			qd->use_tcp ? "tcp" : "udp", host2connect, srv_resolved, account);
-	g_free(host2connect);
+	qq_connect(account);
 }
 
 /* clean up the given QQ connection and free all resources */
@@ -197,20 +177,13 @@ static void qq_close(PurpleConnection *g
 {
 	qq_data *qd;
 
-	g_return_if_fail(gc != NULL);
+	g_return_if_fail(gc != NULL  && gc->proto_data);
 	qd = gc->proto_data;
 
 	qq_disconnect(gc);
 
-	if (qd->real_hostname) {
-		purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n");
-		g_free(qd->real_hostname);
-		qd->real_hostname = NULL;
-	}
-	if (qd->srv_query_data != NULL)
-		purple_srv_cancel(qd->srv_query_data);
+	server_list_remove_all(qd);
 	
-	g_free(qd->server_name);
 	g_free(qd);
 
 	gc->proto_data = NULL;
============================================================
--- libpurple/protocols/qq/qq.h	3aefba86630400977aec225e0d7926696edb9cef
+++ libpurple/protocols/qq/qq.h	94529661816228150ae7d79580c7007509cc9afc
@@ -70,31 +70,36 @@ struct _qq_data {
 
 struct _qq_data {
 	PurpleConnection *gc;
-	gchar *server_name;
 
-	// common network resource
-	PurpleSrvQueryData *srv_query_data;	// srv resolve
+	/* common network resource */
+	GList *servers;
+	gchar *user_server;
+	gint user_port;
+	gboolean use_tcp;		/* network in tcp or udp */
+	
+	gchar *server_name;
 	gboolean is_redirect;
-	gchar *real_hostname;	// from real connction
+	gchar *real_hostname;	/* from real connction */
 	guint16 real_port;
-	gboolean use_tcp;		// network in tcp or udp
-	
+	guint reconnect_timeout;
+	gint reconnect_times;
+
 	PurpleProxyConnectData *connect_data;
-	gint fd;				// socket file handler
-	gint tx_handler; 	// socket can_write handle, use in udp connecting and tcp send out
+	gint fd;				/* socket file handler */
+	gint tx_handler; 	/* socket can_write handle, use in udp connecting and tcp send out */
 
-	GList *transactions;	// check ack packet and resend
+	GList *send_trans;	/* check ack packet and resend */
 	guint resend_timeout;
 
-	guint8 rcv_window[1 << 13];		// windows for check duplicate packet
-	GQueue *rcv_trans;		// queue to store packet can not process before login
+	guint8 rcv_window[1 << 13];		/* windows for check duplicate packet */
+	GQueue *rcv_trans;		/* queue to store packet can not process before login */
 	
-	// tcp related
+	/* tcp related */
 	PurpleCircBuffer *tcp_txbuf;
 	guint8 *tcp_rxqueue;
 	int tcp_rxlen;
 	
-	// udp related
+	/* udp related */
 	PurpleDnsQueryData *udp_query_data;
 
 	guint32 uid;			/* QQ number */
@@ -108,7 +113,6 @@ struct _qq_data {
 	gboolean logged_in;		/* used by qq-add_buddy */
 
 	PurpleXfer *xfer;			/* file transfer handler */
-	struct sockaddr_in dest_sin;
 
 	/* get from login reply packet */
 	time_t login_time;
@@ -140,6 +144,4 @@ struct _qq_data {
 	gboolean modifying_face;
 };
 
-void qq_function_not_implemented(PurpleConnection *gc);
-
 #endif
============================================================
--- libpurple/protocols/qq/qq_network.c	51d45db61522e346a2d4ccbcaacc7b9861a5a236
+++ libpurple/protocols/qq/qq_network.c	58de8478d42cd07d5cbea9ef6c44edea10f37ed2
@@ -45,21 +45,68 @@
 #include "login_logout.h"
 #include "packet_parse.h"
 #include "qq_network.h"
-#include "sendqueue.h"
+#include "qq_trans.h"
 #include "sys_msg.h"
 #include "utils.h"
 
-/* These functions are used only in development phase */
-/*
-   static void _qq_show_socket(gchar *desc, gint fd) {
-   struct sockaddr_in sin;
-   socklen_t len = sizeof(sin);
-   getsockname(fd, (struct sockaddr *)&sin, &len);
-   purple_debug(PURPLE_DEBUG_INFO, desc, "%s:%d\n",
-   inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
-   }
-   */
+/* set QQ_RECONNECT_MAX to 1, when test reconnecting */
+#define QQ_RECONNECT_MAX					4
+#define QQ_RECONNECT_INTERVAL		5000
 
+static gboolean set_new_server(qq_data *qd)
+{
+	gint count;
+	gint index;
+	GList *it = NULL;
+	
+ 	g_return_val_if_fail(qd != NULL, FALSE);
+
+	if (qd->servers == NULL) {
+		purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server list is NULL\n");
+		return FALSE;
+	}
+
+	if (qd->real_hostname) {
+		purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n");
+		g_free(qd->real_hostname);
+		qd->real_hostname = NULL;
+	}
+
+	/* remove server used before */
+	if (qd->server_name != NULL) {
+		purple_debug(PURPLE_DEBUG_INFO, "QQ",
+			"Remove previous server [%s]\n", qd->server_name);
+   		qd->servers = g_list_remove(qd->servers, qd->server_name);
+   		qd->server_name = NULL;
+    }
+	
+	count = g_list_length(qd->servers);
+	purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server list has %d\n", count);
+	if (count <= 0) {
+		/* no server left, disconnect when result is false */
+		qd->servers = NULL;
+		return FALSE;
+	}
+	
+	/* get new server */
+	index  = random() % count;
+	it = g_list_nth(qd->servers, index);
+    qd->server_name = it->data;		/* do not free server_name */
+    if (qd->server_name == NULL || strlen(qd->server_name) <= 0 ) {
+		purple_debug(PURPLE_DEBUG_INFO, "QQ", "Server name at %d is empty\n", index);
+		return FALSE;
+	}
+
+	qd->real_hostname = g_strdup(qd->server_name);
+	qd->real_port = qd->user_port;
+	
+ 	qd->reconnect_times = QQ_RECONNECT_MAX;
+
+	purple_debug(PURPLE_DEBUG_INFO, "QQ",
+		"set new server to %s:%d\n", qd->real_hostname, qd->real_port);
+	return TRUE;
+}
+
 /* QQ 2003iii uses double MD5 for the pwkey to get the session key */
 static guint8 *encrypt_account_password(const gchar *pwd)
 {
@@ -82,7 +129,7 @@ static guint8 *encrypt_account_password(
 }
 
 /* default process, decrypt and dump */
-static void packet_process_unknow(PurpleConnection *gc, guint8 *buf, gint buf_len, guint16 cmd, guint16 seq)
+static void process_cmd_unknow(PurpleConnection *gc, guint8 *buf, gint buf_len, guint16 cmd, guint16 seq)
 {
 	qq_data *qd;
 	guint8 *data;
@@ -148,20 +195,80 @@ static gboolean packet_check_ack(qq_data
 
 	g_return_val_if_fail(qd != NULL, FALSE);
 
-	trans = qq_trans_find(qd, seq);
+	trans = qq_send_trans_find(qd, seq);
 	if (trans == NULL) {
 		return FALSE;
 	}
 	
-	qq_trans_remove(qd, trans);
+	qq_send_trans_remove(qd, trans);
 	return TRUE;
 }
 
-static void packet_process_cmd(
+static gboolean reconnect_later_cb(gpointer data)
+{
+	PurpleConnection *gc;
+	qq_data *qd;
+
+	gc = (PurpleConnection *) data;
+	g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE);
+	qd = (qq_data *) gc->proto_data;
+
+	qd->reconnect_timeout = 0;
+
+	qq_connect(gc->account);
+	return FALSE;	/* timeout callback stops */
+}
+
+static void reconnect_later(PurpleConnection *gc)
+{
+	qq_data *qd;
+
+	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+	qd = (qq_data *) gc->proto_data;
+
+	qd->reconnect_times--;
+	if (qd->reconnect_times < 0) {
+		if ( set_new_server(qd) != TRUE) {
+			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+					_("Failed to connect server"));
+			return;
+		}
+	}
+
+	purple_debug(PURPLE_DEBUG_INFO, "QQ",
+		"Reconnect to server %s:%d next retries %d in %d ms\n",
+		qd->real_hostname, qd->real_port,
+		qd->reconnect_times, QQ_RECONNECT_INTERVAL);
+
+	qd->reconnect_timeout = purple_timeout_add(QQ_RECONNECT_INTERVAL,
+		reconnect_later_cb, gc);
+}
+
+static void process_cmd_server(
 	PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len)
 {
 	/* now process the packet */
 	switch (cmd) {
+		case QQ_CMD_RECV_IM:
+			qq_process_recv_im(data, data_len, seq, gc);
+			break;
+		case QQ_CMD_RECV_MSG_SYS:
+			qq_process_msg_sys(data, data_len, seq, gc);
+			break;
+		case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
+			qq_process_friend_change_status(data, data_len, gc);
+			break;
+		default:
+			process_cmd_unknow(gc, data, data_len, cmd, seq);
+			break;
+	}
+}
+
+static void process_cmd_reply(
+	PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len)
+{
+	/* now process the packet */
+	switch (cmd) {
 		case QQ_CMD_KEEP_ALIVE:
 			qq_process_keep_alive_reply(data, data_len, gc);
 			break;
@@ -189,9 +296,6 @@ static void packet_process_cmd(
 		case QQ_CMD_SEND_IM:
 			qq_process_send_im_reply(data, data_len, gc);
 			break;
-		case QQ_CMD_RECV_IM:
-			qq_process_recv_im(data, data_len, seq, gc);
-			break;
 		case QQ_CMD_LOGIN:
 			qq_process_login_reply(data, data_len, gc);
 			break;
@@ -213,14 +317,8 @@ static void packet_process_cmd(
 		case QQ_CMD_REQUEST_LOGIN_TOKEN:
 			qq_process_request_login_token_reply(data, data_len, gc);
 			break;
-		case QQ_CMD_RECV_MSG_SYS:
-			qq_process_msg_sys(data, data_len, seq, gc);
-			break;
-		case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
-			qq_process_friend_change_status(data, data_len, gc);
-			break;
 		default:
-			packet_process_unknow(gc, data, data_len, cmd, seq);
+			process_cmd_unknow(gc, data, data_len, cmd, seq);
 			break;
 	}
 }
@@ -238,15 +336,17 @@ static void packet_process(PurpleConnect
 	guint8 header_tag;
 	guint16 source_tag;
 	guint16 cmd;
-	guint16 seq;		// May be ack_seq or send_seq, depends on cmd
+	guint16 seq;		/* May be ack_seq or send_seq, depends on cmd */
 
+	gboolean is_reply;
+
 	g_return_if_fail(buf != NULL && buf_len > 0);
 
 	qd = (qq_data *) gc->proto_data;
 
 	prev_login_status = qd->logged_in;
 
-	// Len, header and tail tag have been checked before
+	/* Len, header and tail tag have been checked before */
 	bytes = 0;
 	bytes += packet_get_header(&header_tag, &source_tag, &cmd, &seq, buf + bytes);
 
@@ -258,42 +358,37 @@ static void packet_process(PurpleConnect
 	
 	bytes_not_read = buf_len - bytes - 1;
 
-	if ( !qd->logged_in ) {
-		if (cmd != QQ_CMD_LOGIN && cmd != QQ_CMD_REQUEST_LOGIN_TOKEN) {
+	/* ack packet, we need to update send tranactions */
+	/* we do not check duplication for server ack */
+	is_reply = packet_check_ack(qd, seq);
+	if ( !is_reply ) {
+		if ( !qd->logged_in ) {
 			/* packets before login */
-			qq_packet_push(qd, cmd, seq, buf + bytes, bytes_not_read);
+			qq_rcv_trans_push(qd, cmd, seq, buf + bytes, bytes_not_read);
 			return;	/* do not process it now */
-		} 
+		}
+		
+		/* server intiated packet, we need to send ack and check duplicaion 
+		 * this must be put after processing b4_packet
+		 * as these packets will be passed in twice */
+		if (packet_is_dup(qd, seq)) {
+			purple_debug(PURPLE_DEBUG_WARNING,
+					"QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd));
+			return;
+		}
+		process_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read);
+		return;
 	}
 
-	/* whether it is an ack */
-	switch (cmd) {
-		case QQ_CMD_RECV_IM:
-		case QQ_CMD_RECV_MSG_SYS:
-		case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
-			/* server intiated packet, we need to send ack and check duplicaion 
-			 * this must be put after processing b4_packet
-			 * as these packets will be passed in twice */
-			if (packet_is_dup(qd, seq)) {
-				purple_debug(PURPLE_DEBUG_WARNING,
-						"QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd));
-				return;
-			}
-			break;
-		default:
-			/* ack packet, we need to update sendqueue */
-			/* we do not check duplication for server ack */
-			packet_check_ack(qd, seq);
-	}
-
 	/* this is the length of all the encrypted data (also remove tail tag */
-	packet_process_cmd(gc, cmd, seq, buf + bytes, bytes_not_read);
+	process_cmd_reply(gc, cmd, seq, buf + bytes, bytes_not_read);
 
-	// check is redirect or not, and do it now
+	/* check is redirect or not, and do it now */
 	if (qd->is_redirect) {
-	 	// free resource except real_hostname and port
+	 	/* free resource except real_hostname and port */
 		qq_disconnect(gc);
-		qq_connect(gc->account);
+	 	qd->reconnect_times = QQ_RECONNECT_MAX;
+		reconnect_later(gc);
 		return;
 	}
 
@@ -301,14 +396,15 @@ static void packet_process(PurpleConnect
 		/* logged_in, but we have packets before login */
 		new_data = g_newa(guint8, MAX_PACKET_SIZE);
 		while (1) {
-			new_data_len = qq_packet_pop(qd, &cmd, &seq, new_data, MAX_PACKET_SIZE);
+			memset(new_data, 0, MAX_PACKET_SIZE);
+			new_data_len = qq_rcv_trans_pop(qd, &cmd, &seq, new_data, MAX_PACKET_SIZE);
 			if (new_data_len < 0) {
 				break;
 			}
 			if (new_data_len == 0) {
 				continue;
 			}
-			packet_process_cmd(gc, seq, cmd, new_data, new_data_len);
+			process_cmd_reply(gc, seq, cmd, new_data, new_data_len);
 		}
 	}
 }
@@ -317,7 +413,7 @@ static void tcp_pending(gpointer data, g
 {
 	PurpleConnection *gc;
 	qq_data *qd;
-	guint8 buf[1024];		// set to 16 when test  tcp_rxqueue
+	guint8 buf[1024];		/* set to 16 when test  tcp_rxqueue */
 	gint buf_len;
 	gint bytes;
 	
@@ -389,7 +485,7 @@ static void tcp_pending(gpointer data, g
 		if ( pkt_len < QQ_TCP_HEADER_LENGTH
 		    || *(qd->tcp_rxqueue + bytes) != QQ_PACKET_TAG
 			|| *(qd->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) {
-			// HEY! This isn't even a QQ. What are you trying to pull?
+			/* HEY! This isn't even a QQ. What are you trying to pull? */
 
 			purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING",
 				 "Packet error, failed to check header and tail tag\n");
@@ -404,7 +500,7 @@ static void tcp_pending(gpointer data, g
 				return;
 			}
 
-			// jump and over QQ_PACKET_TAIL
+			/* jump and over QQ_PACKET_TAIL */
 			jump_len = (jump - qd->tcp_rxqueue) + 1;
 			purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING",
 				"Find next QQ_PACKET_TAIL at %d, jump %d bytes\n", jump_len, jump_len + 1);
@@ -416,7 +512,7 @@ static void tcp_pending(gpointer data, g
 		memset(pkt, 0, MAX_PACKET_SIZE);
 		g_memmove(pkt, qd->tcp_rxqueue + bytes, pkt_len - bytes);
 		
-		// jump to next packet
+		/* jump to next packet */
 		qd->tcp_rxlen -= pkt_len;
 		if (qd->tcp_rxlen) {
 			purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING",
@@ -434,8 +530,8 @@ static void tcp_pending(gpointer data, g
 		if (pkt == NULL) {
 			continue;
 		}
-		// do not call packet_process before jump
-		// packet_process may call disconnect and destory tcp_rxqueue
+		/* do not call packet_process before jump 
+		 * packet_process may call disconnect and destory tcp_rxqueue */
 		packet_process(gc, pkt, pkt_len - bytes);
 	}
 }
@@ -539,7 +635,9 @@ static gint tcp_send_out(qq_data *qd, gu
 
 	g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1);
 
-	// purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd);
+	/*
+	 * purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd);
+	 */
 
 	if (qd->tx_handler == 0) {
 		ret = write(qd->fd, data, data_len);
@@ -551,11 +649,13 @@ static gint tcp_send_out(qq_data *qd, gu
 	purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT",
 		"Socket %d, total %d bytes is sent %d\n", qd->fd, data_len, ret);
 	if (ret < 0 && errno == EAGAIN) {
-		// socket is busy, send later
-		// purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Socket is busy and send later\n");
+		/* socket is busy, send later */
+		/*
+		 * purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Socket is busy and send later\n");
+		 */
 		ret = 0;
 	} else if (ret <= 0) {
-		// TODO: what to do here - do we really have to disconnect?
+		/* TODO: what to do here - do we really have to disconnect? */
 		purple_debug(PURPLE_DEBUG_ERROR, "TCP_SEND_OUT",
 			"Send to socket %d failed: %d, %s\n", qd->fd, errno, g_strerror(errno));
 		purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno));
@@ -593,19 +693,19 @@ static gboolean trans_timeout(gpointer d
 
 	while (1) {
 		if (index < 0) {
-			// next record is NULL
+			/* next record is NULL */
 			break;
 		}
-		// purple_debug(PURPLE_DEBUG_ERROR, "QQ", "scan begin %d\n", index);
+		/* purple_debug(PURPLE_DEBUG_ERROR, "QQ", "scan begin %d\n", index); */
 		memset(buf, 0, MAX_PACKET_SIZE);
-		buf_len = qq_trans_scan(qd, &index, buf, MAX_PACKET_SIZE, &cmd, &retries);
+		buf_len = qq_send_trans_scan(qd, &index, buf, MAX_PACKET_SIZE, &cmd, &retries);
 		if (buf_len <= 0) {
-			// curr record is empty, whole trans  is NULL
+			/* curr record is empty, whole trans  is NULL */
 			break;
 		}
-		// index = -1, when get last record of transactions
+		/* index = -1, when get last record of transactions */
 		
-		// purple_debug(PURPLE_DEBUG_ERROR, "QQ", "retries %d next index %d\n", retries, index);
+		/* purple_debug(PURPLE_DEBUG_ERROR, "QQ", "retries %d next index %d\n", retries, index); */
 		if (retries > 0) {
 			if (qd->use_tcp) {
 				tcp_send_out(qd, buf, buf_len);
@@ -615,7 +715,7 @@ static gboolean trans_timeout(gpointer d
 			continue;
 		}
 
-		// retries <= 0
+		/* retries <= 0 */
 		switch (cmd) {
 		case QQ_CMD_KEEP_ALIVE:
 			if (qd->logged_in) {
@@ -648,7 +748,7 @@ static void qq_connect_cb(gpointer data,
 {
 	qq_data *qd;
 	PurpleConnection *gc;
-	gchar *buf;
+	gchar *conn_msg;
 	const gchar *passwd;
 
 	gc = (PurpleConnection *) data;
@@ -667,12 +767,13 @@ static void qq_connect_cb(gpointer data,
 	qd->connect_data = NULL;
 
 	if (source < 0) {	/* socket returns -1 */
-		purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Source is < 0\n");
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
+		purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection, source is < 0\n");
+		qq_disconnect(gc);
+		reconnect_later(gc);
 		return;
 	}
 
-	// _qq_show_socket("Got login socket", source);
+	/* _qq_show_socket("Got login socket", source); */
 
 	/* QQ use random seq, to minimize duplicated packets */
 	srandom(time(NULL));
@@ -697,9 +798,9 @@ static void qq_connect_cb(gpointer data,
 		gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, udp_pending, gc);
 
 	/* Update the login progress status display */
-	buf = g_strdup_printf("Login as %d", qd->uid);
-	purple_connection_update_progress(gc, buf, 1, QQ_CONNECT_STEPS);
-	g_free(buf);
+	conn_msg = g_strdup_printf("Login as %d", qd->uid);
+	purple_connection_update_progress(gc, conn_msg, QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS);
+	g_free(conn_msg);
 
 	qq_send_packet_request_login_token(gc);
 }
@@ -765,8 +866,8 @@ static void udp_host_resolved(GSList *ho
 
 	qd = (qq_data *) gc->proto_data;
 
-	// udp_query_data must be set as NULL.
-	// Otherwise purple_dnsquery_destroy in qq_disconnect cause glib double free error
+	/* udp_query_data must be set as NULL.
+	 * Otherwise purple_dnsquery_destroy in qq_disconnect cause glib double free error */
 	qd->udp_query_data = NULL;
 
 	if (!hosts || !hosts->data) {
@@ -842,18 +943,44 @@ void qq_connect(PurpleAccount *account)
 {
 	PurpleConnection *gc;
 	qq_data *qd;
+	gchar *conn_msg;
 
 	gc = purple_account_get_connection(account);
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
 
 	qd = (qq_data *) gc->proto_data;
 
+
+	/* test set_new_server
+	while (set_new_server(qd)) {
+   		purple_debug(PURPLE_DEBUG_INFO, "QQ_TEST",
+   			"New server %s:%d  Real server %s:%d\n",
+   			qd->server_name, qd->user_port, qd->real_hostname, qd->real_port);
+	}
+	purple_debug(PURPLE_DEBUG_INFO, "QQ_TEST", "qd->servers %lu\n",
+ 			qd->servers);
+ 	exit(1);
+	*/
+	if (qd->server_name == NULL) {
+		/* must be first call this function */
+		if ( set_new_server(qd) != TRUE) {
+			purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+					_("Failed to connect server"));
+			return;
+		}
+	}
+
 	if (qd->real_hostname == NULL || qd->real_port == 0) {
 		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 				_("hostname is NULL or port is 0"));
 		return;
 	}
 
+	conn_msg = g_strdup_printf( _("Connecting server %s, retries %d"),
+		qd->real_hostname, qd->reconnect_times);
+	purple_connection_update_progress(gc, conn_msg, 1, QQ_CONNECT_STEPS);
+	g_free(conn_msg);
+
 	if (qd->is_redirect) {
    		purple_debug(PURPLE_DEBUG_INFO, "QQ", "Redirect to %s:%d\n",
    			qd->real_hostname, qd->real_port);
@@ -863,8 +990,6 @@ void qq_connect(PurpleAccount *account)
 	qd->fd = -1;
 	qd->tx_handler = 0;
 	
-	g_return_if_fail(qd->real_hostname != NULL);
-
 	/* QQ connection via UDP/TCP. 
 	* Now use Purple proxy function to provide TCP proxy support,
 	* and qq_udp_proxy.c to add UDP proxy support (thanks henry) */
@@ -928,6 +1053,11 @@ void qq_disconnect(PurpleConnection *gc)
 		qd->fd = -1;
 	}
 
+	if (qd->reconnect_timeout > 0) {
+		purple_timeout_remove(qd->reconnect_timeout);
+		qd->reconnect_timeout = 0;
+	}
+
 	if (qd->connect_data != NULL) {
 		purple_debug(PURPLE_DEBUG_INFO, "QQ", "Cancel connect_data\n");
 		purple_proxy_connect_cancel(qd->connect_data);
@@ -936,6 +1066,7 @@ void qq_disconnect(PurpleConnection *gc)
 	if(qd->tcp_txbuf != NULL) {
 		purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_txbuf\n");
 		purple_circ_buffer_destroy(qd->tcp_txbuf);
+		qd->tcp_txbuf = NULL;
 	}
 	
 	if (qd->tx_handler) {
@@ -955,8 +1086,9 @@ void qq_disconnect(PurpleConnection *gc)
 		qd->udp_query_data = NULL;
 	}
 
-	purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy transactions\n");
-	qq_trans_remove_all(qd);
+	memset(qd->rcv_window, 0, sizeof(qd->rcv_window));
+	qq_rcv_trans_remove_all(qd);
+	qq_send_trans_remove_all(qd);
 	
 	if (qd->inikey) {
 		purple_debug(PURPLE_DEBUG_INFO, "QQ", "free inikey\n");
@@ -984,7 +1116,6 @@ void qq_disconnect(PurpleConnection *gc)
 		qd->my_ip = NULL;
 	}
 
-	qq_packet_remove_all(qd);
 	qq_group_packets_free(qd);
 	qq_group_free_all(qd);
 	qq_add_buddy_request_free(qd);
@@ -1023,7 +1154,7 @@ static gint encap(qq_data *qd, guint8 *b
 	bytes += qq_putdata(buf + bytes, data, data_len);
 	bytes += qq_put8(buf + bytes, QQ_PACKET_TAIL);
 
-	// set TCP packet length at begin of the packet
+	/* set TCP packet length at begin of the packet */
 	if (qd->use_tcp) {
 		qq_put16(buf, bytes);
 	}
@@ -1031,17 +1162,16 @@ static gint encap(qq_data *qd, guint8 *b
 	return bytes;
 }
 
-gint qq_send_data(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len)
+gint qq_send_data(qq_data *qd, guint16 cmd, guint8 *data, gint data_len)
 {
-	qq_data *qd;
 	guint8 *buf;
 	gint buf_len;
 	gint bytes_sent;
 	gint seq;
 
-	g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1);
-	qd = (qq_data *) gc->proto_data;
-	
+	g_return_val_if_fail(qd != NULL, -1);
+	g_return_val_if_fail(data != NULL && data_len > 0, -1);
+
 	buf = g_newa(guint8, MAX_PACKET_SIZE);
 	memset(buf, 0, MAX_PACKET_SIZE);
 	seq = ++(qd->send_seq);
@@ -1056,8 +1186,8 @@ gint qq_send_data(PurpleConnection *gc, 
 		bytes_sent = udp_send_out(qd, buf, buf_len);
 	}
 
-	// always need ack
-	qq_trans_append(qd, buf, buf_len, cmd, seq);
+	/* always need ack */
+	qq_send_trans_append(qd, buf, buf_len, cmd, seq);
 
 	if (QQ_DEBUG) {
 		qq_show_packet("QQ_SEND_DATA", buf, buf_len);
@@ -1071,31 +1201,26 @@ gint qq_send_data(PurpleConnection *gc, 
 /* send the packet generated with the given cmd and data
  * return the number of bytes sent to socket if succeeds
  * return -1 if there is any error */
-gint qq_send_cmd(PurpleConnection *gc, guint16 cmd,
-		gboolean is_auto_seq, guint16 seq, gboolean need_ack, guint8 *data, gint data_len)
+gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack,
+	guint8 *data, gint data_len)
 {
-	qq_data *qd;
 	guint8 *buf;
 	gint buf_len;
 	guint8 *encrypted_data;
 	gint encrypted_len;
-	gint real_seq;
 	gint bytes_sent;
 
-	qd = (qq_data *) gc->proto_data;
-	g_return_val_if_fail(qd->session_key != NULL, -1);
+	g_return_val_if_fail(qd != NULL && qd->session_key != NULL, -1);
+	g_return_val_if_fail(data != NULL && data_len > 0, -1);
 
 	encrypted_len = data_len + 16;	/* at most 16 bytes more */
 	encrypted_data = g_newa(guint8, encrypted_len);
 
 	qq_encrypt(data, data_len, qd->session_key, encrypted_data, &encrypted_len);
 
-	real_seq = seq;
-	if (is_auto_seq) 	real_seq = ++(qd->send_seq);
-
 	buf = g_newa(guint8, MAX_PACKET_SIZE);
 	memset(buf, 0, MAX_PACKET_SIZE);
-	buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, real_seq, encrypted_data, encrypted_len);
+	buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, encrypted_data, encrypted_len);
 	if (buf_len <= 0) {
 		return -1;
 	}
@@ -1111,14 +1236,23 @@ gint qq_send_cmd(PurpleConnection *gc, g
 	
 	/* if it does not need ACK, we send ACK manually several times */
 	if (need_ack)  {
-		qq_trans_append(qd, buf, buf_len, cmd, real_seq);
+		qq_send_trans_append(qd, buf, buf_len, cmd, seq);
 	}
 
 	if (QQ_DEBUG) {
 		qq_show_packet("QQ_SEND_CMD", buf, buf_len);
 		purple_debug(PURPLE_DEBUG_INFO, "QQ",
 				"<== [%05d], %s, total %d bytes is sent %d\n", 
-				real_seq, qq_get_cmd_desc(cmd), buf_len, bytes_sent);
+				seq, qq_get_cmd_desc(cmd), buf_len, bytes_sent);
 	}
 	return bytes_sent;
 }
+
+gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint data_len)
+{
+	g_return_val_if_fail(qd != NULL, -1);
+	g_return_val_if_fail(data != NULL && data_len > 0, -1);
+
+	qd->send_seq++;
+	return qq_send_cmd_detail(qd, cmd, qd->send_seq, TRUE, data, data_len);
+}
============================================================
--- libpurple/protocols/qq/qq_network.h	13121110b5e9ac5f28a4198374a9714c2ea9731b
+++ libpurple/protocols/qq/qq_network.h	c90f2507036e9f1dddd640837bf37d61fd08ea7a
@@ -30,13 +30,15 @@
 
 #include "qq.h"
 
-#define QQ_CONNECT_STEPS    2	/* steps in connection */
+#define QQ_CONNECT_STEPS    3	/* steps in connection */
 
 void qq_connect(PurpleAccount *account);
 void qq_disconnect(PurpleConnection *gc);
+void qq_connect_later(PurpleConnection *gc);
 
-gint qq_send_data(PurpleConnection *gc, guint16 cmd, guint8 *data, gint datalen);
-gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, gboolean is_auto_seq, guint16 seq, 
-		gboolean need_ack, guint8 *data, gint datalen);
+gint qq_send_data(qq_data *qd, guint16 cmd, guint8 *data, gint datalen);
+gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint datalen);
+gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack,
+	guint8 *data, gint data_len);
 
 #endif
============================================================
--- libpurple/protocols/qq/send_file.c	8c9ea7e61190ec46f24629c714c638f130b05a33
+++ libpurple/protocols/qq/send_file.c	d11d0018e84e3afb67be3475bd9c19ea974711ca
@@ -476,7 +476,7 @@ static void _qq_send_packet_file_request
 	bytes += qq_putdata (raw_data + bytes, (guint8 *) filelen_str, filelen_strlen);
 
 	if (packet_len == bytes)
-		qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, bytes);
+		qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes);
 	else
 		purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_request",
 			    "%d bytes expected but got %d bytes\n",
@@ -517,7 +517,7 @@ static void _qq_send_packet_file_accept(
 	info->local_real_ip = real_ip;
 
 	if (packet_len == bytes)
-		qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, bytes);
+		qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes);
 	else
 		purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_accept",
 			    "%d bytes expected but got %d bytes\n",
@@ -544,7 +544,7 @@ static void _qq_send_packet_file_notifyi
 	bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_NOTIFY, qd, TRUE);
 	bytes += qq_fill_conn_info(raw_data + bytes, info);
 	if (packet_len == bytes)
-		qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, bytes);
+		qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes);
 	else
 		purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_notify",
 			    "%d bytes expected but got %d bytes\n",
@@ -572,7 +572,7 @@ static void _qq_send_packet_file_reject 
 	bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_DENY_UDP, qd, TRUE);
 
 	if (packet_len == bytes)
-		qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, bytes);
+		qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes);
 	else
 		purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file",
 			    "%d bytes expected but got %d bytes\n",
@@ -599,7 +599,7 @@ static void _qq_send_packet_file_cancel 
 
 	if (packet_len == bytes) {
 		purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "before send cmd\n");
-		qq_send_cmd (gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, bytes);
+		qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes);
 	}
 	else
 		purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file",
@@ -938,7 +938,7 @@ static void qq_send_packet_request_key(P
 /*
 static void qq_send_packet_request_key(PurpleConnection *gc, guint8 key)
 {
-	qq_send_cmd(gc, QQ_CMD_REQUEST_KEY, TRUE, 0, TRUE, &key, 1);
+	qq_send_cmd(gc, QQ_CMD_REQUEST_KEY, &key, 1);
 }
 
 static void qq_process_recv_request_key(PurpleConnection *gc)
============================================================
--- libpurple/protocols/qq/sys_msg.c	3ef548df58374cb00964e1c6db64894fc87858ab
+++ libpurple/protocols/qq/sys_msg.c	119ebdf9d586b1690044ac4ac828225ae8d48958
@@ -120,10 +120,13 @@ static void _qq_send_packet_ack_msg_sys(
 /* Send ACK if the sys message needs an ACK */
 static void _qq_send_packet_ack_msg_sys(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq)
 {
+	qq_data *qd;
 	guint8 bar, *ack;
 	gchar *str;
 	gint ack_len, bytes;
 
+	qd = (qq_data *) gc->proto_data;
+	
 	str = g_strdup_printf("%d", from);
 	bar = 0x1e;
 	ack_len = 1 + 1 + strlen(str) + 1 + 2;
@@ -139,7 +142,7 @@ static void _qq_send_packet_ack_msg_sys(
 	g_free(str);
 
 	if (bytes == ack_len)	/* creation OK */
-		qq_send_cmd(gc, QQ_CMD_ACK_SYS_MSG, TRUE, 0, FALSE, ack, ack_len);
+		qq_send_cmd_detail(qd, QQ_CMD_ACK_SYS_MSG, 0, FALSE, ack, ack_len);
 	else
 		purple_debug(PURPLE_DEBUG_ERROR, "QQ",
 			   "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes);
============================================================
--- libpurple/protocols/qq/utils.c	5acca45660aa1851f55504bd6af49fba5b2b3cd4
+++ libpurple/protocols/qq/utils.c	6551e63eec5a6b5658004e318ffadf5c036f8fca
@@ -39,6 +39,17 @@
 
 #define QQ_NAME_FORMAT    "%d"
 
+/* These functions are used only in development phase */
+/*
+   static void _qq_show_socket(gchar *desc, gint fd) {
+   struct sockaddr_in sin;
+   socklen_t len = sizeof(sin);
+   getsockname(fd, (struct sockaddr *)&sin, &len);
+   purple_debug(PURPLE_DEBUG_INFO, desc, "%s:%d\n",
+   inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
+   }
+   */
+
 gchar *get_name_by_index_str(gchar **array, const gchar *index_str, gint amount)
 {
 	gint index;


More information about the Commits mailing list