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