# HG changeset patch # User SHiNE CsyFeK # Date 1221447563 0 # Node ID 967344bc404d3440c471565e64cafa8e501c9fc3 # Parent 5f454b975a9975f098350d3e262bba015e2ea1e1 applied changes from f12c8903079425d7850fa183df0b3f937b2952be through 8cebefbc6cd5d84acb69c74e69e8821f11dd225d Backport of 8cebefbc6cd5d84acb69c74e69e8821f11dd225d to avoid having other changes overwritten. 2008.08.16 - ccpaging * Rename group to room. If you used pidginqq before, this may create a new room with same title, you may delete old one * Replace purple_debug with purple_debug_info, purple_debug_warning, purple_debug_error * Add server notice and server new, and two options to turn on/off * Minor modify for reducing transaction's debug infor * Minor modifies for system notice and QQ news. * Add 4 new strings need translate compare with p10. committer: Daniel Atallah diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/AUTHORS --- a/libpurple/protocols/qq/AUTHORS Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/AUTHORS Mon Sep 15 02:59:23 2008 +0000 @@ -1,35 +1,38 @@ Code Contributors -===== -puzzlebird : original author -gfhuang : patches for libpurple 2.0.0beta2, maintainer -henryouly : file transfer, udp sock5 proxy and qq_show, maintainer -hzhr : maintainer -joymarquis : maintainer -arfankai : fixed bugs in char_conv.c -rakescar : provided filter for HTML tag -yyw : improved performance on PPC linux -lvxiang : provided ip to location original code -markhuetsch : OpenQ merge into libpurple, maintainer 2006-2007 -ccpaging : maintainer since 2007 -icesky : maintainer since 2007 -csyfek : faces, maintainer since 2007 +========= +puzzlebird : original author +gfhuang : patches for libpurple 2.0.0beta2, maintainer +Yuan Qingyun : patches for libpurple 1.5.0, maintainer +henryouly : file transfer, udp sock5 proxy and qq_show, maintainer +hzhr : maintainer +joymarquis : maintainer +arfankai : fixed bugs in char_conv.c +rakescar : provided filter for HTML tag +yyw : improved performance on PPC linux +lvxiang : provided ip to location original code +markhuetsch : OpenQ merge into libpurple, maintainer 2006-2007 +ccpaging : maintainer since 2007 +icesky : maintainer since 2007 +csyfek : faces, maintainer since 2007 Lovely Patch Writers -===== -gnap : message displaying, documentation -manphiz : qun processing -moo : qun processing -Coly Li : qun processing +========= +gnap : message displaying, documentation +manphiz : qun processing +moo : qun processing +Coly Li : qun processing +Emil Alexiev : captcha verification on login based on LumaQQ for MAC (2007), + login, add buddy, remove buddy, message exchange and logout Acknowledgement -===== -Shufeng Tan : http://sf.net/projects/perl-oicq -Jeff Ye : http://www.sinomac.com -Hu Zheng : http://forlinux.yeah.net -yunfan : http://www.myswear.net +========= +Shufeng Tan : http://sf.net/projects/perl-oicq +Jeff Ye : http://www.sinomac.com +Hu Zheng : http://forlinux.yeah.net +yunfan : http://www.myswear.net +OpenQ Team : http://openq.linuxsir.org +LumaQQ Team : http://lumaqq.linuxsir.org khc@pidgin.im qulogic@pidgin.im rlaager@pidgin.im -OpenQ Team -LumaQQ Team -OpenQ Google Group +OpenQ Google Group : http://groups.google.com/group/openq diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/ChangeLog --- a/libpurple/protocols/qq/ChangeLog Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/ChangeLog Mon Sep 15 02:59:23 2008 +0000 @@ -1,6 +1,17 @@ +2008.08.16 - ccpaging + * Rename group to room. If you used pidginqq before, this may create a new room with same title, you may delete old one + * Replace purple_debug with purple_debug_info, purple_debug_warning, purple_debug_error + * Add server notice and server new, and two options to turn on/off + * Minor modify for reducing transaction's debug infor + * Minor modifies for system notice and QQ news. + * Add 4 new strings need translate compare with p10. + 2008.08.10 - csyfek * Commit to Pidgin +2008.08.07 - ccpaging + * Support managing multi-connections according to simple.c + 2008.08.06 - ccpaging * Rename names of variables, Group, to Room * Functions of group_network merged into qq_network and qq_process diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/buddy_info.c --- a/libpurple/protocols/qq/buddy_info.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Mon Sep 15 02:59:23 2008 +0000 @@ -284,7 +284,7 @@ qd = (qq_data *) gc->proto_data; g_snprintf(uid_str, sizeof(uid_str), "%d", uid); - qq_send_cmd(qd, QQ_CMD_GET_USER_INFO, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_GET_USER_INFO, (guint8 *) uid_str, strlen(uid_str)); query = g_new0(qq_info_query, 1); query->uid = uid; @@ -293,6 +293,20 @@ qd->info_query = g_list_append(qd->info_query, query); } +void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, + gint update_class, guint32 ship32) +{ + qq_data *qd; + gchar raw_data[16] = {0}; + + g_return_if_fail(uid != 0); + + qd = (qq_data *) gc->proto_data; + g_snprintf(raw_data, sizeof(raw_data), "%d", uid); + qq_send_cmd_mess(gc, QQ_CMD_GET_USER_INFO, (guint8 *) raw_data, strlen(raw_data), + update_class, ship32); +} + /* set up the fields requesting personal information and send a get_info packet * for myself */ void qq_prepare_modify_info(PurpleConnection *gc) @@ -314,7 +328,6 @@ /* 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; @@ -446,7 +459,7 @@ bytes += qq_put8(raw_data + bytes, bar); - qq_send_cmd(qd, QQ_CMD_UPDATE_INFO, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_UPDATE_INFO, raw_data, bytes); } @@ -697,8 +710,8 @@ data[data_len] = '\0'; if (qd->uid == atoi((gchar *) data)) { /* return should be my uid */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Update info ACK OK\n"); - purple_notify_info(gc, NULL, _("Your information has been updated"), NULL); + purple_debug_info("QQ", "Update info ACK OK\n"); + purple_notify_info(gc, NULL, _("My information has been updated"), NULL); } } @@ -762,7 +775,7 @@ && g_ascii_strncasecmp(icon_path + dir_len + 1 + prefix_len + icon_len, QQ_ICON_SUFFIX, suffix_len) == 0 && icon_len <= 3)) { if (icon_global) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", errmsg); + purple_debug_error("QQ", "%s\n", errmsg); else purple_notify_error(gc, _("Invalid QQ Face"), errmsg, NULL); g_free(errmsg); @@ -775,7 +788,7 @@ /* ensure face number in proper range */ if (icon_num > QQ_FACES) { if (icon_global) - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", errmsg); + purple_debug_error("QQ", "%s\n", errmsg); else purple_notify_error(gc, _("Invalid QQ Face"), errmsg, NULL); g_free(errmsg); @@ -902,19 +915,21 @@ void qq_info_query_free(qq_data *qd) { - gint i; + gint count; qq_info_query *p; g_return_if_fail(qd != NULL); - i = 0; + count = 0; while (qd->info_query != NULL) { p = (qq_info_query *) (qd->info_query->data); qd->info_query = g_list_remove(qd->info_query, p); g_free(p); - i++; + count++; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d info queries are freed!\n", i); + if (count > 0) { + purple_debug_info("QQ", "%d info queries are freed!\n", count); + } } void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid) @@ -927,10 +942,10 @@ bytes += qq_put32(buf + bytes, uid); qd = (qq_data *) gc->proto_data; - qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, bytes); + qq_send_cmd(gc, QQ_CMD_GET_LEVEL, buf, bytes); } -void qq_send_packet_get_buddies_levels(PurpleConnection *gc) +void qq_request_get_buddies_levels(PurpleConnection *gc, gint update_class) { guint8 *buf; guint16 size; @@ -942,12 +957,11 @@ if ( qd->buddies == NULL) { return; } - /* server only sends back levels for online buddies, no point - * in asking for anyone else */ - size = 4 * g_list_length(qd->buddies) + 1; + /* server only reply levels for online buddies */ + size = 4 * g_list_length(qd->buddies) + 1 + 4; buf = g_newa(guint8, size); bytes += qq_put8(buf + bytes, 0x00); - + while (NULL != node) { q_bud = (qq_buddy *) node->data; if (NULL != q_bud) { @@ -955,7 +969,10 @@ } node = node->next; } - qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, size); + + /* my id should be the end if included */ + bytes += qq_put32(buf + bytes, qd->uid); + qq_send_cmd_mess(gc, QQ_CMD_GET_LEVEL, buf, size, update_class, 0); } void qq_process_get_level_reply(guint8 *decr_buf, gint decr_len, PurpleConnection *gc) @@ -970,9 +987,9 @@ qq_data *qd = (qq_data *) gc->proto_data; gint bytes = 0; - decr_len--; + decr_len--; if (decr_len % 12 != 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Get levels list of abnormal length. Truncating last %d bytes.\n", decr_len % 12); decr_len -= (decr_len % 12); } @@ -980,19 +997,18 @@ bytes += 1; /* this byte seems random */ /* - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Byte one of get_level packet: %d\n", buf[0]); + purple_debug_info("QQ", "Byte one of get_level packet: %d\n", buf[0]); */ for (i = 0; i < decr_len; i += 12) { bytes += qq_get32(&uid, decr_buf + bytes); bytes += qq_get32(&onlineTime, decr_buf + bytes); bytes += qq_get16(&level, decr_buf + bytes); bytes += qq_get16(&timeRemainder, decr_buf + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ_LEVEL", - "%d, tmOnline: %d, level: %d, tmRemainder: %d\n", + purple_debug_info("QQ_LEVEL", "%d, tmOnline: %d, level: %d, tmRemainder: %d\n", uid, onlineTime, level, timeRemainder); if (uid == qd->uid) { qd->my_level = level; - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Got my levels as %d\n", qd->my_level); + purple_debug_warning("QQ", "Got my levels as %d\n", qd->my_level); continue; } @@ -1000,7 +1016,7 @@ if (purple_name == NULL) { continue; } - + b = purple_find_buddy(account, purple_name); g_free(purple_name); @@ -1008,10 +1024,9 @@ if (b != NULL) { q_bud = (qq_buddy *) b->proto_data; } - + if (q_bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Got levels of %d not in my buddy list\n", uid); + purple_debug_error("QQ", "Got levels of %d not in my buddy list\n", uid); continue; } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/buddy_info.h --- a/libpurple/protocols/qq/buddy_info.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Mon Sep 15 02:59:23 2008 +0000 @@ -51,14 +51,14 @@ #define QQ_FRIEND_FLAG_MOBILE 0x10 #define QQ_FRIEND_FLAG_BIND_MOBILE 0x20 */ -#define QQ_COMM_FLAG_QQ_MEMBER 0x02 -#define QQ_COMM_FLAG_QQ_VIP 0x04 +#define QQ_COMM_FLAG_QQ_VIP 0x02 +#define QQ_COMM_FLAG_QQ_MEMBER 0x04 #define QQ_COMM_FLAG_TCP_MODE 0x10 #define QQ_COMM_FLAG_MOBILE 0x20 #define QQ_COMM_FLAG_BIND_MOBILE 0x40 #define QQ_COMM_FLAG_VIDEO 0x80 -#define QQ_EXT_FLAG_SPACE 0x02 +#define QQ_EXT_FLAG_ZONE 0x02 #define QQ_BUDDY_GENDER_GG 0x00 #define QQ_BUDDY_GENDER_MM 0x01 @@ -67,7 +67,15 @@ #define QQ_ICON_PREFIX "qq_" #define QQ_ICON_SUFFIX ".png" +enum { + QQ_BUDDY_INFO_UPDATE_ONLY = 0, + QQ_BUDDY_INFO_DISPLAY, + QQ_BUDDY_INFO_MODIFY, +}; + void qq_send_packet_get_info(PurpleConnection *gc, guint32 uid, gboolean show_window); +void qq_request_buddy_info(PurpleConnection *gc, guint32 uid, + gint update_class, guint32 ship32); void qq_set_my_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); void qq_set_buddy_icon_for_user(PurpleAccount *account, const gchar *who, const gchar *icon_num, const gchar *iconfile); void qq_prepare_modify_info(PurpleConnection *gc); @@ -75,6 +83,6 @@ void qq_process_get_info_reply(guint8 *data, gint data_len, PurpleConnection *gc); void qq_info_query_free(qq_data *qd); void qq_send_packet_get_level(PurpleConnection *gc, guint32 uid); -void qq_send_packet_get_buddies_levels(PurpleConnection *gc); +void qq_request_get_buddies_levels(PurpleConnection *gc, gint update_class); void qq_process_get_level_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); #endif diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Mon Sep 15 02:59:23 2008 +0000 @@ -56,7 +56,7 @@ } qq_buddy_online; /* get a list of online_buddies */ -void qq_send_packet_get_buddies_online(PurpleConnection *gc, guint8 position) +void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, gint update_class) { qq_data *qd; guint8 *raw_data; @@ -77,15 +77,14 @@ /* 003-004 */ bytes += qq_put16(raw_data + bytes, 0x0000); - qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_ONLINE, raw_data, 5); + 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, +/* position starts with 0x0000, * 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) +void qq_request_get_buddies_list(PurpleConnection *gc, guint16 position, gint update_class) { - qq_data *qd = (qq_data *) gc->proto_data; guint8 raw_data[16] = {0}; gint bytes = 0; @@ -98,13 +97,12 @@ * March 22, found the 00,00,00 starts to work as well */ bytes += qq_put8(raw_data + bytes, 0x00); - qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_LIST, raw_data, bytes); + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_LIST, raw_data, bytes, update_class, 0); } /* get all list, buddies & Quns with groupsid support */ -void qq_send_packet_get_buddies_and_rooms(PurpleConnection *gc, guint32 position) +void qq_request_get_buddies_and_rooms(PurpleConnection *gc, guint32 position, gint update_class) { - qq_data *qd = (qq_data *) gc->proto_data; guint8 raw_data[16] = {0}; gint bytes = 0; @@ -116,7 +114,7 @@ bytes += qq_put32(raw_data + bytes, 0x00000000); bytes += qq_put32(raw_data + bytes, position); - qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_AND_ROOMS, raw_data, bytes); + qq_send_cmd_mess(gc, QQ_CMD_GET_BUDDIES_AND_ROOMS, raw_data, bytes, update_class, 0); } /* parse the data into qq_buddy_status */ @@ -146,8 +144,8 @@ /* 015-030: unknown key */ bytes += qq_getdata(&(bs->unknown_key[0]), QQ_KEY_LENGTH, data + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ_STATUS", - "uid: %d, U1: %d, ip: %s:%d, U2:%d, status:%d, U3:%04X\n", + purple_debug_info("QQ_STATUS", + "uid: %d, U1: %d, ip: %s:%d, U2:%d, status:%d, U3:%04X\n", bs->uid, bs->unknown1, inet_ntoa(bs->ip), bs->port, bs->unknown2, bs->status, bs->unknown3); @@ -180,13 +178,12 @@ count = 0; while (bytes < data_len) { if (data_len - bytes < QQ_ONLINE_BUDDY_ENTRY_LEN) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "[buddies online] only %d, need %d", + purple_debug_error("QQ", "[buddies online] only %d, need %d", (data_len - bytes), QQ_ONLINE_BUDDY_ENTRY_LEN); break; } memset(&bo, 0 ,sizeof(bo)); - + /* set flag */ bytes_buddy = bytes; /* based on one online buddy entry */ @@ -204,31 +201,29 @@ bytes += qq_get8(&bo.ending, data + bytes); /* 0x00 */ if (bo.bs.uid == 0 || (bytes - bytes_buddy) != QQ_ONLINE_BUDDY_ENTRY_LEN) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "uid=0 or entry complete len(%d) != %d", + purple_debug_error("QQ", "uid=0 or entry complete len(%d) != %d", (bytes - bytes_buddy), QQ_ONLINE_BUDDY_ENTRY_LEN); continue; } /* check if it is a valid entry */ if (bo.bs.uid == qd->uid) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "I am in online list %d\n", bo.bs.uid); + purple_debug_warning("QQ", "I am in online list %d\n", bo.bs.uid); continue; } /* update buddy information */ purple_name = uid_to_purple_name(bo.bs.uid); if (purple_name == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Got an online buddy %d, but not find purple name\n", bo.bs.uid); continue; } b = purple_find_buddy(purple_connection_get_account(gc), purple_name); g_free(purple_name); - + q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Got an online buddy %d, but not in my buddy list\n", bo.bs.uid); continue; } @@ -247,11 +242,11 @@ } if(bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d online buddies, nextposition=%u\n", + purple_debug_info("QQ", "Received %d online buddies, nextposition=%u\n", count, (guint) position); return position; } @@ -274,7 +269,7 @@ qd = (qq_data *) gc->proto_data; if (data_len <= 2) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "empty buddies list"); + purple_debug_error("QQ", "empty buddies list"); return -1; } /* qq_show_packet("QQ get buddies list", data, data_len); */ @@ -305,7 +300,7 @@ bytes_expected = 12 + pascal_len; if (q_bud->uid == 0 || (bytes - buddy_bytes) != bytes_expected) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Buddy entry, expect %d bytes, read %d bytes\n", bytes_expected, bytes - buddy_bytes); g_free(q_bud->nickname); g_free(q_bud); @@ -315,7 +310,7 @@ } #if 1 - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "buddy [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", q_bud->uid, q_bud->ext_flag, q_bud->comm_flag, q_bud->nickname); #endif @@ -334,11 +329,11 @@ } if(bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d buddies, nextposition=%u\n", + purple_debug_info("QQ", "Received %d buddies, nextposition=%u\n", count, (guint) position); return position; } @@ -364,8 +359,7 @@ bytes += qq_get8(&reply_code, data + bytes); if(0 != reply_code) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "qq_process_get_buddies_and_rooms, %d", reply_code); + purple_debug_warning("QQ", "qq_process_get_buddies_and_rooms, %d", reply_code); } bytes += qq_get32(&unknown, data + bytes); @@ -381,48 +375,45 @@ /* 05: groupid*4 */ /* seems to always be 0 */ bytes += qq_get8(&groupid, data + bytes); /* - purple_debug(PURPLE_DEBUG_INFO, "QQ", "groupid: %i\n", groupid); + purple_debug_info("QQ", "groupid: %i\n", groupid); groupid >>= 2; */ if (uid == 0 || (type != 0x1 && type != 0x4)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Buddy entry, uid=%d, type=%d", uid, type); + purple_debug_info("QQ", "Buddy entry, uid=%d, type=%d", uid, type); continue; - } + } if(0x1 == type) { /* a buddy */ - /* don't do anything but count - buddies are handled by - * qq_send_packet_get_buddies_list */ + /* don't do anything but count - buddies are handled by + * qq_request_get_buddies_list */ ++i; } else { /* a group */ group = qq_room_search_id(gc, uid); if(group == NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Not find room id %d in qq_process_get_buddies_and_rooms\n", uid); qq_set_pending_id(&qd->adding_groups_from_server, uid, TRUE); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, uid); } else { - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); } ++j; } } if(bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "qq_process_get_buddies_and_rooms: Dangerous error! maybe protocol changed, notify developers!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Received %d buddies and %d groups, nextposition=%u\n", i, j, (guint) position); + purple_debug_info("QQ", "Received %d buddies and %d groups, nextposition=%u\n", i, j, (guint) position); return position; } #define QQ_MISC_STATUS_HAVING_VIIDEO 0x00000001 #define QQ_CHANGE_ONLINE_STATUS_REPLY_OK 0x30 /* ASCII value of "0" */ -/* TODO: figure out what's going on with the IP region. Sometimes I get valid IP addresses, - * but the port number's weird, other times I get 0s. I get these simultaneously on the same buddy, +/* TODO: figure out what's going on with the IP region. Sometimes I get valid IP addresses, + * but the port number's weird, other times I get 0s. I get these simultaneously on the same buddy, * using different accounts to get info. */ /* check if status means online or offline */ @@ -441,9 +432,9 @@ /* Help calculate the correct icon index to tell the server. */ gint get_icon_offset(PurpleConnection *gc) -{ +{ PurpleAccount *account; - PurplePresence *presence; + PurplePresence *presence; account = purple_connection_get_account(gc); presence = purple_account_get_presence(account); @@ -460,7 +451,7 @@ } /* send a packet to change my online status */ -void qq_send_packet_change_status(PurpleConnection *gc) +void qq_request_change_status(PurpleConnection *gc, gint update_class) { qq_data *qd; guint8 raw_data[16] = {0}; @@ -469,13 +460,13 @@ guint32 misc_status; gboolean fake_video; PurpleAccount *account; - PurplePresence *presence; + PurplePresence *presence; account = purple_connection_get_account(gc); presence = purple_account_get_presence(account); qd = (qq_data *) gc->proto_data; - if (!qd->logged_in) + if (!qd->is_login) return; if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) { @@ -497,7 +488,7 @@ bytes += qq_put8(raw_data + bytes, away_cmd); bytes += qq_put32(raw_data + bytes, misc_status); - qq_send_cmd(qd, QQ_CMD_CHANGE_ONLINE_STATUS, raw_data, bytes); + qq_send_cmd_mess(gc, QQ_CMD_CHANGE_STATUS, raw_data, bytes, update_class, 0); } /* parse the reply packet for change_status */ @@ -513,15 +504,15 @@ g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - + bytes = 0; bytes = qq_get8(&reply, data + bytes); if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Change status fail 0x%02X\n", reply); + purple_debug_warning("QQ", "Change status fail 0x%02X\n", reply); return; } - /* purple_debug(PURPLE_DEBUG_INFO, "QQ", "Change status OK\n"); */ + /* purple_debug_info("QQ", "Change status OK\n"); */ name = uid_to_purple_name(qd->uid); b = purple_find_buddy(gc->account, name); g_free(name); @@ -532,7 +523,7 @@ } /* it is a server message indicating that one of my buddies has changed its status */ -void qq_process_buddy_change_status(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_buddy_change_status(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; gint bytes; @@ -547,16 +538,16 @@ qd = (qq_data *) gc->proto_data; if (data_len < 35) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[buddy status change] only %d, need 35 bytes\n", data_len); + purple_debug_error("QQ", "[buddy status change] only %d, need 35 bytes\n", data_len); return; } - + memset(&bs, 0, sizeof(bs)); bytes = 0; /* 000-030: qq_buddy_status */ bytes += get_buddy_status(&bs, data + bytes); - /* 031-034: Unknow, maybe my uid */ - /* This has a value of 0 when we've changed our status to + /* 031-034: Unknow, maybe my uid */ + /* This has a value of 0 when we've changed our status to * QQ_BUDDY_ONLINE_INVISIBLE */ bytes += qq_get32(&my_uid, data + bytes); @@ -565,13 +556,13 @@ g_free(name); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (q_bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "got information of unknown buddy %d\n", bs.uid); return; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "status:.uid = %d, q_bud->uid = %d\n", bs.uid , q_bud->uid); - if(bs.ip.s_addr != 0) { + purple_debug_info("QQ", "status:.uid = %d, q_bud->uid = %d\n", bs.uid , q_bud->uid); + if(bs.ip.s_addr != 0) { q_bud->ip.s_addr = bs.ip.s_addr; q_bud->port = bs.port; } @@ -589,24 +580,24 @@ gchar *purple_name; PurpleBuddy *bud; gchar *status_id; - + g_return_if_fail(q_bud != NULL); purple_name = uid_to_purple_name(q_bud->uid); if (purple_name == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Not find purple name: %d\n", q_bud->uid); + purple_debug_error("QQ", "Not find purple name: %d\n", q_bud->uid); return; } bud = purple_find_buddy(gc->account, purple_name); if (bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Not find buddy: %d\n", q_bud->uid); + purple_debug_error("QQ", "Not find buddy: %d\n", q_bud->uid); g_free(purple_name); return; } - + purple_blist_server_alias_buddy(bud, q_bud->nickname); /* server */ - q_bud->last_refresh = time(NULL); + q_bud->last_update = time(NULL); /* purple supports signon and idle time * but it is not much use for QQ, I do not use them */ @@ -630,10 +621,10 @@ break; default: status_id = "invisible"; - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "unknown status: %x\n", q_bud->status); + purple_debug_error("QQ", "unknown status: %x\n", q_bud->status); break; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "buddy %d %s\n", q_bud->uid, status_id); + purple_debug_info("QQ", "buddy %d %s\n", q_bud->uid, status_id); purple_prpl_got_user_status(gc->account, purple_name, status_id, NULL); if (q_bud->comm_flag & QQ_COMM_FLAG_MOBILE && q_bud->status != QQ_BUDDY_OFFLINE) @@ -664,7 +655,7 @@ while (list != NULL) { q_bud = (qq_buddy *) list->data; - if (q_bud != NULL && now > q_bud->last_refresh + QQ_UPDATE_ONLINE_INTERVAL + if (q_bud != NULL && now > q_bud->last_update + QQ_UPDATE_ONLINE_INTERVAL && q_bud->status != QQ_BUDDY_ONLINE_INVISIBLE) { q_bud->status = QQ_BUDDY_ONLINE_OFFLINE; qq_update_buddy_contact(gc, q_bud); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/buddy_list.h --- a/libpurple/protocols/qq/buddy_list.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.h Mon Sep 15 02:59:23 2008 +0000 @@ -42,19 +42,19 @@ enum { QQ_BUDDY_OFFLINE = 0x00, - QQ_BUDDY_ONLINE_NORMAL = 0x0a, - QQ_BUDDY_ONLINE_OFFLINE = 0x14, - QQ_BUDDY_ONLINE_AWAY = 0x1e, - QQ_BUDDY_ONLINE_INVISIBLE = 0x28 + QQ_BUDDY_ONLINE_NORMAL = 10, + QQ_BUDDY_ONLINE_OFFLINE = 20, + QQ_BUDDY_ONLINE_AWAY = 30, + QQ_BUDDY_ONLINE_INVISIBLE = 40 }; -void qq_send_packet_get_buddies_online(PurpleConnection *gc, guint8 position); +void qq_request_get_buddies_online(PurpleConnection *gc, guint8 position, gint update_class); guint8 qq_process_get_buddies_online_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_send_packet_get_buddies_list(PurpleConnection *gc, guint16 position); +void qq_request_get_buddies_list(PurpleConnection *gc, guint16 position, gint update_class); guint16 qq_process_get_buddies_list_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_send_packet_get_buddies_and_rooms(PurpleConnection *gc, guint32 position); +void qq_request_get_buddies_and_rooms(PurpleConnection *gc, guint32 position, gint update_class); guint32 qq_process_get_buddies_and_rooms(guint8 *data, gint data_len, PurpleConnection *gc); void qq_refresh_all_buddy_status(PurpleConnection *gc); @@ -63,7 +63,7 @@ gint get_icon_offset(PurpleConnection *gc); -void qq_send_packet_change_status(PurpleConnection *gc); +void qq_request_change_status(PurpleConnection *gc, gint update_class); void qq_process_change_status_reply(guint8 *data, gint data_len, PurpleConnection *gc); void qq_process_buddy_change_status(guint8 *data, gint data_len, PurpleConnection *gc); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/buddy_opt.c --- a/libpurple/protocols/qq/buddy_opt.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Mon Sep 15 02:59:23 2008 +0000 @@ -60,19 +60,17 @@ /* 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(qd, QQ_CMD_DEL_BUDDY, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_DEL_BUDDY, (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,7 +78,7 @@ bytes += qq_put32(raw_data + bytes, uid); - qq_send_cmd(qd, QQ_CMD_REMOVE_SELF, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_REMOVE_SELF, raw_data, bytes); } /* try to add a buddy without authentication */ @@ -94,7 +92,7 @@ /* 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(qd, QQ_CMD_ADD_BUDDY_WO_AUTH, (guint8 *) uid_str, strlen(uid_str)); + qq_send_cmd(gc, QQ_CMD_ADD_BUDDY_WO_AUTH, (guint8 *) uid_str, strlen(uid_str)); /* must be set after sending packet to get the correct send_seq */ req = g_new0(qq_add_buddy_request, 1); @@ -106,7 +104,6 @@ /* 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; @@ -128,7 +125,7 @@ g_free(text_qq); } - qq_send_cmd(qd, QQ_CMD_BUDDY_AUTH, raw_data, bytes); + qq_send_cmd(gc, 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) @@ -204,11 +201,11 @@ g2->uid = uid; msg1 = g_strdup_printf(_("You rejected %d's request"), uid); - msg2 = g_strdup(_("Input your reason:")); + msg2 = g_strdup(_("Message:")); nombre = uid_to_purple_name(uid); purple_request_input(gc, _("Reject request"), msg1, msg2, - _("Sorry, you are not my type..."), TRUE, FALSE, + _("Sorry, you are not my style..."), TRUE, FALSE, NULL, _("Reject"), G_CALLBACK(_qq_reject_add_request_real), _("Cancel"), NULL, purple_connection_get_account(gc), nombre, NULL, g2); @@ -261,7 +258,7 @@ qd = (qq_data *) gc->proto_data; if (data[0] != QQ_ADD_BUDDY_AUTH_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add buddy with auth request failed\n"); + purple_debug_warning("QQ", "Add buddy with auth request failed\n"); if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) { return; } @@ -269,7 +266,7 @@ purple_notify_error(gc, NULL, _("Add buddy with auth request failed"), msg_utf8); g_free(msg_utf8); } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Add buddy with auth request OK\n"); + purple_debug_info("QQ", "Add buddy with auth request OK\n"); } } @@ -284,16 +281,16 @@ if (data[0] != QQ_REMOVE_BUDDY_REPLY_OK) { /* there is no reason return from server */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Remove buddy fails\n"); + purple_debug_warning("QQ", "Remove buddy fails\n"); } else { /* if reply */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Remove buddy OK\n"); + purple_debug_info("QQ", "Remove buddy OK\n"); /* TODO: We don't really need to notify the user about this, do we? */ purple_notify_info(gc, NULL, _("You have successfully removed a buddy"), NULL); } } /* process the server reply for my request to remove myself from a buddy */ -void qq_process_remove_self_reply(guint8 *data, gint data_len, PurpleConnection *gc) +void qq_process_remove_self_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; @@ -303,11 +300,12 @@ if (data[0] != QQ_REMOVE_SELF_REPLY_OK) { /* there is no reason return from server */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Remove self fails\n"); + purple_debug_warning("QQ", "Remove self fails\n"); + purple_notify_info(gc, NULL, _("Failed removing from friend's buddy list"), NULL); } else { /* if reply */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Remove self from a buddy OK\n"); + purple_debug_info("QQ", "Remove from a buddy OK\n"); /* TODO: Does the user really need to be notified about this? */ - purple_notify_info(gc, NULL, _("You have successfully removed yourself from your friend's buddy list"), NULL); + purple_notify_info(gc, NULL, _("Successed removing from friend's buddy list"), NULL); } } @@ -340,25 +338,25 @@ } if (for_uid == 0) { /* we have no record for this */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "We have no record for add buddy reply [%d], discard\n", seq); + purple_debug_error("QQ", "We have no record for add buddy reply [%d], discard\n", seq); return; } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Add buddy reply [%d] is for id [%d]\n", seq, for_uid); + purple_debug_info("QQ", "Add buddy reply [%d] is for id [%d]\n", seq, for_uid); } if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) return; - + uid = segments[0]; reply = segments[1]; if (strtol(uid, NULL, 10) != qd->uid) { /* should not happen */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Add buddy reply is to [%s], not me!", uid); + purple_debug_error("QQ", "Add buddy reply is to [%s], not me!", uid); g_strfreev(segments); return; } if (strtol(reply, NULL, 10) > 0) { /* need auth */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add buddy attempt fails, need authentication\n"); + purple_debug_warning("QQ", "Add buddy attempt fails, need authentication\n"); nombre = uid_to_purple_name(for_uid); b = purple_find_buddy(gc->account, nombre); if (b != NULL) @@ -366,7 +364,7 @@ g = g_new0(gc_and_uid, 1); g->gc = gc; g->uid = for_uid; - msg = g_strdup_printf(_("User %d needs authentication"), for_uid); + msg = g_strdup_printf(_("%d needs authentication"), for_uid); purple_request_input(gc, NULL, msg, _("Input request here"), /* TODO: Awkward string to fix post string freeze - standardize auth dialogues? -evands */ _("Would you be my friend?"), @@ -397,7 +395,7 @@ if (g == NULL) { g = purple_group_new(group_name); purple_blist_add_group(g, NULL); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add new group: %s\n", group_name); + purple_debug_warning("QQ", "Add new group: %s\n", group_name); } return g; @@ -440,11 +438,11 @@ b->proto_data = q_bud; qd->buddies = g_list_append(qd->buddies, q_bud); qq_send_packet_get_info(gc, q_bud->uid, FALSE); - qq_send_packet_get_buddies_online(gc, 0); + qq_request_get_buddies_online(gc, 0, 0); } purple_blist_add_buddy(b, NULL, g, NULL); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add new buddy: [%s]\n", name); + purple_debug_warning("QQ", "Add new buddy: [%s]\n", name); g_free(name); g_free(group_name); @@ -454,8 +452,8 @@ /* add a buddy and send packet to QQ server * note that when purple load local cached buddy list into its blist - * it also calls this funtion, so we have to - * define qd->logged_in=TRUE AFTER serv_finish_login(gc) */ + * it also calls this funtion, so we have to + * define qd->is_login=TRUE AFTER serv_finish_login(gc) */ void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { qq_data *qd; @@ -463,7 +461,7 @@ PurpleBuddy *b; qd = (qq_data *) gc->proto_data; - if (!qd->logged_in) + if (!qd->is_login) return; /* IMPORTANT ! */ uid = purple_name_to_uid(buddy->name); @@ -474,8 +472,8 @@ if (b != NULL) purple_blist_remove_buddy(b); purple_notify_error(gc, NULL, - _("QQid Error"), - _("Invalid QQid")); + _("QQ Number Error"), + _("Invalid QQ Number")); } } @@ -490,7 +488,7 @@ qd = (qq_data *) gc->proto_data; uid = purple_name_to_uid(buddy->name); - if (!qd->logged_in) + if (!qd->is_login) return; if (uid > 0) @@ -502,7 +500,7 @@ if (q_bud != NULL) qd->buddies = g_list_remove(qd->buddies, q_bud); else - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "We have no qq_buddy record for %s\n", buddy->name); + purple_debug_warning("QQ", "We have no qq_buddy record for %s\n", buddy->name); /* remove buddy on blist, this does not trigger qq_remove_buddy again * do this only if the request comes from block request, * otherwise purple segmentation fault */ @@ -514,41 +512,45 @@ /* free add buddy request queue */ void qq_add_buddy_request_free(qq_data *qd) { - gint i; + gint count; qq_add_buddy_request *p; - i = 0; - while (qd->add_buddy_request) { + count = 0; + while (qd->add_buddy_request != NULL) { p = (qq_add_buddy_request *) (qd->add_buddy_request->data); qd->add_buddy_request = g_list_remove(qd->add_buddy_request, p); g_free(p); - i++; + count++; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d add buddy requests are freed!\n", i); + if (count > 0) { + purple_debug_info("QQ", "%d add buddy requests are freed!\n", count); + } } /* free up all qq_buddy */ void qq_buddies_list_free(PurpleAccount *account, qq_data *qd) { - gint i; + gint count; qq_buddy *p; gchar *name; PurpleBuddy *b; - i = 0; + count = 0; while (qd->buddies) { p = (qq_buddy *) (qd->buddies->data); qd->buddies = g_list_remove(qd->buddies, p); name = uid_to_purple_name(p->uid); - b = purple_find_buddy(account, name); - if(b != NULL) + b = purple_find_buddy(account, name); + if(b != NULL) b->proto_data = NULL; else - purple_debug(PURPLE_DEBUG_INFO, "QQ", "qq_buddy %s not found in purple proto_data\n", name); + purple_debug_info("QQ", "qq_buddy %s not found in purple proto_data\n", name); g_free(name); g_free(p); - i++; + count++; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d qq_buddy structures are freed!\n", i); + if (count > 0) { + purple_debug_info("QQ", "%d qq_buddy structures are freed!\n", count); + } } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/char_conv.c --- a/libpurple/protocols/qq/char_conv.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/char_conv.c Mon Sep 15 02:59:23 2008 +0000 @@ -113,7 +113,7 @@ } /* conversion error */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ_CONVERT", "%s\n", error->message); + purple_debug_error("QQ_CONVERT", "%s\n", error->message); qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ_CONVERT", (guint8 *) str, (len == -1) ? strlen(str) : len, @@ -182,7 +182,7 @@ g_string_append_printf(encoded, "", color_code, font_name, font_size / 3); - purple_debug(PURPLE_DEBUG_INFO, "QQ_MESG", + purple_debug_info("QQ_MESG", "recv \n", color_code, font_name, font_size / 3); g_string_append(encoded, msg_utf8); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/file_trans.c --- a/libpurple/protocols/qq/file_trans.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/file_trans.c Mon Sep 15 02:59:23 2008 +0000 @@ -22,10 +22,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#ifdef _WIN32 -#define random rand -#endif - #include "internal.h" #include "debug.h" @@ -62,7 +58,7 @@ { guint8 seed; - seed = random(); + seed = rand() & 0xFF; return _get_file_key(seed); } @@ -261,7 +257,7 @@ if (bytes == len + 12) { _qq_xfer_write(raw_data, bytes, qd->xfer); } else - purple_debug(PURPLE_DEBUG_INFO, "QQ", "send_file: want %d but got %d\n", len + 12, bytes); + purple_debug_info("QQ", "send_file: want %d but got %d\n", len + 12, bytes); return bytes; } @@ -323,13 +319,13 @@ bytes_expected = 61; break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "qq_send_file_ctl_packet: Unknown packet type[%d]\n", + purple_debug_info("QQ", "qq_send_file_ctl_packet: Unknown packet type[%d]\n", packet_type); bytes_expected = 0; } if (bytes != bytes_expected) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "qq_send_file_ctl_packet: Expected to get %d bytes, but get %d", + purple_debug_error("QQ", "qq_send_file_ctl_packet: Expected to get %d bytes, but get %d", bytes_expected, bytes); return; } @@ -346,24 +342,24 @@ guint8 *buf; int buflen; hex_dump = hex_dump_to_str(encrypted_data, encrypted_len); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "encrypted packet: \n%s", hex_dump); + purple_debug_info("QQ", "encrypted packet: \n%s", hex_dump); g_free(hex_dump); buf = g_newa(guint8, MAX_PACKET_SIZE); buflen = encrypted_len; if (qq_crypt(DECRYPT, encrypted_data, encrypted_len, info->file_session_key, buf, &buflen)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt success\n"); + purple_debug_info("QQ", "decrypt success\n"); if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0) - purple_debug(PURPLE_DEBUG_INFO, "QQ", "checksum ok\n"); + purple_debug_info("QQ", "checksum ok\n"); hex_dump = hex_dump_to_str(buf, buflen); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypted packet: \n%s", hex_dump); + purple_debug_info("QQ", "decrypted packet: \n%s", hex_dump); g_free(hex_dump); } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt fail\n"); + purple_debug_info("QQ", "decrypt fail\n"); } #endif - purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); + purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); _qq_send_file(gc, encrypted_data, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); } @@ -410,7 +406,7 @@ info->fragment_num = (filesize - 1) / QQ_FILE_FRAGMENT_MAXLEN + 1; info->fragment_len = QQ_FILE_FRAGMENT_MAXLEN; - purple_debug(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 */ @@ -435,7 +431,7 @@ filename_len); break; case QQ_FILE_DATA_INFO: - purple_debug(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)); */ @@ -448,7 +444,7 @@ bytes += qq_putdata(raw_data + bytes, data, len); break; case QQ_FILE_EOF: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "end of sending data\n"); + purple_debug_info("QQ", "end of sending data\n"); /* bytes += qq_put16(raw_data + bytes, info->fragment_num + 1); */ bytes += qq_put16(raw_data + bytes, info->fragment_num); bytes += qq_put8(raw_data + bytes, sub_type); @@ -474,7 +470,7 @@ break; } } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); + purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); _qq_send_file(gc, raw_data, bytes, QQ_FILE_DATA_PACKET_TAG, info->to_uid); } @@ -516,7 +512,7 @@ decrypted_data = g_newa(guint8, data_len); decrypted_len = qq_decrypt(decrypted_data, data, data_len, qd->session_md5); if ( decrypted_len <= 0 ) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt rcv file ctrl packet\n"); + purple_debug_error("QQ", "Error decrypt rcv file ctrl packet\n"); return; } @@ -526,7 +522,7 @@ decryped_bytes += qq_get16(&seq, decrypted_data + decryped_bytes); decryped_bytes += 4+1+1+19+1; /* skip something */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "==> [%d] receive %s packet\n", seq, qq_get_file_cmd_desc(packet_type)); + purple_debug_info("QQ", "==> [%d] receive %s packet\n", seq, qq_get_file_cmd_desc(packet_type)); qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", decrypted_data, decrypted_len, "decrypted control packet received:"); @@ -566,7 +562,7 @@ qq_send_file_ctl_packet(gc, QQ_FILE_CMD_SENDER_SAY_HELLO, fh.sender_uid, 0); break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "unprocess file command %d\n", packet_type); + purple_debug_info("QQ", "unprocess file command %d\n", packet_type); } } @@ -577,7 +573,7 @@ ft_info *info = (ft_info *) xfer->data; guint32 mask; - purple_debug(PURPLE_DEBUG_INFO, "QQ", + 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) { @@ -585,11 +581,11 @@ purple_xfer_cancel_local(xfer); return; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "object file opened for writing\n"); + purple_debug_info("QQ", "object file opened for writing\n"); } mask = 0x1 << (index % sizeof(info->window)); if (index < info->max_fragment_index || (info->window & mask)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "duplicate %dth fragment, drop it!\n", index+1); + purple_debug_info("QQ", "duplicate %dth fragment, drop it!\n", index+1); return; } @@ -609,7 +605,7 @@ if (mask & 0x8000) mask = 0x0001; else mask = mask << 1; } - purple_debug(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); } @@ -654,12 +650,12 @@ PurpleXfer *xfer = qd->xfer; ft_info *info = (ft_info *) xfer->data; - purple_debug(PURPLE_DEBUG_INFO, "QQ", + 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 || fragment_index >= info->max_fragment_index + sizeof(info->window)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "duplicate %dth fragment, drop it!\n", fragment_index+1); + purple_debug_info("QQ", "duplicate %dth fragment, drop it!\n", fragment_index+1); return; } mask = 0x1 << (fragment_index % sizeof(info->window)); @@ -696,7 +692,7 @@ else mask = mask << 1; } } - purple_debug(PURPLE_DEBUG_INFO, "QQ", + 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); } @@ -737,7 +733,7 @@ info->max_fragment_index = 0; info->window = 0; - purple_debug(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, @@ -747,7 +743,7 @@ bytes += qq_get32(&fragment_index, data + bytes); bytes += qq_get32(&fragment_offset, data + bytes); bytes += qq_get16(&fragment_len, data + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "received %dth fragment with length %d, offset %d\n", fragment_index, fragment_len, fragment_offset); @@ -756,7 +752,7 @@ _qq_recv_file_progess(gc, data + bytes, fragment_len, fragment_index, fragment_offset); break; case QQ_FILE_EOF: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "end of receiving\n"); + purple_debug_info("QQ", "end of receiving\n"); _qq_send_file_data_packet(gc, QQ_FILE_CMD_FILE_OP_ACK, sub_type, 0, 0, NULL, 0); break; @@ -795,11 +791,11 @@ purple_xfer_end(qd->xfer); break; case QQ_FILE_BASIC_INFO: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "here\n"); + purple_debug_info("QQ", "here\n"); _qq_send_file_data_packet(gc, QQ_FILE_DATA_INFO, 0, 0, 0, NULL, 0); break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "_qq_process_recv_file_data: unknown packet type [%d]\n", + purple_debug_info("QQ", "_qq_process_recv_file_data: unknown packet type [%d]\n", packet_type); break; } @@ -824,6 +820,6 @@ _qq_process_recv_file_data(gc, data + bytes, len - bytes); break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "unknown packet tag"); + purple_debug_info("QQ", "unknown packet tag"); } } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group.c --- a/libpurple/protocols/qq/group.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group.c Mon Sep 15 02:59:23 2008 +0000 @@ -64,7 +64,7 @@ pce = g_new0(struct proto_chat_entry, 1); pce->label = _("ID: "); - pce->identifier = QQ_GROUP_KEY_EXTERNAL_ID; + pce->identifier = QQ_ROOM_KEY_EXTERNAL_ID; m = g_list_append(m, pce); return m; @@ -77,7 +77,7 @@ defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); if (chat_name != NULL) - g_hash_table_insert(defaults, QQ_GROUP_KEY_EXTERNAL_ID, g_strdup(chat_name)); + g_hash_table_insert(defaults, QQ_ROOM_KEY_EXTERNAL_ID, g_strdup(chat_name)); return defaults; } @@ -96,30 +96,30 @@ rl = purple_roomlist_new(purple_connection_get_account(gc)); qd->roomlist = rl; - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Group ID"), QQ_GROUP_KEY_EXTERNAL_ID, FALSE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Group ID"), QQ_ROOM_KEY_EXTERNAL_ID, FALSE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Creator"), QQ_GROUP_KEY_CREATOR_UID, FALSE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Creator"), QQ_ROOM_KEY_CREATOR_UID, FALSE); fields = g_list_append(fields, f); f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, - _("Group Description"), QQ_GROUP_KEY_GROUP_DESC_UTF8, FALSE); + _("Group Description"), QQ_ROOM_KEY_DESC_UTF8, FALSE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_INTERNAL_ID, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_ROOM_KEY_INTERNAL_ID, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_TYPE, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_ROOM_KEY_TYPE, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Auth"), QQ_GROUP_KEY_AUTH_TYPE, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, _("Auth"), QQ_ROOM_KEY_AUTH_TYPE, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_GROUP_CATEGORY, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_ROOM_KEY_CATEGORY, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_GROUP_NAME_UTF8, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_ROOM_KEY_TITLE_UTF8, TRUE); fields = g_list_append(fields, f); purple_roomlist_set_fields(rl, fields); purple_roomlist_set_in_progress(qd->roomlist, TRUE); purple_request_input(gc, _("QQ Qun"), - _("Please enter external group ID"), - _("You can only search for permanent QQ groups\n"), + _("Please enter Qun number"), + _("You can only search for permanent Qun\n"), NULL, FALSE, FALSE, NULL, _("Search"), G_CALLBACK(_qq_group_search_callback), _("Cancel"), G_CALLBACK(_qq_group_search_cancel_callback), @@ -157,7 +157,7 @@ purple_group = purple_find_group(PURPLE_GROUP_QQ_QUN); if (purple_group == NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "We have no QQ Qun\n"); + purple_debug_info("QQ", "We have no QQ Qun\n"); return; } @@ -178,8 +178,7 @@ continue; count++; - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Load %d QQ Qun configurations\n", count); + purple_debug_info("QQ", "Load %d QQ Qun configurations\n", count); } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group.h --- a/libpurple/protocols/qq/group.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group.h Mon Sep 15 02:59:23 2008 +0000 @@ -34,27 +34,27 @@ #define PURPLE_GROUP_QQ_QUN "QQ 群" typedef enum { - QQ_GROUP_MEMBER_STATUS_NOT_MEMBER = 0x00, /* default 0x00 means not member */ - QQ_GROUP_MEMBER_STATUS_IS_MEMBER, - QQ_GROUP_MEMBER_STATUS_APPLYING, - QQ_GROUP_MEMBER_STATUS_IS_ADMIN, -} qq_group_member_status; + QQ_ROOM_ROLE_NO = 0x00, /* default 0x00 means not member */ + QQ_ROOM_ROLE_YES, + QQ_ROOM_ROLE_REQUESTING, + QQ_ROOM_ROLE_ADMIN, +} qq_room_role; typedef struct _qq_group { /* all these will be saved when we exit Purple */ - qq_group_member_status my_status; /* my status for this group */ - gchar *my_status_desc; /* my status description */ + qq_room_role my_role; /* my role for this room */ + gchar *my_role_desc; /* my role description */ guint32 id; guint32 ext_id; guint8 type8; /* permanent or temporory */ guint32 creator_uid; - guint32 group_category; + guint32 category; guint8 auth_type; - gchar *group_name_utf8; - gchar *group_desc_utf8; + gchar *title_utf8; + gchar *desc_utf8; /* all these will be loaded from the network */ gchar *notice_utf8; /* group notice by admin */ - GList *members; + GList *members; } qq_group; GList *qq_chat_info(PurpleConnection *gc); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_conv.c --- a/libpurple/protocols/qq/group_conv.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_conv.c Mon Sep 15 02:59:23 2008 +0000 @@ -41,9 +41,9 @@ qd = (qq_data *) gc->proto_data; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - group->group_name_utf8, purple_connection_get_account(gc)); + group->title_utf8, purple_connection_get_account(gc)); if (conv == NULL) /* show only one window per group */ - serv_got_joined_chat(gc, qd->channel++, group->group_name_utf8); + serv_got_joined_chat(gc, qd->channel++, group->title_utf8); } /* refresh online member in group conversation window */ @@ -59,7 +59,7 @@ names = NULL; flags = NULL; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - group->group_name_utf8, purple_connection_get_account(gc)); + group->title_utf8, purple_connection_get_account(gc)); if (conv != NULL && group->members != NULL) { list = group->members; while (list != NULL) { diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_find.c --- a/libpurple/protocols/qq/group_find.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_find.c Mon Sep 15 02:59:23 2008 +0000 @@ -110,10 +110,10 @@ group = NULL; while (list != NULL) { group = (qq_group *) list->data; - if (group->group_name_utf8 == NULL) { + if (group->title_utf8 == NULL) { continue; } - if (!g_ascii_strcasecmp(purple_conversation_get_name(conv), group->group_name_utf8)) + if (!g_ascii_strcasecmp(purple_conversation_get_name(conv), group->title_utf8)) break; list = list->next; } @@ -167,3 +167,83 @@ return NULL; } + +qq_group *qq_room_get_next(PurpleConnection *gc, guint32 room_id) +{ + GList *list; + qq_group *group; + qq_data *qd; + gboolean is_find = FALSE; + + qd = (qq_data *) gc->proto_data; + + if (qd->groups == NULL) { + return NULL; + } + + if (room_id <= 0) { + return (qq_group *) qd->groups->data; + } + + list = qd->groups; + while (list != NULL) { + group = (qq_group *) list->data; + list = list->next; + if (group->id == room_id) { + is_find = TRUE; + break; + } + } + + if ( !is_find || list == NULL) { + return NULL; + } + + return (qq_group *)list->data; +} + +qq_group *qq_room_get_next_conv(PurpleConnection *gc, guint32 room_id) +{ + GList *list; + qq_group *group; + qq_data *qd; + gboolean is_find; + + qd = (qq_data *) gc->proto_data; + + list = qd->groups; + if (room_id > 0) { + /* search next room */ + is_find = FALSE; + while (list != NULL) { + group = (qq_group *) list->data; + list = list->next; + if (group->id == room_id) { + is_find = TRUE; + break; + } + } + if ( !is_find || list == NULL) { + return NULL; + } + } + + is_find = FALSE; + while (list != NULL) { + group = (qq_group *) list->data; + if (group->my_role == QQ_ROOM_ROLE_YES || group->my_role == QQ_ROOM_ROLE_ADMIN) { + if (NULL != purple_find_conversation_with_account( + PURPLE_CONV_TYPE_CHAT,group->title_utf8, purple_connection_get_account(gc))) { + /* In convseration*/ + is_find = TRUE; + break; + } + } + list = list->next; + } + + if ( !is_find) { + return NULL; + } + return group; +} diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_find.h --- a/libpurple/protocols/qq/group_find.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_find.h Mon Sep 15 02:59:23 2008 +0000 @@ -32,10 +32,12 @@ qq_buddy *qq_group_find_member_by_uid(qq_group *group, guint32 uid); void qq_group_remove_member_by_uid(qq_group *group, guint32 uid); qq_buddy *qq_group_find_or_add_member(PurpleConnection *gc, qq_group *group, guint32 member_uid); -gboolean qq_group_find_id_by_seq(PurpleConnection *gc, guint16 seq, guint32 *id); qq_group *qq_group_find_by_channel(PurpleConnection *gc, gint channel); qq_group *qq_room_search_ext_id(PurpleConnection *gc, guint32 ext_id); qq_group *qq_room_search_id(PurpleConnection *gc, guint32 room_id); +qq_group *qq_room_get_next(PurpleConnection *gc, guint32 room_id); +qq_group *qq_room_get_next_conv(PurpleConnection *gc, guint32 room_id); + #endif diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_free.c --- a/libpurple/protocols/qq/group_free.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_free.c Mon Sep 15 02:59:23 2008 +0000 @@ -54,9 +54,9 @@ { g_return_if_fail(group != NULL); qq_group_free_member(group); - g_free(group->my_status_desc); - g_free(group->group_name_utf8); - g_free(group->group_desc_utf8); + g_free(group->my_role_desc); + g_free(group->title_utf8); + g_free(group->desc_utf8); g_free(group->notice_utf8); g_free(group); } @@ -64,16 +64,18 @@ void qq_group_free_all(qq_data *qd) { qq_group *group; - gint i; - g_return_if_fail(qd != NULL); + gint count; - i = 0; + g_return_if_fail(qd != NULL); + count = 0; while (qd->groups != NULL) { - i++; group = (qq_group *) qd->groups->data; qd->groups = g_list_remove(qd->groups, group); qq_group_free(group); + count++; } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d groups are freed\n", i); + if (count > 0) { + purple_debug_info("QQ", "%d rooms are freed\n", count); + } } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_im.c --- a/libpurple/protocols/qq/group_im.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_im.c Mon Sep 15 02:59:23 2008 +0000 @@ -41,6 +41,7 @@ #include "header_info.h" #include "packet_parse.h" #include "qq_network.h" +#include "qq_process.h" #include "utils.h" typedef struct _qq_recv_group_im { @@ -85,12 +86,12 @@ if (bytes == data_len) /* create OK */ qq_send_room_cmd(gc, QQ_ROOM_CMD_SEND_MSG, group->id, raw_data, data_len); else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Fail creating group_im packet, expect %d bytes, build %d bytes\n", data_len, bytes); } /* this is the ACK */ -void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc) +void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc) { /* return should be the internal group id * but we have nothing to do with it */ @@ -98,7 +99,7 @@ } /* receive an application to join the group */ -void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, user_uid; guint8 type8; @@ -119,8 +120,8 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); - msg = g_strdup_printf(_("User %d requested to join group %d"), user_uid, ext_id); - reason = g_strdup_printf(_("Reason: %s"), reason_utf8); + msg = g_strdup_printf(_("%d requested to join Qun %d"), user_uid, ext_id); + reason = g_strdup_printf(_("Message: %s"), reason_utf8); g = g_new0(group_member_opt, 1); g->gc = gc; @@ -149,7 +150,7 @@ } /* the request to join a group is rejected */ -void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, admin_uid; guint8 type8; @@ -170,14 +171,14 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf - (_("Your request to join group %d has been rejected by admin %d"), ext_id, admin_uid); - reason = g_strdup_printf(_("Reason: %s"), reason_utf8); + (_("Your request to join Qun %d has been rejected by admin %d"), ext_id, admin_uid); + reason = g_strdup_printf(_("Message: %s"), reason_utf8); purple_notify_warning(gc, _("QQ Qun Operation"), msg, reason); group = qq_room_search_id(gc, id); if (group != NULL) { - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); } @@ -187,7 +188,7 @@ } /* the request to join a group is approved */ -void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, admin_uid; guint8 type8; @@ -208,13 +209,13 @@ bytes += convert_as_pascal_string(data + bytes, &reason_utf8, QQ_CHARSET_DEFAULT); msg = g_strdup_printf - (_("Your request to join group %d has been approved by admin %d"), ext_id, admin_uid); + (_("Your request to join Qun %d has been approved by admin %d"), ext_id, admin_uid); purple_notify_warning(gc, _("QQ Qun Operation"), msg, NULL); group = qq_room_search_id(gc, id); if (group != NULL) { - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); } @@ -223,7 +224,7 @@ } /* process the packet when removed from a group */ -void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, uid; guint8 type8; @@ -241,12 +242,12 @@ g_return_if_fail(ext_id > 0 && uid > 0); - msg = g_strdup_printf(_("You [%d] have left group \"%d\""), uid, ext_id); + msg = g_strdup_printf(_("[%d] removed from Qun \"%d\""), uid, ext_id); purple_notify_info(gc, _("QQ Qun Operation"), msg, NULL); group = qq_room_search_id(gc, id); if (group != NULL) { - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); } @@ -254,7 +255,7 @@ } /* process the packet when added to a group */ -void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc) +void qq_process_room_msg_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { guint32 ext_id, uid; guint8 type8; @@ -272,18 +273,18 @@ g_return_if_fail(ext_id > 0 && uid > 0); - msg = g_strdup_printf(_("You [%d] have been added to group \"%d\""), uid, ext_id); - purple_notify_info(gc, _("QQ Qun Operation"), msg, _("This group has been added to your buddy list")); + msg = g_strdup_printf(_("[%d] added to Qun \"%d\""), uid, ext_id); + purple_notify_info(gc, _("QQ Qun Operation"), msg, _("Qun is in buddy list")); group = qq_room_search_id(gc, id); if (group != NULL) { - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); } else { /* no such group, try to create a dummy first, and then update */ group = qq_group_create_internal_record(gc, id, ext_id, NULL); - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); + qq_room_update(gc, 0, group->id); /* the return of this cmd will automatically update the group in blist */ } @@ -291,7 +292,7 @@ } /* recv an IM from a group chat */ -void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type) +void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type) { gchar *msg_with_purple_smiley, *msg_utf8_encoded, *im_src_name; guint16 unknown; @@ -310,7 +311,9 @@ qd = (qq_data *) gc->proto_data; - /* qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", data, data_len, "group im hex dump"); */ +#if 0 + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", data, data_len, "group im hex dump"); +#endif im_group = g_newa(qq_recv_group_im, 1); @@ -374,13 +377,13 @@ group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->group_name_utf8, purple_connection_get_account(gc)); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); if (conv == NULL && purple_prefs_get_bool("/plugins/prpl/qq/prompt_group_msg_on_recv")) { /* New conv should open, get group info*/ - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); - - serv_got_joined_chat(gc, qd->channel++, group->group_name_utf8); - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->group_name_utf8, purple_connection_get_account(gc)); + qq_room_update(gc, 0, group->id); + + serv_got_joined_chat(gc, qd->channel++, group->title_utf8); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); } if (conv != NULL) { diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_im.h --- a/libpurple/protocols/qq/group_im.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_im.h Mon Sep 15 02:59:23 2008 +0000 @@ -31,30 +31,17 @@ 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, gint len, PurpleConnection *gc); -/* void qq_process_recv_group_im(guint8 *data, guint8 **cursor, - * gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type); */ -void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type); +void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type); -/* void qq_process_recv_group_im_apply_join(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc); -/* void qq_process_recv_group_im_been_rejected(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc); -/* void qq_process_recv_group_im_been_approved(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc); -/* void qq_process_recv_group_im_been_removed(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc); -/* void qq_process_recv_group_im_been_added(guint8 *data, guint8 **cursor, gint len, - * guint32 id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc); +void qq_process_room_msg_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc); #endif diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_info.c --- a/libpurple/protocols/qq/group_info.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_info.c Mon Sep 15 02:59:23 2008 +0000 @@ -41,16 +41,16 @@ * this interval determines if their member info is outdated */ #define QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL 180 -static gboolean _is_group_member_need_update_info(qq_buddy *member) +static gboolean check_update_interval(qq_buddy *member) { g_return_val_if_fail(member != NULL, FALSE); return (member->nickname == NULL) || - (time(NULL) - member->last_refresh) > QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL; + (time(NULL) - member->last_update) > QQ_GROUP_CHAT_REFRESH_NICKNAME_INTERNAL; } /* this is done when we receive the reply to get_online_members sub_cmd * all member are set offline, and then only those in reply packets are online */ -static void _qq_group_set_members_all_offline(qq_group *group) +static void set_all_offline(qq_group *group) { GList *list; qq_buddy *member; @@ -64,60 +64,24 @@ } } -/* send packet to get online group member, called by keep_alive */ -void qq_send_cmd_group_all_get_online_members(PurpleConnection *gc) -{ - qq_data *qd; - qq_group *group; - GList *list; - - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - qd = (qq_data *) gc->proto_data; - - list = qd->groups; - while (list != NULL) { - group = (qq_group *) list->data; - if (group->my_status == QQ_GROUP_MEMBER_STATUS_IS_MEMBER || - group->my_status == QQ_GROUP_MEMBER_STATUS_IS_ADMIN) - /* no need to get info time and time again, online members enough */ - qq_send_cmd_group_get_online_members(gc, group); - - list = list->next; - } -} - -void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group) -{ - g_return_if_fail(group != NULL); - - /* only get online members when conversation window is on */ - if (NULL == purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,group->group_name_utf8, purple_connection_get_account(gc))) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Conversation \"%s\" is not open, ignore to get online members\n", group->group_name_utf8); - return; - } - - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, group->id); -} - /* send packet to get info for each group member */ -void qq_send_cmd_group_get_members_info(PurpleConnection *gc, qq_group *group) +gint qq_request_room_get_buddies(PurpleConnection *gc, qq_group *group, gint update_class) { guint8 *raw_data; gint bytes, num; GList *list; qq_buddy *member; - g_return_if_fail(group != NULL); + g_return_val_if_fail(group != NULL, 0); for (num = 0, list = group->members; list != NULL; list = list->next) { member = (qq_buddy *) list->data; - if (_is_group_member_need_update_info(member)) + if (check_update_interval(member)) num++; } if (num <= 0) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "No group member info needs to be updated now.\n"); - return; + purple_debug_info("QQ", "No group member info needs to be updated now.\n"); + return 0; } raw_data = g_newa(guint8, 4 * num); @@ -127,12 +91,14 @@ list = group->members; while (list != NULL) { member = (qq_buddy *) list->data; - if (_is_group_member_need_update_info(member)) + if (check_update_interval(member)) bytes += qq_put32(raw_data + bytes, member->uid); list = list->next; } - qq_send_room_cmd(gc, QQ_ROOM_CMD_GET_MEMBER_INFO, group->id, raw_data, bytes); + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_BUDDIES, group->id, raw_data, bytes, + update_class, 0); + return num; } void qq_process_room_cmd_get_info(guint8 *data, gint data_len, PurpleConnection *gc) @@ -174,8 +140,8 @@ bytes += qq_get32(&(group->creator_uid), data + bytes); bytes += qq_get8(&(group->auth_type), data + bytes); bytes += qq_get32(&unknown4, data + bytes); /* oldCategory */ - bytes += qq_get16(&unknown, data + bytes); - bytes += qq_get32(&(group->group_category), data + bytes); + bytes += qq_get16(&unknown, data + bytes); + bytes += qq_get32(&(group->category), data + bytes); bytes += qq_get16(&max_members, data + bytes); bytes += qq_get8(&unknown1, data + bytes); /* the following, while Eva: @@ -183,17 +149,17 @@ * 2(qunNoticeLen), qunNoticeLen(qunNoticeContent, 1(qunDescLen), * qunDestLen(qunDestcontent)) */ bytes += qq_get8(&unknown1, data + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", - group->type8, group->creator_uid, group->group_category, max_members); - + purple_debug_info("QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", + group->type8, group->creator_uid, group->category, max_members); + /* strlen + */ - bytes += convert_as_pascal_string(data + bytes, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\"\n", group->group_name_utf8); + bytes += convert_as_pascal_string(data + bytes, &(group->title_utf8), QQ_CHARSET_DEFAULT); + purple_debug_info("QQ", "group \"%s\"\n", group->title_utf8); bytes += qq_get16(&unknown, data + bytes); /* 0x0000 */ bytes += convert_as_pascal_string(data + bytes, ¬ice, QQ_CHARSET_DEFAULT); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "notice \"%s\"\n", notice); - bytes += convert_as_pascal_string(data + bytes, &(group->group_desc_utf8), QQ_CHARSET_DEFAULT); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "group_desc \"%s\"\n", group->group_desc_utf8); + purple_debug_info("QQ", "notice \"%s\"\n", notice); + bytes += convert_as_pascal_string(data + bytes, &(group->desc_utf8), QQ_CHARSET_DEFAULT); + purple_debug_info("QQ", "group_desc \"%s\"\n", group->desc_utf8); num = 0; /* now comes the member list separated by 0x00 */ @@ -205,7 +171,7 @@ #if 0 if(organization != 0 || role != 0) { - purple_debug(PURPLE_DEBUG_INFO, "QQ_GRP", "%d, organization=%d, role=%d\n", member_uid, organization, role); + purple_debug_info("QQ_GRP", "%d, organization=%d, role=%d\n", member_uid, organization, role); } #endif @@ -214,22 +180,22 @@ member->role = role; } if(bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "group \"%s\" has %d members\n", group->group_name_utf8, num); + purple_debug_info("QQ", "group \"%s\" has %d members\n", group->title_utf8, num); if (group->creator_uid == qd->uid) - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_ADMIN; + group->my_role = QQ_ROOM_ROLE_ADMIN; qq_group_refresh(gc, group); - purple_conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - group->group_name_utf8, purple_connection_get_account(gc)); + purple_conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + group->title_utf8, purple_connection_get_account(gc)); if(NULL == purple_conv) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Conversation \"%s\" is not open, do not set topic\n", group->group_name_utf8); + purple_debug_warning("QQ", + "Conversation \"%s\" is not open, do not set topic\n", group->title_utf8); return; } @@ -237,7 +203,7 @@ qq_filter_str(notice); group->notice_utf8 = strdup(notice); g_free(notice); - + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(purple_conv), NULL, group->notice_utf8); } @@ -252,7 +218,7 @@ g_return_if_fail(data != NULL && len > 0); if (len <= 3) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Invalid group online member reply, discard it!\n"); + purple_debug_error("QQ", "Invalid group online member reply, discard it!\n"); return; } @@ -263,13 +229,12 @@ group = qq_room_search_id(gc, id); if (group == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "We have no group info for internal id [%d]\n", id); + purple_debug_error("QQ", "We have no group info for internal id [%d]\n", id); return; } /* set all offline first, then update those online */ - _qq_group_set_members_all_offline(group); + set_all_offline(group); num = 0; while (bytes < len) { bytes += qq_get32(&member_uid, data + bytes); @@ -279,15 +244,15 @@ member->status = QQ_BUDDY_ONLINE_NORMAL; } if(bytes > len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!"); + purple_debug_error("QQ", + "group_cmd_get_online_members: Dangerous error! maybe protocol changed, notify developers!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" has %d online members\n", group->group_name_utf8, num); + purple_debug_info("QQ", "Group \"%s\" has %d online members\n", group->title_utf8, num); } /* process the reply to get_members_info packet */ -void qq_process_room_cmd_get_members(guint8 *data, gint len, PurpleConnection *gc) +void qq_process_room_cmd_get_buddies(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; gint num; @@ -300,7 +265,7 @@ g_return_if_fail(data != NULL && len > 0); #if 0 - qq_show_packet("qq_process_room_cmd_get_members", data, len); + qq_show_packet("qq_process_room_cmd_get_buddies", data, len); #endif bytes = 0; @@ -331,19 +296,19 @@ qq_filter_str(nick); member->nickname = g_strdup(nick); g_free(nick); - + #if 0 - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "member [%09d]: ext_flag=0x%02x, comm_flag=0x%02x, nick=%s\n", member_uid, member->ext_flag, member->comm_flag, member->nickname); #endif - member->last_refresh = time(NULL); + member->last_update = time(NULL); } if (bytes > len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "group_cmd_get_members_info: Dangerous error! maybe protocol changed, notify developers!"); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Group \"%s\" obtained %d member info\n", group->group_name_utf8, num); + purple_debug_info("QQ", "Group \"%s\" obtained %d member info\n", group->title_utf8, num); } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_info.h --- a/libpurple/protocols/qq/group_info.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_info.h Mon Sep 15 02:59:23 2008 +0000 @@ -29,12 +29,9 @@ #include "connection.h" #include "group.h" -void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group); -void qq_send_cmd_group_all_get_online_members(PurpleConnection *gc); - -void qq_send_cmd_group_get_members_info(PurpleConnection *gc, qq_group *group); +gint qq_request_room_get_buddies(PurpleConnection *gc, qq_group *group, gint update_class); void qq_process_room_cmd_get_info(guint8 *data, gint len, PurpleConnection *gc); void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc); -void qq_process_room_cmd_get_members(guint8 *data, gint len, PurpleConnection *gc); +void qq_process_room_cmd_get_buddies(guint8 *data, gint len, PurpleConnection *gc); #endif diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_internal.c --- a/libpurple/protocols/qq/group_internal.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_internal.c Mon Sep 15 02:59:23 2008 +0000 @@ -31,49 +31,49 @@ #include "group_internal.h" #include "utils.h" -static gchar *_qq_group_set_my_status_desc(qq_group *group) +static gchar *get_role_desc(qq_group *group) { - const char *status_desc; + const char *role_desc; g_return_val_if_fail(group != NULL, g_strdup("")); - switch (group->my_status) { - case QQ_GROUP_MEMBER_STATUS_NOT_MEMBER: - status_desc = _("I am not a member"); + switch (group->my_role) { + case QQ_ROOM_ROLE_NO: + role_desc = _("I am not a member"); break; - case QQ_GROUP_MEMBER_STATUS_IS_MEMBER: - status_desc = _("I am a member"); + case QQ_ROOM_ROLE_YES: + role_desc = _("I am a member"); break; - case QQ_GROUP_MEMBER_STATUS_APPLYING: - status_desc = _("I am applying to join"); + case QQ_ROOM_ROLE_REQUESTING: + role_desc = _("I am requesting"); break; - case QQ_GROUP_MEMBER_STATUS_IS_ADMIN: - status_desc = _("I am the admin"); + case QQ_ROOM_ROLE_ADMIN: + role_desc = _("I am the admin"); break; default: - status_desc = _("Unknown status"); + role_desc = _("Unknown status"); } - return g_strdup(status_desc); + return g_strdup(role_desc); } -static void _qq_group_add_to_blist(PurpleConnection *gc, qq_group *group) +static void add_room_to_blist(PurpleConnection *gc, qq_group *group) { GHashTable *components; PurpleGroup *g; PurpleChat *chat; components = qq_group_to_hashtable(group); - chat = purple_chat_new(purple_connection_get_account(gc), group->group_name_utf8, components); + chat = purple_chat_new(purple_connection_get_account(gc), group->title_utf8, components); g = qq_get_purple_group(PURPLE_GROUP_QQ_QUN); purple_blist_add_chat(chat, g, NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "You have added group \"%s\" to blist locally\n", group->group_name_utf8); + purple_debug_info("QQ", "You have added group \"%s\" to blist locally\n", group->title_utf8); } /* Create a dummy qq_group, which includes only internal_id, ext_id, - * and potentially group_name_utf8, in case we need to call group_conv_show_window + * and potentially title_utf8, in case we need to call group_conv_show_window * right after creation. All other attributes are set to empty. * We need to send a get_group_info to the QQ server to update it right away */ qq_group *qq_group_create_internal_record(PurpleConnection *gc, - guint32 internal_id, guint32 ext_id, gchar *group_name_utf8) + guint32 internal_id, guint32 ext_id, gchar *title_utf8) { qq_group *group; qq_data *qd; @@ -82,21 +82,21 @@ qd = (qq_data *) gc->proto_data; group = g_new0(qq_group, 1); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; - group->my_status_desc = _qq_group_set_my_status_desc(group); + group->my_role = QQ_ROOM_ROLE_NO; + group->my_role_desc = get_role_desc(group); group->id = internal_id; group->ext_id = ext_id; group->type8 = 0x01; /* assume permanent Qun */ group->creator_uid = 10000; /* assume by QQ admin */ - group->group_category = 0x01; + group->category = 0x01; group->auth_type = 0x02; /* assume need auth */ - group->group_name_utf8 = g_strdup(group_name_utf8 == NULL ? "" : group_name_utf8); - group->group_desc_utf8 = g_strdup(""); + group->title_utf8 = g_strdup(title_utf8 == NULL ? "" : title_utf8); + group->desc_utf8 = g_strdup(""); group->notice_utf8 = g_strdup(""); group->members = NULL; qd->groups = g_list_append(qd->groups, group); - _qq_group_add_to_blist(gc, group); + add_room_to_blist(gc, group); return group; } @@ -124,21 +124,21 @@ { GHashTable *components; components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_MEMBER_STATUS), g_strdup_printf("%d", group->my_status)); - group->my_status_desc = _qq_group_set_my_status_desc(group); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_ROLE), g_strdup_printf("%d", group->my_role)); + group->my_role_desc = get_role_desc(group); g_hash_table_insert(components, - g_strdup(QQ_GROUP_KEY_INTERNAL_ID), g_strdup_printf("%d", group->id)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_EXTERNAL_ID), + g_strdup(QQ_ROOM_KEY_INTERNAL_ID), g_strdup_printf("%d", group->id)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_EXTERNAL_ID), g_strdup_printf("%d", group->ext_id)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_TYPE), g_strdup_printf("%d", group->type8)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TYPE), g_strdup_printf("%d", group->type8)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); g_hash_table_insert(components, - g_strdup(QQ_GROUP_KEY_GROUP_CATEGORY), g_strdup_printf("%d", group->group_category)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_MEMBER_STATUS_DESC), g_strdup(group->my_status_desc)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_NAME_UTF8), g_strdup(group->group_name_utf8)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_DESC_UTF8), g_strdup(group->group_desc_utf8)); + g_strdup(QQ_ROOM_KEY_CATEGORY), g_strdup_printf("%d", group->category)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_ROLE_DESC), g_strdup(group->my_role_desc)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(group->title_utf8)); + g_hash_table_insert(components, g_strdup(QQ_ROOM_KEY_DESC_UTF8), g_strdup(group->desc_utf8)); return components; } @@ -152,22 +152,22 @@ qd = (qq_data *) gc->proto_data; group = g_new0(qq_group, 1); - group->my_status = + group->my_role = qq_string_to_dec_value (NULL == g_hash_table_lookup(data, - QQ_GROUP_KEY_MEMBER_STATUS) ? - g_strdup_printf("%d", QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) : - g_hash_table_lookup(data, QQ_GROUP_KEY_MEMBER_STATUS)); - group->id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID)); - group->ext_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID)); - group->type8 = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_TYPE)); - group->creator_uid = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_CREATOR_UID)); - group->group_category = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_CATEGORY)); - group->auth_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_AUTH_TYPE)); - group->group_name_utf8 = g_strdup(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_NAME_UTF8)); - group->group_desc_utf8 = g_strdup(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_DESC_UTF8)); - group->my_status_desc = _qq_group_set_my_status_desc(group); + QQ_ROOM_KEY_ROLE) ? + g_strdup_printf("%d", QQ_ROOM_ROLE_NO) : + g_hash_table_lookup(data, QQ_ROOM_KEY_ROLE)); + group->id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID)); + group->ext_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID)); + group->type8 = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_TYPE)); + group->creator_uid = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_CREATOR_UID)); + group->category = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_CATEGORY)); + group->auth_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_ROOM_KEY_AUTH_TYPE)); + group->title_utf8 = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_TITLE_UTF8)); + group->desc_utf8 = g_strdup(g_hash_table_lookup(data, QQ_ROOM_KEY_DESC_UTF8)); + group->my_role_desc = get_role_desc(group); qd->groups = g_list_append(qd->groups, group); @@ -184,48 +184,54 @@ ext_id = g_strdup_printf("%d", group->ext_id); chat = purple_blist_find_chat(purple_connection_get_account(gc), ext_id); g_free(ext_id); - if (chat == NULL && group->my_status != QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) { - _qq_group_add_to_blist(gc, group); - } else if (chat != NULL) { /* we have a local record, update its info */ - /* if there is group_name_utf8, we update the group name */ - if (group->group_name_utf8 != NULL && strlen(group->group_name_utf8) > 0) - purple_blist_alias_chat(chat, group->group_name_utf8); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_MEMBER_STATUS), g_strdup_printf("%d", group->my_status)); - group->my_status_desc = _qq_group_set_my_status_desc(group); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_MEMBER_STATUS_DESC), g_strdup(group->my_status_desc)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_INTERNAL_ID), - g_strdup_printf("%d", group->id)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_EXTERNAL_ID), - g_strdup_printf("%d", group->ext_id)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_TYPE), g_strdup_printf("%d", group->type8)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_CATEGORY), - g_strdup_printf("%d", group->group_category)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_NAME_UTF8), g_strdup(group->group_name_utf8)); - g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_DESC_UTF8), g_strdup(group->group_desc_utf8)); + if (chat == NULL && group->my_role != QQ_ROOM_ROLE_NO) { + add_room_to_blist(gc, group); + return; + } + + if (chat == NULL) { + return; } + + /* we have a local record, update its info */ + /* if there is title_utf8, we update the group name */ + if (group->title_utf8 != NULL && strlen(group->title_utf8) > 0) + purple_blist_alias_chat(chat, group->title_utf8); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_ROLE), g_strdup_printf("%d", group->my_role)); + group->my_role_desc = get_role_desc(group); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_ROLE_DESC), g_strdup(group->my_role_desc)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_INTERNAL_ID), + g_strdup_printf("%d", group->id)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_EXTERNAL_ID), + g_strdup_printf("%d", group->ext_id)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_TYPE), g_strdup_printf("%d", group->type8)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_CREATOR_UID), g_strdup_printf("%d", group->creator_uid)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_CATEGORY), + g_strdup_printf("%d", group->category)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_AUTH_TYPE), g_strdup_printf("%d", group->auth_type)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_TITLE_UTF8), g_strdup(group->title_utf8)); + g_hash_table_replace(chat->components, + g_strdup(QQ_ROOM_KEY_DESC_UTF8), g_strdup(group->desc_utf8)); } -/* NOTE: If we knew how to convert between an external and internal group id, as the official +/* NOTE: If we knew how to convert between an external and internal group id, as the official * client seems to, the following would be unnecessary. That would be ideal. */ /* Use list to specify if id's alternate id is pending discovery. */ void qq_set_pending_id(GSList **list, guint32 id, gboolean pending) { - if (pending) + if (pending) *list = g_slist_prepend(*list, GINT_TO_POINTER(id)); - else + else *list = g_slist_remove(*list, GINT_TO_POINTER(id)); } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_internal.h --- a/libpurple/protocols/qq/group_internal.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_internal.h Mon Sep 15 02:59:23 2008 +0000 @@ -28,18 +28,18 @@ #include #include "group.h" -#define QQ_GROUP_KEY_MEMBER_STATUS "my_status_code" -#define QQ_GROUP_KEY_MEMBER_STATUS_DESC "my_status_desc" -#define QQ_GROUP_KEY_INTERNAL_ID "id" -#define QQ_GROUP_KEY_EXTERNAL_ID "ext_id" -#define QQ_GROUP_KEY_TYPE "type" -#define QQ_GROUP_KEY_CREATOR_UID "creator_uid" -#define QQ_GROUP_KEY_GROUP_CATEGORY "category" -#define QQ_GROUP_KEY_AUTH_TYPE "auth_type" -#define QQ_GROUP_KEY_GROUP_NAME_UTF8 "name_utf8" -#define QQ_GROUP_KEY_GROUP_DESC_UTF8 "desc_utf8" +#define QQ_ROOM_KEY_ROLE "my_role" +#define QQ_ROOM_KEY_ROLE_DESC "my_role_desc" +#define QQ_ROOM_KEY_INTERNAL_ID "id" +#define QQ_ROOM_KEY_EXTERNAL_ID "ext_id" +#define QQ_ROOM_KEY_TYPE "type" +#define QQ_ROOM_KEY_CREATOR_UID "creator_uid" +#define QQ_ROOM_KEY_CATEGORY "category" +#define QQ_ROOM_KEY_AUTH_TYPE "auth_type" +#define QQ_ROOM_KEY_TITLE_UTF8 "title_utf8" +#define QQ_ROOM_KEY_DESC_UTF8 "desc_utf8" -qq_group *qq_group_create_internal_record(PurpleConnection *gc, +qq_group *qq_group_create_internal_record(PurpleConnection *gc, guint32 internal_id, guint32 ext_id, gchar *group_name_utf8); void qq_group_delete_internal_record(qq_data *qd, guint32 id); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_join.c --- a/libpurple/protocols/qq/group_join.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_join.c Mon Sep 15 02:59:23 2008 +0000 @@ -42,10 +42,11 @@ #include "header_info.h" #include "packet_parse.h" #include "qq_network.h" +#include "qq_process.h" enum { - QQ_GROUP_JOIN_OK = 0x01, - QQ_GROUP_JOIN_NEED_AUTH = 0x02, + QQ_ROOM_JOIN_OK = 0x01, + QQ_ROOM_JOIN_NEED_AUTH = 0x02, }; static void _qq_group_exit_with_gc_and_id(gc_and_uid *g) @@ -68,20 +69,20 @@ { g_return_if_fail(group != NULL); - if (group->my_status == QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) { - group->my_status = QQ_GROUP_MEMBER_STATUS_APPLYING; + if (group->my_role == QQ_ROOM_ROLE_NO) { + group->my_role = QQ_ROOM_ROLE_REQUESTING; qq_group_refresh(gc, group); } switch (group->auth_type) { - case QQ_GROUP_AUTH_TYPE_NO_AUTH: - case QQ_GROUP_AUTH_TYPE_NEED_AUTH: + case QQ_ROOM_AUTH_TYPE_NO_AUTH: + case QQ_ROOM_AUTH_TYPE_NEED_AUTH: break; - case QQ_GROUP_AUTH_TYPE_NO_ADD: - purple_notify_warning(gc, NULL, _("This group does not allow others to join"), NULL); + case QQ_ROOM_AUTH_TYPE_NO_ADD: + purple_notify_warning(gc, NULL, _("The Qun does not allow others to join"), NULL); return; default: - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown group auth type: %d\n", group->auth_type); + purple_debug_error("QQ", "Unknown room auth type: %d\n", group->auth_type); break; } @@ -99,10 +100,10 @@ group = qq_room_search_id(gc, id); if (group == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Can not find qq_group by internal_id: %d\n", id); + purple_debug_error("QQ", "Can not find qq_group by internal_id: %d\n", id); return; } else { /* everything is OK */ - qq_send_cmd_group_auth(gc, group, QQ_GROUP_AUTH_REQUEST_APPLY, 0, reason_utf8); + qq_send_cmd_group_auth(gc, group, QQ_ROOM_AUTH_REQUEST_APPLY, 0, reason_utf8); } } @@ -112,10 +113,9 @@ gc_and_uid *g; g_return_if_fail(group != NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Group (internal id: %d) needs authentication\n", group->id); + purple_debug_info("QQ", "Group (internal id: %d) needs authentication\n", group->id); - msg = g_strdup_printf("Group \"%s\" needs authentication\n", group->group_name_utf8); + msg = g_strdup_printf("Group \"%s\" needs authentication\n", group->title_utf8); g = g_new0(gc_and_uid, 1); g->gc = gc; g->uid = group->id; @@ -125,7 +125,7 @@ _("Send"), G_CALLBACK(_qq_group_join_auth_with_gc_and_id), _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), - purple_connection_get_account(gc), group->group_name_utf8, NULL, + purple_connection_get_account(gc), group->title_utf8, NULL, g); g_free(msg); } @@ -143,8 +143,8 @@ else reason_qq = utf8_to_qq(reason_utf8, QQ_CHARSET_DEFAULT); - if (opt == QQ_GROUP_AUTH_REQUEST_APPLY) { - group->my_status = QQ_GROUP_MEMBER_STATUS_APPLYING; + if (opt == QQ_ROOM_AUTH_REQUEST_APPLY) { + group->my_role = QQ_ROOM_ROLE_REQUESTING; qq_group_refresh(gc, group); uid = 0; } @@ -173,8 +173,7 @@ qd = (qq_data *) gc->proto_data; if (len < 4) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid exit group reply, expect %d bytes, read %d bytes\n", 4, len); + purple_debug_error("QQ", "Invalid exit group reply, expect %d bytes, read %d bytes\n", 4, len); return; } @@ -189,7 +188,7 @@ purple_blist_remove_chat(chat); qq_group_delete_internal_record(qd, id); } - purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully left the group"), NULL); + purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully left the Qun"), NULL); } /* Process the reply to group_auth subcmd */ @@ -203,15 +202,15 @@ qd = (qq_data *) gc->proto_data; if (len < 4) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid join group reply, expect %d bytes, read %d bytes\n", 4, len); + purple_debug_error("QQ", + "Invalid join room reply, expect %d bytes, read %d bytes\n", 4, len); return; } bytes = 0; bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); - purple_notify_info(gc, _("QQ Group Auth"), + purple_notify_info(gc, _("QQ Qun Auth"), _("Your authorization request has been accepted by the QQ server"), NULL); } @@ -226,11 +225,11 @@ g_return_if_fail(data != NULL && len > 0); if (len < 5) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Invalid join group reply, expect %d bytes, read %d bytes\n", 5, len); return; } - + bytes = 0; bytes += qq_get32(&id, data + bytes); bytes += qq_get8(&reply, data + bytes); @@ -240,26 +239,26 @@ /* need to check if group is NULL or not. */ g_return_if_fail(group != NULL); switch (reply) { - case QQ_GROUP_JOIN_OK: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed joining group \"%s\"\n", group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; + case QQ_ROOM_JOIN_OK: + purple_debug_info("QQ", "Succeed joining group \"%s\"\n", group->title_utf8); + group->my_role = QQ_ROOM_ROLE_YES; qq_group_refresh(gc, group); /* this must be shown before getting online members */ qq_group_conv_show_window(gc, group); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); + qq_room_update(gc, 0, group->id); break; - case QQ_GROUP_JOIN_NEED_AUTH: - purple_debug(PURPLE_DEBUG_INFO, "QQ", + case QQ_ROOM_JOIN_NEED_AUTH: + purple_debug_info("QQ", "Fail joining group [%d] %s, needs authentication\n", - group->ext_id, group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + group->ext_id, group->title_utf8); + group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); _qq_group_join_auth(gc, group); break; default: - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Error joining group [%d] %s, unknown reply: 0x%02x\n", - group->ext_id, group->group_name_utf8, reply); + group->ext_id, group->title_utf8, reply); } } @@ -274,7 +273,7 @@ g_return_if_fail(data != NULL); qd = (qq_data *) gc->proto_data; - ext_id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID); + ext_id_ptr = g_hash_table_lookup(data, QQ_ROOM_KEY_EXTERNAL_ID); g_return_if_fail(ext_id_ptr != NULL); errno = 0; ext_id = strtol(ext_id_ptr, NULL, 10); @@ -301,7 +300,7 @@ g_return_if_fail(data != NULL); - id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID); + id_ptr = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID); id = strtol(id_ptr, NULL, 10); g_return_if_fail(id > 0); @@ -312,8 +311,7 @@ purple_request_action(gc, _("QQ Qun Operation"), _("Are you sure you want to leave this Qun?"), - _ - ("Note, if you are the creator, \nthis operation will eventually remove this Qun."), + _("Note, if you are the creator, \nthis operation will eventually remove this Qun."), 1, purple_connection_get_account(gc), NULL, NULL, g, 2, _("Cancel"), diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_join.h --- a/libpurple/protocols/qq/group_join.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_join.h Mon Sep 15 02:59:23 2008 +0000 @@ -30,15 +30,15 @@ #include "group.h" enum { - QQ_GROUP_AUTH_TYPE_NO_AUTH = 0x01, - QQ_GROUP_AUTH_TYPE_NEED_AUTH = 0x02, - QQ_GROUP_AUTH_TYPE_NO_ADD = 0x03 + QQ_ROOM_AUTH_TYPE_NO_AUTH = 0x01, + QQ_ROOM_AUTH_TYPE_NEED_AUTH = 0x02, + QQ_ROOM_AUTH_TYPE_NO_ADD = 0x03 }; enum { - QQ_GROUP_AUTH_REQUEST_APPLY = 0x01, - QQ_GROUP_AUTH_REQUEST_APPROVE = 0x02, - QQ_GROUP_AUTH_REQUEST_REJECT = 0x03 + QQ_ROOM_AUTH_REQUEST_APPLY = 0x01, + QQ_ROOM_AUTH_REQUEST_APPROVE = 0x02, + QQ_ROOM_AUTH_REQUEST_REJECT = 0x03 }; void qq_send_cmd_group_auth(PurpleConnection *gc, qq_group *group, guint8 opt, guint32 uid, const gchar *reason_utf8); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_opt.c --- a/libpurple/protocols/qq/group_opt.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.c Mon Sep 15 02:59:23 2008 +0000 @@ -38,6 +38,7 @@ #include "header_info.h" #include "packet_parse.h" #include "qq_network.h" +#include "qq_process.h" #include "utils.h" static int _compare_guint32(const void *a, @@ -67,7 +68,7 @@ } data_len = 6 + count * 4; data = g_newa(guint8, data_len); - + bytes = 0; bytes += qq_put8(data + bytes, operation); for (i = 0; i < count; i++) @@ -88,7 +89,7 @@ g_return_if_fail(g != NULL && g->gc != NULL && g->id > 0 && g->member > 0); group = qq_room_search_id(g->gc, g->id); g_return_if_fail(group != NULL); - qq_send_cmd_group_auth(g->gc, group, QQ_GROUP_AUTH_REQUEST_REJECT, g->member, msg_utf8); + qq_send_cmd_group_auth(g->gc, group, QQ_ROOM_AUTH_REQUEST_REJECT, g->member, msg_utf8); g_free(g); } @@ -111,11 +112,11 @@ g_return_if_fail(g != NULL && g->gc != NULL && g->member > 0); msg1 = g_strdup_printf(_("You rejected %d's request"), g->member); - msg2 = g_strdup(_("Enter your reason:")); + msg2 = g_strdup(_("Message:")); nombre = uid_to_purple_name(g->member); purple_request_input(g->gc, /* title */ NULL, msg1, msg2, - _("Sorry, you are not my type..."), /* multiline */ TRUE, /* masked */ FALSE, + _("Sorry, you are not my style..."), /* multiline */ TRUE, /* masked */ FALSE, /* hint */ NULL, _("Send"), G_CALLBACK(_qq_group_reject_application_real), _("Cancel"), G_CALLBACK(_qq_group_do_nothing_with_struct), @@ -133,7 +134,7 @@ g_return_if_fail(g != NULL && g->gc != NULL && g->id > 0 && g->member > 0); group = qq_room_search_id(g->gc, g->id); g_return_if_fail(group != NULL); - qq_send_cmd_group_auth(g->gc, group, QQ_GROUP_AUTH_REQUEST_APPROVE, g->member, ""); + qq_send_cmd_group_auth(g->gc, group, QQ_ROOM_AUTH_REQUEST_APPROVE, g->member, ""); qq_group_find_or_add_member(g->gc, group, g->member); g_free(g); } @@ -189,9 +190,9 @@ qq_group_find_or_add_member(gc, group, add_members[i]); if (del > 0) - _qq_group_member_opt(gc, group, QQ_GROUP_MEMBER_DEL, del_members); + _qq_group_member_opt(gc, group, QQ_ROOM_MEMBER_DEL, del_members); if (add > 0) - _qq_group_member_opt(gc, group, QQ_GROUP_MEMBER_ADD, add_members); + _qq_group_member_opt(gc, group, QQ_ROOM_MEMBER_ADD, add_members); } void qq_group_process_modify_members_reply(guint8 *data, gint len, PurpleConnection *gc) @@ -209,9 +210,10 @@ group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in modify members for Qun %d\n", group->ext_id); + purple_debug_info("QQ", "Succeed in modify members for room %d\n", group->ext_id); - purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully modified Qun member"), NULL); + purple_notify_info(gc, _("QQ Qun Operation"), + _("You have successfully modified Qun member"), NULL); } void qq_room_change_info(PurpleConnection *gc, qq_group *group) @@ -223,8 +225,8 @@ g_return_if_fail(group != NULL); - group_name = group->group_name_utf8 == NULL ? "" : utf8_to_qq(group->group_name_utf8, QQ_CHARSET_DEFAULT); - group_desc = group->group_desc_utf8 == NULL ? "" : utf8_to_qq(group->group_desc_utf8, QQ_CHARSET_DEFAULT); + group_name = group->title_utf8 == NULL ? "" : utf8_to_qq(group->title_utf8, QQ_CHARSET_DEFAULT); + group_desc = group->desc_utf8 == NULL ? "" : utf8_to_qq(group->desc_utf8, QQ_CHARSET_DEFAULT); notice = group->notice_utf8 == NULL ? "" : utf8_to_qq(group->notice_utf8, QQ_CHARSET_DEFAULT); data_len = 64 + strlen(group_name) + strlen(group_desc) + strlen(notice); @@ -237,7 +239,7 @@ /* 007-008 */ bytes += qq_put16(data + bytes, 0x0000); /* 009-010 */ - bytes += qq_put16(data + bytes, group->group_category); + bytes += qq_put16(data + bytes, group->category); bytes += qq_put8(data + bytes, strlen(group_name)); bytes += qq_putdata(data + bytes, (guint8 *) group_name, strlen(group_name)); @@ -251,7 +253,7 @@ bytes += qq_putdata(data + bytes, (guint8 *) group_desc, strlen(group_desc)); if (bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Overflow in qq_room_change_info, max %d bytes, now %d bytes\n", data_len, bytes); return; @@ -274,7 +276,7 @@ group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in modify info for Qun %d\n", group->ext_id); + purple_debug_info("QQ", "Succeed in modify info for Qun %d\n", group->ext_id); qq_group_refresh(gc, group); purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully modified Qun information"), NULL); @@ -297,9 +299,9 @@ bytes = 0; /* we create the simpleset group, only group name is given */ /* 001 */ - bytes += qq_put8(data + bytes, QQ_GROUP_TYPE_PERMANENT); + bytes += qq_put8(data + bytes, QQ_ROOM_TYPE_PERMANENT); /* 002 */ - bytes += qq_put8(data + bytes, QQ_GROUP_AUTH_TYPE_NEED_AUTH); + bytes += qq_put8(data + bytes, QQ_ROOM_AUTH_TYPE_NEED_AUTH); /* 003-004 */ bytes += qq_put16(data + bytes, 0x0000); /* 005-006 */ @@ -313,7 +315,7 @@ bytes += qq_put32(data + bytes, qd->uid); /* I am member of coz */ if (bytes > data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Overflow in qq_room_create, max %d bytes, now %d bytes\n", data_len, bytes); return; @@ -352,14 +354,14 @@ g_return_if_fail(id > 0 && ext_id); group = qq_group_create_internal_record(gc, id, ext_id, NULL); - group->my_status = QQ_GROUP_MEMBER_STATUS_IS_ADMIN; + group->my_role = QQ_ROOM_ROLE_ADMIN; group->creator_uid = qd->uid; qq_group_refresh(gc, group); qq_send_room_cmd_only(gc, QQ_ROOM_CMD_ACTIVATE, id); - qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, id); + qq_room_update(gc, 0, group->id); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in create Qun, external ID %d\n", group->ext_id); + purple_debug_info("QQ", "Succeed in create Qun, external ID %d\n", group->ext_id); g = g_new0(gc_and_uid, 1); g->gc = gc; @@ -368,7 +370,7 @@ purple_request_action(gc, _("QQ Qun Operation"), _("You have successfully created a Qun"), _ - ("Would you like to set up the Qun details now?"), + ("Would you like to set up the detail information now?"), 1, purple_connection_get_account(gc), NULL, NULL, g, 2, @@ -391,7 +393,7 @@ group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in activate Qun %d\n", group->ext_id); + purple_debug_info("QQ", "Succeed in activate Qun %d\n", group->ext_id); } void qq_group_manage_group(PurpleConnection *gc, GHashTable *data) @@ -402,7 +404,7 @@ g_return_if_fail(data != NULL); - id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID); + id_ptr = g_hash_table_lookup(data, QQ_ROOM_KEY_INTERNAL_ID); id = strtol(id_ptr, NULL, 10); g_return_if_fail(id > 0); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_opt.h --- a/libpurple/protocols/qq/group_opt.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.h Mon Sep 15 02:59:23 2008 +0000 @@ -38,13 +38,13 @@ } group_member_opt; enum { - QQ_GROUP_TYPE_PERMANENT = 0x01, - QQ_GROUP_TYPE_TEMPORARY + QQ_ROOM_TYPE_PERMANENT = 0x01, + QQ_ROOM_TYPE_TEMPORARY }; enum { - QQ_GROUP_MEMBER_ADD = 0x01, - QQ_GROUP_MEMBER_DEL + QQ_ROOM_MEMBER_ADD = 0x01, + QQ_ROOM_MEMBER_DEL }; void qq_group_modify_members(PurpleConnection *gc, qq_group *group, guint32 *new_members); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/group_search.c --- a/libpurple/protocols/qq/group_search.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/group_search.c Mon Sep 15 02:59:23 2008 +0000 @@ -38,8 +38,8 @@ #include "qq_network.h" enum { - QQ_GROUP_SEARCH_TYPE_BY_ID = 0x01, - QQ_GROUP_SEARCH_TYPE_DEMO = 0x02 + QQ_ROOM_SEARCH_TYPE_BY_ID = 0x01, + QQ_ROOM_SEARCH_TYPE_DEMO = 0x02 }; /* send packet to search for qq_group */ @@ -49,7 +49,7 @@ gint bytes = 0; guint8 type; - type = (ext_id == 0x00000000) ? QQ_GROUP_SEARCH_TYPE_DEMO : QQ_GROUP_SEARCH_TYPE_BY_ID; + type = (ext_id == 0x00000000) ? QQ_ROOM_SEARCH_TYPE_DEMO : QQ_ROOM_SEARCH_TYPE_BY_ID; bytes = 0; bytes += qq_put8(raw_data + bytes, type); @@ -63,21 +63,21 @@ PurpleRoomlistRoom *room; gchar field[11]; - room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, group->group_name_utf8, NULL); + room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, group->title_utf8, NULL); g_snprintf(field, sizeof(field), "%d", group->ext_id); purple_roomlist_room_add_field(qd->roomlist, room, field); g_snprintf(field, sizeof(field), "%d", group->creator_uid); purple_roomlist_room_add_field(qd->roomlist, room, field); - purple_roomlist_room_add_field(qd->roomlist, room, group->group_desc_utf8); + purple_roomlist_room_add_field(qd->roomlist, room, group->desc_utf8); g_snprintf(field, sizeof(field), "%d", group->id); purple_roomlist_room_add_field(qd->roomlist, room, field); g_snprintf(field, sizeof(field), "%d", group->type8); purple_roomlist_room_add_field(qd->roomlist, room, field); g_snprintf(field, sizeof(field), "%d", group->auth_type); purple_roomlist_room_add_field(qd->roomlist, room, field); - g_snprintf(field, sizeof(field), "%d", group->group_category); + g_snprintf(field, sizeof(field), "%d", group->category); purple_roomlist_room_add_field(qd->roomlist, room, field); - purple_roomlist_room_add_field(qd->roomlist, room, group->group_name_utf8); + purple_roomlist_room_add_field(qd->roomlist, room, group->title_utf8); purple_roomlist_room_add(qd->roomlist, room); purple_roomlist_set_in_progress(qd->roomlist, FALSE); @@ -109,14 +109,14 @@ bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); - bytes += qq_get32(&(group.group_category), data + bytes); - bytes += convert_as_pascal_string(data + bytes, &(group.group_name_utf8), QQ_CHARSET_DEFAULT); + bytes += qq_get32(&(group.category), data + bytes); + bytes += convert_as_pascal_string(data + bytes, &(group.title_utf8), QQ_CHARSET_DEFAULT); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get8(&(group.auth_type), data + bytes); - bytes += convert_as_pascal_string(data + bytes, &(group.group_desc_utf8), QQ_CHARSET_DEFAULT); + bytes += convert_as_pascal_string(data + bytes, &(group.desc_utf8), QQ_CHARSET_DEFAULT); /* end of one qq_group */ if(bytes != len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!"); } @@ -125,7 +125,7 @@ qq_set_pending_id(&qd->joining_groups, group.ext_id, FALSE); if (qq_room_search_id(gc, group.id) == NULL) qq_group_create_internal_record(gc, - group.id, group.ext_id, group.group_name_utf8); + group.id, group.ext_id, group.title_utf8); qq_send_cmd_group_join_group(gc, &group); } else { _qq_setup_roomlist(qd, &group); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/header_info.c --- a/libpurple/protocols/qq/header_info.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/header_info.c Mon Sep 15 02:59:23 2008 +0000 @@ -122,7 +122,7 @@ case QQ_SERVER_0100: return "QQ Server 0100"; default: - return "Unknown"; + return "Unknown Version"; } } @@ -146,8 +146,8 @@ return "QQ_CMD_DEL_BUDDY"; case QQ_CMD_BUDDY_AUTH: return "QQ_CMD_BUDDY_AUTH"; - case QQ_CMD_CHANGE_ONLINE_STATUS: - return "QQ_CMD_CHANGE_ONLINE_STATUS"; + case QQ_CMD_CHANGE_STATUS: + return "QQ_CMD_CHANGE_STATUS"; case QQ_CMD_ACK_SYS_MSG: return "QQ_CMD_ACK_SYS_MSG"; case QQ_CMD_SEND_IM: @@ -172,10 +172,10 @@ return "QQ_CMD_TOKEN"; case QQ_CMD_RECV_MSG_SYS: return "QQ_CMD_RECV_MSG_SYS"; - case QQ_CMD_RECV_MSG_BUDDY_CHANGE_STATUS: - return "QQ_CMD_RECV_MSG_BUDDY_CHANGE_STATUS"; + case QQ_CMD_BUDDY_CHANGE_STATUS: + return "QQ_CMD_BUDDY_CHANGE_STATUS"; default: - return "Unknown"; + return "Unknown CMD"; } } @@ -204,8 +204,8 @@ return "QQ_ROOM_CMD_SEND_MSG"; case QQ_ROOM_CMD_GET_ONLINES: return "QQ_ROOM_CMD_GET_ONLINES"; - case QQ_ROOM_CMD_GET_MEMBER_INFO: - return "QQ_ROOM_CMD_GET_MEMBER_INFO"; + case QQ_ROOM_CMD_GET_BUDDIES: + return "QQ_ROOM_CMD_GET_BUDDIES"; case QQ_ROOM_CMD_CHANGE_CARD: return "QQ_ROOM_CMD_CHANGE_CARD"; case QQ_ROOM_CMD_GET_REALNAMES: @@ -231,6 +231,6 @@ case QQ_ROOM_CMD_TEMP_GET_MEMBERS: return "QQ_ROOM_CMD_TEMP_GET_MEMBERS"; default: - return "Unknown QQ Room Command"; + return "Unknown Room Command"; } } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/header_info.h --- a/libpurple/protocols/qq/header_info.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/header_info.h Mon Sep 15 02:59:23 2008 +0000 @@ -47,7 +47,7 @@ QQ_CMD_ADD_BUDDY_WO_AUTH = 0x0009, /* add buddy without auth */ QQ_CMD_DEL_BUDDY = 0x000a, /* delete a buddy */ QQ_CMD_BUDDY_AUTH = 0x000b, /* buddy authentication */ - QQ_CMD_CHANGE_ONLINE_STATUS = 0x000d, /* change my online status */ + QQ_CMD_CHANGE_STATUS = 0x000d, /* change my online status */ QQ_CMD_ACK_SYS_MSG = 0x0012, /* ack system message */ QQ_CMD_SEND_IM = 0x0016, /* send message */ QQ_CMD_RECV_IM = 0x0017, /* receive message */ @@ -59,11 +59,11 @@ QQ_CMD_GET_BUDDIES_ONLINE = 0x0027, /* get online buddies list */ QQ_CMD_CELL_PHONE_2 = 0x0029, /* cell phone 2 */ QQ_CMD_ROOM = 0x0030, /* room command */ - QQ_CMD_GET_BUDDIES_AND_ROOMS = 0x0058, + QQ_CMD_GET_BUDDIES_AND_ROOMS = 0x0058, QQ_CMD_GET_LEVEL = 0x005C, /* get level for one or more buddies */ QQ_CMD_TOKEN = 0x0062, /* get login token */ QQ_CMD_RECV_MSG_SYS = 0x0080, /* receive a system message */ - QQ_CMD_RECV_MSG_BUDDY_CHANGE_STATUS = 0x0081, /* buddy change status */ + QQ_CMD_BUDDY_CHANGE_STATUS = 0x0081, /* buddy change status */ }; const gchar *qq_get_cmd_desc(gint type); @@ -80,7 +80,7 @@ QQ_ROOM_CMD_QUIT = 0x09, QQ_ROOM_CMD_SEND_MSG = 0x0a, QQ_ROOM_CMD_GET_ONLINES = 0x0b, - QQ_ROOM_CMD_GET_MEMBER_INFO = 0x0c, + QQ_ROOM_CMD_GET_BUDDIES = 0x0c, QQ_ROOM_CMD_CHANGE_CARD = 0x0E, QQ_ROOM_CMD_GET_REALNAMES = 0x0F, diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/im.c --- a/libpurple/protocols/qq/im.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/im.c Mon Sep 15 02:59:23 2008 +0000 @@ -209,21 +209,17 @@ return "QQ_RECV_IM_TEMP_QUN_IM"; case QQ_RECV_IM_QUN_IM: return "QQ_RECV_IM_QUN_IM"; + case QQ_RECV_IM_NEWS: + return "QQ_RECV_IM_NEWS"; + case QQ_RECV_IM_FROM_BUDDY_2006: + return "QQ_RECV_IM_FROM_BUDDY_2006"; + case QQ_RECV_IM_FROM_UNKNOWN_2006: + return "QQ_RECV_IM_FROM_UNKNOWN_2006"; default: return "QQ_RECV_IM_UNKNOWN"; } } -/* when we receive a message, - * 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_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, * returns the bytes read if succeed, or -1 if there is any error */ static gint _qq_normal_im_common_read(guint8 *data, gint len, qq_recv_normal_im_common *common) @@ -240,13 +236,61 @@ bytes += qq_get16(&(common->normal_im_type), data + bytes); if (bytes != 28) { /* read common place fail */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Expect 28 bytes, read %d bytes\n", bytes); + purple_debug_error("QQ", "Expect 28 bytes, read %d bytes\n", bytes); return -1; } return bytes; } +static void _qq_process_recv_news(guint8 *data, gint data_len, PurpleConnection *gc) +{ + qq_data *qd = (qq_data *) gc->proto_data; + gint bytes; + guint8 *temp; + guint8 temp_len; + gchar *title, *brief, *url; + gchar *content, *content_utf8; + + g_return_if_fail(data != NULL && data_len != 0); + +#if 0 + qq_show_packet("Rcv news", data, data_len); +#endif + + temp = g_newa(guint8, data_len); + bytes = 4; // ignore unknown 4 bytes + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + title = g_strndup((gchar *)temp, temp_len); + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + brief = g_strndup((gchar *)temp, temp_len); + + bytes += qq_get8(&temp_len, data + bytes); + g_return_if_fail(bytes + temp_len <= data_len); + bytes += qq_getdata(temp, temp_len, data+bytes); + url = g_strndup((gchar *)temp, temp_len); + + content = g_strdup_printf(_("Title: %s\nBrief: %s\n\n%s"), title, brief, url); + content_utf8 = qq_to_utf8(content, QQ_CHARSET_DEFAULT); + + if (qd->is_show_news) { + purple_notify_info(gc, NULL, _("QQ Server News"), content_utf8); + } else { + purple_debug_info("QQ", "QQ Server news:\n%s", content_utf8); + } + g_free(title); + g_free(brief); + g_free(url); + g_free(content); + g_free(content_utf8); +} + /* process received normal text IM */ static void _qq_process_recv_normal_im_text(guint8 *data, gint len, qq_recv_normal_im_common *common, PurpleConnection *gc) { @@ -266,7 +310,7 @@ /* now it is QQ_NORMAL_IM_TEXT */ /* if (*cursor >= (data + len - 1)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n"); + purple_debug_warning("QQ", "Received normal IM text is empty\n"); return; } else */ @@ -313,9 +357,9 @@ } qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (qq_b != NULL) { - qq_b->client_version = common->sender_ver; + qq_b->client_version = common->sender_ver; } - + purple_msg_type = (im_text->msg_type == QQ_IM_AUTO_REPLY) ? PURPLE_MESSAGE_AUTO_RESP : 0; msg_with_purple_smiley = qq_smiley_to_purple(im_text->msg); @@ -350,19 +394,18 @@ bytes = _qq_normal_im_common_read(data, len, common); if (bytes < 0) { - purple_debug (PURPLE_DEBUG_ERROR, "QQ", - "Fail read the common part of normal IM\n"); + purple_debug_error("QQ", "Fail read the common part of normal IM\n"); return; } switch (common->normal_im_type) { case QQ_NORMAL_IM_TEXT: - purple_debug (PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Normal IM, text type:\n [%d] => [%d], src: %s (%04X)\n", common->sender_uid, common->receiver_uid, qq_get_ver_desc (common->sender_ver), common->sender_ver); if (bytes >= len - 1) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Received normal IM text is empty\n"); + purple_debug_warning("QQ", "Received normal IM text is empty\n"); return; } _qq_process_recv_normal_im_text(data + bytes, len - bytes, common, gc); @@ -382,16 +425,50 @@ case QQ_NORMAL_IM_FILE_NOTIFY: qq_process_recv_file_notify(data + bytes, len - bytes, common->sender_uid, gc); break; + case QQ_NORMAL_IM_FILE_REQUEST_TCP: + /* Check ReceivedFileIM::parseContents in eva*/ + /* some client use this function for detect invisable buddy*/ + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REQUEST_TCP\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_APPROVE_TCP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_APPROVE_TCP\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_REJECT_TCP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REJECT_TCP\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_PASV: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_PASV\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_EX_REQUEST_UDP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_REQUEST_TCP\n"); + qq_show_packet ("QQ", data, len); + break; + case QQ_NORMAL_IM_FILE_EX_REQUEST_ACCEPT: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_REQUEST_ACCEPT\n"); + qq_show_packet ("QQ", data, len); + break; + case QQ_NORMAL_IM_FILE_EX_REQUEST_CANCEL: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_REQUEST_CANCEL\n"); + qq_show_packet ("Not support", data, len); + break; + case QQ_NORMAL_IM_FILE_EX_NOTIFY_IP: + purple_debug_warning("QQ", "Normal IM, not support QQ_NORMAL_IM_FILE_EX_NOTIFY_IP\n"); + qq_show_packet ("Not support", data, len); + break; default: im_unprocessed = g_newa (qq_recv_normal_im_unprocessed, 1); im_unprocessed->common = common; im_unprocessed->unknown = data + bytes; im_unprocessed->length = len - bytes; /* a simple process here, maybe more later */ - purple_debug (PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Normal IM, unprocessed type [0x%04x], len %d\n", common->normal_im_type, im_unprocessed->length); - qq_show_packet ("QQ unk-im", im_unprocessed->unknown, im_unprocessed->length); + qq_show_packet ("QQ", im_unprocessed->unknown, im_unprocessed->length); return; } } @@ -412,7 +489,7 @@ reply = strtol(segments[0], NULL, 10); if (reply == QQ_RECV_SYS_IM_KICK_OUT) - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "We are kicked out by QQ server\n"); + purple_debug_warning("QQ", "We are kicked out by QQ server\n"); msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT); purple_notify_warning(gc, NULL, _("System Message"), msg_utf8); } @@ -475,7 +552,7 @@ g_datalist_clear(&attribs); } - purple_debug(PURPLE_DEBUG_INFO, "QQ_MESG", "send mesg: %s\n", msg); + purple_debug_info("QQ_MESG", "send mesg: %s\n", msg); msg_filtered = purple_markup_strip_html(msg); msg_len = strlen(msg_filtered); now = time(NULL); @@ -526,9 +603,9 @@ qq_show_packet("QQ_raw_data debug", raw_data, bytes); if (bytes == raw_len) /* create packet OK */ - qq_send_cmd(qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Fail creating send_im packet, expect %d bytes, build %d bytes\n", raw_len, bytes); if (font_color) @@ -549,10 +626,10 @@ qd = gc->proto_data; if (data[0] != QQ_SEND_IM_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Send IM fail\n"); + purple_debug_warning("QQ", "Send IM fail\n"); purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL); } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "IM ACK OK\n"); + purple_debug_info("QQ", "IM ACK OK\n"); } } @@ -569,16 +646,17 @@ qd = (qq_data *) gc->proto_data; if (data_len < 16) { /* we need to ack with the first 16 bytes */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM is too short\n"); + purple_debug_error("QQ", "MSG is too short\n"); return; } else { - _qq_send_packet_recv_im_ack(gc, seq, data); + /* when we receive a message, + * we send an ACK which is the first 16 bytes of incoming packet */ + qq_send_server_reply(gc, QQ_CMD_RECV_IM, seq, data, 16); } /* check len first */ if (data_len < 20) { /* length of im_header */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail read recv IM header, len should longer than 20 bytes, read %d bytes\n", data_len); + purple_debug_error("QQ", "Invald MSG header, len %d < 20\n", data_len); return; } @@ -594,77 +672,71 @@ /* im_header prepared */ if (im_header->receiver_uid != qd->uid) { /* should not happen */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM to [%d], NOT me\n", im_header->receiver_uid); + purple_debug_error("QQ", "MSG to [%d], NOT me\n", im_header->receiver_uid); return; } /* check bytes */ if (bytes >= data_len - 1) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Received IM is empty\n"); + purple_debug_warning("QQ", "Empty MSG\n"); return; } switch (im_header->im_type) { + case QQ_RECV_IM_NEWS: + _qq_process_recv_news(data + bytes, data_len - bytes, gc); + break; + case QQ_RECV_IM_FROM_BUDDY_2006: + case QQ_RECV_IM_FROM_UNKNOWN_2006: + case QQ_RECV_IM_TO_UNKNOWN: case QQ_RECV_IM_TO_BUDDY: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from buddy [%d], I am in his/her buddy list\n", im_header->sender_uid); - _qq_process_recv_normal_im(data + bytes, data_len - bytes, gc); /* position and rest length */ - break; - case QQ_RECV_IM_TO_UNKNOWN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from buddy [%d], I am a stranger to him/her\n", im_header->sender_uid); + purple_debug_info("QQ", "MSG from buddy [%d]\n", im_header->sender_uid); _qq_process_recv_normal_im(data + bytes, data_len - bytes, gc); break; case QQ_RECV_IM_UNKNOWN_QUN_IM: case QQ_RECV_IM_TEMP_QUN_IM: case QQ_RECV_IM_QUN_IM: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "IM from group, internal_id [%d]\n", im_header->sender_uid); + purple_debug_info("QQ", "MSG from room [%d]\n", im_header->sender_uid); /* sender_uid is in fact id */ - qq_process_recv_group_im(data + bytes, data_len - bytes, im_header->sender_uid, gc, im_header->im_type); + qq_process_room_msg_normal(data + bytes, data_len - bytes, im_header->sender_uid, gc, im_header->im_type); break; case QQ_RECV_IM_ADD_TO_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, added by group internal_id [%d]\n", im_header->sender_uid); + purple_debug_info("QQ", "Notice from [%d], Added\n", im_header->sender_uid); /* sender_uid is group id * we need this to create a dummy group and add to blist */ - qq_process_recv_group_im_been_added(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_been_added(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_DEL_FROM_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, removed by group internal_ID [%d]\n", im_header->sender_uid); + purple_debug_info("QQ", "Notice from room [%d], Removed\n", im_header->sender_uid); /* sender_uid is group id */ - qq_process_recv_group_im_been_removed(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_been_removed(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_APPLY_ADD_TO_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from group, apply to join group internal_ID [%d]\n", im_header->sender_uid); + purple_debug_info("QQ", "Notice from room [%d], Joined\n", im_header->sender_uid); /* sender_uid is group id */ - qq_process_recv_group_im_apply_join(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_apply_join(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM for group system info, approved by group internal_id [%d]\n", + purple_debug_info("QQ", "Notice from room [%d], Confirm add in\n", im_header->sender_uid); /* sender_uid is group id */ - qq_process_recv_group_im_been_approved(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_been_approved(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_REJCT_APPLY_ADD_TO_QUN: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM for group system info, rejected by group internal_id [%d]\n", + purple_debug_info("QQ", "Notice from room [%d], Refuse add in\n", im_header->sender_uid); /* sender_uid is group id */ - qq_process_recv_group_im_been_rejected(data + bytes, data_len - bytes, im_header->sender_uid, gc); + qq_process_room_msg_been_rejected(data + bytes, data_len - bytes, im_header->sender_uid, gc); break; case QQ_RECV_IM_SYS_NOTIFICATION: - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "IM from [%d], should be a system administrator\n", im_header->sender_uid); + purple_debug_info("QQ", "Admin notice from [%d]\n", im_header->sender_uid); _qq_process_recv_sys_im(data + bytes, data_len - bytes, gc); break; default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "IM from [%d], [0x%02x] %s is not processed\n", - im_header->sender_uid, - im_header->im_type, qq_get_recv_im_type_str(im_header->im_type)); + purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%02x]\n", + im_header->sender_uid, qq_get_recv_im_type_str(im_header->im_type), + im_header->im_type); + qq_show_packet("Unknown MSG type", data, data_len); } } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/im.h --- a/libpurple/protocols/qq/im.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/im.h Mon Sep 15 02:59:23 2008 +0000 @@ -41,6 +41,7 @@ enum { QQ_RECV_IM_TO_BUDDY = 0x0009, QQ_RECV_IM_TO_UNKNOWN = 0x000a, + QQ_RECV_IM_NEWS = 0x0018, QQ_RECV_IM_UNKNOWN_QUN_IM = 0x0020, QQ_RECV_IM_ADD_TO_QUN = 0x0021, QQ_RECV_IM_DEL_FROM_QUN = 0x0022, @@ -50,7 +51,9 @@ QQ_RECV_IM_CREATE_QUN = 0x0026, QQ_RECV_IM_TEMP_QUN_IM = 0x002A, QQ_RECV_IM_QUN_IM = 0x002B, - QQ_RECV_IM_SYS_NOTIFICATION = 0x0030 + QQ_RECV_IM_SYS_NOTIFICATION = 0x0030, + QQ_RECV_IM_FROM_BUDDY_2006 = 0x0084, + QQ_RECV_IM_FROM_UNKNOWN_2006 = 0x0085, }; guint8 *qq_get_send_im_tail(const gchar *font_color, diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/packet_parse.c --- a/libpurple/protocols/qq/packet_parse.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.c Mon Sep 15 02:59:23 2008 +0000 @@ -46,8 +46,8 @@ memcpy(&b_dest, buf, sizeof(b_dest)); *b = b_dest; #ifdef PARSER_DEBUG - 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); + purple_debug_info("QQ", "[DBG][get8] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][get8] b_dest 0x%2x, *b 0x%02x\n", b_dest, *b); #endif return sizeof(b_dest); } @@ -61,8 +61,8 @@ memcpy(&w_dest, buf, sizeof(w_dest)); *w = g_ntohs(w_dest); #ifdef PARSER_DEBUG - 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); + purple_debug_info("QQ", "[DBG][get16] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][get16] w_dest 0x%04x, *w 0x%04x\n", w_dest, *w); #endif return sizeof(w_dest); } @@ -75,8 +75,8 @@ memcpy(&dw_dest, buf, sizeof(dw_dest)); *dw = g_ntohl(dw_dest); #ifdef PARSER_DEBUG - 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); + purple_debug_info("QQ", "[DBG][get32] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][get32] dw_dest 0x%08x, *dw 0x%08x\n", dw_dest, *dw); #endif return sizeof(dw_dest); } @@ -93,7 +93,7 @@ { memcpy(data, buf, datalen); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][getdata] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][getdata] buf %p\n", (void *)buf); #endif return datalen; } @@ -107,12 +107,12 @@ guint32 dw_dest; memcpy(&dw_dest, buf, sizeof(dw_dest)); #ifdef PARSER_DEBUG - 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); + purple_debug_info("QQ", "[DBG][getime] buf %p\n", (void *)buf); + 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_INFO, "QQ", "[DBG][getime] dw_dest after 0x%08x\n", dw_dest); + 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); @@ -125,8 +125,8 @@ { memcpy(buf, &b, sizeof(b)); #ifdef PARSER_DEBUG - 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); + purple_debug_info("QQ", "[DBG][put8] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][put8] b 0x%02x\n", b); #endif return sizeof(b); } @@ -139,8 +139,8 @@ guint16 w_porter; w_porter = g_htons(w); #ifdef PARSER_DEBUG - 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); + purple_debug_info("QQ", "[DBG][put16] buf %p\n", (void *)buf); + 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); @@ -154,8 +154,8 @@ guint32 dw_porter; dw_porter = g_htonl(dw); #ifdef PARSER_DEBUG - 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); + purple_debug_info("QQ", "[DBG][put32] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter); #endif memcpy(buf, &dw_porter, sizeof(dw_porter)); return sizeof(dw_porter); @@ -173,7 +173,7 @@ { memcpy(buf, data, datalen); #ifdef PARSER_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ", "[DBG][putdata] buf %p\n", (void *)buf); + purple_debug_info("QQ", "[DBG][putdata] buf %p\n", (void *)buf); #endif return datalen; } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Mon Sep 15 02:59:23 2008 +0000 @@ -24,10 +24,6 @@ #include "internal.h" -#ifdef _WIN32 -#define random rand -#endif - #include "accountopt.h" #include "debug.h" #include "notify.h" @@ -62,79 +58,72 @@ #define OPENQ_AUTHOR "Puzzlebird" #define OPENQ_WEBSITE "http://openq.sourceforge.net" -#define QQ_TCP_PORT 8000 -#define QQ_UDP_PORT 8000 +static GList *server_list_build(gchar select) +{ + GList *list = NULL; -static void server_list_create(PurpleAccount *account) { + if ( select == 'T' || select == 'A') { + list = g_list_append(list, "tcpconn.tencent.com:8000"); + list = g_list_append(list, "tcpconn2.tencent.com:8000"); + list = g_list_append(list, "tcpconn3.tencent.com:8000"); + list = g_list_append(list, "tcpconn4.tencent.com:8000"); + list = g_list_append(list, "tcpconn5.tencent.com:8000"); + list = g_list_append(list, "tcpconn6.tencent.com:8000"); + } + if ( select == 'U' || select == 'A') { + list = g_list_append(list, "sz.tencent.com:8000"); + list = g_list_append(list, "sz2.tencent.com:8000"); + list = g_list_append(list, "sz3.tencent.com:8000"); + list = g_list_append(list, "sz4.tencent.com:8000"); + list = g_list_append(list, "sz5.tencent.com:8000"); + list = g_list_append(list, "sz6.tencent.com:8000"); + list = g_list_append(list, "sz7.tencent.com:8000"); + list = g_list_append(list, "sz8.tencent.com:8000"); + list = g_list_append(list, "sz9.tencent.com:8000"); + } + return list; +} + +static void server_list_create(PurpleAccount *account) +{ PurpleConnection *gc; qq_data *qd; + PurpleProxyInfo *gpi; 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 = gc->proto_data; - 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) { - port = QQ_TCP_PORT; - } else { - port = QQ_UDP_PORT; - } - } - qd->user_port = port; + gpi = purple_proxy_get_setup(account); - 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); + qd->use_tcp = TRUE; + if (purple_proxy_info_get_type(gpi) == PURPLE_PROXY_UDP) { + qd->use_tcp = FALSE; } - if (qd->user_server != NULL) { - qd->servers = g_list_append(qd->servers, qd->user_server); + user_server = purple_account_get_string(account, "server", NULL); + purple_debug_info("QQ", "Select server '%s'\n", user_server); + if ( (user_server != NULL && strlen(user_server) > 0) && strcasecmp(user_server, "auto") != 0) { + qd->servers = g_list_append(qd->servers, g_strdup(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"); + qd->servers = server_list_build('T'); 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"); + + qd->servers = server_list_build('U'); } -static void server_list_remove_all(qq_data *qd) { +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"); + purple_debug_info("QQ", "free server list\n"); g_list_free(qd->servers); + qd->curr_server = NULL; } static void qq_login(PurpleAccount *account) @@ -151,6 +140,7 @@ gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_AUTO_RESP; qd = g_new0(qq_data, 1); + memset(qd, 0, sizeof(qq_data)); qd->gc = gc; gc->proto_data = qd; @@ -165,10 +155,31 @@ } server_list_create(account); - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Server list has %d\n", g_list_length(qd->servers)); + purple_debug_info("QQ", "Server list has %d\n", g_list_length(qd->servers)); + + qd->is_show_notice = purple_account_get_bool(account, "show_notice", TRUE); + qd->is_show_news = purple_account_get_bool(account, "show_news", TRUE); + + qd->itv_config.resend = purple_account_get_int(account, "resend_interval", 10); + if (qd->itv_config.resend <= 0) qd->itv_config.resend = 10; + + qd->itv_config.keep_alive = purple_account_get_int(account, "keep_alive_interval", 60); + if (qd->itv_config.keep_alive < 30) qd->itv_config.keep_alive = 30; + qd->itv_config.keep_alive /= qd->itv_config.resend; + qd->itv_count.keep_alive = qd->itv_config.keep_alive; - qq_connect(account); + qd->itv_config.update = purple_account_get_int(account, "update_interval", 300); + if (qd->itv_config.update > 0) { + if (qd->itv_config.update < qd->itv_config.keep_alive) { + qd->itv_config.update = qd->itv_config.keep_alive; + } + qd->itv_config.update /= qd->itv_config.resend; + qd->itv_count.update = qd->itv_config.update; + } else { + qd->itv_config.update = 0; + } + + qd->connect_watcher = purple_timeout_add_seconds(0, qq_connect_later, gc); } /* clean up the given QQ connection and free all resources */ @@ -179,12 +190,20 @@ g_return_if_fail(gc != NULL && gc->proto_data); qd = 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 = 0; + } + qq_disconnect(gc); - server_list_remove_all(qd); - + g_free(qd); - gc->proto_data = NULL; } @@ -212,7 +231,7 @@ g_string_append(status, _("Offline")); break; case QQ_BUDDY_ONLINE_NORMAL: - return NULL; + g_string_append(status, _("Online")); break; /* TODO What does this status mean? Labelling it as offline... */ case QQ_BUDDY_ONLINE_OFFLINE: @@ -303,8 +322,8 @@ g_string_append( str, _(" Video") ); } - if (q_bud->ext_flag & QQ_EXT_FLAG_SPACE) { - g_string_append( str, _(" Space") ); + if (q_bud->ext_flag & QQ_EXT_FLAG_ZONE) { + g_string_append( str, _(" Zone") ); } purple_notify_user_info_add_pair(user_info, _("Flag"), str->str); @@ -329,7 +348,7 @@ { /* each char** are refering to a filename in pixmaps/purple/status/default/ */ qq_buddy *q_bud; - + if (!b || !(q_bud = b->proto_data)) { return NULL; } @@ -374,11 +393,11 @@ } /* initiate QQ away with proper change_status packet */ -static void _qq_set_away(PurpleAccount *account, PurpleStatus *status) +static void _qq_change_status(PurpleAccount *account, PurpleStatus *status) { PurpleConnection *gc = purple_account_get_connection(account); - qq_send_packet_change_status(gc); + qq_request_change_status(gc, 0); } /* IMPORTANT: PurpleConvImFlags -> PurpleMessageFlags */ @@ -444,7 +463,7 @@ uid = purple_name_to_uid(who); if (uid <= 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Not valid QQid: %s\n", who); + purple_debug_error("QQ", "Not valid QQid: %s\n", who); purple_notify_error(gc, NULL, _("Invalid name"), NULL); return; } @@ -516,9 +535,8 @@ g_string_append(info, "
\n"); - g_string_append_printf(info, _("Server: %s: %d
\n"), qd->server_name, qd->real_port); + g_string_append_printf(info, _("Server: %s
\n"), qd->curr_server); g_string_append_printf(info, _("Connection Mode: %s
\n"), qd->use_tcp ? "TCP" : "UDP"); - g_string_append_printf(info, _("Real hostname: %s: %d
\n"), qd->real_hostname, qd->real_port); g_string_append_printf(info, _("My Public IP: %s
\n"), inet_ntoa(qd->my_ip)); g_string_append(info, "
\n"); @@ -633,7 +651,7 @@ PurpleMenuAction *act; m = NULL; - act = purple_menu_action_new(_("Leave this QQ Qun"), PURPLE_CALLBACK(_qq_menu_unsubscribe_group), NULL, NULL); + act = purple_menu_action_new(_("Leave the QQ Qun"), PURPLE_CALLBACK(_qq_menu_unsubscribe_group), NULL, NULL); m = g_list_append(m, act); /* TODO: enable this @@ -708,7 +726,7 @@ NULL, /* set_info */ NULL, /* send_typing */ _qq_get_info, /* get_info */ - _qq_set_away, /* set_away */ + _qq_change_status, /* change status */ NULL, /* set_idle */ NULL, /* change_passwd */ qq_add_buddy, /* add_buddy */ @@ -800,17 +818,50 @@ static void init_plugin(PurplePlugin *plugin) { PurpleAccountOption *option; + PurpleKeyValuePair *kvp; + GList *list = NULL; + GList *kvlist = NULL; + GList *entry; + 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"); + + kvlist = NULL; + kvp = g_new0(PurpleKeyValuePair, 1); + kvp->key = g_strdup(_("Auto")); + kvp->value = g_strdup("auto"); + kvlist = g_list_append(kvlist, kvp); + + entry = list; + while(entry) { + if (entry->data != NULL && strlen(entry->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); + } + entry = entry->next; + } + + /* option = purple_account_option_string_new(_("Server"), "server", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_int_new(_("Port"), "port", 0); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - - option = purple_account_option_bool_new(_("Connect using TCP"), "use_tcp", TRUE); + */ + option = purple_account_option_list_new(_("Server"), "server", kvlist); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new(_("resend interval(s)"), "resend_interval", 10); + option = purple_account_option_bool_new(_("Show server notice"), "show_notice", TRUE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_bool_new(_("Show server news"), "show_news", TRUE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_int_new(_("Resend interval(s)"), "resend_interval", 10); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_int_new(_("Keep alive interval(s)"), "keep_alive_interval", 60); @@ -825,6 +876,7 @@ purple_prefs_add_bool("/plugins/prpl/qq/show_status_by_icon", TRUE); purple_prefs_add_bool("/plugins/prpl/qq/show_fake_video", FALSE); purple_prefs_add_bool("/plugins/prpl/qq/prompt_group_msg_on_recv", TRUE); + } PURPLE_INIT_PLUGIN(qq, init_plugin, info); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq.h --- a/libpurple/protocols/qq/qq.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq.h Mon Sep 15 02:59:23 2008 +0000 @@ -68,45 +68,46 @@ guint16 timeRemainder; time_t signon; time_t idle; - time_t last_refresh; + time_t last_update; gint8 role; /* role in group, used only in group->members list */ }; +typedef struct _qq_connection qq_connection; +struct _qq_connection { + int fd; /* socket file handler */ + int input_handler; + + /* tcp related */ + int can_write_handler; /* use in tcp_send_out */ + PurpleCircBuffer *tcp_txbuf; + guint8 *tcp_rxqueue; + int tcp_rxlen; +}; + struct _qq_data { PurpleConnection *gc; - /* common network resource */ + GSList *openconns; + gboolean use_tcp; /* network in tcp or udp */ + PurpleProxyConnectData *conn_data; + gint fd; /* socket file handler */ + GList *servers; - gchar *user_server; - gint user_port; - gboolean use_tcp; /* network in tcp or udp */ + gchar *curr_server; /* point to servers->data, do not free*/ - gchar *server_name; - gboolean is_redirect; - gchar *real_hostname; /* from real connction */ - guint16 real_port; - 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 */ + struct in_addr redirect_ip; + guint16 redirect_port; + guint check_watcher; + guint connect_watcher; + gint connect_retry; qq_interval itv_config; qq_interval itv_count; - guint network_timeout; + guint network_watcher; GList *transactions; /* check ack packet and resend */ - /* tcp related */ - PurpleCircBuffer *tcp_txbuf; - guint8 *tcp_rxqueue; - int tcp_rxlen; - - /* udp related */ - PurpleDnsQueryData *udp_query_data; - guint32 uid; /* QQ number */ guint8 *token; /* get from server*/ int token_len; @@ -117,7 +118,8 @@ guint16 send_seq; /* send sequence number */ guint8 login_mode; /* online of invisible */ - gboolean logged_in; /* used by qq-add_buddy */ + gboolean is_login; /* used by qq-add_buddy */ + gboolean is_finish_update; PurpleXfer *xfer; /* file transfer handler */ @@ -148,6 +150,9 @@ /* TODO pass qq_send_packet_get_info() a callback and use signals to get rid of these */ gboolean modifying_info; gboolean modifying_face; + + gboolean is_show_notice; + gboolean is_show_news; }; #endif diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq_base.c --- a/libpurple/protocols/qq/qq_base.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.c Mon Sep 15 02:59:23 2008 +0000 @@ -48,7 +48,7 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x14, 0x11, 0x20, 0x03, 0x9d, 0xb2, 0xe6, 0xb3, 0x11, 0xb7, 0x13, - 0x95, 0x67, 0xda, 0x2c, 0x01 + 0x95, 0x67, 0xda, 0x2c, 0x01 }; */ /* for QQ 2003iii 0304, fixed value */ @@ -139,7 +139,7 @@ { guint8 src[QQ_KEY_LENGTH + QQ_KEY_LENGTH]; gint bytes = 0; - + bytes += qq_put32(src + bytes, uid); bytes += qq_putdata(src + bytes, session_key, QQ_KEY_LENGTH); @@ -161,7 +161,7 @@ bytes += qq_get8(&lrop.result, data + bytes); /* 001-016: session key */ bytes += qq_getdata(lrop.session_key, sizeof(lrop.session_key), data + bytes); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Got session_key\n"); + purple_debug_info("QQ", "Got session_key\n"); /* 017-020: login uid */ bytes += qq_get32(&lrop.uid, data + bytes); /* 021-024: server detected user public IP */ @@ -200,16 +200,16 @@ bytes += qq_getdata((guint8 *) &lrop.unknown6, 8, data + bytes); if (bytes != QQ_LOGIN_REPLY_OK_PACKET_LEN) { /* fail parsing login info */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Fail parsing login info, expect %d bytes, read %d bytes\n", 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)); get_session_md5(qd->session_md5, qd->uid, qd->session_key); - + qd->my_ip.s_addr = lrop.client_ip.s_addr; - + qd->my_port = lrop.client_port; qd->login_time = lrop.login_time; qd->last_login_time = lrop.last_login_time; @@ -237,39 +237,19 @@ bytes += qq_get16(&lrrp.new_server_port, data + bytes); if (bytes != QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + 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; } - + /* 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); - qd->real_hostname = NULL; - } - qd->real_hostname = g_strdup( inet_ntoa(lrrp.new_server_ip) ); - qd->real_port = lrrp.new_server_port; - + qd->redirect_ip.s_addr = lrrp.new_server_ip.s_addr; + qd->redirect_port = lrrp.new_server_port; return QQ_LOGIN_REPLY_REDIRECT; } -/* process login reply which says wrong password */ -static gint8 process_login_wrong_pwd(PurpleConnection *gc, guint8 *data, gint len) -{ - gchar *server_reply, *server_reply_utf8; - server_reply = g_new0(gchar, len); - g_memmove(server_reply, data + 1, len - 1); - server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT); - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Wrong password, server msg in UTF8: %s\n", server_reply_utf8); - g_free(server_reply); - g_free(server_reply_utf8); - - return QQ_LOGIN_REPLY_ERR_PWD; -} - /* request before login */ void qq_send_packet_token(PurpleConnection *gc) { @@ -281,9 +261,9 @@ qd = (qq_data *) gc->proto_data; bytes += qq_put8(buf + bytes, 0); - + qd->send_seq++; - qq_send_data(qd, QQ_CMD_TOKEN, qd->send_seq, TRUE, buf, bytes); + qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN, qd->send_seq, buf, bytes, TRUE); } /* send login packet to QQ server */ @@ -312,14 +292,14 @@ memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH); encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ - + bytes = 0; /* now generate the encrypted data * 000-015 use password_twice_md5 as key to encrypt empty string */ encrypted_len = qq_encrypt(raw_data + bytes, (guint8 *) "", 0, qd->password_twice_md5); g_return_if_fail(encrypted_len == 16); bytes += encrypted_len; - + /* 016-016 */ bytes += qq_put8(raw_data + bytes, 0x00); /* 017-020, used to be IP, now zero */ @@ -349,14 +329,15 @@ bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len); qd->send_seq++; - qq_send_data(qd, QQ_CMD_LOGIN, qd->send_seq, TRUE, buf, bytes); + qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); } -guint8 qq_process_token_reply(PurpleConnection *gc, gchar *error_msg, guint8 *buf, gint buf_len) +guint8 qq_process_token_reply(PurpleConnection *gc, guint8 *buf, gint buf_len) { qq_data *qd; guint8 ret; int token_len; + gchar *error_msg; g_return_val_if_fail(buf != NULL && buf_len != 0, -1); @@ -364,30 +345,37 @@ qd = (qq_data *) gc->proto_data; ret = buf[0]; - + if (ret != QQ_TOKEN_REPLY_OK) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown request login token reply code : %d\n", buf[0]); + purple_debug_error("QQ", "Failed to request token: %d\n", buf[0]); qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", buf, buf_len, ">>> [default] decrypt and dump"); error_msg = try_dump_as_gbk(buf, buf_len); + if (error_msg == NULL) { + error_msg = g_strdup_printf( _("Invalid token reply code, 0x%02X"), ret); + } + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); return ret; } - + token_len = buf_len-2; if (token_len <= 0) { error_msg = g_strdup_printf( _("Invalid token len, %d"), token_len); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); return -1; } - + if (buf[1] != token_len) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", + purple_debug_info("QQ", "Invalid token len. Packet specifies length of %d, actual length is %d\n", buf[1], buf_len-2); } qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", 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); @@ -402,48 +390,85 @@ qd = (qq_data *) gc->proto_data; for (i = 0; i < 4; i++) - qq_send_cmd_detail(qd, QQ_CMD_LOGOUT, 0xffff, FALSE, qd->password_twice_md5, QQ_KEY_LENGTH); + qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->password_twice_md5, QQ_KEY_LENGTH); - qd->logged_in = FALSE; /* update login status AFTER sending logout packets */ + qd->is_login = FALSE; /* update login status AFTER sending logout packets */ } /* process the login reply packet */ -guint8 qq_process_login_reply(guint8 *data, gint data_len, PurpleConnection *gc) +guint8 qq_process_login_reply( PurpleConnection *gc, guint8 *data, gint data_len) { qq_data *qd; - gchar* error_msg; + 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); qd = (qq_data *) gc->proto_data; - switch (data[0]) { + switch (ret) { case QQ_LOGIN_REPLY_OK: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is OK\n"); + purple_debug_info("QQ", "Login OK\n"); return process_login_ok(gc, data, data_len); case QQ_LOGIN_REPLY_REDIRECT: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is redirect\n"); + purple_debug_info("QQ", "Redirect new server\n"); return process_login_redirect(gc, data, data_len); + + case QQ_LOGIN_REPLY_REDIRECT_EX: + purple_debug_error("QQ", "Extend redirect new server, not supported yet\n"); + error_msg = g_strdup( _("Unable login for not support Redirect_EX now") ); + return QQ_LOGIN_REPLY_REDIRECT_EX; + case QQ_LOGIN_REPLY_ERR_PWD: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is error password\n"); - return process_login_wrong_pwd(gc, data, data_len); + server_reply = g_strndup((gchar *)data + 1, data_len - 1); + server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT); + + purple_debug_error("QQ", "Error password: %s\n", server_reply_utf8); + error_msg = g_strdup_printf( _("Error password: %s"), server_reply_utf8); + + g_free(server_reply); + g_free(server_reply_utf8); + + if (!purple_account_get_remember_password(gc->account)) { + purple_account_set_password(gc->account, NULL); + } + + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, error_msg); + g_free(error_msg); + + return QQ_LOGIN_REPLY_ERR_PWD; + case QQ_LOGIN_REPLY_NEED_REACTIVE: - case QQ_LOGIN_REPLY_REDIRECT_EX: - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is not actived or redirect extend\n"); + server_reply = g_strndup((gchar *)data + 1, data_len - 1); + server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT); + + purple_debug_error("QQ", "Need active: %s\n", server_reply_utf8); + error_msg = g_strdup_printf( _("Need active: %s"), server_reply_utf8); + + g_free(server_reply); + g_free(server_reply_utf8); + break; + default: - break; + purple_debug_error("QQ", + "Unable login for unknow reply code 0x%02X\n", data[0]); + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", + data, data_len, + ">>> [default] decrypt and dump"); + error_msg = try_dump_as_gbk(data, data_len); + if (error_msg == NULL) { + error_msg = g_strdup_printf( + _("Unable login for unknow reply code 0x%02X"), data[0] ); + } + break; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown reply code: 0x%02X\n", data[0]); - qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", - data, data_len, - ">>> [default] decrypt and dump"); - error_msg = try_dump_as_gbk(data, data_len); - if (error_msg) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); - g_free(error_msg); - } - return QQ_LOGIN_REPLY_ERR_MISC; + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + g_free(error_msg); + return ret; } /* send keep-alive packet to QQ server (it is a heart-beat) */ @@ -460,11 +485,11 @@ * the amount of online QQ users, my ip and port */ bytes += qq_put32(raw_data + bytes, qd->uid); - qq_send_cmd(qd, QQ_CMD_KEEP_ALIVE, raw_data, 4); + qq_send_cmd(gc, QQ_CMD_KEEP_ALIVE, raw_data, 4); } /* parse the return of keep-alive packet, it includes some system information */ -gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc) +gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; gchar **segments; @@ -478,7 +503,7 @@ /* the last one is 60, don't know what it is */ if (NULL == (segments = split_data(data, data_len, "\x1f", 6))) return TRUE; - + /* segments[0] and segment[1] are all 0x30 ("0") */ qd->total_online = strtol(segments[2], NULL, 10); if(0 == qd->total_online) { @@ -488,9 +513,9 @@ qd->my_ip.s_addr = inet_addr(segments[3]); qd->my_port = strtol(segments[4], NULL, 10); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "keep alive, %s:%d\n", + purple_debug_info("QQ", "keep alive, %s:%d\n", inet_ntoa(qd->my_ip), qd->my_port); - + g_strfreev(segments); return TRUE; } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq_base.h --- a/libpurple/protocols/qq/qq_base.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.h Mon Sep 15 02:59:23 2008 +0000 @@ -44,10 +44,10 @@ #define QQ_UPDATE_ONLINE_INTERVAL 300 /* in sec */ void qq_send_packet_token(PurpleConnection *gc); -guint8 qq_process_token_reply(PurpleConnection *gc, gchar *error_msg, guint8 *buf, gint buf_len); +guint8 qq_process_token_reply(PurpleConnection *gc, guint8 *buf, gint buf_len); void qq_send_packet_login(PurpleConnection *gc); -guint8 qq_process_login_reply(guint8 *data, gint data_len, PurpleConnection *gc); +guint8 qq_process_login_reply( PurpleConnection *gc, guint8 *data, gint data_len); void qq_send_packet_logout(PurpleConnection *gc); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq_network.c --- a/libpurple/protocols/qq/qq_network.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.c Mon Sep 15 02:59:23 2008 +0000 @@ -26,11 +26,6 @@ #include "debug.h" #include "internal.h" -#ifdef _WIN32 -#define random rand -#define srandom srand -#endif - #include "buddy_info.h" #include "group_info.h" #include "group_free.h" @@ -44,63 +39,100 @@ #include "utils.h" #include "qq_process.h" -/* set QQ_RECONNECT_MAX to 1, when test reconnecting */ -#define QQ_RECONNECT_MAX 4 -#define QQ_RECONNECT_INTERVAL 5000 -#define QQ_KEEP_ALIVE_INTERVAL 60000 -#define QQ_TRANS_INTERVAL 10000 +#define QQ_DEFAULT_PORT 8000 + +/* set QQ_CONNECT_MAX to 1, when test reconnecting */ +#define QQ_CONNECT_MAX 3 +#define QQ_CONNECT_INTERVAL 2 +#define QQ_CONNECT_CHECK 5 +#define QQ_KEEP_ALIVE_INTERVAL 60 +#define QQ_TRANS_INTERVAL 10 + +gboolean connect_to_server(PurpleConnection *gc, gchar *server, gint port); + +static qq_connection *connection_find(qq_data *qd, int fd) { + qq_connection *ret = NULL; + GSList *entry = qd->openconns; + while(entry) { + ret = entry->data; + if(ret->fd == fd) return ret; + entry = entry->next; + } + return NULL; +} +static qq_connection *connection_create(qq_data *qd, int fd) { + qq_connection *ret = g_new0(qq_connection, 1); + ret->fd = fd; + qd->openconns = g_slist_append(qd->openconns, ret); + return ret; +} + +static void connection_remove(qq_data *qd, int fd) { + qq_connection *conn = connection_find(qd, fd); + qd->openconns = g_slist_remove(qd->openconns, conn); + + g_return_if_fail( conn != NULL ); + + purple_debug_info("QQ", "Close socket %d\n", conn->fd); + if(conn->input_handler > 0) purple_input_remove(conn->input_handler); + if(conn->can_write_handler > 0) purple_input_remove(conn->can_write_handler); + + if (conn->fd >= 0) close(conn->fd); + if(conn->tcp_txbuf != NULL) purple_circ_buffer_destroy(conn->tcp_txbuf); + if (conn->tcp_rxqueue != NULL) g_free(conn->tcp_rxqueue); + + g_free(conn); +} + +static void connection_free_all(qq_data *qd) { + qq_connection *ret = NULL; + GSList *entry = qd->openconns; + while(entry) { + ret = entry->data; + connection_remove(qd, ret->fd); + entry = qd->openconns; + } +} 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"); + 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->curr_server != NULL) { + purple_debug_info("QQ", + "Remove current [%s] from server list\n", qd->curr_server); + qd->servers = g_list_remove(qd->servers, qd->curr_server); + qd->curr_server = 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); + 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; + index = rand() % 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); + qd->curr_server = it->data; /* do not free server_name */ + if (qd->curr_server == NULL || strlen(qd->curr_server) <= 0 ) { + 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); + purple_debug_info("QQ", "set new server to %s\n", qd->curr_server); return TRUE; } @@ -115,152 +147,208 @@ return bytes; } -static gboolean reconnect_later_cb(gpointer data) +static gboolean connect_check(gpointer data) { - PurpleConnection *gc; + PurpleConnection *gc = (PurpleConnection *) data; qq_data *qd; - gc = (PurpleConnection *) data; + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); + qd = (qq_data *) gc->proto_data; + + if (qd->connect_watcher > 0) { + purple_timeout_remove(qd->connect_watcher); + qd->connect_watcher = 0; + } + + if (qd->fd >= 0 && qd->token != NULL && qd->token_len >= 0) { + purple_debug_info("QQ", "Connect ok\n"); + return FALSE; + } + + qd->connect_watcher = purple_timeout_add_seconds(0, qq_connect_later, gc); + return FALSE; +} + +/* Warning: qq_connect_later destory all connection + * Any function should be care of use qq_data after call this function + * Please conside tcp_pending and udp_pending */ +gboolean qq_connect_later(gpointer data) +{ + PurpleConnection *gc = (PurpleConnection *) data; + qq_data *qd; + char *server; + int port; + gchar **segments; + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); qd = (qq_data *) gc->proto_data; - qd->reconnect_timeout = 0; + if (qd->check_watcher > 0) { + purple_timeout_remove(qd->check_watcher); + qd->check_watcher = 0; + } + qq_disconnect(gc); + + if (qd->redirect_ip.s_addr != 0) { + /* redirect to new server */ + server = g_strdup_printf("%s:%d", inet_ntoa(qd->redirect_ip), qd->redirect_port); + qd->servers = g_list_append(qd->servers, server); + qd->curr_server = server; + + qd->redirect_ip.s_addr = 0; + qd->redirect_port = 0; + qd->connect_retry = QQ_CONNECT_MAX; + } - qq_connect(gc->account); + if (qd->curr_server == NULL || strlen (qd->curr_server) == 0 || qd->connect_retry <= 0) { + if ( set_new_server(qd) != TRUE) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Failed to connect all servers")); + return FALSE; + } + qd->connect_retry = QQ_CONNECT_MAX; + } + + segments = g_strsplit_set(qd->curr_server, ":", 0); + server = g_strdup(segments[0]); + port = atoi(segments[1]); + if (port <= 0) { + purple_debug_info("QQ", "Port not define in %s\n", qd->curr_server); + port = QQ_DEFAULT_PORT; + } + g_strfreev(segments); + + qd->connect_retry--; + if ( !connect_to_server(gc, server, port) ) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Unable to connect.")); + } + + qd->check_watcher = purple_timeout_add_seconds(QQ_CONNECT_CHECK, connect_check, gc); 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); -} - /* process the incoming packet from qq_pending */ -static void packet_process(PurpleConnection *gc, guint8 *buf, gint buf_len) +static gboolean packet_process(PurpleConnection *gc, guint8 *buf, gint buf_len) { qq_data *qd; gint bytes, bytes_not_read; - gboolean prev_login_status; - + gboolean prev_update_status; + guint8 header_tag; guint16 source_tag; guint16 cmd; guint16 seq; /* May be ack_seq or send_seq, depends on cmd */ - guint8 room_cmd; guint32 room_id; + gint update_class; + guint32 ship32; qq_transaction *trans; - g_return_if_fail(buf != NULL && buf_len > 0); + g_return_val_if_fail(buf != NULL && buf_len > 0, TRUE); qd = (qq_data *) gc->proto_data; - prev_login_status = qd->logged_in; - /* Len, header and tail tag have been checked before */ bytes = 0; bytes += packet_get_header(&header_tag, &source_tag, &cmd, &seq, buf + bytes); #if 1 - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "==> [%05d] 0x%04X %s, from (0x%04X %s) len %d\n", - seq, cmd, qq_get_cmd_desc(cmd), source_tag, qq_get_ver_desc(source_tag), buf_len); -#endif + purple_debug_info("QQ", "==> [%05d] 0x%04X %s, source tag 0x%04X len %d\n", + seq, cmd, qq_get_cmd_desc(cmd), source_tag, buf_len); +#endif + /* this is the length of all the encrypted data (also remove tail tag) */ bytes_not_read = buf_len - bytes - 1; /* ack packet, we need to update send tranactions */ /* we do not check duplication for server ack */ - trans = qq_trans_find_rcved(qd, cmd, seq); + trans = qq_trans_find_rcved(gc, cmd, seq); if (trans == NULL) { /* new server command */ - qq_trans_add_server_cmd(qd, cmd, seq, buf + bytes, bytes_not_read); - if ( qd->logged_in ) { + qq_trans_add_server_cmd(gc, cmd, seq, buf + bytes, bytes_not_read); + if ( qd->is_finish_update ) { qq_proc_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); } - return; + return TRUE; } if (qq_trans_is_dup(trans)) { - purple_debug(PURPLE_DEBUG_WARNING, - "QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd)); - return; + purple_debug_info("QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd)); + return TRUE; } if (qq_trans_is_server(trans)) { - if ( qd->logged_in ) { + if ( qd->is_finish_update ) { qq_proc_cmd_server(gc, cmd, seq, buf + bytes, bytes_not_read); } - return; + return TRUE; } - /* this is the length of all the encrypted data (also remove tail tag */ - if (cmd == QQ_CMD_ROOM) { - room_cmd = qq_trans_get_room_cmd(trans); - room_id = qq_trans_get_room_id(trans); + update_class = qq_trans_get_class(trans); + ship32 = qq_trans_get_ship(trans); + + prev_update_status = qd->is_finish_update; + 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_LOGIN: + qq_proc_cmd_login(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; + } + 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; + case QQ_CMD_ROOM: + room_cmd = qq_trans_get_room_cmd(trans); + room_id = qq_trans_get_room_id(trans); #if 1 - purple_debug(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_reply(gc, seq, room_cmd, room_id, buf + bytes, bytes_not_read); - } else { - qq_proc_cmd_reply(gc, cmd, seq, buf + bytes, bytes_not_read); - } - - /* check is redirect or not, and do it now */ - if (qd->is_redirect) { - /* free resource except real_hostname and port */ - qq_disconnect(gc); - qd->reconnect_times = QQ_RECONNECT_MAX; - reconnect_later(gc); - return; + 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_reply(gc, seq, room_cmd, room_id, buf + bytes, bytes_not_read, update_class, ship32); + break; + default: + qq_proc_cmd_reply(gc, cmd, seq, buf + bytes, bytes_not_read, update_class, ship32); + break; } - if (prev_login_status != qd->logged_in && qd->logged_in == TRUE) { - /* logged_in, but we have packets before login */ - qq_trans_process_before_login(qd); + if (prev_update_status != qd->is_finish_update && qd->is_finish_update == TRUE) { + /* is_login, but we have packets before login */ + qq_trans_process_before_login(gc); + return TRUE; } + return TRUE; } static void tcp_pending(gpointer data, gint source, PurpleInputCondition cond) { - PurpleConnection *gc; + PurpleConnection *gc = (PurpleConnection *) data; qq_data *qd; + qq_connection *conn; guint8 buf[1024]; /* set to 16 when test tcp_rxqueue */ gint buf_len; gint bytes; - + guint8 *pkt; guint16 pkt_len; - + gchar *error_msg; guint8 *jump; gint jump_len; - gc = (PurpleConnection *) data; g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; if(cond != PURPLE_INPUT_READ) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, @@ -268,8 +356,9 @@ return; } - qd = (qq_data *) gc->proto_data; - + conn = connection_find(qd, source); + g_return_if_fail(conn != NULL); + /* test code, not using tcp_rxqueue memset(pkt,0, sizeof(pkt)); buf_len = read(qd->fd, pkt, sizeof(pkt)); @@ -278,8 +367,8 @@ } return; */ - - buf_len = read(qd->fd, buf, sizeof(buf)); + + buf_len = read(source, buf, sizeof(buf)); if (buf_len < 0) { if (errno == EAGAIN) /* No worries */ @@ -299,93 +388,93 @@ * QQ need a keep alive packet in every 60 seconds gc->last_received = time(NULL); */ - /* - purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", - "Read %d bytes from socket, rxlen is %d\n", buf_len, qd->tcp_rxlen); - */ - qd->tcp_rxqueue = g_realloc(qd->tcp_rxqueue, buf_len + qd->tcp_rxlen); - memcpy(qd->tcp_rxqueue + qd->tcp_rxlen, buf, buf_len); - qd->tcp_rxlen += buf_len; - + /* purple_debug_info("TCP_PENDING", "Read %d bytes, rxlen is %d\n", buf_len, conn->tcp_rxlen); */ + conn->tcp_rxqueue = g_realloc(conn->tcp_rxqueue, buf_len + conn->tcp_rxlen); + memcpy(conn->tcp_rxqueue + conn->tcp_rxlen, buf, buf_len); + conn->tcp_rxlen += buf_len; + pkt = g_newa(guint8, MAX_PACKET_SIZE); - while (1) { - if (qd->tcp_rxlen < QQ_TCP_HEADER_LENGTH) { + while (PURPLE_CONNECTION_IS_VALID(gc)) { + if (qd->openconns == NULL) { break; } - - bytes = 0; - bytes += qq_get16(&pkt_len, qd->tcp_rxqueue + bytes); - if (qd->tcp_rxlen < pkt_len) { + if (conn->tcp_rxqueue == NULL) { + conn->tcp_rxlen = 0; + break; + } + if (conn->tcp_rxlen < QQ_TCP_HEADER_LENGTH) { break; } - /* - purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", - "Packet len is %d bytes, rxlen is %d\n", pkt_len, qd->tcp_rxlen); - */ - 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? */ + bytes = 0; + bytes += qq_get16(&pkt_len, conn->tcp_rxqueue + bytes); + if (conn->tcp_rxlen < pkt_len) { + break; + } - purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", - "Packet error, failed to check header and tail tag\n"); + /* purple_debug_info("TCP_PENDING", "Packet len=%d, rxlen=%d\n", pkt_len, conn->tcp_rxlen); */ + if ( pkt_len < QQ_TCP_HEADER_LENGTH + || *(conn->tcp_rxqueue + bytes) != QQ_PACKET_TAG + || *(conn->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) { + /* HEY! This isn't even a QQ. What are you trying to pull? */ + purple_debug_warning("TCP_PENDING", "Packet error, no header or tail tag\n"); - jump = memchr(qd->tcp_rxqueue + 1, QQ_PACKET_TAIL, qd->tcp_rxlen - 1); + jump = memchr(conn->tcp_rxqueue + 1, QQ_PACKET_TAIL, conn->tcp_rxlen - 1); if ( !jump ) { - purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING", - "Failed to find next QQ_PACKET_TAIL, clear receive buffer\n"); - g_free(qd->tcp_rxqueue); - qd->tcp_rxqueue = NULL; - qd->tcp_rxlen = 0; + purple_debug_warning("TCP_PENDING", "Failed to find next tail, clear receive buffer\n"); + g_free(conn->tcp_rxqueue); + conn->tcp_rxqueue = NULL; + conn->tcp_rxlen = 0; return; } /* 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); - g_memmove(qd->tcp_rxqueue, jump, qd->tcp_rxlen - jump_len); - qd->tcp_rxlen -= jump_len; + jump_len = (jump - conn->tcp_rxqueue) + 1; + purple_debug_warning("TCP_PENDING", "Find next tail at %d, jump %d\n", jump_len, jump_len + 1); + g_memmove(conn->tcp_rxqueue, jump, conn->tcp_rxlen - jump_len); + conn->tcp_rxlen -= jump_len; continue; } memset(pkt, 0, MAX_PACKET_SIZE); - g_memmove(pkt, qd->tcp_rxqueue + bytes, pkt_len - bytes); - + g_memmove(pkt, conn->tcp_rxqueue + bytes, pkt_len - bytes); + /* jump to next packet */ - qd->tcp_rxlen -= pkt_len; - if (qd->tcp_rxlen) { - /* - purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", "shrink tcp_rxqueue to %d\n", qd->tcp_rxlen); - */ - jump = g_memdup(qd->tcp_rxqueue + pkt_len, qd->tcp_rxlen); - g_free(qd->tcp_rxqueue); - qd->tcp_rxqueue = jump; + conn->tcp_rxlen -= pkt_len; + if (conn->tcp_rxlen) { + /* purple_debug_info("TCP_PENDING", "shrink tcp_rxqueue to %d\n", conn->tcp_rxlen); */ + jump = g_memdup(conn->tcp_rxqueue + pkt_len, conn->tcp_rxlen); + g_free(conn->tcp_rxqueue); + conn->tcp_rxqueue = jump; } else { - /* purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING", "free tcp_rxqueue\n"); */ - g_free(qd->tcp_rxqueue); - qd->tcp_rxqueue = NULL; + /* purple_debug_info("TCP_PENDING", "free tcp_rxqueue\n"); */ + g_free(conn->tcp_rxqueue); + conn->tcp_rxqueue = NULL; } if (pkt == NULL) { continue; } - /* do not call packet_process before jump - * packet_process may call disconnect and destory tcp_rxqueue */ - packet_process(gc, pkt, pkt_len - bytes); + /* packet_process may call disconnect and destory data like conn + * do not call packet_process before jump, + * break if packet_process return FALSE */ + if (packet_process(gc, pkt, pkt_len - bytes) == FALSE) { + purple_debug_info("TCP_PENDING", "Connection has been destory\n"); + break; + } } } static void udp_pending(gpointer data, gint source, PurpleInputCondition cond) { - PurpleConnection *gc; + PurpleConnection *gc = (PurpleConnection *) data; qq_data *qd; guint8 *buf; gint buf_len; gc = (PurpleConnection *) data; g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; if(cond != PURPLE_INPUT_READ) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, @@ -393,13 +482,10 @@ return; } - qd = (qq_data *) gc->proto_data; - g_return_if_fail(qd->fd >= 0); - buf = g_newa(guint8, MAX_PACKET_SIZE); /* here we have UDP proxy suppport */ - buf_len = read(qd->fd, buf, MAX_PACKET_SIZE); + buf_len = read(source, buf, MAX_PACKET_SIZE); if (buf_len <= 0) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to read from socket")); @@ -419,73 +505,95 @@ return; } } - + + /* packet_process may call disconnect and destory data like conn + * do not call packet_process before jump, + * break if packet_process return FALSE */ packet_process(gc, buf, buf_len); } -static gint udp_send_out(qq_data *qd, guint8 *data, gint data_len) +static gint udp_send_out(PurpleConnection *gc, guint8 *data, gint data_len) { + qq_data *qd; gint ret; - g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1); + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *) gc->proto_data; - /* - purple_debug(PURPLE_DEBUG_INFO, "UDP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); - */ - +#if 0 + purple_debug_info("UDP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); +#endif + errno = 0; ret = send(qd->fd, data, data_len, 0); if (ret < 0 && errno == EAGAIN) { return ret; } - + if (ret < 0) { /* TODO: what to do here - do we really have to disconnect? */ - purple_debug(PURPLE_DEBUG_ERROR, "UDP_SEND_OUT", "Send failed: %d, %s\n", errno, g_strerror(errno)); - purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); + purple_debug_error("UDP_SEND_OUT", "Send failed: %d, %s\n", errno, g_strerror(errno)); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); } return ret; } static void tcp_can_write(gpointer data, gint source, PurpleInputCondition cond) { - qq_data *qd = data; + PurpleConnection *gc = (PurpleConnection *) data; + qq_data *qd; + qq_connection *conn; int ret, writelen; - writelen = purple_circ_buffer_get_max_read(qd->tcp_txbuf); + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + conn = connection_find(qd, source); + g_return_if_fail(conn != NULL); + + writelen = purple_circ_buffer_get_max_read(conn->tcp_txbuf); if (writelen == 0) { - purple_input_remove(qd->tx_handler); - qd->tx_handler = 0; + purple_input_remove(conn->can_write_handler); + conn->can_write_handler = 0; return; } - ret = write(qd->fd, qd->tcp_txbuf->outptr, writelen); - purple_debug(PURPLE_DEBUG_ERROR, "TCP_CAN_WRITE", - "total %d bytes is sent %d\n", writelen, ret); + ret = write(source, conn->tcp_txbuf->outptr, writelen); + purple_debug_info("TCP_CAN_WRITE", "total %d bytes is sent %d\n", writelen, ret); if (ret < 0 && errno == EAGAIN) return; else if (ret < 0) { /* TODO: what to do here - do we really have to disconnect? */ - purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Write Error")); return; } - purple_circ_buffer_mark_read(qd->tcp_txbuf, ret); + purple_circ_buffer_mark_read(conn->tcp_txbuf, ret); } -static gint tcp_send_out(qq_data *qd, guint8 *data, gint data_len) +static gint tcp_send_out(PurpleConnection *gc, guint8 *data, gint data_len) { + qq_data *qd; + qq_connection *conn; gint ret; - g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1); + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *) gc->proto_data; - /* - purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); - */ + conn = connection_find(qd, qd->fd); + g_return_val_if_fail(conn, -1); - if (qd->tx_handler == 0) { +#if 0 + purple_debug_info("TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd); +#endif + + if (conn->can_write_handler == 0) { ret = write(qd->fd, data, data_len); } else { ret = -1; @@ -493,28 +601,28 @@ } /* - purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", + 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"); + 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? */ - purple_debug(PURPLE_DEBUG_ERROR, "TCP_SEND_OUT", + 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)); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); return ret; } if (ret < data_len) { - purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", + purple_debug_info("TCP_SEND_OUT", "Add %d bytes to buffer\n", data_len - ret); - if (qd->tx_handler == 0) { - qd->tx_handler = purple_input_add(qd->fd, PURPLE_INPUT_WRITE, tcp_can_write, qd); + if (conn->can_write_handler == 0) { + conn->can_write_handler = purple_input_add(qd->fd, PURPLE_INPUT_WRITE, tcp_can_write, gc); } - purple_circ_buffer_append(qd->tcp_txbuf, data + ret, data_len - ret); + purple_circ_buffer_append(conn->tcp_txbuf, data + ret, data_len - ret); } return ret; } @@ -528,17 +636,17 @@ g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, TRUE); qd = (qq_data *) gc->proto_data; - is_lost_conn = qq_trans_scan(qd); + is_lost_conn = qq_trans_scan(gc); if (is_lost_conn) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Connection lost")); return TRUE; } - if ( !qd->logged_in ) { + if ( !qd->is_login ) { return TRUE; } - + qd->itv_count.keep_alive--; if (qd->itv_count.keep_alive <= 0) { qd->itv_count.keep_alive = qd->itv_config.keep_alive; @@ -553,55 +661,30 @@ qd->itv_count.update--; if (qd->itv_count.update <= 0) { qd->itv_count.update = qd->itv_config.update; - qq_send_packet_get_buddies_online(gc, 0); - - qq_send_cmd_group_all_get_online_members(gc); + qq_update_online(gc, 0); return TRUE; } return TRUE; /* if return FALSE, timeout callback stops */ } -/* the callback function after socket is built - * we setup the qq protocol related configuration here */ -static void qq_connect_cb(gpointer data, gint source, const gchar *error_message) +static void do_request_token(PurpleConnection *gc) { qq_data *qd; - PurpleConnection *gc; gchar *conn_msg; const gchar *passwd; - PurpleAccount *account ; - - gc = (PurpleConnection *) data; - - if (!PURPLE_CONNECTION_IS_VALID(gc)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection\n"); - close(source); - return; - } - - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - - qd = (qq_data *) gc->proto_data; - account = purple_connection_get_account(gc); - - /* Connect is now complete; clear the PurpleProxyConnectData */ - qd->connect_data = NULL; - - if (source < 0) { /* socket returns -1 */ - 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); */ + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + /* QQ use random seq, to minimize duplicated packets */ - srandom(time(NULL)); - qd->send_seq = random() & 0x0000ffff; - qd->fd = source; - qd->logged_in = FALSE; + srand(time(NULL)); + qd->send_seq = rand() & 0xffff; + + qd->is_login = FALSE; + qd->is_finish_update = FALSE; qd->channel = 1; qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10); @@ -614,257 +697,94 @@ qq_get_md5(qd->password_twice_md5, sizeof(qd->password_twice_md5), qd->password_twice_md5, sizeof(qd->password_twice_md5)); - g_return_if_fail(qd->network_timeout == 0); - qd->itv_config.resend = purple_account_get_int(account, "resend_interval", 10); - if (qd->itv_config.resend <= 0) qd->itv_config.resend = 10; - - qd->itv_config.keep_alive = purple_account_get_int(account, "keep_alive_interval", 60); - if (qd->itv_config.keep_alive < 30) qd->itv_config.keep_alive = 30; - qd->itv_config.keep_alive /= qd->itv_config.resend; - qd->itv_count.keep_alive = qd->itv_config.keep_alive; - - qd->itv_config.update = purple_account_get_int(account, "update_interval", 300); - if (qd->itv_config.update > 0) { - if (qd->itv_config.update < qd->itv_config.keep_alive) { - qd->itv_config.update = qd->itv_config.keep_alive; - } - qd->itv_config.update /= qd->itv_config.resend; - qd->itv_count.update = qd->itv_config.update; - } else { - qd->itv_config.update = 0; - } - - qd->network_timeout = purple_timeout_add(qd->itv_config.resend *1000, network_timeout, gc); - - if (qd->use_tcp) - gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, tcp_pending, gc); - else - gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, udp_pending, gc); + 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("Login as %d", qd->uid); - purple_connection_update_progress(gc, conn_msg, QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS); + 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); } -static void udp_can_write(gpointer data, gint source, PurpleInputCondition cond) +/* the callback function after socket is built + * we setup the qq protocol related configuration here */ +static void connect_cb(gpointer data, gint source, const gchar *error_message) { PurpleConnection *gc; qq_data *qd; - socklen_t len; - int error=0, ret; - - gc = (PurpleConnection *) data; - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - - qd = (qq_data *) gc->proto_data; - - - purple_debug_info("proxy", "Connected.\n"); - - /* - * getsockopt after a non-blocking connect returns -1 if something is - * really messed up (bad descriptor, usually). Otherwise, it returns 0 and - * error holds what connect would have returned if it blocked until now. - * Thus, error == 0 is success, error == EINPROGRESS means "try again", - * and anything else is a real error. - * - * (error == EINPROGRESS can happen after a select because the kernel can - * be overly optimistic sometimes. select is just a hint that you might be - * able to do something.) - */ - len = sizeof(error); - ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len); - if (ret == 0 && error == EINPROGRESS) - return; /* we'll be called again later */ - - purple_input_remove(qd->tx_handler); - qd->tx_handler = 0; - if (ret < 0 || error != 0) { - if(ret != 0) - error = errno; - - close(source); - - purple_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", g_strerror(error)); - - qq_connect_cb(gc, -1, _("Unable to connect")); - return; - } - - qq_connect_cb(gc, source, NULL); -} - -static void udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) { - PurpleConnection *gc; - qq_data *qd; - struct sockaddr server_addr; - int addr_size; - gint fd = -1; - int flags; + PurpleAccount *account ; + qq_connection *conn; gc = (PurpleConnection *) data; g_return_if_fail(gc != NULL && gc->proto_data != NULL); 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 */ - qd->udp_query_data = NULL; + account = purple_connection_get_account(gc); - if (!hosts || !hosts->data) { - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Couldn't resolve host")); + /* conn_data will be destoryed */ + qd->conn_data = NULL; + + if (!PURPLE_CONNECTION_IS_VALID(gc)) { + purple_debug_info("QQ_CONN", "Invalid connection\n"); + close(source); return; } - addr_size = GPOINTER_TO_INT(hosts->data); - hosts = g_slist_remove(hosts, hosts->data); - memcpy(&server_addr, hosts->data, addr_size); - g_free(hosts->data); - - hosts = g_slist_remove(hosts, hosts->data); - while(hosts) { - hosts = g_slist_remove(hosts, hosts->data); - g_free(hosts->data); - hosts = g_slist_remove(hosts, hosts->data); - } - - fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Unable to create socket: %s\n", g_strerror(errno)); + if (source < 0) { /* socket returns -1 */ + purple_debug_info("QQ_CONN", + "Could not establish a connection with the server:\n%s\n", + error_message); + 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; } - /* we use non-blocking mode to speed up connection */ - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); + /* _qq_show_socket("Got login socket", source); */ + qd->fd = source; + conn = connection_create(qd, source); + if (qd->use_tcp) { + conn->input_handler = purple_input_add(source, PURPLE_INPUT_READ, tcp_pending, gc); + } else { + conn->input_handler = purple_input_add(source, PURPLE_INPUT_READ, udp_pending, gc); + } - /* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/ - * - * If a UDP socket is unconnected, which is the normal state after a - * bind() call, then send() or write() are not allowed, since no - * destination is available; only sendto() can be used to send data. - * - * Calling connect() on the socket simply records the specified address - * and port number as being the desired communications partner. That - * means that send() or write() are now allowed; they use the destination - * address and port given on the connect call as the destination of packets. - */ - if (connect(fd, &server_addr, addr_size) >= 0) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Connected.\n"); - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); - qq_connect_cb(gc, fd, NULL); - return; - } - - /* [EINPROGRESS] - * The socket is marked as non-blocking and the connection cannot be - * completed immediately. It is possible to select for completion by - * selecting the socket for writing. - * [EINTR] - * A signal interrupted the call. - * The connection is established asynchronously. - */ - if ((errno == EINPROGRESS) || (errno == EINTR)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n"); - qd->tx_handler = purple_input_add(fd, PURPLE_INPUT_WRITE, udp_can_write, gc); - return; - } - - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection failed: %s\n", g_strerror(errno)); - close(fd); + do_request_token( gc ); } -/* establish a generic QQ connection - * TCP/UDP, and direct/redirected */ -void qq_connect(PurpleAccount *account) +gboolean connect_to_server(PurpleConnection *gc, gchar *server, gint port) { - PurpleConnection *gc; + PurpleAccount *account ; qq_data *qd; gchar *conn_msg; - gc = purple_account_get_connection(account); - g_return_if_fail(gc != NULL && gc->proto_data != NULL); - + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE); + account = purple_connection_get_account(gc); 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 (server == NULL || strlen(server) == 0 || port == 0) { + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Invalid server or port")); + return FALSE; } - 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); + 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); - if (qd->is_redirect) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Redirect to %s:%d\n", - qd->real_hostname, qd->real_port); - } - qd->is_redirect = FALSE; - - qd->fd = -1; - qd->tx_handler = 0; - - /* 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) */ - if(qd->use_tcp) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "TCP Connect to %s:%d\n", - qd->real_hostname, qd->real_port); - - /* TODO: is there a good default grow size? */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Create tcp_txbuf\n"); - qd->tcp_txbuf = purple_circ_buffer_new(0); + purple_debug_info("QQ", "Connect to %s:%d\n", server, port); - qd->connect_data = purple_proxy_connect(NULL, account, - qd->real_hostname, qd->real_port, qq_connect_cb, gc); - if (qd->connect_data == NULL) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Unable to connect.")); - } - return; + if (qd->conn_data != NULL) { + purple_proxy_connect_cancel(qd->conn_data); + qd->conn_data = NULL; } - - purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Connect to %s:%d\n", - qd->real_hostname, qd->real_port); - - g_return_if_fail(qd->udp_query_data == NULL); - qd->udp_query_data = purple_dnsquery_a(qd->real_hostname, qd->real_port, - udp_host_resolved, gc); - if (qd->udp_query_data == NULL) { - purple_connection_error_reason(qd->gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Could not resolve hostname")); + qd->conn_data = purple_proxy_connect(gc, account, server, port, connect_cb, gc); + if ( qd->conn_data == NULL ) { + purple_debug_error("QQ", _("Couldn't create socket")); + return FALSE; } + return TRUE; } /* clean up qq_data structure and all its components @@ -876,65 +796,32 @@ g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Disconnecting ...\n"); + purple_debug_info("QQ", "Disconnecting ...\n"); - if (qd->network_timeout > 0) { - purple_timeout_remove(qd->network_timeout); - qd->network_timeout = 0; + if (qd->network_watcher > 0) { + purple_debug_info("QQ", "Remove network watcher\n"); + purple_timeout_remove(qd->network_watcher); + qd->network_watcher = 0; } /* finish all I/O */ - if (qd->fd >= 0 && qd->logged_in) { + if (qd->fd >= 0 && qd->is_login) { qq_send_packet_logout(gc); } - if (gc->inpa > 0) { - purple_input_remove(gc->inpa); - gc->inpa = 0; - } - - if (qd->fd >= 0) { - close(qd->fd); - 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); + /* not connected */ + if (qd->conn_data != NULL) { + purple_debug_info("QQ", "Connect cancel\n"); + purple_proxy_connect_cancel(qd->conn_data); + qd->conn_data = NULL; } - - 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) { - purple_input_remove(qd->tx_handler); - qd->tx_handler = 0; - } - if (qd->tcp_rxqueue != NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_rxqueue\n"); - g_free(qd->tcp_rxqueue); - qd->tcp_rxqueue = NULL; - qd->tcp_rxlen = 0; - } - - if (qd->udp_query_data != NULL) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy udp_query_data\n"); - purple_dnsquery_destroy(qd->udp_query_data); - qd->udp_query_data = NULL; - } + connection_free_all(qd); + qd->fd = -1; - qq_trans_remove_all(qd); - + qq_trans_remove_all(gc); + if (qd->token) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "free token\n"); + purple_debug_info("QQ", "free token\n"); g_free(qd->token); qd->token = NULL; qd->token_len = 0; @@ -952,13 +839,13 @@ qq_buddies_list_free(gc->account, qd); } -static gint encap(qq_data *qd, guint8 *buf, gint maxlen, guint16 cmd, guint16 seq, +static gint packet_encap(qq_data *qd, guint8 *buf, gint maxlen, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { gint bytes = 0; g_return_val_if_fail(qd != NULL && buf != NULL && maxlen > 0, -1); g_return_val_if_fail(data != NULL && data_len > 0, -1); - + /* QQ TCP packet has two bytes in the begining defines packet length * so leave room here to store packet size */ if (qd->use_tcp) { @@ -968,7 +855,7 @@ bytes += qq_put8(buf + bytes, QQ_PACKET_TAG); bytes += qq_put16(buf + bytes, QQ_CLIENT); bytes += qq_put16(buf + bytes, cmd); - + bytes += qq_put16(buf + bytes, seq); bytes += qq_put32(buf + bytes, qd->uid); @@ -984,109 +871,144 @@ } /* data has been encrypted before */ -gint qq_send_data(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, - guint8 *data, gint data_len) +static gint packet_send_out(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { + qq_data *qd; guint8 *buf; gint buf_len; gint bytes_sent; - g_return_val_if_fail(qd != NULL, -1); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *)gc->proto_data; g_return_val_if_fail(data != NULL && data_len > 0, -1); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); - buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, data, data_len); + buf_len = packet_encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, data, data_len); if (buf_len <= 0) { return -1; } if (qd->use_tcp) { - bytes_sent = tcp_send_out(qd, buf, buf_len); + bytes_sent = tcp_send_out(gc, buf, buf_len); } else { - bytes_sent = udp_send_out(qd, buf, buf_len); + bytes_sent = udp_send_out(gc, buf, buf_len); } - if (need_ack) { - qq_trans_add_client_cmd(qd, cmd, seq, data, data_len); - } - -#if 1 - /* qq_show_packet("QQ_SEND_DATA", buf, buf_len); */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "<== [%05d], 0x%04X %s, total %d bytes is sent %d\n", - seq, cmd, qq_get_cmd_desc(cmd), buf_len, bytes_sent); -#endif return bytes_sent; } -/* Encrypt data with session_key, then call qq_send_data */ -gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, - guint8 *data, gint data_len) +gint qq_send_cmd_encrypted(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len, gboolean need_ack) { + gint send_len; + +#if 1 + purple_debug_info("QQ", "<== [%05d], %s(0x%04X), datalen %d\n", + seq, qq_get_cmd_desc(cmd), cmd, data_len); +#endif + + send_len = packet_send_out(gc, cmd, seq, data, data_len); + if (need_ack) { + qq_trans_add_client_cmd(gc, cmd, seq, data, data_len, 0, 0); + } + return send_len; +} + +/* Encrypt data with session_key, and send packet out */ +static gint send_cmd_detail(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len, gboolean need_ack, gint update_class, guint32 ship32) +{ + qq_data *qd; guint8 *encrypted_data; gint encrypted_len; + gint bytes_sent; - g_return_val_if_fail(qd != NULL, -1); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *)gc->proto_data; g_return_val_if_fail(data != NULL && data_len > 0, -1); /* at most 16 bytes more */ encrypted_data = g_newa(guint8, data_len + 16); -#if 0 - purple_debug(PURPLE_DEBUG_INFO, "QQ_ENCRYPT", - "Before %d: [%05d] 0x%04X %s\n", - data_len, seq, cmd, qq_get_cmd_desc(cmd)); -#endif encrypted_len = qq_encrypt(encrypted_data, data, data_len, qd->session_key); if (encrypted_len < 16) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ_ENCRYPT", - "Error len %d: [%05d] 0x%04X %s\n", + purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] 0x%04X %s\n", encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); return -1; } -#if 0 - purple_debug(PURPLE_DEBUG_INFO, "QQ_ENCRYPT", - "After %d: [%05d] 0x%04X %s\n", - encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); -#endif - return qq_send_data(qd, cmd, seq, need_ack, encrypted_data, encrypted_len); + bytes_sent = packet_send_out(gc, cmd, seq, encrypted_data, encrypted_len); + + if (need_ack) { + qq_trans_add_client_cmd(gc, cmd, seq, encrypted_data, encrypted_len, update_class, ship32); + } + return bytes_sent; } -/* set seq and need_ack, then call qq_send_cmd_detail */ -gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint data_len) +gint qq_send_cmd_mess(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len, + gint update_class, guint32 ship32) { - g_return_val_if_fail(qd != NULL, -1); + qq_data *qd; + guint16 seq; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *) gc->proto_data; 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); + seq = ++qd->send_seq; +#if 1 + purple_debug_info("QQ", "<== [%05d], %s(0x%04X), datalen %d\n", + seq, qq_get_cmd_desc(cmd), cmd, data_len); +#endif + return send_cmd_detail(gc, cmd, seq, data, data_len, TRUE, update_class, ship32); } -gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, - guint8 *data, gint data_len) +/* set seq and need_ack, then call send_cmd_detail */ +gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len) { - return qq_send_room_cmd(gc, room_cmd, 0, data, data_len); + qq_data *qd; + guint16 seq; + gboolean need_ack; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + qd = (qq_data *) gc->proto_data; + g_return_val_if_fail(data != NULL && data_len > 0, -1); + + if (cmd != QQ_CMD_LOGOUT) { + seq = ++qd->send_seq; + need_ack = TRUE; + } else { + seq = 0xFFFF; + need_ack = FALSE; + } +#if 1 + purple_debug_info("QQ", "<== [%05d], %s(0x%04X), datalen %d\n", + seq, qq_get_cmd_desc(cmd), cmd, data_len); +#endif + return send_cmd_detail(gc, cmd, seq, data, data_len, need_ack, 0, 0); } -gint qq_send_room_cmd_only(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +/* set seq and need_ack, then call send_cmd_detail */ +gint qq_send_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { - g_return_val_if_fail(room_cmd > 0 && room_id > 0, -1); - return qq_send_room_cmd(gc, room_cmd, room_id, NULL, 0); +#if 1 + purple_debug_info("QQ", "<== [SRV-%05d], %s(0x%04X), datalen %d\n", + seq, qq_get_cmd_desc(cmd), cmd, data_len); +#endif + return send_cmd_detail(gc, cmd, seq, data, data_len, FALSE, 0, 0); } -gint qq_send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, - guint8 *data, gint data_len) +static gint send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len, gint update_class, guint32 ship32) { qq_data *qd; - guint8 *buf; gint buf_len; guint8 *encrypted_data; gint encrypted_len; gint bytes_sent; guint16 seq; - + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); qd = (qq_data *) gc->proto_data; @@ -1103,6 +1025,7 @@ if (data != NULL && data_len > 0) { buf_len += qq_putdata(buf + buf_len, data, data_len); } + qd->send_seq++; seq = qd->send_seq; @@ -1111,32 +1034,43 @@ encrypted_data = g_newa(guint8, buf_len + 16); encrypted_len = qq_encrypt(encrypted_data, buf, buf_len, qd->session_key); if (encrypted_len < 16) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ_ENCRYPT", - "Error len %d: [%05d] QQ_CMD_ROOM.(0x%02X %s)\n", - encrypted_len, seq, room_cmd, qq_get_room_cmd_desc(room_cmd)); - return -1; - } - - /* Encap header to buf */ - buf_len = encap(qd, buf, MAX_PACKET_SIZE, QQ_CMD_ROOM, seq, encrypted_data, encrypted_len); - if (buf_len <= 0) { + purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] %s (0x%02X)\n", + encrypted_len, seq, qq_get_room_cmd_desc(room_cmd), room_cmd); return -1; } - if (qd->use_tcp) { - bytes_sent = tcp_send_out(qd, buf, buf_len); - } else { - bytes_sent = udp_send_out(qd, buf, buf_len); - } - - qq_trans_add_room_cmd(qd, seq, room_cmd, room_id, buf, buf_len); - + bytes_sent = packet_send_out(gc, QQ_CMD_ROOM, seq, encrypted_data, encrypted_len); #if 1 /* qq_show_packet("QQ_SEND_DATA", buf, buf_len); */ - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "<== [%05d], QQ_CMD_ROOM.(0x%02X %s) to room %d, total %d bytes is sent %d\n", - seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, - buf_len, bytes_sent); + purple_debug_info("QQ", + "<== [%05d], %s (0x%02X) to room %d, datalen %d\n", + seq, qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len); #endif + + qq_trans_add_room_cmd(gc, seq, room_cmd, room_id, buf, buf_len, update_class, ship32); return bytes_sent; } + +gint qq_send_room_cmd_mess(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len, gint update_class, guint32 ship32) +{ + return send_room_cmd(gc, room_cmd, room_id, data, data_len, update_class, ship32); +} + +gint qq_send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len) +{ + return send_room_cmd(gc, room_cmd, room_id, data, data_len, 0, 0); +} + +gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, + guint8 *data, gint data_len) +{ + return send_room_cmd(gc, room_cmd, 0, data, data_len, 0, 0); +} + +gint qq_send_room_cmd_only(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +{ + g_return_val_if_fail(room_cmd > 0 && room_id > 0, -1); + return send_room_cmd(gc, room_cmd, room_id, NULL, 0, 0, 0); +} diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq_network.h --- a/libpurple/protocols/qq/qq_network.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.h Mon Sep 15 02:59:23 2008 +0000 @@ -32,19 +32,23 @@ #define QQ_CONNECT_STEPS 3 /* steps in connection */ -void qq_connect(PurpleAccount *account); +gboolean qq_connect_later(gpointer data); void qq_disconnect(PurpleConnection *gc); -void qq_connect_later(PurpleConnection *gc); -gint qq_send_cmd(qq_data *qd, guint16 cmd, guint8 *data, gint datalen); -gint qq_send_data(qq_data *qd, guint16 cmd, 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); +gint qq_send_cmd_encrypted(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len, gboolean need_ack); +gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, guint8 *data, gint datalen); +gint qq_send_cmd_mess(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len, + gint update_class, guint32 ship32); + +gint qq_send_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len); gint qq_send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len); +gint qq_send_room_cmd_mess(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len, gint update_class, guint32 ship32); gint qq_send_room_cmd_only(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); -gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, +gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, guint8 *data, gint data_len); #endif diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq_process.c --- a/libpurple/protocols/qq/qq_process.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Mon Sep 15 02:59:23 2008 +0000 @@ -26,11 +26,6 @@ #include "debug.h" #include "internal.h" -#ifdef _WIN32 -#define random rand -#define srandom srand -#endif - #include "buddy_info.h" #include "buddy_list.h" #include "buddy_opt.h" @@ -88,8 +83,7 @@ } } -void qq_proc_cmd_server(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) +void qq_proc_cmd_server(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) { qq_data *qd; @@ -102,20 +96,20 @@ data = g_newa(guint8, rcved_len); data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); if (data_len < 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Can not decrypt server cmd by session key, [%05d], 0x%04X %s, len %d\n", + purple_debug_warning("QQ", + "Can not decrypt server cmd by session key, [%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); return; } if (data_len <= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Server cmd decrypted is empty, [%05d], 0x%04X %s, len %d\n", + purple_debug_warning("QQ", + "Server cmd decrypted is empty, [%05d], 0x%04X %s, len %d\n", seq, cmd, qq_get_cmd_desc(cmd), rcved_len); return; } - + /* now process the packet */ switch (cmd) { case QQ_CMD_RECV_IM: @@ -124,7 +118,7 @@ case QQ_CMD_RECV_MSG_SYS: qq_process_msg_sys(data, data_len, seq, gc); break; - case QQ_CMD_RECV_MSG_BUDDY_CHANGE_STATUS: + case QQ_CMD_BUDDY_CHANGE_STATUS: qq_process_buddy_change_status(data, data_len, gc); break; default: @@ -133,74 +127,8 @@ } } -static void process_cmd_login(PurpleConnection *gc, guint8 *data, gint data_len) -{ - qq_data *qd; - guint ret_8; - - g_return_if_fail (gc != NULL && gc->proto_data != NULL); - - qd = (qq_data *) gc->proto_data; - - ret_8 = qq_process_login_reply(data, data_len, gc); - if (ret_8 == QQ_LOGIN_REPLY_OK) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login repliess OK; everything is fine\n"); - - purple_connection_set_state(gc, PURPLE_CONNECTED); - qd->logged_in = 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 goes on updating my icon/nickname, not showing info_window */ - qd->modifying_face = FALSE; - - qq_send_packet_get_info(gc, qd->uid, FALSE); - /* grab my level */ - qq_send_packet_get_level(gc, qd->uid); - - qq_send_packet_change_status(gc); - - /* refresh buddies */ - qq_send_packet_get_buddies_list(gc, 0); - - /* refresh groups */ - qq_send_packet_get_buddies_and_rooms(gc, 0); - - return; - } - - if (ret_8 == QQ_LOGIN_REPLY_REDIRECT) { - qd->is_redirect = TRUE; - /* - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Redirected to new server: %s:%d\n", qd->real_hostname, qd->real_port); - */ - return; - } - - if (ret_8 == QQ_LOGIN_REPLY_ERR_PWD) { - if (!purple_account_get_remember_password(gc->account)) { - purple_account_set_password(gc->account, NULL); - } - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Incorrect password.")); - return; - } - - if (ret_8 == QQ_LOGIN_REPLY_ERR_MISC) { - if (purple_debug_is_enabled()) - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to login. Check debug log.")); - else - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to login")); - return; - } -} - -static void process_room_cmd_notify(PurpleConnection *gc, - guint8 room_cmd, guint8 room_id, guint8 reply_cmd, guint8 reply, guint8 *data, gint data_len) +static void process_room_cmd_notify(PurpleConnection *gc, + guint8 room_cmd, guint8 room_id, guint8 reply, guint8 *data, gint data_len) { gchar *msg, *msg_utf8; g_return_if_fail(data != NULL && data_len > 0); @@ -208,23 +136,189 @@ msg = g_strndup((gchar *) data, data_len); /* it will append 0x00 */ msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); g_free(msg); - - msg = g_strdup_printf(_( - "Reply %s(0x%02X )\n" - "Sent %s(0x%02X )\n" - "Room id %d, reply [0x%02X]: \n" - "%s"), - qq_get_room_cmd_desc(reply_cmd), reply_cmd, - qq_get_room_cmd_desc(room_cmd), room_cmd, - room_id, reply, msg_utf8); - - purple_notify_error(gc, NULL, _("Failed room reply"), msg); + + msg = g_strdup_printf(_("Command %s(0x%02X) id %d, reply [0x%02X]:\n%s"), + qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, reply, msg_utf8); + + purple_notify_error(gc, NULL, _("Invalid QQ Qun reply"), msg); g_free(msg); g_free(msg_utf8); } -void qq_proc_room_cmd_reply(PurpleConnection *gc, - guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len) +void qq_room_update(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +{ + qq_data *qd; + qq_group *group; + gint ret; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + group = qq_room_search_id(gc, room_id); + if (group == NULL && room_id <= 0) { + purple_debug_info("QQ", "No room, nothing update\n"); + return; + } + if (group == NULL ) { + purple_debug_warning("QQ", "Failed search room id [%d]\n", room_id); + return; + } + + switch (room_cmd) { + case 0: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ROOM, 0); + break; + case QQ_ROOM_CMD_GET_INFO: + ret = qq_request_room_get_buddies(gc, group, QQ_CMD_CLASS_UPDATE_ROOM); + if (ret <= 0) { + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ROOM, 0); + } + break; + case QQ_ROOM_CMD_GET_BUDDIES: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ROOM, 0); + break; + case QQ_ROOM_CMD_GET_ONLINES: + /* last command */ + default: + break; + } +} + +static void update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +{ + qq_data *qd; + gboolean is_new_turn = FALSE; + qq_group *next_group; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + next_group = qq_room_get_next(gc, room_id); + if (next_group == NULL && room_id <= 0) { + purple_debug_info("QQ", "No room, nothing update\n"); + qd->is_finish_update = TRUE; + return; + } + if (next_group == NULL ) { + is_new_turn = TRUE; + next_group = qq_room_get_next(gc, 0); + g_return_if_fail(next_group != NULL); + } + + switch (room_cmd) { + case 0: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ALL, 0); + break; + case QQ_ROOM_CMD_GET_INFO: + if (!is_new_turn) { + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ALL, 0); + } else { + qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL); + } + break; + case QQ_ROOM_CMD_GET_BUDDIES: + /* last command */ + if (!is_new_turn) { + qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL); + } else { + qd->is_finish_update = TRUE; + } + break; + default: + break; + } +} + +void qq_update_all(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_buddy_info(gc, qd->uid, QQ_CMD_CLASS_UPDATE_ALL, QQ_BUDDY_INFO_UPDATE_ONLY); + break; + case QQ_CMD_GET_USER_INFO: + qq_request_change_status(gc, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_CHANGE_STATUS: + qq_request_get_buddies_list(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_GET_BUDDIES_LIST: + qq_request_get_buddies_and_rooms(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_GET_BUDDIES_AND_ROOMS: + qq_request_get_buddies_levels(gc, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_GET_LEVEL: + qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ALL); + break; + case QQ_CMD_GET_BUDDIES_ONLINE: + /* last command */ + update_all_rooms(gc, 0, 0); + break; + default: + break; + } +} + +static void update_all_rooms_online(PurpleConnection *gc, guint8 room_cmd, guint32 room_id) +{ + qq_data *qd; + qq_group *next_group; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + next_group = qq_room_get_next_conv(gc, room_id); + if (next_group == NULL && room_id <= 0) { + purple_debug_info("QQ", "No room, no update online buddies\n"); + return; + } + if (next_group == NULL ) { + purple_debug_info("QQ", "finished update online buddies\n"); + return; + } + + switch (room_cmd) { + case 0: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ALL, 0); + break; + case QQ_ROOM_CMD_GET_ONLINES: + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ALL, 0); + break; + default: + break; + } +} + +void qq_update_online(PurpleConnection *gc, guint16 cmd) +{ + switch (cmd) { + case 0: + qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ONLINE); + break; + case QQ_CMD_GET_BUDDIES_ONLINE: + /* last command */ + update_all_rooms_online(gc, 0, 0); + break; + default: + break; + } +} + +void qq_proc_room_cmd_reply(PurpleConnection *gc, guint16 seq, + guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, + gint update_class, guint32 ship32) { qq_data *qd; guint8 *data; @@ -239,58 +333,57 @@ data = g_newa(guint8, rcved_len); data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); if (data_len < 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Can not decrypt room cmd by session key, [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Can not decrypt room cmd by session key, [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); qq_show_packet("Can not decrypted", rcved, rcved_len); return; } if (room_id <= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Invaild room id, [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Invaild room id, [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); return; } if (data_len <= 2) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Invaild len of room cmd decrypted, [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Invaild len of room cmd decrypted, [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); return; } - + group = qq_room_search_id(gc, room_id); if (group == NULL) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Missing room id in [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Missing room id in [%05d], 0x%02X %s for %d, len %d\n", seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); } - + bytes = 0; bytes += qq_get8(&reply_cmd, data + bytes); bytes += qq_get8(&reply, data + bytes); if (reply_cmd != room_cmd) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Missing room cmd in reply 0x%02X %s, [%05d], 0x%02X %s for %d, len %d\n", + purple_debug_warning("QQ", + "Missing room cmd in reply 0x%02X %s, [%05d], 0x%02X %s for %d, len %d\n", reply_cmd, qq_get_room_cmd_desc(reply_cmd), seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len); } - + /* now process the packet */ if (reply != QQ_ROOM_CMD_REPLY_OK) { if (group != NULL) { qq_set_pending_id(&qd->joining_groups, group->ext_id, FALSE); } - + switch (reply) { /* this should be all errors */ case QQ_ROOM_CMD_REPLY_NOT_MEMBER: if (group != NULL) { - purple_debug(PURPLE_DEBUG_WARNING, - "QQ", - _("You are not a member of group \"%s\"\n"), group->group_name_utf8); - group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; + purple_debug_warning("QQ", + _("You are not a member of QQ Qun \"%s\"\n"), group->title_utf8); + group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); } break; @@ -300,7 +393,7 @@ purple_roomlist_set_in_progress(qd->roomlist, FALSE); } default: - process_room_cmd_notify(gc, room_cmd, room_id, reply_cmd, reply, data + bytes, data_len - bytes); + process_room_cmd_notify(gc, reply_cmd, room_id, reply, data + bytes, data_len - bytes); } return; } @@ -309,10 +402,6 @@ switch (reply_cmd) { case QQ_ROOM_CMD_GET_INFO: qq_process_room_cmd_get_info(data + bytes, data_len - bytes, gc); - if (group != NULL) { - qq_send_cmd_group_get_members_info(gc, group); - qq_send_cmd_group_get_online_members(gc, group); - } break; case QQ_ROOM_CMD_CREATE: qq_group_process_create_group_reply(data + bytes, data_len - bytes, gc); @@ -346,20 +435,80 @@ if (group != NULL) qq_group_conv_refresh_online_member(gc, group); break; - case QQ_ROOM_CMD_GET_MEMBER_INFO: - qq_process_room_cmd_get_members(data + bytes, data_len - bytes, gc); + case QQ_ROOM_CMD_GET_BUDDIES: + qq_process_room_cmd_get_buddies(data + bytes, data_len - bytes, gc); if (group != NULL) qq_group_conv_refresh_online_member(gc, group); break; default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Unknow room cmd 0x%02X %s\n", + purple_debug_warning("QQ", "Unknow room cmd 0x%02X %s\n", reply_cmd, qq_get_room_cmd_desc(reply_cmd)); } + + purple_debug_info("QQ", "Update class %d\n", update_class); + if (update_class == QQ_CMD_CLASS_UPDATE_ALL) { + update_all_rooms(gc, room_cmd, room_id); + return; + } + if (update_class == QQ_CMD_CLASS_UPDATE_ONLINE) { + update_all_rooms_online(gc, room_cmd, room_id); + return; + } + if (update_class == QQ_CMD_CLASS_UPDATE_ROOM) { + qq_room_update(gc, room_cmd, room_id); + } } -void qq_proc_cmd_reply(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) +void qq_proc_cmd_login(PurpleConnection *gc, guint8 *rcved, gint rcved_len) +{ + qq_data *qd; + guint8 *data; + gint data_len; + guint ret_8; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + 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->inikey); + 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 reply")); + return; + } + } + + ret_8 = qq_process_login_reply(gc, data, data_len); + if (ret_8 != QQ_LOGIN_REPLY_OK) { + return; + } + + 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 */ + + /* now initiate QQ Qun, do it first as it may take longer to finish */ + qq_group_init(gc); + + /* Now goes on updating my icon/nickname, not showing info_window */ + qd->modifying_face = FALSE; + + qq_update_all(gc, 0); + return; +} + +void qq_proc_cmd_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32) { qq_data *qd; @@ -370,7 +519,7 @@ guint8 ret_8 = 0; guint16 ret_16 = 0; guint32 ret_32 = 0; - gchar *error_msg = NULL; + gboolean is_unknow = FALSE; g_return_if_fail(rcved_len > 0); @@ -378,61 +527,23 @@ qd = (qq_data *) gc->proto_data; data = g_newa(guint8, rcved_len); - if (cmd == QQ_CMD_TOKEN) { - g_memmove(data, rcved, rcved_len); - data_len = rcved_len; - } else if (cmd == QQ_CMD_LOGIN) { - /* 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) { - purple_debug(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(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 reply")); - return; - } - } - } else { - data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); - if (data_len < 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Can not reply by session key, [%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); - return; - } + data_len = qq_decrypt(data, rcved, rcved_len, qd->session_key); + if (data_len < 0) { + purple_debug_warning("QQ", + "Reply can not be decrypted by session key, [%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); + return; } - + if (data_len <= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Reply decrypted is empty, [%05d], 0x%04X %s, len %d\n", + purple_debug_warning("QQ", + "Reply decrypted is empty, [%05d], 0x%04X %s, len %d\n", seq, cmd, qq_get_cmd_desc(cmd), rcved_len); return; } switch (cmd) { - case QQ_CMD_TOKEN: - ret_8 = qq_process_token_reply(gc, error_msg, data, data_len); - if (ret_8 != QQ_TOKEN_REPLY_OK) { - if (error_msg == NULL) { - error_msg = g_strdup_printf( _("Invalid token reply code, 0x%02X"), ret_8); - } - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); - g_free(error_msg); - return; - } - - qq_send_packet_login(gc); - break; - case QQ_CMD_LOGIN: - process_cmd_login(gc, data, data_len); - break; case QQ_CMD_UPDATE_INFO: qq_process_modify_info_reply(data, data_len, gc); break; @@ -451,7 +562,7 @@ case QQ_CMD_GET_USER_INFO: qq_process_get_info_reply(data, data_len, gc); break; - case QQ_CMD_CHANGE_ONLINE_STATUS: + case QQ_CMD_CHANGE_STATUS: qq_process_change_status_reply(data, data_len, gc); break; case QQ_CMD_SEND_IM: @@ -463,41 +574,53 @@ case QQ_CMD_GET_BUDDIES_ONLINE: ret_8 = qq_process_get_buddies_online_reply(data, data_len, gc); if (ret_8 > 0 && ret_8 < 0xff) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more online buddies\n"); - qq_send_packet_get_buddies_online(gc, ret_8); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "All online buddies received\n"); - /* Fixme: this should not be called once*/ - qq_send_packet_get_buddies_levels(gc); - - qq_refresh_all_buddy_status(gc); + purple_debug_info("QQ", "Requesting for more online buddies\n"); + qq_request_get_buddies_online(gc, ret_8, update_class); + return; } + purple_debug_info("QQ", "All online buddies received\n"); + qq_refresh_all_buddy_status(gc); break; case QQ_CMD_GET_LEVEL: qq_process_get_level_reply(data, data_len, gc); break; case QQ_CMD_GET_BUDDIES_LIST: ret_16 = qq_process_get_buddies_list_reply(data, data_len, gc); - if (ret_16 > 0 && ret_16 < 0xffff) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more buddies\n"); - qq_send_packet_get_buddies_list(gc, ret_16); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "All buddies received. Requesting buddies' levels\n"); - qq_send_packet_get_buddies_online(gc, 0); + if (ret_16 > 0 && ret_16 < 0xffff) { + purple_debug_info("QQ", "Requesting for more buddies\n"); + qq_request_get_buddies_list(gc, ret_16, update_class); + return; } + purple_debug_info("QQ", "All buddies received. Requesting buddies' levels\n"); break; case QQ_CMD_GET_BUDDIES_AND_ROOMS: ret_32 = qq_process_get_buddies_and_rooms(data, data_len, gc); if (ret_32 > 0 && ret_32 < 0xffffffff) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Requesting for more buddies and groups\n"); - qq_send_packet_get_buddies_and_rooms(gc, ret_32); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "All buddies and groups received\n"); + purple_debug_info("QQ", "Requesting for more buddies and groups\n"); + qq_request_get_buddies_and_rooms(gc, ret_32, update_class); + return; } + purple_debug_info("QQ", "All buddies and groups received\n"); break; default: process_cmd_unknow(gc, "Unknow reply CMD", data, data_len, cmd, seq); + is_unknow = TRUE; break; } + if (is_unknow) + return; + + if (update_class == QQ_CMD_CLASS_NONE) + return; + + purple_debug_info("QQ", "Update class %d\n", update_class); + if (update_class == QQ_CMD_CLASS_UPDATE_ALL) { + qq_update_all(gc, cmd); + return; + } + if (update_class == QQ_CMD_CLASS_UPDATE_ONLINE) { + qq_update_online(gc, cmd); + return; + } } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq_process.h --- a/libpurple/protocols/qq/qq_process.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.h Mon Sep 15 02:59:23 2008 +0000 @@ -30,12 +30,24 @@ #include "qq.h" -void qq_proc_cmd_reply(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); -void qq_proc_room_cmd_reply(PurpleConnection *gc, - guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len); - -void qq_proc_cmd_server(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); +enum { + QQ_CMD_CLASS_NONE = 0, + QQ_CMD_CLASS_UPDATE_ALL, + QQ_CMD_CLASS_UPDATE_ONLINE, + QQ_CMD_CLASS_UPDATE_ROOM, +}; + +void qq_proc_cmd_login(PurpleConnection *gc, guint8 *rcved, gint rcved_len); +void qq_proc_cmd_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32); +void qq_proc_room_cmd_reply(PurpleConnection *gc, guint16 seq, + guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len, + gint update_class, guint32 ship32); + +void qq_proc_cmd_server(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); + +void qq_update_all(PurpleConnection *gc, guint16 cmd); +void qq_update_online(PurpleConnection *gc, guint16 cmd); +void qq_room_update(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); #endif diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq_trans.c --- a/libpurple/protocols/qq/qq_trans.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.c Mon Sep 15 02:59:23 2008 +0000 @@ -37,8 +37,35 @@ #define QQ_RESEND_MAX 3 /* max resend per packet */ -qq_transaction *qq_trans_find_rcved(qq_data *qd, guint16 cmd, guint16 seq) +enum { + QQ_TRANS_IS_SERVER = 0x01, /* Is server command or client command */ + QQ_TRANS_IS_IMPORT = 0x02, /* Only notice if not get reply; or resend, disconn if reties get 0*/ + QQ_TRANS_BEFORE_LOGIN = 0x04, /* server command before login*/ +}; + +struct _qq_transaction { + guint8 flag; + guint16 seq; + guint16 cmd; + + guint8 room_cmd; + guint32 room_id; + + guint8 *data; + gint data_len; + + gint fd; + gint send_retries; + gint rcved_times; + gint scan_times; + + gint update_class; + guint32 ship32; +}; + +qq_transaction *qq_trans_find_rcved(PurpleConnection *gc, guint16 cmd, guint16 seq) { + qq_data *qd = (qq_data *)gc->proto_data; GList *curr; GList *next; qq_transaction *trans; @@ -50,19 +77,21 @@ next = qd->transactions; while( (curr = next) ) { next = curr->next; - + trans = (qq_transaction *) (curr->data); if(trans->cmd == cmd && trans->seq == seq) { if (trans->rcved_times == 0) { trans->scan_times = 0; } trans->rcved_times++; + /* server may not get our confirm reply before, send reply again*/ + /* only rcved buffer stored in transaction if (qq_trans_is_server(trans) && qq_trans_is_dup(trans)) { - /* server may not get our confirm reply before, send reply again*/ if (trans->data != NULL && trans->data_len > 0) { - qq_send_data(qd, trans->cmd, trans->seq, FALSE, trans->data, trans->data_len); + qq_send_cmd_encrypted(gc, trans->cmd, trans->seq, trans->data, trans->data_len, FALSE); } } + */ return trans; } } @@ -70,20 +99,20 @@ return NULL; } -gboolean qq_trans_is_server(qq_transaction *trans) +gboolean qq_trans_is_server(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, FALSE); - + if (trans->flag & QQ_TRANS_IS_SERVER) return TRUE; else return FALSE; } -gboolean qq_trans_is_dup(qq_transaction *trans) +gboolean qq_trans_is_dup(qq_transaction *trans) { g_return_val_if_fail(trans != NULL, TRUE); - + if (trans->rcved_times > 1) return TRUE; else @@ -102,115 +131,122 @@ return trans->room_id; } -/* Remove a packet with seq from send trans */ -static void trans_remove(qq_data *qd, qq_transaction *trans) +gint qq_trans_get_class(qq_transaction *trans) +{ + g_return_val_if_fail(trans != NULL, QQ_CMD_CLASS_NONE); + return trans->update_class; +} + +gint qq_trans_get_ship(qq_transaction *trans) +{ + g_return_val_if_fail(trans != NULL, 0); + return trans->ship32; +} + +static qq_transaction *trans_create(PurpleConnection *gc, gint fd, + guint16 cmd, guint16 seq, guint8 *data, gint data_len, gint update_class, guint32 ship32) { + qq_data *qd; + qq_transaction *trans; + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, NULL); + qd = (qq_data *) gc->proto_data; + + trans = g_new0(qq_transaction, 1); + + memset(trans, 0, sizeof(qq_transaction)); + trans->fd = fd; + trans->cmd = cmd; + trans->seq = seq; + + trans->data = NULL; + trans->data_len = 0; + if (data != NULL && data_len > 0) { + /* don't use g_strdup, may have 0x00 */ + trans->data = g_memdup(data, data_len); + trans->data_len = data_len; + } + + trans->update_class = update_class; + return trans; +} + +/* Remove a packet with seq from send trans */ +static void trans_remove(PurpleConnection *gc, qq_transaction *trans) +{ + qq_data *qd = (qq_data *)gc->proto_data; g_return_if_fail(qd != NULL && trans != NULL); - - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", + +#if 0 + purple_debug_info("QQ_TRANS", "Remove [%s%05d] retry %d rcved %d scan %d %s\n", (trans->flag & QQ_TRANS_IS_SERVER) ? "SRV-" : "", trans->seq, trans->send_retries, trans->rcved_times, trans->scan_times, qq_get_cmd_desc(trans->cmd)); - +#endif if (trans->data) g_free(trans->data); qd->transactions = g_list_remove(qd->transactions, trans); g_free(trans); } -void qq_trans_add_client_cmd(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len) +void qq_trans_add_client_cmd(PurpleConnection *gc, + guint16 cmd, guint16 seq, guint8 *data, gint data_len, gint update_class, guint32 ship32) { - qq_transaction *trans = g_new0(qq_transaction, 1); + qq_data *qd = (qq_data *)gc->proto_data; + qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, update_class, ship32); - g_return_if_fail(trans != NULL); - - trans->flag = 0; if (cmd == QQ_CMD_TOKEN || cmd == QQ_CMD_LOGIN || cmd == QQ_CMD_KEEP_ALIVE) { - trans->flag |= QQ_TRANS_CLI_IMPORT; + trans->flag |= QQ_TRANS_IS_IMPORT; } - trans->fd = qd->fd; - trans->cmd = cmd; - trans->seq = seq; - trans->room_cmd = 0; - trans->room_id = 0; trans->send_retries = QQ_RESEND_MAX; - trans->rcved_times = 0; - trans->scan_times = 0; - - trans->data = NULL; - trans->data_len = 0; - if (data != NULL && data_len > 0) { - trans->data = g_memdup(data, data_len); /* don't use g_strdup, may have 0x00 */ - trans->data_len = data_len; - } - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", - "Add client cmd, seq = %d, data = %p, len = %d\n", +#if 0 + purple_debug_info("QQ_TRANS", "Add client cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); +#endif qd->transactions = g_list_append(qd->transactions, trans); } -void qq_trans_add_room_cmd(qq_data *qd, guint16 seq, guint8 room_cmd, guint32 room_id, - guint8 *data, gint data_len) +void qq_trans_add_room_cmd(PurpleConnection *gc, + guint16 seq, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len, + gint update_class, guint32 ship32) { - qq_transaction *trans = g_new0(qq_transaction, 1); + qq_data *qd = (qq_data *)gc->proto_data; + qq_transaction *trans = trans_create(gc, qd->fd, QQ_CMD_ROOM, seq, data, data_len, + update_class, ship32); - g_return_if_fail(trans != NULL); - - trans->flag = 0; - trans->fd = qd->fd; - trans->seq = seq; - trans->cmd = QQ_CMD_ROOM; trans->room_cmd = room_cmd; trans->room_id = room_id; trans->send_retries = QQ_RESEND_MAX; - trans->rcved_times = 0; - trans->scan_times = 0; - - trans->data = NULL; - trans->data_len = 0; - if (data != NULL && data_len > 0) { - trans->data = g_memdup(data, data_len); /* don't use g_strdup, may have 0x00 */ - trans->data_len = data_len; - } - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", - "Add room cmd, seq = %d, data = %p, len = %d\n", +#if 0 + purple_debug_info("QQ_TRANS", "Add room cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); +#endif qd->transactions = g_list_append(qd->transactions, trans); } -void qq_trans_add_server_cmd(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len) +void qq_trans_add_server_cmd(PurpleConnection *gc, + guint16 cmd, guint16 seq, guint8 *data, gint data_len) { - qq_transaction *trans = g_new0(qq_transaction, 1); - - g_return_if_fail(trans != NULL); + qq_data *qd = (qq_data *)gc->proto_data; + qq_transaction *trans = trans_create(gc, qd->fd, cmd, seq, data, data_len, QQ_CMD_CLASS_NONE, 0); trans->flag = QQ_TRANS_IS_SERVER; - if ( !qd->logged_in ) { + if ( !qd->is_login ) { trans->flag |= QQ_TRANS_BEFORE_LOGIN; } - trans->fd = qd->fd; - trans->cmd = cmd; - trans->seq = seq; - trans->room_cmd = 0; - trans->room_id = 0; trans->send_retries = 0; trans->rcved_times = 1; - trans->scan_times = 0; - trans->data = NULL; - trans->data_len = 0; - if (data != NULL && data_len > 0) { - trans->data = g_memdup(data, data_len); /* don't use g_strdup, may have 0x00 */ - trans->data_len = data_len; - } - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", - "Add server cmd, seq = %d, data = %p, len = %d\n", +#if 0 + purple_debug_info("QQ_TRANS", "Add server cmd, seq %d, data %p, len %d\n", trans->seq, trans->data, trans->data_len); +#endif qd->transactions = g_list_append(qd->transactions, trans); } -void qq_trans_process_before_login(qq_data *qd) +void qq_trans_process_before_login(PurpleConnection *gc) { + qq_data *qd = (qq_data *)gc->proto_data; GList *curr; GList *next; qq_transaction *trans; @@ -221,42 +257,44 @@ while( (curr = next) ) { next = curr->next; trans = (qq_transaction *) (curr->data); - /* purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", "Scan [%d]\n", trans->seq); */ - +#if 0 + purple_debug_info("QQ_TRANS", "Scan [%d]\n", trans->seq); +#endif if ( !(trans->flag & QQ_TRANS_IS_SERVER) ) { continue; } if ( !(trans->flag & QQ_TRANS_BEFORE_LOGIN) ) { continue; } - // set QQ_TRANS_BEFORE_LOGIN off + /* set QQ_TRANS_BEFORE_LOGIN off */ trans->flag &= ~QQ_TRANS_BEFORE_LOGIN; - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", + purple_debug_info("QQ_TRANS", "Process server cmd before login, seq %d, data %p, len %d, send_retries %d\n", trans->seq, trans->data, trans->data_len, trans->send_retries); - qq_proc_cmd_reply(qd->gc, trans->seq, trans->cmd, trans->data, trans->data_len); + qq_proc_cmd_reply(gc, trans->seq, trans->cmd, trans->data, trans->data_len, trans->update_class, trans->ship32); } - /* purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Scan finished\n"); */ + /* purple_debug_info("QQ_TRANS", "Scan finished\n"); */ return; } -gboolean qq_trans_scan(qq_data *qd) +gboolean qq_trans_scan(PurpleConnection *gc) { + qq_data *qd = (qq_data *)gc->proto_data; GList *curr; GList *next; qq_transaction *trans; g_return_val_if_fail(qd != NULL, FALSE); - + next = qd->transactions; while( (curr = next) ) { next = curr->next; trans = (qq_transaction *) (curr->data); - /* purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Scan [%d]\n", trans->seq); */ - + /* purple_debug_info("QQ_TRANS", "Scan [%d]\n", trans->seq); */ + if (trans->flag & QQ_TRANS_BEFORE_LOGIN) { /* keep server cmd before login*/ continue; @@ -270,67 +308,60 @@ if (trans->rcved_times > 0) { /* Has been received */ - trans_remove(qd, trans); + trans_remove(gc, trans); continue; } if (trans->flag & QQ_TRANS_IS_SERVER) { continue; } - + /* Never get reply */ trans->send_retries--; if (trans->send_retries <= 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ_TRANS", + purple_debug_warning("QQ_TRANS", "[%d] %s is lost.\n", trans->seq, qq_get_cmd_desc(trans->cmd)); - if (trans->flag & QQ_TRANS_CLI_IMPORT) { + if (trans->flag & QQ_TRANS_IS_IMPORT) { return TRUE; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", + purple_debug_error("QQ_TRANS", "Lost [%d] %s, data %p, len %d, retries %d\n", trans->seq, qq_get_cmd_desc(trans->cmd), trans->data, trans->data_len, trans->send_retries); - trans_remove(qd, trans); + trans_remove(gc, trans); continue; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", + purple_debug_error("QQ_TRANS", "Resend [%d] %s data %p, len %d, send_retries %d\n", trans->seq, qq_get_cmd_desc(trans->cmd), trans->data, trans->data_len, trans->send_retries); - qq_send_data(qd, trans->cmd, trans->seq, FALSE, trans->data, trans->data_len); + qq_send_cmd_encrypted(gc, trans->cmd, trans->seq, trans->data, trans->data_len, FALSE); } - /* purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Scan finished\n"); */ + /* purple_debug_info("QQ_TRANS", "Scan finished\n"); */ return FALSE; } /* clean up send trans and free all contents */ -void qq_trans_remove_all(qq_data *qd) +void qq_trans_remove_all(PurpleConnection *gc) { - GList *curr; - GList *next; + qq_data *qd = (qq_data *)gc->proto_data; qq_transaction *trans; gint count = 0; - curr = qd->transactions; - while(curr) { - next = curr->next; - - trans = (qq_transaction *) (curr->data); - /* - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", - "Remove to transaction, seq = %d, buf = %p, len = %d\n", - trans->seq, trans->buf, trans->len); - */ - trans_remove(qd, trans); + while(qd->transactions != NULL) { + trans = (qq_transaction *) (qd->transactions->data); + qd->transactions = g_list_remove(qd->transactions, trans); + + if (trans->data) g_free(trans->data); + g_free(trans); count++; - curr = next; } - g_list_free(qd->transactions); - - purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Free all %d packets\n", count); + if (count > 0) { + purple_debug_info("QQ_TRANS", "Free all %d packets\n", count); + } } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/qq_trans.h --- a/libpurple/protocols/qq/qq_trans.h Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.h Mon Sep 15 02:59:23 2008 +0000 @@ -28,44 +28,27 @@ #include #include "qq.h" -enum { - QQ_TRANS_IS_SERVER = 0x01, /* Is server command or client command */ - /* prefix QQ_TRANS_CLI is for client command*/ - QQ_TRANS_CLI_EMERGE = 0x02, /* send at once; or may wait for next reply*/ - QQ_TRANS_CLI_IMPORT = 0x04, /* Only notice if not get reply; or resend, disconn if reties get 0*/ - QQ_TRANS_BEFORE_LOGIN = 0x08, /* server command before login*/ -}; - -typedef struct _qq_transaction { - guint8 flag; - guint16 seq; - guint16 cmd; +typedef struct _qq_transaction qq_transaction; - guint8 room_cmd; - guint32 room_id; - - guint8 *data; - gint data_len; - - gint fd; - gint send_retries; - gint rcved_times; - gint scan_times; -} qq_transaction; - -qq_transaction *qq_trans_find_rcved(qq_data *qd, guint16 cmd, guint16 seq); +qq_transaction *qq_trans_find_rcved(PurpleConnection *gc, guint16 cmd, guint16 seq); gboolean qq_trans_is_server(qq_transaction *trans) ; gboolean qq_trans_is_dup(qq_transaction *trans); guint8 qq_trans_get_room_cmd(qq_transaction *trans); guint32 qq_trans_get_room_id(qq_transaction *trans); +gint qq_trans_get_class(qq_transaction *trans); +gint qq_trans_get_ship(qq_transaction *trans); -void qq_trans_add_client_cmd(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len); -void qq_trans_add_server_cmd(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len); -void qq_trans_add_room_cmd(qq_data *qd, guint16 seq, guint8 room_cmd, guint32 room_id, +void qq_trans_add_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, + guint8 *data, gint data_len, gint update_class, guint32 ship32); +void qq_trans_add_room_cmd(PurpleConnection *gc, + guint16 seq, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len, gint update_class, guint32 ship32); + +void qq_trans_add_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len); -void qq_trans_process_before_login(qq_data *qd); -gboolean qq_trans_scan(qq_data *qd); -void qq_trans_remove_all(qq_data *qd); +void qq_trans_process_before_login(PurpleConnection *gc); +gboolean qq_trans_scan(PurpleConnection *gc); +void qq_trans_remove_all(PurpleConnection *gc); #endif diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/send_file.c --- a/libpurple/protocols/qq/send_file.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/send_file.c Mon Sep 15 02:59:23 2008 +0000 @@ -54,7 +54,7 @@ static int _qq_in_same_lan(ft_info *info) { if (info->remote_internet_ip == info->local_internet_ip) return 1; - purple_debug(PURPLE_DEBUG_INFO, "QQ", + 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); @@ -87,7 +87,7 @@ info = (ft_info *) xfer->data; sinlen = sizeof(sin); r = recvfrom(info->recv_fd, buf, len, 0, (struct sockaddr *) &sin, &sinlen); - purple_debug(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; @@ -121,7 +121,7 @@ sin.sin_port = g_htons(info->remote_minor_port); sin.sin_addr.s_addr = g_htonl(info->remote_real_ip); } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "sending to channel: %d.%d.%d.%d:%d\n", + purple_debug_info("QQ", "sending to channel: %d.%d.%d.%d:%d\n", sin.sin_addr.s_addr & 0xff, (sin.sin_addr.s_addr >> 8) & 0xff, (sin.sin_addr.s_addr >> 16) & 0xff, @@ -207,20 +207,20 @@ qq_xfer_close_file(xfer); if (info->dest_fp != NULL) { fclose(info->dest_fp); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "file closed\n"); + purple_debug_info("QQ", "file closed\n"); } if (info->major_fd != 0) { close(info->major_fd); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "major port closed\n"); + purple_debug_info("QQ", "major port closed\n"); } if (info->minor_fd != 0) { close(info->minor_fd); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "minor port closed\n"); + purple_debug_info("QQ", "minor port closed\n"); } /* if (info->buffer != NULL) { munmap(info->buffer, purple_xfer_get_size(xfer)); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "file mapping buffer is freed.\n"); + purple_debug_info("QQ", "file mapping buffer is freed.\n"); } */ g_free(info); @@ -235,7 +235,7 @@ real_ip_str = gen_ip_str((guint8 *) &ip); ip = g_htonl(info->remote_internet_ip); internet_ip_str = gen_ip_str((guint8 *) &ip); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "remote internet ip[%s:%d], major port[%d], real ip[%s], minor port[%d]\n", + purple_debug_info("QQ", "remote internet ip[%s:%d], major port[%d], real ip[%s], minor port[%d]\n", internet_ip_str, info->remote_internet_port, info->remote_major_port, real_ip_str, info->remote_minor_port ); @@ -393,7 +393,7 @@ info->local_real_ip = 0x7f000001; */ info->local_real_ip = g_ntohl(inet_addr(purple_network_get_my_ip(-1))); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "local real ip is %x", info->local_real_ip); + purple_debug_info("QQ", "local real ip is %x", info->local_real_ip); for (i = 0; i < 2; i++) { sockfd = socket(PF_INET, SOCK_DGRAM, 0); @@ -412,13 +412,13 @@ case 0: info->local_major_port = listen_port; info->major_fd = sockfd; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Major Channel created on port[%d]\n", + purple_debug_info("QQ", "UDP Major Channel created on port[%d]\n", info->local_major_port); break; case 1: info->local_minor_port = listen_port; info->minor_fd = sockfd; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Minor Channel created on port[%d]\n", + purple_debug_info("QQ", "UDP Minor Channel created on port[%d]\n", info->local_minor_port); break; } @@ -475,9 +475,9 @@ bytes += qq_putdata (raw_data + bytes, (guint8 *) filelen_str, filelen_strlen); if (packet_len == bytes) - qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_request", + purple_debug_info("qq_send_packet_file_request", "%d bytes expected but got %d bytes\n", packet_len, bytes); @@ -497,7 +497,7 @@ qd = (qq_data *) gc->proto_data; info = (ft_info *) qd->xfer->data; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "I've accepted the file transfer request from %d\n", to_uid); + purple_debug_info("QQ", "I've accepted the file transfer request from %d\n", to_uid); _qq_xfer_init_socket(qd->xfer); packet_len = 79; @@ -516,9 +516,9 @@ info->local_real_ip = real_ip; if (packet_len == bytes) - qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_accept", + purple_debug_info("qq_send_packet_file_accept", "%d bytes expected but got %d bytes\n", packet_len, bytes); } @@ -539,13 +539,13 @@ raw_data = g_newa (guint8, packet_len); bytes = 0; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "<== sending qq file notify ip packet\n"); + purple_debug_info("QQ", "<== sending qq file notify ip packet\n"); 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 (qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_notify", + purple_debug_info("qq_send_packet_file_notify", "%d bytes expected but got %d bytes\n", packet_len, bytes); @@ -561,7 +561,7 @@ guint8 *raw_data; gint packet_len, bytes; - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_reject", "start"); + purple_debug_info("_qq_send_packet_file_reject", "start"); qd = (qq_data *) gc->proto_data; packet_len = 64; @@ -571,9 +571,9 @@ 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 (qd, QQ_CMD_SEND_IM, raw_data, bytes); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file", + purple_debug_info("qq_send_packet_file", "%d bytes expected but got %d bytes\n", packet_len, bytes); } @@ -585,27 +585,27 @@ guint8 *raw_data; gint packet_len, bytes; - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "start\n"); + purple_debug_info("_qq_send_packet_file_cancel", "start\n"); qd = (qq_data *) gc->proto_data; packet_len = 64; raw_data = g_newa (guint8, packet_len); bytes = 0; - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "before create header\n"); + purple_debug_info("_qq_send_packet_file_cancel", "before create header\n"); bytes += _qq_create_packet_file_header(raw_data + bytes, to_uid, QQ_FILE_TRANS_CANCEL, qd, TRUE); - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "end create header\n"); + purple_debug_info("_qq_send_packet_file_cancel", "end create header\n"); if (packet_len == bytes) { - purple_debug(PURPLE_DEBUG_INFO, "_qq_send_packet_file_cancel", "before send cmd\n"); - qq_send_cmd (qd, QQ_CMD_SEND_IM, raw_data, bytes); + purple_debug_info("_qq_send_packet_file_cancel", "before send cmd\n"); + qq_send_cmd(gc, QQ_CMD_SEND_IM, raw_data, bytes); } else - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file", + purple_debug_info("qq_send_packet_file", "%d bytes expected but got %d bytes\n", packet_len, bytes); - purple_debug (PURPLE_DEBUG_INFO, "qq_send_packet_file_cancel", "end\n"); + purple_debug_info("qq_send_packet_file_cancel", "end\n"); } /* request to send a file */ @@ -694,7 +694,7 @@ /* border has been checked before if (*cursor >= (data + data_len - 1)) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Received file reject message is empty\n"); return; } @@ -724,8 +724,7 @@ /* border has been checked before if (*cursor >= (data + data_len - 1)) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file reject message is empty\n"); + purple_debug_warning("QQ", "Received file reject message is empty\n"); return; } */ @@ -755,8 +754,7 @@ info = (ft_info *) qd->xfer->data; if (data_len <= 30 + QQ_CONN_INFO_LEN) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file reject message is empty\n"); + purple_debug_warning("QQ", "Received file reject message is empty\n"); return; } @@ -789,8 +787,7 @@ info->to_uid = sender_uid; if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file request message is empty\n"); + purple_debug_warning("QQ", "Received file request message is empty\n"); return; } bytes = 0; @@ -806,7 +803,7 @@ /* FACE from IP detector, ignored by gfhuang */ if(g_ascii_strcasecmp(fileinfo[0], "FACE") == 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Received a FACE ip detect from qq-%d, so he/she must be online :)\n", sender_uid); b = purple_find_buddy(gc->account, sender_name); @@ -826,11 +823,11 @@ qq_update_buddy_contact(gc, q_bud); } else - purple_debug(PURPLE_DEBUG_INFO, "QQ", "buddy %d is already online\n", sender_uid); + purple_debug_info("QQ", "buddy %d is already online\n", sender_uid); } else - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "buddy %d is not in list\n", sender_uid); + purple_debug_warning("QQ", "buddy %d is not in list\n", sender_uid); g_free(sender_name); g_strfreev(fileinfo); @@ -892,8 +889,7 @@ xfer = qd->xfer; info = (ft_info *) qd->xfer->data; if (data_len <= 2 + 30 + QQ_CONN_INFO_LEN) { - purple_debug (PURPLE_DEBUG_WARNING, "QQ", - "Received file notify message is empty\n"); + purple_debug_warning("QQ", "Received file notify message is empty\n"); return; } diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/sys_msg.c --- a/libpurple/protocols/qq/sys_msg.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/sys_msg.c Mon Sep 15 02:59:23 2008 +0000 @@ -126,7 +126,7 @@ 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; @@ -142,9 +142,9 @@ g_free(str); if (bytes == ack_len) /* creation OK */ - qq_send_cmd_detail(qd, QQ_CMD_ACK_SYS_MSG, 0, FALSE, ack, ack_len); + qq_send_server_reply(gc, QQ_CMD_ACK_SYS_MSG, 0, ack, ack_len); else - purple_debug(PURPLE_DEBUG_ERROR, "QQ", + purple_debug_error("QQ", "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes); } @@ -194,8 +194,8 @@ g_return_if_fail(from != NULL && to != NULL); - message = g_strdup_printf(_("User %s rejected your request"), from); - reason = g_strdup_printf(_("Reason: %s"), msg_utf8); + message = g_strdup_printf(_("Requestion rejected by %s"), from); + reason = g_strdup_printf(_("Message: %s"), msg_utf8); _qq_sys_msg_log_write(gc, message, from); purple_notify_info(gc, NULL, message, reason); @@ -214,7 +214,7 @@ qd = (qq_data *) gc->proto_data; qq_add_buddy_by_recv_packet(gc, strtol(from, NULL, 10), TRUE, TRUE); - message = g_strdup_printf(_("User %s approved your request"), from); + message = g_strdup_printf(_("Requestion approved by %s"), from); _qq_sys_msg_log_write(gc, message, from); purple_notify_info(gc, NULL, message, NULL); @@ -263,9 +263,9 @@ g2 = g_new0(gc_and_uid, 1); g2->gc = gc; g2->uid = strtol(from, NULL, 10); - message = g_strdup_printf(_("%s is not in your buddy list"), from); + message = g_strdup_printf(_("%s is not in buddy list"), from); purple_request_action(gc, NULL, message, - _("Would you like to add him?"), PURPLE_DEFAULT_ACTION_NONE, + _("Would you add?"), PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc), name, NULL, g2, 3, _("Cancel"), NULL, @@ -279,14 +279,19 @@ static void _qq_process_msg_sys_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) { + qq_data *qd = (qq_data *) gc->proto_data; gchar *title, *content; g_return_if_fail(from != NULL && to != NULL); - title = g_strdup_printf(_("Notice from: %s"), from); + title = g_strdup_printf(_("QQ Server Notice from %s:"), from); content = g_strdup_printf(_("%s"), msg_utf8); - purple_notify_info(gc, NULL, title, content); + if (qd->is_show_notice) { + purple_notify_info(gc, NULL, title, content); + } else { + purple_debug_info("QQ", "Server notice from %s:\n%s", from, msg_utf8); +} g_free(title); g_free(content); } @@ -310,12 +315,19 @@ _qq_send_packet_ack_msg_sys(gc, code[0], strtol(from, NULL, 10), seq); if (strtol(to, NULL, 10) != qd->uid) { /* not to me */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Recv sys msg to [%s], not me!, discard\n", to); + purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to); g_strfreev(segments); return; } msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + if (from == NULL && msg_utf8) { + purple_debug_error("QQ", "Recv NULL sys msg to [%s], discard\n", to); + g_strfreev(segments); + g_free(msg_utf8); + return; + } + switch (strtol(code, NULL, 10)) { case QQ_MSG_SYS_BEING_ADDED: _qq_process_msg_sys_being_added(gc, from, to, msg_utf8); @@ -333,12 +345,12 @@ _qq_process_msg_sys_notice(gc, from, to, msg_utf8); break; case QQ_MSG_SYS_NEW_VERSION: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "QQ server says there is newer version than %s\n", qq_get_ver_desc(QQ_CLIENT)); break; default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Recv unknown sys msg code: %s\n", code); - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "the msg is : %s\n", msg_utf8); + purple_debug_warning("QQ", "Recv unknown sys msg code: %s\n", code); + purple_debug_warning("QQ", "the msg is : %s\n", msg_utf8); } g_free(msg_utf8); g_strfreev(segments); diff -r 5f454b975a99 -r 967344bc404d libpurple/protocols/qq/utils.c --- a/libpurple/protocols/qq/utils.c Sun Aug 10 04:32:14 2008 +0000 +++ b/libpurple/protocols/qq/utils.c Mon Sep 15 02:59:23 2008 +0000 @@ -47,8 +47,8 @@ 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)); + purple_debug_info(desc, "%s:%d\n", + inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); } */ @@ -121,16 +121,16 @@ for (i = 0; segments[i] != NULL; i++) {; } if (i < expected_fields) { /* not enough fields */ - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Invalid data, expect %d fields, found only %d, discard\n", expected_fields, i); + purple_debug_error("QQ", "Invalid data, expect %d fields, found only %d, discard\n", + expected_fields, i); g_strfreev(segments); return NULL; } else if (i > expected_fields) { /* more fields, OK */ - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Dangerous data, expect %d fields, found %d, return all\n", expected_fields, i); + purple_debug_warning("QQ", "Dangerous data, expect %d fields, found %d, return all\n", + expected_fields, i); /* free up those not used */ for (j = expected_fields; j < i; j++) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "field[%d] is %s\n", j, segments[j]); + purple_debug_warning("QQ", "field[%d] is %s\n", j, segments[j]); g_free(segments[j]); } @@ -218,7 +218,7 @@ msg_utf8 = i < len ? qq_to_utf8((gchar *) &incoming[i], QQ_CHARSET_DEFAULT) : NULL; if (msg_utf8 != NULL) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Try extract GB msg: %s\n", msg_utf8); + purple_debug_warning("QQ", "Try extract GB msg: %s\n", msg_utf8); } return msg_utf8; } @@ -257,7 +257,7 @@ hex_buffer = strstrip(buffer); if (strlen(hex_buffer) % 2 != 0) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", + purple_debug_warning("QQ", "Unable to convert an odd number of nibbles to a string of bytes!\n"); g_free(hex_buffer); return NULL; @@ -272,8 +272,8 @@ } else if (g_ascii_isalpha(*cursor) && (gint) *cursor - 87 < 16) { nibble1 = (gint) *cursor - 87; } else { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Invalid char \'%c\' found in hex string!\n", *cursor); + purple_debug_warning("QQ", "Invalid char \'%c\' found in hex string!\n", + *cursor); g_free(hex_str); return NULL; } @@ -284,8 +284,7 @@ } else if (g_ascii_isalpha(*cursor) && (gint) (*cursor - 87) < 16) { nibble2 = (gint) *cursor - 87; } else { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Invalid char found in hex string!\n"); + purple_debug_warning("QQ", "Invalid char found in hex string!\n"); g_free(hex_str); return NULL; } @@ -362,22 +361,7 @@ void qq_show_packet(const gchar *desc, const guint8 *buf, gint len) { - /* - char buf1[8*len+2], buf2[10]; - int i; - buf1[0] = 0; - for (i = 0; i < len; i++) { - sprintf(buf2, " %02x(%d)", buf[i] & 0xff, buf[i] & 0xff); - strcat(buf1, buf2); - } - strcat(buf1, "\n"); - purple_debug(PURPLE_DEBUG_INFO, desc, "%s", buf1); - */ - - /* modified by s3e, 20080424 */ - qq_hex_dump(PURPLE_DEBUG_INFO, desc, - buf, len, - ""); + qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", buf, len, desc); } /* convert face num from packet (0-299) to local face (1-100) */