/* set seq and is_save2trans, then call send_cmd_detail */ gint qq_send_server_reply(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { qq_data *qd; guint8 *encrypted; gint encrypted_len; gint bytes_sent; g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); qd = (qq_data *)gc->proto_data; g_return_val_if_fail(data != NULL && data_len > 0, -1); #if 1 purple_debug_info("QQ", "<== [SRV-%05d] %s(0x%04X), datalen %d\n", seq, qq_get_cmd_desc(cmd), cmd, data_len); #endif /* at most 17 bytes more */ encrypted = g_newa(guint8, data_len + 17); encrypted_len = qq_encrypt(encrypted, data, data_len, qd->session_key); if (encrypted_len < 16) { purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] 0x%04X %s\n", encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); return -1; } bytes_sent = packet_send_out(gc, cmd, seq, encrypted, encrypted_len); qq_trans_add_server_reply(gc, cmd, seq, encrypted, encrypted_len); return bytes_sent; }
/* Encrypt data with session_key, and send packet out */ static gint send_cmd_detail(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len, gboolean is_save2trans, UPDCLS update_class, guint32 ship32) { qq_data *qd; guint8 *encrypted; gint encrypted_len; gint bytes_sent; g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); qd = (qq_data *)gc->proto_data; g_return_val_if_fail(data != NULL && data_len > 0, -1); /* at most 17 bytes more */ encrypted = g_newa(guint8, data_len + 17); encrypted_len = qq_encrypt(encrypted, data, data_len, qd->session_key); if (encrypted_len < 16) { purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] 0x%04X %s\n", encrypted_len, seq, cmd, qq_get_cmd_desc(cmd)); return -1; } bytes_sent = packet_send_out(gc, cmd, seq, encrypted, encrypted_len); if (is_save2trans) { qq_trans_add_client_cmd(gc, cmd, seq, encrypted, encrypted_len, update_class, ship32); } return bytes_sent; }
static gint send_room_cmd(PurpleConnection *gc, guint8 room_cmd, guint32 room_id, guint8 *data, gint data_len, UPDCLS update_class, guint32 ship32) { qq_data *qd; guint8 *buf; gint buf_len; guint8 *encrypted; gint encrypted_len; gint bytes_sent; guint16 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); /* encap room_cmd and room id to buf*/ buf_len = 0; buf_len += qq_put8(buf + buf_len, room_cmd); if (room_id != 0) { /* id 0 is for QQ Demo Group, now they are closed*/ buf_len += qq_put32(buf + buf_len, room_id); } if (data != NULL && data_len > 0) { buf_len += qq_putdata(buf + buf_len, data, data_len); } qd->send_seq++; seq = qd->send_seq; /* Encrypt to encrypted with session_key */ /* at most 17 bytes more */ encrypted = g_newa(guint8, buf_len + 17); encrypted_len = qq_encrypt(encrypted, buf, buf_len, qd->session_key); if (encrypted_len < 16) { purple_debug_error("QQ_ENCRYPT", "Error len %d: [%05d] %s (0x%02X)\n", encrypted_len, seq, qq_get_room_cmd_desc(room_cmd), room_cmd); return -1; } bytes_sent = packet_send_out(gc, QQ_CMD_ROOM, seq, encrypted, encrypted_len); #if 1 /* qq_show_packet("send_room_cmd", buf, buf_len); */ purple_debug_info("QQ", "<== [%05d] %s (0x%02X) to room %d, datalen %d\n", seq, qq_get_room_cmd_desc(room_cmd), room_cmd, room_id, buf_len); #endif qq_trans_add_room_cmd(gc, seq, room_cmd, room_id, encrypted, encrypted_len, update_class, ship32); return bytes_sent; }
/* send a file to udp channel with QQ_FILE_CONTROL_PACKET_TAG */ void qq_send_file_ctl_packet(PurpleConnection *gc, guint16 packet_type, guint32 to_uid, guint8 hellobyte) { qq_data *qd; gint bytes, bytes_expected, encrypted_len; guint8 *raw_data, *encrypted; time_t now; ft_info *info; qd = (qq_data *) gc->proto_data; info = (ft_info *) qd->xfer->data; raw_data = g_newa (guint8, 61); bytes = 0; now = time(NULL); bytes += qq_putdata(raw_data + bytes, qd->session_md5, 16); bytes += qq_put16(raw_data + bytes, packet_type); switch (packet_type) { case QQ_FILE_CMD_SENDER_SAY_HELLO: case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK: case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK: case QQ_FILE_CMD_NOTIFY_IP_ACK: case QQ_FILE_CMD_RECEIVER_SAY_HELLO: bytes += qq_put16(raw_data + bytes, info->send_seq); break; default: bytes += qq_put16(raw_data + bytes, ++qd->send_seq); } bytes += qq_put32(raw_data + bytes, (guint32) now); bytes += qq_put8(raw_data + bytes, 0x00); bytes += qq_put8(raw_data + bytes, qd->my_icon); bytes += qq_put32(raw_data + bytes, 0x00000000); bytes += qq_put32(raw_data + bytes, 0x00000000); bytes += qq_put32(raw_data + bytes, 0x00000000); bytes += qq_put32(raw_data + bytes, 0x00000000); bytes += qq_put16(raw_data + bytes, 0x0000); bytes += qq_put8(raw_data + bytes, 0x00); /* 0x65: send a file, 0x6b: send a custom face */ bytes += qq_put8(raw_data + bytes, QQ_FILE_TRANSFER_FILE); /* FIXME temp by gfhuang */ switch (packet_type) { case QQ_FILE_CMD_SENDER_SAY_HELLO: case QQ_FILE_CMD_RECEIVER_SAY_HELLO: case QQ_FILE_CMD_SENDER_SAY_HELLO_ACK: case QQ_FILE_CMD_RECEIVER_SAY_HELLO_ACK: bytes += qq_put8(raw_data + bytes, 0x00); bytes += qq_put8(raw_data + bytes, hellobyte); bytes_expected = 48; break; case QQ_FILE_CMD_PING: case QQ_FILE_CMD_PONG: case QQ_FILE_CMD_NOTIFY_IP_ACK: bytes += qq_fill_conn_info(raw_data, info); bytes_expected = 61; break; default: purple_debug_info("QQ", "qq_send_file_ctl_packet: Unknown packet type[%d]\n", packet_type); bytes_expected = 0; } if (bytes != bytes_expected) { purple_debug_error("QQ", "qq_send_file_ctl_packet: Expected to get %d bytes, but get %d\n", bytes_expected, bytes); return; } qq_hex_dump(PURPLE_DEBUG_INFO, "QQ", raw_data, bytes, "sending packet[%s]:", qq_get_file_cmd_desc(packet_type)); encrypted = g_newa(guint8, bytes + 17); encrypted_len = qq_encrypt(encrypted, raw_data, bytes, info->file_session_key); /*debug: try to decrypt it */ #if 0 guint8 *buf; int buflen; hex_dump = hex_dump_to_str(encrypted, encrypted_len); purple_debug_info("QQ", "encrypted packet: \n%s\n", hex_dump); g_free(hex_dump); buf = g_newa(guint8, MAX_PACKET_SIZE); buflen = encrypted_len; if (qq_crypt(DECRYPT, encrypted, encrypted_len, info->file_session_key, buf, &buflen)) { purple_debug_info("QQ", "decrypt success\n"); if (buflen == bytes && memcmp(raw_data, buf, buflen) == 0) purple_debug_info("QQ", "checksum ok\n"); hex_dump = hex_dump_to_str(buf, buflen); purple_debug_info("QQ", "decrypted packet: \n%s\n", hex_dump); g_free(hex_dump); } else { purple_debug_info("QQ", "decrypt fail\n"); } #endif purple_debug_info("QQ", "<== send %s packet\n", qq_get_file_cmd_desc(packet_type)); _qq_send_file(gc, encrypted, encrypted_len, QQ_FILE_CONTROL_PACKET_TAG, info->to_uid); }