00001
00023
00024
00025 #include "debug.h"
00026 #include "internal.h"
00027
00028 #include "utils.h"
00029 #include "packet_parse.h"
00030 #include "buddy_info.h"
00031 #include "buddy_list.h"
00032 #include "buddy_opt.h"
00033 #include "buddy_status.h"
00034 #include "char_conv.h"
00035 #include "crypt.h"
00036 #include "group_network.h"
00037 #include "header_info.h"
00038 #include "keep_alive.h"
00039 #include "im.h"
00040 #include "login_logout.h"
00041 #include "qq_proxy.h"
00042 #include "recv_core.h"
00043 #include "sendqueue.h"
00044 #include "sys_msg.h"
00045
00046 typedef struct _packet_before_login packet_before_login;
00047 typedef struct _qq_recv_msg_header qq_recv_msg_header;
00048
00049 struct _packet_before_login {
00050 guint8 *buf;
00051 gint len;
00052 };
00053
00054 struct _qq_recv_msg_header {
00055 guint8 header_tag;
00056 guint16 source_tag;
00057 guint16 cmd;
00058 guint16 seq;
00059 };
00060
00061
00062
00063
00064 gboolean _qq_check_packet_set_window(guint16 seq, GaimConnection * gc)
00065 {
00066 qq_data *qd;
00067 gchar *byte, mask;
00068
00069 g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE);
00070 qd = (qq_data *) gc->proto_data;
00071 byte = &(qd->window[seq / 8]);
00072 mask = (1 << (seq % 8));
00073
00074 if ((*byte) & mask)
00075 return TRUE;
00076 (*byte) |= mask;
00077 return FALSE;
00078 }
00079
00080
00081
00082 void _qq_process_packet_default(guint8 * buf, gint buf_len, guint16 cmd, guint16 seq, GaimConnection * gc) {
00083
00084 qq_data *qd;
00085 guint8 *data;
00086 gchar *msg_utf8;
00087 gint len;
00088
00089 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00090 g_return_if_fail(buf != NULL && buf_len != 0);
00091
00092 qd = (qq_data *) gc->proto_data;
00093 len = buf_len;
00094 data = g_newa(guint8, len);
00095 msg_utf8 = NULL;
00096
00097 if (qq_crypt(DECRYPT, buf, buf_len, qd->session_key, data, &len)) {
00098 gaim_debug(GAIM_DEBUG_WARNING, "QQ",
00099 ">>> [%d] %s, %d bytes -> [default] decrypt and dump\n%s",
00100 seq, qq_get_cmd_desc(cmd), buf_len, hex_dump_to_str(data, len));
00101 try_dump_as_gbk(data, len);
00102 } else
00103 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Fail decrypt packet with default process\n");
00104
00105 }
00106
00107
00108
00109 void _qq_packet_process(guint8 * buf, gint buf_len, GaimConnection * gc)
00110 {
00111 qq_data *qd;
00112 gint len, bytes_expected, bytes_read;
00113 guint16 buf_len_read;
00114 guint8 *cursor;
00115 qq_recv_msg_header header;
00116 packet_before_login *b4_packet;
00117
00118 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00119 g_return_if_fail(buf != NULL && buf_len > 0);
00120
00121 qd = (qq_data *) gc->proto_data;
00122 bytes_expected = qd->use_tcp ? QQ_TCP_HEADER_LENGTH : QQ_UDP_HEADER_LENGTH;
00123
00124 if (buf_len < bytes_expected) {
00125 gaim_debug(GAIM_DEBUG_ERROR,
00126 "QQ", "Received packet is too short, dump and drop\n%s", hex_dump_to_str(buf, buf_len));
00127 return;
00128 }
00129
00130 cursor = buf;
00131 bytes_read = 0;
00132
00133
00134 if (qd->use_tcp) {
00135 bytes_read += read_packet_w(buf, &cursor, buf_len, &buf_len_read);
00136 if (buf_len_read != buf_len) {
00137 gaim_debug
00138 (GAIM_DEBUG_ERROR,
00139 "QQ",
00140 "TCP read %d bytes, header says %d bytes, use header anyway\n", buf_len, buf_len_read);
00141 buf_len = buf_len_read;
00142 }
00143 }
00144
00145
00146 bytes_read += read_packet_b(buf, &cursor, buf_len, &header.header_tag);
00147 bytes_read += read_packet_w(buf, &cursor, buf_len, &header.source_tag);
00148 bytes_read += read_packet_w(buf, &cursor, buf_len, &header.cmd);
00149 bytes_read += read_packet_w(buf, &cursor, buf_len, &header.seq);
00150
00151 if (bytes_read != bytes_expected) {
00152 gaim_debug(GAIM_DEBUG_ERROR, "QQ",
00153 "Fail reading packet header, expect %d bytes, read %d bytes\n", bytes_expected, bytes_read);
00154 return;
00155 }
00156
00157 if ((buf[buf_len - 1] != QQ_PACKET_TAIL) || (header.header_tag != QQ_PACKET_TAG)) {
00158 gaim_debug(GAIM_DEBUG_ERROR,
00159 "QQ", "Unknown QQ proctocol, dump and drop\n%s", hex_dump_to_str(buf, buf_len));
00160 return;
00161 }
00162
00163 if (QQ_DEBUG)
00164 gaim_debug(GAIM_DEBUG_INFO, "QQ",
00165 "==> [%05d] %s, from (%s)\n",
00166 header.seq, qq_get_cmd_desc(header.cmd), qq_get_source_str(header.source_tag));
00167
00168 if (header.cmd != QQ_CMD_LOGIN && header.cmd != QQ_CMD_GET_LOGIN_TOKEN) {
00169 if (!qd->logged_in) {
00170 b4_packet = g_new0(packet_before_login, 1);
00171
00172 b4_packet->buf = g_memdup(buf, buf_len);
00173 b4_packet->len = buf_len;
00174 if (qd->before_login_packets == NULL)
00175 qd->before_login_packets = g_queue_new();
00176 g_queue_push_head(qd->before_login_packets, b4_packet);
00177 return;
00178 } else if (!g_queue_is_empty(qd->before_login_packets)) {
00179
00180 b4_packet = (packet_before_login *)
00181 g_queue_pop_head(qd->before_login_packets);
00182 _qq_packet_process(b4_packet->buf, b4_packet->len, gc);
00183
00184
00185 g_free(b4_packet->buf);
00186 g_free(b4_packet);
00187 }
00188 }
00189
00190
00191 len = buf_len - (bytes_read) - 1;
00192
00193
00194 switch (header.cmd) {
00195 case QQ_CMD_RECV_IM:
00196 case QQ_CMD_RECV_MSG_SYS:
00197 case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
00198
00199
00200
00201 if (_qq_check_packet_set_window(header.seq, gc)) {
00202 gaim_debug(GAIM_DEBUG_WARNING,
00203 "QQ", "dup [%05d] %s, discard...\n", header.seq, qq_get_cmd_desc(header.cmd));
00204 return;
00205 }
00206 break;
00207 default:{
00208
00209 qq_sendqueue_remove(qd, header.seq);
00210 if (QQ_DEBUG)
00211 gaim_debug(GAIM_DEBUG_INFO, "QQ",
00212 "ack [%05d] %s, remove from sendqueue\n",
00213 header.seq, qq_get_cmd_desc(header.cmd));
00214 }
00215 }
00216
00217
00218 switch (header.cmd) {
00219 case QQ_CMD_KEEP_ALIVE:
00220 qq_process_keep_alive_reply(cursor, len, gc);
00221 break;
00222 case QQ_CMD_UPDATE_INFO:
00223 qq_process_modify_info_reply(cursor, len, gc);
00224 break;
00225 case QQ_CMD_ADD_FRIEND_WO_AUTH:
00226 qq_process_add_buddy_reply(cursor, len, header.seq, gc);
00227 break;
00228 case QQ_CMD_DEL_FRIEND:
00229 qq_process_remove_buddy_reply(cursor, len, gc);
00230 break;
00231 case QQ_CMD_REMOVE_SELF:
00232 qq_process_remove_self_reply(cursor, len, gc);
00233 break;
00234 case QQ_CMD_BUDDY_AUTH:
00235 qq_process_add_buddy_auth_reply(cursor, len, gc);
00236 break;
00237 case QQ_CMD_GET_USER_INFO:
00238 qq_process_get_info_reply(cursor, len, gc);
00239 break;
00240 case QQ_CMD_CHANGE_ONLINE_STATUS:
00241 qq_process_change_status_reply(cursor, len, gc);
00242 break;
00243 case QQ_CMD_SEND_IM:
00244 qq_process_send_im_reply(cursor, len, gc);
00245 break;
00246 case QQ_CMD_RECV_IM:
00247 qq_process_recv_im(cursor, len, header.seq, gc);
00248 break;
00249 case QQ_CMD_LOGIN:
00250 qq_process_login_reply(cursor, len, gc);
00251 break;
00252 case QQ_CMD_GET_FRIENDS_LIST:
00253 qq_process_get_buddies_list_reply(cursor, len, gc);
00254 break;
00255 case QQ_CMD_GET_FRIENDS_ONLINE:
00256 qq_process_get_buddies_online_reply(cursor, len, gc);
00257 break;
00258 case QQ_CMD_GROUP_CMD:
00259 qq_process_group_cmd_reply(cursor, len, header.seq, gc);
00260 break;
00261 case QQ_CMD_RECV_MSG_SYS:
00262 qq_process_msg_sys(cursor, len, header.seq, gc);
00263 break;
00264 case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
00265 qq_process_friend_change_status(cursor, len, gc);
00266 break;
00267 case QQ_CMD_GET_LOGIN_TOKEN:
00268 qq_process_login_token_relay(cursor, len, gc);
00269 break;
00270 default:
00271 _qq_process_packet_default(cursor, len, header.cmd, header.seq, gc);
00272 break;
00273 }
00274 }
00275
00276
00277
00278 void qq_b4_packets_free(qq_data * qd)
00279 {
00280 packet_before_login *b4_packet;
00281 g_return_if_fail(qd != NULL);
00282
00283 if (qd->before_login_packets != NULL) {
00284 while (NULL != (b4_packet = g_queue_pop_tail(qd->before_login_packets))) {
00285 g_free(b4_packet->buf);
00286 g_free(b4_packet);
00287 }
00288 g_queue_free(qd->before_login_packets);
00289 }
00290 }
00291
00292
00293 void qq_input_pending(gpointer data, gint source, GaimInputCondition cond)
00294 {
00295 GaimConnection *gc;
00296 qq_data *qd;;
00297 guint8 *buf;
00298 gint len;
00299
00300 gc = (GaimConnection *) data;
00301 g_return_if_fail(gc != NULL && gc->proto_data != NULL && cond == GAIM_INPUT_READ);
00302
00303 qd = (qq_data *) gc->proto_data;
00304
00305
00306 buf = g_newa(guint8, MAX_PACKET_SIZE);
00307
00308
00309 len = qq_proxy_read(qd, buf, MAX_PACKET_SIZE);
00310 if (len <= 0) {
00311 gaim_connection_error(gc, _("Unable to read from socket"));
00312 return;
00313 } else
00314 _qq_packet_process(buf, len, gc);
00315 }
00316
00317
00318