summaryrefslogtreecommitdiff
path: root/libpurple/protocols/qq/qq_process.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpurple/protocols/qq/qq_process.c')
-rw-r--r--libpurple/protocols/qq/qq_process.c759
1 files changed, 622 insertions, 137 deletions
diff --git a/libpurple/protocols/qq/qq_process.c b/libpurple/protocols/qq/qq_process.c
index e2731fcb5a..f95a718862 100644
--- a/libpurple/protocols/qq/qq_process.c
+++ b/libpurple/protocols/qq/qq_process.c
@@ -30,27 +30,22 @@
#include "buddy_list.h"
#include "buddy_opt.h"
#include "group_info.h"
-#include "group_free.h"
#include "char_conv.h"
#include "qq_crypt.h"
-#include "group_conv.h"
-#include "group_find.h"
#include "group_internal.h"
#include "group_im.h"
#include "group_info.h"
#include "group_join.h"
#include "group_opt.h"
-#include "group_search.h"
-#include "header_info.h"
+#include "qq_define.h"
#include "qq_base.h"
#include "im.h"
#include "qq_process.h"
#include "packet_parse.h"
#include "qq_network.h"
#include "qq_trans.h"
-#include "sys_msg.h"
#include "utils.h"
enum {
@@ -60,10 +55,10 @@ enum {
};
/* default process, decrypt and dump */
-static void process_cmd_unknow(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq)
+static void process_unknow_cmd(PurpleConnection *gc,const gchar *title, guint8 *data, gint data_len, guint16 cmd, guint16 seq)
{
qq_data *qd;
- gchar *msg_utf8 = NULL;
+ gchar *msg;
g_return_if_fail(data != NULL && data_len != 0);
@@ -76,11 +71,390 @@ static void process_cmd_unknow(PurpleConnection *gc,const gchar *title, guint8 *
">>> [%d] %s -> [default] decrypt and dump",
seq, qq_get_cmd_desc(cmd));
- msg_utf8 = try_dump_as_gbk(data, data_len);
- if (msg_utf8 != NULL) {
- purple_notify_info(gc, _("QQ Error"), title, msg_utf8);
- g_free(msg_utf8);
+ msg = g_strdup_printf("Unknow command 0x%02X, %s", cmd, qq_get_cmd_desc(cmd));
+ purple_notify_info(gc, _("QQ Error"), title, msg);
+ g_free(msg);
+}
+
+/* parse the reply to send_im */
+static void do_im_ack(guint8 *data, gint data_len, PurpleConnection *gc)
+{
+ qq_data *qd;
+
+ g_return_if_fail(data != NULL && data_len != 0);
+
+ qd = gc->proto_data;
+
+ if (data[0] != 0) {
+ purple_debug_warning("QQ", "Failed sent IM\n");
+ purple_notify_error(gc, _("Error"), _("Failed to send IM."), NULL);
+ return;
+ }
+
+ purple_debug_info("QQ", "OK sent IM\n");
+}
+
+static void do_server_news(guint8 *data, gint data_len, PurpleConnection *gc)
+{
+ qq_data *qd = (qq_data *) gc->proto_data;
+ gint bytes;
+ gchar *title, *brief, *url;
+ gchar *content;
+
+ g_return_if_fail(data != NULL && data_len != 0);
+
+ /* qq_show_packet("Rcv news", data, data_len); */
+
+ bytes = 4; /* skip unknown 4 bytes */
+
+ bytes += qq_get_vstr(&title, QQ_CHARSET_DEFAULT, data + bytes);
+ bytes += qq_get_vstr(&brief, QQ_CHARSET_DEFAULT, data + bytes);
+ bytes += qq_get_vstr(&url, QQ_CHARSET_DEFAULT, data + bytes);
+
+ content = g_strdup_printf(_("Server News:\n%s\n%s\n%s"), title, brief, url);
+
+ if (qd->is_show_news) {
+ qq_got_attention(gc, content);
+ } else {
+ purple_debug_info("QQ", "QQ Server news:\n%s\n", content);
}
+ g_free(title);
+ g_free(brief);
+ g_free(url);
+ g_free(content);
+}
+
+static void do_msg_sys_30(PurpleConnection *gc, guint8 *data, gint data_len)
+{
+ gint len;
+ guint8 reply;
+ gchar **segments, *msg_utf8;
+
+ g_return_if_fail(data != NULL && data_len != 0);
+
+ len = data_len;
+
+ if (NULL == (segments = split_data(data, len, "\x2f", 2)))
+ return;
+
+ reply = strtol(segments[0], NULL, 10);
+ if (reply == 1)
+ purple_debug_warning("QQ", "We are kicked out by QQ server\n");
+
+ msg_utf8 = qq_to_utf8(segments[1], QQ_CHARSET_DEFAULT);
+ qq_got_attention(gc, msg_utf8);
+}
+
+static void do_msg_sys_4c(PurpleConnection *gc, guint8 *data, gint data_len)
+{
+ gint bytes;
+ gint msg_len;
+ GString *content;
+ gchar *msg = NULL;
+
+ g_return_if_fail(data != NULL && data_len > 0);
+
+ bytes = 6; /* skip 0x(06 00 01 1e 01 1c)*/
+
+ content = g_string_new("");
+ while (bytes < data_len) {
+ msg_len = qq_get_vstr(&msg, QQ_CHARSET_DEFAULT, data + bytes);
+ g_string_append(content, msg);
+ g_string_append(content, "\n");
+ g_free(msg);
+
+ if (msg_len <= 1) {
+ break;
+ }
+ bytes += msg_len;
+ }
+ if (bytes != data_len) {
+ purple_debug_warning("QQ", "Failed to read QQ_MSG_SYS_4C\n");
+ qq_show_packet("do_msg_sys_4c", data, data_len);
+ }
+ qq_got_attention(gc, content->str);
+ g_string_free(content, FALSE);
+}
+
+static const gchar *get_im_type_desc(gint type)
+{
+ switch (type) {
+ case QQ_MSG_TO_BUDDY:
+ return "QQ_MSG_TO_BUDDY";
+ case QQ_MSG_TO_UNKNOWN:
+ return "QQ_MSG_TO_UNKNOWN";
+ case QQ_MSG_UNKNOWN_QUN_IM:
+ return "QQ_MSG_UNKNOWN_QUN_IM";
+ case QQ_MSG_ADD_TO_QUN:
+ return "QQ_MSG_ADD_TO_QUN";
+ case QQ_MSG_DEL_FROM_QUN:
+ return "QQ_MSG_DEL_FROM_QUN";
+ case QQ_MSG_APPLY_ADD_TO_QUN:
+ return "QQ_MSG_APPLY_ADD_TO_QUN";
+ case QQ_MSG_CREATE_QUN:
+ return "QQ_MSG_CREATE_QUN";
+ case QQ_MSG_SYS_30:
+ return "QQ_MSG_SYS_30";
+ case QQ_MSG_SYS_4C:
+ return "QQ_MSG_SYS_4C";
+ case QQ_MSG_APPROVE_APPLY_ADD_TO_QUN:
+ return "QQ_MSG_APPROVE_APPLY_ADD_TO_QUN";
+ case QQ_MSG_REJCT_APPLY_ADD_TO_QUN:
+ return "QQ_MSG_REJCT_APPLY_ADD_TO_QUN";
+ case QQ_MSG_TEMP_QUN_IM:
+ return "QQ_MSG_TEMP_QUN_IM";
+ case QQ_MSG_QUN_IM:
+ return "QQ_MSG_QUN_IM";
+ case QQ_MSG_NEWS:
+ return "QQ_MSG_NEWS";
+ case QQ_MSG_EXTEND:
+ return "QQ_MSG_EXTEND";
+ case QQ_MSG_EXTEND_85:
+ return "QQ_MSG_EXTEND_85";
+ default:
+ return "QQ_MSG_UNKNOWN";
+ }
+}
+
+/* I receive a message, mainly it is text msg,
+ * but we need to proess other types (group etc) */
+static void process_private_msg(guint8 *data, gint data_len, guint16 seq, PurpleConnection *gc)
+{
+ qq_data *qd;
+ gint bytes;
+
+ struct {
+ guint32 uid_from;
+ guint32 uid_to;
+ guint32 seq;
+ struct in_addr ip_from;
+ guint16 port_from;
+ guint16 msg_type;
+ } header;
+
+ g_return_if_fail(data != NULL && data_len != 0);
+
+ qd = (qq_data *) gc->proto_data;
+
+ if (data_len < 16) { /* we need to ack with the first 16 bytes */
+ purple_debug_error("QQ", "MSG is too short\n");
+ return;
+ } else {
+ /* when we receive a message,
+ * we send an ACK which is the first 16 bytes of incoming packet */
+ qq_send_server_reply(gc, QQ_CMD_RECV_IM, seq, data, 16);
+ }
+
+ /* check len first */
+ if (data_len < 20) { /* length of im_header */
+ purple_debug_error("QQ", "Invald MSG header, len %d < 20\n", data_len);
+ return;
+ }
+
+ bytes = 0;
+ bytes += qq_get32(&(header.uid_from), data + bytes);
+ bytes += qq_get32(&(header.uid_to), data + bytes);
+ bytes += qq_get32(&(header.seq), data + bytes);
+ /* if the message is delivered via server, it is server IP/port */
+ bytes += qq_getIP(&(header.ip_from), data + bytes);
+ bytes += qq_get16(&(header.port_from), data + bytes);
+ bytes += qq_get16(&(header.msg_type), data + bytes);
+ /* im_header prepared */
+
+ if (header.uid_to != qd->uid) { /* should not happen */
+ purple_debug_error("QQ", "MSG to [%d], NOT me\n", header.uid_to);
+ return;
+ }
+
+ /* check bytes */
+ if (bytes >= data_len - 1) {
+ purple_debug_warning("QQ", "Empty MSG\n");
+ return;
+ }
+
+ switch (header.msg_type) {
+ case QQ_MSG_NEWS:
+ do_server_news(data + bytes, data_len - bytes, gc);
+ break;
+ case QQ_MSG_EXTEND:
+ case QQ_MSG_EXTEND_85:
+ purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from);
+ qq_process_extend_im(gc, data + bytes, data_len - bytes);
+ break;
+ case QQ_MSG_TO_UNKNOWN:
+ case QQ_MSG_TO_BUDDY:
+ purple_debug_info("QQ", "MSG from buddy [%d]\n", header.uid_from);
+ qq_process_im(gc, data + bytes, data_len - bytes);
+ break;
+ case QQ_MSG_UNKNOWN_QUN_IM:
+ case QQ_MSG_TEMP_QUN_IM:
+ case QQ_MSG_QUN_IM:
+ purple_debug_info("QQ", "MSG from room [%d]\n", header.uid_from);
+ qq_process_room_im(data + bytes, data_len - bytes, header.uid_from, gc, header.msg_type);
+ break;
+ case QQ_MSG_ADD_TO_QUN:
+ purple_debug_info("QQ", "Notice from [%d], Added\n", header.uid_from);
+ /* uid_from is group id
+ * we need this to create a dummy group and add to blist */
+ qq_process_room_buddy_joined(data + bytes, data_len - bytes, header.uid_from, gc);
+ break;
+ case QQ_MSG_DEL_FROM_QUN:
+ purple_debug_info("QQ", "Notice from room [%d], Removed\n", header.uid_from);
+ /* uid_from is group id */
+ qq_process_room_buddy_removed(data + bytes, data_len - bytes, header.uid_from, gc);
+ break;
+ case QQ_MSG_APPLY_ADD_TO_QUN:
+ purple_debug_info("QQ", "Notice from room [%d], Joined\n", header.uid_from);
+ /* uid_from is group id */
+ qq_process_room_buddy_request_join(data + bytes, data_len - bytes, header.uid_from, gc);
+ break;
+ case QQ_MSG_APPROVE_APPLY_ADD_TO_QUN:
+ purple_debug_info("QQ", "Notice from room [%d], Confirm add in\n",
+ header.uid_from);
+ /* uid_from is group id */
+ qq_process_room_buddy_approved(data + bytes, data_len - bytes, header.uid_from, gc);
+ break;
+ case QQ_MSG_REJCT_APPLY_ADD_TO_QUN:
+ purple_debug_info("QQ", "Notice from room [%d], Refuse add in\n",
+ header.uid_from);
+ /* uid_from is group id */
+ qq_process_room_buddy_rejected(data + bytes, data_len - bytes, header.uid_from, gc);
+ break;
+ case QQ_MSG_SYS_30:
+ do_msg_sys_30(gc, data + bytes, data_len - bytes);
+ break;
+ case QQ_MSG_SYS_4C:
+ do_msg_sys_4c(gc, data + bytes, data_len - bytes);
+ break;
+ default:
+ purple_debug_warning("QQ", "MSG from [%d], unknown type %s [0x%04X]\n",
+ header.uid_from, get_im_type_desc(header.msg_type), header.msg_type);
+ qq_show_packet("Unknown MSG type", data, data_len);
+ break;
+ }
+}
+
+/* Send ACK if the sys message needs an ACK */
+static void request_server_ack(PurpleConnection *gc, gchar *funct_str, gchar *from, guint16 seq)
+{
+ qq_data *qd;
+ guint8 *raw_data;
+ gint bytes;
+ guint8 bar;
+
+ g_return_if_fail(funct_str != NULL && from != NULL);
+ qd = (qq_data *) gc->proto_data;
+
+
+ bar = 0x1e;
+ raw_data = g_newa(guint8, strlen(funct_str) + strlen(from) + 16);
+
+ bytes = 0;
+ bytes += qq_putdata(raw_data + bytes, (guint8 *)funct_str, strlen(funct_str));
+ bytes += qq_put8(raw_data + bytes, bar);
+ bytes += qq_putdata(raw_data + bytes, (guint8 *)from, strlen(from));
+ bytes += qq_put8(raw_data + bytes, bar);
+ bytes += qq_put16(raw_data + bytes, seq);
+
+ qq_send_server_reply(gc, QQ_CMD_ACK_SYS_MSG, 0, raw_data, bytes);
+}
+
+static void do_server_notice(PurpleConnection *gc, gchar *from, gchar *to,
+ guint8 *data, gint data_len)
+{
+ qq_data *qd = (qq_data *) gc->proto_data;
+ gchar *msg, *msg_utf8;
+ gchar *title, *content;
+
+ g_return_if_fail(from != NULL && to != NULL && data_len > 0);
+
+ msg = g_strndup((gchar *)data, data_len);
+ msg_utf8 = qq_to_utf8(msg, QQ_CHARSET_DEFAULT);
+ g_free(msg);
+ if (msg_utf8 == NULL) {
+ purple_debug_error("QQ", "Recv NULL sys msg from %s to %s, discard\n",
+ from, to);
+ return;
+ }
+
+ title = g_strdup_printf(_("From %s:"), from);
+ content = g_strdup_printf(_("Server notice From %s: \n%s"), from, msg_utf8);
+
+ if (qd->is_show_notice) {
+ qq_got_attention(gc, content);
+ } else {
+ purple_debug_info("QQ", "QQ Server notice from %s:\n%s", from, msg_utf8);
+ }
+ g_free(msg_utf8);
+ g_free(title);
+ g_free(content);
+}
+
+static void process_server_msg(PurpleConnection *gc, guint8 *data, gint data_len, guint16 seq)
+{
+ qq_data *qd;
+ guint8 *data_str;
+ gchar **segments;
+ gchar *funct_str, *from, *to;
+ gint bytes, funct;
+
+ g_return_if_fail(data != NULL && data_len != 0);
+
+ qd = (qq_data *) gc->proto_data;
+
+ data_str = g_newa(guint8, data_len + 1);
+ g_memmove(data_str, data, data_len);
+ data_str[data_len] = 0x00;
+
+ segments = g_strsplit_set((gchar *) data_str, "\x1f", 0);
+ g_return_if_fail(segments != NULL);
+ if (g_strv_length(segments) < 3) {
+ purple_debug_warning("QQ", "Server message segments is less than 3\n");
+ g_strfreev(segments);
+ return;
+ }
+
+ bytes = 0;
+ funct_str = segments[0];
+ bytes += strlen(funct_str) + 1;
+ from = segments[1];
+ bytes += strlen(from) + 1;
+ to = segments[2];
+ bytes += strlen(to) + 1;
+
+ request_server_ack(gc, funct_str, from, seq);
+
+ /* qq_show_packet("Server MSG", data, data_len); */
+ if (strtol(to, NULL, 10) != qd->uid) { /* not to me */
+ purple_debug_error("QQ", "Recv sys msg to [%s], not me!, discard\n", to);
+ g_strfreev(segments);
+ return;
+ }
+
+ funct = strtol(funct_str, NULL, 10);
+ switch (funct) {
+ case QQ_SERVER_BUDDY_ADDED:
+ case QQ_SERVER_BUDDY_ADD_REQUEST:
+ case QQ_SERVER_BUDDY_ADDED_ME:
+ case QQ_SERVER_BUDDY_REJECTED_ME:
+ case QQ_SERVER_BUDDY_ADD_REQUEST_EX:
+ case QQ_SERVER_BUDDY_ADDING_EX:
+ case QQ_SERVER_BUDDY_ADDED_ANSWER:
+ case QQ_SERVER_BUDDY_ADDED_EX:
+ qq_process_buddy_from_server(gc, funct, from, to, data + bytes, data_len - bytes);
+ break;
+ case QQ_SERVER_NOTICE:
+ do_server_notice(gc, from, to, data + bytes, data_len - bytes);
+ break;
+ case QQ_SERVER_NEW_CLIENT:
+ purple_debug_warning("QQ", "QQ Server has newer client version\n");
+ break;
+ default:
+ qq_show_packet("Unknown sys msg", data, data_len);
+ purple_debug_warning("QQ", "Recv unknown sys msg code: %s\n", funct_str);
+ break;
+ }
+ g_strfreev(segments);
}
void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *rcved, gint rcved_len)
@@ -113,16 +487,16 @@ void qq_proc_server_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *
/* now process the packet */
switch (cmd) {
case QQ_CMD_RECV_IM:
- qq_process_recv_im(data, data_len, seq, gc);
+ process_private_msg(data, data_len, seq, gc);
break;
case QQ_CMD_RECV_MSG_SYS:
- qq_process_msg_sys(data, data_len, seq, gc);
+ process_server_msg(gc, data, data_len, seq);
break;
case QQ_CMD_BUDDY_CHANGE_STATUS:
qq_process_buddy_change_status(data, data_len, gc);
break;
default:
- process_cmd_unknow(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq);
+ process_unknow_cmd(gc, _("Unknow SERVER CMD"), data, data_len, cmd, seq);
break;
}
}
@@ -150,36 +524,25 @@ static void process_room_cmd_notify(PurpleConnection *gc,
void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
{
qq_data *qd;
- qq_group *group;
gint ret;
g_return_if_fail (gc != NULL && gc->proto_data != NULL);
qd = (qq_data *) gc->proto_data;
- group = qq_room_search_id(gc, room_id);
- if (group == NULL && room_id <= 0) {
- purple_debug_info("QQ", "No room, nothing update\n");
- return;
- }
- if (group == NULL ) {
- purple_debug_warning("QQ", "Failed search room id [%d]\n", room_id);
- return;
- }
-
switch (room_cmd) {
case 0:
- qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, group->id, NULL, 0,
+ qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, room_id, NULL, 0,
QQ_CMD_CLASS_UPDATE_ROOM, 0);
break;
case QQ_ROOM_CMD_GET_INFO:
- ret = qq_request_room_get_buddies(gc, group, QQ_CMD_CLASS_UPDATE_ROOM);
+ ret = qq_request_room_get_buddies(gc, room_id, QQ_CMD_CLASS_UPDATE_ROOM);
if (ret <= 0) {
- qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, group->id, NULL, 0,
+ qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, room_id, NULL, 0,
QQ_CMD_CLASS_UPDATE_ROOM, 0);
}
break;
case QQ_ROOM_CMD_GET_BUDDIES:
- qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, group->id, NULL, 0,
+ qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, room_id, NULL, 0,
QQ_CMD_CLASS_UPDATE_ROOM, 0);
break;
case QQ_ROOM_CMD_GET_ONLINES:
@@ -189,43 +552,46 @@ void qq_update_room(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
}
}
-static void update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
+void qq_update_all_rooms(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
{
qq_data *qd;
gboolean is_new_turn = FALSE;
- qq_group *next_group;
+ guint32 next_id;
g_return_if_fail (gc != NULL && gc->proto_data != NULL);
qd = (qq_data *) gc->proto_data;
- next_group = qq_room_get_next(gc, room_id);
- if (next_group == NULL && room_id <= 0) {
- purple_debug_info("QQ", "No room. Finished update\n");
- return;
- }
- if (next_group == NULL ) {
- is_new_turn = TRUE;
- next_group = qq_room_get_next(gc, 0);
- g_return_if_fail(next_group != NULL);
+ next_id = qq_room_get_next(gc, room_id);
+ purple_debug_info("QQ", "Update rooms, next id %d, prev id %d\n", next_id, room_id);
+
+ if (next_id <= 0) {
+ if (room_id > 0) {
+ is_new_turn = TRUE;
+ next_id = qq_room_get_next(gc, 0);
+ purple_debug_info("QQ", "new turn, id %d\n", next_id);
+ } else {
+ purple_debug_info("QQ", "No room. Finished update\n");
+ return;
+ }
}
switch (room_cmd) {
case 0:
- qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_group->id, NULL, 0,
+ qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_id, NULL, 0,
QQ_CMD_CLASS_UPDATE_ALL, 0);
break;
case QQ_ROOM_CMD_GET_INFO:
if (!is_new_turn) {
- qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_group->id, NULL, 0,
+ qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_INFO, next_id, NULL, 0,
QQ_CMD_CLASS_UPDATE_ALL, 0);
} else {
- qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL);
+ qq_request_room_get_buddies(gc, next_id, QQ_CMD_CLASS_UPDATE_ALL);
}
break;
case QQ_ROOM_CMD_GET_BUDDIES:
/* last command */
if (!is_new_turn) {
- qq_request_room_get_buddies(gc, next_group, QQ_CMD_CLASS_UPDATE_ALL);
+ qq_request_room_get_buddies(gc, next_id, QQ_CMD_CLASS_UPDATE_ALL);
} else {
purple_debug_info("QQ", "Finished update\n");
}
@@ -244,57 +610,63 @@ void qq_update_all(PurpleConnection *gc, guint16 cmd)
switch (cmd) {
case 0:
- qq_request_buddy_info(gc, qd->uid, QQ_CMD_CLASS_UPDATE_ALL, QQ_BUDDY_INFO_UPDATE_ONLY);
+ qq_request_buddy_info(gc, qd->uid, QQ_CMD_CLASS_UPDATE_ALL, 0);
break;
case QQ_CMD_GET_BUDDY_INFO:
qq_request_change_status(gc, QQ_CMD_CLASS_UPDATE_ALL);
break;
case QQ_CMD_CHANGE_STATUS:
- qq_request_get_buddies_list(gc, 0, QQ_CMD_CLASS_UPDATE_ALL);
+ qq_request_get_buddies(gc, 0, QQ_CMD_CLASS_UPDATE_ALL);
break;
case QQ_CMD_GET_BUDDIES_LIST:
qq_request_get_buddies_and_rooms(gc, 0, QQ_CMD_CLASS_UPDATE_ALL);
break;
case QQ_CMD_GET_BUDDIES_AND_ROOMS:
- qq_request_get_buddies_level(gc, QQ_CMD_CLASS_UPDATE_ALL);
+ if (qd->client_version >= 2007) {
+ /* QQ2007/2008 can not get buddies level*/
+ qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ALL);
+ } else {
+ qq_request_get_buddies_level(gc, QQ_CMD_CLASS_UPDATE_ALL);
+ }
break;
case QQ_CMD_GET_LEVEL:
qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ALL);
break;
case QQ_CMD_GET_BUDDIES_ONLINE:
/* last command */
- update_all_rooms(gc, 0, 0);
+ qq_update_all_rooms(gc, 0, 0);
break;
default:
break;
}
+ qd->online_last_update = time(NULL);
}
static void update_all_rooms_online(PurpleConnection *gc, guint8 room_cmd, guint32 room_id)
{
qq_data *qd;
- qq_group *next_group;
+ guint32 next_id;
g_return_if_fail (gc != NULL && gc->proto_data != NULL);
qd = (qq_data *) gc->proto_data;
- next_group = qq_room_get_next_conv(gc, room_id);
- if (next_group == NULL && room_id <= 0) {
+ next_id = qq_room_get_next_conv(gc, room_id);
+ if (next_id <= 0 && room_id <= 0) {
purple_debug_info("QQ", "No room in conversation, no update online buddies\n");
return;
}
- if (next_group == NULL ) {
+ if (next_id <= 0 ) {
purple_debug_info("QQ", "finished update rooms' online buddies\n");
return;
}
switch (room_cmd) {
case 0:
- qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_group->id, NULL, 0,
+ qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_id, NULL, 0,
QQ_CMD_CLASS_UPDATE_ALL, 0);
break;
case QQ_ROOM_CMD_GET_ONLINES:
- qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_group->id, NULL, 0,
+ qq_send_room_cmd_mess(gc, QQ_ROOM_CMD_GET_ONLINES, next_id, NULL, 0,
QQ_CMD_CLASS_UPDATE_ALL, 0);
break;
default:
@@ -304,6 +676,10 @@ static void update_all_rooms_online(PurpleConnection *gc, guint8 room_cmd, guint
void qq_update_online(PurpleConnection *gc, guint16 cmd)
{
+ qq_data *qd;
+ g_return_if_fail (gc != NULL && gc->proto_data != NULL);
+ qd = (qq_data *) gc->proto_data;
+
switch (cmd) {
case 0:
qq_request_get_buddies_online(gc, 0, QQ_CMD_CLASS_UPDATE_ONLINE);
@@ -315,16 +691,17 @@ void qq_update_online(PurpleConnection *gc, guint16 cmd)
default:
break;
}
+ qd->online_last_update = time(NULL);
}
-void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
+void qq_proc_room_cmds(PurpleConnection *gc, guint16 seq,
guint8 room_cmd, guint32 room_id, guint8 *rcved, gint rcved_len,
gint update_class, guint32 ship32)
{
qq_data *qd;
guint8 *data;
gint data_len;
- qq_group *group;
+ qq_room_data *rmd;
gint bytes;
guint8 reply_cmd, reply;
@@ -355,13 +732,6 @@ void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
return;
}
- group = qq_room_search_id(gc, room_id);
- if (group == NULL) {
- purple_debug_warning("QQ",
- "Missing room id in [%05d], 0x%02X %s for %d, len %d\n",
- seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len);
- }
-
bytes = 0;
bytes += qq_get8(&reply_cmd, data + bytes);
bytes += qq_get8(&reply, data + bytes);
@@ -375,17 +745,17 @@ void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
/* now process the packet */
if (reply != QQ_ROOM_CMD_REPLY_OK) {
- if (group != NULL) {
- qq_set_pending_id(&qd->joining_groups, group->ext_id, FALSE);
- }
-
switch (reply) { /* this should be all errors */
case QQ_ROOM_CMD_REPLY_NOT_MEMBER:
- if (group != NULL) {
+ rmd = qq_room_data_find(gc, room_id);
+ if (rmd == NULL) {
+ purple_debug_warning("QQ",
+ "Missing room id in [%05d], 0x%02X %s for %d, len %d\n",
+ seq, room_cmd, qq_get_room_cmd_desc(room_cmd), room_id, rcved_len);
+ } else {
purple_debug_warning("QQ",
- _("You are not a member of QQ Qun \"%s\"\n"), group->title_utf8);
- group->my_role = QQ_ROOM_ROLE_NO;
- qq_group_refresh(gc, group);
+ _("Not a member of room \"%s\"\n"), rmd->title_utf8);
+ rmd->my_role = QQ_ROOM_ROLE_NO;
}
break;
case QQ_ROOM_CMD_REPLY_SEARCH_ERROR:
@@ -402,7 +772,7 @@ void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
/* 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);
@@ -417,7 +787,7 @@ void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
qq_group_process_activate_group_reply(data + bytes, data_len - bytes, gc);
break;
case QQ_ROOM_CMD_SEARCH:
- qq_process_group_cmd_search_group(data + bytes, data_len - bytes, gc);
+ qq_process_room_search(gc, data + bytes, data_len - bytes, ship32);
break;
case QQ_ROOM_CMD_JOIN:
qq_process_group_cmd_join_group(data + bytes, data_len - bytes, gc);
@@ -429,19 +799,13 @@ void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
qq_process_group_cmd_exit_group(data + bytes, data_len - bytes, gc);
break;
case QQ_ROOM_CMD_SEND_MSG:
- qq_process_group_cmd_im(data + bytes, data_len - bytes, gc);
+ qq_process_room_send_im(gc, data + bytes, data_len - bytes);
break;
case QQ_ROOM_CMD_GET_ONLINES:
qq_process_room_cmd_get_onlines(data + bytes, data_len - bytes, gc);
- if (group != NULL)
- qq_group_conv_refresh_online_member(gc, group);
break;
case QQ_ROOM_CMD_GET_BUDDIES:
qq_process_room_cmd_get_buddies(data + bytes, data_len - bytes, gc);
- if (group != NULL) {
- group->is_got_info = TRUE;
- qq_group_conv_refresh_online_member(gc, group);
- }
break;
default:
purple_debug_warning("QQ", "Unknow room cmd 0x%02X %s\n",
@@ -451,9 +815,8 @@ void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
if (update_class == QQ_CMD_CLASS_NONE)
return;
- purple_debug_info("QQ", "Update class %d\n", update_class);
if (update_class == QQ_CMD_CLASS_UPDATE_ALL) {
- update_all_rooms(gc, room_cmd, room_id);
+ qq_update_all_rooms(gc, room_cmd, room_id);
return;
}
if (update_class == QQ_CMD_CLASS_UPDATE_ONLINE) {
@@ -465,58 +828,159 @@ void qq_proc_room_cmd(PurpleConnection *gc, guint16 seq,
}
}
-void qq_proc_login_cmd(PurpleConnection *gc, guint8 *rcved, gint rcved_len)
+guint8 qq_proc_login_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq,
+ guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32)
{
qq_data *qd;
- guint8 *data;
- gint data_len;
- guint ret_8;
+ guint8 *data = NULL;
+ gint data_len = 0;
+ guint ret_8 = QQ_LOGIN_REPLY_ERR;
- g_return_if_fail (gc != NULL && gc->proto_data != NULL);
+ g_return_val_if_fail (gc != NULL && gc->proto_data != NULL, QQ_LOGIN_REPLY_ERR);
qd = (qq_data *) gc->proto_data;
+ g_return_val_if_fail(rcved_len > 0, QQ_LOGIN_REPLY_ERR);
data = g_newa(guint8, rcved_len);
- /* May use password_twice_md5 in the past version like QQ2005*/
- data_len = qq_decrypt(data, rcved, rcved_len, qd->inikey);
- if (data_len >= 0) {
- purple_debug_warning("QQ",
- "Decrypt login reply packet with inikey, %d bytes\n", data_len);
- } else {
- data_len = qq_decrypt(data, rcved, rcved_len, qd->password_twice_md5);
- if (data_len >= 0) {
- purple_debug_warning("QQ",
- "Decrypt login reply packet with password_twice_md5, %d bytes\n", data_len);
- } else {
- purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Can not decrypt login reply"));
- return;
- }
- }
- ret_8 = qq_process_login_reply(gc, data, data_len);
- if (ret_8 != QQ_LOGIN_REPLY_OK) {
- return;
+ switch (cmd) {
+ case QQ_CMD_TOKEN:
+ if (qq_process_token(gc, rcved, rcved_len) == QQ_LOGIN_REPLY_OK) {
+ if (qd->client_version >= 2007) {
+ qq_request_token_ex(gc);
+ } else {
+ qq_request_login(gc);
+ }
+ return QQ_LOGIN_REPLY_OK;
+ }
+ 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.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_twice_md5);
+ if (data_len >= 0) {
+ purple_debug_warning("QQ", "Decrypt login packet by pwd_twice_md5, %d bytes\n", data_len);
+ }
+ }
+ break;
+ case QQ_CMD_LOGIN:
+ default:
+ if (qd->client_version >= 2007) {
+ data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.pwd_twice_md5);
+ if (data_len >= 0) {
+ purple_debug_warning("QQ", "Decrypt login packet by pwd_twice_md5\n");
+ } else {
+ data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.login_key);
+ if (data_len >= 0) {
+ purple_debug_warning("QQ", "Decrypt login packet by login_key\n");
+ }
+ }
+ } else {
+ /* 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\n");
+ } else {
+ data_len = qq_decrypt(data, rcved, rcved_len, qd->ld.pwd_twice_md5);
+ if (data_len >= 0) {
+ purple_debug_warning("QQ", "Decrypt login packet by pwd_twice_md5\n");
+ }
+ }
+ }
+ break;
}
- purple_debug_info("QQ", "Login repliess OK; everything is fine\n");
+ if (data_len < 0) {
+ purple_debug_warning("QQ",
+ "Can not decrypt login cmd, [%05d], 0x%04X %s, len %d\n",
+ seq, cmd, qq_get_cmd_desc(cmd), rcved_len);
+ qq_show_packet("Can not decrypted", rcved, rcved_len);
+ purple_connection_error_reason(gc,
+ PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
+ _("Can not decrypt login reply"));
+ return QQ_LOGIN_REPLY_ERR;
+ }
- purple_connection_set_state(gc, PURPLE_CONNECTED);
- qd->is_login = TRUE; /* must be defined after sev_finish_login */
+ switch (cmd) {
+ case QQ_CMD_GET_SERVER:
+ ret_8 = qq_process_get_server(gc, data, data_len);
+ if ( ret_8 == QQ_LOGIN_REPLY_OK) {
+ qq_request_token(gc);
+ } else if ( ret_8 == QQ_LOGIN_REPLY_REDIRECT) {
+ return QQ_LOGIN_REPLY_REDIRECT;
+ }
+ break;
+ 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_pwd(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) {
+ qq_captcha_input_dialog(gc, &(qd->captcha));
+ g_free(qd->captcha.token);
+ g_free(qd->captcha.data);
+ memset(&qd->captcha, 0, sizeof(qd->captcha));
+ }
+ break;
+ case QQ_CMD_CHECK_PWD:
+ ret_8 = qq_process_check_pwd(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:
+ if (qd->client_version == 2008) {
+ ret_8 = qq_process_login_2008(gc, data, data_len);
+ if ( ret_8 == QQ_LOGIN_REPLY_REDIRECT) {
+ qq_request_get_server(gc);
+ return QQ_LOGIN_REPLY_OK;
+ }
+ } else if (qd->client_version == 2007) {
+ ret_8 = qq_process_login_2007(gc, data, data_len);
+ if ( ret_8 == QQ_LOGIN_REPLY_REDIRECT) {
+ qq_request_get_server(gc);
+ return QQ_LOGIN_REPLY_OK;
+ }
+ } else {
+ ret_8 = qq_process_login(gc, data, data_len);
+ }
+ if (ret_8 != QQ_LOGIN_REPLY_OK) {
+ return ret_8;
+ }
- /* now initiate QQ Qun, do it first as it may take longer to finish */
- qq_group_init(gc);
+ purple_connection_update_progress(gc, _("Logined"), QQ_CONNECT_STEPS - 1, QQ_CONNECT_STEPS);
+ purple_debug_info("QQ", "Login repliess OK; everything is fine\n");
+ purple_connection_set_state(gc, PURPLE_CONNECTED);
+ qd->is_login = TRUE; /* must be defined after sev_finish_login */
- /* Now goes on updating my icon/nickname, not showing info_window */
- qd->modifying_face = FALSE;
+ /* now initiate QQ Qun, do it first as it may take longer to finish */
+ qq_room_data_initial(gc);
- /* is_login, but we have packets before login */
- qq_trans_process_remained(gc);
+ /* is_login, but we have packets before login */
+ qq_trans_process_remained(gc);
- qq_update_all(gc, 0);
- return;
+ qq_update_all(gc, 0);
+ break;
+ default:
+ process_unknow_cmd(gc, _("Unknow LOGIN CMD"), data, data_len, cmd, seq);
+ return QQ_LOGIN_REPLY_ERR;
+ }
+ return QQ_LOGIN_REPLY_OK;
}
-void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq,
+void qq_proc_client_cmds(PurpleConnection *gc, guint16 cmd, guint16 seq,
guint8 *rcved, gint rcved_len, gint update_class, guint32 ship32)
{
qq_data *qd;
@@ -553,50 +1017,56 @@ void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq,
switch (cmd) {
case QQ_CMD_UPDATE_INFO:
- qq_process_modify_info_reply(data, data_len, gc);
+ qq_process_change_info(gc, data, data_len);
break;
- case QQ_CMD_ADD_BUDDY_WO_AUTH:
- qq_process_add_buddy_reply(data, data_len, seq, gc);
+ case QQ_CMD_ADD_BUDDY_NO_AUTH:
+ qq_process_add_buddy_no_auth(gc, data, data_len, ship32);
break;
- case QQ_CMD_DEL_BUDDY:
- qq_process_remove_buddy_reply(data, data_len, gc);
+ case QQ_CMD_REMOVE_BUDDY:
+ qq_process_remove_buddy(gc, data, data_len, ship32);
break;
- case QQ_CMD_REMOVE_SELF:
- qq_process_remove_self_reply(data, data_len, gc);
+ case QQ_CMD_REMOVE_ME:
+ qq_process_buddy_remove_me(gc, data, data_len, ship32);
break;
- case QQ_CMD_BUDDY_AUTH:
- qq_process_add_buddy_auth_reply(data, data_len, gc);
+ case QQ_CMD_ADD_BUDDY_AUTH:
+ qq_process_add_buddy_auth(data, data_len, gc);
break;
case QQ_CMD_GET_BUDDY_INFO:
- qq_process_get_buddy_info(data, data_len, gc);
+ qq_process_get_buddy_info(data, data_len, ship32, gc);
break;
case QQ_CMD_CHANGE_STATUS:
- qq_process_change_status_reply(data, data_len, gc);
+ qq_process_change_status(data, data_len, gc);
break;
case QQ_CMD_SEND_IM:
- qq_process_send_im_reply(data, data_len, gc);
+ do_im_ack(data, data_len, gc);
break;
case QQ_CMD_KEEP_ALIVE:
- qq_process_keep_alive(data, data_len, gc);
+ if (qd->client_version >= 2008) {
+ qq_process_keep_alive_2008(data, data_len, gc);
+ } else if (qd->client_version >= 2007) {
+ qq_process_keep_alive_2007(data, data_len, gc);
+ } else {
+ qq_process_keep_alive(data, data_len, gc);
+ }
break;
case QQ_CMD_GET_BUDDIES_ONLINE:
- ret_8 = qq_process_get_buddies_online_reply(data, data_len, gc);
+ ret_8 = qq_process_get_buddies_online(data, data_len, gc);
if (ret_8 > 0 && ret_8 < 0xff) {
purple_debug_info("QQ", "Requesting for more online buddies\n");
qq_request_get_buddies_online(gc, ret_8, update_class);
return;
}
purple_debug_info("QQ", "All online buddies received\n");
- qq_refresh_all_buddy_status(gc);
+ qq_update_buddyies_status(gc);
break;
case QQ_CMD_GET_LEVEL:
qq_process_get_level_reply(data, data_len, gc);
break;
case QQ_CMD_GET_BUDDIES_LIST:
- ret_16 = qq_process_get_buddies_list_reply(data, data_len, gc);
+ ret_16 = qq_process_get_buddies(data, data_len, gc);
if (ret_16 > 0 && ret_16 < 0xffff) {
purple_debug_info("QQ", "Requesting for more buddies\n");
- qq_request_get_buddies_list(gc, ret_16, update_class);
+ qq_request_get_buddies(gc, ret_16, update_class);
return;
}
purple_debug_info("QQ", "All buddies received. Requesting buddies' levels\n");
@@ -610,8 +1080,23 @@ void qq_proc_client_cmd(PurpleConnection *gc, guint16 cmd, guint16 seq,
}
purple_debug_info("QQ", "All buddies and groups received\n");
break;
+ case QQ_CMD_AUTH_CODE:
+ qq_process_auth_code(gc, data, data_len, ship32);
+ break;
+ case QQ_CMD_BUDDY_QUESTION:
+ qq_process_question(gc, data, data_len, ship32);
+ break;
+ case QQ_CMD_ADD_BUDDY_NO_AUTH_EX:
+ qq_process_add_buddy_no_auth_ex(gc, data, data_len, ship32);
+ break;
+ case QQ_CMD_ADD_BUDDY_AUTH_EX:
+ qq_process_add_buddy_auth_ex(gc, data, data_len, ship32);
+ break;
+ case QQ_CMD_BUDDY_CHECK_CODE:
+ qq_process_buddy_check_code(gc, data, data_len);
+ break;
default:
- process_cmd_unknow(gc, _("Unknow reply CMD"), data, data_len, cmd, seq);
+ process_unknow_cmd(gc, _("Unknow CLIENT CMD"), data, data_len, cmd, seq);
is_unknow = TRUE;
break;
}