pidgin.openq: bb5558d3: patch 20080922 from ccpaging <ccpaging(a...
csyfek at gmail.com
csyfek at gmail.com
Wed Oct 22 12:12:21 EDT 2008
-----------------------------------------------------------------
Revision: bb5558d316fe6765728168f9e19639095ba6478d
Ancestor: 960054dafdd2879a6835f8e04214129667b11423
Author: csyfek at gmail.com
Date: 2008-10-22T14:33:20
Branch: im.pidgin.pidgin.openq
URL: http://d.pidgin.im/viewmtn/revision/info/bb5558d316fe6765728168f9e19639095ba6478d
Modified files:
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/file_trans.c
libpurple/protocols/qq/group.c
libpurple/protocols/qq/group_conv.c
libpurple/protocols/qq/group_im.c
libpurple/protocols/qq/group_info.c
libpurple/protocols/qq/group_join.c
libpurple/protocols/qq/group_opt.c
libpurple/protocols/qq/group_search.c
libpurple/protocols/qq/im.c libpurple/protocols/qq/qq.c
libpurple/protocols/qq/qq.h libpurple/protocols/qq/qq_base.c
libpurple/protocols/qq/qq_base.h
libpurple/protocols/qq/qq_define.c
libpurple/protocols/qq/qq_define.h
libpurple/protocols/qq/qq_network.c
libpurple/protocols/qq/qq_process.c
libpurple/protocols/qq/qq_process.h
libpurple/protocols/qq/qq_trans.c
libpurple/protocols/qq/send_file.c
ChangeLog:
patch 20080922 from ccpaging <ccpaging(at)gmail.com>
-------------- next part --------------
============================================================
--- libpurple/protocols/qq/Makefile.am 2b1030056344af9a423a29ad3a8ca21831baf583
+++ libpurple/protocols/qq/Makefile.am 207abbad5767fe734607409821587869d715218b
@@ -36,8 +36,8 @@ QQSOURCES = \
group_opt.h \
group_search.c \
group_search.h \
- header_info.c \
- header_info.h \
+ qq_define.c \
+ qq_define.h \
im.c \
im.h \
qq_process.c \
============================================================
--- libpurple/protocols/qq/Makefile.mingw bfdbb323f7edc788f1e3ce2ed7f3731791b4de5a
+++ libpurple/protocols/qq/Makefile.mingw eeef4e620e2b8d4d6d3336b10a7bae215657c8b8
@@ -55,7 +55,7 @@ C_SRC = \
group_join.c \
group_opt.c \
group_search.c \
- header_info.c \
+ qq_define.c \
im.c \
packet_parse.c \
qq.c \
============================================================
--- libpurple/protocols/qq/buddy_info.c 20ae76b726968ba91406b83eabe311b503650f6b
+++ libpurple/protocols/qq/buddy_info.c b82b64007711ec63c899a89220ba30ed3241b2c8
@@ -32,7 +32,7 @@
#include "buddy_list.h"
#include "buddy_info.h"
#include "char_conv.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "qq_base.h"
#include "qq_network.h"
@@ -426,7 +426,11 @@ static void info_modify_dialogue(PurpleC
info_request->iclass = iclass;
info_request->segments = segments;
- purple_request_fields(gc, utf8_title, utf8_prim, NULL, fields,
+ purple_request_fields(gc,
+ utf8_title,
+ utf8_prim,
+ NULL,
+ fields,
_("Update"), G_CALLBACK(info_modify_ok_cb),
_("Cancel"), G_CALLBACK(info_modify_cancel_cb),
purple_connection_get_account(gc), NULL, NULL,
============================================================
--- libpurple/protocols/qq/buddy_list.c 9b1ed5dfeeed12c2f6879cba8e4e6aecb8398414
+++ libpurple/protocols/qq/buddy_list.c a2fd962185dde0cffff2556d476f1659d00d65d5
@@ -34,7 +34,7 @@
#include "buddy_list.h"
#include "buddy_opt.h"
#include "char_conv.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "qq_base.h"
#include "group.h"
#include "group_find.h"
@@ -78,7 +78,6 @@ void qq_request_get_buddies_online(Purpl
bytes += qq_put16(raw_data + bytes, 0x0000);
qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_ONLINE, raw_data, 5, update_class, 0);
- qd->last_get_online = time(NULL);
}
/* position starts with 0x0000,
============================================================
--- libpurple/protocols/qq/buddy_opt.c d3534cf0719079b8d8ef27b6e5e1e0f1fd03ea43
+++ libpurple/protocols/qq/buddy_opt.c 494a448c64ee5e7ea82091e45f136183beb2a954
@@ -32,7 +32,7 @@
#include "buddy_list.h"
#include "buddy_opt.h"
#include "char_conv.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "im.h"
#include "qq_base.h"
#include "packet_parse.h"
============================================================
--- libpurple/protocols/qq/file_trans.c 2775840f1f4b59ea87cddfc4d8a71b825f1ecd3a
+++ libpurple/protocols/qq/file_trans.c 2c8f48f87dabe9f111faa4bb4fba3e6134d342d9
@@ -30,7 +30,7 @@
#include "qq_crypt.h"
#include "file_trans.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "im.h"
#include "packet_parse.h"
#include "proxy.h"
@@ -81,7 +81,7 @@ static void _fill_file_md5(const gchar *
const gint QQ_MAX_FILE_MD5_LENGTH = 10002432;
g_return_if_fail(filename != NULL && md5 != NULL);
- if (filelen > QQ_MAX_FILE_MD5_LENGTH)
+ if (filelen > QQ_MAX_FILE_MD5_LENGTH)
filelen = QQ_MAX_FILE_MD5_LENGTH;
fp = fopen(filename, "rb");
@@ -161,7 +161,7 @@ static int _qq_xfer_open_file(const gcha
fd = open(purple_xfer_get_local_filename(xfer), O_RDONLY);
info->buffer = mmap(0, purple_xfer_get_size(xfer), PROT_READ, MAP_PRIVATE, fd, 0);
}
- else
+ else
{
fd = open(purple_xfer_get_local_filename(xfer), O_RDWR|O_CREAT, 0644);
info->buffer = mmap(0, purple_xfer_get_size(xfer), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, 0);
@@ -248,7 +248,7 @@ static gint _qq_send_file(PurpleConnecti
file_key = _gen_file_key();
bytes += qq_put8(raw_data + bytes, packet_type);
- bytes += qq_put16(raw_data + bytes, QQ_CLIENT);
+ bytes += qq_put16(raw_data + bytes, qd->client_version);
bytes += qq_put8(raw_data + bytes, file_key & 0xff);
bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(qd->uid, file_key));
bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(to_uid, file_key));
@@ -364,7 +364,7 @@ void qq_send_file_ctl_packet(PurpleConne
}
/* send a file to udp channel with QQ_FILE_DATA_PACKET_TAG */
-static void _qq_send_file_data_packet(PurpleConnection *gc, guint16 packet_type, guint8 sub_type,
+static void _qq_send_file_data_packet(PurpleConnection *gc, guint16 packet_type, guint8 sub_type,
guint32 fragment_index, guint16 seq, guint8 *data, gint len)
{
guint8 *raw_data, filename_md5[QQ_KEY_LENGTH], file_md5[QQ_KEY_LENGTH];
@@ -402,11 +402,11 @@ static void _qq_send_file_data_packet(Pu
_fill_file_md5(purple_xfer_get_local_filename(qd->xfer),
purple_xfer_get_size(qd->xfer),
file_md5);
-
+
info->fragment_num = (filesize - 1) / QQ_FILE_FRAGMENT_MAXLEN + 1;
info->fragment_len = QQ_FILE_FRAGMENT_MAXLEN;
- purple_debug_info("QQ",
+ purple_debug_info("QQ",
"start transfering data, %d fragments with %d length each\n",
info->fragment_num, info->fragment_len);
/* Unknown */
@@ -431,7 +431,7 @@ static void _qq_send_file_data_packet(Pu
filename_len);
break;
case QQ_FILE_DATA_INFO:
- purple_debug_info("QQ",
+ purple_debug_info("QQ",
"sending %dth fragment with length %d, offset %d\n",
fragment_index, len, (fragment_index-1)*fragment_size);
/* bytes += qq_put16(raw_data + bytes, ++(qd->send_seq)); */
@@ -532,7 +532,7 @@ static void _qq_process_recv_file_ctl_pa
decryped_bytes = 0;
qq_get_conn_info(info, decrypted_data + decryped_bytes);
/* qq_send_file_ctl_packet(gc, QQ_FILE_CMD_PING, fh->sender_uid, 0); */
- qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0);
+ qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0);
break;
case QQ_FILE_CMD_SENDER_SAY_HELLO:
/* I'm receiver, if we receive SAY_HELLO from sender, we send back the ACK */
@@ -573,8 +573,8 @@ static void _qq_recv_file_progess(Purple
ft_info *info = (ft_info *) xfer->data;
guint32 mask;
- purple_debug_info("QQ",
- "receiving %dth fragment with length %d, slide window status %o, max_fragment_index %d\n",
+ purple_debug_info("QQ",
+ "receiving %dth fragment with length %d, slide window status %o, max_fragment_index %d\n",
index, len, info->window, info->max_fragment_index);
if (info->window == 0 && info->max_fragment_index == 0) {
if (_qq_xfer_open_file(purple_xfer_get_local_filename(xfer), "wb", xfer) == -1) {
@@ -605,7 +605,7 @@ static void _qq_recv_file_progess(Purple
if (mask & 0x8000) mask = 0x0001;
else mask = mask << 1;
}
- purple_debug_info("QQ", "procceed %dth fragment, slide window status %o, max_fragment_index %d\n",
+ purple_debug_info("QQ", "procceed %dth fragment, slide window status %o, max_fragment_index %d\n",
index, info->window, info->max_fragment_index);
}
@@ -650,10 +650,10 @@ static void _qq_update_send_progess(Purp
PurpleXfer *xfer = qd->xfer;
ft_info *info = (ft_info *) xfer->data;
- purple_debug_info("QQ",
- "receiving %dth fragment ack, slide window status %o, max_fragment_index %d\n",
+ purple_debug_info("QQ",
+ "receiving %dth fragment ack, slide window status %o, max_fragment_index %d\n",
fragment_index, info->window, info->max_fragment_index);
- if (fragment_index < info->max_fragment_index ||
+ if (fragment_index < info->max_fragment_index ||
fragment_index >= info->max_fragment_index + sizeof(info->window)) {
purple_debug_info("QQ", "duplicate %dth fragment, drop it!\n", fragment_index+1);
return;
@@ -681,7 +681,7 @@ static void _qq_update_send_progess(Purp
info->window &= ~mask;
buffer = g_newa(guint8, info->fragment_len);
- readbytes = _qq_xfer_read_file(buffer, info->max_fragment_index + sizeof(info->window),
+ readbytes = _qq_xfer_read_file(buffer, info->max_fragment_index + sizeof(info->window),
info->fragment_len, xfer);
if (readbytes > 0)
_qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP, QQ_FILE_DATA_INFO,
@@ -692,8 +692,8 @@ static void _qq_update_send_progess(Purp
else mask = mask << 1;
}
}
- purple_debug_info("QQ",
- "procceed %dth fragment ack, slide window status %o, max_fragment_index %d\n",
+ purple_debug_info("QQ",
+ "procceed %dth fragment ack, slide window status %o, max_fragment_index %d\n",
fragment_index, info->window, info->max_fragment_index);
}
@@ -727,13 +727,13 @@ static void _qq_process_recv_file_data(P
bytes += qq_get32(&info->fragment_num, data + bytes);
bytes += qq_get32(&info->fragment_len, data + bytes);
- /* FIXME: We must check the md5 here,
- * if md5 doesn't match we will ignore
+ /* FIXME: We must check the md5 here,
+ * if md5 doesn't match we will ignore
* the packet or send sth as error number */
info->max_fragment_index = 0;
info->window = 0;
- purple_debug_info("QQ",
+ purple_debug_info("QQ",
"start receiving data, %d fragments with %d length each\n",
info->fragment_num, info->fragment_len);
_qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type,
@@ -743,7 +743,7 @@ static void _qq_process_recv_file_data(P
bytes += qq_get32(&fragment_index, data + bytes);
bytes += qq_get32(&fragment_offset, data + bytes);
bytes += qq_get16(&fragment_len, data + bytes);
- purple_debug_info("QQ",
+ purple_debug_info("QQ",
"received %dth fragment with length %d, offset %d\n",
fragment_index, fragment_len, fragment_offset);
============================================================
--- libpurple/protocols/qq/group.c 0dc229d6263edb2c6a6fa1ee7f661d125b99cee7
+++ libpurple/protocols/qq/group.c 7fa0414e92ad66f7941cc795a9377cd720a7a37f
@@ -33,7 +33,7 @@
#include "group_search.h"
#include "utils.h"
#include "qq_network.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "group_free.h"
static void _qq_group_search_callback(PurpleConnection *gc, const gchar *input)
============================================================
--- libpurple/protocols/qq/group_conv.c 074bbf6f60a497fd05ecc24032b818243819bbb2
+++ libpurple/protocols/qq/group_conv.c 5b30fdabc44113fce4d6e14886de4b9581276962
@@ -27,7 +27,7 @@
#include "group_conv.h"
#include "buddy_list.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "qq_network.h"
#include "qq_process.h"
#include "utils.h"
============================================================
--- libpurple/protocols/qq/group_im.c 94009eace5bf8cd9a136720df3449493ea5380dc
+++ libpurple/protocols/qq/group_im.c 2c084034186d20995d280b3c9b29688ae3efda63
@@ -39,7 +39,7 @@
#include "group_opt.h"
#include "group_conv.h"
#include "im.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "packet_parse.h"
#include "qq_network.h"
#include "qq_process.h"
============================================================
--- libpurple/protocols/qq/group_info.c 5e52c58147c9ab1c318c91212128f8ea6a7d32f1
+++ libpurple/protocols/qq/group_info.c 0089d00bee0b490ac0b3f79637718984fa83f7e1
@@ -32,7 +32,7 @@
#include "group_internal.h"
#include "group_info.h"
#include "buddy_list.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "packet_parse.h"
#include "qq_network.h"
#include "utils.h"
============================================================
--- libpurple/protocols/qq/group_join.c 1dc85c7d1bc5f5fb56c0a1c6aece13022460e4a8
+++ libpurple/protocols/qq/group_join.c 752655badb239f6df8e7e9913f64947c318ecf7c
@@ -38,7 +38,7 @@
#include "group_opt.h"
#include "group_conv.h"
#include "group_search.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "packet_parse.h"
#include "qq_network.h"
#include "qq_process.h"
============================================================
--- libpurple/protocols/qq/group_opt.c 87b480c3666e20d961653cf0f0e16dbabcb50cb1
+++ libpurple/protocols/qq/group_opt.c 9512e5600ad6681ad60d46e8aeccdc65ef8ebd78
@@ -35,7 +35,7 @@
#include "group_info.h"
#include "group_join.h"
#include "group_opt.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "packet_parse.h"
#include "qq_network.h"
#include "qq_process.h"
============================================================
--- libpurple/protocols/qq/group_search.c 3ab74d8fa384063407170325c69f1f61e2021511
+++ libpurple/protocols/qq/group_search.c 9109c264ca8a47e9e284ba5388fd2fdb1a16e6b1
@@ -33,7 +33,7 @@
#include "group_join.h"
#include "group_search.h"
#include "utils.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "packet_parse.h"
#include "qq_network.h"
============================================================
--- libpurple/protocols/qq/im.c 702c7ac1372e88b719dd20b88f106b41e75c155a
+++ libpurple/protocols/qq/im.c 12ab7161d337f989800516b234b5b1124cccc672
@@ -36,7 +36,7 @@
#include "buddy_opt.h"
#include "char_conv.h"
#include "group_im.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "im.h"
#include "packet_parse.h"
#include "qq_network.h"
@@ -502,7 +502,7 @@ void qq_send_packet_im(PurpleConnection
{
qq_data *qd;
guint8 *raw_data, *send_im_tail;
- guint16 client_tag, normal_im_type;
+ guint16 normal_im_type;
gint msg_len, raw_len, font_name_len, tail_len, bytes;
time_t now;
gchar *msg_filtered;
@@ -512,7 +512,6 @@ void qq_send_packet_im(PurpleConnection
const gchar *start, *end, *last;
qd = (qq_data *) gc->proto_data;
- client_tag = QQ_CLIENT;
normal_im_type = QQ_NORMAL_IM_TEXT;
last = msg;
@@ -572,7 +571,7 @@ void qq_send_packet_im(PurpleConnection
/* 004-007: sender uid */
bytes += qq_put32(raw_data + bytes, to_uid);
/* 008-009: sender client version */
- bytes += qq_put16(raw_data + bytes, client_tag);
+ bytes += qq_put16(raw_data + bytes, qd->client_version);
/* 010-013: receiver uid */
bytes += qq_put32(raw_data + bytes, qd->uid);
/* 014-017: sender uid */
============================================================
--- libpurple/protocols/qq/qq.c a07a58489c8d3ba77a04a9a8b5f5877df11221ba
+++ libpurple/protocols/qq/qq.c dc390467f68a19e02ea4906d2029990188041368
@@ -44,7 +44,7 @@
#include "group_info.h"
#include "group_join.h"
#include "group_opt.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "im.h"
#include "qq_process.h"
#include "qq_base.h"
@@ -128,6 +128,7 @@ static void qq_login(PurpleAccount *acco
PurpleConnection *gc;
qq_data *qd;
PurplePresence *presence;
+ const gchar *version_str;
g_return_if_fail(account != NULL);
@@ -154,6 +155,16 @@ static void qq_login(PurpleAccount *acco
server_list_create(account);
purple_debug_info("QQ", "Server list has %d\n", g_list_length(qd->servers));
+ version_str = purple_account_get_string(account, "client_version", NULL);
+ qd->client_version = QQ_CLIENT_0D55; /* set default as QQ2005 */
+ qd->is_above_2007 = FALSE;
+ if (version_str != NULL && strlen(version_str) != 0) {
+ if (strcmp(version_str, "qq2007") == 0) {
+ qd->client_version = QQ_CLIENT_111D;
+ qd->is_above_2007 = TRUE;
+ }
+ }
+
qd->is_show_notice = purple_account_get_bool(account, "show_notice", TRUE);
qd->is_show_news = purple_account_get_bool(account, "show_news", TRUE);
@@ -203,6 +214,11 @@ static void qq_close(PurpleConnection *g
}
qq_disconnect(gc);
+
+ if (qd->ld.token) g_free(qd->ld.token);
+ if (qd->captcha.token) g_free(qd->captcha.token);
+ if (qd->captcha.data) g_free(qd->captcha.data);
+
server_list_remove_all(qd);
g_free(qd);
@@ -536,18 +552,20 @@ static void action_show_account_info(Pur
GString *info;
qd = (qq_data *) gc->proto_data;
- info = g_string_new("<html><body>\n");
+ info = g_string_new("<html><body>");
- g_string_append_printf(info, _("<b>Current Online</b>: %d<br>\n"), qd->total_online);
- g_string_append_printf(info, _("<b>Last Refresh</b>: %s<br>\n"), ctime(&qd->last_get_online));
+ g_string_append_printf(info, _("<b>This Login</b>: %s<br>\n"), ctime(&qd->login_time));
+ g_string_append_printf(info, _("<b>Online Buddies</b>: %d<br>\n"), qd->online_total);
+ g_string_append_printf(info, _("<b>Last Refresh</b>: %s<br>\n"), ctime(&qd->online_last_update));
- g_string_append(info, "<hr>\n");
+ g_string_append(info, "<hr>");
g_string_append_printf(info, _("<b>Server</b>: %s<br>\n"), qd->curr_server);
+ g_string_append_printf(info, _("<b>Client Version</b>: %s<br>\n"), qq_get_ver_desc(qd->client_version));
g_string_append_printf(info, _("<b>Connection Mode</b>: %s<br>\n"), qd->use_tcp ? "TCP" : "UDP");
- g_string_append_printf(info, _("<b>My Internet Address</b>: %s<br>\n"), inet_ntoa(qd->my_ip));
+ g_string_append_printf(info, _("<b>My Internet IP</b>: %s<br>\n"), inet_ntoa(qd->my_ip));
- g_string_append(info, "<hr>\n");
+ g_string_append(info, "<hr>");
g_string_append(info, "<i>Network Status</i><br>\n");
g_string_append_printf(info, _("<b>Sent</b>: %lu<br>\n"), qd->net_stat.sent);
g_string_append_printf(info, _("<b>Resend</b>: %lu<br>\n"), qd->net_stat.resend);
@@ -555,12 +573,11 @@ static void action_show_account_info(Pur
g_string_append_printf(info, _("<b>Received</b>: %lu<br>\n"), qd->net_stat.rcved);
g_string_append_printf(info, _("<b>Received Duplicate</b>: %lu<br>\n"), qd->net_stat.rcved_dup);
- g_string_append(info, "<hr>\n");
+ g_string_append(info, "<hr>");
g_string_append(info, "<i>Information below may not be accurate</i><br>\n");
- g_string_append_printf(info, _("<b>Login Time</b>: %s<br>\n"), ctime(&qd->login_time));
+ g_string_append_printf(info, _("<b>Last Login</b>: %s\n"), ctime(&qd->last_login_time));
g_string_append_printf(info, _("<b>Last Login IP</b>: %s<br>\n"), qd->last_login_ip);
- g_string_append_printf(info, _("<b>Last Login Time</b>: %s\n"), ctime(&qd->last_login_time));
g_string_append(info, "</body></html>");
@@ -848,35 +865,53 @@ static void init_plugin(PurplePlugin *pl
{
PurpleAccountOption *option;
PurpleKeyValuePair *kvp;
- GList *list = NULL;
- GList *kvlist = NULL;
- GList *entry;
+ GList *server_list = NULL;
+ GList *server_kv_list = NULL;
+ GList *it;
+ GList *version_kv_list = NULL;
- list = server_list_build('A');
+ server_list = server_list_build('A');
- purple_prefs_add_string_list("/plugins/prpl/qq/serverlist", list);
- list = purple_prefs_get_string_list("/plugins/prpl/qq/serverlist");
+ purple_prefs_add_string_list("/plugins/prpl/qq/serverlist", server_list);
+ server_list = purple_prefs_get_string_list("/plugins/prpl/qq/serverlist");
- kvlist = NULL;
+ server_kv_list = NULL;
kvp = g_new0(PurpleKeyValuePair, 1);
kvp->key = g_strdup(_("Auto"));
kvp->value = g_strdup("auto");
- kvlist = g_list_append(kvlist, kvp);
+ server_kv_list = g_list_append(server_kv_list, kvp);
- entry = list;
- while(entry) {
- if (entry->data != NULL && strlen(entry->data) > 0) {
+ it = server_list;
+ while(it) {
+ if (it->data != NULL && strlen(it->data) > 0) {
kvp = g_new0(PurpleKeyValuePair, 1);
- kvp->key = g_strdup(entry->data);
- kvp->value = g_strdup(entry->data);
- kvlist = g_list_append(kvlist, kvp);
+ kvp->key = g_strdup(it->data);
+ kvp->value = g_strdup(it->data);
+ server_kv_list = g_list_append(server_kv_list, kvp);
}
- entry = entry->next;
+ it = it->next;
}
- option = purple_account_option_list_new(_("Server"), "server", kvlist);
+ g_list_free(server_list);
+
+ 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
+ kvp = g_new0(PurpleKeyValuePair, 1);
+ kvp->key = g_strdup(_("QQ2005"));
+ kvp->value = g_strdup("qq2005");
+ version_kv_list = g_list_append(version_kv_list, kvp);
+
+ kvp = g_new0(PurpleKeyValuePair, 1);
+ kvp->key = g_strdup(_("QQ2007"));
+ kvp->value = g_strdup("qq2007");
+ version_kv_list = g_list_append(version_kv_list, kvp);
+
+ 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
+
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.h 7d26c6dc840ce378d9b814a90c231c4af6e41c7f
+++ libpurple/protocols/qq/qq.h 3c31740ed75db80caffc96a2decb799775baeec6
@@ -41,7 +41,36 @@ typedef struct _qq_add_request qq_add_re
typedef struct _qq_interval qq_interval;
typedef struct _qq_net_stat qq_net_stat;
typedef struct _qq_add_request qq_add_request;
+typedef struct _qq_redirect_data qq_redirect_data;
+typedef struct _qq_login_data qq_login_data;
+typedef struct _qq_captcha_data qq_captcha_data;
+struct _qq_captcha_data {
+ guint8 *token;
+ guint16 token_len;
+ guint8 next_index;
+ guint8 *data;
+ guint16 data_len;
+};
+
+struct _qq_login_data {
+ guint8 init_key[QQ_KEY_LENGTH]; /* first encrypt key generated by client */
+ guint8 *token; /* get from server*/
+ guint8 token_len;
+ guint8 *token_ex; /* get from server*/
+ guint16 token_ex_len;
+ guint8 captcha_key[QQ_KEY_LENGTH]; /* encrypt key used in captcha generated by client */
+ guint8 pwd_twice_md5[QQ_KEY_LENGTH]; /* password in md5 (or md5' md5) */
+};
+
+struct _qq_redirect_data {
+ guint16 ret;
+ guint8 b1;
+ guint32 w1;
+ guint32 w2;
+ guint32 ip;
+};
+
struct _qq_add_request {
guint32 uid;
PurpleConnection *gc;
@@ -111,8 +140,13 @@ struct _qq_data {
GList *servers;
gchar *curr_server; /* point to servers->data, do not free*/
+ guint16 client_version;
+ gboolean is_above_2007;
+
struct in_addr redirect_ip;
guint16 redirect_port;
+ qq_redirect_data redirect_data;
+
guint check_watcher;
guint connect_watcher;
gint connect_retry;
@@ -125,10 +159,10 @@ struct _qq_data {
GList *transactions; /* check ack packet and resend */
guint32 uid; /* QQ number */
- guint8 *token; /* get from server*/
- int token_len;
- guint8 inikey[QQ_KEY_LENGTH]; /* initial key to encrypt login packet */
- guint8 password_twice_md5[QQ_KEY_LENGTH]; /* password in md5 (or md5' md5) */
+
+ qq_login_data ld;
+ qq_captcha_data captcha;
+
guint8 session_key[QQ_KEY_LENGTH]; /* later use this as key in this session */
guint8 session_md5[QQ_KEY_LENGTH]; /* concatenate my uid with session_key and md5 it */
@@ -147,8 +181,8 @@ struct _qq_data {
guint16 my_port; /* my port detected by server */
guint16 my_icon; /* my icon index */
guint16 my_level; /* my level */
- guint32 total_online; /* the number of online QQ users */
- time_t last_get_online; /* last time send get_friends_online packet */
+ guint32 online_total; /* the number of online QQ users */
+ time_t online_last_update; /* last time send get_friends_online packet */
PurpleRoomlist *roomlist;
gint channel; /* the id for opened chat conversation */
============================================================
--- libpurple/protocols/qq/qq_base.c 6ca17e28fe0a03df4a08018804b3c0c2a51f0b11
+++ libpurple/protocols/qq/qq_base.c 767955d22a2632010a419ef0aee3a009a6f9d029
@@ -26,13 +26,14 @@
#include "internal.h"
#include "server.h"
#include "cipher.h"
+#include "request.h"
#include "buddy_info.h"
#include "buddy_list.h"
#include "char_conv.h"
#include "qq_crypt.h"
#include "group.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "qq_base.h"
#include "packet_parse.h"
#include "qq.h"
@@ -101,39 +102,6 @@ static const guint8 login_53_68[16] = {
*/
-typedef struct _qq_login_reply_ok qq_login_reply_ok_packet;
-typedef struct _qq_login_reply_redirect qq_login_reply_redirect_packet;
-
-struct _qq_login_reply_ok {
- guint8 result;
- guint8 session_key[QQ_KEY_LENGTH];
- guint32 uid;
- struct in_addr client_ip; /* those detected by server */
- guint16 client_port;
- struct in_addr server_ip;
- guint16 server_port;
- time_t login_time;
- guint8 unknown1[26];
- struct in_addr unknown_server1_ip;
- guint16 unknown_server1_port;
- struct in_addr unknown_server2_ip;
- guint16 unknown_server2_port;
- guint16 unknown2; /* 0x0001 */
- guint16 unknown3; /* 0x0000 */
- guint8 unknown4[32];
- guint8 unknown5[12];
- struct in_addr last_client_ip;
- time_t last_login_time;
- guint8 unknown6[8];
-};
-
-struct _qq_login_reply_redirect {
- guint8 result;
- guint32 uid;
- struct in_addr new_server_ip;
- guint16 new_server_port;
-};
-
/* generate a md5 key using uid and session_key */
static void get_session_md5(guint8 *session_md5, guint32 uid, guint8 *session_key)
{
@@ -151,53 +119,75 @@ static gint8 process_login_ok(PurpleConn
{
gint bytes;
qq_data *qd;
- qq_login_reply_ok_packet lrop;
+ struct {
+ guint8 result;
+ guint8 session_key[QQ_KEY_LENGTH];
+ guint32 uid;
+ struct in_addr client_ip; /* those detected by server */
+ guint16 client_port;
+ struct in_addr server_ip;
+ guint16 server_port;
+ time_t login_time;
+ guint8 unknown1[26];
+ struct in_addr unknown_server1_ip;
+ guint16 unknown_server1_port;
+ struct in_addr unknown_server2_ip;
+ guint16 unknown_server2_port;
+ guint16 unknown2; /* 0x0001 */
+ guint16 unknown3; /* 0x0000 */
+ guint8 unknown4[32];
+ guint8 unknown5[12];
+ struct in_addr last_client_ip;
+ time_t last_login_time;
+ guint8 unknown6[8];
+ } packet;
+
qd = (qq_data *) gc->proto_data;
/* FIXME, check QQ_LOGIN_REPLY_OK_PACKET_LEN here */
bytes = 0;
/* 000-000: reply code */
- bytes += qq_get8(&lrop.result, data + bytes);
+ bytes += qq_get8(&packet.result, data + bytes);
/* 001-016: session key */
- bytes += qq_getdata(lrop.session_key, sizeof(lrop.session_key), data + bytes);
+ bytes += qq_getdata(packet.session_key, sizeof(packet.session_key), data + bytes);
purple_debug_info("QQ", "Got session_key\n");
/* 017-020: login uid */
- bytes += qq_get32(&lrop.uid, data + bytes);
+ bytes += qq_get32(&packet.uid, data + bytes);
/* 021-024: server detected user public IP */
- bytes += qq_getIP(&lrop.client_ip, data + bytes);
+ bytes += qq_getIP(&packet.client_ip, data + bytes);
/* 025-026: server detected user port */
- bytes += qq_get16(&lrop.client_port, data + bytes);
+ bytes += qq_get16(&packet.client_port, data + bytes);
/* 027-030: server detected itself ip 127.0.0.1 ? */
- bytes += qq_getIP(&lrop.server_ip, data + bytes);
+ bytes += qq_getIP(&packet.server_ip, data + bytes);
/* 031-032: server listening port */
- bytes += qq_get16(&lrop.server_port, data + bytes);
+ bytes += qq_get16(&packet.server_port, data + bytes);
/* 033-036: login time for current session */
- bytes += qq_getime(&lrop.login_time, data + bytes);
+ bytes += qq_getime(&packet.login_time, data + bytes);
/* 037-062: 26 bytes, unknown */
- bytes += qq_getdata((guint8 *) &lrop.unknown1, 26, data + bytes);
+ bytes += qq_getdata((guint8 *) &packet.unknown1, 26, data + bytes);
/* 063-066: unknown server1 ip address */
- bytes += qq_getIP(&lrop.unknown_server1_ip, data + bytes);
+ bytes += qq_getIP(&packet.unknown_server1_ip, data + bytes);
/* 067-068: unknown server1 port */
- bytes += qq_get16(&lrop.unknown_server1_port, data + bytes);
+ bytes += qq_get16(&packet.unknown_server1_port, data + bytes);
/* 069-072: unknown server2 ip address */
- bytes += qq_getIP(&lrop.unknown_server2_ip, data + bytes);
+ bytes += qq_getIP(&packet.unknown_server2_ip, data + bytes);
/* 073-074: unknown server2 port */
- bytes += qq_get16(&lrop.unknown_server2_port, data + bytes);
+ bytes += qq_get16(&packet.unknown_server2_port, data + bytes);
/* 075-076: 2 bytes unknown */
- bytes += qq_get16(&lrop.unknown2, data + bytes);
+ bytes += qq_get16(&packet.unknown2, data + bytes);
/* 077-078: 2 bytes unknown */
- bytes += qq_get16(&lrop.unknown3, data + bytes);
+ bytes += qq_get16(&packet.unknown3, data + bytes);
/* 079-110: 32 bytes unknown */
- bytes += qq_getdata((guint8 *) &lrop.unknown4, 32, data + bytes);
+ bytes += qq_getdata((guint8 *) &packet.unknown4, 32, data + bytes);
/* 111-122: 12 bytes unknown */
- bytes += qq_getdata((guint8 *) &lrop.unknown5, 12, data + bytes);
+ bytes += qq_getdata((guint8 *) &packet.unknown5, 12, data + bytes);
/* 123-126: login IP of last session */
- bytes += qq_getIP(&lrop.last_client_ip, data + bytes);
+ bytes += qq_getIP(&packet.last_client_ip, data + bytes);
/* 127-130: login time of last session */
- bytes += qq_getime(&lrop.last_login_time, data + bytes);
+ bytes += qq_getime(&packet.last_login_time, data + bytes);
/* 131-138: 8 bytes unknown */
- bytes += qq_getdata((guint8 *) &lrop.unknown6, 8, data + bytes);
+ bytes += qq_getdata((guint8 *) &packet.unknown6, 8, data + bytes);
if (bytes != QQ_LOGIN_REPLY_OK_PACKET_LEN) { /* fail parsing login info */
purple_debug_warning("QQ",
@@ -205,15 +195,15 @@ static gint8 process_login_ok(PurpleConn
QQ_LOGIN_REPLY_OK_PACKET_LEN, bytes);
} /* but we still go on as login OK */
- memcpy(qd->session_key, lrop.session_key, sizeof(qd->session_key));
+ memcpy(qd->session_key, packet.session_key, sizeof(qd->session_key));
get_session_md5(qd->session_md5, qd->uid, qd->session_key);
- qd->my_ip.s_addr = lrop.client_ip.s_addr;
+ qd->my_ip.s_addr = packet.client_ip.s_addr;
- qd->my_port = lrop.client_port;
- qd->login_time = lrop.login_time;
- qd->last_login_time = lrop.last_login_time;
- qd->last_login_ip = g_strdup( inet_ntoa(lrop.last_client_ip) );
+ qd->my_port = packet.client_port;
+ qd->login_time = packet.login_time;
+ qd->last_login_time = packet.last_login_time;
+ qd->last_login_ip = g_strdup( inet_ntoa(packet.last_client_ip) );
return QQ_LOGIN_REPLY_OK;
}
@@ -223,35 +213,41 @@ static gint8 process_login_redirect(Purp
{
qq_data *qd;
gint bytes;
- qq_login_reply_redirect_packet lrrp;
+ struct {
+ guint8 result;
+ guint32 uid;
+ struct in_addr new_server_ip;
+ guint16 new_server_port;
+ } packet;
+
qd = (qq_data *) gc->proto_data;
bytes = 0;
/* 000-000: reply code */
- bytes += qq_get8(&lrrp.result, data + bytes);
+ bytes += qq_get8(&packet.result, data + bytes);
/* 001-004: login uid */
- bytes += qq_get32(&lrrp.uid, data + bytes);
+ bytes += qq_get32(&packet.uid, data + bytes);
/* 005-008: redirected new server IP */
- bytes += qq_getIP(&lrrp.new_server_ip, data + bytes);
+ bytes += qq_getIP(&packet.new_server_ip, data + bytes);
/* 009-010: redirected new server port */
- bytes += qq_get16(&lrrp.new_server_port, data + bytes);
+ bytes += qq_get16(&packet.new_server_port, data + bytes);
if (bytes != QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN) {
purple_debug_error("QQ",
"Fail parsing login redirect packet, expect %d bytes, read %d bytes\n",
QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN, bytes);
- return QQ_LOGIN_REPLY_ERR_MISC;
+ return QQ_LOGIN_REPLY_ERR;
}
/* redirect to new server, do not disconnect or connect here
* those connect should be called at packet_process */
- qd->redirect_ip.s_addr = lrrp.new_server_ip.s_addr;
- qd->redirect_port = lrrp.new_server_port;
+ qd->redirect_ip.s_addr = packet.new_server_ip.s_addr;
+ qd->redirect_port = packet.new_server_port;
return QQ_LOGIN_REPLY_REDIRECT;
}
/* request before login */
-void qq_send_packet_token(PurpleConnection *gc)
+void qq_request_token(PurpleConnection *gc)
{
qq_data *qd;
guint8 buf[16] = {0};
@@ -267,7 +263,7 @@ void qq_send_packet_token(PurpleConnecti
}
/* send login packet to QQ server */
-void qq_send_packet_login(PurpleConnection *gc)
+void qq_request_login(PurpleConnection *gc)
{
qq_data *qd;
guint8 *buf, *raw_data;
@@ -278,16 +274,8 @@ void qq_send_packet_login(PurpleConnecti
g_return_if_fail(gc != NULL && gc->proto_data != NULL);
qd = (qq_data *) gc->proto_data;
- g_return_if_fail(qd->token != NULL && qd->token_len > 0);
+ g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0);
-#ifdef DEBUG
- memset(qd->inikey, 0x01, sizeof(qd->inikey));
-#else
- for (bytes = 0; bytes < sizeof(qd->inikey); bytes++) {
- qd->inikey[bytes] = (guint8) (rand() & 0xff);
- }
-#endif
-
raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH);
memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH);
@@ -296,7 +284,7 @@ void qq_send_packet_login(PurpleConnecti
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->password_twice_md5);
+ encrypted_len = qq_encrypt(raw_data + bytes, (guint8 *) "", 0, qd->ld.pwd_twice_md5);
g_return_if_fail(encrypted_len == 16);
bytes += encrypted_len;
@@ -313,26 +301,26 @@ void qq_send_packet_login(PurpleConnecti
/* 053-068, fixed value, maybe related to per machine */
bytes += qq_putdata(raw_data + bytes, login_53_68, 16);
/* 069, login token length */
- bytes += qq_put8(raw_data + bytes, qd->token_len);
+ bytes += qq_put8(raw_data + bytes, qd->ld.token_len);
/* 070-093, login token, normally 24 bytes */
- bytes += qq_putdata(raw_data + bytes, qd->token, qd->token_len);
+ bytes += qq_putdata(raw_data + bytes, qd->ld.token, qd->ld.token_len);
/* 100 bytes unknown */
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->inikey);
+ encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key);
buf = g_newa(guint8, MAX_PACKET_SIZE);
memset(buf, 0, MAX_PACKET_SIZE);
bytes = 0;
- bytes += qq_putdata(buf + bytes, qd->inikey, QQ_KEY_LENGTH);
+ bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH);
bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len);
qd->send_seq++;
qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE);
}
-guint8 qq_process_token_reply(PurpleConnection *gc, guint8 *buf, gint buf_len)
+guint8 qq_process_token(PurpleConnection *gc, guint8 *buf, gint buf_len)
{
qq_data *qd;
guint8 ret;
@@ -346,7 +334,7 @@ guint8 qq_process_token_reply(PurpleConn
ret = buf[0];
- if (ret != QQ_TOKEN_REPLY_OK) {
+ if (ret != QQ_LOGIN_REPLY_OK) {
purple_debug_error("QQ", "Failed to request token: %d\n", buf[0]);
qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
buf, buf_len,
@@ -357,7 +345,7 @@ guint8 qq_process_token_reply(PurpleConn
}
purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg);
g_free(error_msg);
- return ret;
+ return QQ_LOGIN_REPLY_ERR;
}
token_len = buf_len-2;
@@ -365,7 +353,7 @@ guint8 qq_process_token_reply(PurpleConn
error_msg = g_strdup_printf( _("Invalid token len, %d"), token_len);
purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg);
g_free(error_msg);
- return -1;
+ return QQ_LOGIN_REPLY_ERR;
}
if (buf[1] != token_len) {
@@ -376,34 +364,39 @@ guint8 qq_process_token_reply(PurpleConn
buf+2, token_len,
"<<< got a token -> [default] decrypt and dump");
- qd->token = g_new0(guint8, token_len);
- qd->token_len = token_len;
- g_memmove(qd->token, buf + 2, qd->token_len);
+ if (qd->ld.token != NULL) {
+ g_free(qd->ld.token);
+ qd->ld.token = NULL;
+ qd->ld.token_len = 0;
+ }
+ qd->ld.token = g_new0(guint8, token_len);
+ qd->ld.token_len = token_len;
+ g_memmove(qd->ld.token, buf + 2, qd->ld.token_len);
return ret;
}
/* send logout packets to QQ server */
-void qq_send_packet_logout(PurpleConnection *gc)
+void qq_request_logout(PurpleConnection *gc)
{
gint i;
qq_data *qd;
qd = (qq_data *) gc->proto_data;
for (i = 0; i < 4; i++)
- qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->password_twice_md5, QQ_KEY_LENGTH);
+ qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->ld.pwd_twice_md5, QQ_KEY_LENGTH);
qd->is_login = FALSE; /* update login status AFTER sending logout packets */
}
/* process the login reply packet */
-guint8 qq_process_login_reply( PurpleConnection *gc, guint8 *data, gint data_len)
+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;
- g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR_MISC);
+ g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR);
qd = (qq_data *) gc->proto_data;
@@ -472,7 +465,7 @@ guint8 qq_process_login_reply( PurpleCon
}
/* send keep-alive packet to QQ server (it is a heart-beat) */
-void qq_send_packet_keep_alive(PurpleConnection *gc)
+void qq_request_keep_alive(PurpleConnection *gc)
{
qq_data *qd;
guint8 raw_data[16] = {0};
@@ -505,8 +498,8 @@ gboolean qq_process_keep_alive(guint8 *d
return TRUE;
/* segments[0] and segment[1] are all 0x30 ("0") */
- qd->total_online = strtol(segments[2], NULL, 10);
- if(0 == qd->total_online) {
+ qd->online_total = strtol(segments[2], NULL, 10);
+ if(0 == qd->online_total) {
purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
_("Keep alive error"));
}
@@ -519,3 +512,341 @@ gboolean qq_process_keep_alive(guint8 *d
g_strfreev(segments);
return TRUE;
}
+
+/* For QQ2007/2008 */
+void qq_request_get_server(PurpleConnection *gc)
+{
+ qq_data *qd;
+ guint8 *buf, *raw_data;
+ gint bytes;
+ guint8 *encrypted_data;
+ gint encrypted_len;
+
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+ qd = (qq_data *) gc->proto_data;
+
+ 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 */
+
+ 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);
+
+ 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);
+
+ 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)
+{
+ 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;
+ }
+
+ if (data_len < sizeof(qq_redirect_data)) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Can not decrypt get server reply"));
+ return QQ_LOGIN_REPLY_ERR;
+ }
+
+ redirect = (qq_redirect_data *)data;
+ if (redirect->ret == 0) {
+ memset(&qd->redirect_data, 0, sizeof(qd->redirect_data));
+ qd->redirect_ip.s_addr = 0;
+ return QQ_LOGIN_REPLY_OK;
+ }
+
+ g_memmove(&qd->redirect_data, redirect, sizeof(qd->redirect_data));
+ g_memmove(&qd->redirect_ip, &redirect->ip, sizeof(qd->redirect_ip));
+ return QQ_LOGIN_REPLY_REDIRECT;
+}
+
+void qq_request_token_ex(PurpleConnection *gc)
+{
+ qq_data *qd;
+ guint8 *buf, *raw_data;
+ gint bytes;
+ guint8 *encrypted_data;
+ gint encrypted_len;
+
+ 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_data = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */
+
+ bytes = 0;
+ bytes += qq_put8(raw_data + bytes, qd->ld.token_len);
+ bytes += qq_putdata(raw_data + bytes, qd->ld.token, qd->ld.token_len);
+ bytes += qq_put8(raw_data + bytes, 3); /* Subcommand */
+ bytes += qq_put16(raw_data + bytes, 5);
+ bytes += qq_put32(raw_data + bytes, 0);
+ 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);
+
+ 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);
+
+ qd->send_seq++;
+ qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
+}
+
+void qq_request_token_ex_next(PurpleConnection *gc)
+{
+ qq_data *qd;
+ guint8 *buf, *raw_data;
+ gint bytes;
+ guint8 *encrypted_data;
+ gint encrypted_len;
+
+ 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_data = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */
+
+ bytes = 0;
+ bytes += qq_put8(raw_data + bytes, qd->ld.token_len);
+ bytes += qq_putdata(raw_data + bytes, qd->ld.token, qd->ld.token_len);
+ bytes += qq_put8(raw_data + bytes, 3); /* Subcommand */
+ bytes += qq_put16(raw_data + bytes, 5);
+ bytes += qq_put32(raw_data + bytes, 0);
+ bytes += qq_put8(raw_data + bytes, qd->captcha.next_index); /* fragment index */
+ 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);
+
+ 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);
+
+ qd->send_seq++;
+ qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
+
+ purple_connection_update_progress(gc, _("Requesting captcha ..."), 3, QQ_CONNECT_STEPS);
+}
+
+static void request_token_ex_code(PurpleConnection *gc,
+ guint8 *token, guint16 token_len, guint8 *code, guint16 code_len)
+{
+ qq_data *qd;
+ guint8 *buf, *raw_data;
+ gint bytes;
+ guint8 *encrypted_data;
+ gint encrypted_len;
+
+ 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(code != NULL && code_len > 0);
+
+ 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 */
+
+ bytes = 0;
+ bytes += qq_put8(raw_data + bytes, qd->ld.token_len);
+ bytes += qq_putdata(raw_data + bytes, qd->ld.token, qd->ld.token_len);
+ bytes += qq_put8(raw_data + bytes, 4); /* Subcommand */
+ bytes += qq_put16(raw_data + bytes, 5);
+ 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);
+
+ encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_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);
+
+ qd->send_seq++;
+ qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE);
+
+ purple_connection_update_progress(gc, _("Checking code of captcha ..."), 3, QQ_CONNECT_STEPS);
+}
+
+typedef struct {
+ PurpleConnection *gc;
+ guint8 *token;
+ guint16 token_len;
+} qq_captcha_request;
+
+static void captcha_request_destory(qq_captcha_request *captcha_req)
+{
+ g_return_if_fail(captcha_req != NULL);
+ if (captcha_req->token) g_free(captcha_req->token);
+ g_free(captcha_req);
+}
+
+static void captcha_input_cancel_cb(qq_captcha_request *captcha_req,
+ PurpleRequestFields *fields)
+{
+ captcha_request_destory(captcha_req);
+
+ purple_connection_error_reason(captcha_req->gc,
+ PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
+ _("Failed captcha verify"));
+}
+
+static void captcha_input_ok_cb(qq_captcha_request *captcha_req,
+ PurpleRequestFields *fields)
+{
+ gchar *code;
+
+ g_return_if_fail(captcha_req != NULL && captcha_req->gc != NULL);
+
+ code = utf8_to_qq(
+ purple_request_fields_get_string(fields, "captcha_code"),
+ QQ_CHARSET_DEFAULT);
+
+ if (strlen(code) <= 0) {
+ captcha_input_cancel_cb(captcha_req, fields);
+ return;
+ }
+
+ request_token_ex_code(captcha_req->gc,
+ captcha_req->token, captcha_req->token_len,
+ (guint8 *)code, strlen(code));
+
+ captcha_request_destory(captcha_req);
+}
+
+void qq_captcha_input_dialog(PurpleConnection *gc,qq_captcha_data *captcha)
+{
+ PurpleAccount *account;
+ PurpleRequestFields *fields;
+ PurpleRequestFieldGroup *group;
+ PurpleRequestField *field;
+ qq_captcha_request *captcha_req;
+
+ g_return_if_fail(captcha->token != NULL && captcha->token_len > 0);
+ g_return_if_fail(captcha->data != NULL && captcha->data_len > 0);
+
+ captcha_req = g_new0(qq_captcha_request, 1);
+ captcha_req->gc = gc;
+ captcha_req->token = g_new0(guint8, captcha->token_len);
+ g_memmove(captcha_req->token, captcha->token, captcha->token_len);
+ captcha_req->token_len = captcha->token_len;
+
+ account = purple_connection_get_account(gc);
+
+ fields = purple_request_fields_new();
+ group = purple_request_field_group_new(NULL);
+ purple_request_fields_add_group(fields, group);
+
+ field = purple_request_field_image_new("captcha_img",
+ _("Captcha Image"), (char *)captcha->data, captcha->data_len);
+ purple_request_field_group_add_field(group, field);
+
+ field = purple_request_field_string_new("captcha_code",
+ _("Enter code"), "", FALSE);
+ purple_request_field_string_set_masked(field, FALSE);
+ purple_request_field_group_add_field(group, field);
+
+ purple_request_fields(account,
+ _("QQ Captcha Verifing"),
+ _("QQ Captcha Verifing"),
+ _("Please fill code according to image"),
+ fields,
+ _("OK"), G_CALLBACK(captcha_input_ok_cb),
+ _("Cancel"), G_CALLBACK(captcha_input_cancel_cb),
+ purple_connection_get_account(gc), NULL, NULL,
+ captcha_req);
+}
+
+guint8 qq_process_token_ex(PurpleConnection *gc, guint8 *buf, gint buf_len)
+{
+ qq_data *qd;
+ int bytes;
+ guint8 ret;
+ guint8 sub_cmd;
+ guint8 reply;
+ guint16 captcha_len;
+ guint8 curr_index;
+
+ g_return_val_if_fail(buf != NULL && buf_len != 0, -1);
+
+ g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1);
+ qd = (qq_data *) gc->proto_data;
+
+ ret = buf[0];
+
+ bytes = 0;
+ bytes += qq_get8(&sub_cmd, buf + bytes);
+ bytes += 2;
+ bytes += qq_get8(&reply, buf + bytes);
+
+ bytes += qq_get16(&(qd->ld.token_ex_len), buf + 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);
+
+ if(reply != 1)
+ {
+ purple_debug_info("QQ", "All captchaes is verified\n");
+ return QQ_LOGIN_REPLY_OK;
+ }
+
+ bytes += qq_get16(&captcha_len, buf + 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);
+ qd->captcha.data_len += captcha_len;
+
+ bytes += qq_get8(&curr_index, buf + bytes);
+ bytes += qq_get8(&qd->captcha.next_index, buf + bytes);
+
+ bytes += qq_get16(&qd->captcha.token_len, buf + bytes);
+ qd->captcha.token = g_new0(guint8, qd->captcha.token_len);
+ bytes += qq_getdata(qd->captcha.token, qd->captcha.token_len, buf + bytes);
+
+ if(qd->captcha.next_index > 0)
+ {
+ return QQ_LOGIN_REPLY_NEXT_TOKEN_EX;
+ }
+
+ return QQ_LOGIN_REPLY_CAPTCHA_DLG;
+}
============================================================
--- libpurple/protocols/qq/qq_base.h 1be7d89ee372ed31923b785525b7966caa34db3f
+++ libpurple/protocols/qq/qq_base.h ea7caf396b13c3400b8d302a782cef8aa3761425
@@ -28,29 +28,40 @@
#include <glib.h>
#include "connection.h"
-#define QQ_TOKEN_REPLY_OK 0x00
-
#define QQ_LOGIN_REPLY_OK 0x00
#define QQ_LOGIN_REPLY_REDIRECT 0x01
#define QQ_LOGIN_REPLY_ERR_PWD 0x05
#define QQ_LOGIN_REPLY_NEED_REACTIVE 0x06
#define QQ_LOGIN_REPLY_REDIRECT_EX 0x0A
-#define QQ_LOGIN_REPLY_ERR_MISC 0xff /* defined by myself */
+/* defined by myself */
+#define QQ_LOGIN_REPLY_CAPTCHA_DLG 0xfc
+#define QQ_LOGIN_REPLY_NEXT_TOKEN_EX 0xfd
+#define QQ_LOGIN_REPLY_ERR_DECRYPT 0xfe
+#define QQ_LOGIN_REPLY_ERR 0xff
-#define QQ_LOGIN_MODE_NORMAL 0x0a
-#define QQ_LOGIN_MODE_AWAY 0x1e
-#define QQ_LOGIN_MODE_HIDDEN 0x28
+#define QQ_LOGIN_MODE_NORMAL 0x0a
+#define QQ_LOGIN_MODE_AWAY 0x1e
+#define QQ_LOGIN_MODE_HIDDEN 0x28
#define QQ_UPDATE_ONLINE_INTERVAL 300 /* in sec */
-void qq_send_packet_token(PurpleConnection *gc);
-guint8 qq_process_token_reply(PurpleConnection *gc, guint8 *buf, gint buf_len);
+void qq_request_token(PurpleConnection *gc);
+guint8 qq_process_token(PurpleConnection *gc, guint8 *buf, gint buf_len);
-void qq_send_packet_login(PurpleConnection *gc);
-guint8 qq_process_login_reply( PurpleConnection *gc, guint8 *data, gint data_len);
+void qq_request_token_ex(PurpleConnection *gc);
+void qq_request_token_ex_next(PurpleConnection *gc);
+guint8 qq_process_token_ex(PurpleConnection *gc, guint8 *buf, gint buf_len);
+void qq_captcha_input_dialog(PurpleConnection *gc,qq_captcha_data *captcha);
-void qq_send_packet_logout(PurpleConnection *gc);
+void qq_request_login(PurpleConnection *gc);
+guint8 qq_process_login( PurpleConnection *gc, guint8 *data, gint data_len);
-void qq_send_packet_keep_alive(PurpleConnection *gc);
+void qq_request_logout(PurpleConnection *gc);
+
+void qq_request_keep_alive(PurpleConnection *gc);
gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc);
+
+/* for QQ2007 */
+void qq_request_get_server(PurpleConnection *gc);
+guint16 qq_process_get_server(PurpleConnection *gc, guint8 *rcved, gint rcved_len);
#endif
============================================================
--- libpurple/protocols/qq/qq_define.c 2a513cf15a10847e24922596fcd0d05c5f2412d2
+++ libpurple/protocols/qq/qq_define.c b0b876be933b82e32bcef47e673b4fabe5ab339a
@@ -1,5 +1,5 @@
/**
- * @file header_info.c
+ * @file qq_define.c
*
* purple
*
@@ -24,7 +24,7 @@
#include "internal.h"
-#include "header_info.h"
+#include "qq_define.h"
#define QQ_CLIENT_062E 0x062e /* GB QQ2000c build 0630 */
#define QQ_CLIENT_072E 0x072e /* EN QQ2000c build 0305 */
@@ -51,7 +51,6 @@
#define QQ_CLIENT_0F4B 0x0F4B /* QQ2006 Beta 3 */
#define QQ_CLIENT_1105 0x1105 /* QQ2007 beta4*/
-#define QQ_CLIENT_111D 0x111D /* QQ2007 */
#define QQ_CLIENT_115B 0x115B /* QQ2008 */
#define QQ_CLIENT_1203 0x1203 /* QQ2008 */
#define QQ_CLIENT_1205 0x1205 /* QQ2008 */
@@ -94,6 +93,7 @@ const gchar *qq_get_ver_desc(gint source
return "QQ2005 beta1";
case QQ_CLIENT_0D51:
return "QQ2005 beta2";
+ case QQ_CLIENT_0D55:
case QQ_CLIENT_0D61:
return "QQ2005";
case QQ_CLIENT_0E1B:
============================================================
--- libpurple/protocols/qq/qq_define.h 8241e8f0df57be7a021443c7796c1c249c539b5f
+++ libpurple/protocols/qq/qq_define.h 5048b85b1fc951d59bfc35da16f22c9f10cabfd2
@@ -1,5 +1,5 @@
/**
- * @file header_info.h
+ * @file qq_define.h
*
* purple
*
@@ -30,10 +30,11 @@
#define QQ_UDP_HEADER_LENGTH 7
#define QQ_TCP_HEADER_LENGTH 9
-#define QQ_PACKET_TAG 0x02 /* all QQ text packets starts with it */
-#define QQ_PACKET_TAIL 0x03 /* all QQ text packets end with it */
+#define QQ_PACKET_TAG 0x02 /* all QQ text packets starts with it */
+#define QQ_PACKET_TAIL 0x03 /* all QQ text packets end with it */
-#define QQ_CLIENT 0x0d55
+#define QQ_CLIENT_0D55 0x0d55 /* QQ2005 used by openq before */
+#define QQ_CLIENT_111D 0x111D /* QQ2007 */
const gchar *qq_get_ver_desc(gint source);
@@ -64,6 +65,13 @@ enum {
QQ_CMD_TOKEN = 0x0062, /* get login token */
QQ_CMD_RECV_MSG_SYS = 0x0080, /* receive a system message */
QQ_CMD_BUDDY_CHANGE_STATUS = 0x0081, /* buddy change status */
+ /* for QQ2007*/
+ QQ_CMD_GET_SERVER = 0x0091, /* select login server */
+ QQ_CMD_TOKEN_EX = 0x00BA, /* get LOGIN token */
+ QQ_CMD_CHECK_PWD = 0x00DD, /* Password verify */
+ QQ_CMD_GET_CAPTCHA = 0x00AE, /* the request verification of information */
+ QQ_CMD_BUDDY_ADD_NO_AUTH_EX = 0x00A7, /* add friend without auth */
+ QQ_CMD_BUDDY_ADD_AUTH_EX = 0x00A8, /* add buddy with auth */
};
const gchar *qq_get_cmd_desc(gint type);
============================================================
--- libpurple/protocols/qq/qq_network.c a8e9da018f66d0d8ce5641e76142356bb0cd03a3
+++ libpurple/protocols/qq/qq_network.c dbde8647a131927c84dbcbf99f73ea6a03605ca2
@@ -30,7 +30,7 @@
#include "group_info.h"
#include "group_free.h"
#include "qq_crypt.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "qq_base.h"
#include "buddy_list.h"
#include "packet_parse.h"
@@ -160,7 +160,7 @@ static gboolean connect_check(gpointer d
qd->connect_watcher = 0;
}
- if (qd->fd >= 0 && qd->token != NULL && qd->token_len >= 0) {
+ if (qd->fd >= 0 && qd->ld.token != NULL && qd->ld.token_len > 0) {
purple_debug_info("QQ", "Connect ok\n");
return FALSE;
}
@@ -228,6 +228,19 @@ gboolean qq_connect_later(gpointer data)
return FALSE; /* timeout callback stops */
}
+static void redirect_server(PurpleConnection *gc)
+{
+ qq_data *qd;
+ qd = (qq_data *) gc->proto_data;
+
+ if (qd->check_watcher > 0) {
+ purple_timeout_remove(qd->check_watcher);
+ qd->check_watcher = 0;
+ }
+ if (qd->connect_watcher > 0) purple_timeout_remove(qd->connect_watcher);
+ qd->connect_watcher = purple_timeout_add_seconds(QQ_CONNECT_INTERVAL, qq_connect_later, gc);
+}
+
/* process the incoming packet from qq_pending */
static gboolean packet_process(PurpleConnection *gc, guint8 *buf, gint buf_len)
{
@@ -242,6 +255,7 @@ static gboolean packet_process(PurpleCon
guint32 room_id;
gint update_class;
guint32 ship32;
+ int ret;
qq_transaction *trans;
@@ -292,20 +306,13 @@ static gboolean packet_process(PurpleCon
switch (cmd) {
case QQ_CMD_TOKEN:
- if (qq_process_token_reply(gc, buf + bytes, bytes_not_read) == QQ_TOKEN_REPLY_OK) {
- qq_send_packet_login(gc);
- }
- break;
+ case QQ_CMD_GET_SERVER:
case QQ_CMD_LOGIN:
- qq_proc_login_cmd(gc, buf + bytes, bytes_not_read);
- /* check is redirect or not, and do it now */
- if (qd->redirect_ip.s_addr != 0) {
- if (qd->check_watcher > 0) {
- purple_timeout_remove(qd->check_watcher);
- qd->check_watcher = 0;
+ ret = qq_proc_login_cmds(gc, cmd, seq, buf + bytes, bytes_not_read, update_class, ship32);
+ if (ret != QQ_LOGIN_REPLY_OK) {
+ if (ret == QQ_LOGIN_REPLY_REDIRECT) {
+ redirect_server(gc);
}
- if (qd->connect_watcher > 0) purple_timeout_remove(qd->connect_watcher);
- qd->connect_watcher = purple_timeout_add_seconds(QQ_CONNECT_INTERVAL, qq_connect_later, gc);
return FALSE; /* do nothing after this function and return now */
}
break;
@@ -316,10 +323,10 @@ static gboolean packet_process(PurpleCon
purple_debug_info("QQ", "%s (0x%02X) for room %d, len %d\n",
qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len);
#endif
- qq_proc_room_cmd(gc, seq, room_cmd, room_id, buf + bytes, bytes_not_read, update_class, ship32);
+ qq_proc_room_cmds(gc, seq, room_cmd, room_id, buf + bytes, bytes_not_read, update_class, ship32);
break;
default:
- qq_proc_client_cmd(gc, cmd, seq, buf + bytes, bytes_not_read, update_class, ship32);
+ qq_proc_client_cmds(gc, cmd, seq, buf + bytes, bytes_not_read, update_class, ship32);
break;
}
@@ -645,7 +652,7 @@ 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_send_packet_keep_alive(gc);
+ qq_request_keep_alive(gc);
return TRUE;
}
@@ -663,10 +670,9 @@ static gboolean network_timeout(gpointer
return TRUE; /* if return FALSE, timeout callback stops */
}
-static void do_request_token(PurpleConnection *gc)
+static void set_all_keys(PurpleConnection *gc)
{
qq_data *qd;
- gchar *conn_msg;
const gchar *passwd;
/* _qq_show_socket("Got login socket", source); */
@@ -682,24 +688,27 @@ static void do_request_token(PurpleConne
qd->channel = 1;
qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10);
+#ifdef DEBUG
+ memset(qd->ld.init_key, 0x01, sizeof(qd->ld.init_key));
+ memset(qd->ld.captcha_key, 0x02, sizeof(qd->ld.captcha_key));
+#else
+ for (bytes = 0; bytes < sizeof(qd->ld.init_key); bytes++) {
+ qd->ld.init_key[bytes] = (guint8) (rand() & 0xff);
+ }
+ for (bytes = 0; bytes < sizeof(qd->captcha_key); bytes++) {
+ qd->captcha_key[bytes] = (guint8) (rand() & 0xff);
+ }
+#endif
+
/* now generate md5 processed passwd */
passwd = purple_account_get_password(purple_connection_get_account(gc));
/* use twice-md5 of user password as session key since QQ 2003iii */
- qq_get_md5(qd->password_twice_md5, sizeof(qd->password_twice_md5),
+ qq_get_md5(qd->ld.pwd_twice_md5, sizeof(qd->ld.pwd_twice_md5),
(guint8 *)passwd, strlen(passwd));
- qq_get_md5(qd->password_twice_md5, sizeof(qd->password_twice_md5),
- qd->password_twice_md5, sizeof(qd->password_twice_md5));
+ qq_get_md5(qd->ld.pwd_twice_md5, sizeof(qd->ld.pwd_twice_md5),
+ qd->ld.pwd_twice_md5, sizeof(qd->ld.pwd_twice_md5));
- g_return_if_fail(qd->network_watcher == 0);
- qd->network_watcher = purple_timeout_add_seconds(qd->itv_config.resend, network_timeout, gc);
-
- /* Update the login progress status display */
- conn_msg = g_strdup_printf(_("Request token"));
- purple_connection_update_progress(gc, conn_msg, 2, QQ_CONNECT_STEPS);
- g_free(conn_msg);
-
- qq_send_packet_token(gc);
}
/* the callback function after socket is built
@@ -744,7 +753,19 @@ static void connect_cb(gpointer data, gi
conn->input_handler = purple_input_add(source, PURPLE_INPUT_READ, udp_pending, gc);
}
- do_request_token( gc );
+ g_return_if_fail(qd->network_watcher == 0);
+ qd->network_watcher = purple_timeout_add_seconds(qd->itv_config.resend, network_timeout, gc);
+
+ set_all_keys( gc );
+
+ if (qd->is_above_2007) {
+ purple_connection_update_progress(gc, _("Get server ..."), 2, QQ_CONNECT_STEPS);
+ qq_request_get_server(gc);
+ return;
+ }
+
+ purple_connection_update_progress(gc, _("Request token"), 2, QQ_CONNECT_STEPS);
+ qq_request_token(gc);
}
#ifndef purple_proxy_connect_udp
@@ -888,7 +909,6 @@ gboolean connect_to_server(PurpleConnect
{
PurpleAccount *account ;
qq_data *qd;
- gchar *conn_msg;
g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE);
account = purple_connection_get_account(gc);
@@ -900,9 +920,7 @@ gboolean connect_to_server(PurpleConnect
return FALSE;
}
- conn_msg = g_strdup_printf( _("Connecting server %s, retries %d"), server, port);
- purple_connection_update_progress(gc, conn_msg, 1, QQ_CONNECT_STEPS);
- g_free(conn_msg);
+ purple_connection_update_progress(gc, _("Connecting server ..."), 1, QQ_CONNECT_STEPS);
purple_debug_info("QQ", "Connect to %s:%d\n", server, port);
@@ -963,7 +981,7 @@ void qq_disconnect(PurpleConnection *gc)
/* finish all I/O */
if (qd->fd >= 0 && qd->is_login) {
- qq_send_packet_logout(gc);
+ qq_request_logout(gc);
}
/* not connected */
@@ -988,14 +1006,9 @@ void qq_disconnect(PurpleConnection *gc)
qq_trans_remove_all(gc);
- if (qd->token) {
- purple_debug_info("QQ", "free token\n");
- g_free(qd->token);
- qd->token = NULL;
- qd->token_len = 0;
- }
- memset(qd->inikey, 0, sizeof(qd->inikey));
- memset(qd->password_twice_md5, 0, sizeof(qd->password_twice_md5));
+ memset(qd->ld.init_key, 0, sizeof(qd->ld.init_key));
+ memset(qd->ld.captcha_key, 0, sizeof(qd->ld.captcha_key));
+ memset(qd->ld.pwd_twice_md5, 0, sizeof(qd->ld.pwd_twice_md5));
memset(qd->session_key, 0, sizeof(qd->session_key));
memset(qd->session_md5, 0, sizeof(qd->session_md5));
@@ -1019,7 +1032,7 @@ static gint packet_encap(qq_data *qd, gu
}
/* now comes the normal QQ packet as UDP */
bytes += qq_put8(buf + bytes, QQ_PACKET_TAG);
- bytes += qq_put16(buf + bytes, QQ_CLIENT);
+ bytes += qq_put16(buf + bytes, qd->client_version);
bytes += qq_put16(buf + bytes, cmd);
bytes += qq_put16(buf + bytes, seq);
============================================================
--- libpurple/protocols/qq/qq_process.c 587c83dd9bd715ffdc1da1e0a6cce725971355ef
+++ libpurple/protocols/qq/qq_process.c 3d29b82d408d5a9504ea576ebac6eed88032156e
@@ -42,7 +42,7 @@
#include "group_join.h"
#include "group_opt.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "qq_base.h"
#include "im.h"
#include "qq_process.h"
@@ -176,8 +176,7 @@ static void process_server_msg(guint8 *d
_qq_process_msg_sys_notice(gc, from, to, msg_utf8);
break;
case QQ_SERVER_NEW_CLIENT:
- purple_debug_warning("QQ",
- "QQ Server has newer client than %s\n", qq_get_ver_desc(QQ_CLIENT));
+ purple_debug_warning("QQ", "QQ Server has newer client version\n");
break;
default:
purple_debug_warning("QQ", "Recv unknown sys msg code: %s\nMsg: %s\n", code, msg_utf8);
@@ -407,6 +406,10 @@ void qq_update_online(PurpleConnection *
void qq_update_online(PurpleConnection *gc, guint16 cmd)
{
+ qq_data *qd;
+ g_return_if_fail (gc != NULL && gc->proto_data != NULL);
+ qd = (qq_data *) gc->proto_data;
+
switch (cmd) {
case 0:
qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ONLINE);
@@ -414,13 +417,14 @@ void qq_update_online(PurpleConnection *
case QQ_CMD_GET_BUDDIES_ONLINE:
/* last command */
update_all_rooms_online(gc, 0, 0);
+ qd->online_last_update = time(NULL);
break;
default:
break;
}
}
-void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
+void qq_proc_room_cmds(PurpleConnection *gc, guint16 seq,
guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len,
gint update_class, guint32 ship32)
{
@@ -567,55 +571,108 @@ void qq_proc_room_cmd(PurpleConnection *
}
}
-void qq_proc_login_cmd(PurpleConnection *gc, guint8 *rcved, gint rcved_len)
+guint8 qq_proc_login_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq,
+ guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32)
{
qq_data *qd;
- guint8 *data;
- gint data_len;
- guint ret_8;
+ guint8 *data = NULL;
+ gint data_len = 0;
+ guint ret_8 = QQ_LOGIN_REPLY_ERR;
- g_return_if_fail (gc != NULL && gc->proto_data != NULL);
+ g_return_val_if_fail (gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
qd = (qq_data *) gc->proto_data;
+ g_return_val_if_fail(rcved_len > 0, QQ_LOGIN_REPLY_ERR);
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->inikey);
- if (data_len >= 0) {
+
+ switch (cmd) {
+ case QQ_CMD_TOKEN:
+ if (qq_process_token(gc, rcved, rcved_len) == QQ_LOGIN_REPLY_OK) {
+ if (qd->is_above_2007) {
+ qq_request_token_ex(gc);
+ } else {
+ qq_request_login(gc);
+ }
+ return QQ_LOGIN_REPLY_OK;
+ }
+ return QQ_LOGIN_REPLY_ERR;
+ case QQ_CMD_GET_SERVER:
+ case QQ_CMD_TOKEN_EX:
+ data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.init_key);
+ break;
+ default:
+ /* 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_debug_warning("QQ", "Decrypt login packet by init_key, %d bytes\n", data_len);
+ } else {
+ 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 password_twice_md5, %d bytes\n", data_len);
+ }
+ }
+ break;
+ }
+
+ if (data_len < 0) {
purple_debug_warning("QQ",
- "Decrypt login reply packet with inikey, %d bytes\n", data_len);
- } else {
- data_len = qq_decrypt(data, rcved, rcved_len, qd->password_twice_md5);
- if (data_len >= 0) {
- purple_debug_warning("QQ",
- "Decrypt login reply packet with password_twice_md5, %d bytes\n", data_len);
- } else {
- purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ "Can not decrypt login cmd, [%05d], 0x%04X %s, len %d\n",
+ seq, cmd, qq_get_cmd_desc(cmd), rcved_len);
+ qq_show_packet("Can not decrypted", rcved, rcved_len);
+ purple_connection_error_reason(gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
_("Can not decrypt login reply"));
- return;
- }
+ return QQ_LOGIN_REPLY_ERR_DECRYPT;
}
- ret_8 = qq_process_login_reply(gc, data, data_len);
- if (ret_8 != QQ_LOGIN_REPLY_OK) {
- return;
- }
+ switch (cmd) {
+ case QQ_CMD_GET_SERVER:
+ ret_8 = qq_process_get_server(gc, data, data_len);
+ if ( ret_8 == QQ_LOGIN_REPLY_OK) {
+ qq_request_token(gc);
+ } else if ( ret_8 == QQ_LOGIN_REPLY_REDIRECT) {
+ return QQ_LOGIN_REPLY_REDIRECT;
+ }
+ break;
+ case QQ_CMD_TOKEN_EX:
+ ret_8 = qq_process_token_ex(gc, data, data_len);
+ if (ret_8 == QQ_LOGIN_REPLY_OK) {
+ //qq_request_check_password(gc);
+ } else if (ret_8 == QQ_LOGIN_REPLY_NEXT_TOKEN_EX) {
+ qq_request_token_ex_next(gc);
+ } else if (ret_8 == QQ_LOGIN_REPLY_CAPTCHA_DLG) {
+ qq_captcha_input_dialog(gc, &(qd->captcha));
+ g_free(qd->captcha.token);
+ g_free(qd->captcha.data);
+ memset(&qd->captcha, 0, sizeof(qd->captcha));
+ }
+ break;
+ case QQ_CMD_LOGIN:
+ ret_8 = qq_process_login(gc, data, data_len);
+ if (ret_8 != QQ_LOGIN_REPLY_OK) {
+ return ret_8;
+ }
- purple_debug_info("QQ", "Login repliess OK; everything is fine\n");
+ 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 */
- purple_connection_set_state(gc, PURPLE_CONNECTED);
- qd->is_login = TRUE; /* must be defined after sev_finish_login */
+ /* now initiate QQ Qun, do it first as it may take longer to finish */
+ qq_group_init(gc);
- /* now initiate QQ Qun, do it first as it may take longer to finish */
- qq_group_init(gc);
+ /* is_login, but we have packets before login */
+ qq_trans_process_remained(gc);
- /* is_login, but we have packets before login */
- qq_trans_process_remained(gc);
-
- qq_update_all(gc, 0);
- return;
+ qq_update_all(gc, 0);
+ break;
+ default:
+ process_cmd_unknow(gc, _("Unknow LOGIN CMD"), data, data_len, cmd, seq);
+ return QQ_LOGIN_REPLY_ERR;
+ }
+ return QQ_LOGIN_REPLY_OK;
}
-void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq,
+void qq_proc_client_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq,
guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32)
{
qq_data *qd;
@@ -710,7 +767,7 @@ void qq_proc_client_cmd(PurpleConnection
purple_debug_info("QQ", "All buddies and groups received\n");
break;
default:
- process_cmd_unknow(gc, _("Unknow reply CMD"), data, data_len, cmd, seq);
+ process_cmd_unknow(gc, _("Unknow CLIENT CMD"), data, data_len, cmd, seq);
is_unknow = TRUE;
break;
}
============================================================
--- libpurple/protocols/qq/qq_process.h 8c9135998e632d7d4b13a3373fde6fee15053896
+++ libpurple/protocols/qq/qq_process.h 785653af694fe209081308333c2cb8f5a8065bbc
@@ -38,10 +38,11 @@ enum {
QQ_CMD_CLASS_UPDATE_ROOM,
};
-void qq_proc_login_cmd(PurpleConnection *gc, guint8 *rcved, gint rcved_len);
-void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq,
+guint8 qq_proc_login_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq,
guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32);
-void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
+void qq_proc_client_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq,
+ guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32);
+void qq_proc_room_cmds(PurpleConnection *gc, guint16 seq,
guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len,
gint update_class, guint32 ship32);
============================================================
--- libpurple/protocols/qq/qq_trans.c f513eebd952e6d6aaefa38b76dbc42f2bca7f3a5
+++ libpurple/protocols/qq/qq_trans.c 685b1c333f6f5f72e93b6572a0eabb6c5f7f98bf
@@ -30,7 +30,7 @@
#include "prefs.h"
#include "request.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "qq_network.h"
#include "qq_process.h"
#include "qq_trans.h"
============================================================
--- libpurple/protocols/qq/send_file.c 9e43dc2a0a6cb55e09ba358583550243846eec45
+++ libpurple/protocols/qq/send_file.c 591962a2446a469711b3abaf0c80d7a4b76faf81
@@ -31,7 +31,7 @@
#include "buddy_list.h"
#include "file_trans.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "im.h"
#include "qq_base.h"
#include "packet_parse.h"
@@ -54,8 +54,8 @@ static int _qq_in_same_lan(ft_info *info
static int _qq_in_same_lan(ft_info *info)
{
if (info->remote_internet_ip == info->local_internet_ip) return 1;
- purple_debug_info("QQ",
- "Not in the same LAN, remote internet ip[%x], local internet ip[%x]\n",
+ purple_debug_info("QQ",
+ "Not in the same LAN, remote internet ip[%x], local internet ip[%x]\n",
info->remote_internet_ip
, info->local_internet_ip);
return 0;
@@ -87,7 +87,7 @@ static ssize_t _qq_xfer_udp_recv(guint8
info = (ft_info *) xfer->data;
sinlen = sizeof(sin);
r = recvfrom(info->recv_fd, buf, len, 0, (struct sockaddr *) &sin, &sinlen);
- purple_debug_info("QQ",
+ purple_debug_info("QQ",
"==> recv %d bytes from File UDP Channel, remote ip[%s], remote port[%d]\n",
r, inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
return r;
@@ -301,7 +301,7 @@ static gint _qq_create_packet_file_heade
/* 004-007: sender uid */
bytes += qq_put32 (raw_data + bytes, to_uid);
/* 008-009: sender client version */
- bytes += qq_put16 (raw_data + bytes, QQ_CLIENT);
+ bytes += qq_put16 (raw_data + bytes, qd->client_version);
/* 010-013: receiver uid */
bytes += qq_put32 (raw_data + bytes, qd->uid);
/* 014-017: sender uid */
@@ -380,7 +380,7 @@ static void _qq_xfer_init_socket(PurpleX
static void _qq_xfer_init_socket(PurpleXfer *xfer)
{
- gint sockfd, listen_port = 0, i;
+ gint sockfd, listen_port = 0, i;
socklen_t sin_len;
struct sockaddr_in sin;
ft_info *info;
@@ -389,7 +389,7 @@ static void _qq_xfer_init_socket(PurpleX
g_return_if_fail(xfer->data != NULL);
info = (ft_info *) xfer->data;
- /* debug
+ /* debug
info->local_real_ip = 0x7f000001;
*/
info->local_real_ip = g_ntohl(inet_addr(purple_network_get_my_ip(-1)));
@@ -460,7 +460,7 @@ static void _qq_send_packet_file_request
raw_data = g_newa(guint8, packet_len);
bytes = 0;
- bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid,
+ bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid,
QQ_FILE_TRANS_REQ, qd, FALSE);
bytes += qq_fill_conn_info(raw_data + bytes, info);
/* 079: 0x20 */
@@ -682,7 +682,7 @@ static void _qq_xfer_recv_init(PurpleXfe
}
/* process reject im for file transfer request */
-void qq_process_recv_file_reject (guint8 *data, gint data_len,
+void qq_process_recv_file_reject (guint8 *data, gint data_len,
guint32 sender_uid, PurpleConnection *gc)
{
gchar *msg, *filename;
@@ -711,7 +711,7 @@ void qq_process_recv_file_reject (guint8
}
/* process cancel im for file transfer request */
-void qq_process_recv_file_cancel (guint8 *data, gint data_len,
+void qq_process_recv_file_cancel (guint8 *data, gint data_len,
guint32 sender_uid, PurpleConnection *gc)
{
gchar *msg, *filename;
@@ -785,7 +785,7 @@ void qq_process_recv_file_request(guint8
info->local_internet_port = qd->my_port;
info->local_real_ip = 0x00000000;
info->to_uid = sender_uid;
-
+
if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) {
purple_debug_warning("QQ", "Received file request message is empty\n");
return;
@@ -822,18 +822,18 @@ void qq_process_recv_file_request(guint8
q_bud->status = QQ_BUDDY_ONLINE_INVISIBLE;
qq_update_buddy_contact(gc, q_bud);
}
- else
+ else
purple_debug_info("QQ", "buddy %d is already online\n", sender_uid);
}
- else
+ else
purple_debug_warning("QQ", "buddy %d is not in list\n", sender_uid);
- g_free(sender_name);
+ g_free(sender_name);
g_strfreev(fileinfo);
return;
}
-
+
xfer = purple_xfer_new(purple_connection_get_account(gc),
PURPLE_XFER_RECEIVE,
sender_name);
@@ -875,7 +875,7 @@ static void _qq_xfer_send_notify_ip_ack(
*/
}
-void qq_process_recv_file_notify(guint8 *data, gint data_len,
+void qq_process_recv_file_notify(guint8 *data, gint data_len,
guint32 sender_uid, PurpleConnection *gc)
{
gint bytes;
@@ -892,7 +892,7 @@ void qq_process_recv_file_notify(guint8
purple_debug_warning("QQ", "Received file notify message is empty\n");
return;
}
-
+
bytes = 0;
bytes += qq_get16(&(info->send_seq), data + bytes);
More information about the Commits
mailing list