Mercurial > pidgin
changeset 23695:5f454b975a99
2008.08.10 - csyfek <csyfek(at)gmail.com>
* Commit to Pidgin
2008.08.06 - ccpaging <ecc_hy(at)hotmail.com>
* Rename names of variables, Group, to Room
* Functions of group_network merged into qq_network and qq_process
* Canceled managing glist of group packet, add sub_cmdd and room_id to transaction
* Fixed error of demo group:
If 'room list' and 'room infor' are not setup, response received from server will emits
'room_id = 0' packet.
2008.08.04 - ccpaging <ecc_hy(at)hotmail.com>
* Use new crypt/decrypt functions
* Rename crypt.c/h to qq_crypt.c/h
* Clean code of decrypt functions
* Fixed decryption failure
2008.08.04 - csyfek <csyfek(at)gmail.com>
* Update AUTHORS
line wrap: on
line diff
--- a/libpurple/protocols/qq/ChangeLog Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/ChangeLog Sun Aug 10 04:32:14 2008 +0000 @@ -1,3 +1,22 @@ +2008.08.10 - csyfek <csyfek(at)gmail.com> + * Commit to Pidgin + +2008.08.06 - ccpaging <ecc_hy(at)hotmail.com> + * Rename names of variables, Group, to Room + * Functions of group_network merged into qq_network and qq_process + * Canceled managing glist of group packet, add sub_cmdd and room_id to transaction + * Fixed error of demo group: + If 'room list' and 'room infor' are not setup, response received from server will emits 'room_id = 0' packet. + +2008.08.04 - ccpaging <ecc_hy(at)hotmail.com> + * Use new crypt/decrypt functions + * Rename crypt.c/h to qq_crypt.c/h + * Clean code of decrypt functions + * Fixed decryption failure + +2008.08.04 - csyfek <csyfek(at)gmail.com> + * Update AUTHORS + 2008.08.03 - csyfek <csyfek(at)gmail.com> * Commit lost files to Pidgin
--- a/libpurple/protocols/qq/Makefile.am Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/Makefile.am Sun Aug 10 04:32:14 2008 +0000 @@ -12,8 +12,8 @@ buddy_opt.h \ char_conv.c \ char_conv.h \ - crypt.c \ - crypt.h \ + qq_crypt.c \ + qq_crypt.h \ file_trans.c \ file_trans.h \ group.c \ @@ -32,8 +32,6 @@ group_info.h \ group_join.c \ group_join.h \ - group_network.c \ - group_network.h \ group_opt.c \ group_opt.h \ group_search.c \
--- a/libpurple/protocols/qq/Makefile.mingw Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/Makefile.mingw Sun Aug 10 04:32:14 2008 +0000 @@ -43,7 +43,7 @@ buddy_list.c \ buddy_opt.c \ char_conv.c \ - crypt.c \ + qq_crypt.c \ file_trans.c \ group.c \ group_conv.c \ @@ -53,18 +53,17 @@ group_im.c \ group_info.c \ group_join.c \ - group_network.c \ group_opt.c \ group_search.c \ header_info.c \ im.c \ + qq_process.c \ + qq_base.c \ packet_parse.c \ qq.c \ - qq_base.c \ qq_network.c \ - qq_process.c \ + send_file.c \ qq_trans.c \ - send_file.c \ sys_msg.c \ utils.c
--- a/libpurple/protocols/qq/buddy_info.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Sun Aug 10 04:32:14 2008 +0000 @@ -32,7 +32,6 @@ #include "buddy_list.h" #include "buddy_info.h" #include "char_conv.h" -#include "crypt.h" #include "header_info.h" #include "qq_base.h" #include "qq_network.h" @@ -688,26 +687,18 @@ } /* process the reply of modify_info packet */ -void qq_process_modify_info_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_modify_info_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len; - guint8 *data; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - 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); - } - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt modify info reply\n"); + 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); } } @@ -858,10 +849,8 @@ } /* process reply to get_info packet */ -void qq_process_get_info_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_get_info_reply(guint8 *data, gint data_len, PurpleConnection *gc) { - gint len; - guint8 *data; gchar **segments; qq_info_query *query; qq_data *qd; @@ -869,52 +858,46 @@ GList *list, *query_list; PurpleNotifyUserInfo *user_info; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; list = query_list = NULL; - len = buf_len; - data = g_newa(guint8, len); info = NULL; - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - if (NULL == (segments = split_data(data, len, "\x1e", QQ_CONTACT_FIELDS))) - return; + if (NULL == (segments = split_data(data, data_len, "\x1e", QQ_CONTACT_FIELDS))) + return; - info = (contact_info *) segments; - if (qd->modifying_face && strtol(info->face, NULL, 10) != qd->my_icon) { - gchar *icon = g_strdup_printf("%d", qd->my_icon); - qd->modifying_face = FALSE; - g_free(info->face); - info->face = icon; - qq_send_packet_modify_info(gc, (contact_info *)segments); - } + info = (contact_info *) segments; + if (qd->modifying_face && strtol(info->face, NULL, 10) != qd->my_icon) { + gchar *icon = g_strdup_printf("%d", qd->my_icon); + qd->modifying_face = FALSE; + g_free(info->face); + info->face = icon; + qq_send_packet_modify_info(gc, (contact_info *)segments); + } - qq_refresh_buddy_and_myself(info, gc); + qq_refresh_buddy_and_myself(info, gc); - query_list = qd->info_query; - /* ensure we're processing the right query */ - while (query_list) { - query = (qq_info_query *) query_list->data; - if (query->uid == atoi(info->uid)) { - if (query->show_window) { - user_info = info_to_notify_user_info(info); - purple_notify_userinfo(gc, info->uid, user_info, NULL, NULL); - purple_notify_user_info_destroy(user_info); - } else if (query->modify_info) { - create_modify_info_dialogue(gc, info); - } - qd->info_query = g_list_remove(qd->info_query, qd->info_query->data); - g_free(query); - break; + query_list = qd->info_query; + /* ensure we're processing the right query */ + while (query_list) { + query = (qq_info_query *) query_list->data; + if (query->uid == atoi(info->uid)) { + if (query->show_window) { + user_info = info_to_notify_user_info(info); + purple_notify_userinfo(gc, info->uid, user_info, NULL, NULL); + purple_notify_user_info_destroy(user_info); + } else if (query->modify_info) { + create_modify_info_dialogue(gc, info); } - query_list = query_list->next; + qd->info_query = g_list_remove(qd->info_query, qd->info_query->data); + g_free(query); + break; } + query_list = query_list->next; + } - g_strfreev(segments); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt get info reply\n"); - } + g_strfreev(segments); } void qq_info_query_free(qq_data *qd) @@ -975,25 +958,18 @@ qq_send_cmd(qd, QQ_CMD_GET_LEVEL, buf, size); } -void qq_process_get_level_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_get_level_reply(guint8 *decr_buf, gint decr_len, PurpleConnection *gc) { guint32 uid, onlineTime; guint16 level, timeRemainder; gchar *purple_name; PurpleBuddy *b; qq_buddy *q_bud; - gint decr_len, i; - guint8 *decr_buf; + gint i; PurpleAccount *account = purple_connection_get_account(gc); qq_data *qd = (qq_data *) gc->proto_data; gint bytes = 0; - decr_len = buf_len; - decr_buf = g_new0(guint8, buf_len); - if (!qq_decrypt(buf, buf_len, qd->session_key, decr_buf, &decr_len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Couldn't decrypt get level packet\n"); - } - decr_len--; if (decr_len % 12 != 0) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", @@ -1014,25 +990,34 @@ purple_debug(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); + continue; + } + purple_name = uid_to_purple_name(uid); + if (purple_name == NULL) { + continue; + } + b = purple_find_buddy(account, purple_name); - q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; + g_free(purple_name); - if (q_bud != NULL || uid == qd->uid) { - if (q_bud) { - q_bud->onlineTime = onlineTime; - q_bud->level = level; - q_bud->timeRemainder = timeRemainder; - } - if (uid == qd->uid) { - qd->my_level = level; - } - } else { + q_bud = NULL; + if (b != NULL) { + q_bud = (qq_buddy *) b->proto_data; + } + + if (q_bud == NULL) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Got an online buddy %d, but not in my buddy list\n", uid); + "Got levels of %d not in my buddy list\n", uid); + continue; } - g_free(purple_name); + + q_bud->onlineTime = onlineTime; + q_bud->level = level; + q_bud->timeRemainder = timeRemainder; } - g_free(decr_buf); }
--- a/libpurple/protocols/qq/buddy_info.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.h Sun Aug 10 04:32:14 2008 +0000 @@ -71,8 +71,8 @@ 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); -void qq_process_modify_info_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); -void qq_process_get_info_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); +void qq_process_modify_info_reply(guint8 *data, gint data_len, PurpleConnection *gc); +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);
--- a/libpurple/protocols/qq/buddy_list.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Sun Aug 10 04:32:14 2008 +0000 @@ -34,7 +34,6 @@ #include "buddy_list.h" #include "buddy_opt.h" #include "char_conv.h" -#include "crypt.h" #include "header_info.h" #include "qq_base.h" #include "group.h" @@ -103,7 +102,7 @@ } /* get all list, buddies & Quns with groupsid support */ -void qq_send_packet_get_all_list_with_group(PurpleConnection *gc, guint32 position) +void qq_send_packet_get_buddies_and_rooms(PurpleConnection *gc, guint32 position) { qq_data *qd = (qq_data *) gc->proto_data; guint8 raw_data[16] = {0}; @@ -117,7 +116,7 @@ bytes += qq_put32(raw_data + bytes, 0x00000000); bytes += qq_put32(raw_data + bytes, position); - qq_send_cmd(qd, QQ_CMD_GET_ALL_LIST_WITH_GROUP, raw_data, bytes); + qq_send_cmd(qd, QQ_CMD_GET_BUDDIES_AND_ROOMS, raw_data, bytes); } /* parse the data into qq_buddy_status */ @@ -158,28 +157,20 @@ #define QQ_ONLINE_BUDDY_ENTRY_LEN 38 /* process the reply packet for get_buddies_online packet */ -guint8 qq_process_get_buddies_online_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +guint8 qq_process_get_buddies_online_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len, bytes, bytes_buddy; + gint bytes, bytes_buddy; gint count; - guint8 *data, position; + guint8 position; PurpleBuddy *b; qq_buddy *q_bud; qq_buddy_online bo; + gchar *purple_name; - g_return_val_if_fail(buf != NULL && buf_len != 0, -1); + g_return_val_if_fail(data != NULL && data_len != 0, -1); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - - purple_debug(PURPLE_DEBUG_INFO, "QQ", "processing get_buddies_online_reply\n"); - - if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies online"); - return -1; - } /* qq_show_packet("Get buddies online reply packet", data, len); */ @@ -187,11 +178,11 @@ bytes += qq_get8(&position, data + bytes); count = 0; - while (bytes < len) { - if (len - bytes < QQ_ONLINE_BUDDY_ENTRY_LEN) { + 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", - (len - bytes), QQ_ONLINE_BUDDY_ENTRY_LEN); + (data_len - bytes), QQ_ONLINE_BUDDY_ENTRY_LEN); break; } memset(&bo, 0 ,sizeof(bo)); @@ -219,9 +210,22 @@ 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); + continue; + } + /* update buddy information */ - b = purple_find_buddy(purple_connection_get_account(gc), - uid_to_purple_name(bo.bs.uid) ); + purple_name = uid_to_purple_name(bo.bs.uid); + if (purple_name == NULL) { + purple_debug(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", @@ -242,7 +246,7 @@ count++; } - if(bytes > len) { + if(bytes > data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "qq_process_get_buddies_online_reply: Dangerous error! maybe protocol changed, notify developers!\n"); } @@ -254,32 +258,31 @@ /* process reply for get_buddies_list */ -guint16 qq_process_get_buddies_list_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +guint16 qq_process_get_buddies_list_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; qq_buddy *q_bud; - gint len, bytes_expected, count; + gint bytes_expected, count; gint bytes, buddy_bytes; guint16 position, unknown; - guint8 *data, pascal_len; + guint8 pascal_len; gchar *name; PurpleBuddy *b; - g_return_val_if_fail(buf != NULL && buf_len != 0, -1); + g_return_val_if_fail(data != NULL && data_len != 0, -1); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt buddies list"); + if (data_len <= 2) { + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "empty buddies list"); return -1; } + /* qq_show_packet("QQ get buddies list", data, data_len); */ bytes = 0; bytes += qq_get16(&position, data + bytes); /* the following data is buddy list in this packet */ count = 0; - while (bytes < len) { + while (bytes < data_len) { q_bud = g_new0(qq_buddy, 1); /* set flag */ buddy_bytes = bytes; @@ -311,11 +314,11 @@ count++; } - if (QQ_DEBUG) { - purple_debug(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); - } +#if 1 + purple_debug(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 name = uid_to_purple_name(q_bud->uid); b = purple_find_buddy(gc->account, name); @@ -330,7 +333,7 @@ qq_update_buddy_contact(gc, q_bud); } - if(bytes > len) { + if(bytes > data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "qq_process_get_buddies_list_reply: Dangerous error! maybe protocol changed, notify developers!"); } @@ -340,36 +343,29 @@ return position; } -guint32 qq_process_get_all_list_with_group_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +guint32 qq_process_get_buddies_and_rooms(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len, i, j; - gint bytes = 0; - guint8 *data; + gint i, j; + gint bytes; guint8 sub_cmd, reply_code; guint32 unknown, position; guint32 uid; guint8 type, groupid; qq_group *group; - g_return_val_if_fail(buf != NULL && buf_len != 0, -1); + g_return_val_if_fail(data != NULL && data_len != 0, -1); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt all list with group"); - return -1; - } - + bytes = 0; bytes += qq_get8(&sub_cmd, data + bytes); g_return_val_if_fail(sub_cmd == 0x01, -1); bytes += qq_get8(&reply_code, data + bytes); if(0 != reply_code) { purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Get all list with group reply, reply_code(%d) is not zero", reply_code); + "qq_process_get_buddies_and_rooms, %d", reply_code); } bytes += qq_get32(&unknown, data + bytes); @@ -377,7 +373,7 @@ /* the following data is all list in this packet */ i = 0; j = 0; - while (bytes < len) { + while (bytes < data_len) { /* 00-03: uid */ bytes += qq_get32(&uid, data + bytes); /* 04: type 0x1:buddy 0x4:Qun */ @@ -398,24 +394,24 @@ * qq_send_packet_get_buddies_list */ ++i; } else { /* a group */ - group = qq_group_find_by_id(gc, uid, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, uid); if(group == NULL) { + purple_debug(PURPLE_DEBUG_INFO, "QQ", + "Not find room id %d in qq_process_get_buddies_and_rooms\n", uid); qq_set_pending_id(&qd->adding_groups_from_server, uid, TRUE); - group = g_newa(qq_group, 1); - group->internal_group_id = uid; - qq_send_cmd_group_get_group_info(gc, group); + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, uid); } else { group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group); - qq_send_cmd_group_get_group_info(gc, group); + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); } ++j; } } - if(bytes > len) { + if(bytes > data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "qq_process_get_all_list_with_group_reply: Dangerous error! maybe protocol changed, notify developers!"); + "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); @@ -505,26 +501,19 @@ } /* parse the reply packet for change_status */ -void qq_process_change_status_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_change_status_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len, bytes; - guint8 *data, reply; + gint bytes; + guint8 reply; PurpleBuddy *b; qq_buddy *q_bud; gchar *name; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - - if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt chg status reply\n"); - return; - } - + bytes = 0; bytes = qq_get8(&reply, data + bytes); if (reply != QQ_CHANGE_ONLINE_STATUS_REPLY_OK) { @@ -543,28 +532,19 @@ } /* it is a server message indicating that one of my buddies has changed its status */ -void qq_process_buddy_change_status(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_buddy_change_status(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; gint bytes; guint32 my_uid; - guint8 *data; - gint data_len; PurpleBuddy *b; qq_buddy *q_bud; qq_buddy_status bs; gchar *name; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - data_len = buf_len; - data = g_newa(guint8, data_len); - - if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &data_len) ) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[buddy status change] Failed decrypt\n"); - return; - } if (data_len < 35) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[buddy status change] only %d, need 35 bytes\n", data_len); @@ -606,18 +586,22 @@ /*TODO: maybe this should be qq_update_buddy_status() ?*/ void qq_update_buddy_contact(PurpleConnection *gc, qq_buddy *q_bud) { - gchar *name; + gchar *purple_name; PurpleBuddy *bud; gchar *status_id; g_return_if_fail(q_bud != NULL); - name = uid_to_purple_name(q_bud->uid); - bud = purple_find_buddy(gc->account, name); + 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); + return; + } + bud = purple_find_buddy(gc->account, purple_name); if (bud == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "unknown buddy: %d\n", q_bud->uid); - g_free(name); + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Not find buddy: %d\n", q_bud->uid); + g_free(purple_name); return; } @@ -650,19 +634,19 @@ break; } purple_debug(PURPLE_DEBUG_INFO, "QQ", "buddy %d %s\n", q_bud->uid, status_id); - purple_prpl_got_user_status(gc->account, name, status_id, NULL); + 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) - purple_prpl_got_user_status(gc->account, name, "mobile", NULL); + purple_prpl_got_user_status(gc->account, purple_name, "mobile", NULL); else - purple_prpl_got_user_status_deactive(gc->account, name, "mobile"); + purple_prpl_got_user_status_deactive(gc->account, purple_name, "mobile"); if (q_bud->comm_flag & QQ_COMM_FLAG_VIDEO && q_bud->status != QQ_BUDDY_OFFLINE) - purple_prpl_got_user_status(gc->account, name, "video", NULL); + purple_prpl_got_user_status(gc->account, purple_name, "video", NULL); else - purple_prpl_got_user_status_deactive(gc->account, name, "video"); + purple_prpl_got_user_status_deactive(gc->account, purple_name, "video"); - g_free(name); + g_free(purple_name); } /* refresh all buddies online/offline,
--- a/libpurple/protocols/qq/buddy_list.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.h Sun Aug 10 04:32:14 2008 +0000 @@ -49,13 +49,13 @@ }; void qq_send_packet_get_buddies_online(PurpleConnection *gc, guint8 position); -guint8 qq_process_get_buddies_online_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); +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); -guint16 qq_process_get_buddies_list_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); +guint16 qq_process_get_buddies_list_reply(guint8 *data, gint data_len, PurpleConnection *gc); -void qq_send_packet_get_all_list_with_group(PurpleConnection *gc, guint32 position); -guint32 qq_process_get_all_list_with_group_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); +void qq_send_packet_get_buddies_and_rooms(PurpleConnection *gc, guint32 position); +guint32 qq_process_get_buddies_and_rooms(guint8 *data, gint data_len, PurpleConnection *gc); void qq_refresh_all_buddy_status(PurpleConnection *gc); @@ -64,8 +64,8 @@ gint get_icon_offset(PurpleConnection *gc); void qq_send_packet_change_status(PurpleConnection *gc); -void qq_process_change_status_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); -void qq_process_buddy_change_status(guint8 *buf, gint buf_len, PurpleConnection *gc); +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); void qq_refresh_all_buddy_status(PurpleConnection *gc); void qq_update_buddy_contact(PurpleConnection *gc, qq_buddy *q_bud);
--- a/libpurple/protocols/qq/buddy_opt.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Sun Aug 10 04:32:14 2008 +0000 @@ -31,7 +31,6 @@ #include "buddy_list.h" #include "buddy_opt.h" #include "char_conv.h" -#include "crypt.h" #include "header_info.h" #include "im.h" #include "qq_base.h" @@ -252,29 +251,18 @@ } /* process reply to add_buddy_auth request */ -void qq_process_add_buddy_auth_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_add_buddy_auth_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len; - gint bytes = 0; - guint8 *data, reply; gchar **segments, *msg_utf8; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt add buddy with auth reply\n"); - } - - bytes += qq_get8(&reply, data + bytes); - - if (reply != QQ_ADD_BUDDY_AUTH_REPLY_OK) { + if (data[0] != QQ_ADD_BUDDY_AUTH_REPLY_OK) { purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Add buddy with auth request failed\n"); - if (NULL == (segments = split_data(data, len, "\x1f", 2))) { + if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) { return; } msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT); @@ -286,26 +274,15 @@ } /* process the server reply for my request to remove a buddy */ -void qq_process_remove_buddy_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_remove_buddy_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len; - gint bytes = 0; - guint8 *data, reply; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt remove buddy reply\n"); - } - - bytes += qq_get8(&reply, data + bytes); - - if (reply != QQ_REMOVE_BUDDY_REPLY_OK) { + 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"); } else { /* if reply */ @@ -316,26 +293,15 @@ } /* process the server reply for my request to remove myself from a buddy */ -void qq_process_remove_self_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_remove_self_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len; - gint bytes = 0; - guint8 *data, reply; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt remove self reply\n"); - } - - bytes += qq_get8(&reply, data + bytes); - - if (reply != QQ_REMOVE_SELF_REPLY_OK) { + 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"); } else { /* if reply */ @@ -345,23 +311,21 @@ } } -void qq_process_add_buddy_reply(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc) +void qq_process_add_buddy_reply(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc) { qq_data *qd; - gint len, for_uid; + gint for_uid; gchar *msg, **segments, *uid, *reply; - guint8 *data; GList *list; PurpleBuddy *b; gc_and_uid *g; qq_add_buddy_request *req; gchar *nombre; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); for_uid = 0; qd = (qq_data *) gc->proto_data; - len = buf_len; list = qd->add_buddy_request; while (list != NULL) { @@ -382,50 +346,45 @@ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Add buddy reply [%d] is for id [%d]\n", seq, for_uid); } - data = g_newa(guint8, len); - - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - if (NULL == (segments = split_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); - g_strfreev(segments); - return; - } + 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); + 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"); - nombre = uid_to_purple_name(for_uid); - b = purple_find_buddy(gc->account, nombre); - if (b != NULL) - purple_blist_remove_buddy(b); - g = g_new0(gc_and_uid, 1); - g->gc = gc; - g->uid = for_uid; - msg = g_strdup_printf(_("User %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?"), - TRUE, FALSE, NULL, _("Send"), - G_CALLBACK - (_qq_send_packet_add_buddy_auth_with_gc_and_uid), - _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), - purple_connection_get_account(gc), nombre, NULL, - g); - g_free(msg); - g_free(nombre); - } else { /* add OK */ - qq_add_buddy_by_recv_packet(gc, for_uid, TRUE, TRUE); - msg = g_strdup_printf(_("You have added %d to buddy list"), for_uid); - purple_notify_info(gc, NULL, msg, NULL); - g_free(msg); - } - g_strfreev(segments); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt add buddy reply\n"); + if (strtol(reply, NULL, 10) > 0) { /* need auth */ + purple_debug(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) + purple_blist_remove_buddy(b); + g = g_new0(gc_and_uid, 1); + g->gc = gc; + g->uid = for_uid; + msg = g_strdup_printf(_("User %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?"), + TRUE, FALSE, NULL, _("Send"), + G_CALLBACK + (_qq_send_packet_add_buddy_auth_with_gc_and_uid), + _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid), + purple_connection_get_account(gc), nombre, NULL, + g); + g_free(msg); + g_free(nombre); + } else { /* add OK */ + qq_add_buddy_by_recv_packet(gc, for_uid, TRUE, TRUE); + msg = g_strdup_printf(_("You have added %d to buddy list"), for_uid); + purple_notify_info(gc, NULL, msg, NULL); + g_free(msg); } + g_strfreev(segments); } PurpleGroup *qq_get_purple_group(const gchar *group_name)
--- a/libpurple/protocols/qq/buddy_opt.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.h Sun Aug 10 04:32:14 2008 +0000 @@ -46,9 +46,9 @@ void qq_do_nothing_with_gc_and_uid(gc_and_uid *g, const gchar *msg); void qq_process_remove_buddy_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); -void qq_process_remove_self_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); -void qq_process_add_buddy_reply(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc); -void qq_process_add_buddy_auth_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); +void qq_process_remove_self_reply(guint8 *data, gint data_len, PurpleConnection *gc); +void qq_process_add_buddy_reply(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc); +void qq_process_add_buddy_auth_reply(guint8 *data, gint data_len, PurpleConnection *gc); PurpleBuddy *qq_add_buddy_by_recv_packet(PurpleConnection *gc, guint32 uid, gboolean is_known, gboolean create); void qq_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
--- a/libpurple/protocols/qq/crypt.c Sat Aug 09 23:23:48 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/** - * @file crypt.c - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * QQ encryption algorithm - * Convert from ASM code provided by PerlOICQ - * - * Puzzlebird, Nov-Dec 2002 - */ - -/* Notes: (QQ uses 16 rounds, and modified something...) - -IN : 64 bits of data in v[0] - v[1]. -OUT: 64 bits of data in w[0] - w[1]. -KEY: 128 bits of key in k[0] - k[3]. - -delta is chosen to be the real part of -the golden ratio: Sqrt(5/4) - 1/2 ~ 0.618034 multiplied by 2^32. - -0x61C88647 is what we can track on the ASM codes.!! -*/ - -#include <string.h> - -#include "crypt.h" -#include "debug.h" - -/* 1, fixed alignment problem, when compiled on different platform - * 2, whether we need core debug - * 20070717, s3e */ -#if 0 -#define CORE_DEBUG -#endif - -/******************************************************************** - * encryption - *******************************************************************/ - -/* Tiny Encryption Algorithm (TEA) */ -static void qq_encipher(guint32 *const v, const guint32 *const k, guint32 *const w) -{ - register guint32 - y = g_ntohl(v[0]), - z = g_ntohl(v[1]), - a = g_ntohl(k[0]), - b = g_ntohl(k[1]), - c = g_ntohl(k[2]), - d = g_ntohl(k[3]), - n = 0x10, - sum = 0, - delta = 0x9E3779B9; /* 0x9E3779B9 - 0x100000000 = -0x61C88647 */ - - while (n-- > 0) { - sum += delta; - y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); - z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); - } - - w[0] = g_htonl(y); - w[1] = g_htonl(z); -} - -/* it can be the real random seed function */ -/* override with number, convenient for debug */ -#ifdef DEBUG -static gint rand(void) { - return 0xdead; -} -#else -#include <stdlib.h> -#endif - -/* 64-bit blocks and some kind of feedback mode of operation */ -static inline void encrypt_block(guint8 *plain, guint8 *plain_pre_8, guint8 **crypted, - guint8 **crypted_pre_8, const guint8 *const key, gint *count, - gint *pos_in_block, gint *is_header) -{ - /* loop it */ - int j; - /* ships in encipher */ - guint32 ptr_p[2]; /* 64 bits, guint32[2] */ - guint32 ptr_k[4]; /* 128 bits, guint32[4] */ - guint32 ptr_c[2]; /* 64 bits, guint32[2] */ - - /* prepare input text */ -#ifdef CORE_DEBUG - purple_debug(PURPLE_DEBUG_ERROR, "QQ_CORE_DEBUG", - "!we are in encrypt_block! *pos_in_block comes: %d, *is_header comes: %d\n", - *pos_in_block, *is_header); -#endif - for(j = 0; j < 8; j++) { -#ifdef CORE_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ_CORE_DEBUG", - "plain[%d]: 0x%02x, plain_pre_8[%d]: 0x%02x\n", - j, plain[j], j, plain_pre_8[j]); -#endif - if (!*is_header) { -#ifdef CORE_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ_CORE_DEBUG", - "(*crypted_pre_8 + %d): 0x%02x\n", - j, *(*crypted_pre_8 + j)); -#endif - plain[j] ^= (*(*crypted_pre_8 + j)); -#ifdef CORE_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ_CORE_DEBUG", - "NOW plain[%d]: 0x%02x\n", - j, plain[j]); -#endif - } else { - plain[j] ^= plain_pre_8[j]; -#ifdef CORE_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ_CORE_DEBUG", - "NOW plain[%d]: 0x%02x\n", - j, plain[j]); -#endif - } - } - - g_memmove(ptr_p, plain, 8); - g_memmove(ptr_k, key, 16); - g_memmove(ptr_c, *crypted, 8); - - /* encrypt it */ - qq_encipher(ptr_p, ptr_k, ptr_c); - - g_memmove(plain, ptr_p, 8); - g_memmove(*crypted, ptr_c, 8); - - for(j = 0; j < 8; j++) { -#ifdef CORE_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ_CORE_DEBUG", - "j: %d, *(*crypted + %d): 0x%02x, plain_pre_8[%d]: 0x%02x\n", - j, j, *(*crypted + j), j, plain_pre_8[j]); -#endif - (*(*crypted + j)) ^= plain_pre_8[j]; -#ifdef CORE_DEBUG - purple_debug(PURPLE_DEBUG_INFO, "QQ_CORE_DEBUG", - "NOW *(*crypted + [%d]): 0x%02x\n", - j, *(*crypted + j)); -#endif - } - - memcpy(plain_pre_8, plain, 8); /* prepare next */ - - *crypted_pre_8 = *crypted; /* store position of previous 8 byte */ - *crypted += 8; /* prepare next output */ - *count += 8; /* outstrlen increase by 8 */ - *pos_in_block = 0; /* back to start */ - *is_header = 0; /* and exit header */ -} /* encrypt_block */ - -void qq_encrypt(const guint8 *const instr, gint instrlen, - const guint8 *const key, - guint8 *outstr, gint *outstrlen_ptr) -{ - guint8 plain[8], /* plain text buffer */ - plain_pre_8[8], /* plain text buffer, previous 8 bytes */ - *crypted, /* crypted text */ - *crypted_pre_8; /* crypted text, previous 8 bytes */ - const guint8 *inp; /* current position in instr */ - gint pos_in_block = 1, /* loop in the byte */ - is_header = 1, /* header is one byte */ - count = 0, /* number of bytes being crypted */ - padding = 0; /* number of padding stuff */ - - pos_in_block = (instrlen + 0x0a) % 8; /* header padding decided by instrlen */ - if (pos_in_block) - pos_in_block = 8 - pos_in_block; - - /* initialization vector */ - plain[0] = (rand() & 0xf8) | pos_in_block; - memset(plain + 1, rand() & 0xff, pos_in_block++); - - memset(plain_pre_8, 0x00, sizeof(plain_pre_8)); - - crypted = crypted_pre_8 = outstr; - - padding = 1; /* pad some stuff in header */ - while (padding <= 2) { /* at most two bytes */ - if (pos_in_block < 8) { - plain[pos_in_block++] = rand() & 0xff; - padding++; - } - if (pos_in_block == 8) { - encrypt_block(plain, plain_pre_8, &crypted, &crypted_pre_8, - key, &count, &pos_in_block, &is_header); - } - } - - inp = instr; - while (instrlen > 0) { - if (pos_in_block < 8) { - plain[pos_in_block++] = *(inp++); - instrlen--; - } - if (pos_in_block == 8) { - encrypt_block(plain, plain_pre_8, &crypted, &crypted_pre_8, - key, &count, &pos_in_block, &is_header); - } - } - - padding = 1; /* pad some stuff in tail */ - while (padding <= 7) { /* at most seven bytes */ - if (pos_in_block < 8) { - plain[pos_in_block++] = 0x00; - padding++; - } - if (pos_in_block == 8) { - encrypt_block(plain, plain_pre_8, &crypted, &crypted_pre_8, - key, &count, &pos_in_block, &is_header); - } - } - - *outstrlen_ptr = count; -} - - -/******************************************************************** - * decryption - ********************************************************************/ - -static void qq_decipher(guint32 *const v, const guint32 *const k, guint32 *const w) -{ - register guint32 - y = g_ntohl(v[0]), - z = g_ntohl(v[1]), - a = g_ntohl(k[0]), - b = g_ntohl(k[1]), - c = g_ntohl(k[2]), - d = g_ntohl(k[3]), - n = 0x10, - sum = 0xE3779B90, /* why this ? must be related with n value */ - delta = 0x9E3779B9; - - /* sum = delta<<5, in general sum = delta * n */ - while (n-- > 0) { - z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); - y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); - sum -= delta; - } - - w[0] = g_htonl(y); - w[1] = g_htonl(z); -} - -static gint decrypt_block(const guint8 **crypt_buff, const gint instrlen, - const guint8 *const key, gint *context_start, - guint8 *decrypted, gint *pos_in_block) -{ - /* loop */ - int i; - /* ships in decipher */ - guint32 ptr_v[2]; - guint32 ptr_k[4]; - - if (*context_start == instrlen) - return 1; - - for(i = 0; i < 8; i++) { - decrypted[i] ^= (*(*crypt_buff + i)); - } - - g_memmove(ptr_v, decrypted, 8); - g_memmove(ptr_k, key, 16); - - qq_decipher(ptr_v, ptr_k, ptr_v); - - g_memmove(decrypted, ptr_v, 8); - - *context_start += 8; - *crypt_buff += 8; - *pos_in_block = 0; - - return 1; -} - -/* return 0 if failed, 1 otherwise */ -gint qq_decrypt(const guint8 *const instr, gint instrlen, - const guint8 *const key, - guint8 *outstr, gint *outstrlen_ptr) -{ - guint8 decrypted[8], m[8], *outp; - const guint8 *crypt_buff, *crypt_buff_pre_8; - gint count, context_start, pos_in_block, padding; - /* ships */ - guint32 ptr_instr[2]; - guint32 ptr_key[4]; - guint32 ptr_decr[2]; - - /* at least 16 bytes and %8 == 0 */ - if ((instrlen % 8) || (instrlen < 16)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Ciphertext len is either too short or not a multiple of 8 bytes, read %d bytes\n", - instrlen); - return 0; - } - g_memmove(ptr_instr, instr, 8); - g_memmove(ptr_key, key, 16); - g_memmove(ptr_decr, decrypted, 8); - - qq_decipher(ptr_instr, ptr_key, ptr_decr); - - g_memmove(decrypted, ptr_decr, 8); - - pos_in_block = decrypted[0] & 0x7; - count = instrlen - pos_in_block - 10; /* this is the plaintext length */ - /* return if outstr buffer is not large enough or error plaintext length */ - if (*outstrlen_ptr < count || count < 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Buffer len %d is less than real len %d", - *outstrlen_ptr, count); - return 0; - } - - memset(m, 0, 8); - crypt_buff_pre_8 = m; - *outstrlen_ptr = count; /* everything is ok! set return string length */ - - crypt_buff = instr + 8; /* address of real data start */ - context_start = 8; /* context is at the second block of 8 bytes */ - pos_in_block++; /* start of paddng stuff */ - - padding = 1; /* at least one in header */ - while (padding <= 2) { /* there are 2 byte padding stuff in header */ - if (pos_in_block < 8) { /* bypass the padding stuff, it's nonsense data */ - pos_in_block++; - padding++; - } - if (pos_in_block == 8) { - crypt_buff_pre_8 = instr; - if (!decrypt_block(&crypt_buff, instrlen, key, - &context_start, decrypted, &pos_in_block)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "decrypt every 8 bytes error A"); - return 0; - } - } - } - - outp = outstr; - while (count != 0) { - if (pos_in_block < 8) { - *outp = crypt_buff_pre_8[pos_in_block] ^ decrypted[pos_in_block]; - outp++; - count--; - pos_in_block++; - } - if (pos_in_block == 8) { - crypt_buff_pre_8 = crypt_buff - 8; - if (!decrypt_block(&crypt_buff, instrlen, key, - &context_start, decrypted, &pos_in_block)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "decrypt every 8 bytes error B"); - return 0; - } - } - } - - for (padding = 1; padding < 8; padding++) { - if (pos_in_block < 8) { - if (crypt_buff_pre_8[pos_in_block] ^ decrypted[pos_in_block]) - return 0; - pos_in_block++; - } - if (pos_in_block == 8) { - crypt_buff_pre_8 = crypt_buff; - if (!decrypt_block(&crypt_buff, instrlen, key, - &context_start, decrypted, &pos_in_block)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "decrypt every 8 bytes error C"); - return 0; - } - } - } - - return 1; -}
--- a/libpurple/protocols/qq/crypt.h Sat Aug 09 23:23:48 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ - /** - * @file crypt.h - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _QQ_CRYPT_H_ -#define _QQ_CRYPT_H_ - -#include <glib.h> - -#define DECRYPT 0x00 -#define ENCRYPT 0x01 - -void qq_encrypt(const guint8 *const instr, gint instrlen, - const guint8 *const key, - guint8 *outstr, gint *outstrlen_ptr); - -gint qq_decrypt(const guint8 *const instr, gint instrlen, - const guint8 *const key, - guint8 *outstr, gint *outstrlen_ptr); -#endif
--- a/libpurple/protocols/qq/file_trans.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/file_trans.c Sun Aug 10 04:32:14 2008 +0000 @@ -32,7 +32,7 @@ #include "ft.h" #include "cipher.h" -#include "crypt.h" +#include "qq_crypt.h" #include "file_trans.h" #include "header_info.h" #include "im.h" @@ -338,31 +338,30 @@ raw_data, bytes, "sending packet[%s]:", qq_get_file_cmd_desc(packet_type)); - encrypted_len = bytes + 16; - encrypted_data = g_newa(guint8, encrypted_len); - qq_encrypt(raw_data, bytes, info->file_session_key, encrypted_data, &encrypted_len); + encrypted_data = g_newa(guint8, bytes + 16); + encrypted_len = qq_encrypt(encrypted_data, raw_data, bytes, info->file_session_key); /*debug: try to decrypt it */ - /* - if (QQ_DEBUG) { - 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); - 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"); + +#if 0 + 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); + 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"); if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0) - purple_debug(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); - g_free(hex_dump); - } else { - purple_debug(PURPLE_DEBUG_INFO, "QQ", "decrypt fail\n"); - } - } - */ + purple_debug(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); + g_free(hex_dump); + } else { + purple_debug(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)); _qq_send_file(gc, encrypted_data, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); @@ -498,7 +497,7 @@ */ -static void _qq_process_recv_file_ctl_packet(PurpleConnection *gc, guint8 *data, gint len) +static void _qq_process_recv_file_ctl_packet(PurpleConnection *gc, guint8 *data, gint data_len) { gint bytes ; gint decryped_bytes; @@ -514,10 +513,9 @@ bytes = 0; bytes += _qq_get_file_header(&fh, data + bytes); - decrypted_data = g_newa(guint8, len); - decrypted_len = len; - - if ( !qq_decrypt(data, len, qd->session_md5, decrypted_data, &decrypted_len) ) { + 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"); return; }
--- a/libpurple/protocols/qq/group.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group.c Sun Aug 10 04:32:14 2008 +0000 @@ -32,17 +32,18 @@ #include "group_info.h" #include "group_search.h" #include "utils.h" - +#include "qq_network.h" +#include "header_info.h" #include "group.h" static void _qq_group_search_callback(PurpleConnection *gc, const gchar *input) { - guint32 external_group_id; + guint32 ext_id; g_return_if_fail(input != NULL); - external_group_id = qq_string_to_dec_value(input); + ext_id = qq_string_to_dec_value(input); /* 0x00000000 means search for demo group */ - qq_send_cmd_group_search_group(gc, external_group_id); + qq_send_cmd_group_search_group(gc, ext_id); } static void _qq_group_search_cancel_callback(PurpleConnection *gc, const gchar *input) @@ -104,7 +105,7 @@ fields = g_list_append(fields, f); f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_INTERNAL_ID, TRUE); fields = g_list_append(fields, f); - f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_KEY_GROUP_TYPE, TRUE); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", QQ_GROUP_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); fields = g_list_append(fields, f); @@ -145,12 +146,12 @@ /* this should be called upon signin, even when we did not open group chat window */ void qq_group_init(PurpleConnection *gc) { - gint i; PurpleAccount *account; PurpleChat *chat; PurpleGroup *purple_group; PurpleBlistNode *node; qq_group *group; + gint count; account = purple_connection_get_account(gc); @@ -160,18 +161,25 @@ return; } - i = 0; - for (node = ((PurpleBlistNode *) purple_group)->child; node != NULL; node = node->next) - if (PURPLE_BLIST_NODE_IS_CHAT(node)) { /* got one */ - chat = (PurpleChat *) node; - if (account != chat->account) - continue; /* very important here ! */ - group = qq_group_from_hashtable(gc, chat->components); - if (group != NULL) { - i++; - qq_send_cmd_group_get_group_info(gc, group); /* get group info and members */ - } + count = 0; + for (node = ((PurpleBlistNode *) purple_group)->child; node != NULL; node = node->next) { + if ( !PURPLE_BLIST_NODE_IS_CHAT(node)) { + continue; } + /* got one */ + chat = (PurpleChat *) node; + if (account != chat->account) /* not qq account*/ + continue; + group = qq_group_from_hashtable(gc, chat->components); + if (group == NULL) + continue; - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Load %d QQ Qun configurations\n", i); + if (group->id <= 0) + 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); }
--- a/libpurple/protocols/qq/group.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group.h Sun Aug 10 04:32:14 2008 +0000 @@ -44,9 +44,9 @@ /* 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 */ - guint32 internal_group_id; - guint32 external_group_id; - guint8 group_type; /* permanent or temporory */ + guint32 id; + guint32 ext_id; + guint8 type8; /* permanent or temporory */ guint32 creator_uid; guint32 group_category; guint8 auth_type;
--- a/libpurple/protocols/qq/group_find.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_find.c Sun Aug 10 04:32:14 2008 +0000 @@ -29,36 +29,8 @@ #include "util.h" #include "group_find.h" -#include "group_network.h" #include "utils.h" -/* find the internal_group_id by the reply packet sequence - * return TRUE if we have a record of it, return FALSE if not */ -gboolean qq_group_find_internal_group_id_by_seq(PurpleConnection *gc, guint16 seq, guint32 *internal_group_id) -{ - GList *list; - qq_data *qd; - group_packet *p; - - if (internal_group_id == NULL) - return FALSE; - qd = (qq_data *) gc->proto_data; - - list = qd->group_packets; - while (list != NULL) { - p = (group_packet *) (list->data); - if (p->send_seq == seq) { /* found and remove */ - *internal_group_id = p->internal_group_id; - qd->group_packets = g_list_remove(qd->group_packets, p); - g_free(p); - return TRUE; - } - list = list->next; - } - - return FALSE; -} - /* find a qq_buddy by uid, called by im.c */ qq_buddy *qq_group_find_member_by_uid(qq_group *group, guint32 uid) { @@ -150,7 +122,7 @@ } /* find a qq_group by its id, flag is QQ_INTERNAL_ID or QQ_EXTERNAL_ID */ -qq_group *qq_group_find_by_id(PurpleConnection *gc, guint32 id, gboolean flag) +qq_group *qq_room_search_ext_id(PurpleConnection *gc, guint32 ext_id) { GList *list; qq_group *group; @@ -158,17 +130,40 @@ qd = (qq_data *) gc->proto_data; - if (qd->groups == NULL || id <= 0) + if (qd->groups == NULL || ext_id <= 0) return NULL; list = qd->groups; while (list != NULL) { group = (qq_group *) list->data; - if (flag == QQ_INTERNAL_ID ? - (group->internal_group_id == id) : (group->external_group_id == id)) + if (group->ext_id == ext_id) { return group; + } list = list->next; } return NULL; } + +qq_group *qq_room_search_id(PurpleConnection *gc, guint32 room_id) +{ + GList *list; + qq_group *group; + qq_data *qd; + + qd = (qq_data *) gc->proto_data; + + if (qd->groups == NULL || room_id <= 0) + return NULL; + + list = qd->groups; + while (list != NULL) { + group = (qq_group *) list->data; + if (group->id == room_id) { + return group; + } + list = list->next; + } + + return NULL; +}
--- a/libpurple/protocols/qq/group_find.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_find.h Sun Aug 10 04:32:14 2008 +0000 @@ -29,14 +29,13 @@ #include "connection.h" #include "group.h" -#define QQ_INTERNAL_ID 0 -#define QQ_EXTERNAL_ID 1 - 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_internal_group_id_by_seq(PurpleConnection *gc, guint16 seq, guint32 *internal_group_id); +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_group_find_by_id(PurpleConnection *gc, guint32 id, gboolean flag); + +qq_group *qq_room_search_ext_id(PurpleConnection *gc, guint32 ext_id); +qq_group *qq_room_search_id(PurpleConnection *gc, guint32 room_id); #endif
--- a/libpurple/protocols/qq/group_free.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_free.c Sun Aug 10 04:32:14 2008 +0000 @@ -28,7 +28,6 @@ #include "buddy_list.h" #include "group_free.h" -#include "group_network.h" /* gracefully free all members in a group */ static void qq_group_free_member(qq_group *group) @@ -62,22 +61,6 @@ g_free(group); } -/* clean up group_packets and free all contents */ -void qq_group_packets_free(qq_data *qd) -{ - group_packet *p; - gint i; - - i = 0; - while (qd->group_packets != NULL) { - p = (group_packet *) (qd->group_packets->data); - qd->group_packets = g_list_remove(qd->group_packets, p); - g_free(p); - i++; - } - purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d group packets are freed!\n", i); -} - void qq_group_free_all(qq_data *qd) { qq_group *group;
--- a/libpurple/protocols/qq/group_free.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_free.h Sun Aug 10 04:32:14 2008 +0000 @@ -29,8 +29,6 @@ #include "qq.h" #include "group.h" -void qq_group_packets_free(qq_data *qd); - void qq_group_free(qq_group *group); void qq_group_free_all(qq_data *qd);
--- a/libpurple/protocols/qq/group_im.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_im.c Sun Aug 10 04:32:14 2008 +0000 @@ -36,15 +36,16 @@ #include "group_internal.h" #include "group_info.h" #include "group_im.h" -#include "group_network.h" #include "group_opt.h" #include "im.h" +#include "header_info.h" #include "packet_parse.h" +#include "qq_network.h" #include "utils.h" typedef struct _qq_recv_group_im { - guint32 external_group_id; - guint8 group_type; + guint32 ext_id; + guint8 type8; guint32 member_uid; guint16 msg_seq; time_t send_time; @@ -68,12 +69,10 @@ purple_debug_info("QQ_MESG", "Send qun mesg filterd: %s\n", msg_filtered); msg_len = strlen(msg_filtered); - data_len = 7 + msg_len + QQ_SEND_IM_AFTER_MSG_LEN; + data_len = 2 + msg_len + QQ_SEND_IM_AFTER_MSG_LEN; raw_data = g_newa(guint8, data_len); bytes = 0; - bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_SEND_MSG); - bytes += qq_put32(raw_data + bytes, group->internal_group_id); bytes += qq_put16(raw_data + bytes, msg_len + QQ_SEND_IM_AFTER_MSG_LEN); bytes += qq_putdata(raw_data + bytes, (guint8 *) msg_filtered, msg_len); send_im_tail = qq_get_send_im_tail(NULL, NULL, NULL, @@ -84,7 +83,7 @@ g_free(msg_filtered); if (bytes == data_len) /* create OK */ - qq_send_group_cmd(gc, group, raw_data, data_len); + qq_send_room_cmd(gc, QQ_ROOM_CMD_SEND_MSG, group->id, raw_data, data_len); else purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail creating group_im packet, expect %d bytes, build %d bytes\n", data_len, bytes); @@ -99,33 +98,33 @@ } /* receive an application to join the group */ -void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { - guint32 external_group_id, user_uid; - guint8 group_type; + guint32 ext_id, user_uid; + guint8 type8; gchar *reason_utf8, *msg, *reason; group_member_opt *g; gchar *nombre; gint bytes = 0; - g_return_if_fail(internal_group_id > 0 && data != NULL && len > 0); + g_return_if_fail(id > 0 && data != NULL && len > 0); /* FIXME: check length here */ - bytes += qq_get32(&external_group_id, data + bytes); - bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&ext_id, data + bytes); + bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&user_uid, data + bytes); - g_return_if_fail(external_group_id > 0 && user_uid > 0); + g_return_if_fail(ext_id > 0 && user_uid > 0); 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, external_group_id); + msg = g_strdup_printf(_("User %d requested to join group %d"), user_uid, ext_id); reason = g_strdup_printf(_("Reason: %s"), reason_utf8); g = g_new0(group_member_opt, 1); g->gc = gc; - g->internal_group_id = internal_group_id; + g->id = id; g->member = user_uid; nombre = uid_to_purple_name(user_uid); @@ -150,10 +149,10 @@ } /* the request to join a group is rejected */ -void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { - guint32 external_group_id, admin_uid; - guint8 group_type; + guint32 ext_id, admin_uid; + guint8 type8; gchar *reason_utf8, *msg, *reason; qq_group *group; gint bytes = 0; @@ -162,21 +161,21 @@ /* FIXME: check length here */ - bytes += qq_get32(&external_group_id, data + bytes); - bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&ext_id, data + bytes); + bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&admin_uid, data + bytes); - g_return_if_fail(external_group_id > 0 && admin_uid > 0); + g_return_if_fail(ext_id > 0 && admin_uid > 0); 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"), external_group_id, admin_uid); + (_("Your request to join group %d has been rejected by admin %d"), ext_id, admin_uid); reason = g_strdup_printf(_("Reason: %s"), reason_utf8); purple_notify_warning(gc, _("QQ Qun Operation"), msg, reason); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); if (group != NULL) { group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; qq_group_refresh(gc, group); @@ -188,10 +187,10 @@ } /* the request to join a group is approved */ -void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { - guint32 external_group_id, admin_uid; - guint8 group_type; + guint32 ext_id, admin_uid; + guint8 type8; gchar *reason_utf8, *msg; qq_group *group; gint bytes = 0; @@ -200,20 +199,20 @@ /* FIXME: check length here */ - bytes += qq_get32(&external_group_id, data + bytes); - bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&ext_id, data + bytes); + bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&admin_uid, data + bytes); - g_return_if_fail(external_group_id > 0 && admin_uid > 0); + g_return_if_fail(ext_id > 0 && admin_uid > 0); /* it is also a "æ— " here, so do not display */ 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"), external_group_id, admin_uid); + (_("Your request to join group %d has been approved by admin %d"), ext_id, admin_uid); purple_notify_warning(gc, _("QQ Qun Operation"), msg, NULL); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); if (group != NULL) { group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group); @@ -224,10 +223,10 @@ } /* process the packet when removed from a group */ -void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { - guint32 external_group_id, uid; - guint8 group_type; + guint32 ext_id, uid; + guint8 type8; gchar *msg; qq_group *group; gint bytes = 0; @@ -236,16 +235,16 @@ /* FIXME: check length here */ - bytes += qq_get32(&external_group_id, data + bytes); - bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&ext_id, data + bytes); + bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&uid, data + bytes); - g_return_if_fail(external_group_id > 0 && uid > 0); + g_return_if_fail(ext_id > 0 && uid > 0); - msg = g_strdup_printf(_("You [%d] have left group \"%d\""), uid, external_group_id); + msg = g_strdup_printf(_("You [%d] have left group \"%d\""), uid, ext_id); purple_notify_info(gc, _("QQ Qun Operation"), msg, NULL); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); if (group != NULL) { group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; qq_group_refresh(gc, group); @@ -255,10 +254,10 @@ } /* process the packet when added to a group */ -void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc) +void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { - guint32 external_group_id, uid; - guint8 group_type; + guint32 ext_id, uid; + guint8 type8; qq_group *group; gchar *msg; gint bytes = 0; @@ -267,24 +266,24 @@ /* FIXME: check length here */ - bytes += qq_get32(&external_group_id, data + bytes); - bytes += qq_get8(&group_type, data + bytes); + bytes += qq_get32(&ext_id, data + bytes); + bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&uid, data + bytes); - g_return_if_fail(external_group_id > 0 && uid > 0); + g_return_if_fail(ext_id > 0 && uid > 0); - msg = g_strdup_printf(_("You [%d] have been added to group \"%d\""), uid, external_group_id); + 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")); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); if (group != NULL) { group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; 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, internal_group_id, external_group_id, NULL); + group = qq_group_create_internal_record(gc, id, ext_id, NULL); group->my_status = QQ_GROUP_MEMBER_STATUS_IS_MEMBER; qq_group_refresh(gc, group); - qq_send_cmd_group_get_group_info(gc, group); + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); /* the return of this cmd will automatically update the group in blist */ } @@ -292,7 +291,7 @@ } /* recv an IM from a group chat */ -void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type) +void qq_process_recv_group_im(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; @@ -315,11 +314,11 @@ im_group = g_newa(qq_recv_group_im, 1); - bytes += qq_get32(&(im_group->external_group_id), data + bytes); - bytes += qq_get8(&(im_group->group_type), data + bytes); + bytes += qq_get32(&(im_group->ext_id), data + bytes); + bytes += qq_get8(&(im_group->type8), data + bytes); if(QQ_RECV_IM_TEMP_QUN_IM == im_type) { - bytes += qq_get32(&(internal_group_id), data + bytes); + bytes += qq_get32(&(id), data + bytes); } bytes += qq_get32(&(im_group->member_uid), bytes + data); @@ -372,13 +371,13 @@ else msg_utf8_encoded = qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + 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)); if (conv == NULL && purple_prefs_get_bool("/plugins/prpl/qq/prompt_group_msg_on_recv")) { /* New conv should open, get group info*/ - qq_send_cmd_group_get_group_info(gc, group); + 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));
--- a/libpurple/protocols/qq/group_im.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_im.h Sun Aug 10 04:32:14 2008 +0000 @@ -35,26 +35,26 @@ void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc); /* void qq_process_recv_group_im(guint8 *data, guint8 **cursor, - * gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type); */ -void qq_process_recv_group_im(guint8 *data, gint data_len, guint32 internal_group_id, PurpleConnection *gc, guint16 im_type); + * 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_recv_group_im_apply_join(guint8 *data, guint8 **cursor, gint len, - * guint32 internal_group_id, PurpleConnection *gc); */ -void qq_process_recv_group_im_apply_join(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + * guint32 id, PurpleConnection *gc); */ +void qq_process_recv_group_im_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 internal_group_id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_rejected(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + * guint32 id, PurpleConnection *gc); */ +void qq_process_recv_group_im_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 internal_group_id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_approved(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + * guint32 id, PurpleConnection *gc); */ +void qq_process_recv_group_im_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 internal_group_id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_removed(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + * guint32 id, PurpleConnection *gc); */ +void qq_process_recv_group_im_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 internal_group_id, PurpleConnection *gc); */ -void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 internal_group_id, PurpleConnection *gc); + * guint32 id, PurpleConnection *gc); */ +void qq_process_recv_group_im_been_added(guint8 *data, gint len, guint32 id, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/group_info.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_info.c Sun Aug 10 04:32:14 2008 +0000 @@ -32,7 +32,10 @@ #include "group_internal.h" #include "group_info.h" #include "buddy_list.h" -#include "group_network.h" +#include "header_info.h" +#include "packet_parse.h" +#include "qq_network.h" +#include "utils.h" /* we check who needs to update member info every minutes * this interval determines if their member info is outdated */ @@ -61,20 +64,6 @@ } } -/* send packet to get detailed information of one group */ -void qq_send_cmd_group_get_group_info(PurpleConnection *gc, qq_group *group) -{ - guint8 raw_data[16] = {0}; - gint bytes = 0; - - g_return_if_fail(group != NULL); - - bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_GROUP_INFO); - bytes += qq_put32(raw_data + bytes, group->internal_group_id); - - qq_send_group_cmd(gc, group, raw_data, bytes); -} - /* send packet to get online group member, called by keep_alive */ void qq_send_cmd_group_all_get_online_members(PurpleConnection *gc) { @@ -99,9 +88,6 @@ void qq_send_cmd_group_get_online_members(PurpleConnection *gc, qq_group *group) { - guint8 raw_data[16] = {0}; - gint bytes = 0; - g_return_if_fail(group != NULL); /* only get online members when conversation window is on */ @@ -111,17 +97,14 @@ return; } - bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_ONLINE_MEMBER); - bytes += qq_put32(raw_data + bytes, group->internal_group_id); - - qq_send_group_cmd(gc, group, raw_data, bytes); + 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) { guint8 *raw_data; - gint bytes, num, data_len; + gint bytes, num; GList *list; qq_buddy *member; @@ -137,12 +120,9 @@ return; } - data_len = 5 + 4 * num; - raw_data = g_newa(guint8, data_len); + raw_data = g_newa(guint8, 4 * num); bytes = 0; - bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_GET_MEMBER_INFO); - bytes += qq_put32(raw_data + bytes, group->internal_group_id); list = group->members; while (list != NULL) { @@ -152,16 +132,10 @@ list = list->next; } - if (bytes != data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_GET_MEMBER_INFO)); - return; - } - - qq_send_group_cmd(gc, group, raw_data, bytes); + qq_send_room_cmd(gc, QQ_ROOM_CMD_GET_MEMBER_INFO, group->id, raw_data, bytes); } -void qq_process_group_cmd_get_group_info(guint8 *data, gint len, PurpleConnection *gc) +void qq_process_room_cmd_get_info(guint8 *data, gint data_len, PurpleConnection *gc) { qq_group *group; qq_buddy *member; @@ -169,33 +143,33 @@ PurpleConversation *purple_conv; guint8 organization, role; guint16 unknown, max_members; - guint32 member_uid, internal_group_id, external_group_id; + guint32 member_uid, id, ext_id; GSList *pending_id; guint32 unknown4; guint8 unknown1; gint bytes, num; gchar *notice; - g_return_if_fail(data != NULL && len > 0); + g_return_if_fail(data != NULL && data_len > 0); qd = (qq_data *) gc->proto_data; bytes = 0; - bytes += qq_get32(&(internal_group_id), data + bytes); - g_return_if_fail(internal_group_id > 0); + bytes += qq_get32(&id, data + bytes); + g_return_if_fail(id > 0); - bytes += qq_get32(&(external_group_id), data + bytes); - g_return_if_fail(external_group_id > 0); + bytes += qq_get32(&ext_id, data + bytes); + g_return_if_fail(ext_id > 0); - pending_id = qq_get_pending_id(qd->adding_groups_from_server, internal_group_id); + pending_id = qq_get_pending_id(qd->adding_groups_from_server, id); if (pending_id != NULL) { - qq_set_pending_id(&qd->adding_groups_from_server, internal_group_id, FALSE); - qq_group_create_internal_record(gc, internal_group_id, external_group_id, NULL); + qq_set_pending_id(&qd->adding_groups_from_server, id, FALSE); + qq_group_create_internal_record(gc, id, ext_id, NULL); } - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - bytes += qq_get8(&(group->group_type), data + bytes); + bytes += qq_get8(&(group->type8), data + bytes); bytes += qq_get32(&unknown4, data + bytes); /* unknown 4 bytes */ bytes += qq_get32(&(group->creator_uid), data + bytes); bytes += qq_get8(&(group->auth_type), data + bytes); @@ -210,7 +184,7 @@ * qunDestLen(qunDestcontent)) */ bytes += qq_get8(&unknown1, data + bytes); purple_debug(PURPLE_DEBUG_INFO, "QQ", "type=%u creatorid=%u category=%u maxmembers=%u\n", - group->group_type, group->creator_uid, group->group_category, max_members); + group->type8, group->creator_uid, group->group_category, max_members); /* strlen + <str content> */ bytes += convert_as_pascal_string(data + bytes, &(group->group_name_utf8), QQ_CHARSET_DEFAULT); @@ -223,23 +197,25 @@ num = 0; /* now comes the member list separated by 0x00 */ - while (bytes < len) { + while (bytes < data_len) { bytes += qq_get32(&member_uid, data + bytes); num++; bytes += qq_get8(&organization, data + bytes); bytes += qq_get8(&role, data + bytes); - /* +#if 0 if(organization != 0 || role != 0) { purple_debug(PURPLE_DEBUG_INFO, "QQ_GRP", "%d, organization=%d, role=%d\n", member_uid, organization, role); } - */ +#endif + member = qq_group_find_or_add_member(gc, group, member_uid); if (member != NULL) member->role = role; } - if(bytes > len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "group_cmd_get_group_info: Dangerous error! maybe protocol changed, notify me!"); + if(bytes > data_len) { + purple_debug(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); @@ -265,9 +241,9 @@ purple_conv_chat_set_topic(PURPLE_CONV_CHAT(purple_conv), NULL, group->notice_utf8); } -void qq_process_group_cmd_get_online_members(guint8 *data, gint len, PurpleConnection *gc) +void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc) { - guint32 internal_group_id, member_uid; + guint32 id, member_uid; guint8 unknown; gint bytes, num; qq_group *group; @@ -281,14 +257,14 @@ } bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); + bytes += qq_get32(&id, data + bytes); bytes += qq_get8(&unknown, data + bytes); /* 0x3c ?? */ - g_return_if_fail(internal_group_id > 0); + g_return_if_fail(id > 0); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + 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", internal_group_id); + "We have no group info for internal id [%d]\n", id); return; } @@ -311,11 +287,11 @@ } /* process the reply to get_members_info packet */ -void qq_process_group_cmd_get_members_info(guint8 *data, gint len, PurpleConnection *gc) +void qq_process_room_cmd_get_members(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; gint num; - guint32 internal_group_id, member_uid; + guint32 id, member_uid; guint16 unknown; qq_group *group; qq_buddy *member; @@ -323,11 +299,15 @@ g_return_if_fail(data != NULL && len > 0); +#if 0 + qq_show_packet("qq_process_room_cmd_get_members", data, len); +#endif + bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); - g_return_if_fail(internal_group_id > 0); + bytes += qq_get32(&id, data + bytes); + g_return_if_fail(id > 0); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); num = 0; @@ -352,19 +332,18 @@ member->nickname = g_strdup(nick); g_free(nick); - /* - if (QQ_DEBUG) { - purple_debug(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); - } - */ +#if 0 + purple_debug(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); } - if(bytes > len) { + if (bytes > len) { purple_debug(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); } +
--- a/libpurple/protocols/qq/group_info.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_info.h Sun Aug 10 04:32:14 2008 +0000 @@ -29,14 +29,12 @@ #include "connection.h" #include "group.h" -void qq_send_cmd_group_get_group_info(PurpleConnection *gc, qq_group *group); 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); -void qq_process_group_cmd_get_group_info(guint8 *data, gint len, PurpleConnection *gc); -void qq_process_group_cmd_get_online_members(guint8 *data, gint len, PurpleConnection *gc); -void qq_process_group_cmd_get_members_info(guint8 *data, gint len, PurpleConnection *gc); - +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); #endif
--- a/libpurple/protocols/qq/group_internal.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_internal.c Sun Aug 10 04:32:14 2008 +0000 @@ -68,12 +68,12 @@ purple_debug(PURPLE_DEBUG_INFO, "QQ", "You have added group \"%s\" to blist locally\n", group->group_name_utf8); } -/* Create a dummy qq_group, which includes only internal_id, external_id, +/* 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 * 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 external_id, gchar *group_name_utf8) + guint32 internal_id, guint32 ext_id, gchar *group_name_utf8) { qq_group *group; qq_data *qd; @@ -84,9 +84,9 @@ 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->internal_group_id = internal_id; - group->external_group_id = external_id; - group->group_type = 0x01; /* assume permanent Qun */ + 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->auth_type = 0x02; /* assume need auth */ @@ -101,7 +101,7 @@ return group; } -void qq_group_delete_internal_record(qq_data *qd, guint32 internal_group_id) +void qq_group_delete_internal_record(qq_data *qd, guint32 id) { qq_group *group; GList *list; @@ -109,7 +109,7 @@ list = qd->groups; while (list != NULL) { group = (qq_group *) qd->groups->data; - if (internal_group_id == group->internal_group_id) { + if (id == group->id) { qd->groups = g_list_remove(qd->groups, group); qq_group_free(group); break; @@ -128,10 +128,10 @@ group->my_status_desc = _qq_group_set_my_status_desc(group); g_hash_table_insert(components, - g_strdup(QQ_GROUP_KEY_INTERNAL_ID), g_strdup_printf("%d", group->internal_group_id)); + 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_printf("%d", group->external_group_id)); - g_hash_table_insert(components, g_strdup(QQ_GROUP_KEY_GROUP_TYPE), g_strdup_printf("%d", group->group_type)); + 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_GROUP_KEY_GROUP_CATEGORY), g_strdup_printf("%d", group->group_category)); @@ -157,12 +157,11 @@ (NULL == g_hash_table_lookup(data, QQ_GROUP_KEY_MEMBER_STATUS) ? - g_strdup_printf("%d", - QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) : + g_strdup_printf("%d", QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) : g_hash_table_lookup(data, QQ_GROUP_KEY_MEMBER_STATUS)); - group->internal_group_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID)); - group->external_group_id = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID)); - group->group_type = qq_string_to_dec_value(g_hash_table_lookup(data, QQ_GROUP_KEY_GROUP_TYPE)); + 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)); @@ -179,12 +178,12 @@ void qq_group_refresh(PurpleConnection *gc, qq_group *group) { PurpleChat *chat; - gchar *external_group_id; + gchar *ext_id; g_return_if_fail(group != NULL); - external_group_id = g_strdup_printf("%d", group->external_group_id); - chat = purple_blist_find_chat(purple_connection_get_account(gc), external_group_id); - g_free(external_group_id); + 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 */ @@ -198,12 +197,12 @@ 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->internal_group_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->external_group_id)); + g_strdup_printf("%d", group->ext_id)); g_hash_table_replace(chat->components, - g_strdup(QQ_GROUP_KEY_GROUP_TYPE), g_strdup_printf("%d", group->group_type)); + 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,
--- a/libpurple/protocols/qq/group_internal.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_internal.h Sun Aug 10 04:32:14 2008 +0000 @@ -28,20 +28,20 @@ #include <glib.h> #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 "internal_group_id" -#define QQ_GROUP_KEY_EXTERNAL_ID "external_group_id" -#define QQ_GROUP_KEY_GROUP_TYPE "group_type" -#define QQ_GROUP_KEY_CREATOR_UID "creator_uid" -#define QQ_GROUP_KEY_GROUP_CATEGORY "group_category" -#define QQ_GROUP_KEY_AUTH_TYPE "auth_type" -#define QQ_GROUP_KEY_GROUP_NAME_UTF8 "group_name_utf8" -#define QQ_GROUP_KEY_GROUP_DESC_UTF8 "group_desc_utf8" +#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" qq_group *qq_group_create_internal_record(PurpleConnection *gc, - guint32 internal_id, guint32 external_id, gchar *group_name_utf8); -void qq_group_delete_internal_record(qq_data *qd, guint32 internal_group_id); + guint32 internal_id, guint32 ext_id, gchar *group_name_utf8); +void qq_group_delete_internal_record(qq_data *qd, guint32 id); GHashTable *qq_group_to_hashtable(qq_group *group); qq_group *qq_group_from_hashtable(PurpleConnection *gc, GHashTable *data);
--- a/libpurple/protocols/qq/group_join.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_join.c Sun Aug 10 04:32:14 2008 +0000 @@ -38,8 +38,10 @@ #include "group_info.h" #include "group_join.h" #include "group_opt.h" -#include "group_network.h" #include "group_search.h" +#include "header_info.h" +#include "packet_parse.h" +#include "qq_network.h" enum { QQ_GROUP_JOIN_OK = 0x01, @@ -49,24 +51,21 @@ static void _qq_group_exit_with_gc_and_id(gc_and_uid *g) { PurpleConnection *gc; - guint32 internal_group_id; + guint32 id; qq_group *group; gc = g->gc; - internal_group_id = g->uid; + id = g->uid; - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); - qq_send_cmd_group_exit_group(gc, group); + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_QUIT, group->id); } /* send packet to join a group without auth */ void qq_send_cmd_group_join_group(PurpleConnection *gc, qq_group *group) { - guint8 raw_data[16] = {0}; - gint bytes = 0; - g_return_if_fail(group != NULL); if (group->my_status == QQ_GROUP_MEMBER_STATUS_NOT_MEMBER) { @@ -86,25 +85,21 @@ break; } - bytes = 0; - bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_JOIN_GROUP); - bytes += qq_put32(raw_data + bytes, group->internal_group_id); - - qq_send_group_cmd(gc, group, raw_data, bytes); + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_JOIN, group->id); } static void _qq_group_join_auth_with_gc_and_id(gc_and_uid *g, const gchar *reason_utf8) { PurpleConnection *gc; qq_group *group; - guint32 internal_group_id; + guint32 id; gc = g->gc; - internal_group_id = g->uid; + id = g->uid; - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + 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", internal_group_id); + purple_debug(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); @@ -118,12 +113,12 @@ g_return_if_fail(group != NULL); purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Group (internal id: %d) needs authentication\n", group->internal_group_id); + "Group (internal id: %d) needs authentication\n", group->id); msg = g_strdup_printf("Group \"%s\" needs authentication\n", group->group_name_utf8); g = g_new0(gc_and_uid, 1); g->gc = gc; - g->uid = group->internal_group_id; + g->uid = group->id; purple_request_input(gc, NULL, msg, _("Input request here"), _("Would you be my friend?"), TRUE, FALSE, NULL, @@ -139,7 +134,7 @@ { guint8 *raw_data; gchar *reason_qq; - gint bytes, data_len; + gint bytes; g_return_if_fail(group != NULL); @@ -154,45 +149,22 @@ uid = 0; } - data_len = 10 + strlen(reason_qq) + 1; - raw_data = g_newa(guint8, data_len); + raw_data = g_newa(guint8, 6 + strlen(reason_qq)); bytes = 0; - bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_JOIN_GROUP_AUTH); - bytes += qq_put32(raw_data + bytes, group->internal_group_id); bytes += qq_put8(raw_data + bytes, opt); bytes += qq_put32(raw_data + bytes, uid); bytes += qq_put8(raw_data + bytes, strlen(reason_qq)); bytes += qq_putdata(raw_data + bytes, (guint8 *) reason_qq, strlen(reason_qq)); - if (bytes != data_len) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create packet for %s\n", qq_group_cmd_get_desc(QQ_GROUP_CMD_JOIN_GROUP_AUTH)); - return; - } - - qq_send_group_cmd(gc, group, raw_data, data_len); -} - -/* send a packet to exit a group */ -void qq_send_cmd_group_exit_group(PurpleConnection *gc, qq_group *group) -{ - guint8 raw_data[16] = {0}; - gint bytes = 0; - - g_return_if_fail(group != NULL); - - bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_EXIT_GROUP); - bytes += qq_put32(raw_data + bytes, group->internal_group_id); - - qq_send_group_cmd(gc, group, raw_data, bytes); + qq_send_room_cmd(gc, QQ_ROOM_CMD_AUTH, group->id, raw_data, bytes); } /* If comes here, cmd is OK already */ void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; - guint32 internal_group_id; + guint32 id; PurpleChat *chat; qq_group *group; qq_data *qd; @@ -207,15 +179,15 @@ } bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); + bytes += qq_get32(&id, data + bytes); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); if (group != NULL) { chat = purple_blist_find_chat - (purple_connection_get_account(gc), g_strdup_printf("%d", group->external_group_id)); + (purple_connection_get_account(gc), g_strdup_printf("%d", group->ext_id)); if (chat != NULL) purple_blist_remove_chat(chat); - qq_group_delete_internal_record(qd, internal_group_id); + qq_group_delete_internal_record(qd, id); } purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully left the group"), NULL); } @@ -224,7 +196,7 @@ void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; - guint32 internal_group_id; + guint32 id; qq_data *qd; g_return_if_fail(data != NULL && len > 0); @@ -236,8 +208,8 @@ return; } bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); - g_return_if_fail(internal_group_id > 0); + bytes += qq_get32(&id, data + bytes); + g_return_if_fail(id > 0); purple_notify_info(gc, _("QQ Group Auth"), _("Your authorization request has been accepted by the QQ server"), NULL); @@ -247,7 +219,7 @@ void qq_process_group_cmd_join_group(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; - guint32 internal_group_id; + guint32 id; guint8 reply; qq_group *group; @@ -260,11 +232,11 @@ } bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); + bytes += qq_get32(&id, data + bytes); bytes += qq_get8(&reply, data + bytes); /* join group OK */ - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); /* need to check if group is NULL or not. */ g_return_if_fail(group != NULL); switch (reply) { @@ -274,12 +246,12 @@ qq_group_refresh(gc, group); /* this must be shown before getting online members */ qq_group_conv_show_window(gc, group); - qq_send_cmd_group_get_group_info(gc, group); + qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_INFO, group->id); break; case QQ_GROUP_JOIN_NEED_AUTH: purple_debug(PURPLE_DEBUG_INFO, "QQ", "Fail joining group [%d] %s, needs authentication\n", - group->external_group_id, group->group_name_utf8); + group->ext_id, group->group_name_utf8); group->my_status = QQ_GROUP_MEMBER_STATUS_NOT_MEMBER; qq_group_refresh(gc, group); _qq_group_join_auth(gc, group); @@ -287,7 +259,7 @@ default: purple_debug(PURPLE_DEBUG_INFO, "QQ", "Error joining group [%d] %s, unknown reply: 0x%02x\n", - group->external_group_id, group->group_name_utf8, reply); + group->ext_id, group->group_name_utf8, reply); } } @@ -295,48 +267,48 @@ void qq_group_join(PurpleConnection *gc, GHashTable *data) { qq_data *qd; - gchar *external_group_id_ptr; - guint32 external_group_id; + gchar *ext_id_ptr; + guint32 ext_id; qq_group *group; g_return_if_fail(data != NULL); qd = (qq_data *) gc->proto_data; - external_group_id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID); - g_return_if_fail(external_group_id_ptr != NULL); + ext_id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_EXTERNAL_ID); + g_return_if_fail(ext_id_ptr != NULL); errno = 0; - external_group_id = strtol(external_group_id_ptr, NULL, 10); + ext_id = strtol(ext_id_ptr, NULL, 10); if (errno != 0) { purple_notify_error(gc, _("Error"), _("You entered a group ID outside the acceptable range"), NULL); return; } - group = qq_group_find_by_id(gc, external_group_id, QQ_EXTERNAL_ID); + group = qq_room_search_ext_id(gc, ext_id); if (group) { qq_send_cmd_group_join_group(gc, group); } else { - qq_set_pending_id(&qd->joining_groups, external_group_id, TRUE); - qq_send_cmd_group_search_group(gc, external_group_id); + qq_set_pending_id(&qd->joining_groups, ext_id, TRUE); + qq_send_cmd_group_search_group(gc, ext_id); } } void qq_group_exit(PurpleConnection *gc, GHashTable *data) { - gchar *internal_group_id_ptr; - guint32 internal_group_id; + gchar *id_ptr; + guint32 id; gc_and_uid *g; g_return_if_fail(data != NULL); - internal_group_id_ptr = g_hash_table_lookup(data, "internal_group_id"); - internal_group_id = strtol(internal_group_id_ptr, NULL, 10); + id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID); + id = strtol(id_ptr, NULL, 10); - g_return_if_fail(internal_group_id > 0); + g_return_if_fail(id > 0); g = g_new0(gc_and_uid, 1); g->gc = gc; - g->uid = internal_group_id; + g->uid = id; purple_request_action(gc, _("QQ Qun Operation"), _("Are you sure you want to leave this Qun?"),
--- a/libpurple/protocols/qq/group_join.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_join.h Sun Aug 10 04:32:14 2008 +0000 @@ -45,7 +45,6 @@ void qq_group_join(PurpleConnection *gc, GHashTable *data); void qq_send_cmd_group_join_group(PurpleConnection *gc, qq_group *group); void qq_group_exit(PurpleConnection *gc, GHashTable *data); -void qq_send_cmd_group_exit_group(PurpleConnection *gc, qq_group *group); void qq_process_group_cmd_exit_group(guint8 *data, gint len, PurpleConnection *gc); void qq_process_group_cmd_join_group_auth(guint8 *data, gint len, PurpleConnection *gc); void qq_process_group_cmd_join_group(guint8 *data, gint len, PurpleConnection *gc);
--- a/libpurple/protocols/qq/group_network.c Sat Aug 09 23:23:48 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -/** - * @file group_network.c - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" - -#include "debug.h" -#include "notify.h" - -#include "char_conv.h" -#include "crypt.h" -#include "group_conv.h" -#include "group_find.h" -#include "group_internal.h" -#include "group_im.h" -#include "group_info.h" -#include "group_join.h" -#include "group_network.h" -#include "group_opt.h" -#include "group_search.h" -#include "header_info.h" -#include "qq_network.h" -#include "utils.h" - -enum { - QQ_GROUP_CMD_REPLY_OK = 0x00, - QQ_GROUP_CMD_REPLY_SEARCH_ERROR = 0x02, - QQ_GROUP_CMD_REPLY_NOT_MEMBER = 0x0a -}; - -const gchar *qq_group_cmd_get_desc(qq_group_cmd cmd) -{ - switch (cmd) { - case QQ_GROUP_CMD_CREATE_GROUP: - return "QQ_GROUP_CMD_CREATE_GROUP"; - case QQ_GROUP_CMD_MEMBER_OPT: - return "QQ_GROUP_CMD_MEMBER_OPT"; - case QQ_GROUP_CMD_MODIFY_GROUP_INFO: - return "QQ_GROUP_CMD_MODIFY_GROUP_INFO"; - case QQ_GROUP_CMD_GET_GROUP_INFO: - return "QQ_GROUP_CMD_GET_GROUP_INFO"; - case QQ_GROUP_CMD_ACTIVATE_GROUP: - return "QQ_GROUP_CMD_ACTIVATE_GROUP"; - case QQ_GROUP_CMD_SEARCH_GROUP: - return "QQ_GROUP_CMD_SEARCH_GROUP"; - case QQ_GROUP_CMD_JOIN_GROUP: - return "QQ_GROUP_CMD_JOIN_GROUP"; - case QQ_GROUP_CMD_JOIN_GROUP_AUTH: - return "QQ_GROUP_CMD_JOIN_GROUP_AUTH"; - case QQ_GROUP_CMD_EXIT_GROUP: - return "QQ_GROUP_CMD_EXIT_GROUP"; - case QQ_GROUP_CMD_SEND_MSG: - return "QQ_GROUP_CMD_SEND_MSG"; - case QQ_GROUP_CMD_GET_ONLINE_MEMBER: - return "QQ_GROUP_CMD_GET_ONLINE_MEMBER"; - case QQ_GROUP_CMD_GET_MEMBER_INFO: - return "QQ_GROUP_CMD_GET_MEMBER_INFO"; - case QQ_GROUP_CMD_MODIFY_CARD: - return "QQ_GROUP_CMD_MODIFY_CARD"; - case QQ_GROUP_CMD_REQUEST_ALL_REALNAMES: - return "QQ_GROUP_CMD_REQUEST_ALL_REALNAMES"; - case QQ_GROUP_CMD_REQUEST_CARD: - return "QQ_GROUP_CMD_REQUEST_CARD"; - case QQ_GROUP_CMD_SEND_IM_EX: - return "QQ_GROUP_CMD_SEND_IM_EX"; - case QQ_GROUP_CMD_ADMIN: - return "QQ_GROUP_CMD_ADMIN"; - case QQ_GROUP_CMD_TRANSFER: - return "QQ_GROUP_CMD_TRANSFER"; - case QQ_GROUP_CMD_CREATE_TEMP_QUN: - return "QQ_GROUP_CMD_CREATE_TEMP_QUN"; - case QQ_GROUP_CMD_MODIFY_TEMP_QUN_MEMBER: - return "QQ_GROUP_CMD_MODIFY_TEMP_QUN_MEMBER"; - case QQ_GROUP_CMD_EXIT_TEMP_QUN: - return "QQ_GROUP_CMD_EXIT_TEMP_QUN"; - case QQ_GROUP_CMD_GET_TEMP_QUN_INFO: - return "QQ_GROUP_CMD_GET_TEMP_QUN_INFO"; - case QQ_GROUP_CMD_SEND_TEMP_QUN_IM: - return "QQ_GROUP_CMD_SEND_TEMP_QUN_IM"; - case QQ_GROUP_CMD_GET_TEMP_QUN_MEMBERS: - return "QQ_GROUP_CMD_GET_TEMP_QUN_MEMBERS"; - default: - return "Unknown QQ Group Command"; - } -} - -/* default process of reply error */ -static void _qq_process_group_cmd_reply_error_default(guint8 reply, guint8 *data, gint len, PurpleConnection *gc) -{ - gchar *msg, *msg_utf8; - g_return_if_fail(data != NULL && len > 0); - - msg = g_strndup((gchar *) data, len); /* it will append 0x00 */ - msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); - g_free(msg); - msg = g_strdup_printf(_("Code [0x%02X]: %s"), reply, msg_utf8); - purple_notify_error(gc, NULL, _("Group Operation Error"), msg); - g_free(msg); - g_free(msg_utf8); -} - -/* default process, dump only */ -static void _qq_process_group_cmd_reply_default(guint8 *data, gint len, PurpleConnection *gc) -{ - g_return_if_fail(data != NULL && len > 0); - - qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", - data, len, - "Dump unprocessed group cmd reply:"); -} - -/* The lower layer command of send group cmd */ -void qq_send_group_cmd(PurpleConnection *gc, qq_group *group, guint8 *raw_data, gint data_len) -{ - qq_data *qd; - group_packet *p; - - g_return_if_fail(raw_data != NULL && data_len > 0); - - qd = (qq_data *) gc->proto_data; - - qq_send_cmd(qd, QQ_CMD_GROUP_CMD, raw_data, data_len); - - p = g_new0(group_packet, 1); - - p->send_seq = qd->send_seq; - if (group == NULL) - p->internal_group_id = 0; - else - p->internal_group_id = group->internal_group_id; - - qd->group_packets = g_list_append(qd->group_packets, p); -} - -/* the main entry of group cmd processing, called by qq_recv_core.c */ -void qq_process_group_cmd_reply(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc) -{ - qq_group *group; - qq_data *qd; - gint len, bytes; - guint32 internal_group_id; - guint8 *data, sub_cmd, reply; - - g_return_if_fail(buf != NULL && buf_len != 0); - - qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - - if (!qq_group_find_internal_group_id_by_seq(gc, seq, &internal_group_id)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", "We have no record of group cmd, seq [%d]\n", seq); - return; - } - - if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt group cmd reply\n"); - return; - } - - if (len <= 2) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Group cmd reply is too short, only %d bytes\n", len); - return; - } - - bytes = 0; - bytes += qq_get8(&sub_cmd, data + bytes); - bytes += qq_get8(&reply, data + bytes); - - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); - - if (reply != QQ_GROUP_CMD_REPLY_OK) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Group cmd reply says cmd %s fails\n", qq_group_cmd_get_desc(sub_cmd)); - - if (group != NULL) - qq_set_pending_id(&qd->joining_groups, group->external_group_id, FALSE); - - switch (reply) { /* this should be all errors */ - case QQ_GROUP_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; - qq_group_refresh(gc, group); - } - break; - case QQ_GROUP_CMD_REPLY_SEARCH_ERROR: - if (qd->roomlist != NULL) { - if (purple_roomlist_get_in_progress(qd->roomlist)) - purple_roomlist_set_in_progress(qd->roomlist, FALSE); - } - _qq_process_group_cmd_reply_error_default(reply, data + bytes, len - bytes, gc); - break; - default: - _qq_process_group_cmd_reply_error_default(reply, data + bytes, len - bytes, gc); - } - return; - } - - /* seems ok so far, so we process the reply according to sub_cmd */ - switch (sub_cmd) { - case QQ_GROUP_CMD_GET_GROUP_INFO: - qq_process_group_cmd_get_group_info(data + bytes, 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_GROUP_CMD_CREATE_GROUP: - qq_group_process_create_group_reply(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_MODIFY_GROUP_INFO: - qq_group_process_modify_info_reply(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_MEMBER_OPT: - qq_group_process_modify_members_reply(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_ACTIVATE_GROUP: - qq_group_process_activate_group_reply(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_SEARCH_GROUP: - qq_process_group_cmd_search_group(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_JOIN_GROUP: - qq_process_group_cmd_join_group(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_JOIN_GROUP_AUTH: - qq_process_group_cmd_join_group_auth(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_EXIT_GROUP: - qq_process_group_cmd_exit_group(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_SEND_MSG: - qq_process_group_cmd_im(data + bytes, len - bytes, gc); - break; - case QQ_GROUP_CMD_GET_ONLINE_MEMBER: - qq_process_group_cmd_get_online_members(data + bytes, len - bytes, gc); - if (group != NULL) - qq_group_conv_refresh_online_member(gc, group); - break; - case QQ_GROUP_CMD_GET_MEMBER_INFO: - qq_process_group_cmd_get_members_info(data + bytes, len - bytes, gc); - if (group != NULL) - qq_group_conv_refresh_online_member(gc, group); - break; - default: - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Group cmd %s is processed by default\n", qq_group_cmd_get_desc(sub_cmd)); - _qq_process_group_cmd_reply_default(data + bytes, len, gc); - } -}
--- a/libpurple/protocols/qq/group_network.h Sat Aug 09 23:23:48 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/** - * @file group_network.h - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef _QQ_GROUP_NETWORK_H_ -#define _QQ_GROUP_NETWORK_H_ - -#include <glib.h> -#include "connection.h" -#include "group.h" -#include "packet_parse.h" - -typedef enum { - QQ_GROUP_CMD_CREATE_GROUP = 0x01, - QQ_GROUP_CMD_MEMBER_OPT = 0x02, - QQ_GROUP_CMD_MODIFY_GROUP_INFO = 0x03, - QQ_GROUP_CMD_GET_GROUP_INFO = 0x04, - QQ_GROUP_CMD_ACTIVATE_GROUP = 0x05, - QQ_GROUP_CMD_SEARCH_GROUP = 0x06, - QQ_GROUP_CMD_JOIN_GROUP = 0x07, - QQ_GROUP_CMD_JOIN_GROUP_AUTH = 0x08, - QQ_GROUP_CMD_EXIT_GROUP = 0x09, - QQ_GROUP_CMD_SEND_MSG = 0x0a, - QQ_GROUP_CMD_GET_ONLINE_MEMBER = 0x0b, - QQ_GROUP_CMD_GET_MEMBER_INFO = 0x0c, - - QQ_GROUP_CMD_MODIFY_CARD = 0x0E, - QQ_GROUP_CMD_REQUEST_ALL_REALNAMES = 0x0F, - QQ_GROUP_CMD_REQUEST_CARD = 0x10, - QQ_GROUP_CMD_SEND_IM_EX = 0x1A, - QQ_GROUP_CMD_ADMIN = 0x1B, - QQ_GROUP_CMD_TRANSFER = 0x1C, - QQ_GROUP_CMD_CREATE_TEMP_QUN = 0x30, - QQ_GROUP_CMD_MODIFY_TEMP_QUN_MEMBER = 0x31, - QQ_GROUP_CMD_EXIT_TEMP_QUN = 0x32, - QQ_GROUP_CMD_GET_TEMP_QUN_INFO = 0x33, - QQ_GROUP_CMD_SEND_TEMP_QUN_IM = 0x35, - QQ_GROUP_CMD_GET_TEMP_QUN_MEMBERS = 0x37, -} qq_group_cmd; - -typedef struct _group_packet { - guint16 send_seq; - guint32 internal_group_id; -} group_packet; - -const gchar *qq_group_cmd_get_desc(qq_group_cmd cmd); - -void qq_send_group_cmd(PurpleConnection *gc, qq_group *group, guint8 *raw_data, gint data_len); -void qq_process_group_cmd_reply(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc); - -#endif
--- a/libpurple/protocols/qq/group_opt.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.c Sun Aug 10 04:32:14 2008 +0000 @@ -34,9 +34,10 @@ #include "group_internal.h" #include "group_info.h" #include "group_join.h" -#include "group_network.h" #include "group_opt.h" +#include "header_info.h" #include "packet_parse.h" +#include "qq_network.h" #include "utils.h" static int _compare_guint32(const void *a, @@ -68,13 +69,11 @@ data = g_newa(guint8, data_len); bytes = 0; - bytes += qq_put8(data + bytes, QQ_GROUP_CMD_MEMBER_OPT); - bytes += qq_put32(data + bytes, group->internal_group_id); bytes += qq_put8(data + bytes, operation); for (i = 0; i < count; i++) bytes += qq_put32(data + bytes, members[i]); - qq_send_group_cmd(gc, group, data, bytes); + qq_send_room_cmd(gc, QQ_ROOM_CMD_MEMBER_OPT, group->id, data, bytes); } static void _qq_group_do_nothing_with_struct(group_member_opt *g) @@ -86,8 +85,8 @@ static void _qq_group_reject_application_real(group_member_opt *g, gchar *msg_utf8) { qq_group *group; - g_return_if_fail(g != NULL && g->gc != NULL && g->internal_group_id > 0 && g->member > 0); - group = qq_group_find_by_id(g->gc, g->internal_group_id, QQ_INTERNAL_ID); + 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); g_free(g); @@ -131,8 +130,8 @@ void qq_group_approve_application_with_struct(group_member_opt *g) { qq_group *group; - g_return_if_fail(g != NULL && g->gc != NULL && g->internal_group_id > 0 && g->member > 0); - group = qq_group_find_by_id(g->gc, g->internal_group_id, QQ_INTERNAL_ID); + 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_group_find_or_add_member(g->gc, group, g->member); @@ -198,24 +197,24 @@ void qq_group_process_modify_members_reply(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; - guint32 internal_group_id; + guint32 id; qq_group *group; g_return_if_fail(data != NULL); bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); - g_return_if_fail(internal_group_id > 0); + bytes += qq_get32(&id, data + bytes); + g_return_if_fail(id > 0); /* we should have its info locally */ - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + 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->external_group_id); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in modify members for Qun %d\n", group->ext_id); purple_notify_info(gc, _("QQ Qun Operation"), _("You have successfully modified Qun member"), NULL); } -void qq_group_modify_info(PurpleConnection *gc, qq_group *group) +void qq_room_change_info(PurpleConnection *gc, qq_group *group) { guint8 *data; gint data_len; @@ -228,16 +227,9 @@ group_desc = group->group_desc_utf8 == NULL ? "" : utf8_to_qq(group->group_desc_utf8, QQ_CHARSET_DEFAULT); notice = group->notice_utf8 == NULL ? "" : utf8_to_qq(group->notice_utf8, QQ_CHARSET_DEFAULT); - data_len = 13 + 1 + strlen(group_name) - + 1 + strlen(group_desc) - + 1 + strlen(notice); - + data_len = 64 + strlen(group_name) + strlen(group_desc) + strlen(notice); data = g_newa(guint8, data_len); bytes = 0; - /* 000-000 */ - bytes += qq_put8(data + bytes, QQ_GROUP_CMD_MODIFY_GROUP_INFO); - /* 001-004 */ - bytes += qq_put32(data + bytes, group->internal_group_id); /* 005-005 */ bytes += qq_put8(data + bytes, 0x01); /* 006-006 */ @@ -258,54 +250,52 @@ bytes += qq_put8(data + bytes, strlen(group_desc)); bytes += qq_putdata(data + bytes, (guint8 *) group_desc, strlen(group_desc)); - if (bytes != data_len) { + if (bytes > data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail to create group_modify_info packet, expect %d bytes, wrote %d bytes\n", + "Overflow in qq_room_change_info, max %d bytes, now %d bytes\n", data_len, bytes); return; } - - qq_send_group_cmd(gc, group, data, bytes); + qq_send_room_cmd(gc, QQ_ROOM_CMD_CHANGE_INFO, group->id, data, bytes); } void qq_group_process_modify_info_reply(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; - guint32 internal_group_id; + guint32 id; qq_group *group; g_return_if_fail(data != NULL); bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); - g_return_if_fail(internal_group_id > 0); + bytes += qq_get32(&id, data + bytes); + g_return_if_fail(id > 0); /* we should have its info locally */ - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + 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->external_group_id); + purple_debug(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); } /* we create a very simple group first, and then let the user to modify */ -void qq_group_create_with_name(PurpleConnection *gc, const gchar *name) +void qq_room_create_new(PurpleConnection *gc, const gchar *name) { + guint8 *data; gint data_len; - guint8 *data; gint bytes; qq_data *qd; g_return_if_fail(name != NULL); qd = (qq_data *) gc->proto_data; - data_len = 7 + 1 + strlen(name) + 2 + 1 + 1 + 4; + + data_len = 64 + strlen(name); data = g_newa(guint8, data_len); bytes = 0; /* we create the simpleset group, only group name is given */ - /* 000 */ - bytes += qq_put8(data + bytes, QQ_GROUP_CMD_CREATE_GROUP); /* 001 */ bytes += qq_put8(data + bytes, QQ_GROUP_TYPE_PERMANENT); /* 002 */ @@ -322,14 +312,13 @@ bytes += qq_put8(data + bytes, 0x00); /* no group desc */ bytes += qq_put32(data + bytes, qd->uid); /* I am member of coz */ - if (bytes != data_len) { + if (bytes > data_len) { purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "Fail create create_group packet, expect %d bytes, written %d bytes\n", + "Overflow in qq_room_create, max %d bytes, now %d bytes\n", data_len, bytes); return; } - - qq_send_group_cmd(gc, NULL, data, bytes); + qq_send_room_cmd_noid(gc, QQ_ROOM_CMD_CREATE, data, bytes); } static void qq_group_setup_with_gc_and_uid(gc_and_uid *g) @@ -337,7 +326,7 @@ qq_group *group; g_return_if_fail(g != NULL && g->gc != NULL && g->uid > 0); - group = qq_group_find_by_id(g->gc, g->uid, QQ_INTERNAL_ID); + group = qq_room_search_id(g->gc, g->uid); g_return_if_fail(group != NULL); /* TODO insert UI code here */ @@ -348,7 +337,7 @@ void qq_group_process_create_group_reply(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; - guint32 internal_group_id, external_group_id; + guint32 id, ext_id; qq_group *group; gc_and_uid *g; qq_data *qd; @@ -358,23 +347,23 @@ qd = (qq_data *) gc->proto_data; bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); - bytes += qq_get32(&external_group_id, data + bytes); - g_return_if_fail(internal_group_id > 0 && external_group_id); + bytes += qq_get32(&id, data + bytes); + bytes += qq_get32(&ext_id, data + bytes); + g_return_if_fail(id > 0 && ext_id); - group = qq_group_create_internal_record(gc, internal_group_id, external_group_id, NULL); + group = qq_group_create_internal_record(gc, id, ext_id, NULL); group->my_status = QQ_GROUP_MEMBER_STATUS_IS_ADMIN; group->creator_uid = qd->uid; qq_group_refresh(gc, group); - qq_group_activate_group(gc, internal_group_id); - qq_send_cmd_group_get_group_info(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); - purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in create Qun, external ID %d\n", group->external_group_id); + purple_debug(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; - g->uid = internal_group_id; + g->uid = id; purple_request_action(gc, _("QQ Qun Operation"), _("You have successfully created a Qun"), @@ -387,54 +376,37 @@ _("Cancel"), G_CALLBACK(qq_do_nothing_with_gc_and_uid)); } -/* we have to activate group after creation, otherwise the group can not be searched */ -void qq_group_activate_group(PurpleConnection *gc, guint32 internal_group_id) -{ - guint8 data[16] = {0}; - gint bytes = 0; - g_return_if_fail(internal_group_id > 0); - - bytes = 0; - /* we create the simplest group, only group name is given */ - /* 000 */ - bytes += qq_put8(data + bytes, QQ_GROUP_CMD_ACTIVATE_GROUP); - /* 001-005 */ - bytes += qq_put32(data + bytes, internal_group_id); - - qq_send_group_cmd(gc, NULL, data, bytes); -} - void qq_group_process_activate_group_reply(guint8 *data, gint len, PurpleConnection *gc) { gint bytes; - guint32 internal_group_id; + guint32 id; qq_group *group; g_return_if_fail(data != NULL); bytes = 0; - bytes += qq_get32(&internal_group_id, data + bytes); - g_return_if_fail(internal_group_id > 0); + bytes += qq_get32(&id, data + bytes); + g_return_if_fail(id > 0); /* we should have its info locally */ - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + 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->external_group_id); + purple_debug(PURPLE_DEBUG_INFO, "QQ", "Succeed in activate Qun %d\n", group->ext_id); } void qq_group_manage_group(PurpleConnection *gc, GHashTable *data) { - gchar *internal_group_id_ptr; - guint32 internal_group_id; + gchar *id_ptr; + guint32 id; qq_group *group; g_return_if_fail(data != NULL); - internal_group_id_ptr = g_hash_table_lookup(data, "internal_group_id"); - internal_group_id = strtol(internal_group_id_ptr, NULL, 10); - g_return_if_fail(internal_group_id > 0); + id_ptr = g_hash_table_lookup(data, QQ_GROUP_KEY_INTERNAL_ID); + id = strtol(id_ptr, NULL, 10); + g_return_if_fail(id > 0); - group = qq_group_find_by_id(gc, internal_group_id, QQ_INTERNAL_ID); + group = qq_room_search_id(gc, id); g_return_if_fail(group != NULL); /* XXX insert UI code here */
--- a/libpurple/protocols/qq/group_opt.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.h Sun Aug 10 04:32:14 2008 +0000 @@ -33,7 +33,7 @@ typedef struct _group_member_opt { PurpleConnection *gc; - guint32 internal_group_id; + guint32 id; guint32 member; } group_member_opt; @@ -48,7 +48,7 @@ }; void qq_group_modify_members(PurpleConnection *gc, qq_group *group, guint32 *new_members); -void qq_group_modify_info(PurpleConnection *gc, qq_group *group); +void qq_room_change_info(PurpleConnection *gc, qq_group *group); void qq_group_approve_application_with_struct(group_member_opt *g); void qq_group_reject_application_with_struct(group_member_opt *g); @@ -57,8 +57,7 @@ void qq_group_process_modify_info_reply(guint8 *data, gint len, PurpleConnection *gc); void qq_group_process_modify_members_reply(guint8 *data, gint len, PurpleConnection *gc); void qq_group_manage_group(PurpleConnection *gc, GHashTable *data); -void qq_group_create_with_name(PurpleConnection *gc, const gchar *name); -void qq_group_activate_group(PurpleConnection *gc, guint32 internal_group_id); +void qq_room_create_new(PurpleConnection *gc, const gchar *name); void qq_group_process_activate_group_reply(guint8 *data, gint len, PurpleConnection *gc); void qq_group_process_create_group_reply(guint8 *data, gint len, PurpleConnection *gc);
--- a/libpurple/protocols/qq/group_search.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/group_search.c Sun Aug 10 04:32:14 2008 +0000 @@ -31,9 +31,11 @@ #include "group_free.h" #include "group_internal.h" #include "group_join.h" -#include "group_network.h" #include "group_search.h" #include "utils.h" +#include "header_info.h" +#include "packet_parse.h" +#include "qq_network.h" enum { QQ_GROUP_SEARCH_TYPE_BY_ID = 0x01, @@ -41,20 +43,19 @@ }; /* send packet to search for qq_group */ -void qq_send_cmd_group_search_group(PurpleConnection *gc, guint32 external_group_id) +void qq_send_cmd_group_search_group(PurpleConnection *gc, guint32 ext_id) { guint8 raw_data[16] = {0}; gint bytes = 0; guint8 type; - type = (external_group_id == 0x00000000) ? QQ_GROUP_SEARCH_TYPE_DEMO : QQ_GROUP_SEARCH_TYPE_BY_ID; + type = (ext_id == 0x00000000) ? QQ_GROUP_SEARCH_TYPE_DEMO : QQ_GROUP_SEARCH_TYPE_BY_ID; bytes = 0; - bytes += qq_put8(raw_data + bytes, QQ_GROUP_CMD_SEARCH_GROUP); bytes += qq_put8(raw_data + bytes, type); - bytes += qq_put32(raw_data + bytes, external_group_id); + bytes += qq_put32(raw_data + bytes, ext_id); - qq_send_group_cmd(gc, NULL, raw_data, bytes); + qq_send_room_cmd_noid(gc, QQ_ROOM_CMD_SEARCH, raw_data, bytes); } static void _qq_setup_roomlist(qq_data *qd, qq_group *group) @@ -63,14 +64,14 @@ gchar field[11]; room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, group->group_name_utf8, NULL); - g_snprintf(field, sizeof(field), "%d", group->external_group_id); + 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); - g_snprintf(field, sizeof(field), "%d", group->internal_group_id); + g_snprintf(field, sizeof(field), "%d", group->id); purple_roomlist_room_add_field(qd->roomlist, room, field); - g_snprintf(field, sizeof(field), "%d", group->group_type); + 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); @@ -99,9 +100,9 @@ bytes += qq_get8(&search_type, data + bytes); /* now it starts with group_info_entry */ - bytes += qq_get32(&(group.internal_group_id), data + bytes); - bytes += qq_get32(&(group.external_group_id), data + bytes); - bytes += qq_get8(&(group.group_type), data + bytes); + bytes += qq_get32(&(group.id), data + bytes); + bytes += qq_get32(&(group.ext_id), data + bytes); + bytes += qq_get8(&(group.type8), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get16(&(unknown), data + bytes); bytes += qq_get32(&(group.creator_uid), data + bytes); @@ -119,12 +120,12 @@ "group_cmd_search_group: Dangerous error! maybe protocol changed, notify developers!"); } - pending_id = qq_get_pending_id(qd->joining_groups, group.external_group_id); + pending_id = qq_get_pending_id(qd->joining_groups, group.ext_id); if (pending_id != NULL) { - qq_set_pending_id(&qd->joining_groups, group.external_group_id, FALSE); - if (qq_group_find_by_id(gc, group.internal_group_id, QQ_INTERNAL_ID) == NULL) + 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.internal_group_id, group.external_group_id, group.group_name_utf8); + group.id, group.ext_id, group.group_name_utf8); qq_send_cmd_group_join_group(gc, &group); } else { _qq_setup_roomlist(qd, &group);
--- a/libpurple/protocols/qq/header_info.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/header_info.c Sun Aug 10 04:32:14 2008 +0000 @@ -61,58 +61,6 @@ #define QQ_SERVER_0100 0x0100 /* server */ -/* given command alias, return the command name accordingly */ -const gchar *qq_get_cmd_desc(gint type) -{ - switch (type) { - case QQ_CMD_LOGOUT: - return "QQ_CMD_LOGOUT"; - case QQ_CMD_KEEP_ALIVE: - return "QQ_CMD_KEEP_ALIVE"; - case QQ_CMD_UPDATE_INFO: - return "QQ_CMD_UPDATE_INFO"; - case QQ_CMD_SEARCH_USER: - return "QQ_CMD_SEARCH_USER"; - case QQ_CMD_GET_USER_INFO: - return "QQ_CMD_GET_USER_INFO"; - case QQ_CMD_ADD_BUDDY_WO_AUTH: - return "QQ_CMD_ADD_BUDDY_WO_AUTH"; - case QQ_CMD_DEL_BUDDY: - 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_ACK_SYS_MSG: - return "QQ_CMD_ACK_SYS_MSG"; - case QQ_CMD_SEND_IM: - return "QQ_CMD_SEND_IM"; - case QQ_CMD_RECV_IM: - return "QQ_CMD_RECV_IM"; - case QQ_CMD_REMOVE_SELF: - return "QQ_CMD_REMOVE_SELF"; - case QQ_CMD_LOGIN: - return "QQ_CMD_LOGIN"; - case QQ_CMD_GET_BUDDIES_LIST: - return "QQ_CMD_GET_BUDDIES_LIST"; - case QQ_CMD_GET_BUDDIES_ONLINE: - return "QQ_CMD_GET_BUDDIES_ONLINE"; - case QQ_CMD_GROUP_CMD: - return "QQ_CMD_GROUP_CMD"; - case QQ_CMD_GET_ALL_LIST_WITH_GROUP: - return "QQ_CMD_GET_ALL_LIST_WITH_GROUP"; - case QQ_CMD_GET_LEVEL: - return "QQ_CMD_GET_LEVEL"; - case QQ_CMD_TOKEN: - 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"; - default: - return "Unknown"; - } -} /* given source tag, return its description accordingly */ const gchar *qq_get_ver_desc(gint source) @@ -177,3 +125,112 @@ return "Unknown"; } } + +/* given command alias, return the command name accordingly */ +const gchar *qq_get_cmd_desc(gint cmd) +{ + switch (cmd) { + case QQ_CMD_LOGOUT: + return "QQ_CMD_LOGOUT"; + case QQ_CMD_KEEP_ALIVE: + return "QQ_CMD_KEEP_ALIVE"; + case QQ_CMD_UPDATE_INFO: + return "QQ_CMD_UPDATE_INFO"; + case QQ_CMD_SEARCH_USER: + return "QQ_CMD_SEARCH_USER"; + case QQ_CMD_GET_USER_INFO: + return "QQ_CMD_GET_USER_INFO"; + case QQ_CMD_ADD_BUDDY_WO_AUTH: + return "QQ_CMD_ADD_BUDDY_WO_AUTH"; + case QQ_CMD_DEL_BUDDY: + 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_ACK_SYS_MSG: + return "QQ_CMD_ACK_SYS_MSG"; + case QQ_CMD_SEND_IM: + return "QQ_CMD_SEND_IM"; + case QQ_CMD_RECV_IM: + return "QQ_CMD_RECV_IM"; + case QQ_CMD_REMOVE_SELF: + return "QQ_CMD_REMOVE_SELF"; + case QQ_CMD_LOGIN: + return "QQ_CMD_LOGIN"; + case QQ_CMD_GET_BUDDIES_LIST: + return "QQ_CMD_GET_BUDDIES_LIST"; + case QQ_CMD_GET_BUDDIES_ONLINE: + return "QQ_CMD_GET_BUDDIES_ONLINE"; + case QQ_CMD_ROOM: + return "QQ_CMD_ROOM"; + case QQ_CMD_GET_BUDDIES_AND_ROOMS: + return "QQ_CMD_GET_BUDDIES_AND_ROOMS"; + case QQ_CMD_GET_LEVEL: + return "QQ_CMD_GET_LEVEL"; + case QQ_CMD_TOKEN: + 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"; + default: + return "Unknown"; + } +} + +const gchar *qq_get_room_cmd_desc(gint room_cmd) +{ + switch (room_cmd) { + case QQ_ROOM_CMD_CREATE: + return "QQ_ROOM_CMD_CREATE"; + case QQ_ROOM_CMD_MEMBER_OPT: + return "QQ_ROOM_CMD_MEMBER_OPT"; + case QQ_ROOM_CMD_CHANGE_INFO: + return "QQ_ROOM_CMD_CHANGE_INFO"; + case QQ_ROOM_CMD_GET_INFO: + return "QQ_ROOM_CMD_GET_INFO"; + case QQ_ROOM_CMD_ACTIVATE: + return "QQ_ROOM_CMD_ACTIVATE"; + case QQ_ROOM_CMD_SEARCH: + return "QQ_ROOM_CMD_SEARCH"; + case QQ_ROOM_CMD_JOIN: + return "QQ_ROOM_CMD_JOIN"; + case QQ_ROOM_CMD_AUTH: + return "QQ_ROOM_CMD_AUTH"; + case QQ_ROOM_CMD_QUIT: + return "QQ_ROOM_CMD_QUIT"; + case QQ_ROOM_CMD_SEND_MSG: + 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_CHANGE_CARD: + return "QQ_ROOM_CMD_CHANGE_CARD"; + case QQ_ROOM_CMD_GET_REALNAMES: + return "QQ_ROOM_CMD_GET_REALNAMES"; + case QQ_ROOM_CMD_GET_CARD: + return "QQ_ROOM_CMD_GET_CARD"; + case QQ_ROOM_CMD_SEND_IM_EX: + return "QQ_ROOM_CMD_SEND_IM_EX"; + case QQ_ROOM_CMD_ADMIN: + return "QQ_ROOM_CMD_ADMIN"; + case QQ_ROOM_CMD_TRANSFER: + return "QQ_ROOM_CMD_TRANSFER"; + case QQ_ROOM_CMD_TEMP_CREATE: + return "QQ_ROOM_CMD_TEMP_CREATE"; + case QQ_ROOM_CMD_TEMP_CHANGE_MEMBER: + return "QQ_ROOM_CMD_TEMP_CHANGE_MEMBER"; + case QQ_ROOM_CMD_TEMP_QUIT: + return "QQ_ROOM_CMD_TEMP_QUIT"; + case QQ_ROOM_CMD_TEMP_GET_INFO: + return "QQ_ROOM_CMD_TEMP_GET_INFO"; + case QQ_ROOM_CMD_TEMP_SEND_IM: + return "QQ_ROOM_CMD_TEMP_SEND_IM"; + case QQ_ROOM_CMD_TEMP_GET_MEMBERS: + return "QQ_ROOM_CMD_TEMP_GET_MEMBERS"; + default: + return "Unknown QQ Room Command"; + } +}
--- a/libpurple/protocols/qq/header_info.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/header_info.h Sun Aug 10 04:32:14 2008 +0000 @@ -35,6 +35,8 @@ #define QQ_CLIENT 0x0d55 +const gchar *qq_get_ver_desc(gint source); + /* list of known QQ commands */ enum { QQ_CMD_LOGOUT = 0x0001, /* log out */ @@ -56,8 +58,8 @@ QQ_CMD_GET_BUDDIES_LIST = 0x0026, /* get buddies list */ QQ_CMD_GET_BUDDIES_ONLINE = 0x0027, /* get online buddies list */ QQ_CMD_CELL_PHONE_2 = 0x0029, /* cell phone 2 */ - QQ_CMD_GROUP_CMD = 0x0030, /* group command */ - QQ_CMD_GET_ALL_LIST_WITH_GROUP = 0x0058, + QQ_CMD_ROOM = 0x0030, /* room command */ + 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 */ @@ -66,6 +68,34 @@ const gchar *qq_get_cmd_desc(gint type); -const gchar *qq_get_ver_desc(gint source); +enum { + QQ_ROOM_CMD_CREATE = 0x01, + QQ_ROOM_CMD_MEMBER_OPT = 0x02, + QQ_ROOM_CMD_CHANGE_INFO = 0x03, + QQ_ROOM_CMD_GET_INFO = 0x04, + QQ_ROOM_CMD_ACTIVATE = 0x05, + QQ_ROOM_CMD_SEARCH = 0x06, + QQ_ROOM_CMD_JOIN = 0x07, + QQ_ROOM_CMD_AUTH = 0x08, + 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_CHANGE_CARD = 0x0E, + QQ_ROOM_CMD_GET_REALNAMES = 0x0F, + QQ_ROOM_CMD_GET_CARD = 0x10, + QQ_ROOM_CMD_SEND_IM_EX = 0x1A, + QQ_ROOM_CMD_ADMIN = 0x1B, + QQ_ROOM_CMD_TRANSFER = 0x1C, + QQ_ROOM_CMD_TEMP_CREATE = 0x30, + QQ_ROOM_CMD_TEMP_CHANGE_MEMBER = 0x31, + QQ_ROOM_CMD_TEMP_QUIT = 0x32, + QQ_ROOM_CMD_TEMP_GET_INFO = 0x33, + QQ_ROOM_CMD_TEMP_SEND_IM = 0x35, + QQ_ROOM_CMD_TEMP_GET_MEMBERS = 0x37, +}; + +const gchar *qq_get_room_cmd_desc(gint room_cmd); #endif
--- a/libpurple/protocols/qq/im.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/im.c Sun Aug 10 04:32:14 2008 +0000 @@ -35,7 +35,6 @@ #include "buddy_list.h" #include "buddy_opt.h" #include "char_conv.h" -#include "crypt.h" #include "group_im.h" #include "header_info.h" #include "im.h" @@ -541,52 +540,35 @@ } /* parse the reply to send_im */ -void qq_process_send_im_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +void qq_process_send_im_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len; - guint8 *data, reply; - gint bytes = 0; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - bytes += qq_get8(&reply, data + bytes); - if (reply != QQ_SEND_IM_REPLY_OK) { - purple_debug(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"); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt send im reply\n"); + if (data[0] != QQ_SEND_IM_REPLY_OK) { + purple_debug(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"); } } /* I receive a message, mainly it is text msg, * but we need to proess other types (group etc) */ -void qq_process_recv_im(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc) +void qq_process_recv_im(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc) { qq_data *qd; - gint len, bytes; - guint8 *data; + gint bytes; qq_recv_im_header *im_header; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - if (!qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt rev im\n"); - } - - if (len < 16) { /* we need to ack with the first 16 bytes */ + if (data_len < 16) { /* we need to ack with the first 16 bytes */ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "IM is too short\n"); return; } else { @@ -594,9 +576,9 @@ } /* check len first */ - if (len < 20) { /* length of im_header */ + 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", len); + "Fail read recv IM header, len should longer than 20 bytes, read %d bytes\n", data_len); return; } @@ -617,7 +599,7 @@ } /* check bytes */ - if (bytes >= len - 1) { + if (bytes >= data_len - 1) { purple_debug (PURPLE_DEBUG_WARNING, "QQ", "Received IM is empty\n"); return; } @@ -626,57 +608,57 @@ 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, len - bytes, gc); /* position and rest length */ + _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); - _qq_process_recv_normal_im(data + bytes, len - bytes, gc); + _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); - /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im(data + bytes, len - bytes, im_header->sender_uid, gc, im_header->im_type); + /* 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); 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); - /* sender_uid is in fact internal_group_id + /* 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, len - bytes, im_header->sender_uid, gc); + qq_process_recv_group_im_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); - /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im_been_removed(data + bytes, len - bytes, im_header->sender_uid, gc); + /* sender_uid is group id */ + qq_process_recv_group_im_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); - /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im_apply_join(data + bytes, len - bytes, im_header->sender_uid, gc); + /* sender_uid is group id */ + qq_process_recv_group_im_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", im_header->sender_uid); - /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im_been_approved(data + bytes, len - bytes, im_header->sender_uid, gc); + /* sender_uid is group id */ + qq_process_recv_group_im_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", im_header->sender_uid); - /* sender_uid is in fact internal_group_id */ - qq_process_recv_group_im_been_rejected(data + bytes, len - bytes, im_header->sender_uid, gc); + /* sender_uid is group id */ + qq_process_recv_group_im_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); - _qq_process_recv_sys_im(data + bytes, len - bytes, gc); + _qq_process_recv_sys_im(data + bytes, data_len - bytes, gc); break; default: purple_debug(PURPLE_DEBUG_WARNING, "QQ",
--- a/libpurple/protocols/qq/im.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/im.h Sun Aug 10 04:32:14 2008 +0000 @@ -59,7 +59,7 @@ gboolean is_bold, gboolean is_italic, gboolean is_underline, gint len); void qq_send_packet_im(PurpleConnection *gc, guint32 to_uid, gchar *msg, gint type); -void qq_process_recv_im(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc); -void qq_process_send_im_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); +void qq_process_recv_im(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc); +void qq_process_send_im_reply(guint8 *data, gint data_len, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/packet_parse.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/packet_parse.h Sun Aug 10 04:32:14 2008 +0000 @@ -37,11 +37,7 @@ */ #define MAX_PACKET_SIZE 65535 -#ifndef _WIN32 #include <netinet/in.h> -#else -#include "win32dep.h" -#endif gint qq_get8(guint8 *b, guint8 *buf); gint qq_get16(guint16 *w, guint8 *buf);
--- a/libpurple/protocols/qq/qq.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Sun Aug 10 04:32:14 2008 +0000 @@ -42,7 +42,6 @@ #include "buddy_opt.h" #include "buddy_list.h" #include "char_conv.h" -#include "crypt.h" #include "group.h" #include "group_find.h" #include "group_im.h" @@ -551,7 +550,7 @@ _("Input Qun name here"), _("Only QQ members can create permanent Qun"), "OpenQ", FALSE, FALSE, NULL, - _("Create"), G_CALLBACK(qq_group_create_with_name), _("Cancel"), NULL, gc); + _("Create"), G_CALLBACK(qq_room_create_new), _("Cancel"), NULL, gc); } */ @@ -689,8 +688,8 @@ return chat_name_to_purple_name(who); } -static PurplePluginProtocolInfo prpl_info = -{ +PurplePlugin *my_protocol = NULL; +static PurplePluginProtocolInfo prpl_info = { OPT_PROTO_CHAT_TOPIC | OPT_PROTO_USE_POINTSIZE, NULL, /* user_splits */ NULL, /* protocol_options */ @@ -753,11 +752,11 @@ NULL, /* PurpleWhiteboardPrplOps */ NULL, /* send_raw */ NULL, /* roomlist_room_serialize */ - NULL, /* unregister_user */ - NULL, /* send_attention */ - NULL, /* get attention_types */ - sizeof(PurplePluginProtocolInfo), /* struct_size */ + /* padding */ + NULL, + NULL, + NULL, NULL }; @@ -820,6 +819,8 @@ option = purple_account_option_int_new(_("Update interval(s)"), "update_interval", 300); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + my_protocol = plugin; + purple_prefs_add_none("/plugins/prpl/qq"); purple_prefs_add_bool("/plugins/prpl/qq/show_status_by_icon", TRUE); purple_prefs_add_bool("/plugins/prpl/qq/show_fake_video", FALSE);
--- a/libpurple/protocols/qq/qq.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq.h Sun Aug 10 04:32:14 2008 +0000 @@ -35,7 +35,6 @@ #include "roomlist.h" #define QQ_KEY_LENGTH 16 -#define QQ_DEBUG 1 /* whether we are doing DEBUG */ #ifdef _WIN32 const char *qq_win32_buddy_icon_dir(void); @@ -138,7 +137,6 @@ gint channel; /* the id for opened chat conversation */ GList *groups; - GList *group_packets; GSList *joining_groups; GSList *adding_groups_from_server; /* internal ids of groups the server wants in my blist */ GList *buddies;
--- a/libpurple/protocols/qq/qq_base.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.c Sun Aug 10 04:32:14 2008 +0000 @@ -30,7 +30,7 @@ #include "buddy_info.h" #include "buddy_list.h" #include "char_conv.h" -#include "crypt.h" +#include "qq_crypt.h" #include "group.h" #include "header_info.h" #include "qq_base.h" @@ -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", "Get session_key done\n"); + purple_debug(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 */ @@ -300,23 +300,26 @@ g_return_if_fail(qd->token != NULL && qd->token_len > 0); - raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH); - memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH); - - encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ #ifdef DEBUG memset(qd->inikey, 0x01, sizeof(qd->inikey)); #else for (bytes = 0; bytes < sizeof(qd->inikey); bytes++) { - qd->inikey[bytes] = (guint8) (g_random_int_range(0, 255) % 256); + qd->inikey[bytes] = (guint8) (rand() & 0xff); } #endif + raw_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH); + memset(raw_data, 0, QQ_LOGIN_DATA_LENGTH); + + encrypted_data = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ + bytes = 0; /* now generate the encrypted data * 000-015 use password_twice_md5 as key to encrypt empty string */ - qq_encrypt((guint8 *) "", 0, qd->password_twice_md5, raw_data + bytes, &encrypted_len); - bytes += 16; + 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 */ @@ -337,7 +340,7 @@ bytes += qq_putdata(raw_data + bytes, login_100_bytes, 100); /* all zero left */ - qq_encrypt(raw_data, QQ_LOGIN_DATA_LENGTH, qd->inikey, encrypted_data, &encrypted_len); + encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->inikey); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); @@ -405,36 +408,15 @@ } /* process the login reply packet */ -guint8 qq_process_login_reply(guint8 *buf, gint buf_len, PurpleConnection *gc) +guint8 qq_process_login_reply(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - guint8 *data; - gint data_len; gchar* error_msg; - g_return_val_if_fail(buf != NULL && buf_len != 0, QQ_LOGIN_REPLY_ERR_MISC); + g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR_MISC); qd = (qq_data *) gc->proto_data; - data_len = buf_len; - data = g_newa(guint8, data_len); - - if (qq_decrypt(buf, buf_len, qd->inikey, data, &data_len)) { - purple_debug(PURPLE_DEBUG_WARNING, "QQ", - "Decrypt login reply packet with inikey, %d bytes\n", data_len); - } else { - /* reset data_len since it may changed */ - data_len = buf_len; - if (qq_decrypt(buf, buf_len, qd->password_twice_md5, data, &data_len)) { - purple_debug(PURPLE_DEBUG_INFO, "QQ", - "Decrypt login reply packet with password_twice_md5, %d bytes\n", data_len); - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", - "No idea how to decrypt login reply\n"); - return QQ_LOGIN_REPLY_ERR_MISC; - } - } - switch (data[0]) { case QQ_LOGIN_REPLY_OK: purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login reply is OK\n"); @@ -452,7 +434,7 @@ break; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Unknown reply code: %d\n", data[0]); + 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"); @@ -482,28 +464,19 @@ } /* parse the return of keep-alive packet, it includes some system information */ -gboolean qq_process_keep_alive(guint8 *buf, gint buf_len, PurpleConnection *gc) +gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd; - gint len; gchar **segments; - guint8 *data; - g_return_val_if_fail(buf != NULL && buf_len != 0, FALSE); + g_return_val_if_fail(data != NULL && data_len != 0, FALSE); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); - - if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &len) ) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt keep alive reply\n"); - return FALSE; - } /* qq_show_packet("Keep alive reply packet", data, len); */ /* the last one is 60, don't know what it is */ - if (NULL == (segments = split_data(data, len, "\x1f", 6))) + if (NULL == (segments = split_data(data, data_len, "\x1f", 6))) return TRUE; /* segments[0] and segment[1] are all 0x30 ("0") */
--- a/libpurple/protocols/qq/qq_base.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.h Sun Aug 10 04:32:14 2008 +0000 @@ -47,10 +47,10 @@ guint8 qq_process_token_reply(PurpleConnection *gc, gchar *error_msg, guint8 *buf, gint buf_len); void qq_send_packet_login(PurpleConnection *gc); -guint8 qq_process_login_reply(guint8 *buf, gint buf_len, PurpleConnection *gc); +guint8 qq_process_login_reply(guint8 *data, gint data_len, PurpleConnection *gc); void qq_send_packet_logout(PurpleConnection *gc); void qq_send_packet_keep_alive(PurpleConnection *gc); -gboolean qq_process_keep_alive(guint8 *buf, gint buf_len, PurpleConnection *gc); +gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc); #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/qq/qq_crypt.c Sun Aug 10 04:32:14 2008 +0000 @@ -0,0 +1,330 @@ +/** + * @file qq_crypt.c + * + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * QQ encryption algorithm + * Convert from ASM code provided by PerlOICQ + * + * Puzzlebird, Nov-Dec 2002 + */ + +/* Notes: (QQ uses 16 rounds, and modified something...) + +IN : 64 bits of data in v[0] - v[1]. +OUT: 64 bits of data in w[0] - w[1]. +KEY: 128 bits of key in k[0] - k[3]. + +delta is chosen to be the real part of +the golden ratio: Sqrt(5/4) - 1/2 ~ 0.618034 multiplied by 2^32. + +0x61C88647 is what we can track on the ASM codes.!! +*/ + +#include <string.h> + +#include "debug.h" +#include "qq_crypt.h" + +#if 0 +void show_binary(char *psztitle, const guint8 *const buffer, gint bytes) +{ + printf("== %s %d ==\r\n", psztitle, bytes); + gint i, j, ch; + for (i = 0; i < bytes; i += 16) { + /* length label */ + printf("%07x: ", i); + + /* dump hex value */ + for (j = 0; j < 16; j++) { + if (j == 8) { + printf(" -"); + } + if ((i + j) < bytes) + printf(" %02x", buffer[i + j]); + else + printf(" "); + } + + printf(" "); + + + /* dump ascii value */ + for (j = 0; j < 16 && (i + j) < bytes; j++) { + ch = buffer[i + j] & 127; + if (ch < ' ' || ch == 127) + printf("."); + else + printf("%c", ch); + } + printf("\r\n"); + } + printf("========\r\n"); +} +#else + +#define show_binary(args... ) /* nothing */ + +#endif + +/******************************************************************** + * encryption + *******************************************************************/ + +/* Tiny Encryption Algorithm (TEA) */ +static inline void qq_encipher(guint32 *const v, const guint32 *const k, guint32 *const w) +{ + register guint32 + y = g_ntohl(v[0]), + z = g_ntohl(v[1]), + a = g_ntohl(k[0]), + b = g_ntohl(k[1]), + c = g_ntohl(k[2]), + d = g_ntohl(k[3]), + n = 0x10, + sum = 0, + delta = 0x9E3779B9; /* 0x9E3779B9 - 0x100000000 = -0x61C88647 */ + + while (n-- > 0) { + sum += delta; + y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); + z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); + } + + w[0] = g_htonl(y); + w[1] = g_htonl(z); +} + +/* it can be the real random seed function */ +/* override with number, convenient for debug */ +#ifdef DEBUG +static gint crypt_rand(void) { + return 0xdead; +} +#else +#include <stdlib.h> +#define crypt_rand() rand() +#endif + +/* 64-bit blocks and some kind of feedback mode of operation */ +static inline void encrypt_out(guint8 *crypted, const gint crypted_len, const guint8 *key) +{ + /* ships in encipher */ + guint32 plain32[2]; + guint32 p32_prev[2]; + guint32 key32[4]; + guint32 crypted32[2]; + guint32 c32_prev[2]; + + guint8 *crypted_ptr; + gint count64; + + /* prepare at first */ + crypted_ptr = crypted; + + memcpy(crypted32, crypted_ptr, sizeof(crypted32)); + c32_prev[0] = crypted32[0]; c32_prev[1] = crypted32[1]; + + p32_prev[0] = 0; p32_prev[1] = 0; + plain32[0] = crypted32[0] ^ p32_prev[0]; plain32[1] = crypted32[1] ^ p32_prev[1]; + + g_memmove(key32, key, 16); + count64 = crypted_len / 8; + while (count64-- > 0){ + /* encrypt it */ + qq_encipher(plain32, key32, crypted32); + + crypted32[0] ^= p32_prev[0]; crypted32[1] ^= p32_prev[1]; + + /* store curr 64 bits crypted */ + g_memmove(crypted_ptr, crypted32, sizeof(crypted32)); + + /* set prev */ + p32_prev[0] = plain32[0]; p32_prev[1] = plain32[1]; + c32_prev[0] = crypted32[0]; c32_prev[1] = crypted32[1]; + + /* set next 64 bits want to crypt*/ + crypted_ptr += 8; + memcpy(crypted32, crypted_ptr, sizeof(crypted32)); + plain32[0] = crypted32[0] ^ c32_prev[0]; plain32[1] = crypted32[1] ^ c32_prev[1]; + } +} + +/* length of crypted buffer must be plain_len + 16*/ +gint qq_encrypt(guint8* crypted, const guint8* const plain, const gint plain_len, const guint8* const key) +{ + guint8 *crypted_ptr = crypted; /* current position of dest */ + gint pos, padding; + + padding = (plain_len + 10) % 8; + if (padding) { + padding = 8 - padding; + } + + pos = 0; + + /* set first byte as padding len */ + crypted_ptr[pos] = (rand() & 0xf8) | padding; + pos++; + + /* extra 2 bytes */ + padding += 2; + + /* faster a little + memset(crypted_ptr + pos, rand() & 0xff, padding); + pos += padding; + */ + + /* more random */ + while (padding--) { + crypted_ptr[pos++] = rand() & 0xff; + } + + g_memmove(crypted_ptr + pos, plain, plain_len); + pos += plain_len; + + /* header padding len + plain len must be multiple of 8 + * tail pading len is always 8 - (1st byte) + */ + memset(crypted_ptr + pos, 0x00, 7); + pos += 7; + + show_binary("After padding", crypted, pos); + + encrypt_out(crypted, pos, key); + + show_binary("Encrypted", crypted, pos); + return pos; +} + +/******************************************************************** + * decryption + ********************************************************************/ + +static inline void qq_decipher(guint32 *const v, const guint32 *const k, guint32 *const w) +{ + register guint32 + y = g_ntohl(v[0]), + z = g_ntohl(v[1]), + a = g_ntohl(k[0]), + b = g_ntohl(k[1]), + c = g_ntohl(k[2]), + d = g_ntohl(k[3]), + n = 0x10, + sum = 0xE3779B90, /* why this ? must be related with n value */ + delta = 0x9E3779B9; + + /* sum = delta<<5, in general sum = delta * n */ + while (n-- > 0) { + z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); + y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); + sum -= delta; + } + + w[0] = g_htonl(y); + w[1] = g_htonl(z); +} + +static inline gint decrypt_out(guint8 *dest, gint crypted_len, const guint8* const key) +{ + gint plain_len; + guint32 key32[4]; + guint32 crypted32[2]; + guint32 c32_prev[2]; + guint32 plain32[2]; + guint32 p32_prev[2]; + gint count64; + gint padding; + guint8 *crypted_ptr = dest; + + /* decrypt first 64 bit */ + memcpy(key32, key, sizeof(key32)); + memcpy(crypted32, crypted_ptr, sizeof(crypted32)); + c32_prev[0] = crypted32[0]; c32_prev[1] = crypted32[1]; + + qq_decipher(crypted32, key32, p32_prev); + memcpy(crypted_ptr, p32_prev, sizeof(p32_prev)); + + /* check padding len */ + padding = 2 + (crypted_ptr[0] & 0x7); + if (padding < 2) { + padding += 8; + } + plain_len = crypted_len - 1 - padding - 7; + if( plain_len < 0 ) { + return -2; + } + + count64 = crypted_len / 8; + while (count64-- > 0){ + c32_prev[0] = crypted32[0]; c32_prev[1] = crypted32[1]; + crypted_ptr += 8; + + memcpy(crypted32, crypted_ptr, sizeof(crypted32)); + p32_prev[0] ^= crypted32[0]; p32_prev[1] ^= crypted32[1]; + + qq_decipher(p32_prev, key32, p32_prev); + + plain32[0] = p32_prev[0] ^ c32_prev[0]; plain32[1] = p32_prev[1] ^ c32_prev[1]; + memcpy(crypted_ptr, plain32, sizeof(plain32)); + } + + return plain_len; +} + +/* length of plain buffer must be equal to crypted_len */ +gint qq_decrypt(guint8 *plain, const guint8* const crypted, const gint crypted_len, const guint8* const key) +{ + gint plain_len = 0; + gint hdr_padding; + gint pos; + + /* at least 16 bytes and %8 == 0 */ + if ((crypted_len % 8) || (crypted_len < 16)) { + return -1; + } + + memcpy(plain, crypted, crypted_len); + + plain_len = decrypt_out(plain, crypted_len, key); + if (plain_len < 0) { + return plain_len; /* invalid first 64 bits */ + } + + show_binary("Decrypted with padding", plain, crypted_len); + + /* check last 7 bytes is zero or not? */ + for (pos = crypted_len - 1; pos > crypted_len - 8; pos--) { + if (plain[pos] != 0) { + return -3; + } + } + if (plain_len == 0) { + return plain_len; + } + + hdr_padding = crypted_len - plain_len - 7; + g_memmove(plain, plain + hdr_padding, plain_len); + + return plain_len; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/qq/qq_crypt.h Sun Aug 10 04:32:14 2008 +0000 @@ -0,0 +1,33 @@ + /** + * @file qq_crypt.h + * + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _QQ_CRYPT_H_ +#define _QQ_CRYPT_H_ + +#include <glib.h> + +gint qq_encrypt(guint8* crypted, const guint8* const plain, const gint plain_len, const guint8* const key); + +gint qq_decrypt(guint8 *plain, const guint8* const crypted, const gint crypted_len, const guint8* const key); +#endif
--- a/libpurple/protocols/qq/qq_network.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.c Sun Aug 10 04:32:14 2008 +0000 @@ -34,7 +34,7 @@ #include "buddy_info.h" #include "group_info.h" #include "group_free.h" -#include "crypt.h" +#include "qq_crypt.h" #include "header_info.h" #include "qq_base.h" #include "buddy_list.h" @@ -167,6 +167,9 @@ guint16 source_tag; guint16 cmd; guint16 seq; /* May be ack_seq or send_seq, depends on cmd */ + + guint8 room_cmd; + guint32 room_id; qq_transaction *trans; @@ -180,12 +183,11 @@ bytes = 0; bytes += packet_get_header(&header_tag, &source_tag, &cmd, &seq, buf + bytes); - if (QQ_DEBUG) { +#if 1 purple_debug(PURPLE_DEBUG_INFO, "QQ", - "==> [%05d] 0x%04X %s, from (0x%04X %s)\n", - seq, cmd, qq_get_cmd_desc(cmd), source_tag, qq_get_ver_desc(source_tag)); - } - + "==> [%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 bytes_not_read = buf_len - bytes - 1; /* ack packet, we need to update send tranactions */ @@ -214,8 +216,19 @@ } /* this is the length of all the encrypted data (also remove tail tag */ - qq_proc_cmd_reply(gc, cmd, seq, buf + bytes, bytes_not_read); - + if (cmd == 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 */ @@ -933,7 +946,6 @@ qd->my_ip.s_addr = 0; - qq_group_packets_free(qd); qq_group_free_all(qd); qq_add_buddy_request_free(qd); qq_info_query_free(qd); @@ -945,16 +957,8 @@ { 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); - if (data == NULL) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail encap packet, data is NULL\n"); - return -1; - } - if (data_len <= 0) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail encap packet, data len <= 0\n"); - return -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) { @@ -1007,12 +1011,12 @@ qq_trans_add_client_cmd(qd, cmd, seq, data, data_len); } - if (QQ_DEBUG) { +#if 1 /* qq_show_packet("QQ_SEND_DATA", buf, buf_len); */ purple_debug(PURPLE_DEBUG_INFO, "QQ", - "<== [%05d], %s, total %d bytes is sent %d\n", - seq, qq_get_cmd_desc(cmd), buf_len, bytes_sent); - } + "<== [%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; } @@ -1026,11 +1030,26 @@ g_return_val_if_fail(qd != NULL, -1); g_return_val_if_fail(data != NULL && data_len > 0, -1); - encrypted_len = data_len + 16; /* at most 16 bytes more */ - encrypted_data = g_newa(guint8, encrypted_len); + /* 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", + encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); + return -1; + } - qq_encrypt(data, data_len, qd->session_key, encrypted_data, &encrypted_len); - +#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); } @@ -1043,3 +1062,81 @@ qd->send_seq++; return qq_send_cmd_detail(qd, cmd, qd->send_seq, TRUE, data, data_len); } + +gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, + guint8 *data, gint data_len) +{ + return qq_send_room_cmd(gc, room_cmd, 0, data, data_len); +} + +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 qq_send_room_cmd(gc, room_cmd, room_id, NULL, 0); +} + +gint qq_send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, + guint8 *data, gint data_len) +{ + 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; + + buf = g_newa(guint8, MAX_PACKET_SIZE); + memset(buf, 0, MAX_PACKET_SIZE); + + /* encap room_cmd and room id to buf*/ + buf_len = 0; + buf_len += qq_put8(buf + buf_len, room_cmd); + if (room_id != 0) { + /* id 0 is for QQ Demo Group, now there are not existed*/ + buf_len += qq_put32(buf + buf_len, room_id); + } + if (data != NULL && data_len > 0) { + buf_len += qq_putdata(buf + buf_len, data, data_len); + } + qd->send_seq++; + seq = qd->send_seq; + + /* Encrypt to encrypted_data with session_key */ + /* at most 16 bytes more */ + 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) { + 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); + +#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); +#endif + return bytes_sent; +}
--- a/libpurple/protocols/qq/qq_network.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.h Sun Aug 10 04:32:14 2008 +0000 @@ -42,4 +42,9 @@ gint qq_send_cmd_detail(qq_data *qd, guint16 cmd, guint16 seq, gboolean need_ack, 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_only(PurpleConnection *gc, guint8 room_cmd, guint32 room_id); +gint qq_send_room_cmd_noid(PurpleConnection *gc, guint8 room_cmd, + guint8 *data, gint data_len); #endif
--- a/libpurple/protocols/qq/qq_process.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Sun Aug 10 04:32:14 2008 +0000 @@ -37,8 +37,17 @@ #include "group_info.h" #include "group_free.h" #include "char_conv.h" -#include "crypt.h" -#include "group_network.h" +#include "qq_crypt.h" + +#include "group_conv.h" +#include "group_find.h" +#include "group_internal.h" +#include "group_im.h" +#include "group_info.h" +#include "group_join.h" +#include "group_opt.h" +#include "group_search.h" + #include "header_info.h" #include "qq_base.h" #include "im.h" @@ -49,28 +58,24 @@ #include "sys_msg.h" #include "utils.h" +enum { + QQ_ROOM_CMD_REPLY_OK = 0x00, + QQ_ROOM_CMD_REPLY_SEARCH_ERROR = 0x02, + QQ_ROOM_CMD_REPLY_NOT_MEMBER = 0x0a +}; + /* default process, decrypt and dump */ -static void process_cmd_unknow(PurpleConnection *gc,gchar *title, guint8 *buf, gint buf_len, guint16 cmd, guint16 seq) +static void process_cmd_unknow(PurpleConnection *gc,gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq) { qq_data *qd; - guint8 *data; - gint data_len; gchar *msg_utf8 = NULL; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); - qq_show_packet(title, buf, buf_len); + qq_show_packet(title, data, data_len); qd = (qq_data *) gc->proto_data; - data_len = buf_len; - data = g_newa(guint8, data_len); - memset(data, 0, data_len); - if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &data_len )) { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail decrypt packet with default process\n"); - return; - } - qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, ">>> [%d] %s -> [default] decrypt and dump", @@ -78,13 +83,39 @@ msg_utf8 = try_dump_as_gbk(data, data_len); if (msg_utf8) { + purple_notify_info(gc, NULL, msg_utf8, NULL); g_free(msg_utf8); } } void qq_proc_cmd_server(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *data, gint data_len) + guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) { + qq_data *qd; + + guint8 *data; + gint data_len; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + 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", + 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", + seq, cmd, qq_get_cmd_desc(cmd), rcved_len); + return; + } + /* now process the packet */ switch (cmd) { case QQ_CMD_RECV_IM: @@ -134,7 +165,7 @@ qq_send_packet_get_buddies_list(gc, 0); /* refresh groups */ - qq_send_packet_get_all_list_with_group(gc, 0); + qq_send_packet_get_buddies_and_rooms(gc, 0); return; } @@ -168,14 +199,223 @@ } } +static void process_room_cmd_notify(PurpleConnection *gc, + guint8 room_cmd, guint8 room_id, guint8 reply_cmd, guint8 reply, guint8 *data, gint data_len) +{ + gchar *msg, *msg_utf8; + g_return_if_fail(data != NULL && data_len > 0); + + 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); + 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) +{ + qq_data *qd; + guint8 *data; + gint data_len; + qq_group *group; + gint bytes; + guint8 reply_cmd, reply; + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + 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", + 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", + 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", + 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", + 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", + 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; + qq_group_refresh(gc, group); + } + break; + case QQ_ROOM_CMD_REPLY_SEARCH_ERROR: + if (qd->roomlist != NULL) { + if (purple_roomlist_get_in_progress(qd->roomlist)) + 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); + } + return; + } + + /* seems ok so far, so we process the reply according to sub_cmd */ + 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); + break; + case QQ_ROOM_CMD_CHANGE_INFO: + qq_group_process_modify_info_reply(data + bytes, data_len - bytes, gc); + break; + case QQ_ROOM_CMD_MEMBER_OPT: + qq_group_process_modify_members_reply(data + bytes, data_len - bytes, gc); + break; + case QQ_ROOM_CMD_ACTIVATE: + qq_group_process_activate_group_reply(data + bytes, data_len - bytes, gc); + break; + case QQ_ROOM_CMD_SEARCH: + qq_process_group_cmd_search_group(data + bytes, data_len - bytes, gc); + break; + case QQ_ROOM_CMD_JOIN: + qq_process_group_cmd_join_group(data + bytes, data_len - bytes, gc); + break; + case QQ_ROOM_CMD_AUTH: + qq_process_group_cmd_join_group_auth(data + bytes, data_len - bytes, gc); + break; + case QQ_ROOM_CMD_QUIT: + qq_process_group_cmd_exit_group(data + bytes, data_len - bytes, gc); + break; + case QQ_ROOM_CMD_SEND_MSG: + qq_process_group_cmd_im(data + bytes, data_len - bytes, gc); + break; + case QQ_ROOM_CMD_GET_ONLINES: + qq_process_room_cmd_get_onlines(data + bytes, data_len - bytes, gc); + 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); + 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", + reply_cmd, qq_get_room_cmd_desc(reply_cmd)); + } +} + void qq_proc_cmd_reply(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *data, gint data_len) + guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len) { + qq_data *qd; + + guint8 *data; + gint data_len; + + gboolean ret_bool = FALSE; guint8 ret_8 = 0; guint16 ret_16 = 0; guint32 ret_32 = 0; gchar *error_msg = NULL; + g_return_if_fail(rcved_len > 0); + + g_return_if_fail (gc != NULL && gc->proto_data != NULL); + 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; + } + } + + if (data_len <= 0) { + purple_debug(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); @@ -246,14 +486,11 @@ qq_send_packet_get_buddies_online(gc, 0); } break; - case QQ_CMD_GROUP_CMD: - qq_process_group_cmd_reply(data, data_len, seq, gc); - break; - case QQ_CMD_GET_ALL_LIST_WITH_GROUP: - ret_32 = qq_process_get_all_list_with_group_reply(data, data_len, gc); + 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_all_list_with_group(gc, ret_32); + qq_send_packet_get_buddies_and_rooms(gc, ret_32); } else { purple_debug(PURPLE_DEBUG_INFO, "QQ", "All buddies and groups received\n"); }
--- a/libpurple/protocols/qq/qq_process.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.h Sun Aug 10 04:32:14 2008 +0000 @@ -31,8 +31,11 @@ #include "qq.h" void qq_proc_cmd_reply(PurpleConnection *gc, - guint16 cmd, guint16 seq, guint8 *data, gint data_len); + 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 *data, gint data_len); + guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len); #endif
--- a/libpurple/protocols/qq/qq_trans.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.c Sun Aug 10 04:32:14 2008 +0000 @@ -90,6 +90,18 @@ return FALSE; } +guint8 qq_trans_get_room_cmd(qq_transaction *trans) +{ + g_return_val_if_fail(trans != NULL, 0); + return trans->room_cmd; +} + +guint32 qq_trans_get_room_id(qq_transaction *trans) +{ + g_return_val_if_fail(trans != NULL, 0); + return trans->room_id; +} + /* Remove a packet with seq from send trans */ static void trans_remove(qq_data *qd, qq_transaction *trans) { @@ -120,21 +132,53 @@ 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_ERROR, "QQ_TRANS", + purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Add client cmd, seq = %d, data = %p, len = %d\n", trans->seq, trans->data, trans->data_len); 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) +{ + qq_transaction *trans = g_new0(qq_transaction, 1); + + 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", + trans->seq, trans->data, trans->data_len); + 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) { qq_transaction *trans = g_new0(qq_transaction, 1); @@ -148,6 +192,8 @@ 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; @@ -157,7 +203,7 @@ trans->data = g_memdup(data, data_len); /* don't use g_strdup, may have 0x00 */ trans->data_len = data_len; } - purple_debug(PURPLE_DEBUG_ERROR, "QQ_TRANS", + purple_debug(PURPLE_DEBUG_INFO, "QQ_TRANS", "Add server cmd, seq = %d, data = %p, len = %d\n", trans->seq, trans->data, trans->data_len); qd->transactions = g_list_append(qd->transactions, trans);
--- a/libpurple/protocols/qq/qq_trans.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/qq_trans.h Sun Aug 10 04:32:14 2008 +0000 @@ -40,6 +40,10 @@ guint8 flag; guint16 seq; guint16 cmd; + + guint8 room_cmd; + guint32 room_id; + guint8 *data; gint data_len; @@ -52,8 +56,14 @@ qq_transaction *qq_trans_find_rcved(qq_data *qd, 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); + 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, + 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);
--- a/libpurple/protocols/qq/send_file.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/send_file.c Sun Aug 10 04:32:14 2008 +0000 @@ -30,7 +30,6 @@ #include "notify.h" #include "buddy_list.h" -#include "crypt.h" #include "file_trans.h" #include "header_info.h" #include "im.h"
--- a/libpurple/protocols/qq/sys_msg.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/sys_msg.c Sun Aug 10 04:32:14 2008 +0000 @@ -31,7 +31,6 @@ #include "buddy_list.h" #include "buddy_opt.h" #include "char_conv.h" -#include "crypt.h" #include "header_info.h" #include "packet_parse.h" #include "qq.h" @@ -292,64 +291,55 @@ g_free(content); } -void qq_process_msg_sys(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc) +void qq_process_msg_sys(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc) { qq_data *qd; - gint len; - guint8 *data; gchar **segments, *code, *from, *to, *msg, *msg_utf8; - g_return_if_fail(buf != NULL && buf_len != 0); + g_return_if_fail(data != NULL && data_len != 0); qd = (qq_data *) gc->proto_data; - len = buf_len; - data = g_newa(guint8, len); + + if (NULL == (segments = split_data(data, data_len, "\x1f", 4))) + return; + code = segments[0]; + from = segments[1]; + to = segments[2]; + msg = segments[3]; - if (qq_decrypt(buf, buf_len, qd->session_key, data, &len)) { - if (NULL == (segments = split_data(data, len, "\x1f", 4))) - return; - code = segments[0]; - from = segments[1]; - to = segments[2]; - msg = segments[3]; + _qq_send_packet_ack_msg_sys(gc, code[0], strtol(from, NULL, 10), seq); - _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); - g_strfreev(segments); - return; - } + 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); + g_strfreev(segments); + return; + } - msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); - switch (strtol(code, NULL, 10)) { - case QQ_MSG_SYS_BEING_ADDED: - _qq_process_msg_sys_being_added(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_ADD_CONTACT_REQUEST: - _qq_process_msg_sys_add_contact_request(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_ADD_CONTACT_APPROVED: - _qq_process_msg_sys_add_contact_approved(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_ADD_CONTACT_REJECTED: - _qq_process_msg_sys_add_contact_rejected(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_NOTICE: - _qq_process_msg_sys_notice(gc, from, to, msg_utf8); - break; - case QQ_MSG_SYS_NEW_VERSION: - purple_debug(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); - } - g_free(msg_utf8); - g_strfreev(segments); - - } else { - purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Error decrypt recv msg sys\n"); + msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + switch (strtol(code, NULL, 10)) { + case QQ_MSG_SYS_BEING_ADDED: + _qq_process_msg_sys_being_added(gc, from, to, msg_utf8); + break; + case QQ_MSG_SYS_ADD_CONTACT_REQUEST: + _qq_process_msg_sys_add_contact_request(gc, from, to, msg_utf8); + break; + case QQ_MSG_SYS_ADD_CONTACT_APPROVED: + _qq_process_msg_sys_add_contact_approved(gc, from, to, msg_utf8); + break; + case QQ_MSG_SYS_ADD_CONTACT_REJECTED: + _qq_process_msg_sys_add_contact_rejected(gc, from, to, msg_utf8); + break; + case QQ_MSG_SYS_NOTICE: + _qq_process_msg_sys_notice(gc, from, to, msg_utf8); + break; + case QQ_MSG_SYS_NEW_VERSION: + purple_debug(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); } + g_free(msg_utf8); + g_strfreev(segments); }
--- a/libpurple/protocols/qq/sys_msg.h Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/sys_msg.h Sun Aug 10 04:32:14 2008 +0000 @@ -28,6 +28,6 @@ #include <glib.h> #include "connection.h" -void qq_process_msg_sys(guint8 *buf, gint buf_len, guint16 seq, PurpleConnection *gc); +void qq_process_msg_sys(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc); #endif
--- a/libpurple/protocols/qq/utils.c Sat Aug 09 23:23:48 2008 +0000 +++ b/libpurple/protocols/qq/utils.c Sun Aug 10 04:32:14 2008 +0000 @@ -314,7 +314,7 @@ if ((i + j) < bytes) g_string_append_printf(str, " %02x", buffer[i + j]); else - g_string_append(str, " "); + g_string_append(str, " --"); g_string_append(str, " "); /* dump ascii value */