pidgin.openq: a1204255: 2009.10.02 - ccpaging <ccpaging(at)gmail...

csyfek at gmail.com csyfek at gmail.com
Wed Oct 22 12:12:18 EDT 2008


-----------------------------------------------------------------
Revision: a1204255da7539e4db8d86fa00d0a532afc0c07a
Ancestor: 2fa69c961d2404c06ff3f8307112ef5095995530
Author: csyfek at gmail.com
Date: 2008-10-22T14:43:46
Branch: im.pidgin.pidgin.openq
URL: http://d.pidgin.im/viewmtn/revision/info/a1204255da7539e4db8d86fa00d0a532afc0c07a

Modified files:
        libpurple/protocols/qq/ChangeLog
        libpurple/protocols/qq/buddy_list.c
        libpurple/protocols/qq/buddy_list.h
        libpurple/protocols/qq/char_conv.c
        libpurple/protocols/qq/char_conv.h
        libpurple/protocols/qq/group_im.c
        libpurple/protocols/qq/im.c
        libpurple/protocols/qq/packet_parse.c
        libpurple/protocols/qq/packet_parse.h
        libpurple/protocols/qq/qq.c libpurple/protocols/qq/qq_base.c
        libpurple/protocols/qq/qq_base.h
        libpurple/protocols/qq/qq_network.c
        libpurple/protocols/qq/qq_network.h
        libpurple/protocols/qq/qq_process.c
        libpurple/protocols/qq/send_file.c

ChangeLog: 

2009.10.02 - ccpaging <ccpaging(at)gmail.com>
	* Added 'Captcha Display' function
	* Most functions from patch written by Emil Alexiev merged into trunk,
except 'buddy operations'
	* 'online buddy status' and 'qun buddies' still have problems

-------------- next part --------------
============================================================
--- libpurple/protocols/qq/ChangeLog	b29ecb8e886615ccbb95b04f60c3075e96e8eb3b
+++ libpurple/protocols/qq/ChangeLog	b91d6b9d72b981dbce3bf88d025525bd76f55945
@@ -1,3 +1,8 @@
+2009.10.02 - ccpaging <ccpaging(at)gmail.com>
+	* Added 'Captcha Display' function
+	* Most functions from patch written by Emil Alexiev merged into trunk, except 'buddy operations'
+	* 'online buddy status' and 'qun buddies' still have problems
+
 2008.09.30 - ccpaging <ccpaging(at)gmail.com>
 	* Successfully login using 2007/2008 protocols
 
============================================================
--- libpurple/protocols/qq/buddy_list.c	ced41b6fcd418107900307abbb3c333e2cfa689a
+++ libpurple/protocols/qq/buddy_list.c	4ffdca36498c9dbd077a24972759cd52a933d465
@@ -84,9 +84,12 @@ void qq_request_get_buddies_list(PurpleC
  * server may return a position tag if list is too long for one packet */
 void qq_request_get_buddies_list(PurpleConnection *gc, guint16 position, gint update_class)
 {
+	qq_data *qd;
 	guint8 raw_data[16] = {0};
 	gint bytes = 0;
 
+	qd = (qq_data *) gc->proto_data;
+
 	/* 000-001 starting position, can manually specify */
 	bytes += qq_put16(raw_data + bytes, position);
 	/* before Mar 18, 2004, any value can work, and we sent 00
@@ -95,7 +98,10 @@ void qq_request_get_buddies_list(PurpleC
 	 * Now I tested that 00,00,00,00,00,01 work perfectly
 	 * March 22, found the 00,00,00 starts to work as well */
 	bytes += qq_put8(raw_data + bytes, 0x00);
-
+	if (qd->client_version >= 2007) {
+		bytes += qq_put16(raw_data + bytes, 0x0000);
+	}
+	
 	qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_LIST, raw_data, bytes, update_class, 0);
 }
 
@@ -177,7 +183,7 @@ guint8 qq_process_get_buddies_online_rep
 	count = 0;
 	while (bytes < data_len) {
 		if (data_len - bytes < QQ_ONLINE_BUDDY_ENTRY_LEN) {
-			purple_debug_error("QQ", "[buddies online] only %d, need %d",
+			purple_debug_error("QQ", "[buddies online] only %d, need %d\n",
 					(data_len - bytes), QQ_ONLINE_BUDDY_ENTRY_LEN);
 			break;
 		}
@@ -292,11 +298,18 @@ guint16 qq_process_get_buddies_list_repl
 		bytes += pascal_len;
 		qq_filter_str(q_bud->nickname);
 
+		/* Fixme: merge following as 32bit flag */
 		bytes += qq_get16(&unknown, data + bytes);
 		bytes += qq_get8(&q_bud->ext_flag, data + bytes);
 		bytes += qq_get8(&q_bud->comm_flag, data + bytes);
+		
+		if (qd->client_version >= 2007) {
+			bytes += 4;		/* skip 4 bytes */
+			bytes_expected = 16 + pascal_len;
+		} else {
+			bytes_expected = 12 + pascal_len;
+		}
 
-		bytes_expected = 12 + pascal_len;
 
 		if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) {
 			purple_debug_info("QQ",
@@ -390,6 +403,10 @@ guint32 qq_process_get_buddies_and_rooms
 				purple_debug_info("QQ",
 					"Not find room id %d in qq_process_get_buddies_and_rooms\n", uid);
 				qq_set_pending_id(&qd->adding_groups_from_server, uid, TRUE);
+				//group = g_newa(qq_group, 1);
+				//group->id = uid;
+				qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, uid, NULL, 0,
+						0, 0);
 			} else {
 				group->my_role = QQ_ROOM_ROLE_YES;
 				qq_group_refresh(gc, group);
@@ -421,6 +438,7 @@ gboolean is_online(guint8 status)
 		case QQ_BUDDY_ONLINE_NORMAL:
 		case QQ_BUDDY_ONLINE_AWAY:
 		case QQ_BUDDY_ONLINE_INVISIBLE:
+		case QQ_BUDDY_ONLINE_BUSY:
 			return TRUE;
 		case QQ_BUDDY_CHANGE_TO_OFFLINE:
 			return FALSE;
@@ -469,6 +487,13 @@ void qq_request_change_status(PurpleConn
 
 	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) {
 		away_cmd = QQ_BUDDY_ONLINE_INVISIBLE;
+	} else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE))
+	{
+		if (qd->client_version >= 2007) {
+			away_cmd = QQ_BUDDY_ONLINE_BUSY;
+		} else {
+			away_cmd = QQ_BUDDY_ONLINE_INVISIBLE;
+		}
 	} else if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY)
 			|| purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_EXTENDED_AWAY)
 			|| purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_UNAVAILABLE)) {
@@ -476,13 +501,13 @@ void qq_request_change_status(PurpleConn
 	} else {
 		away_cmd = QQ_BUDDY_ONLINE_NORMAL;
 	}
-
+	
 	misc_status = 0x00000000;
 	fake_video = purple_prefs_get_bool("/plugins/prpl/qq/show_fake_video");
 	if (fake_video)
 		misc_status |= QQ_MISC_STATUS_HAVING_VIIDEO;
 
-	if (qd->client_version > 2005) {
+	if (qd->client_version >= 2007) {
 		bytes = 0;
 		bytes += qq_put8(raw_data + bytes, away_cmd);
 		/* status version */
@@ -625,6 +650,9 @@ void qq_update_buddy_contact(PurpleConne
 	case QQ_BUDDY_ONLINE_INVISIBLE:
 		status_id = "invisible";
 		break;
+	case QQ_BUDDY_ONLINE_BUSY:
+		status_id = "busy";
+		break;
 	default:
 		status_id = "invisible";
 		purple_debug_error("QQ", "unknown status: %x\n", q_bud->status);
============================================================
--- libpurple/protocols/qq/buddy_list.h	e163ac3f29e44454cf0cdf5f5b6af2fd4a0f3848
+++ libpurple/protocols/qq/buddy_list.h	f8beb3b9d675b30c9128e7acf8aff396b411bd64
@@ -45,7 +45,8 @@ enum {
 	QQ_BUDDY_ONLINE_NORMAL = 10,
 	QQ_BUDDY_CHANGE_TO_OFFLINE = 20,
 	QQ_BUDDY_ONLINE_AWAY = 30,
-	QQ_BUDDY_ONLINE_INVISIBLE = 40
+	QQ_BUDDY_ONLINE_INVISIBLE = 40,
+	QQ_BUDDY_ONLINE_BUSY = 50,
 };
 
 void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, gint update_class);
============================================================
--- libpurple/protocols/qq/char_conv.c	eee3c39ca1bb92e50e3b9092341ffce8d4071f19
+++ libpurple/protocols/qq/char_conv.c	401be250c456459219f5a293203ca59c1d2972f9
@@ -141,7 +141,7 @@ gint convert_as_pascal_string(guint8 *da
 }
 
 /* convert QQ formatted msg to Purple formatted msg (and UTF-8) */
-gchar *qq_encode_to_purple(guint8 *data, gint len, const gchar *msg)
+gchar *qq_encode_to_purple(guint8 *data, gint len, const gchar *msg, const gint client_version)
 {
 	GString *encoded;
 	guint8 font_attr, font_size, color[3], bar;
@@ -153,6 +153,9 @@ gchar *qq_encode_to_purple(guint8 *data,
 	/* checked qq_show_packet OK */
 	/* qq_show_packet("QQ_MESG recv for font style", data, len); */
 
+	if (client_version >= 2007) {
+		bytes += 1;
+	}
 	bytes += qq_get8(&font_attr, data + bytes);
 	bytes += qq_getdata(color, 3, data + bytes);	/* red,green,blue */
 	color_code = g_strdup_printf("#%02x%02x%02x", color[0], color[1], color[2]);
@@ -232,8 +235,10 @@ gchar *qq_smiley_to_purple(gchar *text)
 
 	converted = g_string_new("");
 	segments = split_data((guint8 *) text, strlen(text), "\x14\x15", 0);
-	g_string_append(converted, segments[0]);
+	if(segments == NULL)
+		return NULL;
 
+	g_string_append(converted, segments[0]);
 	while ((*(++segments)) != NULL) {
 		cur_seg = *segments;
 		qq_smiley = cur_seg[0];
============================================================
--- libpurple/protocols/qq/char_conv.h	c982dd5edde48bc1ff655d59a9c762b9fd162fde
+++ libpurple/protocols/qq/char_conv.h	207f24991e06d598d52cffeecc87516e00ab9a03
@@ -37,7 +37,7 @@ gchar *qq_to_utf8(const gchar *str, cons
 
 gchar *utf8_to_qq(const gchar *str, const gchar *to_charset);
 gchar *qq_to_utf8(const gchar *str, const gchar *from_charset);
-gchar *qq_encode_to_purple(guint8 *font_attr_data, gint len, const gchar *msg);
+gchar *qq_encode_to_purple(guint8 *font_attr_data, gint len, const gchar *msg, const gint client_version);
 
 gchar *qq_im_filter_html(const gchar *text);
 void qq_filter_str(gchar *str);
============================================================
--- libpurple/protocols/qq/group_im.c	61e16cd31f54b9f0b254330ccc744d9c94e6a8f9
+++ libpurple/protocols/qq/group_im.c	3966fcb6e6a1f8fda309e328d46e8b5830d3eb4c
@@ -401,12 +401,12 @@ void qq_process_room_msg_normal(guint8 *
 
 	/* group im_group has no flag to indicate whether it has font_attr or not */
 	msg_with_purple_smiley = qq_smiley_to_purple(packet.msg);
-	if (packet.font_attr_len > 0)
+	if (packet.font_attr_len > 0) {
 		msg_utf8_encoded = qq_encode_to_purple(packet.font_attr,
-				packet.font_attr_len, msg_with_purple_smiley);
-	else
+				packet.font_attr_len, msg_with_purple_smiley, qd->client_version);
+	} else {
 		msg_utf8_encoded = qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT);
-
+	}
 	group = qq_room_search_id(gc, id);
  	qq_room_got_chat_in(gc, group, packet.member_uid, msg_utf8_encoded, packet.send_time);
 
============================================================
--- libpurple/protocols/qq/im.c	b4ccbe8ec5e04eaaf3a822baa7b4f5243ef4eee0
+++ libpurple/protocols/qq/im.c	4db6a4426726984be7305ad84bf712aa44b00edc
@@ -390,7 +390,8 @@ static void process_recv_normal_im_text(
 	msg_utf8_encoded = im_text->is_there_font_attr ?
 		qq_encode_to_purple(im_text->font_attr,
 				im_text->font_attr_len,
-				msg_with_purple_smiley) : qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT);
+				msg_with_purple_smiley, qd->client_version) 
+		: qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT);
 
 	/* send encoded to purple, note that we use im_text->send_time,
 	 * not the time we receive the message
============================================================
--- libpurple/protocols/qq/packet_parse.c	62cdbf4a27fb94fdb2458c47a37eae5367bd6c2d
+++ libpurple/protocols/qq/packet_parse.c	50b4e2960eb3809ce3ddb42ac25800292a3a67ce
@@ -151,6 +151,9 @@ gint qq_put32(guint8 *buf, guint32 dw)
  * return the number of bytes packed, otherwise return -1 */
 gint qq_put32(guint8 *buf, guint32 dw)
 {
+	guint32 dw_dest;
+	memcpy(&dw_dest, buf, sizeof(dw_dest));
+
     guint32 dw_porter;
     dw_porter = g_htonl(dw);
 #ifdef PARSER_DEBUG
@@ -161,6 +164,19 @@ gint qq_put32(guint8 *buf, guint32 dw)
     return sizeof(dw_porter);
 }
 
+gint qq_putime(guint8 *buf, time_t *t)
+{
+	guint32 dw, dw_porter;
+	memcpy(&dw, t, sizeof(dw));
+    dw_porter = g_htonl(dw);
+#ifdef PARSER_DEBUG
+	purple_debug_info("QQ", "[DBG][put32] buf %p\n", (void *)buf);
+	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);
+}
+
 gint qq_putIP(guint8* buf, struct in_addr *ip)
 {
     memcpy(buf, ip, sizeof(struct in_addr));
============================================================
--- libpurple/protocols/qq/packet_parse.h	2a60f02107e0c4e04f2c8186e1adf8f0466b36e9
+++ libpurple/protocols/qq/packet_parse.h	89769c59d1224745e5a85b9372cdbaed07fa01dd
@@ -54,6 +54,7 @@ gint qq_putIP(guint8* buf, struct in_add
 gint qq_put16(guint8 *buf, guint16 w);
 gint qq_put32(guint8 *buf, guint32 dw);
 gint qq_putIP(guint8* buf, struct in_addr *ip);
+gint qq_putime(guint8 *buf, time_t *t);
 gint qq_putdata(guint8 *buf, const guint8 *data, const int datalen);
 
 /*
============================================================
--- libpurple/protocols/qq/qq.c	6026eaa9bcbb6d84fb4c4c0bb68c08cbfe214bea
+++ libpurple/protocols/qq/qq.c	d6924486ed11ec637cfb8cda8f079ab51b9d0179
@@ -267,6 +267,9 @@ static gchar *qq_status_text(PurpleBuddy
 	case QQ_BUDDY_ONLINE_INVISIBLE:
 		g_string_append(status, _("Invisible"));
 		break;
+	case QQ_BUDDY_ONLINE_BUSY:
+		g_string_append(status, _("Busy"));
+		break;
 	default:
 		g_string_printf(status, _("Unknown-%d"), q_bud->status);
 	}
@@ -405,6 +408,10 @@ static GList *qq_status_types(PurpleAcco
 			"invisible", _("Invisible"), FALSE, TRUE, FALSE);
 	types = g_list_append(types, status);
 
+	status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE,
+			"busy", _("Busy"), TRUE, TRUE, FALSE);
+	types = g_list_append(types, status);
+
 	status = purple_status_type_new_full(PURPLE_STATUS_OFFLINE,
 			"offline", _("Offline"), FALSE, TRUE, FALSE);
 	types = g_list_append(types, status);
@@ -898,7 +905,9 @@ static void init_plugin(PurplePlugin *pl
 	GList *server_list = NULL;
 	GList *server_kv_list = NULL;
 	GList *it;
+//#ifdef DEBUG
 	GList *version_kv_list = NULL;
+//#endif
 
 	server_list = server_list_build('A');
 
@@ -927,7 +936,7 @@ static void init_plugin(PurplePlugin *pl
 	option = purple_account_option_list_new(_("Select Server"), "server", server_kv_list);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
-#ifdef DEBUG
+//#ifdef DEBUG
 	kvp = g_new0(PurpleKeyValuePair, 1);
 	kvp->key = g_strdup(_("QQ2005"));
 	kvp->value = g_strdup("qq2005");
@@ -945,7 +954,7 @@ static void init_plugin(PurplePlugin *pl
 
 	option = purple_account_option_list_new(_("Client Version"), "client_version", version_kv_list);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
-#endif
+//#endif
 
 	option = purple_account_option_bool_new(_("Connect by TCP"), "use_tcp", TRUE);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
============================================================
--- libpurple/protocols/qq/qq_base.c	28e364ec00620f7d5751cf7dd568b4f13c1de426
+++ libpurple/protocols/qq/qq_base.c	cff38b38098d8ef21f94b7a1e12713de27aaa3cb
@@ -460,11 +460,10 @@ void qq_request_keep_alive(PurpleConnect
 	 * with this command, server return the same result including
 	 * 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, raw_data, 4);
+	qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, bytes);
 }
 
-/* parse the return of keep-alive packet, it includes some system information */
+/* parse the return ofqq_process_keep_alive keep-alive packet, it includes some system information */
 gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc)
 {
 	qq_data *qd;
@@ -497,6 +496,107 @@ gboolean qq_process_keep_alive(guint8 *d
 	return TRUE;
 }
 
+void qq_request_keep_alive_2007(PurpleConnection *gc)
+{
+	qq_data *qd;
+	guint8 raw_data[32] = {0};
+	gint bytes= 0;
+	gchar *uid_str;
+
+	qd = (qq_data *) gc->proto_data;
+
+	/* In fact, we can send whatever we like to server
+	 * with this command, server return the same result including
+	 * the amount of online QQ users, my ip and port */
+	uid_str = g_strdup_printf("%u", qd->uid);
+	bytes += qq_putdata(raw_data + bytes, (guint8 *)uid_str, strlen(uid_str));
+	qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, bytes);
+
+	g_free(uid_str);
+}
+
+gboolean qq_process_keep_alive_2007(guint8 *data, gint data_len, PurpleConnection *gc)
+{
+	qq_data *qd;
+	gint bytes= 0;
+	guint8 ret;
+
+	g_return_val_if_fail(data != NULL && data_len != 0, FALSE);
+
+	qd = (qq_data *) gc->proto_data;
+
+	/* qq_show_packet("Keep alive reply packet", data, len); */
+
+	bytes = 0;
+	bytes += qq_get8(&ret, data + bytes);
+	bytes += qq_get32(&qd->online_total, data + bytes);
+	if(0 == qd->online_total) {
+		purple_connection_error_reason(gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Keep alive error"));
+	}
+
+	bytes += qq_getIP(&qd->my_ip, data + bytes);
+	bytes += qq_get16(&qd->my_port, data + bytes);
+	return TRUE;
+}
+
+void qq_request_keep_alive_2008(PurpleConnection *gc)
+{
+	qq_data *qd;
+	guint8 raw_data[16] = {0};
+	gint bytes= 0;
+
+	qd = (qq_data *) gc->proto_data;
+
+	/* In fact, we can send whatever we like to server
+	 * with this command, server return the same result including
+	 * the amount of online QQ users, my ip and port */
+	bytes += qq_put32(raw_data + bytes, qd->uid);
+	bytes += qq_putime(raw_data + bytes, &qd->login_time);
+	qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, bytes);
+}
+
+gboolean qq_process_keep_alive_2008(guint8 *data, gint data_len, PurpleConnection *gc)
+{
+	qq_data *qd;
+	gint bytes= 0;
+	guint8 ret;
+	time_t server_time;
+	struct tm *tm_local;
+
+	g_return_val_if_fail(data != NULL && data_len != 0, FALSE);
+
+	qd = (qq_data *) gc->proto_data;
+
+	/* qq_show_packet("Keep alive reply packet", data, len); */
+
+	bytes = 0;
+	bytes += qq_get8(&ret, data + bytes);
+	bytes += qq_get32(&qd->online_total, data + bytes);
+	if(0 == qd->online_total) {
+		purple_connection_error_reason(gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Keep alive error"));
+	}
+
+	bytes += qq_getIP(&qd->my_ip, data + bytes);
+	bytes += qq_get16(&qd->my_port, data + bytes);
+	/* skip 2 byytes, 0x(00 3c) */
+	bytes += 2;
+	bytes += qq_getime(&server_time, data + bytes);
+	/* skip 5 bytes, all are 0 */
+
+	purple_debug_info("QQ", "keep alive, %s:%d\n",
+		inet_ntoa(qd->my_ip), qd->my_port);
+
+	tm_local = localtime(&server_time);
+	purple_debug_info("QQ", "Server time: %d-%d-%d, %d:%d:%d\n",
+			(1900 +tm_local->tm_year), (1 + tm_local->tm_mon), tm_local->tm_mday,
+			tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec);
+	return TRUE;
+}
+
 /* For QQ2007/2008 */
 void qq_request_get_server(PurpleConnection *gc)
 {
@@ -681,8 +781,8 @@ static void request_token_ex_code(Purple
 	bytes += qq_put32(raw_data + bytes, 0);
 	bytes += qq_put16(raw_data + bytes, code_len);
 	bytes += qq_putdata(raw_data + bytes, code, code_len);
-	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);
+	bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len); 	/* login token ex */
+	bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len);
 
 	encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key);
 
@@ -811,7 +911,9 @@ guint8 qq_process_token_ex(PurpleConnect
 
 	bytes += qq_get16(&(qd->ld.token_ex_len), data + bytes);
 	qd->ld.token_ex = g_realloc(qd->ld.token_ex, qd->ld.token_ex_len);
-	bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len , data + bytes);
+	bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len, data + bytes);
+	qq_show_packet("Get token ex", qd->ld.token_ex, qd->ld.token_ex_len);
+	
 	if(reply != 1)
 	{
 		purple_debug_info("QQ", "Captcha verified, result %d\n", reply);
@@ -828,9 +930,12 @@ guint8 qq_process_token_ex(PurpleConnect
 	bytes += qq_get8(&qd->captcha.next_index, data + bytes);
 
 	bytes += qq_get16(&qd->captcha.token_len, data + bytes);
-	qd->captcha.token = g_new0(guint8, qd->captcha.token_len);
+	qd->captcha.token = g_realloc(qd->captcha.token, qd->captcha.token_len);
 	bytes += qq_getdata(qd->captcha.token, qd->captcha.token_len, data + bytes);
+	qq_show_packet("Get captcha token", qd->captcha.token, qd->captcha.token_len);
 
+	purple_debug_info("QQ", "Request next captcha %d, new %d, total %d\n", 
+			qd->captcha.next_index, captcha_len, qd->captcha.data_len);
 	if(qd->captcha.next_index > 0)
 	{
 		return QQ_LOGIN_REPLY_NEXT_TOKEN_EX;
@@ -894,7 +999,7 @@ void qq_request_check_pwd(PurpleConnecti
 	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);
+	g_return_if_fail(qd->ld.token_ex != NULL && qd->ld.token_ex_len > 0);
 
 	raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16);
 	memset(raw_data, 0, MAX_PACKET_SIZE - 16);
@@ -913,7 +1018,7 @@ void qq_request_check_pwd(PurpleConnecti
 	bytes = 0;
 	bytes += qq_putdata(raw_data + bytes, header, sizeof(header));
 	/* token get from qq_request_token_ex */
-	bytes += qq_put8(raw_data + bytes, qd->ld.token_ex_len);
+	bytes += qq_put8(raw_data + bytes, (guint8)(qd->ld.token_ex_len & 0xff));
 	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);
@@ -923,7 +1028,7 @@ void qq_request_check_pwd(PurpleConnecti
 	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_put8(raw_data + 1, bytes - 2);
 	
@@ -933,7 +1038,7 @@ void qq_request_check_pwd(PurpleConnecti
 	bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[1]);
 	bytes += qq_put8(raw_data + bytes, qd->ld.pwd_md5[2]);
 
-	/* qq_show_packet("Check password", raw_data, bytes); */
+	qq_show_packet("Check password", raw_data, bytes);
 	/* Encrypted by random key*/
 	encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.random_key);
 
@@ -963,7 +1068,7 @@ guint8 qq_process_check_pwd( PurpleConne
 	g_return_val_if_fail(gc != NULL  && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
 	qd = (qq_data *) gc->proto_data;
 
-	/* qq_show_packet("Check password reply", data, data_len); */
+	qq_show_packet("Check password reply", data, data_len);
 
 	bytes = 0;
 	bytes += qq_get16(&unknow_token_len, data + bytes);	/* maybe total length */
@@ -1097,11 +1202,12 @@ void qq_request_login_2007(PurpleConnect
 	memset(raw_data + bytes, 0, 10);
 	bytes += 10;
 	/* redirect data, 15 bytes */
+	qq_show_packet("Redirect", qd->redirect, qd->redirect_len);
 	bytes += qq_putdata(raw_data + bytes, qd->redirect, qd->redirect_len);
 	/* unknow fill */
 	bytes += qq_putdata(raw_data + bytes, login_2_16, sizeof(login_2_16));
 	/* captcha token get from qq_process_token_ex */
-	bytes += qq_put8(raw_data + bytes, qd->ld.token_ex_len);
+	bytes += qq_put8(raw_data + bytes, (guint8)(qd->ld.token_ex_len & 0xff));
 	bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len);
 	/* unknow fill */
 	bytes += qq_putdata(raw_data + bytes, login_3_83, sizeof(login_3_83));
@@ -1130,8 +1236,10 @@ guint8 qq_process_login_2007( PurpleConn
 	qq_data *qd;
 	gint bytes;
 	guint8 ret;
+	guint32 uid;
 	gchar *error;
-	guint32 uid;
+	gchar *msg;
+	gchar *msg_utf8;
 
 	g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
 
@@ -1140,15 +1248,34 @@ guint8 qq_process_login_2007( PurpleConn
 	bytes = 0;
 	bytes += qq_get8(&ret, data + bytes);
 	if (ret != 0) {
-		qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
-				">>> [default] decrypt and dump");
-		error = g_strdup_printf(
-				_("Unknow reply code when login (0x%02X)"),
-				ret );
+		msg = g_strndup((gchar *)data + bytes, data_len - bytes);
+		msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
+
+		switch (ret) {
+			case 0x05:
+				error = g_strdup_printf(
+						_("Server is busy now, Please try later\n%s"),
+						ret, msg_utf8);
+				break;
+			case 0x0A:
+				/* 0a 2d 9a 4b 9a 01 01 00 00 00 05 00 00 00 00 79 0e 5f fd */
+			default:
+				error = g_strdup_printf(
+						_("Unknow reply code when login (0x%02X):\n%s"),
+						ret, msg_utf8);
+				break;
+		}
+
+		purple_debug_error("QQ", "%s\n", error);
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_OTHER_ERROR,
 				error);
+
+		qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, error);
+
 		g_free(error);
+		g_free(msg_utf8);
+		g_free(msg);
 		return QQ_LOGIN_REPLY_ERR;
 	}
 
@@ -1262,7 +1389,7 @@ void qq_request_login_2008(PurpleConnect
 	/* unknow fill */
 	bytes += qq_putdata(raw_data + bytes, login_2_16, sizeof(login_2_16));
 	/* captcha token get from qq_process_token_ex */
-	bytes += qq_put8(raw_data + bytes, qd->ld.token_ex_len);
+	bytes += qq_put8(raw_data + bytes, (guint8)(qd->ld.token_ex_len & 0xff));
 	bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len);
 	/* unknow fill */
 	bytes += qq_putdata(raw_data + bytes, login_3_18, sizeof(login_3_18));
@@ -1301,8 +1428,10 @@ guint8 qq_process_login_2008( PurpleConn
 	qq_data *qd;
 	gint bytes;
 	guint8 ret;
+	guint32 uid;
 	gchar *error;
-	guint32 uid;
+	gchar *msg;
+	gchar *msg_utf8;
 
 	g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
 
@@ -1311,15 +1440,32 @@ guint8 qq_process_login_2008( PurpleConn
 	bytes = 0;
 	bytes += qq_get8(&ret, data + bytes);
 	if (ret != 0) {
-		qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len,
-				">>> [default] decrypt and dump");
-		error = g_strdup_printf(
-				_("Unknow reply code when login (0x%02X)"),
-				ret );
+		msg = g_strndup((gchar *)data + bytes, data_len - bytes);
+		msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
+
+		switch (ret) {
+			case 0x05:
+				error = g_strdup_printf(
+						_("Server is busy now, Please try later\n%s"),
+						ret, msg_utf8);
+				break;
+			default:
+				error = g_strdup_printf(
+						_("Unknow reply code when login (0x%02X):\n%s"),
+						ret, msg_utf8);
+				break;
+		}
+
+		purple_debug_error("QQ", "%s\n", error);
 		purple_connection_error_reason(gc,
 				PURPLE_CONNECTION_ERROR_OTHER_ERROR,
 				error);
+
+		qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, error);
+
 		g_free(error);
+		g_free(msg_utf8);
+		g_free(msg);
 		return QQ_LOGIN_REPLY_ERR;
 	}
 
============================================================
--- libpurple/protocols/qq/qq_base.h	3d8a80825363d0941c79352ba552c5a03b87bc89
+++ libpurple/protocols/qq/qq_base.h	ab3178def027c3d85eb21ecf515ef9c721686757
@@ -52,6 +52,12 @@ gboolean qq_process_keep_alive(guint8 *d
 void qq_request_keep_alive(PurpleConnection *gc);
 gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc);
 
+void qq_request_keep_alive_2007(PurpleConnection *gc);
+gboolean qq_process_keep_alive_2007(guint8 *data, gint data_len, PurpleConnection *gc);
+
+void qq_request_keep_alive_2008(PurpleConnection *gc);
+gboolean qq_process_keep_alive_2008(guint8 *data, gint data_len, PurpleConnection *gc);
+
 /* for QQ2007/2008 */
 void qq_request_get_server(PurpleConnection *gc);
 guint16 qq_process_get_server(PurpleConnection *gc, guint8 *rcved, gint rcved_len);
============================================================
--- libpurple/protocols/qq/qq_network.c	e980710f438f68c435ac95ed09bcdf732e091bb3
+++ libpurple/protocols/qq/qq_network.c	ecfb66d708a004a81b2ac2644516b07dcb27ff84
@@ -667,7 +667,13 @@ static gboolean network_timeout(gpointer
 	qd->itv_count.keep_alive--;
 	if (qd->itv_count.keep_alive <= 0) {
 		qd->itv_count.keep_alive = qd->itv_config.keep_alive;
-		qq_request_keep_alive(gc);
+		if (qd->client_version >= 2008) {
+			qq_request_keep_alive_2008(gc);
+		} else if (qd->client_version >= 2007) {
+			qq_request_keep_alive_2007(gc);
+		} else {
+			qq_request_keep_alive(gc);
+		}
 		return TRUE;
 	}
 
@@ -691,7 +697,9 @@ static void set_all_keys(PurpleConnectio
 	const gchar *passwd;
 	guint8 *dest;
 	int dest_len = QQ_KEY_LENGTH;
-
+#ifndef DEBUG
+	int bytes;
+#endif
 	/* _qq_show_socket("Got login socket", source); */
 
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
@@ -771,7 +779,7 @@ static void connect_cb(gpointer data, gi
 
 	set_all_keys( gc );
 
-	if (qd->client_version > 2005) {
+	if (qd->client_version >= 2007) {
 		purple_connection_update_progress(gc, _("Get server ..."), 2, QQ_CONNECT_STEPS);
 		qq_request_get_server(gc);
 		return;
============================================================
--- libpurple/protocols/qq/qq_network.h	1e908088d3f41d42646e83d59572f2670a6b3ece
+++ libpurple/protocols/qq/qq_network.h	b5da3ac74a10b4a53df0b6ea29860d12e42d0d61
@@ -30,7 +30,7 @@
 
 #include "qq.h"
 
-#define QQ_CONNECT_STEPS    3	/* steps in connection */
+#define QQ_CONNECT_STEPS    4	/* steps in connection */
 
 gboolean qq_connect_later(gpointer data);
 void qq_disconnect(PurpleConnection *gc);
============================================================
--- libpurple/protocols/qq/qq_process.c	704cd19e09d79732c04337624136c8529cef47f9
+++ libpurple/protocols/qq/qq_process.c	1cd91fd9f8aa68e792523cc394bfad6cca747445
@@ -589,7 +589,7 @@ guint8 qq_proc_login_cmds(PurpleConnecti
 	switch (cmd) {
 		case QQ_CMD_TOKEN:
 			if (qq_process_token(gc, rcved, rcved_len) == QQ_LOGIN_REPLY_OK) {
-				if (qd->client_version > 2005) {
+				if (qd->client_version >= 2007) {
 					qq_request_token_ex(gc);
 				} else {
 					qq_request_login(gc);
@@ -615,7 +615,7 @@ guint8 qq_proc_login_cmds(PurpleConnecti
 			break;
 		case QQ_CMD_LOGIN:
 		default:
-			if (qd->client_version > 2005) {
+			if (qd->client_version >= 2007) {
 				data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.pwd_twice_md5);
 				if (data_len >= 0) {
 					purple_debug_warning("QQ", "Decrypt login packet by pwd_twice_md5\n");
@@ -696,6 +696,7 @@ guint8 qq_proc_login_cmds(PurpleConnecti
 				return  ret_8;
 			}
 
+			purple_connection_update_progress(gc, _("Logined"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS);
 			purple_debug_info("QQ", "Login repliess OK; everything is fine\n");
 			purple_connection_set_state(gc, PURPLE_CONNECTED);
 			qd->is_login = TRUE;	/* must be defined after sev_finish_login */
@@ -776,7 +777,13 @@ void qq_proc_client_cmds(PurpleConnectio
 			qq_process_send_im_reply(data, data_len, gc);
 			break;
 		case QQ_CMD_KEEP_ALIVE:
-			qq_process_keep_alive(data, data_len, gc);
+			if (qd->client_version >= 2008) {
+				qq_process_keep_alive_2008(data, data_len, gc);
+			} else if (qd->client_version >= 2007) {
+				qq_process_keep_alive_2007(data, data_len, gc);
+			} else {
+				qq_process_keep_alive(data, data_len, gc);
+			}
 			break;
 		case QQ_CMD_GET_BUDDIES_ONLINE:
 			ret_8 = qq_process_get_buddies_online_reply(data, data_len, gc);
============================================================
--- libpurple/protocols/qq/send_file.c	271b750f28e52519c0b0cdef1c6ca880d5b418dc
+++ libpurple/protocols/qq/send_file.c	d7e6ab68ca7284c476a7e822bb9cff1c43deb564
@@ -121,11 +121,8 @@ static ssize_t _qq_xfer_udp_send(const g
 		sin.sin_port = g_htons(info->remote_minor_port);
 		sin.sin_addr.s_addr = g_htonl(info->remote_real_ip);
 	}
-	purple_debug_info("QQ", "sending to channel: %d.%d.%d.%d:%d\n",
-			(int)sin.sin_addr.s_addr & 0xff,
-			(int)(sin.sin_addr.s_addr >> 8) & 0xff,
-			(int)(sin.sin_addr.s_addr >> 16) & 0xff,
-			(int)sin.sin_addr.s_addr >> 24,
+	purple_debug_info("QQ", "sending to channel: %s:%d\n",
+			inet_ntoa(sin.sin_addr),
 			(int)g_ntohs(sin.sin_port)
 		  );
 	return sendto(info->sender_fd, buf, len, 0, (struct sockaddr *) &sin, sizeof(sin));


More information about the Commits mailing list