libpurple/protocols/qq/qq_base.c

branch
openq
changeset 24341
02abffea97fe
parent 24340
36ceebf026a0
child 24343
9c695a1f475b
--- a/libpurple/protocols/qq/qq_base.c	Wed Oct 22 14:33:20 2008 +0000
+++ b/libpurple/protocols/qq/qq_base.c	Wed Oct 22 14:35:05 2008 +0000
@@ -44,64 +44,6 @@
 #define QQ_LOGIN_REPLY_OK_PACKET_LEN        139
 #define QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN  11
 
-/* for QQ 2003iii 0117, fixed value */
-/* static const guint8 login_23_51[29] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xbf, 0x14, 0x11, 0x20,
-	0x03, 0x9d, 0xb2, 0xe6, 0xb3, 0x11, 0xb7, 0x13,
-	0x95, 0x67, 0xda, 0x2c, 0x01
-}; */
-
-/* for QQ 2003iii 0304, fixed value */
-/*
-static const guint8 login_23_51[29] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x9a, 0x93, 0xfe, 0x85,
-	0xd3, 0xd9, 0x2a, 0x41, 0xc8, 0x0d, 0xff, 0xb6,
-	0x40, 0xb8, 0xac, 0x32, 0x01
-};
-*/
-
-/* for QQ 2005? copy from lumaqq */
-/* 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,
-	0x2c, 0xd3, 0x73, 0x6c, 0x14, 0xf6, 0xf6, 0xaf,
-	0xc3, 0xfa, 0x33, 0xa4, 0x01
-};
-
-static const guint8 login_53_68[16] = {
- 	0x8D, 0x8B, 0xFA, 0xEC, 0xD5, 0x52, 0x17, 0x4A,
- 	0x86, 0xF9, 0xA7, 0x75, 0xE6, 0x32, 0xD1, 0x6D
-};
-
-static const guint8 login_100_bytes[100] = {
-	0x40, 0x0B, 0x04, 0x02, 0x00, 0x01, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x01, 0xE9, 0x03, 0x01,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x03,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xED,
-	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-	0xEC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x01, 0xEE, 0x03, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x01, 0xEF, 0x03, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x01, 0xEB, 0x03, 0x00,
-	0x00, 0x00, 0x00, 0x00
-};
-
-
-/* fixed value, not affected by version, or mac address */
-/*
-static const guint8 login_53_68[16] = {
-	0x82, 0x2a, 0x91, 0xfd, 0xa5, 0xca, 0x67, 0x4c,
-	0xac, 0x81, 0x1f, 0x6f, 0x52, 0x05, 0xa7, 0xbf
-};
-*/
-
-
 /* generate a md5 key using uid and session_key */
 static void get_session_md5(guint8 *session_md5, guint32 uid, guint8 *session_key)
 {
@@ -268,9 +210,38 @@
 	qq_data *qd;
 	guint8 *buf, *raw_data;
 	gint bytes;
-	guint8 *encrypted_data;
+	guint8 *encrypted;
 	gint encrypted_len;
 
+	/* for QQ 2005? copy from lumaqq */
+	static const guint8 login_23_51[29] = {
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x86, 0xcc, 0x4c, 0x35,
+			0x2c, 0xd3, 0x73, 0x6c, 0x14, 0xf6, 0xf6, 0xaf,
+			0xc3, 0xfa, 0x33, 0xa4, 0x01
+	};
+
+	static const guint8 login_53_68[16] = {
+ 			0x8D, 0x8B, 0xFA, 0xEC, 0xD5, 0x52, 0x17, 0x4A,
+ 			0x86, 0xF9, 0xA7, 0x75, 0xE6, 0x32, 0xD1, 0x6D
+	};
+
+	static const guint8 login_100_bytes[100] = {
+		0x40, 0x0B, 0x04, 0x02, 0x00, 0x01, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x01, 0xE9, 0x03, 0x01,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x03,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xED,
+		0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+		0xEC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x01, 0xEE, 0x03, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x01, 0xEF, 0x03, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x01, 0xEB, 0x03, 0x00,
+		0x00, 0x00, 0x00, 0x00
+	};
+
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
 	qd = (qq_data *) gc->proto_data;
 
@@ -279,12 +250,12 @@
 	raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH);
 	memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH);
 
-	encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16);	/* 16 bytes more */
+	encrypted = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16);	/* 16 bytes more */
 
 	bytes = 0;
 	/* now generate the encrypted data
 	 * 000-015 use password_twice_md5 as key to encrypt empty string */
-	encrypted_len = qq_encrypt(raw_data + bytes, (guint8 *) "", 0, qd->ld.pwd_twice_md5);
+	encrypted_len = qq_encrypt(raw_data + bytes, (guint8 *) "", 0, qd->ld.pwd_2nd_md5);
 	g_return_if_fail(encrypted_len == 16);
 	bytes += encrypted_len;
 
@@ -308,13 +279,13 @@
 	bytes += qq_putdata(raw_data + bytes, login_100_bytes, 100);
 	/* all zero left */
 
-	encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key);
+	encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key);
 
 	buf = g_newa(guint8, MAX_PACKET_SIZE);
 	memset(buf, 0, MAX_PACKET_SIZE);
 	bytes = 0;
-	bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH);
-	bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len);
+	bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH);
+	bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
 
 	qd->send_seq++;
 	qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE);
@@ -327,9 +298,9 @@
 	int token_len;
 	gchar *error_msg;
 
-	g_return_val_if_fail(buf != NULL && buf_len != 0, -1);
+	g_return_val_if_fail(buf != NULL && buf_len != 0, QQ_LOGIN_REPLY_ERR);
 
-	g_return_val_if_fail(gc != NULL  && gc->proto_data != NULL, -1);
+	g_return_val_if_fail(gc != NULL  && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
 	qd = (qq_data *) gc->proto_data;
 
 	ret = buf[0];
@@ -343,7 +314,9 @@
 		if (error_msg == NULL) {
 				error_msg = g_strdup_printf( _("Invalid token reply code, 0x%02X"), ret);
 		}
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg);
+		purple_connection_error_reason(gc,
+				PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
+				error_msg);
 		g_free(error_msg);
 		return QQ_LOGIN_REPLY_ERR;
 	}
@@ -351,7 +324,9 @@
 	token_len = buf_len-2;
 	if (token_len <= 0) {
 		error_msg = g_strdup_printf( _("Invalid token len, %d"), token_len);
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg);
+		purple_connection_error_reason(gc,
+				PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
+				error_msg);
 		g_free(error_msg);
 		return QQ_LOGIN_REPLY_ERR;
 	}
@@ -383,18 +358,45 @@
 
 	qd = (qq_data *) gc->proto_data;
 	for (i = 0; i < 4; i++)
-		qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->ld.pwd_twice_md5, QQ_KEY_LENGTH);
+		qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->ld.pwd_2nd_md5, QQ_KEY_LENGTH);
 
 	qd->is_login = FALSE;	/* update login status AFTER sending logout packets */
 }
 
+/* for QQ 2003iii 0117, fixed value */
+/* static const guint8 login_23_51[29] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xbf, 0x14, 0x11, 0x20,
+	0x03, 0x9d, 0xb2, 0xe6, 0xb3, 0x11, 0xb7, 0x13,
+	0x95, 0x67, 0xda, 0x2c, 0x01
+}; */
+
+/* for QQ 2003iii 0304, fixed value */
+/*
+static const guint8 login_23_51[29] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x9a, 0x93, 0xfe, 0x85,
+	0xd3, 0xd9, 0x2a, 0x41, 0xc8, 0x0d, 0xff, 0xb6,
+	0x40, 0xb8, 0xac, 0x32, 0x01
+};
+*/
+
+/* fixed value, not affected by version, or mac address */
+/*
+static const guint8 login_53_68[16] = {
+	0x82, 0x2a, 0x91, 0xfd, 0xa5, 0xca, 0x67, 0x4c,
+	0xac, 0x81, 0x1f, 0x6f, 0x52, 0x05, 0xa7, 0xbf
+};
+*/
+
 /* process the login reply packet */
 guint8 qq_process_login( PurpleConnection *gc, guint8 *data, gint data_len)
 {
 	qq_data *qd;
 	guint8 ret = data[0];
-	gchar *server_reply, *server_reply_utf8;
-	gchar *error_msg;
+	gchar *msg, *msg_utf8;
+	gchar *error;
+	PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 
 	g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
 
@@ -408,60 +410,42 @@
 			purple_debug_info("QQ", "Redirect new server\n");
 			return process_login_redirect(gc, data, data_len);
 
-		case QQ_LOGIN_REPLY_REDIRECT_EX:
-			purple_debug_error("QQ", "Extend redirect new server, not supported yet\n");
-			error_msg = g_strdup( _("Unable login for not support Redirect_EX now") );
-			return QQ_LOGIN_REPLY_REDIRECT_EX;
-
-		case QQ_LOGIN_REPLY_ERR_PWD:
-			server_reply = g_strndup((gchar *)data + 1, data_len - 1);
-			server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT);
-
-			purple_debug_error("QQ", "Error password: %s\n", server_reply_utf8);
-			error_msg = g_strdup_printf( _("Error password: %s"), server_reply_utf8);
-
-			g_free(server_reply);
-			g_free(server_reply_utf8);
-
+		case 0x0A:		/* extend redirect used in QQ2006 */
+			error = g_strdup( _("Not support Redirect_EX now") );
+			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+			break;
+		case 0x05:		/* invalid password */
 			if (!purple_account_get_remember_password(gc->account)) {
 				purple_account_set_password(gc->account, NULL);
 			}
-
-			purple_connection_error_reason(gc,
-				PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, error_msg);
-			g_free(error_msg);
-
-			return QQ_LOGIN_REPLY_ERR_PWD;
-
-		case QQ_LOGIN_REPLY_NEED_REACTIVE:
-			server_reply = g_strndup((gchar *)data + 1, data_len - 1);
-			server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT);
-
-			purple_debug_error("QQ", "Need active: %s\n", server_reply_utf8);
-			error_msg = g_strdup_printf( _("Need active: %s"), server_reply_utf8);
-
-			g_free(server_reply);
-			g_free(server_reply_utf8);
+			error = g_strdup( _("Error password"));
+			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+			break;
+		case 0x06:		/* need activation */
+			error = g_strdup( _("Need active"));
+			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 			break;
 
 		default:
-			purple_debug_error("QQ",
-				"Unable login for unknow reply code 0x%02X\n", data[0]);
-			qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
-				data, data_len,
-				">>> [default] decrypt and dump");
-			error_msg = try_dump_as_gbk(data, data_len);
-			if (error_msg == NULL) {
-				error_msg = g_strdup_printf(
-					_("Unable login for unknow reply code 0x%02X"), data[0] );
-			}
+			qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
+					">>> [default] decrypt and dump");
+			error = g_strdup_printf(
+						_("Unknow reply code when checking password (0x%02X)"),
+						ret );
+			reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
 			break;
 	}
 
-	purple_connection_error_reason(gc,
-		PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg);
-	g_free(error_msg);
-	return ret;
+	msg = g_strndup((gchar *)data + 1, data_len - 1);
+	msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
+
+	purple_debug_error("QQ", "%s: %s\n", error, msg_utf8);
+	purple_connection_error_reason(gc, reason, msg_utf8);
+
+	g_free(error);
+	g_free(msg);
+	g_free(msg_utf8);
+	return QQ_LOGIN_REPLY_ERR;
 }
 
 /* send keep-alive packet to QQ server (it is a heart-beat) */
@@ -500,7 +484,8 @@
 	/* segments[0] and segment[1] are all 0x30 ("0") */
 	qd->online_total = strtol(segments[2], NULL, 10);
 	if(0 == qd->online_total) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+		purple_connection_error_reason(gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 				_("Keep alive error"));
 	}
 	qd->my_ip.s_addr = inet_addr(segments[3]);
@@ -519,7 +504,7 @@
 	qq_data *qd;
 	guint8 *buf, *raw_data;
 	gint bytes;
-	guint8 *encrypted_data;
+	guint8 *encrypted;
 	gint encrypted_len;
 
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
@@ -528,44 +513,35 @@
 	raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH);
 	memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH);
 
-	encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16);	/* 16 bytes more */
+	encrypted = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16);	/* 16 bytes more */
 
 	bytes = 0;
 	bytes += qq_putdata(raw_data + bytes, (guint8 *)&qd->redirect_data, sizeof(qd->redirect_data));
 
-	encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key);
+	encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key);
 
 	buf = g_newa(guint8, MAX_PACKET_SIZE);
 	memset(buf, 0, MAX_PACKET_SIZE);
 	bytes = 0;
-	bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH);
-	bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len);
+	bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH);
+	bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
 
 	qd->send_seq++;
 	qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE);
 }
 
-guint16 qq_process_get_server(PurpleConnection *gc, guint8 *rcved, gint rcved_len)
+guint16 qq_process_get_server(PurpleConnection *gc, guint8 *data, gint data_len)
 {
 	qq_data *qd;
-	guint8 *data;
-	gint data_len;
 	qq_redirect_data *redirect;
 
 	g_return_val_if_fail (gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
 	qd = (qq_data *) gc->proto_data;
 
-	data = g_newa(guint8, rcved_len);
-	/* May use password_twice_md5 in the past version like QQ2005*/
-	data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.init_key);
-	if (data_len < 0) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Can not decrypt get server reply"));
-		return QQ_LOGIN_REPLY_ERR;
-	}
-
+	g_return_val_if_fail (data != NULL, QQ_LOGIN_REPLY_ERR);
 	if (data_len < sizeof(qq_redirect_data)) {
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+		purple_connection_error_reason(gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 				_("Can not decrypt get server reply"));
 		return QQ_LOGIN_REPLY_ERR;
 	}
@@ -587,7 +563,7 @@
 	qq_data *qd;
 	guint8 *buf, *raw_data;
 	gint bytes;
-	guint8 *encrypted_data;
+	guint8 *encrypted;
 	gint encrypted_len;
 
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
@@ -598,7 +574,7 @@
 	raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16);
 	memset(raw_data, 0, MAX_PACKET_SIZE - 16);
 
-	encrypted_data = g_newa(guint8, MAX_PACKET_SIZE);	/* 16 bytes more */
+	encrypted = g_newa(guint8, MAX_PACKET_SIZE);	/* 16 bytes more */
 
 	bytes = 0;
 	bytes += qq_put8(raw_data + bytes, qd->ld.token_len);
@@ -609,13 +585,13 @@
 	bytes += qq_put8(raw_data + bytes, 0); 		/* fragment index */
 	bytes += qq_put16(raw_data + bytes, 0); 	/* captcha token */
 
-	encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key);
+	encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key);
 
 	buf = g_newa(guint8, MAX_PACKET_SIZE);
 	memset(buf, 0, MAX_PACKET_SIZE);
 	bytes = 0;
-	bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH);
-	bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len);
+	bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH);
+	bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
 
 	qd->send_seq++;
 	qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
@@ -626,7 +602,7 @@
 	qq_data *qd;
 	guint8 *buf, *raw_data;
 	gint bytes;
-	guint8 *encrypted_data;
+	guint8 *encrypted;
 	gint encrypted_len;
 
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
@@ -637,7 +613,7 @@
 	raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16);
 	memset(raw_data, 0, MAX_PACKET_SIZE - 16);
 
-	encrypted_data = g_newa(guint8, MAX_PACKET_SIZE);	/* 16 bytes more */
+	encrypted = g_newa(guint8, MAX_PACKET_SIZE);	/* 16 bytes more */
 
 	bytes = 0;
 	bytes += qq_put8(raw_data + bytes, qd->ld.token_len);
@@ -649,13 +625,13 @@
 	bytes += qq_put16(raw_data + bytes, qd->captcha.token_len); 	/* captcha token */
 	bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len);
 
-	encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key);
+	encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key);
 
 	buf = g_newa(guint8, MAX_PACKET_SIZE);
 	memset(buf, 0, MAX_PACKET_SIZE);
 	bytes = 0;
-	bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH);
-	bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len);
+	bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH);
+	bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
 
 	qd->send_seq++;
 	qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
@@ -669,7 +645,7 @@
 	qq_data *qd;
 	guint8 *buf, *raw_data;
 	gint bytes;
-	guint8 *encrypted_data;
+	guint8 *encrypted;
 	gint encrypted_len;
 
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
@@ -681,7 +657,7 @@
 	raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16);
 	memset(raw_data, 0, MAX_PACKET_SIZE - 16);
 
-	encrypted_data = g_newa(guint8, MAX_PACKET_SIZE);	/* 16 bytes more */
+	encrypted = g_newa(guint8, MAX_PACKET_SIZE);	/* 16 bytes more */
 
 	bytes = 0;
 	bytes += qq_put8(raw_data + bytes, qd->ld.token_len);
@@ -694,13 +670,13 @@
 	bytes += qq_put16(raw_data + bytes, qd->captcha.token_len); 	/* captcha token */
 	bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len);
 
-	encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key);
+	encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key);
 
 	buf = g_newa(guint8, MAX_PACKET_SIZE);
 	memset(buf, 0, MAX_PACKET_SIZE);
 	bytes = 0;
-	bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH);
-	bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len);
+	bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH);
+	bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
 
 	qd->send_seq++;
 	qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
@@ -797,7 +773,7 @@
 		captcha_req);
 }
 
-guint8 qq_process_token_ex(PurpleConnection *gc, guint8 *buf, gint buf_len)
+guint8 qq_process_token_ex(PurpleConnection *gc, guint8 *data, gint data_len)
 {
 	qq_data *qd;
 	int bytes;
@@ -807,41 +783,41 @@
 	guint16 captcha_len;
 	guint8 curr_index;
 
-	g_return_val_if_fail(buf != NULL && buf_len != 0, -1);
+	g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
 
-	g_return_val_if_fail(gc != NULL  && gc->proto_data != NULL, -1);
+	g_return_val_if_fail(gc != NULL  && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
 	qd = (qq_data *) gc->proto_data;
 
-	ret = buf[0];
+	ret = data[0];
 
 	bytes = 0;
-	bytes += qq_get8(&sub_cmd, buf + bytes);
+	bytes += qq_get8(&sub_cmd, data + bytes);
 	bytes += 2;
-	bytes += qq_get8(&reply, buf + bytes);
+	bytes += qq_get8(&reply, data + bytes);
 
-	bytes += qq_get16(&(qd->ld.token_ex_len), buf + bytes);
+	bytes += qq_get16(&(qd->ld.token_ex_len), data + bytes);
 	if (qd->ld.token_ex != NULL)	g_free(qd->ld.token_ex);
 	qd->ld.token_ex = g_new0(guint8, qd->ld.token_ex_len);
-	bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len , buf + bytes);
+	bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len , data + bytes);
 
 	if(reply != 1)
 	{
-		purple_debug_info("QQ", "All captchaes is verified\n");
+		purple_debug_info("QQ", "Captcha verified\n");
 		return QQ_LOGIN_REPLY_OK;
 	}
 
-	bytes += qq_get16(&captcha_len, buf + bytes);
+	bytes += qq_get16(&captcha_len, data + bytes);
 
 	qd->captcha.data = g_realloc(qd->captcha.data, qd->captcha.data_len + captcha_len);
-	bytes += qq_getdata(qd->captcha.data + qd->captcha.data_len, captcha_len, buf + bytes);
+	bytes += qq_getdata(qd->captcha.data + qd->captcha.data_len, captcha_len, data + bytes);
 	qd->captcha.data_len += captcha_len;
 
-	bytes += qq_get8(&curr_index, buf + bytes);
-	bytes += qq_get8(&qd->captcha.next_index, buf + bytes);
+	bytes += qq_get8(&curr_index, data + bytes);
+	bytes += qq_get8(&qd->captcha.next_index, data + bytes);
 
-	bytes += qq_get16(&qd->captcha.token_len, buf + bytes);
+	bytes += qq_get16(&qd->captcha.token_len, data + bytes);
 	qd->captcha.token = g_new0(guint8, qd->captcha.token_len);
-	bytes += qq_getdata(qd->captcha.token, qd->captcha.token_len, buf + bytes);
+	bytes += qq_getdata(qd->captcha.token, qd->captcha.token_len, data + bytes);
 
 	if(qd->captcha.next_index > 0)
 	{
@@ -850,3 +826,425 @@
 
 	return QQ_LOGIN_REPLY_CAPTCHA_DLG;
 }
+
+/* source copy from gg's common.c */
+static guint32 crc32_table[256];
+static int crc32_initialized = 0;
+
+static void crc32_make_table()
+{
+	guint32 h = 1;
+	unsigned int i, j;
+
+	memset(crc32_table, 0, sizeof(crc32_table));
+
+	for (i = 128; i; i >>= 1) {
+		h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
+
+		for (j = 0; j < 256; j += 2 * i)
+			crc32_table[i + j] = crc32_table[j] ^ h;
+	}
+
+	crc32_initialized = 1;
+}
+
+static guint32 crc32(guint32 crc, const guint8 *buf, int len)
+{
+	if (!crc32_initialized)
+		crc32_make_table();
+
+	if (!buf || len < 0)
+		return crc;
+
+	crc ^= 0xffffffffL;
+
+	while (len--)
+		crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
+
+	return crc ^ 0xffffffffL;
+}
+
+void qq_request_check_pwd_2007(PurpleConnection *gc)
+{
+	qq_data *qd;
+	guint8 *buf, *raw_data;
+	gint bytes;
+	guint8 *encrypted;
+	gint encrypted_len;
+	static guint8 header[] = { 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0x0E };
+
+	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+	qd = (qq_data *) gc->proto_data;
+
+	g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0);
+
+	raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16);
+	memset(raw_data, 0, MAX_PACKET_SIZE - 16);
+
+	encrypted = g_newa(guint8, MAX_PACKET_SIZE);	/* 16 bytes more */
+
+	/* Encrypted password and put in encrypted */
+	bytes = 0;
+	bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5));
+	bytes += qq_put16(raw_data + bytes, 0);
+	bytes += qq_put16(raw_data + bytes, 0);
+
+	encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5);
+
+	/* create packet */
+	bytes = 0;
+	bytes += qq_putdata(raw_data + bytes, header, sizeof(header));
+	/* token get from qq_request_token_ex */
+	bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len);
+	bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len);
+	/* password encrypted */
+	bytes += qq_put16(raw_data + bytes, encrypted_len);
+	bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len);
+	/* some random data */
+	bytes += qq_put16(raw_data + bytes, 0x0014);
+	bytes += qq_put32(raw_data + bytes, rand() & 0xffff);
+	bytes += qq_put32(raw_data + bytes, rand() & 0xffff);
+	bytes += qq_put32(raw_data + bytes, rand() & 0xffff);
+	bytes += qq_put32(raw_data + bytes, rand() & 0xffff);
+	bytes += qq_put32(raw_data + bytes, rand() & 0xffff);
+	/* put length into first 2 bytes */
+	qq_put16(raw_data, bytes - 2);
+	/* tail */
+	bytes += qq_put8(raw_data + bytes, 0);
+	bytes += qq_put8(raw_data + bytes, 0x03);
+	bytes += qq_put8(raw_data + bytes, 0);
+	bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[1]);
+	bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[2]);
+
+	/* Encrypted by random key*/
+	encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key);
+
+	buf = g_newa(guint8, MAX_PACKET_SIZE);
+	memset(buf, 0, MAX_PACKET_SIZE);
+	bytes = 0;
+	bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH);
+	bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
+
+	qd->send_seq++;
+	qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE);
+}
+
+guint8 qq_process_check_pwd_2007( PurpleConnection *gc, guint8 *data, gint data_len)
+{
+	qq_data *qd;
+	int bytes;
+	guint8 ret;
+	guint16 unknown_len;
+	gchar *error = NULL;
+	gchar *msg, *msg_utf8;
+	guint16 msg_len;
+	PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+
+	g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
+
+	g_return_val_if_fail(gc != NULL  && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
+	qd = (qq_data *) gc->proto_data;
+
+	bytes = 2;	// skip 2 bytes
+	bytes += qq_get8(&ret, data + bytes);
+	bytes += 4;  // skip 4 bytes
+	/* 2 unknow */
+	bytes += qq_get16(&unknown_len, data + bytes);
+	bytes += unknown_len;
+	bytes += qq_get16(&unknown_len, data + bytes);
+	bytes += unknown_len;
+	if (ret == QQ_LOGIN_REPLY_OK) {
+		/* get login_token */
+		bytes += qq_get16(&qd->ld.login_token_len, data + bytes);
+		if (qd->ld.login_token != NULL) g_free(qd->ld.login_token);
+		qd->ld.login_token = g_new0(guint8, qd->ld.login_token_len);
+		bytes += qq_getdata(qd->ld.login_token, qd->ld.login_token_len, data + bytes);
+		/* get login_key */
+		bytes += qq_getdata(qd->ld.login_key, sizeof(qd->ld.login_key), data + bytes);
+		return QQ_LOGIN_REPLY_OK;
+	}
+
+	switch (ret)
+	{
+		case 0x34:		/* invalid password */
+			if (!purple_account_get_remember_password(gc->account)) {
+				purple_account_set_password(gc->account, NULL);
+			}
+			error = g_strdup(_("Error password"));
+			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+			break;
+		case 0x33:		/* need activation */
+		case 0x51:		/* need activation */
+			error = g_strdup(_("Need active"));
+			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+			break;
+		case 0xBF:		/* uid is not exist */
+			error = g_strdup(_("invalid user name"));
+			reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
+			break;
+		default:
+			qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
+					">>> [default] decrypt and dump");
+			error = g_strdup_printf(
+						_("Unknow reply code when checking password (0x%02X)"),
+						ret );
+			reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+			break;
+	}
+	qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
+			">>> [default] decrypt and dump");
+	bytes = 1;
+	bytes += qq_get16(&msg_len, data + bytes);
+
+	msg = g_strndup((gchar *)data + bytes, msg_len);
+	msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
+
+	purple_debug_error("QQ", "%s: %s\n", error, msg_utf8);
+	purple_connection_error_reason(gc, reason, msg_utf8);
+
+	g_free(error);
+	g_free(msg);
+	g_free(msg_utf8);
+	return QQ_LOGIN_REPLY_ERR;
+}
+
+guint8 qq_process_check_pwd_2008( PurpleConnection *gc, guint8 *data, gint data_len)
+{
+	qq_data *qd;
+	int bytes;
+	guint8 ret;
+	gchar *error = NULL;
+	gchar *msg, *msg_utf8;
+	guint16 msg_len;
+	PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+
+	g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
+
+	g_return_val_if_fail(gc != NULL  && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
+	qd = (qq_data *) gc->proto_data;
+
+	bytes = 1;	// skip 1 bytes, always 0
+	bytes += qq_get8(&ret, data + bytes);
+	if (ret == 0x97) {
+		/* get login_token */
+		bytes += qq_get16(&qd->ld.login_token_len, data);
+		if (qd->ld.login_token != NULL) g_free(qd->ld.login_token);
+		qd->ld.login_token = g_new0(guint8, qd->ld.login_token_len);
+		bytes += qq_getdata(qd->ld.login_token, qd->ld.login_token_len, data + bytes);
+		/* get login_key */
+		bytes += qq_getdata(qd->ld.login_key, sizeof(qd->ld.login_key), data + bytes);
+		return QQ_LOGIN_REPLY_OK;
+	}
+
+	switch (ret)
+	{
+		case 0xc6:		/* invalid password */
+			if (!purple_account_get_remember_password(gc->account)) {
+				purple_account_set_password(gc->account, NULL);
+			}
+			error = g_strdup(_("Error password"));
+			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+			break;
+		case 0x33:		/* need activation */
+		case 0x51:		/* need activation */
+			error = g_strdup(_("Need active"));
+			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
+			break;
+		case 0xBF:		/* uid is not exist */
+			error = g_strdup(_("invalid user name"));
+			reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME;
+			break;
+		default:
+			qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
+					">>> [default] decrypt and dump");
+			error = g_strdup_printf(
+						_("Unknow reply code when checking password (0x%02X)"),
+						ret );
+			reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
+			break;
+	}
+
+	bytes = 11;
+	bytes += qq_get16(&msg_len, data + bytes);
+
+	msg = g_strndup((gchar *)data + bytes, msg_len);
+	msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
+
+	purple_debug_error("QQ", "%s: %s\n", error, msg_utf8);
+	purple_connection_error_reason(gc, reason, msg_utf8);
+
+	g_free(error);
+	g_free(msg);
+	g_free(msg_utf8);
+	return QQ_LOGIN_REPLY_ERR;
+}
+
+void qq_request_check_pwd_2008(PurpleConnection *gc)
+{
+	qq_data *qd;
+	guint8 *buf, *raw_data;
+	gint bytes;
+	guint8 *encrypted;
+	gint encrypted_len;
+	static guint8 header[] = { 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0xE0 };
+	static guint8 unknown[] = { 0xDB, 0xB9, 0xF3, 0x0B, 0xF9, 0x13, 0x87, 0xB2,
+		0xE6, 0x20, 0x43, 0xBE, 0x53, 0xCA, 0x65, 0x03 };
+
+	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+	qd = (qq_data *) gc->proto_data;
+
+	g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0);
+
+	raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16);
+	memset(raw_data, 0, MAX_PACKET_SIZE - 16);
+
+	encrypted = g_newa(guint8, MAX_PACKET_SIZE);	/* 16 bytes more */
+
+	/* Encrypted password and put in encrypted */
+	bytes = 0;
+	bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5));
+	bytes += qq_put16(raw_data + bytes, 0);
+	bytes += qq_put16(raw_data + bytes, (guint16) (rand() & 0xffff));
+
+	encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5);
+
+	/* create packet */
+	bytes = 0;
+	bytes += qq_putdata(raw_data + bytes, header, sizeof(header));
+	/* token get from qq_request_token_ex */
+	bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len);
+	bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len);
+	bytes += qq_put8(raw_data + bytes, 0);
+	/* password encrypted */
+	bytes += qq_put16(raw_data + bytes, encrypted_len);
+	bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len);
+	bytes += qq_put8(raw_data + bytes, 0);
+	/* len of unknown + len of CRC32 */
+	bytes += qq_put8(raw_data + bytes, sizeof(unknown) + 4);
+	bytes += qq_putdata(raw_data + bytes, unknown, sizeof(unknown));
+	bytes += qq_put32(
+			raw_data + bytes, crc32(0xFFFFFFFF, unknown, sizeof(unknown)));
+	/* put length into first 2 bytes */
+	qq_put16(raw_data, bytes - 2);
+	/* tail */
+	bytes += qq_put8(raw_data + bytes, 0);
+	bytes += qq_put8(raw_data + bytes, 0x03);
+	bytes += qq_put8(raw_data + bytes, 0);
+	bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[1]);
+	bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[2]);
+
+	/* Encrypted by random key*/
+	encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key);
+
+	buf = g_newa(guint8, MAX_PACKET_SIZE);
+	memset(buf, 0, MAX_PACKET_SIZE);
+	bytes = 0;
+	bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH);
+	bytes += qq_putdata(buf + bytes, encrypted, encrypted_len);
+
+	qd->send_seq++;
+	qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE);
+}
+
+/*
+static void qq_send_packet_login2007(PurpleConnection *gc)
+{
+	qq_data *qd;
+	guint8 *buf, *cursor, *cursor_verify_data;
+	guint16 seq_ret;
+	gint encrypted_len, bytes;
+	gint pos, bodyOffset, encrypted_data_bytes, tail_offset, body_length, temp_pos;
+	guint8 verifyData[QQ_LOGIN_DATA_LENGTH], raw_data[QQ_LOGIN_ENCRYPT_BUFFER], encrypted_data[QQ_LOGIN_DATA_LENGTH];
+	
+	memset(raw_data, 0, QQ_LOGIN_ENCRYPT_BUFFER);
+	memset(verifyData, 0, QQ_LOGIN_DATA_LENGTH);
+	memset(encrypted_data, 0, QQ_LOGIN_DATA_LENGTH);
+	qd = (qq_data *) gc->proto_data;
+	buf = g_newa(guint8, MAX_PACKET_SIZE);
+	
+	cursor = buf;
+	bytes = 0;
+	bytes += _create_packet_head_seq(buf, &cursor, gc, QQ_CMD_LOGIN, TRUE, &seq_ret);
+	bytes += create_packet_dw(buf, &cursor, qd->uid);
+
+	bodyOffset = bytes;
+
+	bytes += create_packet_w(buf, &cursor, qd->passport_key_lenght);
+	bytes += create_packet_data(buf, &cursor, qd->passport_key, qd->passport_key_lenght);
+	bytes += create_packet_w(buf, &cursor, 0);
+	pos = bytes;
+	bytes += 2;
+	cursor += 2;
+
+	encrypted_data_bytes = 0;
+	cursor_verify_data = verifyData;
+	encrypted_data_bytes += create_packet_data(verifyData, &cursor_verify_data, qd->pwkey, QQ_KEY_LENGTH);
+	encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 0);
+	encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 0);
+	encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 255);
+	encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 255);
+//	encrypted_data_bytes += create_packet_w(verifyData, &cursor_verify_data, 0);
+	
+	qq_encrypt(verifyData, encrypted_data_bytes, qd->pwkey_double, encrypted_data, &encrypted_len);
+	bytes += create_packet_data(buf, &cursor, encrypted_data, encrypted_len);
+	
+	temp_pos = bytes;
+	bytes = pos;
+	cursor = buf+bytes;
+	bytes += create_packet_w(buf, &cursor, encrypted_len);
+	bytes = temp_pos;
+	cursor = buf+bytes;
+	
+	qq_encrypt((guint8 *) "", 0, qd->pwkey_double, raw_data, &encrypted_len);
+	bytes += create_packet_data(buf, &cursor, raw_data, encrypted_len);
+	
+	g_memmove(buf+bytes, kQQFixedContent1_35, 35);
+	bytes += 35;
+	cursor = buf+bytes;
+	
+	bytes += create_packet_b(buf, &cursor, g_random_int_range (0,255));
+	bytes += create_packet_b(buf, &cursor, qd->login_mode);
+	
+	bytes += create_packet_dw(buf, &cursor, 0);
+	bytes += create_packet_dw(buf, &cursor, 0);
+	bytes += create_packet_w(buf, &cursor, 0);
+	
+	bytes += create_packet_data(buf, &cursor, qd->selected_server, qd->selected_server_lenght);
+	
+	g_memmove(buf+bytes, kQQFixedContent2_16, 16);
+	bytes += 16;
+	cursor = buf+bytes;
+	
+	bytes += create_packet_b(buf, &cursor, qd->login_token_lenght);
+	bytes += create_packet_data(buf, &cursor, qd->login_token, qd->login_token_lenght);
+
+	g_memmove(buf+bytes, kQQFixedContent3_332, 332);
+	bytes += 332;
+	cursor = buf+bytes;
+	
+	tail_offset = bytes;
+	body_length = tail_offset - bodyOffset;
+
+	memset(raw_data, 0, QQ_LOGIN_ENCRYPT_BUFFER);
+	encrypted_len = body_length;
+//	qq_encrypt(buf+passport_length+2+11, body_length-passport_length-2 , qd->pwkey, raw_data, &encrypted_len);
+	qq_encrypt(buf+qd->passport_key_lenght+2+11, body_length-qd->passport_key_lenght-2 , qd->login_key, raw_data, &encrypted_len);
+	bytes = qd->passport_key_lenght+2+11;
+	cursor = buf+bytes;
+	bytes += create_packet_data(buf, &cursor, raw_data, encrypted_len);
+	bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL);
+
+	if (bytes == (cursor - buf))	// packet creation OK
+		_qq_send_packet(gc, buf, bytes, QQ_CMD_LOGIN);
+	else
+		purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create login packet\n");
+	
+}
+ */
+void qq_request_login_2007(PurpleConnection *gc)
+{
+}
+
+void qq_request_login_2008(PurpleConnection *gc)
+{
+}

mercurial