pidgin.openq: 8ff543e6: 2008.09.26 - ccpaging <ccpaging(at)gmail...
csyfek at gmail.com
csyfek at gmail.com
Wed Oct 22 12:12:05 EDT 2008
-----------------------------------------------------------------
Revision: 8ff543e6a27ca96a8ca7233b36314fb7e97b1e23
Ancestor: bb5558d316fe6765728168f9e19639095ba6478d
Author: csyfek at gmail.com
Date: 2008-10-22T14:35:05
Branch: im.pidgin.pidgin.openq
URL: http://d.pidgin.im/viewmtn/revision/info/8ff543e6a27ca96a8ca7233b36314fb7e97b1e23
Modified files:
libpurple/protocols/qq/buddy_info.c
libpurple/protocols/qq/buddy_list.c
libpurple/protocols/qq/buddy_opt.c
libpurple/protocols/qq/file_trans.c
libpurple/protocols/qq/group_conv.c
libpurple/protocols/qq/group_im.c
libpurple/protocols/qq/group_im.h
libpurple/protocols/qq/group_info.c
libpurple/protocols/qq/group_info.h
libpurple/protocols/qq/group_internal.c
libpurple/protocols/qq/group_join.c
libpurple/protocols/qq/group_join.h
libpurple/protocols/qq/group_opt.c
libpurple/protocols/qq/im.c libpurple/protocols/qq/im.h
libpurple/protocols/qq/qq.c libpurple/protocols/qq/qq.h
libpurple/protocols/qq/qq_base.c
libpurple/protocols/qq/qq_base.h
libpurple/protocols/qq/qq_define.c
libpurple/protocols/qq/qq_define.h
libpurple/protocols/qq/qq_network.c
libpurple/protocols/qq/qq_process.c
libpurple/protocols/qq/send_file.c
libpurple/protocols/qq/utils.c
ChangeLog:
2008.09.26 - ccpaging <ccpaging(at)gmail.com>
* Added 'Request/Add/Remove Buddy' functions
-------------- next part --------------
============================================================
--- libpurple/protocols/qq/buddy_info.c b82b64007711ec63c899a89220ba30ed3241b2c8
+++ libpurple/protocols/qq/buddy_info.c 49d7853ce0d123563875612b7944b764c3498ec8
@@ -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 @@ void qq_process_modify_info_reply(guint8
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 @@ void qq_process_get_level_reply(guint8 *
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);
============================================================
--- libpurple/protocols/qq/buddy_list.c a2fd962185dde0cffff2556d476f1659d00d65d5
+++ libpurple/protocols/qq/buddy_list.c d1094ce99ac6dc4f9e8d4b8ef21bda69c9b833c7
@@ -138,7 +138,7 @@ static gint get_buddy_status(qq_buddy_st
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 @@ guint8 qq_process_get_buddies_online_rep
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 @@ guint8 qq_process_get_buddies_online_rep
}
/* 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;
============================================================
--- libpurple/protocols/qq/buddy_opt.c 494a448c64ee5e7ea82091e45f136183beb2a954
+++ libpurple/protocols/qq/buddy_opt.c 9ac9005db536eb3c2d5c5e624f6980e8059c7947
@@ -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 @@ void qq_add_buddy(PurpleConnection *gc,
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 @@ void qq_remove_buddy_and_me(PurpleBlistN
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 @@ void qq_process_buddy_add_auth(guint8 *d
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 @@ void qq_process_buddy_remove(guint8 *dat
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 @@ void qq_process_buddy_remove_me(guint8 *
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 @@ void qq_process_buddy_add_no_auth(guint8
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 @@ PurpleBuddy *qq_create_buddy(PurpleConne
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 @@ PurpleBuddy *qq_create_buddy(PurpleConne
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 @@ static void server_buddy_added(PurpleCon
_("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 @@ static void server_buddy_added_me(Purple
/* 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 @@ static void server_buddy_added_me(Purple
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 */
============================================================
--- libpurple/protocols/qq/file_trans.c 2c8f48f87dabe9f111faa4bb4fba3e6134d342d9
+++ libpurple/protocols/qq/file_trans.c fca62851a2a3c22e64c44f18723b44372680f226
@@ -248,7 +248,7 @@ static gint _qq_send_file(PurpleConnecti
file_key = _gen_file_key();
bytes += qq_put8(raw_data + bytes, packet_type);
- bytes += qq_put16(raw_data + bytes, 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 @@ void qq_send_file_ctl_packet(PurpleConne
{
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 @@ void qq_send_file_ctl_packet(PurpleConne
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 @@ void qq_send_file_ctl_packet(PurpleConne
#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 */
============================================================
--- libpurple/protocols/qq/group_conv.c 5b30fdabc44113fce4d6e14886de4b9581276962
+++ libpurple/protocols/qq/group_conv.c 7615797f0108d685b7433b6aa67efaa649b74043
@@ -37,6 +37,7 @@ PurpleConversation *qq_room_conv_create(
{
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 @@ PurpleConversation *qq_room_conv_create(
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 @@ void qq_group_conv_refresh_online_member
/* 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 */
============================================================
--- libpurple/protocols/qq/group_im.c 2c084034186d20995d280b3c9b29688ae3efda63
+++ libpurple/protocols/qq/group_im.c 61e16cd31f54b9f0b254330ccc744d9c94e6a8f9
@@ -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 @@ void qq_process_room_msg_apply_join(guin
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 @@ void qq_process_room_msg_been_rejected(g
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 @@ void qq_process_room_msg_been_rejected(g
qq_group_refresh(gc, group);
}
- g_free(reason);
g_free(msg);
+ g_free(reason);
g_free(reason_utf8);
}
@@ -193,35 +216,36 @@ void qq_process_room_msg_been_approved(g
{
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);
+ bytes += convert_as_pascal_string(data + bytes, &reason, 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);
-
group = qq_room_search_id(gc, id);
if (group != NULL) {
group->my_role = QQ_ROOM_ROLE_YES;
qq_group_refresh(gc, group);
}
+ msg = g_strdup_printf(_("<b>Joinning Qun %d is approved by Admin %d for %s</b>"),
+ 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 @@ void qq_process_room_msg_been_removed(gu
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(_("<b>Removed buddy %d.</b>"), uid);
+ qq_room_got_chat_in(gc, group, 0, msg, now);
g_free(msg);
}
@@ -262,21 +286,19 @@ void qq_process_room_msg_been_added(guin
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,23 +311,34 @@ void qq_process_room_msg_been_added(guin
/* the return of this cmd will automatically update the group in blist */
}
+ msg = g_strdup_printf(_("<b>Added new buddy %d.</b>"), 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);
/* FIXME: check length here */
@@ -315,21 +348,20 @@ void qq_process_room_msg_normal(guint8 *
#if 0
qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", data, data_len, "group im hex dump");
#endif
+ memset(&packet, 0, sizeof(packet));
+ bytes = 0;
+ bytes += qq_get32(&(packet.ext_id), data + bytes);
+ bytes += qq_get8(&(packet.type8), data + bytes);
- 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);
-
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 @@ void qq_process_room_msg_normal(guint8 *
* 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 @@ void qq_process_room_msg_normal(guint8 *
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);
+ qq_room_got_chat_in(gc, group, packet.member_uid, msg_utf8_encoded, packet.send_time);
- 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);
- }
-
- 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);
}
============================================================
--- libpurple/protocols/qq/group_im.h 80dbc5dfa185c472df09adc543fa04eea527b8b8
+++ libpurple/protocols/qq/group_im.h f082bf0a6d5c24f2fa63cf2d18a18461f1283fbb
@@ -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);
============================================================
--- libpurple/protocols/qq/group_info.c 0089d00bee0b490ac0b3f79637718984fa83f7e1
+++ libpurple/protocols/qq/group_info.c 34d0c999c22b0d2562bac53c5faac7ad69f2a228
@@ -101,12 +101,48 @@ gint qq_request_room_get_buddies(PurpleC
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 @@ void qq_process_room_cmd_get_info(guint8
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 @@ void qq_process_room_cmd_get_info(guint8
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)
============================================================
--- libpurple/protocols/qq/group_info.h 5acd27bb23463327232e8d73f22c6b33c7a2fe6d
+++ libpurple/protocols/qq/group_info.h 611e8625eb38b8fa61dd92dd89d487b7f517473e
@@ -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
============================================================
--- libpurple/protocols/qq/group_internal.c 1877bfc0f0735292c875f9c1e4c0a2b27b5463d7
+++ libpurple/protocols/qq/group_internal.c 506a1f5c336a811d396a585ffdb934edd34e8b3f
@@ -38,19 +38,19 @@ static gchar *get_role_desc(qq_group *gr
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 @@ static void add_room_to_blist(PurpleConn
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,
============================================================
--- libpurple/protocols/qq/group_join.c 752655badb239f6df8e7e9913f64947c318ecf7c
+++ libpurple/protocols/qq/group_join.c 63e1f568d5d68fde30ee60df8409c9e1dc7142be
@@ -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 @@ void qq_process_group_cmd_exit_group(gui
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 @@ void qq_process_group_cmd_exit_group(gui
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 @@ void qq_process_group_cmd_join_group_aut
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_join(PurpleConnection *gc,
}
}
-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 @@ void qq_group_exit(PurpleConnection *gc,
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,
============================================================
--- libpurple/protocols/qq/group_join.h c66eec2d0af474f149a15208c3692f0348d6bc68
+++ libpurple/protocols/qq/group_join.h 484a35954c04266abee1f7f8d28a4758eb6af6db
@@ -44,7 +44,7 @@ void qq_request_room_join(PurpleConnecti
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);
============================================================
--- libpurple/protocols/qq/group_opt.c 9512e5600ad6681ad60d46e8aeccdc65ef8ebd78
+++ libpurple/protocols/qq/group_opt.c 7998997dd6b297225e1d46d6b2ebdb9821521401
@@ -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 @@ void qq_group_process_modify_members_rep
{
gint bytes;
guint32 id;
+ time_t now = time(NULL);
qq_group *group;
g_return_if_fail(data != NULL);
@@ -212,7 +214,7 @@ void qq_group_process_modify_members_rep
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 @@ void qq_group_process_modify_info_reply(
gint bytes;
guint32 id;
qq_group *group;
+ time_t now = time(NULL);
+
g_return_if_fail(data != NULL);
bytes = 0;
@@ -278,7 +282,7 @@ void qq_group_process_modify_info_reply(
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 */
============================================================
--- libpurple/protocols/qq/im.c 12ab7161d337f989800516b234b5b1124cccc672
+++ libpurple/protocols/qq/im.c d588d868095010ea523fc9eec5e4a6ae29ec562e
@@ -222,7 +222,7 @@ static const gchar *qq_get_recv_im_type_
/* 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 @@ static gint _qq_normal_im_common_read(gu
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 @@ static void _qq_process_recv_news(guint8
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 @@ static void _qq_process_recv_news(guint8
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 @@ static void _qq_process_recv_normal_im_t
}
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 @@ static void _qq_process_recv_normal_im_t
}
/* 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 @@ static void _qq_process_recv_normal_im(g
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 @@ static void _qq_process_recv_normal_im(g
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 @@ static void _qq_process_recv_normal_im(g
}
/* 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 @@ void qq_send_packet_im(PurpleConnection
/* 004-007: sender uid */
bytes += qq_put32(raw_data + bytes, to_uid);
/* 008-009: sender client version */
- bytes += qq_put16(raw_data + bytes, 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 @@ void qq_process_recv_im(guint8 *data, gi
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 @@ void qq_process_recv_im(guint8 *data, gi
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",
============================================================
--- libpurple/protocols/qq/im.h 0dbb0b4261a59a829f78c7b75a43c416ee868329
+++ libpurple/protocols/qq/im.h 0e8503aeb523371d6975e46fcff382849e1da18c
@@ -56,10 +56,12 @@ enum {
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);
============================================================
--- libpurple/protocols/qq/qq.c dc390467f68a19e02ea4906d2029990188041368
+++ libpurple/protocols/qq/qq.c b7f925bb3f0d335b90d1d45b7e2b3e0a9cb6094d
@@ -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 @@ static void qq_login(PurpleAccount *acco
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 @@ static void qq_close(PurpleConnection *g
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 @@ static void qq_close(PurpleConnection *g
}
/* 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 @@ static gchar *_qq_status_text(PurpleBudd
/* 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 @@ static void _qq_tooltip_text(PurpleBuddy
#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 @@ static void _qq_tooltip_text(PurpleBuddy
}
/* 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 @@ static const char *_qq_list_emblem(Purpl
}
/* 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 @@ static GList *_qq_away_states(PurpleAcco
}
/* 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 @@ static void _qq_change_status(PurpleAcco
/* 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 @@ static gint _qq_send_im(PurpleConnection
}
/* 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 @@ static void action_show_account_info(Pur
g_string_append(info, "<hr>");
g_string_append_printf(info, _("<b>Server</b>: %s<br>\n"), qd->curr_server);
- g_string_append_printf(info, _("<b>Client Version</b>: %s<br>\n"), qq_get_ver_desc(qd->client_version));
+ g_string_append_printf(info, _("<b>Client Tag</b>: %s<br>\n"), qq_get_ver_desc(qd->client_tag));
g_string_append_printf(info, _("<b>Connection Mode</b>: %s<br>\n"), qd->use_tcp ? "TCP" : "UDP");
g_string_append_printf(info, _("<b>My Internet IP</b>: %s<br>\n"), inet_ntoa(qd->my_ip));
@@ -605,7 +610,7 @@ static void _qq_menu_create_permanent_gr
}
*/
-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 @@ static void _qq_menu_unsubscribe_group(P
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 @@ static GList *qq_actions(PurplePlugin *p
}
/* 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 @@ static GList *_qq_buddy_menu(PurpleBlist
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 @@ static void _qq_get_chat_buddy_info(Purp
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 @@ static PurplePluginProtocolInfo prpl_inf
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 @@ static PurplePluginProtocolInfo prpl_inf
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 @@ static PurplePluginProtocolInfo prpl_inf
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 @@ static void init_plugin(PurplePlugin *pl
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
============================================================
--- libpurple/protocols/qq/qq.h 3c31740ed75db80caffc96a2decb799775baeec6
+++ libpurple/protocols/qq/qq.h 81f75e40c77db1d1d0011c8c7af40a544e866d1e
@@ -54,13 +54,16 @@ struct _qq_login_data {
};
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 @@ struct _qq_buddy {
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 @@ struct _qq_data {
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 @@ struct _qq_data {
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 */
============================================================
--- libpurple/protocols/qq/qq_base.c 767955d22a2632010a419ef0aee3a009a6f9d029
+++ libpurple/protocols/qq/qq_base.c 9998ab6705011d4929fa854b0008db696be5f4ad
@@ -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 @@ void qq_request_login(PurpleConnection *
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 @@ void qq_request_login(PurpleConnection *
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 @@ void qq_request_login(PurpleConnection *
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 @@ guint8 qq_process_token(PurpleConnection
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 @@ guint8 qq_process_token(PurpleConnection
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 @@ guint8 qq_process_token(PurpleConnection
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 @@ void qq_request_logout(PurpleConnection
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 @@ guint8 qq_process_login( PurpleConnectio
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 @@ gboolean qq_process_keep_alive(guint8 *d
/* 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 @@ void qq_request_get_server(PurpleConnect
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 @@ void qq_request_get_server(PurpleConnect
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 @@ void qq_request_token_ex(PurpleConnectio
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 @@ void qq_request_token_ex(PurpleConnectio
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 @@ void qq_request_token_ex(PurpleConnectio
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 @@ void qq_request_token_ex_next(PurpleConn
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 @@ void qq_request_token_ex_next(PurpleConn
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 @@ void qq_request_token_ex_next(PurpleConn
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 @@ static void request_token_ex_code(Purple
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 @@ static void request_token_ex_code(Purple
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 @@ static void request_token_ex_code(Purple
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 @@ void qq_captcha_input_dialog(PurpleConne
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 @@ guint8 qq_process_token_ex(PurpleConnect
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 @@ guint8 qq_process_token_ex(PurpleConnect
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)
+{
+}
============================================================
--- libpurple/protocols/qq/qq_base.h ea7caf396b13c3400b8d302a782cef8aa3761425
+++ libpurple/protocols/qq/qq_base.h 50d174aa4b537a8df7d8cc35713d83765e22b125
@@ -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 @@ guint8 qq_process_token(PurpleConnection
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 @@ gboolean qq_process_keep_alive(guint8 *d
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
============================================================
--- libpurple/protocols/qq/qq_define.c b0b876be933b82e32bcef47e673b4fabe5ab339a
+++ libpurple/protocols/qq/qq_define.c a862490bbf4d332a5e148c48c33d811b812d1858
@@ -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 @@ const gchar *qq_get_cmd_desc(gint cmd)
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";
}
============================================================
--- libpurple/protocols/qq/qq_define.h 5048b85b1fc951d59bfc35da16f22c9f10cabfd2
+++ libpurple/protocols/qq/qq_define.h bd128147801873bb5085307282051520167bf846
@@ -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 @@ enum {
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 */
};
============================================================
--- libpurple/protocols/qq/qq_network.c dbde8647a131927c84dbcbf99f73ea6a03605ca2
+++ libpurple/protocols/qq/qq_network.c 633a2fb01e5d4d9570670883c0b7e96b4aea23fb
@@ -202,7 +202,8 @@ gboolean qq_connect_later(gpointer data)
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 @@ gboolean qq_connect_later(gpointer data)
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 @@ static void tcp_pending(gpointer data, g
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 @@ static void tcp_pending(gpointer data, g
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 @@ static void udp_pending(gpointer data, g
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 @@ static void udp_pending(gpointer data, g
/* 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 @@ static gint udp_send_out(PurpleConnectio
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 @@ static void tcp_can_write(gpointer data,
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 @@ static gint tcp_send_out(PurpleConnectio
/* 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 @@ static gboolean network_timeout(gpointer
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 @@ static void set_all_keys(PurpleConnectio
{
qq_data *qd;
const gchar *passwd;
+ guint8 *dest;
+ int dest_len = QQ_KEY_LENGTH;
/* _qq_show_socket("Got login socket", source); */
@@ -689,26 +704,24 @@ static void set_all_keys(PurpleConnectio
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->ld.random_key); bytes++) {
+ qd->ld.random_key[bytes] = (guint8) (rand() & 0xff);
}
- for (bytes = 0; bytes < sizeof(qd->captcha_key); bytes++) {
- qd->captcha_key[bytes] = (guint8) (rand() & 0xff);
- }
#endif
/* now generate md5 processed passwd */
passwd = purple_account_get_password(purple_connection_get_account(gc));
/* use twice-md5 of user password as session key since QQ 2003iii */
- qq_get_md5(qd->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 @@ static void connect_cb(gpointer data, gi
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 @@ static void udp_host_resolved(GSList *ho
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 @@ gboolean connect_to_server(PurpleConnect
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 @@ void qq_disconnect(PurpleConnection *gc)
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 @@ static gint packet_encap(qq_data *qd, gu
}
/* now comes the normal QQ packet as UDP */
bytes += qq_put8(buf + bytes, QQ_PACKET_TAG);
- bytes += qq_put16(buf + bytes, 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(PurpleConnect
}
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 @@ gint qq_send_cmd_encrypted(PurpleConnect
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 @@ static gint send_cmd_detail(PurpleConnec
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 @@ static gint send_cmd_detail(PurpleConnec
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(PurpleConnecti
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 @@ gint qq_send_server_reply(PurpleConnecti
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 @@ static gint send_room_cmd(PurpleConnecti
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 @@ static gint send_room_cmd(PurpleConnecti
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 @@ static gint send_room_cmd(PurpleConnecti
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(PurpleConnect
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);
}
============================================================
--- libpurple/protocols/qq/qq_process.c 3d29b82d408d5a9504ea576ebac6eed88032156e
+++ libpurple/protocols/qq/qq_process.c f299a881d70bbf12c5a9dfdb4f3b90fc65cdc5b8
@@ -82,7 +82,7 @@ static void process_cmd_unknow(PurpleCon
}
/* 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 @@ static void _qq_send_packet_ack_msg_sys(
"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 @@ static void _qq_process_msg_sys_notice(P
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 @@ static void process_server_msg(guint8 *d
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 @@ static void process_server_msg(guint8 *d
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 @@ void qq_proc_room_cmds(PurpleConnection
/* 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 @@ guint8 qq_proc_login_cmds(PurpleConnecti
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 @@ guint8 qq_proc_login_cmds(PurpleConnecti
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 @@ guint8 qq_proc_login_cmds(PurpleConnecti
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 @@ guint8 qq_proc_login_cmds(PurpleConnecti
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 @@ guint8 qq_proc_login_cmds(PurpleConnecti
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) {
============================================================
--- libpurple/protocols/qq/send_file.c 591962a2446a469711b3abaf0c80d7a4b76faf81
+++ libpurple/protocols/qq/send_file.c 271b750f28e52519c0b0cdef1c6ca880d5b418dc
@@ -301,7 +301,7 @@ static gint _qq_create_packet_file_heade
/* 004-007: sender uid */
bytes += qq_put32 (raw_data + bytes, to_uid);
/* 008-009: sender client version */
- bytes += qq_put16 (raw_data + bytes, 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 @@ void qq_process_recv_file_request(guint8
/* 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;
============================================================
--- libpurple/protocols/qq/utils.c 4a81d7cc987d03659ec91b083f2fb6ab3e706b92
+++ libpurple/protocols/qq/utils.c 4e79bc0cd7a01c7cf733cb0e2cf94c8301fb696d
@@ -191,7 +191,7 @@ gchar *chat_name_to_purple_name(const gc
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,
}
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;
More information about the Commits
mailing list