# HG changeset patch # User SHiNE CsyFeK # Date 1224686105 0 # Node ID dbc7a9742f8d452dbb8e423077d94546106e15e5 # Parent bdfcfd71449cb40056c8bae112248debfa28119c 2008.09.26 - ccpaging * Added 'Request/Add/Remove Buddy' functions diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/buddy_info.c --- a/libpurple/protocols/qq/buddy_info.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/buddy_info.c Wed Oct 22 14:35:05 2008 +0000 @@ -32,6 +32,7 @@ #include "buddy_list.h" #include "buddy_info.h" #include "char_conv.h" +#include "im.h" #include "qq_define.h" #include "qq_base.h" #include "qq_network.h" @@ -452,7 +453,7 @@ data[data_len] = '\0'; if (qd->uid == atoi((gchar *) data)) { /* return should be my uid */ purple_debug_info("QQ", "Update info ACK OK\n"); - purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), _("Change buddy information.")); + qq_got_attention(gc, _("Successed changing buddy information.")); } } @@ -735,7 +736,6 @@ if (uid == qd->uid) { qd->my_level = level; purple_debug_warning("QQ", "Got my levels as %d\n", qd->my_level); - continue; } purple_name = uid_to_purple_name(uid); diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/buddy_list.c --- a/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/buddy_list.c Wed Oct 22 14:35:05 2008 +0000 @@ -138,7 +138,7 @@ bytes += qq_get8(&bs->unknown2, data + bytes); /* 012-012: status */ bytes += qq_get8(&bs->status, data + bytes); - /* 013-014: client_version */ + /* 013-014: client tag */ bytes += qq_get16(&bs->unknown3, data + bytes); /* 015-030: unknown key */ bytes += qq_getdata(&(bs->unknown_key[0]), QQ_KEY_LENGTH, data + bytes); @@ -207,7 +207,6 @@ if (bo.bs.uid == qd->uid) { purple_debug_warning("QQ", "I am in online list %d\n", bo.bs.uid); - continue; } /* update buddy information */ @@ -228,8 +227,8 @@ } /* we find one and update qq_buddy */ /* - if(0 != fe->s->client_version) - q_bud->client_version = fe->s->client_version; + if(0 != fe->s->client_tag) + q_bud->client_tag = fe->s->client_tag; */ q_bud->ip.s_addr = bo.bs.ip.s_addr; q_bud->port = bo.bs.port; diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/buddy_opt.c --- a/libpurple/protocols/qq/buddy_opt.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/buddy_opt.c Wed Oct 22 14:35:05 2008 +0000 @@ -40,8 +40,7 @@ #include "utils.h" #define PURPLE_GROUP_QQ_FORMAT "QQ (%s)" -#define PURPLE_GROUP_QQ_UNKNOWN "QQ Unknown" -#define PURPLE_GROUP_QQ_BLOCKED "QQ Blocked" +#define PURPLE_GROUP_QQ_UNKNOWN "QQ Unknown" #define QQ_REMOVE_BUDDY_REPLY_OK 0x00 #define QQ_REMOVE_SELF_REPLY_OK 0x00 @@ -237,7 +236,7 @@ if (b != NULL) { purple_blist_remove_buddy(b); } - purple_notify_error(gc, NULL, _("QQ Number Error"), _("Invalid QQ Number")); + purple_notify_error(gc, _("QQ Buddy"), _("QQ Number Error"), _("Invalid QQ Number")); } void qq_change_buddys_group(PurpleConnection *gc, const char *who, @@ -347,6 +346,10 @@ uid = purple_name_to_uid(who); g_return_if_fail(uid > 0); + + if (uid == qd->uid) { + return; + } add_req = g_new0(qq_add_request, 1); add_req->gc = gc; @@ -373,15 +376,15 @@ qd = (qq_data *) gc->proto_data; if (data[0] != QQ_ADD_BUDDY_AUTH_REPLY_OK) { - purple_debug_warning("QQ", "Add buddy with auth request failed\n"); + purple_debug_warning("QQ", "Failed authorizing of adding requestion\n"); if (NULL == (segments = split_data(data, data_len, "\x1f", 2))) { return; } msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT); - purple_notify_error(gc, NULL, _("Add buddy with auth request failed"), msg_utf8); + purple_notify_error(gc, _("QQ Buddy"), _("Failed authorizing of adding requestion"), msg_utf8); g_free(msg_utf8); } else { - purple_debug_info("QQ", "Add buddy with auth request OK\n"); + qq_got_attention(gc, _("Successed authorizing of adding requestion")); } } @@ -399,9 +402,7 @@ purple_debug_warning("QQ", "Remove buddy fails\n"); purple_notify_info(gc, _("QQ Buddy"), _("Failed:"), _("Remove buddy")); } else { /* if reply */ - purple_debug_info("QQ", "Remove buddy OK\n"); - /* TODO: We don't really need to notify the user about this, do we? */ - purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), _("Remove buddy")); + qq_got_attention(gc, _("Successed removing budy.")); } } @@ -419,10 +420,7 @@ purple_debug_warning("QQ", "Remove self fails\n"); purple_notify_info(gc, _("QQ Buddy"), _("Failed:"), _("Remove me from other's buddy list")); } else { /* if reply */ - purple_debug_info("QQ", "Remove from a buddy OK\n"); -#if 0 - purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), _("Remove from other's buddy list")); -#endif + qq_got_attention(gc, _("Successed removing me from other's budy list.")); } } @@ -478,8 +476,8 @@ g_free(nombre); } else { /* add OK */ qq_create_buddy(gc, uid, TRUE, TRUE); - msg = g_strdup_printf(_("Add into %d's buddy list"), uid); - purple_notify_info(gc, _("QQ Buddy"), _("Successed:"), msg); + msg = g_strdup_printf(_("Successed adding into %d's buddy list"), uid); + qq_got_attention(gc, msg); g_free(msg); } g_strfreev(segments); @@ -514,7 +512,7 @@ g_return_val_if_fail(gc->account != NULL && uid != 0, NULL); qd = (qq_data *) gc->proto_data; - if (is_known) { + if (is_known || uid == qd->uid) { group_name = g_strdup_printf(PURPLE_GROUP_QQ_FORMAT, purple_account_get_username(gc->account)); } else { @@ -531,7 +529,7 @@ purple_blist_remove_buddy(buddy); buddy = purple_buddy_new(gc->account, buddy_name, NULL); - if ( !is_known ) { + if ( !is_known && uid != qd->uid) { if (purple_privacy_check(gc->account, buddy_name)) { purple_privacy_deny(gc->account, buddy_name, TRUE, FALSE); } else { @@ -701,8 +699,8 @@ _("Add"), G_CALLBACK(buddy_add_no_auth_cb), _("Search"), G_CALLBACK(buddy_add_check_info_cb)); } else { - message = g_strdup_printf(_("%s added you [%s] to buddy list"), from, to); - purple_notify_info(gc, _("QQ Budy"), _("Successed:"), message); + message = g_strdup_printf(_("Successed adding into %s's buddy list"), from); + qq_got_attention(gc, message); } g_free(name); @@ -712,7 +710,7 @@ /* the buddy approves your request of adding him/her as your friend */ static void server_buddy_added_me(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) { - gchar *message; + PurpleAccount *account = purple_connection_get_account(gc); qq_data *qd; g_return_if_fail(from != NULL && to != NULL); @@ -720,10 +718,7 @@ qd = (qq_data *) gc->proto_data; qq_create_buddy(gc, strtol(from, NULL, 10), TRUE, TRUE); - message = g_strdup_printf(_("Requestion approved by %s"), from); - purple_notify_info(gc, _("QQ Buddy"), _("Notice:"), message); - - g_free(message); + purple_account_notify_added(account, from, to, NULL, msg_utf8); } /* you are rejected by the person */ diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/file_trans.c --- a/libpurple/protocols/qq/file_trans.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/file_trans.c Wed Oct 22 14:35:05 2008 +0000 @@ -248,7 +248,7 @@ file_key = _gen_file_key(); bytes += qq_put8(raw_data + bytes, packet_type); - bytes += qq_put16(raw_data + bytes, qd->client_version); + bytes += qq_put16(raw_data + bytes, qd->client_tag); bytes += qq_put8(raw_data + bytes, file_key & 0xff); bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(qd->uid, file_key)); bytes += qq_put32(raw_data + bytes, _encrypt_qq_uid(to_uid, file_key)); @@ -266,7 +266,7 @@ { qq_data *qd; gint bytes, bytes_expected, encrypted_len; - guint8 *raw_data, *encrypted_data; + guint8 *raw_data, *encrypted; time_t now; ft_info *info; @@ -334,19 +334,19 @@ raw_data, bytes, "sending packet[%s]:", qq_get_file_cmd_desc(packet_type)); - encrypted_data = g_newa(guint8, bytes + 16); - encrypted_len = qq_encrypt(encrypted_data, raw_data, bytes, info->file_session_key); + encrypted = g_newa(guint8, bytes + 16); + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, info->file_session_key); /*debug: try to decrypt it */ #if 0 guint8 *buf; int buflen; - hex_dump = hex_dump_to_str(encrypted_data, encrypted_len); + hex_dump = hex_dump_to_str(encrypted, encrypted_len); 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)) { + if (qq_crypt(DECRYPT, encrypted, encrypted_len, info->file_session_key, buf, &buflen)) { purple_debug_info("QQ", "decrypt success\n"); if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0) purple_debug_info("QQ", "checksum ok\n"); @@ -360,7 +360,7 @@ #endif 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); + _qq_send_file(gc, encrypted, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); } /* send a file to udp channel with QQ_FILE_DATA_PACKET_TAG */ diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_conv.c --- a/libpurple/protocols/qq/group_conv.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_conv.c Wed Oct 22 14:35:05 2008 +0000 @@ -37,6 +37,7 @@ { PurpleConversation *conv; qq_data *qd; + gchar *topic_utf8; g_return_val_if_fail(group != NULL, NULL); qd = (qq_data *) gc->proto_data; @@ -51,7 +52,11 @@ serv_got_joined_chat(gc, qd->channel++, group->title_utf8); conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); if (conv != NULL) { - purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, group->notice_utf8); + topic_utf8 = g_strdup_printf("%d %s", group->ext_id, group->notice_utf8); + purple_debug_info("QQ", "Set chat topic to %s\n", topic_utf8); + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, topic_utf8); + g_free(topic_utf8); + if (group->is_got_info) qq_send_room_cmd_only(gc, QQ_ROOM_CMD_GET_ONLINES, group->id); else @@ -83,9 +88,9 @@ /* we need unique identifiers for everyone in the chat or else we'll * run into problems with functions like get_cb_real_name from qq.c */ member_name = (member->nickname != NULL && *(member->nickname) != '\0') ? - g_strdup_printf("%s (qq-%u)", member->nickname, member->uid) : - g_strdup_printf("(qq-%u)", member->uid); - member_uid = g_strdup_printf("(qq-%u)", member->uid); + g_strdup_printf("%s (%u)", member->nickname, member->uid) : + g_strdup_printf("(%u)", member->uid); + member_uid = g_strdup_printf("(%u)", member->uid); flag = 0; /* TYPING to put online above OP and FOUNDER */ diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_im.c --- a/libpurple/protocols/qq/group_im.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_im.c Wed Oct 22 14:35:05 2008 +0000 @@ -45,18 +45,6 @@ #include "qq_process.h" #include "utils.h" -typedef struct _qq_recv_group_im { - guint32 ext_id; - guint8 type8; - guint32 member_uid; - guint16 msg_seq; - time_t send_time; - guint16 msg_len; - gchar *msg; - guint8 *font_attr; - gint font_attr_len; -} qq_recv_group_im; - /* send IM to a group */ void qq_send_packet_group_im(PurpleConnection *gc, qq_group *group, const gchar *msg) { @@ -150,6 +138,41 @@ g_free(reason_utf8); } +void qq_room_got_chat_in(PurpleConnection *gc, + qq_group *group, guint32 uid_from, const gchar *msg, time_t in_time) +{ + PurpleAccount *account = purple_connection_get_account(gc); + PurpleConversation *conv; + qq_buddy *buddy; + gchar *from; + + g_return_if_fail(group != NULL); + + conv = purple_find_conversation_with_account( + PURPLE_CONV_TYPE_CHAT, group->title_utf8, account); + if (conv == NULL && purple_prefs_get_bool("/plugins/prpl/qq/show_room_when_newin")) { + conv = qq_room_conv_create(gc, group); + } + + if (conv == NULL) { + return; + } + + if (uid_from != 0) { + buddy = qq_group_find_member_by_uid(group, uid_from); + if (buddy == NULL || buddy->nickname == NULL) + from = uid_to_purple_name(uid_from); + else + from = g_strdup(buddy->nickname); + } else { + from = g_strdup(""); + } + serv_got_chat_in(gc, + purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), + from, 0, msg, in_time); + g_free(from); +} + /* the request to join a group is rejected */ void qq_process_room_msg_been_rejected(guint8 *data, gint len, guint32 id, PurpleConnection *gc) { @@ -157,12 +180,12 @@ guint8 type8; gchar *reason_utf8, *msg, *reason; qq_group *group; - gint bytes = 0; + gint bytes; g_return_if_fail(data != NULL && len > 0); /* FIXME: check length here */ - + bytes = 0; bytes += qq_get32(&ext_id, data + bytes); bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&admin_uid, data + bytes); @@ -183,8 +206,8 @@ qq_group_refresh(gc, group); } + g_free(msg); g_free(reason); - g_free(msg); g_free(reason_utf8); } @@ -193,26 +216,22 @@ { guint32 ext_id, admin_uid; guint8 type8; - gchar *reason_utf8, *msg; + gchar *msg, *reason; qq_group *group; - gint bytes = 0; + gint bytes; + time_t now; g_return_if_fail(data != NULL && len > 0); /* FIXME: check length here */ - + bytes = 0; bytes += qq_get32(&ext_id, data + bytes); bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&admin_uid, data + bytes); 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 - (_("Successed to join Qun %d, operated by admin %d"), ext_id, admin_uid); - - purple_notify_warning(gc, _("QQ Qun Operation"), msg, NULL); + bytes += convert_as_pascal_string(data + bytes, &reason, QQ_CHARSET_DEFAULT); group = qq_room_search_id(gc, id); if (group != NULL) { @@ -220,8 +239,13 @@ qq_group_refresh(gc, group); } + msg = g_strdup_printf(_("Joinning Qun %d is approved by Admin %d for %s"), + ext_id, admin_uid, reason); + now = time(NULL); + qq_room_got_chat_in(gc, group, 0, msg, now); + g_free(msg); - g_free(reason_utf8); + g_free(reason); } /* process the packet when removed from a group */ @@ -232,26 +256,26 @@ gchar *msg; qq_group *group; gint bytes = 0; + time_t now = time(NULL); g_return_if_fail(data != NULL && len > 0); /* FIXME: check length here */ - + bytes = 0; bytes += qq_get32(&ext_id, data + bytes); bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&uid, data + bytes); g_return_if_fail(ext_id > 0 && uid > 0); - msg = g_strdup_printf(_("[%d] removed from Qun \"%d\""), uid, ext_id); - purple_notify_info(gc, _("QQ Qun Operation"), _("Notice:"), msg); - group = qq_room_search_id(gc, id); if (group != NULL) { group->my_role = QQ_ROOM_ROLE_NO; qq_group_refresh(gc, group); } + msg = g_strdup_printf(_("Removed buddy %d."), uid); + qq_room_got_chat_in(gc, group, 0, msg, now); g_free(msg); } @@ -262,21 +286,19 @@ guint8 type8; qq_group *group; gchar *msg; - gint bytes = 0; + gint bytes; + time_t now = time(NULL); g_return_if_fail(data != NULL && len > 0); /* FIXME: check length here */ - + bytes = 0; bytes += qq_get32(&ext_id, data + bytes); bytes += qq_get8(&type8, data + bytes); bytes += qq_get32(&uid, data + bytes); g_return_if_fail(ext_id > 0 && uid > 0); - msg = g_strdup_printf(_("[%d] added to Qun \"%d\""), uid, ext_id); - purple_notify_info(gc, _("QQ Qun Operation"), _("Notice:"), msg); - group = qq_room_search_id(gc, id); if (group != NULL) { group->my_role = QQ_ROOM_ROLE_YES; @@ -289,22 +311,33 @@ /* the return of this cmd will automatically update the group in blist */ } + msg = g_strdup_printf(_("Added new buddy %d."), uid); + qq_room_got_chat_in(gc, group, 0, msg, now); g_free(msg); } /* recv an IM from a group chat */ void qq_process_room_msg_normal(guint8 *data, gint data_len, guint32 id, PurpleConnection *gc, guint16 im_type) { - gchar *msg_with_purple_smiley, *msg_utf8_encoded, *im_src_name; - guint16 unknown; - guint32 unknown4; - PurpleConversation *conv; + gchar *msg_with_purple_smiley, *msg_utf8_encoded; qq_data *qd; - qq_buddy *member; qq_group *group; - qq_recv_group_im *im_group; gint skip_len; - gint bytes = 0; + gint bytes ; + struct { + guint32 ext_id; + guint8 type8; + guint32 member_uid; + guint16 unknown; + guint16 msg_seq; + time_t send_time; + guint32 unknown4; + guint16 msg_len; + gchar *msg; + guint8 *font_attr; + gint font_attr_len; + } packet; + g_return_if_fail(data != NULL && data_len > 0); @@ -315,21 +348,20 @@ #if 0 qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", data, data_len, "group im hex dump"); #endif - - im_group = g_newa(qq_recv_group_im, 1); - - bytes += qq_get32(&(im_group->ext_id), data + bytes); - bytes += qq_get8(&(im_group->type8), data + bytes); + memset(&packet, 0, sizeof(packet)); + bytes = 0; + bytes += qq_get32(&(packet.ext_id), data + bytes); + bytes += qq_get8(&(packet.type8), data + bytes); if(QQ_RECV_IM_TEMP_QUN_IM == im_type) { bytes += qq_get32(&(id), data + bytes); } - bytes += qq_get32(&(im_group->member_uid), bytes + data); - bytes += qq_get16(&unknown, data + bytes); /* 0x0001? */ - bytes += qq_get16(&(im_group->msg_seq), data + bytes); - bytes += qq_getime(&im_group->send_time, data + bytes); - bytes += qq_get32(&unknown4, data + bytes); /* versionID */ + bytes += qq_get32(&(packet.member_uid), bytes + data); + bytes += qq_get16(&packet.unknown, data + bytes); /* 0x0001? */ + bytes += qq_get16(&(packet.msg_seq), data + bytes); + bytes += qq_getime(&packet.send_time, data + bytes); + bytes += qq_get32(&packet.unknown4, data + bytes); /* versionID */ /* * length includes font_attr * this msg_len includes msg and font_attr @@ -340,8 +372,8 @@ * 3. font_attr */ - bytes += qq_get16(&(im_group->msg_len), data + bytes); - g_return_if_fail(im_group->msg_len > 0); + bytes += qq_get16(&(packet.msg_len), data + bytes); + g_return_if_fail(packet.msg_len > 0); /* * 10 bytes from lumaqq @@ -358,44 +390,28 @@ skip_len = 0; bytes += skip_len; - im_group->msg = g_strdup((gchar *) data + bytes); - bytes += strlen(im_group->msg) + 1; + packet.msg = g_strdup((gchar *) data + bytes); + bytes += strlen(packet.msg) + 1; /* there might not be any font_attr, check it */ - im_group->font_attr_len = im_group->msg_len - strlen(im_group->msg) - 1 - skip_len; - if (im_group->font_attr_len > 0) - im_group->font_attr = g_memdup(data + bytes, im_group->font_attr_len); + packet.font_attr_len = packet.msg_len - strlen(packet.msg) - 1 - skip_len; + if (packet.font_attr_len > 0) + packet.font_attr = g_memdup(data + bytes, packet.font_attr_len); else - im_group->font_attr = NULL; + packet.font_attr = NULL; /* group im_group has no flag to indicate whether it has font_attr or not */ - msg_with_purple_smiley = qq_smiley_to_purple(im_group->msg); - if (im_group->font_attr_len > 0) - msg_utf8_encoded = qq_encode_to_purple(im_group->font_attr, - im_group->font_attr_len, msg_with_purple_smiley); + msg_with_purple_smiley = qq_smiley_to_purple(packet.msg); + if (packet.font_attr_len > 0) + msg_utf8_encoded = qq_encode_to_purple(packet.font_attr, + packet.font_attr_len, msg_with_purple_smiley); else msg_utf8_encoded = qq_to_utf8(msg_with_purple_smiley, QQ_CHARSET_DEFAULT); group = qq_room_search_id(gc, id); - g_return_if_fail(group != NULL); - - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); - if (conv == NULL && purple_prefs_get_bool("/plugins/prpl/qq/show_room_when_newin")) { - conv = qq_room_conv_create(gc, group); - } + qq_room_got_chat_in(gc, group, packet.member_uid, msg_utf8_encoded, packet.send_time); - if (conv != NULL) { - member = qq_group_find_member_by_uid(group, im_group->member_uid); - if (member == NULL || member->nickname == NULL) - im_src_name = uid_to_purple_name(im_group->member_uid); - else - im_src_name = g_strdup(member->nickname); - serv_got_chat_in(gc, - purple_conv_chat_get_id(PURPLE_CONV_CHAT - (conv)), im_src_name, 0, msg_utf8_encoded, im_group->send_time); - g_free(im_src_name); - } g_free(msg_with_purple_smiley); g_free(msg_utf8_encoded); - g_free(im_group->msg); - g_free(im_group->font_attr); + g_free(packet.msg); + g_free(packet.font_attr); } diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_im.h --- a/libpurple/protocols/qq/group_im.h Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_im.h Wed Oct 22 14:35:05 2008 +0000 @@ -29,6 +29,9 @@ #include "connection.h" #include "group.h" +void qq_room_got_chat_in(PurpleConnection *gc, + qq_group *group, guint32 uid_from, const gchar *msg, time_t in_time); + void qq_send_packet_group_im(PurpleConnection *gc, qq_group *group, const gchar *msg); void qq_process_group_cmd_im(guint8 *data, gint len, PurpleConnection *gc); diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_info.c --- a/libpurple/protocols/qq/group_info.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_info.c Wed Oct 22 14:35:05 2008 +0000 @@ -101,12 +101,48 @@ return num; } -void qq_process_room_cmd_get_info(guint8 *data, gint data_len, PurpleConnection *gc) +static void room_info_display(PurpleConnection *gc, qq_group *group) +{ + PurpleNotifyUserInfo *room_info; + gchar *utf8_value; + + g_return_if_fail(group != NULL && group->id > 0); + + room_info = purple_notify_user_info_new(); + + purple_notify_user_info_add_pair(room_info, _("Title"), group->title_utf8); + purple_notify_user_info_add_pair(room_info, _("Notice"), group->notice_utf8); + purple_notify_user_info_add_pair(room_info, _("Detail"), group->desc_utf8); + + purple_notify_user_info_add_section_break(room_info); + + utf8_value = g_strdup_printf(("%d"), group->creator_uid); + purple_notify_user_info_add_pair(room_info, _("Creator"), utf8_value); + g_free(utf8_value); + + purple_notify_user_info_add_pair(room_info, _("About me"), group->my_role_desc); + + utf8_value = g_strdup_printf(("%d"), group->category); + purple_notify_user_info_add_pair(room_info, _("Category"), utf8_value); + g_free(utf8_value); + + utf8_value = g_strdup_printf(("%d"), group->auth_type); + purple_notify_user_info_add_pair(room_info, _("Authorize"), utf8_value); + g_free(utf8_value); + + utf8_value = g_strdup_printf(("%d"), group->ext_id); + purple_notify_userinfo(gc, utf8_value, room_info, NULL, NULL); + g_free(utf8_value); + + purple_notify_user_info_destroy(room_info); +} + +void qq_process_room_cmd_get_info(guint8 *data, gint data_len, guint32 action, PurpleConnection *gc) { qq_group *group; qq_buddy *member; qq_data *qd; - PurpleConversation *purple_conv; + PurpleConversation *conv; guint8 organization, role; guint16 unknown, max_members; guint32 member_uid, id, ext_id; @@ -115,6 +151,7 @@ guint8 unknown1; gint bytes, num; gchar *notice; + gchar *topic_utf8; g_return_if_fail(data != NULL && data_len > 0); qd = (qq_data *) gc->proto_data; @@ -196,16 +233,22 @@ qq_group_refresh(gc, group); - purple_conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + if (action == QQ_ROOM_INFO_DISPLAY) { + room_info_display(gc, group); + } + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, group->title_utf8, purple_connection_get_account(gc)); - if(NULL == purple_conv) { + if(NULL == conv) { purple_debug_warning("QQ", "Conversation \"%s\" is not open, do not set topic\n", group->title_utf8); return; } - purple_debug_info("QQ", "Set chat topic to %s\n", group->notice_utf8); - purple_conv_chat_set_topic(PURPLE_CONV_CHAT(purple_conv), NULL, group->notice_utf8); + topic_utf8 = g_strdup_printf("%d %s", group->ext_id, group->notice_utf8); + purple_debug_info("QQ", "Set chat topic to %s\n", topic_utf8); + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv), NULL, topic_utf8); + g_free(topic_utf8); } void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc) diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_info.h --- a/libpurple/protocols/qq/group_info.h Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_info.h Wed Oct 22 14:35:05 2008 +0000 @@ -29,9 +29,14 @@ #include "connection.h" #include "group.h" +enum { + QQ_ROOM_INFO_UPDATE_ONLY = 0, + QQ_ROOM_INFO_DISPLAY, +}; + gint qq_request_room_get_buddies(PurpleConnection *gc, qq_group *group, gint update_class); -void qq_process_room_cmd_get_info(guint8 *data, gint len, PurpleConnection *gc); +void qq_process_room_cmd_get_info(guint8 *data, gint len, guint32 action, PurpleConnection *gc); void qq_process_room_cmd_get_onlines(guint8 *data, gint len, PurpleConnection *gc); void qq_process_room_cmd_get_buddies(guint8 *data, gint len, PurpleConnection *gc); #endif diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_internal.c --- a/libpurple/protocols/qq/group_internal.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_internal.c Wed Oct 22 14:35:05 2008 +0000 @@ -38,19 +38,19 @@ switch (group->my_role) { case QQ_ROOM_ROLE_NO: - role_desc = _("I am not a member"); + role_desc = _("Not member"); break; case QQ_ROOM_ROLE_YES: - role_desc = _("I am a member"); + role_desc = _("Member"); break; case QQ_ROOM_ROLE_REQUESTING: - role_desc = _("I am requesting"); + role_desc = _("Requesting"); break; case QQ_ROOM_ROLE_ADMIN: - role_desc = _("I am the admin"); + role_desc = _("Admin"); break; default: - role_desc = _("Unknown status"); + role_desc = _("Unknown"); } return g_strdup(role_desc); @@ -65,7 +65,7 @@ chat = purple_chat_new(purple_connection_get_account(gc), group->title_utf8, components); g = qq_create_group(PURPLE_GROUP_QQ_QUN); purple_blist_add_chat(chat, g, NULL); - purple_debug_info("QQ", "You have added group \"%s\" to blist locally\n", group->title_utf8); + purple_debug_info("QQ", "Added room \"%s\" to blist locally\n", group->title_utf8); } /* Create a dummy qq_group, which includes only internal_id, ext_id, diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_join.c --- a/libpurple/protocols/qq/group_join.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_join.c Wed Oct 22 14:35:05 2008 +0000 @@ -30,6 +30,7 @@ #include "server.h" #include "char_conv.h" +#include "im.h" #include "group_conv.h" #include "group_find.h" #include "group_internal.h" @@ -190,6 +191,7 @@ PurpleChat *chat; qq_group *group; qq_data *qd; + gchar *msg; g_return_if_fail(data != NULL && len > 0); qd = (qq_data *) gc->proto_data; @@ -204,13 +206,18 @@ group = qq_room_search_id(gc, id); if (group != NULL) { + msg = g_strdup_printf(_("Successed quit Qun %s (%d)"), + group->title_utf8, group->ext_id); chat = purple_blist_find_chat (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, id); + } else { + msg = g_strdup(_("Successed quit Qun")); } - purple_notify_info(gc, _("QQ Qun Operation"), _("Successed:"), _("Remove from Qun")); + qq_got_attention(gc, msg); + g_free(msg); } /* Process the reply to group_auth subcmd */ @@ -232,7 +239,7 @@ bytes += qq_get32(&id, data + bytes); g_return_if_fail(id > 0); - purple_notify_info(gc, _("QQ Qun Operation"), _("Successed:"), _("Join to Qun")); + qq_got_attention(gc, _("Successed join to Qun")); } /* process group cmd reply "join group" */ @@ -320,7 +327,7 @@ } } -void qq_group_exit(PurpleConnection *gc, GHashTable *data) +void qq_room_quit(PurpleConnection *gc, GHashTable *data) { gchar *id_ptr; guint32 id; @@ -338,7 +345,7 @@ add_req->uid = id; purple_request_action(gc, _("QQ Qun Operation"), - _("Are you sure you want to leave this Qun?"), + _("Quit Qun"), _("Note, if you are the creator, \nthis operation will eventually remove this Qun."), 1, purple_connection_get_account(gc), NULL, NULL, diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_join.h --- a/libpurple/protocols/qq/group_join.h Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_join.h Wed Oct 22 14:35:05 2008 +0000 @@ -44,7 +44,7 @@ void qq_send_cmd_group_auth(PurpleConnection *gc, qq_group *group, guint8 opt, guint32 uid, const gchar *reason_utf8); void qq_group_join(PurpleConnection *gc, GHashTable *data); void qq_request_room_join(PurpleConnection *gc, qq_group *group); -void qq_group_exit(PurpleConnection *gc, GHashTable *data); +void qq_room_quit(PurpleConnection *gc, GHashTable *data); 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); diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/group_opt.c --- a/libpurple/protocols/qq/group_opt.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/group_opt.c Wed Oct 22 14:35:05 2008 +0000 @@ -34,6 +34,7 @@ #include "group_internal.h" #include "group_info.h" #include "group_join.h" +#include "group_im.h" #include "group_opt.h" #include "qq_define.h" #include "packet_parse.h" @@ -199,6 +200,7 @@ { gint bytes; guint32 id; + time_t now = time(NULL); qq_group *group; g_return_if_fail(data != NULL); @@ -212,7 +214,7 @@ purple_debug_info("QQ", "Succeed in modify members for room %d\n", group->ext_id); - purple_notify_info(gc, _("QQ Qun Operation"), _("Successed:"), _("Change Qun member")); + qq_room_got_chat_in(gc, group, 0, _("Successed changing Qun member"), now); } void qq_room_change_info(PurpleConnection *gc, qq_group *group) @@ -265,6 +267,8 @@ gint bytes; guint32 id; qq_group *group; + time_t now = time(NULL); + g_return_if_fail(data != NULL); bytes = 0; @@ -278,7 +282,7 @@ 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"), _("Successed:"), _("Change Qun information")); + qq_room_got_chat_in(gc, group, 0, _("Successed changing Qun information"), now); } /* we create a very simple group first, and then let the user to modify */ diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/im.c --- a/libpurple/protocols/qq/im.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/im.c Wed Oct 22 14:35:05 2008 +0000 @@ -222,7 +222,7 @@ /* read the common parts of the normal_im, * returns the bytes read if succeed, or -1 if there is any error */ -static gint _qq_normal_im_common_read(guint8 *data, gint len, qq_recv_normal_im_common *common) +static gint normal_im_common_read(guint8 *data, gint len, qq_recv_normal_im_common *common) { gint bytes; g_return_val_if_fail(data != NULL && len != 0 && common != NULL, -1); @@ -243,7 +243,7 @@ return bytes; } -static void _qq_process_recv_news(guint8 *data, gint data_len, PurpleConnection *gc) +static void process_recv_news(guint8 *data, gint data_len, PurpleConnection *gc) { qq_data *qd = (qq_data *) gc->proto_data; gint bytes; @@ -278,11 +278,11 @@ url = g_strndup((gchar *)temp, temp_len); title_utf8 = qq_to_utf8(title, QQ_CHARSET_DEFAULT); - content = g_strdup_printf(_("%s\n\n%s"), brief, url); + content = g_strdup_printf(_("Server News:\n%s\n%s\n%s"), title, brief, url); content_utf8 = qq_to_utf8(content, QQ_CHARSET_DEFAULT); if (qd->is_show_news) { - purple_notify_info(gc, _("QQ Server News"), title_utf8, content_utf8); + qq_got_attention(gc, content_utf8); } else { purple_debug_info("QQ", "QQ Server news:\n%s\n%s", title_utf8, content_utf8); } @@ -294,8 +294,32 @@ g_free(content_utf8); } +void qq_got_attention(PurpleConnection *gc, const gchar *msg) +{ + qq_data *qd; + gchar *from; + PurpleBuddy *b; + qq_buddy *qq_b; + time_t now = time(NULL); + + qd = (qq_data *) gc->proto_data; + + from = uid_to_purple_name(qd->uid); + g_return_if_fail(qd->uid > 0); + + b = purple_find_buddy(gc->account, from); + if (b == NULL) { + qq_create_buddy(gc, qd->uid, FALSE, TRUE); + b = purple_find_buddy(gc->account, from); + } + qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; + g_return_if_fail(qq_b != NULL); + + serv_got_im(gc, from, msg, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NOTIFY, now); +} + /* process received normal text IM */ -static void _qq_process_recv_normal_im_text(guint8 *data, gint len, qq_recv_normal_im_common *common, PurpleConnection *gc) +static void process_recv_normal_im_text(guint8 *data, gint len, qq_recv_normal_im_common *common, PurpleConnection *gc) { guint16 purple_msg_type; gchar *name; @@ -360,7 +384,7 @@ } qq_b = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; if (qq_b != NULL) { - qq_b->client_version = common->sender_ver; + qq_b->client_tag = common->sender_ver; } purple_msg_type = (im_text->msg_type == QQ_IM_AUTO_REPLY) ? PURPLE_MESSAGE_AUTO_RESP : 0; @@ -385,7 +409,7 @@ } /* it is a normal IM, maybe text or video request */ -static void _qq_process_recv_normal_im(guint8 *data, gint len, PurpleConnection *gc) +static void process_recv_normal_im(guint8 *data, gint len, PurpleConnection *gc) { gint bytes = 0; qq_recv_normal_im_common *common; @@ -395,7 +419,7 @@ common = g_newa (qq_recv_normal_im_common, 1); - bytes = _qq_normal_im_common_read(data, len, common); + bytes = normal_im_common_read(data, len, common); if (bytes < 0) { purple_debug_error("QQ", "Fail read the common part of normal IM\n"); return; @@ -411,7 +435,7 @@ purple_debug_warning("QQ", "Received normal IM text is empty\n"); return; } - _qq_process_recv_normal_im_text(data + bytes, len - bytes, common, gc); + process_recv_normal_im_text(data + bytes, len - bytes, common, gc); break; case QQ_NORMAL_IM_FILE_REJECT_UDP: qq_process_recv_file_reject(data + bytes, len - bytes, common->sender_uid, gc); @@ -477,7 +501,7 @@ } /* process im from system administrator */ -static void _qq_process_recv_sys_im(guint8 *data, gint data_len, PurpleConnection *gc) +static void process_recv_sys_im(guint8 *data, gint data_len, PurpleConnection *gc) { gint len; guint8 reply; @@ -571,7 +595,7 @@ /* 004-007: sender uid */ bytes += qq_put32(raw_data + bytes, to_uid); /* 008-009: sender client version */ - bytes += qq_put16(raw_data + bytes, qd->client_version); + bytes += qq_put16(raw_data + bytes, qd->client_tag); /* 010-013: receiver uid */ bytes += qq_put32(raw_data + bytes, qd->uid); /* 014-017: sender uid */ @@ -686,14 +710,14 @@ switch (im_header->im_type) { case QQ_RECV_IM_NEWS: - _qq_process_recv_news(data + bytes, data_len - bytes, gc); + process_recv_news(data + bytes, data_len - bytes, gc); break; case QQ_RECV_IM_FROM_BUDDY_2006: case QQ_RECV_IM_FROM_UNKNOWN_2006: case QQ_RECV_IM_TO_UNKNOWN: case QQ_RECV_IM_TO_BUDDY: purple_debug_info("QQ", "MSG from buddy [%d]\n", im_header->sender_uid); - _qq_process_recv_normal_im(data + bytes, data_len - bytes, gc); + 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: @@ -732,7 +756,7 @@ break; case QQ_RECV_IM_SYS_NOTIFICATION: purple_debug_info("QQ", "Admin notice from [%d]\n", im_header->sender_uid); - _qq_process_recv_sys_im(data + bytes, data_len - bytes, gc); + process_recv_sys_im(data + bytes, data_len - bytes, gc); break; default: purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%02x]\n", diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/im.h --- a/libpurple/protocols/qq/im.h Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/im.h Wed Oct 22 14:35:05 2008 +0000 @@ -56,10 +56,12 @@ QQ_RECV_IM_FROM_UNKNOWN_2006 = 0x0085, }; +void qq_got_attention(PurpleConnection *gc, const gchar *msg); + guint8 *qq_get_send_im_tail(const gchar *font_color, - const gchar *font_size, - const gchar *font_name, - gboolean is_bold, gboolean is_italic, gboolean is_underline, gint len); + const gchar *font_size, + const gchar *font_name, + 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 *data, gint data_len, guint16 seq, PurpleConnection *gc); diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/qq.c Wed Oct 22 14:35:05 2008 +0000 @@ -44,6 +44,7 @@ #include "group_info.h" #include "group_join.h" #include "group_opt.h" +#include "group_internal.h" #include "qq_define.h" #include "im.h" #include "qq_process.h" @@ -156,12 +157,15 @@ purple_debug_info("QQ", "Server list has %d\n", g_list_length(qd->servers)); version_str = purple_account_get_string(account, "client_version", NULL); - qd->client_version = QQ_CLIENT_0D55; /* set default as QQ2005 */ - qd->is_above_2007 = FALSE; + qd->client_tag = QQ_CLIENT_0D55; /* set default as QQ2005 */ + qd->client_version = 2005; if (version_str != NULL && strlen(version_str) != 0) { if (strcmp(version_str, "qq2007") == 0) { - qd->client_version = QQ_CLIENT_111D; - qd->is_above_2007 = TRUE; + qd->client_tag = QQ_CLIENT_111D; + qd->client_version = 2007; + } else if (strcmp(version_str, "qq2008") == 0) { + qd->client_tag = QQ_CLIENT_115B; + qd->client_version = 2008; } } @@ -216,6 +220,7 @@ qq_disconnect(gc); if (qd->ld.token) g_free(qd->ld.token); + if (qd->ld.token_ex) g_free(qd->ld.token_ex); if (qd->captcha.token) g_free(qd->captcha.token); if (qd->captcha.data) g_free(qd->captcha.data); @@ -226,14 +231,14 @@ } /* returns the icon name for a buddy or protocol */ -static const gchar *_qq_list_icon(PurpleAccount *a, PurpleBuddy *b) +static const gchar *qq_list_icon(PurpleAccount *a, PurpleBuddy *b) { return "qq"; } /* a short status text beside buddy icon*/ -static gchar *_qq_status_text(PurpleBuddy *b) +static gchar *qq_status_text(PurpleBuddy *b) { qq_buddy *q_bud; GString *status; @@ -270,7 +275,7 @@ /* a floating text when mouse is on the icon, show connection status here */ -static void _qq_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) +static void qq_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) { qq_buddy *q_bud; gchar *tmp; @@ -349,8 +354,8 @@ #ifdef DEBUG tmp = g_strdup_printf( "%s (%04X)", - qq_get_ver_desc(q_bud->client_version), - q_bud->client_version ); + qq_get_ver_desc(q_bud->client_tag), + q_bud->client_tag ); purple_notify_user_info_add_pair(user_info, _("Ver"), tmp); g_free(tmp); @@ -362,7 +367,7 @@ } /* we can show tiny icons on the four corners of buddy icon, */ -static const char *_qq_list_emblem(PurpleBuddy *b) +static const char *qq_list_emblem(PurpleBuddy *b) { /* each char** are refering to a filename in pixmaps/purple/status/default/ */ qq_buddy *q_bud; @@ -382,7 +387,7 @@ } /* QQ away status (used to initiate QQ away packet) */ -static GList *_qq_away_states(PurpleAccount *ga) +static GList *qq_status_types(PurpleAccount *ga) { PurpleStatusType *status; GList *types = NULL; @@ -411,7 +416,7 @@ } /* initiate QQ away with proper change_status packet */ -static void _qq_change_status(PurpleAccount *account, PurpleStatus *status) +static void qq_change_status(PurpleAccount *account, PurpleStatus *status) { PurpleConnection *gc = purple_account_get_connection(account); @@ -420,7 +425,7 @@ /* IMPORTANT: PurpleConvImFlags -> PurpleMessageFlags */ /* send an instant msg to a buddy */ -static gint _qq_send_im(PurpleConnection *gc, const gchar *who, const gchar *message, PurpleMessageFlags flags) +static gint qq_send_im(PurpleConnection *gc, const gchar *who, const gchar *message, PurpleMessageFlags flags) { gint type, to_uid; gchar *msg, *msg_with_qq_smiley; @@ -450,7 +455,7 @@ } /* send a chat msg to a QQ Qun */ -static int _qq_chat_send(PurpleConnection *gc, int channel, const char *message, PurpleMessageFlags flags) +static int qq_chat_send(PurpleConnection *gc, int channel, const char *message, PurpleMessageFlags flags) { gchar *msg, *msg_with_qq_smiley; qq_group *group; @@ -561,7 +566,7 @@ g_string_append(info, "
"); g_string_append_printf(info, _("Server: %s
\n"), qd->curr_server); - g_string_append_printf(info, _("Client Version: %s
\n"), qq_get_ver_desc(qd->client_version)); + g_string_append_printf(info, _("Client Tag: %s
\n"), qq_get_ver_desc(qd->client_tag)); g_string_append_printf(info, _("Connection Mode: %s
\n"), qd->use_tcp ? "TCP" : "UDP"); g_string_append_printf(info, _("My Internet IP: %s
\n"), inet_ntoa(qd->my_ip)); @@ -605,7 +610,7 @@ } */ -static void _qq_menu_unsubscribe_group(PurpleBlistNode * node) +static void action_chat_quit(PurpleBlistNode * node) { PurpleChat *chat = (PurpleChat *)node; PurpleConnection *gc = purple_account_get_connection(chat->account); @@ -614,22 +619,34 @@ g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); g_return_if_fail(components != NULL); - qq_group_exit(gc, components); + qq_room_quit(gc, components); } -/* -static void _qq_menu_manage_group(PurpleBlistNode * node) +static void action_chat_get_info(PurpleBlistNode * node) { PurpleChat *chat = (PurpleChat *)node; PurpleConnection *gc = purple_account_get_connection(chat->account); GHashTable *components = chat -> components; + gchar *uid_str; + guint32 uid; + qq_group *group; g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); g_return_if_fail(components != NULL); - qq_group_manage_group(gc, components); + + uid_str = g_hash_table_lookup(components, QQ_ROOM_KEY_INTERNAL_ID); + uid = strtol(uid_str, NULL, 10); + + group = qq_room_search_id(gc, uid); + if (group == NULL) { + return; + } + g_return_if_fail(group->id > 0); + + qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, group->id, NULL, 0, + QQ_CMD_CLASS_UPDATE_ROOM, QQ_ROOM_INFO_DISPLAY); } -*/ #if 0 /* TODO: re-enable this */ @@ -690,31 +707,28 @@ } /* chat-related (QQ Qun) menu shown up with right-click */ -static GList *_qq_chat_menu(PurpleBlistNode *node) +static GList *qq_chat_menu(PurpleBlistNode *node) { GList *m; PurpleMenuAction *act; m = NULL; - act = purple_menu_action_new(_("Leave the QQ Qun"), PURPLE_CALLBACK(_qq_menu_unsubscribe_group), NULL, NULL); + act = purple_menu_action_new(_("Get Info"), PURPLE_CALLBACK(action_chat_get_info), NULL, NULL); m = g_list_append(m, act); - /* TODO: enable this - act = purple_menu_action_new(_("Show Details"), PURPLE_CALLBACK(_qq_menu_manage_group), NULL, NULL); + act = purple_menu_action_new(_("Quit Qun"), PURPLE_CALLBACK(action_chat_quit), NULL, NULL); m = g_list_append(m, act); - */ - return m; } /* buddy-related menu shown up with right-click */ -static GList *_qq_buddy_menu(PurpleBlistNode * node) +static GList *qq_buddy_menu(PurpleBlistNode * node) { GList *m; PurpleMenuAction *act; if(PURPLE_BLIST_NODE_IS_CHAT(node)) - return _qq_chat_menu(node); + return qq_chat_menu(node); m = NULL; @@ -732,9 +746,9 @@ return m; } -/* convert chat nickname to qq-uid to get this buddy info */ +/* convert chat nickname to uid to get this buddy info */ /* who is the nickname of buddy in QQ chat-room (Qun) */ -static void _qq_get_chat_buddy_info(PurpleConnection *gc, gint channel, const gchar *who) +static void qq_get_chat_buddy_info(PurpleConnection *gc, gint channel, const gchar *who) { gchar *purple_name; g_return_if_fail(who != NULL); @@ -744,9 +758,9 @@ qq_show_buddy_info(gc, purple_name); } -/* convert chat nickname to qq-uid to invite individual IM to buddy */ +/* convert chat nickname to uid to invite individual IM to buddy */ /* who is the nickname of buddy in QQ chat-room (Qun) */ -static gchar *_qq_get_chat_buddy_real_name(PurpleConnection *gc, gint channel, const gchar *who) +static gchar *qq_get_chat_buddy_real_name(PurpleConnection *gc, gint channel, const gchar *who) { g_return_val_if_fail(who != NULL, NULL); return chat_name_to_purple_name(who); @@ -758,21 +772,21 @@ NULL, /* user_splits */ NULL, /* protocol_options */ {"png", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND}, /* icon_spec */ - _qq_list_icon, /* list_icon */ - _qq_list_emblem, /* list_emblems */ - _qq_status_text, /* status_text */ - _qq_tooltip_text, /* tooltip_text */ - _qq_away_states, /* away_states */ - _qq_buddy_menu, /* blist_node_menu */ + qq_list_icon, /* list_icon */ + qq_list_emblem, /* list_emblems */ + qq_status_text, /* status_text */ + qq_tooltip_text, /* tooltip_text */ + qq_status_types, /* away_states */ + qq_buddy_menu, /* blist_node_menu */ qq_chat_info, /* chat_info */ qq_chat_info_defaults, /* chat_info_defaults */ qq_login, /* open */ qq_close, /* close */ - _qq_send_im, /* send_im */ + qq_send_im, /* send_im */ NULL, /* set_info */ NULL, /* send_typing */ qq_show_buddy_info, /* get_info */ - _qq_change_status, /* change status */ + qq_change_status, /* change status */ NULL, /* set_idle */ NULL, /* change_passwd */ qq_add_buddy, /* add_buddy */ @@ -790,10 +804,10 @@ NULL, /* chat_invite */ NULL, /* chat_leave */ NULL, /* chat_whisper */ - _qq_chat_send, /* chat_send */ + qq_chat_send, /* chat_send */ NULL, /* keepalive */ NULL, /* register_user */ - _qq_get_chat_buddy_info, /* get_cb_info */ + qq_get_chat_buddy_info, /* get_cb_info */ NULL, /* get_cb_away */ NULL, /* alias_buddy */ qq_change_buddys_group, /* group_buddy */ @@ -803,7 +817,7 @@ NULL, /* normalize */ qq_set_buddy_icon, /* set_buddy_icon */ NULL, /* remove_group */ - _qq_get_chat_buddy_real_name, /* get_cb_real_name */ + qq_get_chat_buddy_real_name, /* get_cb_real_name */ NULL, /* set_chat_topic */ NULL, /* find_blist_chat */ qq_roomlist_get_list, /* roomlist_get_list */ @@ -908,6 +922,11 @@ kvp->value = g_strdup("qq2007"); version_kv_list = g_list_append(version_kv_list, kvp); + kvp = g_new0(PurpleKeyValuePair, 1); + kvp->key = g_strdup(_("QQ2008")); + kvp->value = g_strdup("qq2008"); + version_kv_list = g_list_append(version_kv_list, kvp); + option = purple_account_option_list_new(_("Client Version"), "client_version", version_kv_list); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); #endif diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/qq.h --- a/libpurple/protocols/qq/qq.h Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/qq.h Wed Oct 22 14:35:05 2008 +0000 @@ -54,13 +54,16 @@ }; struct _qq_login_data { - guint8 init_key[QQ_KEY_LENGTH]; /* first encrypt key generated by client */ - guint8 *token; /* get from server*/ + guint8 random_key[QQ_KEY_LENGTH]; /* first encrypt key generated by client */ + guint8 *token; /* get from server */ guint8 token_len; - guint8 *token_ex; /* get from server*/ + guint8 *token_ex; /* get from server */ guint16 token_ex_len; - guint8 captcha_key[QQ_KEY_LENGTH]; /* encrypt key used in captcha generated by client */ - guint8 pwd_twice_md5[QQ_KEY_LENGTH]; /* password in md5 (or md5' md5) */ + guint8 pwd_2nd_md5[QQ_KEY_LENGTH]; /* password in md5 (or md5' md5) */ + guint8 pwd_4th_md5[QQ_KEY_LENGTH]; + guint8 *login_token; + guint16 login_token_len; + guint8 login_key[QQ_KEY_LENGTH]; }; struct _qq_redirect_data { @@ -101,7 +104,7 @@ guint8 status; guint8 ext_flag; guint8 comm_flag; /* details in qq_buddy_list.c */ - guint16 client_version; + guint16 client_tag; guint8 onlineTime; guint16 level; guint16 timeRemainder; @@ -140,8 +143,8 @@ GList *servers; gchar *curr_server; /* point to servers->data, do not free*/ - guint16 client_version; - gboolean is_above_2007; + guint16 client_tag; + gint client_version; struct in_addr redirect_ip; guint16 redirect_port; @@ -159,16 +162,16 @@ GList *transactions; /* check ack packet and resend */ guint32 uid; /* QQ number */ - + qq_login_data ld; qq_captcha_data captcha; - + guint8 session_key[QQ_KEY_LENGTH]; /* later use this as key in this session */ guint8 session_md5[QQ_KEY_LENGTH]; /* concatenate my uid with session_key and md5 it */ guint16 send_seq; /* send sequence number */ guint8 login_mode; /* online of invisible */ - gboolean is_login; /* used by qq-add_buddy */ + gboolean is_login; /* used by qq_add_buddy */ PurpleXfer *xfer; /* file transfer handler */ diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/qq_base.c --- a/libpurple/protocols/qq/qq_base.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.c Wed Oct 22 14:35:05 2008 +0000 @@ -44,64 +44,6 @@ #define QQ_LOGIN_REPLY_OK_PACKET_LEN 139 #define QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN 11 -/* for QQ 2003iii 0117, fixed value */ -/* static const guint8 login_23_51[29] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xbf, 0x14, 0x11, 0x20, - 0x03, 0x9d, 0xb2, 0xe6, 0xb3, 0x11, 0xb7, 0x13, - 0x95, 0x67, 0xda, 0x2c, 0x01 -}; */ - -/* for QQ 2003iii 0304, fixed value */ -/* -static const guint8 login_23_51[29] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x9a, 0x93, 0xfe, 0x85, - 0xd3, 0xd9, 0x2a, 0x41, 0xc8, 0x0d, 0xff, 0xb6, - 0x40, 0xb8, 0xac, 0x32, 0x01 -}; -*/ - -/* for QQ 2005? copy from lumaqq */ -/* FIXME: change to guint8 */ -static const guint8 login_23_51[29] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x86, 0xcc, 0x4c, 0x35, - 0x2c, 0xd3, 0x73, 0x6c, 0x14, 0xf6, 0xf6, 0xaf, - 0xc3, 0xfa, 0x33, 0xa4, 0x01 -}; - -static const guint8 login_53_68[16] = { - 0x8D, 0x8B, 0xFA, 0xEC, 0xD5, 0x52, 0x17, 0x4A, - 0x86, 0xF9, 0xA7, 0x75, 0xE6, 0x32, 0xD1, 0x6D -}; - -static const guint8 login_100_bytes[100] = { - 0x40, 0x0B, 0x04, 0x02, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xE9, 0x03, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xED, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xEC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xEE, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xEF, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xEB, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - - -/* fixed value, not affected by version, or mac address */ -/* -static const guint8 login_53_68[16] = { - 0x82, 0x2a, 0x91, 0xfd, 0xa5, 0xca, 0x67, 0x4c, - 0xac, 0x81, 0x1f, 0x6f, 0x52, 0x05, 0xa7, 0xbf -}; -*/ - - /* generate a md5 key using uid and session_key */ static void get_session_md5(guint8 *session_md5, guint32 uid, guint8 *session_key) { @@ -268,9 +210,38 @@ qq_data *qd; guint8 *buf, *raw_data; gint bytes; - guint8 *encrypted_data; + guint8 *encrypted; gint encrypted_len; + /* for QQ 2005? copy from lumaqq */ + static const guint8 login_23_51[29] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x86, 0xcc, 0x4c, 0x35, + 0x2c, 0xd3, 0x73, 0x6c, 0x14, 0xf6, 0xf6, 0xaf, + 0xc3, 0xfa, 0x33, 0xa4, 0x01 + }; + + static const guint8 login_53_68[16] = { + 0x8D, 0x8B, 0xFA, 0xEC, 0xD5, 0x52, 0x17, 0x4A, + 0x86, 0xF9, 0xA7, 0x75, 0xE6, 0x32, 0xD1, 0x6D + }; + + static const guint8 login_100_bytes[100] = { + 0x40, 0x0B, 0x04, 0x02, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xE9, 0x03, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xED, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xEC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xEE, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xEF, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xEB, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + g_return_if_fail(gc != NULL && gc->proto_data != NULL); qd = (qq_data *) gc->proto_data; @@ -279,12 +250,12 @@ 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 */ + encrypted = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ bytes = 0; /* now generate the encrypted data * 000-015 use password_twice_md5 as key to encrypt empty string */ - encrypted_len = qq_encrypt(raw_data + bytes, (guint8 *) "", 0, qd->ld.pwd_twice_md5); + encrypted_len = qq_encrypt(raw_data + bytes, (guint8 *) "", 0, qd->ld.pwd_2nd_md5); g_return_if_fail(encrypted_len == 16); bytes += encrypted_len; @@ -308,13 +279,13 @@ bytes += qq_putdata(raw_data + bytes, login_100_bytes, 100); /* all zero left */ - encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key); + encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); bytes = 0; - bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH); - bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len); + bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH); + bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); qd->send_seq++; qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); @@ -327,9 +298,9 @@ int token_len; gchar *error_msg; - g_return_val_if_fail(buf != NULL && buf_len != 0, -1); + g_return_val_if_fail(buf != NULL && buf_len != 0, QQ_LOGIN_REPLY_ERR); - g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR); qd = (qq_data *) gc->proto_data; ret = buf[0]; @@ -343,7 +314,9 @@ if (error_msg == NULL) { error_msg = g_strdup_printf( _("Invalid token reply code, 0x%02X"), ret); } - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, + error_msg); g_free(error_msg); return QQ_LOGIN_REPLY_ERR; } @@ -351,7 +324,9 @@ token_len = buf_len-2; if (token_len <= 0) { error_msg = g_strdup_printf( _("Invalid token len, %d"), token_len); - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, + error_msg); g_free(error_msg); return QQ_LOGIN_REPLY_ERR; } @@ -383,18 +358,45 @@ qd = (qq_data *) gc->proto_data; for (i = 0; i < 4; i++) - qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->ld.pwd_twice_md5, QQ_KEY_LENGTH); + qq_send_cmd(gc, QQ_CMD_LOGOUT, qd->ld.pwd_2nd_md5, QQ_KEY_LENGTH); qd->is_login = FALSE; /* update login status AFTER sending logout packets */ } +/* for QQ 2003iii 0117, fixed value */ +/* static const guint8 login_23_51[29] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbf, 0x14, 0x11, 0x20, + 0x03, 0x9d, 0xb2, 0xe6, 0xb3, 0x11, 0xb7, 0x13, + 0x95, 0x67, 0xda, 0x2c, 0x01 +}; */ + +/* for QQ 2003iii 0304, fixed value */ +/* +static const guint8 login_23_51[29] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9a, 0x93, 0xfe, 0x85, + 0xd3, 0xd9, 0x2a, 0x41, 0xc8, 0x0d, 0xff, 0xb6, + 0x40, 0xb8, 0xac, 0x32, 0x01 +}; +*/ + +/* fixed value, not affected by version, or mac address */ +/* +static const guint8 login_53_68[16] = { + 0x82, 0x2a, 0x91, 0xfd, 0xa5, 0xca, 0x67, 0x4c, + 0xac, 0x81, 0x1f, 0x6f, 0x52, 0x05, 0xa7, 0xbf +}; +*/ + /* process the login reply packet */ guint8 qq_process_login( PurpleConnection *gc, guint8 *data, gint data_len) { qq_data *qd; guint8 ret = data[0]; - gchar *server_reply, *server_reply_utf8; - gchar *error_msg; + gchar *msg, *msg_utf8; + gchar *error; + PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR); @@ -408,60 +410,42 @@ purple_debug_info("QQ", "Redirect new server\n"); return process_login_redirect(gc, data, data_len); - case QQ_LOGIN_REPLY_REDIRECT_EX: - purple_debug_error("QQ", "Extend redirect new server, not supported yet\n"); - error_msg = g_strdup( _("Unable login for not support Redirect_EX now") ); - return QQ_LOGIN_REPLY_REDIRECT_EX; - - case QQ_LOGIN_REPLY_ERR_PWD: - server_reply = g_strndup((gchar *)data + 1, data_len - 1); - server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT); - - purple_debug_error("QQ", "Error password: %s\n", server_reply_utf8); - error_msg = g_strdup_printf( _("Error password: %s"), server_reply_utf8); - - g_free(server_reply); - g_free(server_reply_utf8); - + case 0x0A: /* extend redirect used in QQ2006 */ + error = g_strdup( _("Not support Redirect_EX now") ); + reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; + break; + case 0x05: /* invalid password */ if (!purple_account_get_remember_password(gc->account)) { purple_account_set_password(gc->account, NULL); } - - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, error_msg); - g_free(error_msg); - - return QQ_LOGIN_REPLY_ERR_PWD; - - case QQ_LOGIN_REPLY_NEED_REACTIVE: - server_reply = g_strndup((gchar *)data + 1, data_len - 1); - server_reply_utf8 = qq_to_utf8(server_reply, QQ_CHARSET_DEFAULT); - - purple_debug_error("QQ", "Need active: %s\n", server_reply_utf8); - error_msg = g_strdup_printf( _("Need active: %s"), server_reply_utf8); - - g_free(server_reply); - g_free(server_reply_utf8); + error = g_strdup( _("Error password")); + reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; + break; + case 0x06: /* need activation */ + error = g_strdup( _("Need active")); + reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; break; default: - purple_debug_error("QQ", - "Unable login for unknow reply code 0x%02X\n", data[0]); - qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", - data, data_len, - ">>> [default] decrypt and dump"); - error_msg = try_dump_as_gbk(data, data_len); - if (error_msg == NULL) { - error_msg = g_strdup_printf( - _("Unable login for unknow reply code 0x%02X"), data[0] ); - } + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, + ">>> [default] decrypt and dump"); + error = g_strdup_printf( + _("Unknow reply code when checking password (0x%02X)"), + ret ); + reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR; break; } - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); - g_free(error_msg); - return ret; + msg = g_strndup((gchar *)data + 1, data_len - 1); + msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + + purple_debug_error("QQ", "%s: %s\n", error, msg_utf8); + purple_connection_error_reason(gc, reason, msg_utf8); + + g_free(error); + g_free(msg); + g_free(msg_utf8); + return QQ_LOGIN_REPLY_ERR; } /* send keep-alive packet to QQ server (it is a heart-beat) */ @@ -500,7 +484,8 @@ /* segments[0] and segment[1] are all 0x30 ("0") */ qd->online_total = strtol(segments[2], NULL, 10); if(0 == qd->online_total) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Keep alive error")); } qd->my_ip.s_addr = inet_addr(segments[3]); @@ -519,7 +504,7 @@ qq_data *qd; guint8 *buf, *raw_data; gint bytes; - guint8 *encrypted_data; + guint8 *encrypted; gint encrypted_len; g_return_if_fail(gc != NULL && gc->proto_data != NULL); @@ -528,44 +513,35 @@ 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 */ + encrypted = g_newa(guint8, QQ_LOGIN_DATA_LENGTH + 16); /* 16 bytes more */ bytes = 0; bytes += qq_putdata(raw_data + bytes, (guint8 *)&qd->redirect_data, sizeof(qd->redirect_data)); - encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key); + encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); bytes = 0; - bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH); - bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len); + bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH); + bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); qd->send_seq++; qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); } -guint16 qq_process_get_server(PurpleConnection *gc, guint8 *rcved, gint rcved_len) +guint16 qq_process_get_server(PurpleConnection *gc, guint8 *data, gint data_len) { qq_data *qd; - guint8 *data; - gint data_len; qq_redirect_data *redirect; g_return_val_if_fail (gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR); qd = (qq_data *) gc->proto_data; - data = g_newa(guint8, rcved_len); - /* May use password_twice_md5 in the past version like QQ2005*/ - data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.init_key); - if (data_len < 0) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Can not decrypt get server reply")); - return QQ_LOGIN_REPLY_ERR; - } - + g_return_val_if_fail (data != NULL, QQ_LOGIN_REPLY_ERR); if (data_len < sizeof(qq_redirect_data)) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Can not decrypt get server reply")); return QQ_LOGIN_REPLY_ERR; } @@ -587,7 +563,7 @@ qq_data *qd; guint8 *buf, *raw_data; gint bytes; - guint8 *encrypted_data; + guint8 *encrypted; gint encrypted_len; g_return_if_fail(gc != NULL && gc->proto_data != NULL); @@ -598,7 +574,7 @@ raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16); memset(raw_data, 0, MAX_PACKET_SIZE - 16); - encrypted_data = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ + encrypted = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ bytes = 0; bytes += qq_put8(raw_data + bytes, qd->ld.token_len); @@ -609,13 +585,13 @@ bytes += qq_put8(raw_data + bytes, 0); /* fragment index */ bytes += qq_put16(raw_data + bytes, 0); /* captcha token */ - encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key); + encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); bytes = 0; - bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH); - bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len); + bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH); + bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); qd->send_seq++; qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE); @@ -626,7 +602,7 @@ qq_data *qd; guint8 *buf, *raw_data; gint bytes; - guint8 *encrypted_data; + guint8 *encrypted; gint encrypted_len; g_return_if_fail(gc != NULL && gc->proto_data != NULL); @@ -637,7 +613,7 @@ raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16); memset(raw_data, 0, MAX_PACKET_SIZE - 16); - encrypted_data = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ + encrypted = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ bytes = 0; bytes += qq_put8(raw_data + bytes, qd->ld.token_len); @@ -649,13 +625,13 @@ bytes += qq_put16(raw_data + bytes, qd->captcha.token_len); /* captcha token */ bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len); - encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key); + encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); bytes = 0; - bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH); - bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len); + bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH); + bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); qd->send_seq++; qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE); @@ -669,7 +645,7 @@ qq_data *qd; guint8 *buf, *raw_data; gint bytes; - guint8 *encrypted_data; + guint8 *encrypted; gint encrypted_len; g_return_if_fail(gc != NULL && gc->proto_data != NULL); @@ -681,7 +657,7 @@ raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16); memset(raw_data, 0, MAX_PACKET_SIZE - 16); - encrypted_data = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ + encrypted = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ bytes = 0; bytes += qq_put8(raw_data + bytes, qd->ld.token_len); @@ -694,13 +670,13 @@ bytes += qq_put16(raw_data + bytes, qd->captcha.token_len); /* captcha token */ bytes += qq_putdata(raw_data + bytes, qd->captcha.token, qd->captcha.token_len); - encrypted_len = qq_encrypt(encrypted_data, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.init_key); + encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); bytes = 0; - bytes += qq_putdata(buf + bytes, qd->ld.init_key, QQ_KEY_LENGTH); - bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len); + bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH); + bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); qd->send_seq++; qq_send_cmd_encrypted(gc, QQ_CMD_TOKEN_EX, qd->send_seq, buf, bytes, TRUE); @@ -797,7 +773,7 @@ captcha_req); } -guint8 qq_process_token_ex(PurpleConnection *gc, guint8 *buf, gint buf_len) +guint8 qq_process_token_ex(PurpleConnection *gc, guint8 *data, gint data_len) { qq_data *qd; int bytes; @@ -807,41 +783,41 @@ guint16 captcha_len; guint8 curr_index; - g_return_val_if_fail(buf != NULL && buf_len != 0, -1); + g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR); - g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR); qd = (qq_data *) gc->proto_data; - ret = buf[0]; + ret = data[0]; bytes = 0; - bytes += qq_get8(&sub_cmd, buf + bytes); + bytes += qq_get8(&sub_cmd, data + bytes); bytes += 2; - bytes += qq_get8(&reply, buf + bytes); + bytes += qq_get8(&reply, data + bytes); - bytes += qq_get16(&(qd->ld.token_ex_len), buf + bytes); + bytes += qq_get16(&(qd->ld.token_ex_len), data + bytes); if (qd->ld.token_ex != NULL) g_free(qd->ld.token_ex); qd->ld.token_ex = g_new0(guint8, qd->ld.token_ex_len); - bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len , buf + bytes); + bytes += qq_getdata(qd->ld.token_ex, qd->ld.token_ex_len , data + bytes); if(reply != 1) { - purple_debug_info("QQ", "All captchaes is verified\n"); + purple_debug_info("QQ", "Captcha verified\n"); return QQ_LOGIN_REPLY_OK; } - bytes += qq_get16(&captcha_len, buf + bytes); + bytes += qq_get16(&captcha_len, data + bytes); qd->captcha.data = g_realloc(qd->captcha.data, qd->captcha.data_len + captcha_len); - bytes += qq_getdata(qd->captcha.data + qd->captcha.data_len, captcha_len, buf + bytes); + bytes += qq_getdata(qd->captcha.data + qd->captcha.data_len, captcha_len, data + bytes); qd->captcha.data_len += captcha_len; - bytes += qq_get8(&curr_index, buf + bytes); - bytes += qq_get8(&qd->captcha.next_index, buf + bytes); + bytes += qq_get8(&curr_index, data + bytes); + bytes += qq_get8(&qd->captcha.next_index, data + bytes); - bytes += qq_get16(&qd->captcha.token_len, buf + bytes); + bytes += qq_get16(&qd->captcha.token_len, data + bytes); qd->captcha.token = g_new0(guint8, qd->captcha.token_len); - bytes += qq_getdata(qd->captcha.token, qd->captcha.token_len, buf + bytes); + bytes += qq_getdata(qd->captcha.token, qd->captcha.token_len, data + bytes); if(qd->captcha.next_index > 0) { @@ -850,3 +826,425 @@ return QQ_LOGIN_REPLY_CAPTCHA_DLG; } + +/* source copy from gg's common.c */ +static guint32 crc32_table[256]; +static int crc32_initialized = 0; + +static void crc32_make_table() +{ + guint32 h = 1; + unsigned int i, j; + + memset(crc32_table, 0, sizeof(crc32_table)); + + for (i = 128; i; i >>= 1) { + h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0); + + for (j = 0; j < 256; j += 2 * i) + crc32_table[i + j] = crc32_table[j] ^ h; + } + + crc32_initialized = 1; +} + +static guint32 crc32(guint32 crc, const guint8 *buf, int len) +{ + if (!crc32_initialized) + crc32_make_table(); + + if (!buf || len < 0) + return crc; + + crc ^= 0xffffffffL; + + while (len--) + crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff]; + + return crc ^ 0xffffffffL; +} + +void qq_request_check_pwd_2007(PurpleConnection *gc) +{ + qq_data *qd; + guint8 *buf, *raw_data; + gint bytes; + guint8 *encrypted; + gint encrypted_len; + static guint8 header[] = { 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0x0E }; + + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0); + + raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16); + memset(raw_data, 0, MAX_PACKET_SIZE - 16); + + encrypted = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ + + /* Encrypted password and put in encrypted */ + bytes = 0; + bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5)); + bytes += qq_put16(raw_data + bytes, 0); + bytes += qq_put16(raw_data + bytes, 0); + + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5); + + /* create packet */ + bytes = 0; + bytes += qq_putdata(raw_data + bytes, header, sizeof(header)); + /* token get from qq_request_token_ex */ + bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len); + bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); + /* password encrypted */ + bytes += qq_put16(raw_data + bytes, encrypted_len); + bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); + /* some random data */ + bytes += qq_put16(raw_data + bytes, 0x0014); + bytes += qq_put32(raw_data + bytes, rand() & 0xffff); + bytes += qq_put32(raw_data + bytes, rand() & 0xffff); + bytes += qq_put32(raw_data + bytes, rand() & 0xffff); + bytes += qq_put32(raw_data + bytes, rand() & 0xffff); + bytes += qq_put32(raw_data + bytes, rand() & 0xffff); + /* put length into first 2 bytes */ + qq_put16(raw_data, bytes - 2); + /* tail */ + bytes += qq_put8(raw_data + bytes, 0); + bytes += qq_put8(raw_data + bytes, 0x03); + bytes += qq_put8(raw_data + bytes, 0); + bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[1]); + bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[2]); + + /* Encrypted by random key*/ + encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + + buf = g_newa(guint8, MAX_PACKET_SIZE); + memset(buf, 0, MAX_PACKET_SIZE); + bytes = 0; + bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH); + bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); + + qd->send_seq++; + qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); +} + +guint8 qq_process_check_pwd_2007( PurpleConnection *gc, guint8 *data, gint data_len) +{ + qq_data *qd; + int bytes; + guint8 ret; + guint16 unknown_len; + gchar *error = NULL; + gchar *msg, *msg_utf8; + guint16 msg_len; + PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; + + g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR); + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR); + qd = (qq_data *) gc->proto_data; + + bytes = 2; // skip 2 bytes + bytes += qq_get8(&ret, data + bytes); + bytes += 4; // skip 4 bytes + /* 2 unknow */ + bytes += qq_get16(&unknown_len, data + bytes); + bytes += unknown_len; + bytes += qq_get16(&unknown_len, data + bytes); + bytes += unknown_len; + if (ret == QQ_LOGIN_REPLY_OK) { + /* get login_token */ + bytes += qq_get16(&qd->ld.login_token_len, data + bytes); + if (qd->ld.login_token != NULL) g_free(qd->ld.login_token); + qd->ld.login_token = g_new0(guint8, qd->ld.login_token_len); + bytes += qq_getdata(qd->ld.login_token, qd->ld.login_token_len, data + bytes); + /* get login_key */ + bytes += qq_getdata(qd->ld.login_key, sizeof(qd->ld.login_key), data + bytes); + return QQ_LOGIN_REPLY_OK; + } + + switch (ret) + { + case 0x34: /* invalid password */ + if (!purple_account_get_remember_password(gc->account)) { + purple_account_set_password(gc->account, NULL); + } + error = g_strdup(_("Error password")); + reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; + break; + case 0x33: /* need activation */ + case 0x51: /* need activation */ + error = g_strdup(_("Need active")); + reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; + break; + case 0xBF: /* uid is not exist */ + error = g_strdup(_("invalid user name")); + reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME; + break; + default: + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, + ">>> [default] decrypt and dump"); + error = g_strdup_printf( + _("Unknow reply code when checking password (0x%02X)"), + ret ); + reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR; + break; + } + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, + ">>> [default] decrypt and dump"); + bytes = 1; + bytes += qq_get16(&msg_len, data + bytes); + + msg = g_strndup((gchar *)data + bytes, msg_len); + msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + + purple_debug_error("QQ", "%s: %s\n", error, msg_utf8); + purple_connection_error_reason(gc, reason, msg_utf8); + + g_free(error); + g_free(msg); + g_free(msg_utf8); + return QQ_LOGIN_REPLY_ERR; +} + +guint8 qq_process_check_pwd_2008( PurpleConnection *gc, guint8 *data, gint data_len) +{ + qq_data *qd; + int bytes; + guint8 ret; + gchar *error = NULL; + gchar *msg, *msg_utf8; + guint16 msg_len; + PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; + + g_return_val_if_fail(data != NULL && data_len != 0, QQ_LOGIN_REPLY_ERR); + + g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR); + qd = (qq_data *) gc->proto_data; + + bytes = 1; // skip 1 bytes, always 0 + bytes += qq_get8(&ret, data + bytes); + if (ret == 0x97) { + /* get login_token */ + bytes += qq_get16(&qd->ld.login_token_len, data); + if (qd->ld.login_token != NULL) g_free(qd->ld.login_token); + qd->ld.login_token = g_new0(guint8, qd->ld.login_token_len); + bytes += qq_getdata(qd->ld.login_token, qd->ld.login_token_len, data + bytes); + /* get login_key */ + bytes += qq_getdata(qd->ld.login_key, sizeof(qd->ld.login_key), data + bytes); + return QQ_LOGIN_REPLY_OK; + } + + switch (ret) + { + case 0xc6: /* invalid password */ + if (!purple_account_get_remember_password(gc->account)) { + purple_account_set_password(gc->account, NULL); + } + error = g_strdup(_("Error password")); + reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; + break; + case 0x33: /* need activation */ + case 0x51: /* need activation */ + error = g_strdup(_("Need active")); + reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; + break; + case 0xBF: /* uid is not exist */ + error = g_strdup(_("invalid user name")); + reason = PURPLE_CONNECTION_ERROR_INVALID_USERNAME; + break; + default: + qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ", data, data_len, + ">>> [default] decrypt and dump"); + error = g_strdup_printf( + _("Unknow reply code when checking password (0x%02X)"), + ret ); + reason = PURPLE_CONNECTION_ERROR_OTHER_ERROR; + break; + } + + bytes = 11; + bytes += qq_get16(&msg_len, data + bytes); + + msg = g_strndup((gchar *)data + bytes, msg_len); + msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT); + + purple_debug_error("QQ", "%s: %s\n", error, msg_utf8); + purple_connection_error_reason(gc, reason, msg_utf8); + + g_free(error); + g_free(msg); + g_free(msg_utf8); + return QQ_LOGIN_REPLY_ERR; +} + +void qq_request_check_pwd_2008(PurpleConnection *gc) +{ + qq_data *qd; + guint8 *buf, *raw_data; + gint bytes; + guint8 *encrypted; + gint encrypted_len; + static guint8 header[] = { 0x00, 0x5F, 0x00, 0x00, 0x08, 0x04, 0x01, 0xE0 }; + static guint8 unknown[] = { 0xDB, 0xB9, 0xF3, 0x0B, 0xF9, 0x13, 0x87, 0xB2, + 0xE6, 0x20, 0x43, 0xBE, 0x53, 0xCA, 0x65, 0x03 }; + + g_return_if_fail(gc != NULL && gc->proto_data != NULL); + qd = (qq_data *) gc->proto_data; + + g_return_if_fail(qd->ld.token != NULL && qd->ld.token_len > 0); + + raw_data = g_newa(guint8, MAX_PACKET_SIZE - 16); + memset(raw_data, 0, MAX_PACKET_SIZE - 16); + + encrypted = g_newa(guint8, MAX_PACKET_SIZE); /* 16 bytes more */ + + /* Encrypted password and put in encrypted */ + bytes = 0; + bytes += qq_putdata(raw_data + bytes, qd->ld.pwd_2nd_md5, sizeof(qd->ld.pwd_2nd_md5)); + bytes += qq_put16(raw_data + bytes, 0); + bytes += qq_put16(raw_data + bytes, (guint16) (rand() & 0xffff)); + + encrypted_len = qq_encrypt(encrypted, raw_data, bytes, qd->ld.pwd_4th_md5); + + /* create packet */ + bytes = 0; + bytes += qq_putdata(raw_data + bytes, header, sizeof(header)); + /* token get from qq_request_token_ex */ + bytes += qq_put16(raw_data + bytes, qd->ld.token_ex_len); + bytes += qq_putdata(raw_data + bytes, qd->ld.token_ex, qd->ld.token_ex_len); + bytes += qq_put8(raw_data + bytes, 0); + /* password encrypted */ + bytes += qq_put16(raw_data + bytes, encrypted_len); + bytes += qq_putdata(raw_data + bytes, encrypted, encrypted_len); + bytes += qq_put8(raw_data + bytes, 0); + /* len of unknown + len of CRC32 */ + bytes += qq_put8(raw_data + bytes, sizeof(unknown) + 4); + bytes += qq_putdata(raw_data + bytes, unknown, sizeof(unknown)); + bytes += qq_put32( + raw_data + bytes, crc32(0xFFFFFFFF, unknown, sizeof(unknown))); + /* put length into first 2 bytes */ + qq_put16(raw_data, bytes - 2); + /* tail */ + bytes += qq_put8(raw_data + bytes, 0); + bytes += qq_put8(raw_data + bytes, 0x03); + bytes += qq_put8(raw_data + bytes, 0); + bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[1]); + bytes += qq_put8(raw_data + bytes, qd->ld.pwd_2nd_md5[2]); + + /* Encrypted by random key*/ + encrypted_len = qq_encrypt(encrypted, raw_data, QQ_LOGIN_DATA_LENGTH, qd->ld.random_key); + + buf = g_newa(guint8, MAX_PACKET_SIZE); + memset(buf, 0, MAX_PACKET_SIZE); + bytes = 0; + bytes += qq_putdata(buf + bytes, qd->ld.random_key, QQ_KEY_LENGTH); + bytes += qq_putdata(buf + bytes, encrypted, encrypted_len); + + qd->send_seq++; + qq_send_cmd_encrypted(gc, QQ_CMD_LOGIN, qd->send_seq, buf, bytes, TRUE); +} + +/* +static void qq_send_packet_login2007(PurpleConnection *gc) +{ + qq_data *qd; + guint8 *buf, *cursor, *cursor_verify_data; + guint16 seq_ret; + gint encrypted_len, bytes; + gint pos, bodyOffset, encrypted_data_bytes, tail_offset, body_length, temp_pos; + guint8 verifyData[QQ_LOGIN_DATA_LENGTH], raw_data[QQ_LOGIN_ENCRYPT_BUFFER], encrypted_data[QQ_LOGIN_DATA_LENGTH]; + + memset(raw_data, 0, QQ_LOGIN_ENCRYPT_BUFFER); + memset(verifyData, 0, QQ_LOGIN_DATA_LENGTH); + memset(encrypted_data, 0, QQ_LOGIN_DATA_LENGTH); + qd = (qq_data *) gc->proto_data; + buf = g_newa(guint8, MAX_PACKET_SIZE); + + cursor = buf; + bytes = 0; + bytes += _create_packet_head_seq(buf, &cursor, gc, QQ_CMD_LOGIN, TRUE, &seq_ret); + bytes += create_packet_dw(buf, &cursor, qd->uid); + + bodyOffset = bytes; + + bytes += create_packet_w(buf, &cursor, qd->passport_key_lenght); + bytes += create_packet_data(buf, &cursor, qd->passport_key, qd->passport_key_lenght); + bytes += create_packet_w(buf, &cursor, 0); + pos = bytes; + bytes += 2; + cursor += 2; + + encrypted_data_bytes = 0; + cursor_verify_data = verifyData; + encrypted_data_bytes += create_packet_data(verifyData, &cursor_verify_data, qd->pwkey, QQ_KEY_LENGTH); + encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 0); + encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 0); + encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 255); + encrypted_data_bytes += create_packet_b(verifyData, &cursor_verify_data, 255); +// encrypted_data_bytes += create_packet_w(verifyData, &cursor_verify_data, 0); + + qq_encrypt(verifyData, encrypted_data_bytes, qd->pwkey_double, encrypted_data, &encrypted_len); + bytes += create_packet_data(buf, &cursor, encrypted_data, encrypted_len); + + temp_pos = bytes; + bytes = pos; + cursor = buf+bytes; + bytes += create_packet_w(buf, &cursor, encrypted_len); + bytes = temp_pos; + cursor = buf+bytes; + + qq_encrypt((guint8 *) "", 0, qd->pwkey_double, raw_data, &encrypted_len); + bytes += create_packet_data(buf, &cursor, raw_data, encrypted_len); + + g_memmove(buf+bytes, kQQFixedContent1_35, 35); + bytes += 35; + cursor = buf+bytes; + + bytes += create_packet_b(buf, &cursor, g_random_int_range (0,255)); + bytes += create_packet_b(buf, &cursor, qd->login_mode); + + bytes += create_packet_dw(buf, &cursor, 0); + bytes += create_packet_dw(buf, &cursor, 0); + bytes += create_packet_w(buf, &cursor, 0); + + bytes += create_packet_data(buf, &cursor, qd->selected_server, qd->selected_server_lenght); + + g_memmove(buf+bytes, kQQFixedContent2_16, 16); + bytes += 16; + cursor = buf+bytes; + + bytes += create_packet_b(buf, &cursor, qd->login_token_lenght); + bytes += create_packet_data(buf, &cursor, qd->login_token, qd->login_token_lenght); + + g_memmove(buf+bytes, kQQFixedContent3_332, 332); + bytes += 332; + cursor = buf+bytes; + + tail_offset = bytes; + body_length = tail_offset - bodyOffset; + + memset(raw_data, 0, QQ_LOGIN_ENCRYPT_BUFFER); + encrypted_len = body_length; +// qq_encrypt(buf+passport_length+2+11, body_length-passport_length-2 , qd->pwkey, raw_data, &encrypted_len); + qq_encrypt(buf+qd->passport_key_lenght+2+11, body_length-qd->passport_key_lenght-2 , qd->login_key, raw_data, &encrypted_len); + bytes = qd->passport_key_lenght+2+11; + cursor = buf+bytes; + bytes += create_packet_data(buf, &cursor, raw_data, encrypted_len); + bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL); + + if (bytes == (cursor - buf)) // packet creation OK + _qq_send_packet(gc, buf, bytes, QQ_CMD_LOGIN); + else + purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create login packet\n"); + +} + */ +void qq_request_login_2007(PurpleConnection *gc) +{ +} + +void qq_request_login_2008(PurpleConnection *gc) +{ +} diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/qq_base.h --- a/libpurple/protocols/qq/qq_base.h Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/qq_base.h Wed Oct 22 14:35:05 2008 +0000 @@ -30,13 +30,9 @@ #define QQ_LOGIN_REPLY_OK 0x00 #define QQ_LOGIN_REPLY_REDIRECT 0x01 -#define QQ_LOGIN_REPLY_ERR_PWD 0x05 -#define QQ_LOGIN_REPLY_NEED_REACTIVE 0x06 -#define QQ_LOGIN_REPLY_REDIRECT_EX 0x0A /* defined by myself */ #define QQ_LOGIN_REPLY_CAPTCHA_DLG 0xfc #define QQ_LOGIN_REPLY_NEXT_TOKEN_EX 0xfd -#define QQ_LOGIN_REPLY_ERR_DECRYPT 0xfe #define QQ_LOGIN_REPLY_ERR 0xff #define QQ_LOGIN_MODE_NORMAL 0x0a @@ -48,11 +44,6 @@ void qq_request_token(PurpleConnection *gc); guint8 qq_process_token(PurpleConnection *gc, guint8 *buf, gint buf_len); -void qq_request_token_ex(PurpleConnection *gc); -void qq_request_token_ex_next(PurpleConnection *gc); -guint8 qq_process_token_ex(PurpleConnection *gc, guint8 *buf, gint buf_len); -void qq_captcha_input_dialog(PurpleConnection *gc,qq_captcha_data *captcha); - void qq_request_login(PurpleConnection *gc); guint8 qq_process_login( PurpleConnection *gc, guint8 *data, gint data_len); @@ -61,7 +52,24 @@ void qq_request_keep_alive(PurpleConnection *gc); gboolean qq_process_keep_alive(guint8 *data, gint data_len, PurpleConnection *gc); -/* for QQ2007 */ +/* for QQ2007/2008 */ void qq_request_get_server(PurpleConnection *gc); guint16 qq_process_get_server(PurpleConnection *gc, guint8 *rcved, gint rcved_len); + +void qq_request_token_ex(PurpleConnection *gc); +void qq_request_token_ex_next(PurpleConnection *gc); +guint8 qq_process_token_ex(PurpleConnection *gc, guint8 *buf, gint buf_len); +void qq_captcha_input_dialog(PurpleConnection *gc,qq_captcha_data *captcha); + +void qq_request_check_pwd_2007(PurpleConnection *gc); +guint8 qq_process_check_pwd_2007( PurpleConnection *gc, guint8 *data, gint data_len); + +void qq_request_check_pwd_2008(PurpleConnection *gc); +guint8 qq_process_check_pwd_2008( PurpleConnection *gc, guint8 *data, gint data_len); + +void qq_request_login_2007(PurpleConnection *gc); +guint8 qq_process_login_2007( PurpleConnection *gc, guint8 *data, gint data_len); + +void qq_request_login_2008(PurpleConnection *gc); +guint8 qq_process_login_2008( PurpleConnection *gc, guint8 *data, gint data_len); #endif diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/qq_define.c --- a/libpurple/protocols/qq/qq_define.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/qq_define.c Wed Oct 22 14:35:05 2008 +0000 @@ -51,9 +51,8 @@ #define QQ_CLIENT_0F4B 0x0F4B /* QQ2006 Beta 3 */ #define QQ_CLIENT_1105 0x1105 /* QQ2007 beta4*/ -#define QQ_CLIENT_115B 0x115B /* QQ2008 */ #define QQ_CLIENT_1203 0x1203 /* QQ2008 */ -#define QQ_CLIENT_1205 0x1205 /* QQ2008 */ +#define QQ_CLIENT_1205 0x1205 /* QQ2008 Qi Fu */ #define QQ_CLIENT_120B 0x120B /* QQ2008 July 8.0.978.400 */ #define QQ_CLIENT_1412 0x1412 /* QQMac 1.0 preview1 build 670 */ #define QQ_CLIENT_1441 0x1441 /* QQ2009 preview2 */ @@ -174,6 +173,18 @@ return "QQ_CMD_RECV_MSG_SYS"; case QQ_CMD_BUDDY_CHANGE_STATUS: return "QQ_CMD_BUDDY_CHANGE_STATUS"; + case QQ_CMD_GET_SERVER: + return "QQ_CMD_GET_SERVER"; + case QQ_CMD_TOKEN_EX: + return "QQ_CMD_TOKEN_EX"; + case QQ_CMD_CHECK_PWD: + return "QQ_CMD_CHECK_PWD"; + case QQ_CMD_BUDDY_AUTH: + return "QQ_CMD_BUDDY_AUTH"; + case QQ_CMD_BUDDY_ADD_NO_AUTH_EX: + return "QQ_CMD_BUDDY_ADD_NO_AUTH_EX"; + case QQ_CMD_BUDDY_ADD_AUTH_EX: + return "QQ_CMD_BUDDY_ADD_AUTH_EX"; default: return "Unknown CMD"; } diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/qq_define.h --- a/libpurple/protocols/qq/qq_define.h Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/qq_define.h Wed Oct 22 14:35:05 2008 +0000 @@ -35,6 +35,7 @@ #define QQ_CLIENT_0D55 0x0d55 /* QQ2005 used by openq before */ #define QQ_CLIENT_111D 0x111D /* QQ2007 */ +#define QQ_CLIENT_115B 0x115B /* QQ2008 He Sui*/ const gchar *qq_get_ver_desc(gint source); @@ -69,7 +70,7 @@ QQ_CMD_GET_SERVER = 0x0091, /* select login server */ QQ_CMD_TOKEN_EX = 0x00BA, /* get LOGIN token */ QQ_CMD_CHECK_PWD = 0x00DD, /* Password verify */ - QQ_CMD_GET_CAPTCHA = 0x00AE, /* the request verification of information */ + QQ_CMD_BUDDY_AUTH = 0x00AE, /* the request verification of information */ QQ_CMD_BUDDY_ADD_NO_AUTH_EX = 0x00A7, /* add friend without auth */ QQ_CMD_BUDDY_ADD_AUTH_EX = 0x00A8, /* add buddy with auth */ }; diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/qq_network.c --- a/libpurple/protocols/qq/qq_network.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/qq_network.c Wed Oct 22 14:35:05 2008 +0000 @@ -202,7 +202,8 @@ if (qd->curr_server == NULL || strlen (qd->curr_server) == 0 || qd->connect_retry <= 0) { if ( set_new_server(qd) != TRUE) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Failed to connect all servers")); return FALSE; } @@ -220,7 +221,8 @@ qd->connect_retry--; if ( !connect_to_server(gc, server, port) ) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect.")); } @@ -353,7 +355,8 @@ qd = (qq_data *) gc->proto_data; if(cond != PURPLE_INPUT_READ) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Socket error")); return; } @@ -377,7 +380,9 @@ return; error_msg = g_strdup_printf(_("Lost connection with server:\n%d, %s"), errno, g_strerror(errno)); - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + error_msg); g_free(error_msg); return; } else if (buf_len == 0) { @@ -479,7 +484,8 @@ qd = (qq_data *) gc->proto_data; if(cond != PURPLE_INPUT_READ) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Socket error")); return; } @@ -489,7 +495,8 @@ /* here we have UDP proxy suppport */ buf_len = read(source, buf, MAX_PACKET_SIZE); if (buf_len <= 0) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to read from socket")); return; } @@ -537,7 +544,9 @@ if (ret < 0) { /* TODO: what to do here - do we really have to disconnect? */ purple_debug_error("UDP_SEND_OUT", "Send failed: %d, %s\n", errno, g_strerror(errno)); - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + g_strerror(errno)); } return ret; } @@ -569,8 +578,9 @@ return; else if (ret < 0) { /* TODO: what to do here - do we really have to disconnect? */ - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Write Error")); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Write Error")); return; } @@ -614,7 +624,9 @@ /* TODO: what to do here - do we really have to disconnect? */ purple_debug_error("TCP_SEND_OUT", "Send to socket %d failed: %d, %s\n", qd->fd, errno, g_strerror(errno)); - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno)); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + g_strerror(errno)); return ret; } @@ -641,7 +653,8 @@ is_lost_conn = qq_trans_scan(gc); if (is_lost_conn) { purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Connection lost")); + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Connection lost")); return TRUE; } @@ -674,6 +687,8 @@ { qq_data *qd; const gchar *passwd; + guint8 *dest; + int dest_len = QQ_KEY_LENGTH; /* _qq_show_socket("Got login socket", source); */ @@ -689,14 +704,10 @@ qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10); #ifdef DEBUG - memset(qd->ld.init_key, 0x01, sizeof(qd->ld.init_key)); - memset(qd->ld.captcha_key, 0x02, sizeof(qd->ld.captcha_key)); + memset(qd->ld.random_key, 0x01, sizeof(qd->ld.random_key)); #else - for (bytes = 0; bytes < sizeof(qd->ld.init_key); bytes++) { - qd->ld.init_key[bytes] = (guint8) (rand() & 0xff); - } - for (bytes = 0; bytes < sizeof(qd->captcha_key); bytes++) { - qd->captcha_key[bytes] = (guint8) (rand() & 0xff); + for (bytes = 0; bytes < sizeof(qd->ld.random_key); bytes++) { + qd->ld.random_key[bytes] = (guint8) (rand() & 0xff); } #endif @@ -704,11 +715,13 @@ passwd = purple_account_get_password(purple_connection_get_account(gc)); /* use twice-md5 of user password as session key since QQ 2003iii */ - qq_get_md5(qd->ld.pwd_twice_md5, sizeof(qd->ld.pwd_twice_md5), - (guint8 *)passwd, strlen(passwd)); - qq_get_md5(qd->ld.pwd_twice_md5, sizeof(qd->ld.pwd_twice_md5), - qd->ld.pwd_twice_md5, sizeof(qd->ld.pwd_twice_md5)); + dest = qd->ld.pwd_2nd_md5; + qq_get_md5(dest, dest_len, (guint8 *)passwd, strlen(passwd)); + qq_get_md5(dest, dest_len, dest, dest_len); + dest = qd->ld.pwd_4th_md5; + qq_get_md5(dest, dest_len, qd->ld.pwd_2nd_md5, dest_len); + qq_get_md5(dest, dest_len, dest, dest_len); } /* the callback function after socket is built @@ -758,7 +771,7 @@ set_all_keys( gc ); - if (qd->is_above_2007) { + if (qd->client_version > 2005) { purple_connection_update_progress(gc, _("Get server ..."), 2, QQ_CONNECT_STEPS); qq_request_get_server(gc); return; @@ -836,8 +849,8 @@ if (!hosts || !hosts->data) { purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Couldn't resolve host")); + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Couldn't resolve host")); return; } @@ -915,7 +928,8 @@ qd = (qq_data *) gc->proto_data; if (server == NULL || strlen(server) == 0 || port == 0) { - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Invalid server or port")); return FALSE; } @@ -1006,9 +1020,10 @@ qq_trans_remove_all(gc); - memset(qd->ld.init_key, 0, sizeof(qd->ld.init_key)); - memset(qd->ld.captcha_key, 0, sizeof(qd->ld.captcha_key)); - memset(qd->ld.pwd_twice_md5, 0, sizeof(qd->ld.pwd_twice_md5)); + memset(qd->ld.random_key, 0, sizeof(qd->ld.random_key)); + memset(qd->ld.pwd_2nd_md5, 0, sizeof(qd->ld.pwd_2nd_md5)); + memset(qd->ld.pwd_4th_md5, 0, sizeof(qd->ld.pwd_4th_md5)); + memset(qd->ld.login_key, 0, sizeof(qd->ld.login_key)); memset(qd->session_key, 0, sizeof(qd->session_key)); memset(qd->session_md5, 0, sizeof(qd->session_md5)); @@ -1032,7 +1047,7 @@ } /* now comes the normal QQ packet as UDP */ bytes += qq_put8(buf + bytes, QQ_PACKET_TAG); - bytes += qq_put16(buf + bytes, qd->client_version); + bytes += qq_put16(buf + bytes, qd->client_tag); bytes += qq_put16(buf + bytes, cmd); bytes += qq_put16(buf + bytes, seq); @@ -1079,7 +1094,7 @@ } gint qq_send_cmd_encrypted(PurpleConnection *gc, guint16 cmd, guint16 seq, - guint8 *encrypted_data, gint encrypted_len, gboolean is_save2trans) + guint8 *encrypted, gint encrypted_len, gboolean is_save2trans) { gint sent_len; @@ -1089,9 +1104,9 @@ seq, qq_get_cmd_desc(cmd), cmd, encrypted_len); #endif - sent_len = packet_send_out(gc, cmd, seq, encrypted_data, encrypted_len); + sent_len = packet_send_out(gc, cmd, seq, encrypted, encrypted_len); if (is_save2trans) { - qq_trans_add_client_cmd(gc, cmd, seq, encrypted_data, encrypted_len, 0, 0); + qq_trans_add_client_cmd(gc, cmd, seq, encrypted, encrypted_len, 0, 0); } return sent_len; } @@ -1101,7 +1116,7 @@ guint8 *data, gint data_len, gboolean is_save2trans, gint update_class, guint32 ship32) { qq_data *qd; - guint8 *encrypted_data; + guint8 *encrypted; gint encrypted_len; gint bytes_sent; @@ -1110,18 +1125,18 @@ g_return_val_if_fail(data != NULL && data_len > 0, -1); /* at most 16 bytes more */ - encrypted_data = g_newa(guint8, data_len + 16); - encrypted_len = qq_encrypt(encrypted_data, data, data_len, qd->session_key); + encrypted = g_newa(guint8, data_len + 16); + encrypted_len = qq_encrypt(encrypted, data, data_len, qd->session_key); if (encrypted_len < 16) { purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] 0x%04X %s\n", encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); return -1; } - bytes_sent = packet_send_out(gc, cmd, seq, encrypted_data, encrypted_len); + bytes_sent = packet_send_out(gc, cmd, seq, encrypted, encrypted_len); if (is_save2trans) { - qq_trans_add_client_cmd(gc, cmd, seq, encrypted_data, encrypted_len, + qq_trans_add_client_cmd(gc, cmd, seq, encrypted, encrypted_len, update_class, ship32); } return bytes_sent; @@ -1174,7 +1189,7 @@ gint qq_send_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { qq_data *qd; - guint8 *encrypted_data; + guint8 *encrypted; gint encrypted_len; gint bytes_sent; @@ -1187,16 +1202,16 @@ seq, qq_get_cmd_desc(cmd), cmd, data_len); #endif /* at most 16 bytes more */ - encrypted_data = g_newa(guint8, data_len + 16); - encrypted_len = qq_encrypt(encrypted_data, data, data_len, qd->session_key); + encrypted = g_newa(guint8, data_len + 16); + encrypted_len = qq_encrypt(encrypted, data, data_len, qd->session_key); if (encrypted_len < 16) { purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] 0x%04X %s\n", encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); return -1; } - bytes_sent = packet_send_out(gc, cmd, seq, encrypted_data, encrypted_len); - qq_trans_add_server_reply(gc, cmd, seq, encrypted_data, encrypted_len); + bytes_sent = packet_send_out(gc, cmd, seq, encrypted, encrypted_len); + qq_trans_add_server_reply(gc, cmd, seq, encrypted, encrypted_len); return bytes_sent; } @@ -1207,7 +1222,7 @@ qq_data *qd; guint8 *buf; gint buf_len; - guint8 *encrypted_data; + guint8 *encrypted; gint encrypted_len; gint bytes_sent; guint16 seq; @@ -1232,17 +1247,17 @@ qd->send_seq++; seq = qd->send_seq; - /* Encrypt to encrypted_data with session_key */ + /* Encrypt to encrypted 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); + encrypted = g_newa(guint8, buf_len + 16); + encrypted_len = qq_encrypt(encrypted, buf, buf_len, qd->session_key); if (encrypted_len < 16) { purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] %s (0x%02X)\n", encrypted_len, seq, qq_get_room_cmd_desc(room_cmd), room_cmd); return -1; } - bytes_sent = packet_send_out(gc, QQ_CMD_ROOM, seq, encrypted_data, encrypted_len); + bytes_sent = packet_send_out(gc, QQ_CMD_ROOM, seq, encrypted, encrypted_len); #if 1 /* qq_show_packet("send_room_cmd", buf, buf_len); */ purple_debug_info("QQ", @@ -1250,7 +1265,7 @@ seq, qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len); #endif - qq_trans_add_room_cmd(gc, seq, room_cmd, room_id, encrypted_data, encrypted_len, + qq_trans_add_room_cmd(gc, seq, room_cmd, room_id, encrypted, encrypted_len, update_class, ship32); return bytes_sent; } @@ -1258,6 +1273,7 @@ gint qq_send_room_cmd_mess(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len, gint update_class, guint32 ship32) { + g_return_val_if_fail(room_id > 0, -1); return send_room_cmd(gc, room_cmd, room_id, data, data_len, update_class, ship32); } diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/qq_process.c --- a/libpurple/protocols/qq/qq_process.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/qq_process.c Wed Oct 22 14:35:05 2008 +0000 @@ -82,7 +82,7 @@ } /* Send ACK if the sys message needs an ACK */ -static void _qq_send_packet_ack_msg_sys(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq) +static void ack_server_msg(PurpleConnection *gc, guint8 code, guint32 from, guint16 seq) { qq_data *qd; guint8 bar, *ack; @@ -112,7 +112,7 @@ "Fail creating sys msg ACK, expect %d bytes, build %d bytes\n", ack_len, bytes); } -static void _qq_process_msg_sys_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) +static void process_server_notice(PurpleConnection *gc, gchar *from, gchar *to, gchar *msg_utf8) { qq_data *qd = (qq_data *) gc->proto_data; gchar *title, *content; @@ -120,13 +120,13 @@ g_return_if_fail(from != NULL && to != NULL); title = g_strdup_printf(_("From %s:"), from); - content = g_strdup_printf(_("%s"), msg_utf8); + content = g_strdup_printf(_("Server notice From %s: \n%s"), from, msg_utf8); if (qd->is_show_notice) { - purple_notify_info(gc, _("QQ Server Notice"), title, content); + qq_got_attention(gc, content); } else { purple_debug_info("QQ", "QQ Server notice from %s:\n%s", from, msg_utf8); -} + } g_free(title); g_free(content); } @@ -148,7 +148,7 @@ to = segments[2]; msg = segments[3]; - _qq_send_packet_ack_msg_sys(gc, code[0], strtol(from, NULL, 10), seq); + ack_server_msg(gc, code[0], strtol(from, NULL, 10), seq); if (strtol(to, NULL, 10) != qd->uid) { /* not to me */ purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to); @@ -173,13 +173,14 @@ qq_process_buddy_from_server(gc, funct, from, to, msg_utf8); break; case QQ_SERVER_NOTICE: - _qq_process_msg_sys_notice(gc, from, to, msg_utf8); + process_server_notice(gc, from, to, msg_utf8); break; case QQ_SERVER_NEW_CLIENT: purple_debug_warning("QQ", "QQ Server has newer client version\n"); break; default: purple_debug_warning("QQ", "Recv unknown sys msg code: %s\nMsg: %s\n", code, msg_utf8); + break; } g_free(msg_utf8); g_strfreev(segments); @@ -509,7 +510,7 @@ /* 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); + qq_process_room_cmd_get_info(data + bytes, data_len - bytes, ship32, gc); break; case QQ_ROOM_CMD_CREATE: qq_group_process_create_group_reply(data + bytes, data_len - bytes, gc); @@ -588,7 +589,7 @@ switch (cmd) { case QQ_CMD_TOKEN: if (qq_process_token(gc, rcved, rcved_len) == QQ_LOGIN_REPLY_OK) { - if (qd->is_above_2007) { + if (qd->client_version > 2005) { qq_request_token_ex(gc); } else { qq_request_login(gc); @@ -598,17 +599,29 @@ return QQ_LOGIN_REPLY_ERR; case QQ_CMD_GET_SERVER: case QQ_CMD_TOKEN_EX: - data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.init_key); + data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.random_key); + break; + case QQ_CMD_CHECK_PWD: + /* May use password_twice_md5 in the past version like QQ2005 */ + data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.random_key); + if (data_len >= 0) { + purple_debug_warning("QQ", "Decrypt login packet by random_key, %d bytes\n", data_len); + } else { + data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.pwd_4th_md5); + if (data_len >= 0) { + purple_debug_warning("QQ", "Decrypt login packet by pwd_4th_md5, %d bytes\n", data_len); + } + } break; default: /* May use password_twice_md5 in the past version like QQ2005 */ - data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.init_key); + data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.random_key); if (data_len >= 0) { - purple_debug_warning("QQ", "Decrypt login packet by init_key, %d bytes\n", data_len); + purple_debug_warning("QQ", "Decrypt login packet by random_key, %d bytes\n", data_len); } else { - data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.pwd_twice_md5); + data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.pwd_2nd_md5); if (data_len >= 0) { - purple_debug_warning("QQ", "Decrypt login packet by password_twice_md5, %d bytes\n", data_len); + purple_debug_warning("QQ", "Decrypt login packet by pwd_2nd_md5, %d bytes\n", data_len); } } break; @@ -620,9 +633,9 @@ seq, cmd, qq_get_cmd_desc(cmd), rcved_len); qq_show_packet("Can not decrypted", rcved, rcved_len); purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, _("Can not decrypt login reply")); - return QQ_LOGIN_REPLY_ERR_DECRYPT; + return QQ_LOGIN_REPLY_ERR; } switch (cmd) { @@ -637,7 +650,11 @@ case QQ_CMD_TOKEN_EX: ret_8 = qq_process_token_ex(gc, data, data_len); if (ret_8 == QQ_LOGIN_REPLY_OK) { - //qq_request_check_password(gc); + if (qd->client_version == 2008) { + qq_request_check_pwd_2008(gc); + } else { + qq_request_check_pwd_2007(gc); + } } else if (ret_8 == QQ_LOGIN_REPLY_NEXT_TOKEN_EX) { qq_request_token_ex_next(gc); } else if (ret_8 == QQ_LOGIN_REPLY_CAPTCHA_DLG) { @@ -647,6 +664,21 @@ memset(&qd->captcha, 0, sizeof(qd->captcha)); } break; + case QQ_CMD_CHECK_PWD: + if (qd->client_version == 2008) { + ret_8 = qq_process_check_pwd_2008(gc, data, data_len); + } else { + ret_8 = qq_process_check_pwd_2007(gc, data, data_len); + } + if (ret_8 != QQ_LOGIN_REPLY_OK) { + return ret_8; + } + if (qd->client_version == 2008) { + qq_request_login_2008(gc); + } else { + qq_request_login_2007(gc); + } + break; case QQ_CMD_LOGIN: ret_8 = qq_process_login(gc, data, data_len); if (ret_8 != QQ_LOGIN_REPLY_OK) { diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/send_file.c --- a/libpurple/protocols/qq/send_file.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/send_file.c Wed Oct 22 14:35:05 2008 +0000 @@ -301,7 +301,7 @@ /* 004-007: sender uid */ bytes += qq_put32 (raw_data + bytes, to_uid); /* 008-009: sender client version */ - bytes += qq_put16 (raw_data + bytes, qd->client_version); + bytes += qq_put16 (raw_data + bytes, qd->client_tag); /* 010-013: receiver uid */ bytes += qq_put32 (raw_data + bytes, qd->uid); /* 014-017: sender uid */ @@ -804,7 +804,7 @@ /* FACE from IP detector, ignored by gfhuang */ if(g_ascii_strcasecmp(fileinfo[0], "FACE") == 0) { purple_debug_warning("QQ", - "Received a FACE ip detect from qq-%d, so he/she must be online :)\n", sender_uid); + "Received a FACE ip detect from %d, so he/she must be online :)\n", sender_uid); b = purple_find_buddy(gc->account, sender_name); q_bud = (b == NULL) ? NULL : (qq_buddy *) b->proto_data; diff -r bdfcfd71449c -r dbc7a9742f8d libpurple/protocols/qq/utils.c --- a/libpurple/protocols/qq/utils.c Wed Oct 22 14:33:20 2008 +0000 +++ b/libpurple/protocols/qq/utils.c Wed Oct 22 14:35:05 2008 +0000 @@ -191,7 +191,7 @@ g_return_val_if_fail(name != NULL, NULL); - tmp = (gchar *) purple_strcasestr(name, "(qq-"); + tmp = (gchar *) purple_strcasestr(name, "("); ret = g_strndup(tmp + 4, strlen(name) - (tmp - name) - 4 - 1); return ret; @@ -335,7 +335,7 @@ } void qq_hex_dump(PurpleDebugLevel level, const char *category, - const guint8 *pdata, gint bytes, + const guint8 *pdata, gint bytes, const char *format, ...) { va_list args;