pidgin.2.4.3: fcd04238: patch-04-tcp-pending
csyfek at gmail.com
csyfek at gmail.com
Tue Jun 24 08:41:18 EDT 2008
-----------------------------------------------------------------
Revision: fcd04238bea0560e8077f1f3f052119c00305e5f
Ancestor: 1ee6cc253824c05fec211e0416e8bb5391278fa9
Author: csyfek at gmail.com
Date: 2008-06-24T12:22:40
Branch: im.pidgin.pidgin.2.4.3
URL: http://d.pidgin.im/viewmtn/revision/info/fcd04238bea0560e8077f1f3f052119c00305e5f
Deleted entries:
libpurple/protocols/qq/qq_proxy.c
libpurple/protocols/qq/qq_proxy.h
libpurple/protocols/qq/recv_core.c
libpurple/protocols/qq/recv_core.h
libpurple/protocols/qq/send_core.c
libpurple/protocols/qq/send_core.h
libpurple/protocols/qq/udp_proxy_s5.c
libpurple/protocols/qq/udp_proxy_s5.h
Added files:
libpurple/protocols/qq/qq_network.c
libpurple/protocols/qq/qq_network.h
Modified files:
libpurple/protocols/qq/ChangeLog
libpurple/protocols/qq/Makefile.am
libpurple/protocols/qq/Makefile.mingw
libpurple/protocols/qq/buddy_info.c
libpurple/protocols/qq/buddy_list.c
libpurple/protocols/qq/buddy_opt.c
libpurple/protocols/qq/buddy_status.c
libpurple/protocols/qq/char_conv.c
libpurple/protocols/qq/file_trans.c
libpurple/protocols/qq/group_network.c
libpurple/protocols/qq/im.c
libpurple/protocols/qq/keep_alive.c
libpurple/protocols/qq/login_logout.c
libpurple/protocols/qq/packet_parse.c
libpurple/protocols/qq/packet_parse.h
libpurple/protocols/qq/qq.c libpurple/protocols/qq/qq.h
libpurple/protocols/qq/send_file.c
libpurple/protocols/qq/sendqueue.c
libpurple/protocols/qq/sendqueue.h
libpurple/protocols/qq/sys_msg.c
libpurple/protocols/qq/utils.c
libpurple/protocols/qq/utils.h
ChangeLog:
patch-04-tcp-pending
-------------- next part --------------
============================================================
--- libpurple/protocols/qq/qq_network.c 51d45db61522e346a2d4ccbcaacc7b9861a5a236
+++ libpurple/protocols/qq/qq_network.c 51d45db61522e346a2d4ccbcaacc7b9861a5a236
@@ -0,0 +1,1124 @@
+/**
+ * @file qq_network.c
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "cipher.h"
+#include "debug.h"
+#include "internal.h"
+
+#ifdef _WIN32
+#define random rand
+#define srandom srand
+#endif
+
+#include "buddy_info.h"
+#include "buddy_list.h"
+#include "buddy_opt.h"
+#include "buddy_status.h"
+#include "group_free.h"
+#include "char_conv.h"
+#include "crypt.h"
+#include "group_network.h"
+#include "header_info.h"
+#include "keep_alive.h"
+#include "im.h"
+#include "login_logout.h"
+#include "packet_parse.h"
+#include "qq_network.h"
+#include "sendqueue.h"
+#include "sys_msg.h"
+#include "utils.h"
+
+/* These functions are used only in development phase */
+/*
+ static void _qq_show_socket(gchar *desc, gint fd) {
+ struct sockaddr_in sin;
+ socklen_t len = sizeof(sin);
+ getsockname(fd, (struct sockaddr *)&sin, &len);
+ purple_debug(PURPLE_DEBUG_INFO, desc, "%s:%d\n",
+ inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
+ }
+ */
+
+/* QQ 2003iii uses double MD5 for the pwkey to get the session key */
+static guint8 *encrypt_account_password(const gchar *pwd)
+{
+ PurpleCipher *cipher;
+ PurpleCipherContext *context;
+
+ guchar pwkey_tmp[QQ_KEY_LENGTH];
+
+ cipher = purple_ciphers_find_cipher("md5");
+ context = purple_cipher_context_new(cipher, NULL);
+ purple_cipher_context_append(context, (guchar *) pwd, strlen(pwd));
+ purple_cipher_context_digest(context, sizeof(pwkey_tmp), pwkey_tmp, NULL);
+ purple_cipher_context_destroy(context);
+ context = purple_cipher_context_new(cipher, NULL);
+ purple_cipher_context_append(context, pwkey_tmp, QQ_KEY_LENGTH);
+ purple_cipher_context_digest(context, sizeof(pwkey_tmp), pwkey_tmp, NULL);
+ purple_cipher_context_destroy(context);
+
+ return g_memdup(pwkey_tmp, QQ_KEY_LENGTH);
+}
+
+/* default process, decrypt and dump */
+static void packet_process_unknow(PurpleConnection *gc, guint8 *buf, gint buf_len, guint16 cmd, guint16 seq)
+{
+ qq_data *qd;
+ guint8 *data;
+ gint data_len;
+ gchar *msg_utf8 = NULL;
+
+ g_return_if_fail(buf != NULL && buf_len != 0);
+
+ qq_show_packet("Processing unknown packet", buf, buf_len);
+
+ qd = (qq_data *) gc->proto_data;
+
+ data_len = buf_len;
+ data = g_newa(guint8, data_len);
+ memset(data, 0, data_len);
+ if ( !qq_decrypt(buf, buf_len, qd->session_key, data, &data_len )) {
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail decrypt packet with default process\n");
+ return;
+ }
+
+ qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
+ data, data_len,
+ ">>> [%d] %s -> [default] decrypt and dump",
+ seq, qq_get_cmd_desc(cmd));
+
+ msg_utf8 = try_dump_as_gbk(data, data_len);
+ if (msg_utf8) {
+ g_free(msg_utf8);
+ }
+}
+
+static gint packet_get_header(guint8 *header_tag, guint16 *source_tag,
+ guint16 *cmd, guint16 *seq, guint8 *buf)
+{
+ gint bytes = 0;
+ bytes += qq_get8(header_tag, buf + bytes);
+ bytes += qq_get16(source_tag, buf + bytes);
+ bytes += qq_get16(cmd, buf + bytes);
+ bytes += qq_get16(seq, buf + bytes);
+ return bytes;
+}
+
+/* check whether one sequence number is duplicated or not
+ * return TRUE if it is duplicated, otherwise FALSE */
+static gboolean packet_is_dup(qq_data *qd, guint16 seq)
+{
+ guint8 *byte, mask;
+
+ g_return_val_if_fail(qd != NULL, FALSE);
+
+ byte = &(qd->rcv_window[seq / 8]);
+ mask = (1 << (seq % 8));
+
+ if ((*byte) & mask)
+ return TRUE; /* check mask */
+ (*byte) |= mask;
+ return FALSE; /* set mask */
+}
+
+static gboolean packet_check_ack(qq_data *qd, guint16 seq)
+{
+ gpointer trans;
+
+ g_return_val_if_fail(qd != NULL, FALSE);
+
+ trans = qq_trans_find(qd, seq);
+ if (trans == NULL) {
+ return FALSE;
+ }
+
+ qq_trans_remove(qd, trans);
+ return TRUE;
+}
+
+static void packet_process_cmd(
+ PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len)
+{
+ /* now process the packet */
+ switch (cmd) {
+ case QQ_CMD_KEEP_ALIVE:
+ qq_process_keep_alive_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_UPDATE_INFO:
+ qq_process_modify_info_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_ADD_FRIEND_WO_AUTH:
+ qq_process_add_buddy_reply(data, data_len, seq, gc);
+ break;
+ case QQ_CMD_DEL_FRIEND:
+ qq_process_remove_buddy_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_REMOVE_SELF:
+ qq_process_remove_self_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_BUDDY_AUTH:
+ qq_process_add_buddy_auth_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_GET_USER_INFO:
+ qq_process_get_info_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_CHANGE_ONLINE_STATUS:
+ qq_process_change_status_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_SEND_IM:
+ qq_process_send_im_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_RECV_IM:
+ qq_process_recv_im(data, data_len, seq, gc);
+ break;
+ case QQ_CMD_LOGIN:
+ qq_process_login_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_GET_FRIENDS_LIST:
+ qq_process_get_buddies_list_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_GET_FRIENDS_ONLINE:
+ qq_process_get_buddies_online_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_GROUP_CMD:
+ qq_process_group_cmd_reply(data, data_len, seq, gc);
+ break;
+ case QQ_CMD_GET_ALL_LIST_WITH_GROUP:
+ qq_process_get_all_list_with_group_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_GET_LEVEL:
+ qq_process_get_level_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_REQUEST_LOGIN_TOKEN:
+ qq_process_request_login_token_reply(data, data_len, gc);
+ break;
+ case QQ_CMD_RECV_MSG_SYS:
+ qq_process_msg_sys(data, data_len, seq, gc);
+ break;
+ case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
+ qq_process_friend_change_status(data, data_len, gc);
+ break;
+ default:
+ packet_process_unknow(gc, data, data_len, cmd, seq);
+ break;
+ }
+}
+
+/* process the incoming packet from qq_pending */
+static void packet_process(PurpleConnection *gc, guint8 *buf, gint buf_len)
+{
+ qq_data *qd;
+ gint bytes, bytes_not_read;
+
+ gboolean prev_login_status;
+ guint8 *new_data;
+ gint new_data_len;
+
+ guint8 header_tag;
+ guint16 source_tag;
+ guint16 cmd;
+ guint16 seq; // May be ack_seq or send_seq, depends on cmd
+
+ g_return_if_fail(buf != NULL && buf_len > 0);
+
+ qd = (qq_data *) gc->proto_data;
+
+ prev_login_status = qd->logged_in;
+
+ // Len, header and tail tag have been checked before
+ bytes = 0;
+ bytes += packet_get_header(&header_tag, &source_tag, &cmd, &seq, buf + bytes);
+
+ if (QQ_DEBUG) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ",
+ "==> [%05d] 0x%04X %s, from (0x%04X %s)\n",
+ seq, cmd, qq_get_cmd_desc(cmd), source_tag, qq_get_source_str(source_tag));
+ }
+
+ bytes_not_read = buf_len - bytes - 1;
+
+ if ( !qd->logged_in ) {
+ if (cmd != QQ_CMD_LOGIN && cmd != QQ_CMD_REQUEST_LOGIN_TOKEN) {
+ /* packets before login */
+ qq_packet_push(qd, cmd, seq, buf + bytes, bytes_not_read);
+ return; /* do not process it now */
+ }
+ }
+
+ /* whether it is an ack */
+ switch (cmd) {
+ case QQ_CMD_RECV_IM:
+ case QQ_CMD_RECV_MSG_SYS:
+ case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
+ /* server intiated packet, we need to send ack and check duplicaion
+ * this must be put after processing b4_packet
+ * as these packets will be passed in twice */
+ if (packet_is_dup(qd, seq)) {
+ purple_debug(PURPLE_DEBUG_WARNING,
+ "QQ", "dup [%05d] %s, discard...\n", seq, qq_get_cmd_desc(cmd));
+ return;
+ }
+ break;
+ default:
+ /* ack packet, we need to update sendqueue */
+ /* we do not check duplication for server ack */
+ packet_check_ack(qd, seq);
+ }
+
+ /* this is the length of all the encrypted data (also remove tail tag */
+ packet_process_cmd(gc, cmd, seq, buf + bytes, bytes_not_read);
+
+ // check is redirect or not, and do it now
+ if (qd->is_redirect) {
+ // free resource except real_hostname and port
+ qq_disconnect(gc);
+ qq_connect(gc->account);
+ return;
+ }
+
+ if (prev_login_status != qd->logged_in && qd->logged_in == TRUE) {
+ /* logged_in, but we have packets before login */
+ new_data = g_newa(guint8, MAX_PACKET_SIZE);
+ while (1) {
+ new_data_len = qq_packet_pop(qd, &cmd, &seq, new_data, MAX_PACKET_SIZE);
+ if (new_data_len < 0) {
+ break;
+ }
+ if (new_data_len == 0) {
+ continue;
+ }
+ packet_process_cmd(gc, seq, cmd, new_data, new_data_len);
+ }
+ }
+}
+
+static void tcp_pending(gpointer data, gint source, PurpleInputCondition cond)
+{
+ PurpleConnection *gc;
+ qq_data *qd;
+ guint8 buf[1024]; // set to 16 when test tcp_rxqueue
+ gint buf_len;
+ gint bytes;
+
+ guint8 *pkt;
+ guint16 pkt_len;
+
+ gchar *error_msg;
+ guint8 *jump;
+ gint jump_len;
+
+ gc = (PurpleConnection *) data;
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+
+ if(cond != PURPLE_INPUT_READ) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Socket error"));
+ return;
+ }
+
+ qd = (qq_data *) gc->proto_data;
+
+ /* test code, not using tcp_rxqueue
+ memset(pkt,0, sizeof(pkt));
+ buf_len = read(qd->fd, pkt, sizeof(pkt));
+ if (buf_len > 2) {
+ packet_process(gc, pkt + 2, buf_len - 2);
+ }
+ return;
+ */
+
+ buf_len = read(qd->fd, buf, sizeof(buf));
+ if (buf_len < 0) {
+ if (errno == EAGAIN)
+ /* No worries */
+ 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);
+ g_free(error_msg);
+ return;
+ } else if (buf_len == 0) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Server closed the connection."));
+ return;
+ }
+
+ gc->last_received = time(NULL);
+ purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING",
+ "Read %d bytes from socket, rxlen is %d\n", buf_len, qd->tcp_rxlen);
+ qd->tcp_rxqueue = g_realloc(qd->tcp_rxqueue, buf_len + qd->tcp_rxlen);
+ memcpy(qd->tcp_rxqueue + qd->tcp_rxlen, buf, buf_len);
+ qd->tcp_rxlen += buf_len;
+
+ pkt = g_newa(guint8, MAX_PACKET_SIZE);
+ while (1) {
+ if (qd->tcp_rxlen < QQ_TCP_HEADER_LENGTH) {
+ break;
+ }
+
+ bytes = 0;
+ bytes += qq_get16(&pkt_len, qd->tcp_rxqueue + bytes);
+ if (qd->tcp_rxlen < pkt_len) {
+ break;
+ }
+
+ purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING",
+ "Packet len is %d bytes, rxlen is %d\n", pkt_len, qd->tcp_rxlen);
+
+ if ( pkt_len < QQ_TCP_HEADER_LENGTH
+ || *(qd->tcp_rxqueue + bytes) != QQ_PACKET_TAG
+ || *(qd->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) {
+ // HEY! This isn't even a QQ. What are you trying to pull?
+
+ purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING",
+ "Packet error, failed to check header and tail tag\n");
+
+ jump = memchr(qd->tcp_rxqueue + 1, QQ_PACKET_TAIL, qd->tcp_rxlen - 1);
+ if ( !jump ) {
+ purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING",
+ "Failed to find next QQ_PACKET_TAIL, clear receive buffer\n");
+ g_free(qd->tcp_rxqueue);
+ qd->tcp_rxqueue = NULL;
+ qd->tcp_rxlen = 0;
+ return;
+ }
+
+ // jump and over QQ_PACKET_TAIL
+ jump_len = (jump - qd->tcp_rxqueue) + 1;
+ purple_debug(PURPLE_DEBUG_INFO, "TCP_PENDING",
+ "Find next QQ_PACKET_TAIL at %d, jump %d bytes\n", jump_len, jump_len + 1);
+ g_memmove(qd->tcp_rxqueue, jump, qd->tcp_rxlen - jump_len);
+ qd->tcp_rxlen -= jump_len;
+ continue;
+ }
+
+ memset(pkt, 0, MAX_PACKET_SIZE);
+ g_memmove(pkt, qd->tcp_rxqueue + bytes, pkt_len - bytes);
+
+ // jump to next packet
+ qd->tcp_rxlen -= pkt_len;
+ if (qd->tcp_rxlen) {
+ purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING",
+ "shrink tcp_rxqueue to %d\n", qd->tcp_rxlen);
+ jump = g_memdup(qd->tcp_rxqueue + pkt_len, qd->tcp_rxlen);
+ g_free(qd->tcp_rxqueue);
+ qd->tcp_rxqueue = jump;
+ } else {
+ purple_debug(PURPLE_DEBUG_ERROR, "TCP_PENDING",
+ "free tcp_rxqueue\n");
+ g_free(qd->tcp_rxqueue);
+ qd->tcp_rxqueue = NULL;
+ }
+
+ if (pkt == NULL) {
+ continue;
+ }
+ // do not call packet_process before jump
+ // packet_process may call disconnect and destory tcp_rxqueue
+ packet_process(gc, pkt, pkt_len - bytes);
+ }
+}
+
+static void udp_pending(gpointer data, gint source, PurpleInputCondition cond)
+{
+ PurpleConnection *gc;
+ qq_data *qd;
+ guint8 *buf;
+ gint buf_len;
+
+ gc = (PurpleConnection *) data;
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+
+ if(cond != PURPLE_INPUT_READ) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Socket error"));
+ return;
+ }
+
+ qd = (qq_data *) gc->proto_data;
+ g_return_if_fail(qd->fd >= 0);
+
+ buf = g_newa(guint8, MAX_PACKET_SIZE);
+
+ /* here we have UDP proxy suppport */
+ buf_len = read(qd->fd, buf, MAX_PACKET_SIZE);
+ if (buf_len <= 0) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Unable to read from socket"));
+ return;
+ }
+
+ gc->last_received = time(NULL);
+
+ if (buf_len < QQ_UDP_HEADER_LENGTH) {
+ if (buf[0] != QQ_PACKET_TAG || buf[buf_len - 1] != QQ_PACKET_TAIL) {
+ qq_hex_dump(PURPLE_DEBUG_ERROR, "UDP_PENDING",
+ buf, buf_len,
+ "Received packet is too short, or no header and tail tag");
+ return;
+ }
+ }
+
+ packet_process(gc, buf, buf_len);
+}
+
+static gint udp_send_out(qq_data *qd, guint8 *data, gint data_len)
+{
+ gint ret;
+
+ g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1);
+
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Send %d bytes to socket %d\n", data_len, qd->fd);
+
+ errno = 0;
+ ret = send(qd->fd, data, data_len, 0);
+ if (ret < 0 && errno == EAGAIN) {
+ return ret;
+ }
+
+ if (ret < 0) {
+ /* TODO: what to do here - do we really have to disconnect? */
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Send failed: %d, %s\n", errno, g_strerror(errno));
+ purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno));
+ }
+ return ret;
+}
+
+static void tcp_can_write(gpointer data, gint source, PurpleInputCondition cond)
+{
+ qq_data *qd = data;
+ int ret, writelen;
+
+ writelen = purple_circ_buffer_get_max_read(qd->tcp_txbuf);
+ if (writelen == 0) {
+ purple_input_remove(qd->tx_handler);
+ qd->tx_handler = 0;
+ return;
+ }
+
+ ret = write(qd->fd, qd->tcp_txbuf->outptr, writelen);
+ purple_debug(PURPLE_DEBUG_ERROR, "TCP_CAN_WRITE",
+ "total %d bytes is sent %d\n", writelen, ret);
+
+ if (ret < 0 && errno == EAGAIN)
+ return;
+ else if (ret < 0) {
+ /* TODO: what to do here - do we really have to disconnect? */
+ purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Write Error"));
+ return;
+ }
+
+ purple_circ_buffer_mark_read(qd->tcp_txbuf, ret);
+}
+
+static gint tcp_send_out(qq_data *qd, guint8 *data, gint data_len)
+{
+ gint ret;
+
+ g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && data_len > 0, -1);
+
+ // purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Send %d bytes to socket %d\n", data_len, qd->fd);
+
+ if (qd->tx_handler == 0) {
+ ret = write(qd->fd, data, data_len);
+ } else {
+ ret = -1;
+ errno = EAGAIN;
+ }
+
+ purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT",
+ "Socket %d, total %d bytes is sent %d\n", qd->fd, data_len, ret);
+ if (ret < 0 && errno == EAGAIN) {
+ // socket is busy, send later
+ // purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT", "Socket is busy and send later\n");
+ ret = 0;
+ } else if (ret <= 0) {
+ // TODO: what to do here - do we really have to disconnect?
+ purple_debug(PURPLE_DEBUG_ERROR, "TCP_SEND_OUT",
+ "Send to socket %d failed: %d, %s\n", qd->fd, errno, g_strerror(errno));
+ purple_connection_error_reason(qd->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, g_strerror(errno));
+ return ret;
+ }
+
+ if (ret < data_len) {
+ purple_debug(PURPLE_DEBUG_INFO, "TCP_SEND_OUT",
+ "Add %d bytes to buffer\n", data_len - ret);
+ if (qd->tx_handler == 0) {
+ qd->tx_handler = purple_input_add(qd->fd, PURPLE_INPUT_WRITE, tcp_can_write, qd);
+ }
+ purple_circ_buffer_append(qd->tcp_txbuf, data + ret, data_len - ret);
+ }
+ return ret;
+}
+
+static gboolean trans_timeout(gpointer data)
+{
+ PurpleConnection *gc;
+ qq_data *qd;
+ guint8 *buf;
+ gint buf_len = 0;
+ guint16 cmd;
+ gint retries = 0;
+ int index;
+
+ gc = (PurpleConnection *) data;
+ g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, TRUE);
+
+ qd = (qq_data *) gc->proto_data;
+
+ index = 0;
+ buf = g_newa(guint8, MAX_PACKET_SIZE);
+
+ while (1) {
+ if (index < 0) {
+ // next record is NULL
+ break;
+ }
+ // purple_debug(PURPLE_DEBUG_ERROR, "QQ", "scan begin %d\n", index);
+ memset(buf, 0, MAX_PACKET_SIZE);
+ buf_len = qq_trans_scan(qd, &index, buf, MAX_PACKET_SIZE, &cmd, &retries);
+ if (buf_len <= 0) {
+ // curr record is empty, whole trans is NULL
+ break;
+ }
+ // index = -1, when get last record of transactions
+
+ // purple_debug(PURPLE_DEBUG_ERROR, "QQ", "retries %d next index %d\n", retries, index);
+ if (retries > 0) {
+ if (qd->use_tcp) {
+ tcp_send_out(qd, buf, buf_len);
+ } else {
+ udp_send_out(qd, buf, buf_len);
+ }
+ continue;
+ }
+
+ // retries <= 0
+ switch (cmd) {
+ case QQ_CMD_KEEP_ALIVE:
+ if (qd->logged_in) {
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection lost!\n");
+ purple_connection_error_reason(gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Connection lost"));
+ qd->logged_in = FALSE;
+ }
+ break;
+ case QQ_CMD_LOGIN:
+ case QQ_CMD_REQUEST_LOGIN_TOKEN:
+ if (!qd->logged_in) {
+ /* cancel login progress */
+ purple_connection_error_reason(gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Login failed, no reply"));
+ }
+ break;
+ default:
+ purple_debug(PURPLE_DEBUG_WARNING, "QQ",
+ "%s packet lost.\n", qq_get_cmd_desc(cmd));
+ }
+ }
+
+ return TRUE; /* if return FALSE, timeout callback stops */
+}
+
+/* the callback function after socket is built
+ * we setup the qq protocol related configuration here */
+static void qq_connect_cb(gpointer data, gint source, const gchar *error_message)
+{
+ qq_data *qd;
+ PurpleConnection *gc;
+ gchar *buf;
+ const gchar *passwd;
+
+ gc = (PurpleConnection *) data;
+
+ if (!PURPLE_CONNECTION_IS_VALID(gc)) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Invalid connection\n");
+ close(source);
+ return;
+ }
+
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+
+ qd = (qq_data *) gc->proto_data;
+
+ /* Connect is now complete; clear the PurpleProxyConnectData */
+ qd->connect_data = NULL;
+
+ if (source < 0) { /* socket returns -1 */
+ purple_debug(PURPLE_DEBUG_INFO, "QQ_CONN", "Source is < 0\n");
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
+ return;
+ }
+
+ // _qq_show_socket("Got login socket", source);
+
+ /* QQ use random seq, to minimize duplicated packets */
+ srandom(time(NULL));
+ qd->send_seq = random() & 0x0000ffff;
+ qd->fd = source;
+ qd->logged_in = FALSE;
+ qd->channel = 1;
+ qd->uid = strtol(purple_account_get_username(purple_connection_get_account(gc)), NULL, 10);
+
+ /* now generate md5 processed passwd */
+ passwd = purple_account_get_password(purple_connection_get_account(gc));
+ g_return_if_fail(qd->pwkey == NULL);
+ qd->pwkey = encrypt_account_password(passwd);
+
+ g_return_if_fail(qd->resend_timeout == 0);
+ /* call trans_timeout every 5 seconds */
+ qd->resend_timeout = purple_timeout_add(5000, trans_timeout, gc);
+
+ if (qd->use_tcp)
+ gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, tcp_pending, gc);
+ else
+ gc->inpa = purple_input_add(qd->fd, PURPLE_INPUT_READ, udp_pending, gc);
+
+ /* Update the login progress status display */
+ buf = g_strdup_printf("Login as %d", qd->uid);
+ purple_connection_update_progress(gc, buf, 1, QQ_CONNECT_STEPS);
+ g_free(buf);
+
+ qq_send_packet_request_login_token(gc);
+}
+
+static void udp_can_write(gpointer data, gint source, PurpleInputCondition cond)
+{
+ PurpleConnection *gc;
+ qq_data *qd;
+ socklen_t len;
+ int error=0, ret;
+
+ gc = (PurpleConnection *) data;
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+
+ qd = (qq_data *) gc->proto_data;
+
+
+ purple_debug_info("proxy", "Connected.\n");
+
+ /*
+ * getsockopt after a non-blocking connect returns -1 if something is
+ * really messed up (bad descriptor, usually). Otherwise, it returns 0 and
+ * error holds what connect would have returned if it blocked until now.
+ * Thus, error == 0 is success, error == EINPROGRESS means "try again",
+ * and anything else is a real error.
+ *
+ * (error == EINPROGRESS can happen after a select because the kernel can
+ * be overly optimistic sometimes. select is just a hint that you might be
+ * able to do something.)
+ */
+ len = sizeof(error);
+ ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len);
+ if (ret == 0 && error == EINPROGRESS)
+ return; /* we'll be called again later */
+
+ purple_input_remove(qd->tx_handler);
+ qd->tx_handler = 0;
+ if (ret < 0 || error != 0) {
+ if(ret != 0)
+ error = errno;
+
+ close(source);
+
+ purple_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", g_strerror(error));
+
+ qq_connect_cb(gc, -1, _("Unable to connect"));
+ return;
+ }
+
+ qq_connect_cb(gc, source, NULL);
+}
+
+static void udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) {
+ PurpleConnection *gc;
+ qq_data *qd;
+ struct sockaddr server_addr;
+ int addr_size;
+ gint fd = -1;
+ int flags;
+
+ gc = (PurpleConnection *) data;
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+
+ qd = (qq_data *) gc->proto_data;
+
+ // udp_query_data must be set as NULL.
+ // Otherwise purple_dnsquery_destroy in qq_disconnect cause glib double free error
+ qd->udp_query_data = NULL;
+
+ if (!hosts || !hosts->data) {
+ purple_connection_error_reason(gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Couldn't resolve host"));
+ return;
+ }
+
+ addr_size = GPOINTER_TO_INT(hosts->data);
+ hosts = g_slist_remove(hosts, hosts->data);
+ memcpy(&server_addr, hosts->data, addr_size);
+ g_free(hosts->data);
+
+ hosts = g_slist_remove(hosts, hosts->data);
+ while(hosts) {
+ hosts = g_slist_remove(hosts, hosts->data);
+ g_free(hosts->data);
+ hosts = g_slist_remove(hosts, hosts->data);
+ }
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+ "Unable to create socket: %s\n", g_strerror(errno));
+ return;
+ }
+
+ /* we use non-blocking mode to speed up connection */
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ /* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/
+ *
+ * If a UDP socket is unconnected, which is the normal state after a
+ * bind() call, then send() or write() are not allowed, since no
+ * destination is available; only sendto() can be used to send data.
+ *
+ * Calling connect() on the socket simply records the specified address
+ * and port number as being the desired communications partner. That
+ * means that send() or write() are now allowed; they use the destination
+ * address and port given on the connect call as the destination of packets.
+ */
+ if (connect(fd, &server_addr, addr_size) >= 0) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Connected.\n");
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+ qq_connect_cb(gc, fd, NULL);
+ return;
+ }
+
+ /* [EINPROGRESS]
+ * The socket is marked as non-blocking and the connection cannot be
+ * completed immediately. It is possible to select for completion by
+ * selecting the socket for writing.
+ * [EINTR]
+ * A signal interrupted the call.
+ * The connection is established asynchronously.
+ */
+ if ((errno == EINPROGRESS) || (errno == EINTR)) {
+ purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n");
+ qd->tx_handler = purple_input_add(fd, PURPLE_INPUT_WRITE, udp_can_write, gc);
+ return;
+ }
+
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection failed: %d\n", g_strerror(errno));
+ close(fd);
+}
+
+/* establish a generic QQ connection
+ * TCP/UDP, and direct/redirected */
+void qq_connect(PurpleAccount *account)
+{
+ PurpleConnection *gc;
+ qq_data *qd;
+
+ gc = purple_account_get_connection(account);
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+
+ qd = (qq_data *) gc->proto_data;
+
+ if (qd->real_hostname == NULL || qd->real_port == 0) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("hostname is NULL or port is 0"));
+ return;
+ }
+
+ if (qd->is_redirect) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Redirect to %s:%d\n",
+ qd->real_hostname, qd->real_port);
+ }
+ qd->is_redirect = FALSE;
+
+ qd->fd = -1;
+ qd->tx_handler = 0;
+
+ g_return_if_fail(qd->real_hostname != NULL);
+
+ /* QQ connection via UDP/TCP.
+ * Now use Purple proxy function to provide TCP proxy support,
+ * and qq_udp_proxy.c to add UDP proxy support (thanks henry) */
+ if(qd->use_tcp) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "TCP Connect to %s:%d\n",
+ qd->real_hostname, qd->real_port);
+
+ /* TODO: is there a good default grow size? */
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Create tcp_txbuf\n");
+ qd->tcp_txbuf = purple_circ_buffer_new(0);
+
+ qd->connect_data = purple_proxy_connect(NULL, account,
+ qd->real_hostname, qd->real_port, qq_connect_cb, gc);
+ if (qd->connect_data == NULL) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Unable to connect."));
+ }
+ return;
+ }
+
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "UDP Connect to %s:%d\n",
+ qd->real_hostname, qd->real_port);
+
+ g_return_if_fail(qd->udp_query_data == NULL);
+ qd->udp_query_data = purple_dnsquery_a(qd->real_hostname, qd->real_port,
+ udp_host_resolved, gc);
+ if (qd->udp_query_data == NULL) {
+ purple_connection_error_reason(qd->gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Could not resolve hostname"));
+ }
+}
+
+/* clean up qq_data structure and all its components
+ * always used before a redirectly connection */
+void qq_disconnect(PurpleConnection *gc)
+{
+ qq_data *qd;
+
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+ qd = (qq_data *) gc->proto_data;
+
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Disconnecting ...\n");
+ /* finish all I/O */
+ if (qd->fd >= 0 && qd->logged_in) {
+ qq_send_packet_logout(gc);
+ }
+
+ if (qd->resend_timeout > 0) {
+ purple_timeout_remove(qd->resend_timeout);
+ qd->resend_timeout = 0;
+ }
+
+ if (gc->inpa > 0) {
+ purple_input_remove(gc->inpa);
+ gc->inpa = 0;
+ }
+
+ if (qd->fd >= 0) {
+ close(qd->fd);
+ qd->fd = -1;
+ }
+
+ if (qd->connect_data != NULL) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "Cancel connect_data\n");
+ purple_proxy_connect_cancel(qd->connect_data);
+ }
+
+ if(qd->tcp_txbuf != NULL) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_txbuf\n");
+ purple_circ_buffer_destroy(qd->tcp_txbuf);
+ }
+
+ if (qd->tx_handler) {
+ purple_input_remove(qd->tx_handler);
+ qd->tx_handler = 0;
+ }
+ if (qd->tcp_rxqueue != NULL) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy tcp_rxqueue\n");
+ g_free(qd->tcp_rxqueue);
+ qd->tcp_rxqueue = NULL;
+ qd->tcp_rxlen = 0;
+ }
+
+ if (qd->udp_query_data != NULL) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy udp_query_data\n");
+ purple_dnsquery_destroy(qd->udp_query_data);
+ qd->udp_query_data = NULL;
+ }
+
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "destroy transactions\n");
+ qq_trans_remove_all(qd);
+
+ if (qd->inikey) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "free inikey\n");
+ g_free(qd->inikey);
+ qd->inikey = NULL;
+ }
+ if (qd->pwkey) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "free pwkey\n");
+ g_free(qd->pwkey);
+ qd->pwkey = NULL;
+ }
+ if (qd->session_key) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "free session_key\n");
+ g_free(qd->session_key);
+ qd->session_key = NULL;
+ }
+ if (qd->session_md5) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "free session_md5\n");
+ g_free(qd->session_md5);
+ qd->session_md5 = NULL;
+ }
+ if (qd->my_ip) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "free my_ip\n");
+ g_free(qd->my_ip);
+ qd->my_ip = NULL;
+ }
+
+ qq_packet_remove_all(qd);
+ qq_group_packets_free(qd);
+ qq_group_free_all(qd);
+ qq_add_buddy_request_free(qd);
+ qq_info_query_free(qd);
+ qq_buddies_list_free(gc->account, qd);
+}
+
+static gint encap(qq_data *qd, guint8 *buf, gint maxlen, guint16 cmd, guint16 seq,
+ guint8 *data, gint data_len)
+{
+ gint bytes = 0;
+ g_return_val_if_fail(qd != NULL && buf != NULL && maxlen > 0, -1);
+
+ if (data == NULL) {
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail encap packet, data is NULL\n");
+ return -1;
+ }
+ if (data_len <= 0) {
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail encap packet, data len <= 0\n");
+ return -1;
+ }
+
+ /* QQ TCP packet has two bytes in the begining defines packet length
+ * so leave room here to store packet size */
+ if (qd->use_tcp) {
+ bytes += qq_put16(buf + bytes, 0x0000);
+ }
+ /* now comes the normal QQ packet as UDP */
+ bytes += qq_put8(buf + bytes, QQ_PACKET_TAG);
+ bytes += qq_put16(buf + bytes, QQ_CLIENT);
+ bytes += qq_put16(buf + bytes, cmd);
+
+ bytes += qq_put16(buf + bytes, seq);
+
+ bytes += qq_put32(buf + bytes, qd->uid);
+ bytes += qq_putdata(buf + bytes, data, data_len);
+ bytes += qq_put8(buf + bytes, QQ_PACKET_TAIL);
+
+ // set TCP packet length at begin of the packet
+ if (qd->use_tcp) {
+ qq_put16(buf, bytes);
+ }
+
+ return bytes;
+}
+
+gint qq_send_data(PurpleConnection *gc, guint16 cmd, guint8 *data, gint data_len)
+{
+ qq_data *qd;
+ guint8 *buf;
+ gint buf_len;
+ gint bytes_sent;
+ gint seq;
+
+ g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1);
+ qd = (qq_data *) gc->proto_data;
+
+ buf = g_newa(guint8, MAX_PACKET_SIZE);
+ memset(buf, 0, MAX_PACKET_SIZE);
+ seq = ++(qd->send_seq);
+ buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, data, data_len);
+ if (buf_len <= 0) {
+ return -1;
+ }
+
+ if (qd->use_tcp) {
+ bytes_sent = tcp_send_out(qd, buf, buf_len);
+ } else {
+ bytes_sent = udp_send_out(qd, buf, buf_len);
+ }
+
+ // always need ack
+ qq_trans_append(qd, buf, buf_len, cmd, seq);
+
+ if (QQ_DEBUG) {
+ qq_show_packet("QQ_SEND_DATA", buf, buf_len);
+ purple_debug(PURPLE_DEBUG_INFO, "QQ",
+ "<== [%05d], %s, total %d bytes is sent %d\n",
+ seq, qq_get_cmd_desc(cmd), buf_len, bytes_sent);
+ }
+ return bytes_sent;
+}
+
+/* send the packet generated with the given cmd and data
+ * return the number of bytes sent to socket if succeeds
+ * return -1 if there is any error */
+gint qq_send_cmd(PurpleConnection *gc, guint16 cmd,
+ gboolean is_auto_seq, guint16 seq, gboolean need_ack, guint8 *data, gint data_len)
+{
+ qq_data *qd;
+ guint8 *buf;
+ gint buf_len;
+ guint8 *encrypted_data;
+ gint encrypted_len;
+ gint real_seq;
+ gint bytes_sent;
+
+ qd = (qq_data *) gc->proto_data;
+ g_return_val_if_fail(qd->session_key != NULL, -1);
+
+ encrypted_len = data_len + 16; /* at most 16 bytes more */
+ encrypted_data = g_newa(guint8, encrypted_len);
+
+ qq_encrypt(data, data_len, qd->session_key, encrypted_data, &encrypted_len);
+
+ real_seq = seq;
+ if (is_auto_seq) real_seq = ++(qd->send_seq);
+
+ buf = g_newa(guint8, MAX_PACKET_SIZE);
+ memset(buf, 0, MAX_PACKET_SIZE);
+ buf_len = encap(qd, buf, MAX_PACKET_SIZE, cmd, real_seq, encrypted_data, encrypted_len);
+ if (buf_len <= 0) {
+ return -1;
+ }
+
+ if (QQ_DEBUG) {
+ qq_show_packet("QQ_SEND_CMD", buf, buf_len);
+ }
+ if (qd->use_tcp) {
+ bytes_sent = tcp_send_out(qd, buf, buf_len);
+ } else {
+ bytes_sent = udp_send_out(qd, buf, buf_len);
+ }
+
+ /* if it does not need ACK, we send ACK manually several times */
+ if (need_ack) {
+ qq_trans_append(qd, buf, buf_len, cmd, real_seq);
+ }
+
+ if (QQ_DEBUG) {
+ qq_show_packet("QQ_SEND_CMD", buf, buf_len);
+ purple_debug(PURPLE_DEBUG_INFO, "QQ",
+ "<== [%05d], %s, total %d bytes is sent %d\n",
+ real_seq, qq_get_cmd_desc(cmd), buf_len, bytes_sent);
+ }
+ return bytes_sent;
+}
============================================================
--- libpurple/protocols/qq/qq_network.h 13121110b5e9ac5f28a4198374a9714c2ea9731b
+++ libpurple/protocols/qq/qq_network.h 13121110b5e9ac5f28a4198374a9714c2ea9731b
@@ -0,0 +1,42 @@
+/**
+ * @file qq_network.h
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef _QQ_PROXY_H
+#define _QQ_PROXY_H
+
+#include <glib.h>
+#include "connection.h"
+
+#include "qq.h"
+
+#define QQ_CONNECT_STEPS 2 /* steps in connection */
+
+void qq_connect(PurpleAccount *account);
+void qq_disconnect(PurpleConnection *gc);
+
+gint qq_send_data(PurpleConnection *gc, guint16 cmd, guint8 *data, gint datalen);
+gint qq_send_cmd(PurpleConnection *gc, guint16 cmd, gboolean is_auto_seq, guint16 seq,
+ gboolean need_ack, guint8 *data, gint datalen);
+
+#endif
============================================================
--- libpurple/protocols/qq/ChangeLog 74834c1fda007327cf685f705151dfa8c309b0b1
+++ libpurple/protocols/qq/ChangeLog c71777eb23741e23437cac84a09b8bb0bd8692cb
@@ -1,4 +1,32 @@
+2008.05.14 - ccpaging <ecc_hy(at)hotmail.com>
+ * Move function for before login packets storing to sendqueue
+ * Use transaction data structure to store before login packets
+ * Rewrite tcp_pending and packet_process in qq_network.c
+
+2008.05.09 - ccpaging <ecc_hy(at)hotmail.com>
+ * Remove function _create_packet_head_seq in qq_network.c
+ * Create new function encap in qq_netowork.c
+ * Clean code of qq_send_packet_request_login_token and qq_send_packet_login in login_out.c
+
+2008.05.09 - ccpaging <ecc_hy(at)hotmail.com>
+ * Clean code of packet_parse.c, enable PARSER_DEBUG
+ * Rewrite send_queue
+
+2008.05.08 - ccpaging <ecc_hy(at)hotmail.com>
+ * Rewrite qq_network
+ * Add srv resolve function when qq_login
+ * Merge function _qq_common_clean in qq_proxy.c to qq_disconnect
+ * Move orignal qq_disconnect to qq_close
+ * qq_data alloc in qq_open and release in qq_close
+ * Network connect of QQ is created in qq_connect, and release in qq_disconnect
+
2008.05.05 - ccpaging <ecc_hy(at)hotmail.com>
+ * Merge function _qq_common_clean in qq_proxy.c to qq_disconnect
+ * Move orignal qq_disconnect to qq_close
+ * qq_data alloc in qq_open and release in qq_close
+ * Network connect of QQ is created in qq_connect, and release in qq_disconnect
+
+2008.05.05 - ccpaging <ecc_hy(at)hotmail.com>
* Add qq_hex_dump function
2008.04.25 - ccpaging <ecc_hy(at)hotmail.com>, csyfek <csyfek(at)gmail.com>
============================================================
--- libpurple/protocols/qq/Makefile.am 7757c2396080bb41056dd926d7ddbb0eeb1e3ad9
+++ libpurple/protocols/qq/Makefile.am 5f9cc460a8b169911e15ca4b55bbb68fd456acb7
@@ -52,20 +52,14 @@ QQSOURCES = \
packet_parse.h \
qq.c \
qq.h \
- qq_proxy.c \
- qq_proxy.h \
- recv_core.c \
- recv_core.h \
- send_core.c \
- send_core.h \
+ qq_network.c \
+ qq_network.h \
send_file.c \
send_file.h \
sendqueue.c \
sendqueue.h \
sys_msg.c \
sys_msg.h \
- udp_proxy_s5.c \
- udp_proxy_s5.h \
utils.c \
utils.h
============================================================
--- libpurple/protocols/qq/Makefile.mingw 5bf68ee252f7f365850547d565c32d11e1612ba0
+++ libpurple/protocols/qq/Makefile.mingw 0cd549b5aa0bb7745db1f61f3aa19b223f7a6e6a
@@ -63,13 +63,10 @@ C_SRC = \
login_logout.c \
packet_parse.c \
qq.c \
- qq_proxy.c \
- recv_core.c \
- send_core.c \
+ qq_network.c \
send_file.c \
sendqueue.c \
sys_msg.c \
- udp_proxy_s5.c \
utils.c
OBJECTS = $(C_SRC:%.c=%.o)
============================================================
--- libpurple/protocols/qq/buddy_info.c b67a8339be3923fb0ee199312b4c00d2b32769e5
+++ libpurple/protocols/qq/buddy_info.c b7646da7a807e77ea2391025491833f5a0b2df52
@@ -34,7 +34,7 @@
#include "crypt.h"
#include "header_info.h"
#include "keep_alive.h"
-#include "send_core.h"
+#include "qq_network.h"
#define QQ_PRIMARY_INFORMATION _("Primary Information")
#define QQ_ADDITIONAL_INFORMATION _("Additional Information")
============================================================
--- libpurple/protocols/qq/buddy_list.c c9abe3b8e1650eb7f3be22b26f797df4e26a00f1
+++ libpurple/protocols/qq/buddy_list.c fd6a60ef4a37d22cd31438bde3f338ba290bd2b8
@@ -38,13 +38,12 @@
#include "crypt.h"
#include "header_info.h"
#include "keep_alive.h"
-#include "send_core.h"
#include "group.h"
#include "group_find.h"
#include "group_internal.h"
#include "group_info.h"
-#include "qq_proxy.h"
+#include "qq_network.h"
#define QQ_GET_ONLINE_BUDDY_02 0x02
#define QQ_GET_ONLINE_BUDDY_03 0x03 /* unknown function */
@@ -164,7 +163,7 @@ void qq_process_get_buddies_online_reply
return;
}
- _qq_show_packet("Get buddies online reply packet", data, len);
+ qq_show_packet("Get buddies online reply packet", data, len);
bytes = 0;
bytes += qq_get8(&position, data + bytes);
============================================================
--- libpurple/protocols/qq/buddy_opt.c e7d5590e12c1034f9d286da2c7ee595959fd2931
+++ libpurple/protocols/qq/buddy_opt.c 19e35c2fca88964688857a8d3b9d2501e3d7f503
@@ -36,7 +36,7 @@
#include "im.h"
#include "keep_alive.h"
#include "packet_parse.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "utils.h"
#define PURPLE_GROUP_QQ_FORMAT "QQ (%s)"
============================================================
--- libpurple/protocols/qq/buddy_status.c bcc44df9ddf11a89efa5bee55a2a2b635529a892
+++ libpurple/protocols/qq/buddy_status.c 0632ad56e2f8b1700583f2bec90d4b2655036141
@@ -33,10 +33,9 @@
#include "header_info.h"
#include "keep_alive.h"
#include "packet_parse.h"
-#include "send_core.h"
#include "utils.h"
-#include "qq_proxy.h"
+#include "qq_network.h"
#define QQ_MISC_STATUS_HAVING_VIIDEO 0x00000001
#define QQ_CHANGE_ONLINE_STATUS_REPLY_OK 0x30 /* ASCII value of "0" */
@@ -57,7 +56,7 @@ void qq_buddy_status_dump_unclear(qq_bud
g_string_append_printf(dump, "013-014: %04x (client_version)\n", s->client_version);
/* g_string_append_printf(dump, "015-030: %s (unknown key)\n", s->unknown_key); */
purple_debug(PURPLE_DEBUG_INFO, "QQ", "Buddy status entry, %s", dump->str);
- _qq_show_packet("Unknown key", s->unknown_key, QQ_KEY_LENGTH);
+ qq_show_packet("Unknown key", s->unknown_key, QQ_KEY_LENGTH);
g_string_free(dump, TRUE);
}
============================================================
--- libpurple/protocols/qq/char_conv.c 8d6f5265c225bb6c8c9b2ae5d7834b9c7d2356c7
+++ libpurple/protocols/qq/char_conv.c c9333306d49303892a75c85fe7f0b536642e49a4
@@ -39,9 +39,6 @@
#define QQ_NULL_MSG "(NULL)" /* return this if conversion fails */
#define QQ_NULL_SMILEY "(SM)" /* return this if smiley conversion fails */
-/* a debug function */
-void _qq_show_packet(const gchar *desc, const guint8 *buf, gint len);
-
const gchar qq_smiley_map[QQ_SMILEY_AMOUNT] = {
0x41, 0x43, 0x42, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x73,
@@ -111,18 +108,19 @@ static gchar *_my_convert(const gchar *s
ret = g_convert(str, len, to_charset, from_charset, &byte_read, &byte_write, &error);
- if (error == NULL)
+ if (error == NULL) {
return ret; /* conversion is OK */
- else { /* conversion error */
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", error->message);
+ }
+
+ /* conversion error */
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "%s\n", error->message);
- qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
- (guint8 *) str, (len == -1) ? strlen(str) : len,
- "Dump failed text");
+ qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
+ (guint8 *) str, (len == -1) ? strlen(str) : len,
+ "Dump failed text");
- g_error_free(error);
- return g_strdup(QQ_NULL_MSG);
- }
+ g_error_free(error);
+ return g_strdup(QQ_NULL_MSG);
}
/* take the input as a pascal string and return a converted c-string in UTF-8
@@ -150,8 +148,8 @@ gchar *qq_encode_to_purple(guint8 *data,
gchar *font_name, *color_code, *msg_utf8, *tmp, *ret;
gint bytes = 0;
- /* checked _qq_show_packet OK */
- _qq_show_packet("QQ_MESG recv for font style", data, len);
+ /* checked qq_show_packet OK */
+ qq_show_packet("QQ_MESG recv for font style", data, len);
bytes += qq_get8(&font_attr, data + bytes);
bytes += qq_getdata(color, 3, data + bytes); /* red,green,blue */
============================================================
--- libpurple/protocols/qq/file_trans.c 9aa7babe032da796a32376265d7578f157f5bd22
+++ libpurple/protocols/qq/file_trans.c 4b99d365724c1f0e4fbef73a1febe2fbe78a46ab
@@ -38,7 +38,7 @@
#include "im.h"
#include "packet_parse.h"
#include "proxy.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "send_file.h"
#include "utils.h"
============================================================
--- libpurple/protocols/qq/group_network.c 3fafccf0c35fd48708f3d338cc64099df102798b
+++ libpurple/protocols/qq/group_network.c 80d18884793457839a0acb6771b7be36aacaa832
@@ -39,7 +39,7 @@
#include "group_opt.h"
#include "group_search.h"
#include "header_info.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "utils.h"
enum {
============================================================
--- libpurple/protocols/qq/im.c e670e2d144edd9eb3d861492771bc0f36b9d2cd9
+++ libpurple/protocols/qq/im.c e91f72d83ec7c15b2f2680116206653e6c0507d1
@@ -40,16 +40,13 @@
#include "header_info.h"
#include "im.h"
#include "packet_parse.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "send_file.h"
#include "utils.h"
#define QQ_SEND_IM_REPLY_OK 0x00
#define DEFAULT_FONT_NAME_LEN 4
-/* a debug function */
-void _qq_show_packet(const gchar *desc, const guint8 *buf, gint len);
-
enum
{
QQ_NORMAL_IM_TEXT = 0x000b,
@@ -182,7 +179,7 @@ guint8 *qq_get_send_im_tail(const gchar
send_im_tail[5] = 0x00;
send_im_tail[6] = 0x86;
send_im_tail[7] = 0x22; /* encoding, 0x8622=GB, 0x0000=EN, define BIG5 support here */
- _qq_show_packet("QQ_MESG", send_im_tail, tail_len);
+ qq_show_packet("QQ_MESG", send_im_tail, tail_len);
return (guint8 *) send_im_tail;
}
@@ -306,8 +303,6 @@ static void _qq_process_recv_normal_im_t
} else /* not im_text->is_there_font_attr */
im_text->msg = g_strndup((gchar *)(data + bytes), len - bytes);
} /* if im_text->msg_type */
- /* XXX _qq_show_packet here should not be used here */
- /* _qq_show_packet("QQ_MESG recv", data, *cursor - data); */
name = uid_to_purple_name(common->sender_uid);
if (purple_find_buddy(gc->account, name) == NULL)
@@ -386,11 +381,8 @@ static void _qq_process_recv_normal_im(g
im_unprocessed->length = len - bytes;
/* a simple process here, maybe more later */
purple_debug (PURPLE_DEBUG_WARNING, "QQ",
- "Normal IM, unprocessed type [0x%04x]\n",
- common->normal_im_type);
- purple_debug (PURPLE_DEBUG_WARNING, "QQ",
- im_unprocessed->unknown, im_unprocessed->length,
- "Dump unknown part.");
+ "Normal IM, unprocessed type [0x%04x], unknown [0x%02x], len %d\n",
+ common->normal_im_type, im_unprocessed->unknown, im_unprocessed->length);
g_free (common->session_md5);
return;
}
@@ -522,10 +514,10 @@ void qq_send_packet_im(PurpleConnection
bytes += qq_putdata(raw_data + bytes, (guint8 *) msg_filtered, msg_len);
send_im_tail = qq_get_send_im_tail(font_color, font_size, font_name, is_bold,
is_italic, is_underline, tail_len);
- _qq_show_packet("QQ_send_im_tail debug", send_im_tail, tail_len);
+ qq_show_packet("QQ_send_im_tail debug", send_im_tail, tail_len);
bytes += qq_putdata(raw_data + bytes, send_im_tail, tail_len);
- _qq_show_packet("QQ_raw_data debug", raw_data, bytes);
+ qq_show_packet("QQ_raw_data debug", raw_data, bytes);
if (bytes == raw_len) /* create packet OK */
qq_send_cmd(gc, QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, bytes);
============================================================
--- libpurple/protocols/qq/keep_alive.c 8c8e3adf3b8065151a548eedd319ff7b97d3d26c
+++ libpurple/protocols/qq/keep_alive.c 8577d0e6e583940cb85a8e3162d2c297c16c6843
@@ -40,7 +40,7 @@
#include "header_info.h"
#include "keep_alive.h"
#include "packet_parse.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "utils.h"
#define QQ_UPDATE_ONLINE_INTERVAL 300 /* in sec */
============================================================
--- libpurple/protocols/qq/login_logout.c 04590221b4bd53171616bee7c3df9094bdfa8cad
+++ libpurple/protocols/qq/login_logout.c 2aff209621bedc661e18371eb42f7aee94676f3a
@@ -25,6 +25,7 @@
#include "debug.h"
#include "internal.h"
#include "server.h"
+#include "cipher.h"
#include "buddy_info.h"
#include "buddy_list.h"
@@ -36,8 +37,7 @@
#include "login_logout.h"
#include "packet_parse.h"
#include "qq.h"
-#include "qq_proxy.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "utils.h"
#define QQ_LOGIN_DATA_LENGTH 416
@@ -71,32 +71,35 @@ static const guint8 login_23_51[29] = {
/* for QQ 2005? copy from lumaqq */
// Fixme: change to guint8
-static const gint8 login_23_51[29] = {
- 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, -122,
- -52, 76, 53, 44, -45, 115, 108, 20, -10, -10,
- -81, -61, -6, 51, -92, 1
+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 gint8 login_53_68[16] = {
- -115, -117, -6, -20, -43, 82, 23, 74, -122, -7,
- -89, 117, -26, 50, -47, 109
+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 gint8 login_100_bytes[100] = {
- 64,
- 11, 4, 2, 0, 1, 0, 0, 0, 0, 0,
- 3, 9, 0, 0, 0, 0, 0, 0, 0, 1,
- -23, 3, 1, 0, 0, 0, 0, 0, 1, -13,
- 3, 0, 0, 0, 0, 0, 0, 1, -19, 3,
- 0, 0, 0, 0, 0, 0, 1, -20, 3, 0,
- 0, 0, 0, 0, 0, 3, 5, 0, 0, 0,
- 0, 0, 0, 0, 3, 7, 0, 0, 0, 0,
- 0, 0, 0, 1, -18, 3, 0, 0, 0, 0,
- 0, 0, 1, -17, 3, 0, 0, 0, 0, 0,
- 0, 1, -21, 3, 0, 0, 0, 0, 0
+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] = {
@@ -139,17 +142,24 @@ struct _qq_login_reply_redirect {
guint16 new_server_port;
};
-extern gint /* defined in send_core.c */
- _create_packet_head_seq(guint8 *buf, PurpleConnection *gc,
- guint16 cmd, gboolean is_auto_seq, guint16 *seq);
-extern gint /* defined in send_core.c */
- _qq_send_packet(PurpleConnection *gc, guint8 *buf, gint len, guint16 cmd);
+/* generate a md5 key using uid and session_key */
+static guint8 *gen_session_md5(gint uid, guint8 *session_key)
+{
+ guint8 *src, md5_str[QQ_KEY_LENGTH];
+ PurpleCipher *cipher;
+ PurpleCipherContext *context;
-/* It is fixed to 16 bytes 0x01 for QQ2003,
- * Any value works (or a random 16 bytes string) */
-static guint8 *_gen_login_key(void)
-{
- return (guint8 *) g_strnfill(QQ_KEY_LENGTH, 0x01);
+ src = g_newa(guint8, 20);
+ memcpy(src, &uid, 4);
+ memcpy(src, session_key, QQ_KEY_LENGTH);
+
+ cipher = purple_ciphers_find_cipher("md5");
+ context = purple_cipher_context_new(cipher, NULL);
+ purple_cipher_context_append(context, src, 20);
+ purple_cipher_context_digest(context, sizeof(md5_str), md5_str, NULL);
+ purple_cipher_context_destroy(context);
+
+ return g_memdup(md5_str, QQ_KEY_LENGTH);
}
/* process login reply which says OK */
@@ -211,9 +221,15 @@ static gint _qq_process_login_ok(PurpleC
QQ_LOGIN_REPLY_OK_PACKET_LEN, bytes);
} /* but we still go on as login OK */
+ g_return_val_if_fail(qd->session_key == NULL, QQ_LOGIN_REPLY_MISC_ERROR);
qd->session_key = lrop.session_key;
- qd->session_md5 = _gen_session_md5(qd->uid, qd->session_key);
+
+ g_return_val_if_fail(qd->session_md5 == NULL, QQ_LOGIN_REPLY_MISC_ERROR);
+ qd->session_md5 = gen_session_md5(qd->uid, qd->session_key);
+
+ g_return_val_if_fail(qd->my_ip == NULL, QQ_LOGIN_REPLY_MISC_ERROR);
qd->my_ip = gen_ip_str(lrop.client_ip);
+
qd->my_port = lrop.client_port;
qd->login_time = lrop.login_time;
qd->last_login_time = lrop.last_login_time;
@@ -245,7 +261,6 @@ static gint _qq_process_login_redirect(P
static gint _qq_process_login_redirect(PurpleConnection *gc, guint8 *data, gint len)
{
gint bytes, ret;
- gchar *new_server_str;
qq_data *qd;
qq_login_reply_redirect_packet lrrp;
@@ -265,12 +280,21 @@ static gint _qq_process_login_redirect(P
"Fail parsing login redirect packet, expect %d bytes, read %d bytes\n",
QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN, bytes);
ret = QQ_LOGIN_REPLY_MISC_ERROR;
- } else { /* start new connection */
- new_server_str = gen_ip_str(lrrp.new_server_ip);
+ } else {
+ // redirect to new server, do not disconnect or connect here
+ // those connect should be called at packet_process
+ if (qd->real_hostname) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n");
+ g_free(qd->real_hostname);
+ qd->real_hostname = NULL;
+ }
+ qd->real_hostname = gen_ip_str(lrrp.new_server_ip);
+ qd->real_port = lrrp.new_server_port;
+ qd->is_redirect = TRUE;
+
purple_debug(PURPLE_DEBUG_WARNING, "QQ",
- "Redirected to new server: %s:%d\n", new_server_str, lrrp.new_server_port);
- qq_connect(gc->account, new_server_str, lrrp.new_server_port, qd->use_tcp, TRUE);
- g_free(new_server_str);
+ "Redirected to new server: %s:%d\n", qd->real_hostname, qd->real_port);
+
ret = QQ_LOGIN_REPLY_REDIRECT;
}
@@ -295,50 +319,37 @@ void qq_send_packet_request_login_token(
void qq_send_packet_request_login_token(PurpleConnection *gc)
{
qq_data *qd;
- guint8 *buf;
- guint16 seq_ret;
- gint bytes, bytes_sent;
+ guint8 buf[16] = {0};
+ gint bytes = 0;
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
qd = (qq_data *) gc->proto_data;
- buf = g_newa(guint8, MAX_PACKET_SIZE);
- bytes = 0;
- purple_debug(PURPLE_DEBUG_INFO, "QQ", "=BEGIN= send_packet_request_login, bytes: %d\n", bytes);
- bytes += _create_packet_head_seq(buf + bytes, gc, QQ_CMD_REQUEST_LOGIN_TOKEN, TRUE, &seq_ret);
- purple_debug(PURPLE_DEBUG_INFO, "QQ", "send_packet_request_login, bytes: %d\n", bytes);
- if (bytes <= 0) {
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create request login token packet\n");
- return;
- }
- bytes += qq_put32(buf + bytes, qd->uid);
- purple_debug(PURPLE_DEBUG_INFO, "QQ", "send_packet_request_login, bytes: %d\n", bytes);
bytes += qq_put8(buf + bytes, 0);
- purple_debug(PURPLE_DEBUG_INFO, "QQ", "send_packet_request_login, bytes: %d\n", bytes);
- bytes += qq_put8(buf + bytes, QQ_PACKET_TAIL);
- purple_debug(PURPLE_DEBUG_INFO, "QQ", "send_packet_request_login, bytes: %d\n", bytes);
-
- /* debugging info, s3e, 20070628 */
- bytes_sent = _qq_send_packet(gc, buf, bytes, QQ_CMD_REQUEST_LOGIN_TOKEN);
- purple_debug(PURPLE_DEBUG_INFO, "QQ", "world<==me %s, %d bytes\n",
- qq_get_cmd_desc(QQ_CMD_REQUEST_LOGIN_TOKEN), bytes_sent);
-
+
+ qq_send_data(gc, QQ_CMD_REQUEST_LOGIN_TOKEN, buf, bytes);
}
/* send login packet to QQ server */
static void qq_send_packet_login(PurpleConnection *gc, guint8 token_length, guint8 *token)
{
qq_data *qd;
- guint8 *buf, *raw_data, *encrypted_data;
- guint16 seq_ret;
- gint encrypted_len, bytes;
+ guint8 *buf, *raw_data;
+ gint bytes;
+ guint8 *encrypted_data;
+ gint encrypted_len;
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
qd = (qq_data *) gc->proto_data;
- buf = g_newa(guint8, MAX_PACKET_SIZE);
+
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 */
- qd->inikey = _gen_login_key();
+ if (qd->inikey) {
+ g_free(qd->inikey);
+ }
+ qd->inikey = (guint8 *) g_strnfill(QQ_KEY_LENGTH, 0x01);
bytes = 0;
/* now generate the encrypted data
@@ -357,7 +368,6 @@ static void qq_send_packet_login(PurpleC
bytes += qq_put8(raw_data + bytes, qd->login_mode);
/* 053-068, fixed value, maybe related to per machine */
bytes += qq_putdata(raw_data + bytes, login_53_68, 16);
-
/* 069, login token length */
bytes += qq_put8(raw_data + bytes, token_length);
/* 070-093, login token, normally 24 bytes */
@@ -368,23 +378,19 @@ static void qq_send_packet_login(PurpleC
qq_encrypt(raw_data, QQ_LOGIN_DATA_LENGTH, qd->inikey, encrypted_data, &encrypted_len);
+ buf = g_newa(guint8, MAX_PACKET_SIZE);
+ memset(buf, 0, MAX_PACKET_SIZE);
bytes = 0;
- bytes += _create_packet_head_seq(buf, gc, QQ_CMD_LOGIN, TRUE, &seq_ret);
- if (bytes <= 0) {
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Fail create login packet\n");
- return;
- }
- bytes += qq_put32(buf + bytes, qd->uid);
bytes += qq_putdata(buf + bytes, qd->inikey, QQ_KEY_LENGTH);
bytes += qq_putdata(buf + bytes, encrypted_data, encrypted_len);
- bytes += qq_put8(buf + bytes, QQ_PACKET_TAIL);
- _qq_send_packet(gc, buf, bytes, QQ_CMD_LOGIN);
+ qq_send_data(gc, QQ_CMD_LOGIN, buf, bytes);
}
void qq_process_request_login_token_reply(guint8 *buf, gint buf_len, PurpleConnection *gc)
{
qq_data *qd;
+ gchar *error_msg;
g_return_if_fail(buf != NULL && buf_len != 0);
@@ -406,8 +412,14 @@ void qq_process_request_login_token_repl
qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
buf, buf_len,
">>> [default] decrypt and dump");
- try_dump_as_gbk(buf, buf_len);
- purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Error requesting login token"));
+ error_msg = try_dump_as_gbk(buf, buf_len);
+ if (error_msg) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg);
+ g_free(error_msg);
+ } else {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Error requesting login token"));
+ }
}
}
@@ -430,6 +442,7 @@ void qq_process_login_reply(guint8 *buf,
gint len, ret, bytes;
guint8 *data;
qq_data *qd;
+ gchar* error_msg;
g_return_if_fail(buf != NULL && buf_len != 0);
@@ -465,8 +478,11 @@ void qq_process_login_reply(guint8 *buf,
qq_hex_dump(PURPLE_DEBUG_WARNING, "QQ",
data, len,
">>> [default] decrypt and dump");
- try_dump_as_gbk(data, len);
-
+ error_msg = try_dump_as_gbk(data, len);
+ if (error_msg) {
+ purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_msg);
+ g_free(error_msg);
+ }
ret = QQ_LOGIN_REPLY_MISC_ERROR;
}
} else { /* no idea how to decrypt */
============================================================
--- libpurple/protocols/qq/packet_parse.c 9bcbaef736ee2464e3caa9485916bafdb3aa2694
+++ libpurple/protocols/qq/packet_parse.c 6bd97b798f0597efd5d94216e7168874fbaa622d
@@ -43,178 +43,57 @@
/* read one byte from buf,
* return the number of bytes read if succeeds, otherwise return -1 */
-/*
-gint read_packet_b(guint8 *buf, guint8 **cursor, gint buflen, guint8 *b)
-{
- guint8 *b_ship = NULL;
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_b] buf addr: 0x%x\n", (gpointer)buf);
-#endif
- if (*cursor <= buf + buflen - sizeof(*b)) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_b] *cursor addr: 0x%x, buf expected addr: 0x%x\n",
- (gpointer)*cursor, (gpointer)(buf + buflen - sizeof(*b)));
-#endif
- b_ship = g_new0(guint8, sizeof(guint8));
- g_memmove(b_ship, *cursor, sizeof(guint8));
- *b = *b_ship;
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_b] data: 0x%02x->0x%02x\n",
- **(guint8 **)cursor, *b);
-#endif
- *cursor += sizeof(*b);
- // free
- g_free(b_ship);
- b_ship = NULL;
-
- return sizeof(*b);
- } else {
- return -1;
- }
-}
-*/
gint qq_get8(guint8 *b, guint8 *buf)
{
guint8 b_dest;
memcpy(&b_dest, buf, sizeof(b_dest));
*b = b_dest;
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get8] buf %lu\n", (void *)buf);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get8] b_dest 0x%2x, *b 0x%02x\n", b_dest, *b);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get8] buf %lu\n", (void *)buf);
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get8] b_dest 0x%2x, *b 0x%02x\n", b_dest, *b);
+#endif
return sizeof(b_dest);
}
/* read two bytes as "guint16" from buf,
* return the number of bytes read if succeeds, otherwise return -1 */
-/*
-gint read_packet_w(guint8 *buf, guint8 **cursor, gint buflen, guint16 *w)
-{
- guint8 *w_ship = NULL;
- guint16 w_dest;
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_w] buf addr: 0x%x\n", (gpointer)buf);
-#endif
- if (*cursor <= buf + buflen - sizeof(*w)) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_w] *cursor addr: 0x%x, buf expected addr: 0x%x\n",
- (gpointer)*cursor, (gpointer)(buf + buflen - sizeof(*w)));
-#endif
- // type should match memory buffer
- w_ship = (guint8 *)g_new0(guint16, 1);
- // copy bytes into temporary buffer
- g_memmove(w_ship, *cursor, sizeof(guint16));
- // type convert and assign value
- w_dest = *(guint16 *)w_ship;
- // ntohs
- *w = g_ntohs(w_dest);
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_w] data: 0x%04x->0x%04x-g_ntohs->0x%04x\n",
- **(guint16 **)cursor, w_dest, *w);
-#endif
- // *cursor goes on
- *cursor += sizeof(*w);
-
- // free mem
- g_free(w_ship);
- w_ship = NULL;
-
- return sizeof(*w);
- } else {
- return -1;
- }
-}
-*/
gint qq_get16(guint16 *w, guint8 *buf)
{
guint16 w_dest;
memcpy(&w_dest, buf, sizeof(w_dest));
*w = g_ntohs(w_dest);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get16] buf %lu\n", (void *)buf);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get16] w_dest 0x%04x, *w 0x%04x\n", w_dest, *w);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get16] buf %lu\n", (void *)buf);
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get16] w_dest 0x%04x, *w 0x%04x\n", w_dest, *w);
+#endif
return sizeof(w_dest);
}
/* read four bytes as "guint32" from buf,
* return the number of bytes read if succeeds, otherwise return -1 */
-/*
-gint read_packet_dw(guint8 *buf, guint8 **cursor, gint buflen, guint32 *dw)
-{
- guint8 *dw_ship = NULL;
- guint32 dw_dest;
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_dw] buf addr: 0x%x\n", (gpointer)buf);
-#endif
- if (*cursor <= buf + buflen - sizeof(*dw)) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_dw] *cursor addr: 0x%x, buf expected addr: 0x%x\n",
- (gpointer)*cursor, (gpointer)(buf + buflen - sizeof(*dw)));
-#endif
- dw_ship = (guint8 *)g_new0(guint32, 1);
- g_memmove(dw_ship, *cursor, sizeof(guint32));
- dw_dest = *(guint32 *)dw_ship;
- *dw = g_ntohl(dw_dest);
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_dw] data: 0x%08x->0x%08x-g_ntohl->0x%08x\n",
- **(guint32 **)cursor, dw_dest, *dw);
-#endif
- *cursor += sizeof(*dw);
-
- g_free(dw_ship);
- dw_ship = NULL;
-
- return sizeof(*dw);
- } else {
- return -1;
- }
-}
-*/
gint qq_get32(guint32 *dw, guint8 *buf)
{
guint32 dw_dest;
memcpy(&dw_dest, buf, sizeof(dw_dest));
*dw = g_ntohl(dw_dest);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get32] buf %lu\n", (void *)buf);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get32] dw_dest 0x%08x, *dw 0x%08x\n", dw_dest, *dw);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get32] buf %lu\n", (void *)buf);
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][get32] dw_dest 0x%08x, *dw 0x%08x\n", dw_dest, *dw);
+#endif
return sizeof(dw_dest);
}
/* read datalen bytes from buf,
* return the number of bytes read if succeeds, otherwise return -1 */
-/*
-gint read_packet_data(guint8 *buf, guint8 **cursor, gint buflen, guint8 *data, gint datalen) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_data] buf addr: 0x%x\n", (gpointer)buf);
-#endif
- if (*cursor <= buf + buflen - datalen) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[read_data] *cursor addr: 0x%x, buf expected addr: 0x%x\n",
- (gpointer)*cursor, (gpointer)(buf + buflen - datalen));
-#endif
- g_memmove(data, *cursor, datalen);
- *cursor += datalen;
- return datalen;
- } else {
- return -1;
- }
-}
-*/
gint qq_getdata(guint8 *data, gint datalen, guint8 *buf)
{
memcpy(data, buf, datalen);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getdata] buf %lu\n", (void *)buf);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getdata] buf %lu\n", (void *)buf);
+#endif
return datalen;
}
@@ -222,25 +101,18 @@ gint qq_getdata(guint8 *data, gint datal
/* read four bytes as "time_t" from buf,
* return the number of bytes read if succeeds, otherwise return -1
* This function is a wrapper around read_packet_dw() to avoid casting. */
-/*
-gint read_packet_time(guint8 *buf, guint8 **cursor, gint buflen, time_t *t)
-{
- guint32 time;
- gint ret = read_packet_dw(buf, cursor, buflen, &time);
- if (ret != -1 ) {
- *t = time;
- }
- return ret;
-}
-*/
gint qq_getime(time_t *t, guint8 *buf)
{
guint32 dw_dest;
memcpy(&dw_dest, buf, sizeof(dw_dest));
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] buf %lu\n", (void *)buf);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] dw_dest before 0x%08x\n", dw_dest);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] buf %lu\n", (void *)buf);
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] dw_dest before 0x%08x\n", dw_dest);
+#endif
dw_dest = g_ntohl(dw_dest);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] dw_dest after 0x%08x\n", dw_dest);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][getime] dw_dest after 0x%08x\n", dw_dest);
+#endif
memcpy(t, &dw_dest, sizeof(dw_dest));
return sizeof(dw_dest);
}
@@ -248,87 +120,27 @@ gint qq_getime(time_t *t, guint8 *buf)
/*------------------------------------------------PUT------------------------------------------------*/
/* pack one byte into buf
* return the number of bytes packed, otherwise return -1 */
-/*
-gint create_packet_b(guint8 *buf, guint8 **cursor, guint8 b)
-{
- guint8 b_dest;
-#ifdef PARSER_DEBUG
- // show me the address!
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_b] buf addr: 0x%x\n", (gpointer)buf);
-#endif
- // using gpointer is more safe, s3e, 20070704
- if ((gpointer)*cursor <= (gpointer)(buf + MAX_PACKET_SIZE - sizeof(guint8))) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_b] *cursor addr: 0x%x, buf expected addr: 0x%x\n",
- (gpointer)*cursor,
- (gpointer)(buf + MAX_PACKET_SIZE - sizeof(guint8)));
-#endif
- b_dest = b;
- g_memmove(*cursor, &b_dest, sizeof(guint8));
-#ifdef PARSER_DEBUG
- // show data
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_b] data: 0x%02x->0x%02x\n", b, **(guint8 **)cursor);
-#endif
- *cursor += sizeof(guint8);
- return sizeof(guint8);
- } else {
- return -1;
- }
-}
-*/
gint qq_put8(guint8 *buf, guint8 b)
{
memcpy(buf, &b, sizeof(b));
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put8] buf %lu\n", (void *)buf);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put8] b 0x%02x\n", b);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put8] buf %lu\n", (void *)buf);
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put8] b 0x%02x\n", b);
+#endif
return sizeof(b);
}
/* pack two bytes as "guint16" into buf
* return the number of bytes packed, otherwise return -1 */
-/*
-gint create_packet_w(guint8 *buf, guint8 **cursor, guint16 w)
-{
- guint16 w_dest;
- guint8 *w_ship = NULL;
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_w] buf addr: 0x%x\n", (gpointer)buf);
-#endif
- if ((gpointer)*cursor <= (gpointer)(buf + MAX_PACKET_SIZE - sizeof(guint16))) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_w] *cursor addr: 0x%x, buf expected addr: 0x%x\n",
- (gpointer)*cursor,
- (gpointer)(buf + MAX_PACKET_SIZE - sizeof(guint16)));
-#endif
- // obscure bugs found by ccpaging, patches from him.
- // similar bugs have been fixed, s3e, 20070710
- w_dest = g_htons(w);
- w_ship = (guint8 *)&w_dest;
- g_memmove(*cursor, w_ship, sizeof(guint16));
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_w] data: 0x%04x-g_htons->0x%04x->0x%04x\n",
- w, w_dest, **(guint16 **)cursor);
-#endif
- *cursor += sizeof(guint16);
- return sizeof(guint16);
- } else {
- return -1;
- }
-}
-*/
gint qq_put16(guint8 *buf, guint16 w)
{
guint16 w_porter;
w_porter = g_htons(w);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put16] buf %lu\n", (void *)buf);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put16] w 0x%04x, w_porter 0x%04x\n", w, w_porter);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put16] buf %lu\n", (void *)buf);
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put16] w 0x%04x, w_porter 0x%04x\n", w, w_porter);
+#endif
memcpy(buf, &w_porter, sizeof(w_porter));
return sizeof(w_porter);
}
@@ -336,42 +148,14 @@ gint qq_put16(guint8 *buf, guint16 w)
/* pack four bytes as "guint32" into buf
* return the number of bytes packed, otherwise return -1 */
-/*
-gint create_packet_dw(guint8 *buf, guint8 **cursor, guint32 dw)
-{
- guint32 dw_dest;
- guint8 *dw_ship = NULL;
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER", "[create_dw] buf addr: 0x%x\n", (gpointer)buf);
-#endif
- if ((gpointer)*cursor <= (gpointer)(buf + MAX_PACKET_SIZE - sizeof(guint32))) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_dw] *cursor addr: 0x%x, buf expected addr: 0x%x\n",
- (gpointer)*cursor,
- (gpointer)(buf + MAX_PACKET_SIZE -sizeof(guint32)));
-#endif
- dw_dest = g_htonl(dw);
- dw_ship = (guint8 *)&dw_dest;
- g_memmove(*cursor, dw_ship, sizeof(guint32));
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_dw] data: 0x%08x-g_htonl->0x%08x->0x%08x\n",
- dw, dw_dest, **(guint32 **)cursor);
-#endif
- *cursor += sizeof(guint32);
- return sizeof(guint32);
- } else {
- return -1;
- }
-}
-*/
gint qq_put32(guint8 *buf, guint32 dw)
{
guint32 dw_porter;
dw_porter = g_htonl(dw);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put32] buf %lu\n", (void *)buf);
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter);
+#ifdef PARSER_DEBUG
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put32] buf %lu\n", (void *)buf);
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][put32] dw 0x%08x, dw_porter 0x%08x\n", dw, dw_porter);
+#endif
memcpy(buf, &dw_porter, sizeof(dw_porter));
return sizeof(dw_porter);
}
@@ -379,33 +163,11 @@ gint qq_put32(guint8 *buf, guint32 dw)
/* pack datalen bytes into buf
* return the number of bytes packed, otherwise return -1 */
-/*
-gint create_packet_data(guint8 *buf, guint8 **cursor, guint8 *data, gint datalen)
+gint qq_putdata(guint8 *buf, const guint8 *data, const int datalen)
{
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_data] buf addr: 0x%x\n", (gpointer)buf);
-#endif
- if ((gpointer)*cursor <= (gpointer)(buf + MAX_PACKET_SIZE - datalen)) {
-#ifdef PARSER_DEBUG
- purple_debug(PURPLE_DEBUG_INFO, "QQ_DEBUGGER",
- "[create_data] *cursor addr: 0x%x, buf expected addr: 0x%x\n",
- (gpointer)*cursor,
- (gpointer)(buf + MAX_PACKET_SIZE - datalen));
-#endif
- g_memmove(*cursor, data, datalen);
- *cursor += datalen;
- return datalen;
- } else {
- return -1;
- }
-}
-*/
-gint qq_putdata(guint8 *buf, guint8 *data, const int datalen)
-{
memcpy(buf, data, datalen);
+#ifdef PARSER_DEBUG
purple_debug(PURPLE_DEBUG_ERROR, "QQ", "[DBG][putdata] buf %lu\n", (void *)buf);
+#endif
return datalen;
}
-
-
============================================================
--- libpurple/protocols/qq/packet_parse.h 3a72432f0b05f7516982fdf47847bc47bbf5f6cf
+++ libpurple/protocols/qq/packet_parse.h a7e348bfde7cdd37680633be4c2746d684ca5aa1
@@ -46,7 +46,7 @@ gint qq_put32(guint8 *buf, guint32 dw);
gint qq_put8(guint8 *buf, guint8 b);
gint qq_put16(guint8 *buf, guint16 w);
gint qq_put32(guint8 *buf, guint32 dw);
-gint qq_putdata(guint8 *buf, guint8 *data, const int datalen);
+gint qq_putdata(guint8 *buf, const guint8 *data, const int datalen);
//gint read_packet_b(guint8 *buf, guint8 **cursor, gint buflen, guint8 *b);
//gint read_packet_w(guint8 *buf, guint8 **cursor, gint buflen, guint16 *w);
============================================================
--- libpurple/protocols/qq/qq.c 3242aa1932271ecf9adc3daa35993f6d8d1ad1df
+++ libpurple/protocols/qq/qq.c 9efff1f2f37bd0d7c71c21fb505b31ac76246e90
@@ -55,16 +55,15 @@
#include "login_logout.h"
#include "packet_parse.h"
#include "qq.h"
-#include "qq_proxy.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "send_file.h"
#include "utils.h"
#include "version.h"
#define OPENQ_AUTHOR "Puzzlebird"
#define OPENQ_WEBSITE "http://openq.sourceforge.net"
-#define QQ_TCP_QUERY_PORT "8000"
-#define QQ_UDP_PORT "8000"
+#define QQ_TCP_PORT 8000
+#define QQ_UDP_PORT 8000
const gchar *udp_server_list[] = {
"sz.tencent.com",
@@ -90,13 +89,61 @@ const gint tcp_server_amount = (sizeof(t
};
const gint tcp_server_amount = (sizeof(tcp_server_list) / sizeof(tcp_server_list[0]));
-static void _qq_login(PurpleAccount *account)
+static void srv_resolved(PurpleSrvResponse *resp, int results, gpointer account)
{
- const gchar *qq_server, *qq_port;
+ PurpleConnection *gc;
qq_data *qd;
+ gchar *hostname;
+ int port;
+
+ gc = purple_account_get_connection(account);
+ g_return_if_fail(gc != NULL && gc->proto_data != NULL);
+ qd = (qq_data *) gc->proto_data;
+
+ qd->srv_query_data = NULL;
+
+ /* find the host to connect to */
+ port = purple_account_get_int(account, "port", 0);
+ if (port == 0) {
+ if (qd->use_tcp) {
+ port = QQ_TCP_PORT;
+ } else {
+ port = QQ_UDP_PORT;
+ }
+ }
+
+ if(results) {
+ hostname = g_strdup(resp->hostname);
+ if(!port)
+ port = resp->port;
+ g_free(resp);
+ } else {
+ if(!purple_account_get_bool(account, "useproxy", FALSE)) {
+ hostname = g_strdup(qd->server_name);
+ } else {
+ hostname = g_strdup(purple_account_get_string(account,
+ "proxy", qd->server_name));
+ }
+ }
+
+ /*
+ purple_debug(PURPLE_DEBUG_INFO, "QQ",
+ "using with server %s and port %d\n", hostname, port);
+ */
+ qd->real_hostname = g_strdup(hostname);
+ qd->real_port = port;
+ qq_connect(account);
+
+ g_free(hostname);
+}
+
+static void qq_login(PurpleAccount *account)
+{
+ const gchar *userserver;
+ qq_data *qd;
+ gchar *host2connect;
PurpleConnection *gc;
PurplePresence *presence;
- gboolean use_tcp;
g_return_if_fail(account != NULL);
@@ -109,13 +156,7 @@ static void _qq_login(PurpleAccount *acc
qd->gc = gc;
gc->proto_data = qd;
- qq_server = purple_account_get_string(account, "server", NULL);
- qq_port = purple_account_get_string(account, "port", NULL);
- use_tcp = purple_account_get_bool(account, "use_tcp", FALSE);
presence = purple_account_get_presence(account);
-
- qd->use_tcp = use_tcp;
-
if(purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_INVISIBLE)) {
qd->login_mode = QQ_LOGIN_MODE_HIDDEN;
} else if(purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_AWAY)
@@ -125,26 +166,54 @@ static void _qq_login(PurpleAccount *acc
qd->login_mode = QQ_LOGIN_MODE_NORMAL;
}
- if (qq_server == NULL || strlen(qq_server) == 0)
- qq_server = use_tcp ?
- tcp_server_list[random() % tcp_server_amount] :
- udp_server_list[random() % udp_server_amount];
+ userserver = purple_account_get_string(account, "server", NULL);
+ qd->use_tcp = purple_account_get_bool(account, "use_tcp", TRUE);
- if (qq_port == NULL || strtol(qq_port, NULL, 10) == 0)
- qq_port = use_tcp ? QQ_TCP_QUERY_PORT : QQ_UDP_PORT;
+ if (userserver == NULL || strlen(userserver) == 0) {
+ if (qd->use_tcp) {
+ qd->server_name = g_strdup(tcp_server_list[random() % tcp_server_amount]);
+ } else {
+ qd->server_name = g_strdup(udp_server_list[random() % udp_server_amount]);
+ }
+ } else {
+ qd->server_name = g_strdup(userserver);
+ }
purple_connection_update_progress(gc, _("Connecting"), 0, QQ_CONNECT_STEPS);
- if (qq_connect(account, qq_server, strtol(qq_port, NULL, 10), use_tcp, FALSE) < 0)
- purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unable to connect."));
+ if(!purple_account_get_bool(account, "useproxy", FALSE)) {
+ host2connect = g_strdup(qd->server_name);
+ } else {
+ host2connect = g_strdup(purple_account_get_string(account, "proxy", qd->server_name));
+ }
+
+ qd->srv_query_data = purple_srv_resolve("QQ",
+ qd->use_tcp ? "tcp" : "udp", host2connect, srv_resolved, account);
+ g_free(host2connect);
}
-/* directly goes for qq_disconnect */
-static void _qq_close(PurpleConnection *gc)
+/* clean up the given QQ connection and free all resources */
+static void qq_close(PurpleConnection *gc)
{
+ qq_data *qd;
+
g_return_if_fail(gc != NULL);
+ qd = gc->proto_data;
+
qq_disconnect(gc);
+
+ if (qd->real_hostname) {
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "free real_hostname\n");
+ g_free(qd->real_hostname);
+ qd->real_hostname = NULL;
+ }
+ if (qd->srv_query_data != NULL)
+ purple_srv_cancel(qd->srv_query_data);
+
+ g_free(qd->server_name);
+ g_free(qd);
+
+ gc->proto_data = NULL;
}
/* returns the icon name for a buddy or protocol */
@@ -442,8 +511,9 @@ static void _qq_menu_show_login_info(Pur
g_string_append(info, "<hr>\n");
+ g_string_append_printf(info, _("<b>Server</b>: %s: %d<br>\n"), qd->server_name, qd->real_port);
g_string_append_printf(info, _("<b>Connection Mode</b>: %s<br>\n"), qd->use_tcp ? "TCP" : "UDP");
- g_string_append_printf(info, _("<b>Server IP</b>: %s: %d<br>\n"), qd->server_ip, qd->server_port);
+ g_string_append_printf(info, _("<b>Real hostname</b>: %s: %d<br>\n"), qd->real_hostname, qd->real_port);
g_string_append_printf(info, _("<b>My Public IP</b>: %s<br>\n"), qd->my_ip);
g_string_append(info, "<hr>\n");
@@ -594,7 +664,7 @@ static GList *_qq_buddy_menu(PurpleBlist
}
-static void _qq_keep_alive(PurpleConnection *gc)
+static void qq_keep_alive(PurpleConnection *gc)
{
qq_group *group;
qq_data *qd;
@@ -651,8 +721,8 @@ static PurplePluginProtocolInfo prpl_inf
_qq_buddy_menu, /* blist_node_menu */
qq_chat_info, /* chat_info */
qq_chat_info_defaults, /* chat_info_defaults */
- _qq_login, /* login */
- _qq_close, /* close */
+ qq_login, /* open */
+ qq_close, /* close */
_qq_send_im, /* send_im */
NULL, /* set_info */
NULL, /* send_typing */
@@ -676,7 +746,7 @@ static PurplePluginProtocolInfo prpl_inf
NULL, /* chat_leave */
NULL, /* chat_whisper */
_qq_chat_send, /* chat_send */
- _qq_keep_alive, /* keepalive */
+ qq_keep_alive, /* keepalive */
NULL, /* register_user */
_qq_get_chat_buddy_info, /* get_cb_info */
NULL, /* get_cb_away */
@@ -750,13 +820,13 @@ static void init_plugin(PurplePlugin *pl
{
PurpleAccountOption *option;
- option = purple_account_option_bool_new(_("Connect using TCP"), "use_tcp", FALSE);
+ option = purple_account_option_string_new(_("Server"), "server", NULL);
prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
- option = purple_account_option_string_new(_("Server"), "server", NULL);
+ option = purple_account_option_int_new(_("Port"), "port", 0);
prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
- option = purple_account_option_string_new(_("Port"), "port", NULL);
+ option = purple_account_option_bool_new(_("Connect using TCP"), "use_tcp", TRUE);
prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
my_protocol = plugin;
============================================================
--- libpurple/protocols/qq/qq.h 1d409ac09e01183d7485867ff8004ad4ea2efdba
+++ libpurple/protocols/qq/qq.h 3aefba86630400977aec225e0d7926696edb9cef
@@ -28,6 +28,9 @@
#include <glib.h>
#include "internal.h"
#include "ft.h"
+#include "circbuffer.h"
+#include "dnsquery.h"
+#include "dnssrv.h"
#include "proxy.h"
#include "roomlist.h"
@@ -66,7 +69,34 @@ struct _qq_data {
};
struct _qq_data {
- gint fd; /* socket file handler */
+ PurpleConnection *gc;
+ gchar *server_name;
+
+ // common network resource
+ PurpleSrvQueryData *srv_query_data; // srv resolve
+ gboolean is_redirect;
+ gchar *real_hostname; // from real connction
+ guint16 real_port;
+ gboolean use_tcp; // network in tcp or udp
+
+ PurpleProxyConnectData *connect_data;
+ gint fd; // socket file handler
+ gint tx_handler; // socket can_write handle, use in udp connecting and tcp send out
+
+ GList *transactions; // check ack packet and resend
+ guint resend_timeout;
+
+ guint8 rcv_window[1 << 13]; // windows for check duplicate packet
+ GQueue *rcv_trans; // queue to store packet can not process before login
+
+ // tcp related
+ PurpleCircBuffer *tcp_txbuf;
+ guint8 *tcp_rxqueue;
+ int tcp_rxlen;
+
+ // udp related
+ PurpleDnsQueryData *udp_query_data;
+
guint32 uid; /* QQ number */
guint8 *inikey; /* initial key to encrypt login packet */
guint8 *pwkey; /* password in md5 (or md5' md5) */
@@ -76,17 +106,10 @@ struct _qq_data {
guint16 send_seq; /* send sequence number */
guint8 login_mode; /* online of invisible */
gboolean logged_in; /* used by qq-add_buddy */
- gboolean use_tcp; /* network in tcp or udp */
- PurpleProxyType proxy_type;
- PurpleConnection *gc;
-
PurpleXfer *xfer; /* file transfer handler */
struct sockaddr_in dest_sin;
- /* from real connction */
- gchar *server_ip;
- guint16 server_port;
/* get from login reply packet */
time_t login_time;
time_t last_login_time;
@@ -99,9 +122,6 @@ struct _qq_data {
guint32 all_online; /* the number of online QQ users */
time_t last_get_online; /* last time send get_friends_online packet */
- guint8 window[1 << 13]; /* check up for duplicated packet */
- gint sendqueue_timeout;
-
PurpleRoomlist *roomlist;
gint channel; /* the id for opened chat conversation */
@@ -112,10 +132,8 @@ struct _qq_data {
GList *buddies;
GList *contact_info_window;
GList *group_info_window;
- GList *sendqueue;
GList *info_query;
GList *add_buddy_request;
- GQueue *before_login_packets;
/* TODO pass qq_send_packet_get_info() a callback and use signals to get rid of these */
gboolean modifying_info;
============================================================
--- libpurple/protocols/qq/send_file.c 489b72e91374f022de7a4fda0c7e622c4a6aef10
+++ libpurple/protocols/qq/send_file.c 8c9ea7e61190ec46f24629c714c638f130b05a33
@@ -36,7 +36,7 @@
#include "im.h"
#include "keep_alive.h"
#include "packet_parse.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "utils.h"
enum
============================================================
--- libpurple/protocols/qq/sendqueue.c 1e1281845e07c668525c01370bf3510afe60757d
+++ libpurple/protocols/qq/sendqueue.c 537ca9ecb0ea3297c1caa8d2b3bd75a1e7a6d1a4
@@ -31,126 +31,213 @@
#include "request.h"
#include "header_info.h"
-#include "qq_proxy.h"
+#include "qq_network.h"
#include "sendqueue.h"
#define QQ_RESEND_MAX 8 /* max resend per packet */
-typedef struct _gc_and_packet gc_and_packet;
+typedef struct _transaction {
+ guint16 seq;
+ guint16 cmd;
+ guint8 *buf;
+ gint buf_len;
-struct _gc_and_packet {
- PurpleConnection *gc;
- qq_sendpacket *packet;
-};
+ gint fd;
+ gint retries;
+ time_t create_time;
+} transaction;
-/* Remove a packet with send_seq from sendqueue */
-void qq_sendqueue_remove(qq_data *qd, guint16 send_seq)
+void qq_trans_append(qq_data *qd, guint8 *buf, gint buf_len, guint16 cmd, guint16 seq)
{
- GList *list;
- qq_sendpacket *p;
+ transaction *trans = g_new0(transaction, 1);
- list = qd->sendqueue;
- while (list != NULL) {
- p = (qq_sendpacket *) (list->data);
- if (p->send_seq == send_seq) {
- qd->sendqueue = g_list_remove(qd->sendqueue, p);
- g_free(p->buf);
- g_free(p);
- break;
+ g_return_if_fail(trans != NULL);
+
+ trans->fd = qd->fd;
+ trans->cmd = cmd;
+ trans->seq = seq;
+ trans->retries = QQ_RESEND_MAX;
+ trans->create_time = time(NULL);
+ trans->buf = g_memdup(buf, buf_len); /* don't use g_strdup, may have 0x00 */
+ trans->buf_len = buf_len;
+
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+ "Add to transaction, seq = %d, buf = %lu, len = %d\n",
+ trans->seq, trans->buf, trans->buf_len);
+ qd->transactions = g_list_append(qd->transactions, trans);
+}
+
+/* Remove a packet with seq from sendqueue */
+void qq_trans_remove(qq_data *qd, gpointer data)
+{
+ transaction *trans = (transaction *)data;
+
+ g_return_if_fail(qd != NULL && data != NULL);
+
+ purple_debug(PURPLE_DEBUG_INFO, "QQ",
+ "ack [%05d] %s, remove from sendqueue\n",
+ trans->seq, qq_get_cmd_desc(trans->cmd));
+
+ if (trans->buf) g_free(trans->buf);
+ qd->transactions = g_list_remove(qd->transactions, trans);
+ g_free(trans);
+}
+
+gpointer qq_trans_find(qq_data *qd, guint16 seq)
+{
+ GList *curr;
+ GList *next;
+ transaction *trans;
+
+ curr = qd->transactions;
+ while(curr) {
+ next = curr->next;
+ trans = (transaction *) (curr->data);
+ if(trans->seq == seq) {
+ return trans;
}
- list = list->next;
+ curr = next;
}
+
+ return NULL;
}
-
+
/* clean up sendqueue and free all contents */
-void qq_sendqueue_free(qq_data *qd)
+void qq_trans_remove_all(qq_data *qd)
{
- qq_sendpacket *p;
- gint i;
+ GList *curr;
+ GList *next;
+ transaction *trans;
+ gint count = 0;
- i = 0;
- while (qd->sendqueue != NULL) {
- p = (qq_sendpacket *) (qd->sendqueue->data);
- qd->sendqueue = g_list_remove(qd->sendqueue, p);
- g_free(p->buf);
- g_free(p);
- i++;
+ curr = qd->transactions;
+ while(curr) {
+ next = curr->next;
+
+ trans = (transaction *) (curr->data);
+ /*
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+ "Remove to transaction, seq = %d, buf = %lu, len = %d\n",
+ trans->seq, trans->buf, trans->len);
+ */
+ qq_trans_remove(qd, trans);
+
+ count++;
+ curr = next;
}
- purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d packets in sendqueue are freed!\n", i);
+ g_list_free(qd->transactions);
+
+ purple_debug(PURPLE_DEBUG_INFO, "QQ", "%d packets in sendqueue are freed!\n", count);
}
-/* FIXME We shouldn't be dropping packets, but for now we have to because
- * somewhere we're generating invalid packets that the server won't ack.
- * Given enough time, a buildup of those packets would crash the client. */
-gboolean qq_sendqueue_timeout_callback(gpointer data)
+gint qq_trans_scan(qq_data *qd, gint *start,
+ guint8 *buf, gint maxlen, guint16 *cmd, gint *retries)
{
- PurpleConnection *gc;
- qq_data *qd;
- GList *list;
- qq_sendpacket *p;
- time_t now;
- gint wait_time;
+ GList *curr;
+ GList *next = NULL;
+ transaction *trans;
+ gint copylen;
- gc = (PurpleConnection *) data;
- qd = (qq_data *) gc->proto_data;
- now = time(NULL);
- list = qd->sendqueue;
+ g_return_val_if_fail(qd != NULL && *start >= 0 && maxlen > 0, -1);
+
+ //purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Scan from %d\n", *start);
+ curr = g_list_nth(qd->transactions, *start);
+ while(curr) {
+ next = curr->next;
+ *start = g_list_position(qd->transactions, next);
+
+ trans = (transaction *) (curr->data);
+ if (trans->buf == NULL || trans->buf_len <= 0) {
+ qq_trans_remove(qd, trans);
+ curr = next;
+ continue;
+ }
- /* empty queue, return TRUE so that timeout continues functioning */
- if (qd->sendqueue == NULL)
- return TRUE;
-
- while (list != NULL) { /* remove all packet whose resend_times == -1 */
- p = (qq_sendpacket *) list->data;
- if (p->resend_times == -1) { /* to remove */
- qd->sendqueue = g_list_remove(qd->sendqueue, p);
- g_free(p->buf);
- g_free(p);
- list = qd->sendqueue;
- } else {
- list = list->next;
+ if (trans->retries < 0) {
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+ "Remove transaction, seq %d, buf %lu, len %d, retries %d, next %d\n",
+ trans->seq, trans->buf, trans->buf_len, trans->retries, *start);
+ qq_trans_remove(qd, trans);
+ curr = next;
+ continue;
}
+
+ purple_debug(PURPLE_DEBUG_ERROR, "QQ",
+ "Resend transaction, seq %d, buf %lu, len %d, retries %d, next %d\n",
+ trans->seq, trans->buf, trans->buf_len, trans->retries, *start);
+ copylen = MIN(trans->buf_len, maxlen);
+ g_memmove(buf, trans->buf, copylen);
+
+ *cmd = trans->cmd;
+ *retries = trans->retries;
+ trans->retries--;
+ return copylen;
}
- list = qd->sendqueue;
- while (list != NULL) {
- p = (qq_sendpacket *) list->data;
- if (p->resend_times == QQ_RESEND_MAX) { /* reach max */
- switch (p->cmd) {
- case QQ_CMD_KEEP_ALIVE:
- if (qd->logged_in) {
- purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection lost!\n");
- purple_connection_error_reason(gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Connection lost"));
- qd->logged_in = FALSE;
- }
- p->resend_times = -1;
- break;
- case QQ_CMD_LOGIN:
- case QQ_CMD_REQUEST_LOGIN_TOKEN:
- if (!qd->logged_in) /* cancel login progress */
- purple_connection_error_reason(gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Login failed, no reply"));
- p->resend_times = -1;
- break;
- default:{
- purple_debug(PURPLE_DEBUG_WARNING, "QQ",
- "%s packet sent %d times but not acked. Not resending it.\n",
- qq_get_cmd_desc(p->cmd), QQ_RESEND_MAX);
- }
- p->resend_times = -1;
- }
- } else { /* resend_times < QQ_RESEND_MAX, so sent it again */
- wait_time = (gint) (QQ_SENDQUEUE_TIMEOUT / 1000);
- if (difftime(now, p->sendtime) > (wait_time * (p->resend_times + 1))) {
- qq_proxy_write(qd, p->buf, p->len);
- p->resend_times++;
- purple_debug(PURPLE_DEBUG_INFO,
- "QQ", "<<< [%05d] send again for %d times!\n",
- p->send_seq, p->resend_times);
- }
+ // purple_debug(PURPLE_DEBUG_INFO, "QQ", "Scan finished\n");
+ return -1;
+}
+
+void qq_packet_push(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len)
+{
+ transaction *trans = g_new0(transaction, 1);
+
+ g_return_if_fail(data != NULL && data_len > 0);
+ g_return_if_fail(trans != NULL);
+
+ trans->cmd = cmd;
+ trans->seq = seq;
+ trans->buf = g_memdup(data, data_len);
+ trans->buf_len = data_len;
+ trans->create_time = time(NULL);
+
+ if (qd->rcv_trans == NULL)
+ qd->rcv_trans = g_queue_new();
+
+ g_queue_push_head(qd->rcv_trans, trans);
+}
+
+gint qq_packet_pop(qq_data *qd, guint16 *cmd, guint16 *seq, guint8 *data, gint max_len)
+{
+ transaction *trans = NULL;
+ gint copy_len;
+
+ g_return_val_if_fail(data != NULL && max_len > 0, -1);
+
+ if (g_queue_is_empty(qd->rcv_trans)) {
+ return -1;
+ }
+ trans = (transaction *) g_queue_pop_head(qd->rcv_trans);
+ if (trans == NULL) {
+ return 0;
+ }
+ if (trans->buf == NULL || trans->buf_len <= 0) {
+ return 0;
+ }
+
+ copy_len = MIN(max_len, trans->buf_len);
+ g_memmove(data, trans->buf, copy_len);
+ *cmd = trans->cmd;
+ *seq = trans->seq;
+
+ g_free(trans->buf);
+ g_free(trans);
+ return copy_len;
+}
+
+/* clean up the packets before login */
+void qq_packet_remove_all(qq_data *qd)
+{
+ transaction *trans = NULL;
+
+ g_return_if_fail(qd != NULL);
+
+ /* now clean up my own data structures */
+ if (qd->rcv_trans != NULL) {
+ while (NULL != (trans = g_queue_pop_tail(qd->rcv_trans))) {
+ g_free(trans->buf);
+ g_free(trans);
}
- list = list->next;
+ g_queue_free(qd->rcv_trans);
}
- return TRUE; /* if we return FALSE, the timeout callback stops functioning */
}
============================================================
--- libpurple/protocols/qq/sendqueue.h 30b940cb25d042b2ab71cf074a122c92ffdd7538
+++ libpurple/protocols/qq/sendqueue.h a1fac89a94824f66841c217546f176979afa6aa6
@@ -28,23 +28,15 @@
#include <glib.h>
#include "qq.h"
-#define QQ_SENDQUEUE_TIMEOUT 5000 /* in 1/1000 sec */
+void qq_trans_append(qq_data *qd, guint8 *buf, gint bus_len, guint16 cmd, guint16 seq);
+void qq_trans_remove(qq_data *qd, gpointer data);
+gpointer qq_trans_find(qq_data *qd, guint16 seq);
+void qq_trans_remove_all(qq_data *qd);
-typedef struct _qq_sendpacket qq_sendpacket;
+gint qq_trans_scan(qq_data *qd, gint *start, guint8 *buf, gint maxlen, guint16 *cmd, gint *retries);
-struct _qq_sendpacket {
- gint fd;
- gint len;
- guint8 *buf;
- guint16 cmd;
- guint16 send_seq;
- gint resend_times;
- time_t sendtime;
-};
+void qq_packet_push(qq_data *qd, guint16 cmd, guint16 seq, guint8 *data, gint data_len);
+gint qq_packet_pop(qq_data *qd, guint16 *cmd, guint16* seq, guint8 *data, gint max_len);
+void qq_packet_remove_all(qq_data *qd);
-void qq_sendqueue_free(qq_data *qd);
-
-void qq_sendqueue_remove(qq_data *qd, guint16 send_seq);
-gboolean qq_sendqueue_timeout_callback(gpointer data);
-
#endif
============================================================
--- libpurple/protocols/qq/sys_msg.c e5838f9559ca2e93f574dc22c5e910b0c9ae344c
+++ libpurple/protocols/qq/sys_msg.c 3ef548df58374cb00964e1c6db64894fc87858ab
@@ -35,7 +35,7 @@
#include "header_info.h"
#include "packet_parse.h"
#include "qq.h"
-#include "send_core.h"
+#include "qq_network.h"
#include "sys_msg.h"
#include "utils.h"
============================================================
--- libpurple/protocols/qq/utils.c e59b26e6b4b9683e8a161cef8dbe81c5da935e5f
+++ libpurple/protocols/qq/utils.c 5acca45660aa1851f55504bd6af49fba5b2b3cd4
@@ -22,7 +22,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
-#include "cipher.h"
#include "limits.h"
#include "stdlib.h"
#include "string.h"
@@ -113,26 +112,6 @@ gchar **split_data(guint8 *data, gint le
return segments;
}
-/* generate a md5 key using uid and session_key */
-guint8 *_gen_session_md5(gint uid, guint8 *session_key)
-{
- guint8 *src, md5_str[QQ_KEY_LENGTH];
- PurpleCipher *cipher;
- PurpleCipherContext *context;
-
- src = g_newa(guint8, 20);
- memcpy(src, &uid, 4);
- memcpy(src, session_key, QQ_KEY_LENGTH);
-
- cipher = purple_ciphers_find_cipher("md5");
- context = purple_cipher_context_new(cipher, NULL);
- purple_cipher_context_append(context, src, 20);
- purple_cipher_context_digest(context, sizeof(md5_str), md5_str, NULL);
- purple_cipher_context_destroy(context);
-
- return g_memdup(md5_str, QQ_KEY_LENGTH);
-}
-
/* given a four-byte ip data, convert it into a human readable ip string
* the return needs to be freed */
gchar *gen_ip_str(guint8 *ip)
@@ -194,7 +173,7 @@ gchar *chat_name_to_purple_name(const gc
}
/* try to dump the data as GBK */
-void try_dump_as_gbk(const guint8 *const data, gint len)
+gchar* try_dump_as_gbk(const guint8 *const data, gint len)
{
gint i;
guint8 *incoming;
@@ -215,8 +194,8 @@ void try_dump_as_gbk(const guint8 *const
if (msg_utf8 != NULL) {
purple_debug(PURPLE_DEBUG_WARNING, "QQ", "Try extract GB msg: %s\n", msg_utf8);
- g_free(msg_utf8);
}
+ return msg_utf8;
}
/* strips whitespace */
@@ -356,6 +335,26 @@ void qq_hex_dump(PurpleDebugLevel level,
g_free(phex);
}
+void qq_show_packet(const gchar *desc, const guint8 *buf, gint len)
+{
+ /*
+ char buf1[8*len+2], buf2[10];
+ int i;
+ buf1[0] = 0;
+ for (i = 0; i < len; i++) {
+ sprintf(buf2, " %02x(%d)", buf[i] & 0xff, buf[i] & 0xff);
+ strcat(buf1, buf2);
+ }
+ strcat(buf1, "\n");
+ purple_debug(PURPLE_DEBUG_INFO, desc, "%s", buf1);
+ */
+
+ /* modified by s3e, 20080424 */
+ qq_hex_dump(PURPLE_DEBUG_INFO, desc,
+ buf, len,
+ "");
+}
+
/* convert face num from packet (0-299) to local face (1-100) */
gchar *face_to_icon_str(gint face)
{
============================================================
--- libpurple/protocols/qq/utils.h 234f20c24b8ffe74a312c2fede83156f9740cbc1
+++ libpurple/protocols/qq/utils.h 2e90d8ad0ec426c0a9c85fb8e3999f0ec26c3a5a
@@ -35,7 +35,6 @@ gchar **split_data(guint8 *data, gint le
gint qq_string_to_dec_value(const gchar *str);
gchar **split_data(guint8 *data, gint len, const gchar *delimit, gint expected_fields);
-guint8 *_gen_session_md5(gint uid, guint8 *session_key);
gchar *gen_ip_str(guint8 *ip);
guint8 *str_ip_gen(gchar *str);
@@ -46,8 +45,9 @@ gchar *face_to_icon_str(gint face);
gchar *face_to_icon_str(gint face);
-void try_dump_as_gbk(const guint8 *const data, gint len);
+gchar *try_dump_as_gbk(const guint8 *const data, gint len);
+void qq_show_packet(const gchar *desc, const guint8 *buf, gint len);
void qq_hex_dump(PurpleDebugLevel level, const char *category,
const guint8 *pdata, gint bytes,
const char *format, ...);
More information about the Commits
mailing list