Name and permission analyzing is now available

This commit is contained in:
Him188 2019-10-18 19:32:03 +08:00
parent 7e90737c68
commit d5587bb3d8
12 changed files with 407 additions and 390 deletions

View File

@ -5,12 +5,20 @@ import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.network.protocol.tim.packet.SenderPermission
abstract class GroupEvent(bot: Bot, val group: Group) : BotEvent(bot)
class GroupMessageEvent(bot: Bot, group: Group, val sender: QQ, val message: MessageChain) : GroupEvent(bot, group) {
class GroupMessageEvent(
bot: Bot,
group: Group,
val sender: QQ,
val message: MessageChain,
val senderPermission: SenderPermission,
val senderName: String//若他有群名片就是群名片, 没有就是昵称
) : GroupEvent(bot, group) {
suspend inline fun reply(message: Message) = group.sendMessage(message)
suspend inline fun reply(message: String) = group.sendMessage(message)

View File

@ -29,30 +29,31 @@ internal fun IoBuffer.parseMessageImage0x06(): Image {
//MiraiLogger.logDebug(this.toUHexString())
val filenameLength = readShort()
val suffix = readString(filenameLength).substringAfter(".")
discardExact(this.readRemaining - 37 - 1 - filenameLength - 2 - 8 - 4)
val imageId = readString(36)
MiraiLogger.logDebug("imageId=$imageId")//todo ID似乎错了??
discardExact(1)//0x41
return Image("{$imageId}.$suffix")
discardExact(8)//03 00 04 00 00 02 9C 04
val length = readShort()//27
discardExact(1)
return Image("{${readString(length - 2/*去掉首尾各一个*/)}}.$suffix")
}
}
//00 1B filenameLength
// 43 37 46 29 5F 34 32 34 4E 33 55 37 7B 4C 47 36 7D 4F 25 5A 51 58 51 2E 6A 70 67 get suffix
// 03 00 04 00 00 02 9C 04
// 00 25 2F 32 65 37 61 65 33 36 66 2D 61 39 31 63 2D 34 31 32 39 2D 62 61 34 32 2D 37 65 30 31 32 39 37 37 35 63 63 38 14
// 00 04 03 00 00 00 18
// 00 25 2F 32 65 37 61 65 33 36 66 2D 61 39 31 63 2D 34 31 32 39 2D 62 61 34 32 2D 37 65 30 31 32 39 37 37 35 63 63 38 19
// 00 04 00 00 00 2E 1A 00 04 00 00 00 2E FF
// 00 63 16 20 20 39 39 31 30 20 38 38 31 43 42 20 20 20 20 20 20 20 36 36 38 65 35 43 36 38 45 36 42 44 32 46 35 38 34 31 42 30 39 37 39 45 37 46 32 35 34 33 38 38 31 33 43 33 2E 6A 70 67 66 2F 32 65 37 61 65 33 36 66 2D 61 39 31 63 2D 34 31 32 39 2D 62 61 34 32 2D 37 65 30 31 32 39 37 37 35 63 63 38 41
fun main() {
println("f/".toByteArray().toUHexString())
println("16 20 20 39 39 31 30 20 38 38 31 43 42 20 20 20 20 20 20 20 36 36 38 65 35 43 36 38 45 36 42 44 32 46 35 38 34 31 42 30 39 37 39 45 37 46 32 35 34 33 38 38 31 33 43 33 2E 6A 70 67 66 2F 32 65 37 61 65 33 36 66 2D 61 39 31 63 2D 34 31 32 39 2D 62 61 34 32 2D 37 65 30 31 32 39 37 37 35 63 63 38 41"
.hexToBytes().stringOf())
}
internal fun IoBuffer.parseMessageImage0x03(): Image {
discardExact(1)
return Image(String(readLVByteArray()))
/*
println(String(readLVByteArray()))
readTLVMap()
return Image(String(readLVByteArray().cutTail(5).getRight(42)))
/
discardExact(data.size - 47)
val imageId = String(readBytes(42))
discardExact(1)//0x41
discardExact(1)//0x42
discardExact(1)//0x43
discardExact(1)//0x41
return Image(imageId)*/
}
internal fun ByteReadPacket.parseMessageChain(): MessageChain {
@ -63,50 +64,56 @@ internal fun ByteReadPacket.readMessage(): Message? {
val messageType = this.readByte().toInt()
val sectionLength = this.readShort().toLong()//sectionLength: short
val sectionData = this.readIoBuffer(sectionLength.toInt())//use buffer instead
return when (messageType) {
0x01 -> sectionData.parsePlainText()
0x02 -> sectionData.parseMessageFace()
0x03 -> sectionData.parseMessageImage0x03()
0x06 -> sectionData.parseMessageImage0x06()
return try {
when (messageType) {
0x01 -> sectionData.parsePlainText()
0x02 -> sectionData.parseMessageFace()
0x03 -> sectionData.parseMessageImage0x03()
0x06 -> sectionData.parseMessageImage0x06()
0x19 -> {//未知, 可能是长文本?
//bot手机自己跟自己发消息会出这个
//似乎手机发消息就会有这个?
//sectionData: 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00
// 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00
return null
sectionData.readBytes().debugPrint("sectionData")
return PlainText("[UNKNOWN(${this.readBytes().toUHexString()})]")
println()
val value = readLVByteArray()
//todo 未知压缩算法
PlainText(String(value))
0x19 -> {//未知, 可能是长文本?
//bot手机自己跟自己发消息会出这个
//似乎手机发消息就会有这个?
//sectionData: 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00
// 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00
return null
sectionData.readBytes().debugPrint("sectionData")
return PlainText("[UNKNOWN(${this.readBytes().toUHexString()})]")
println()
val value = readLVByteArray()
//todo 未知压缩算法
PlainText(String(value))
// PlainText(String(GZip.uncompress( value)))
}
0x14 -> {//长文本
val value = readLVByteArray()
println(value.size)
println(value.toUHexString())
//todo 未知压缩算法
this.discardExact(7)//几个TLV
return PlainText(String(value))
}
0x0E -> {
null
}
else -> {
println("未知的messageType=0x${messageType.toByte().toUHexString()}")
println("后文=${this.readBytes().toUHexString()}")
null
// PlainText(String(GZip.uncompress( value)))
}
0x14 -> {//长文本
//是否要用 sectionData.read?
val value = readLVByteArray()
println(value.size)
println(value.toUHexString())
//todo 未知压缩算法
this.discardExact(7)//几个TLV
return PlainText(String(value))
}
0x0E -> {
null
}
else -> {
println("未知的messageType=0x${messageType.toByte().toUHexString()}")
println("后文=${this.readBytes().toUHexString()}")
null
}
}
} finally {
sectionData.release(IoBuffer.Pool)
}
}
fun ByteReadPacket.readMessageChain(): MessageChain {

View File

@ -10,7 +10,9 @@ import net.mamoe.mirai.getQQ
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.distributePacket
import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.network.protocol.tim.packet.IgnoredServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerFriendOnlineStatusChangedPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientSendFriendMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientSendGroupMessagePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendFriendMessageResponsePacket
@ -41,7 +43,14 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) {
is ServerGroupMessageEventPacket -> {
if (packet.qq.toLong() == bot.account.account) return
GroupMessageEvent(bot, bot.getGroupByNumber(packet.groupNumber), bot.getQQ(packet.qq), packet.message).broadcast()
GroupMessageEvent(
bot,
group = bot.getGroupByNumber(packet.groupNumber),
sender = bot.getQQ(packet.qq),
message = packet.message,
senderName = packet.senderName,
senderPermission = packet.senderPermission
).broadcast()
}
is ServerSendFriendMessageResponsePacket,
@ -49,8 +58,8 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) {
//ignored
}
is ServerFieldOnlineStatusChangedPacket.Encrypted -> distributePacket(packet.decrypt(sessionKey))
is ServerFieldOnlineStatusChangedPacket -> {
is ServerFriendOnlineStatusChangedPacket.Encrypted -> distributePacket(packet.decrypt(sessionKey))
is ServerFriendOnlineStatusChangedPacket -> {
MiraiLogger.logInfo("${packet.qq.toLong()} 登录状态改变为 ${packet.status}")
//TODO
}

View File

@ -13,7 +13,7 @@ import kotlin.properties.Delegates
* 好友在线状态改变
*/
@PacketId(0x00_81u)
class ServerFieldOnlineStatusChangedPacket(input: ByteReadPacket) : ServerPacket(input) {
class ServerFriendOnlineStatusChangedPacket(input: ByteReadPacket) : ServerPacket(input) {
var qq: UInt by Delegates.notNull()
lateinit var status: OnlineStatus
@ -28,6 +28,6 @@ class ServerFieldOnlineStatusChangedPacket(input: ByteReadPacket) : ServerPacket
@PacketId(0x00_81u)
class Encrypted(input: ByteReadPacket) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): ServerFieldOnlineStatusChangedPacket = ServerFieldOnlineStatusChangedPacket(this.decryptBy(sessionKey)).applySequence(sequenceId)
fun decrypt(sessionKey: ByteArray): ServerFriendOnlineStatusChangedPacket = ServerFriendOnlineStatusChangedPacket(this.decryptBy(sessionKey)).applySequence(sequenceId)
}
}

View File

@ -1,325 +0,0 @@
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.io.core.*
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.utils.*
import kotlin.properties.Delegates
/**
* 事件的识别 ID. [事件确认包][ServerEventPacket.ResponsePacket] 中被使用.
*/
data class EventPacketIdentity(
val from: UInt,//对于好友消息, 这个是发送人
val to: UInt,//对于好友消息, 这个是bot
internal val uniqueId: IoBuffer//8
) {
override fun toString(): String = "(from=$from, to=$to)"
}
fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) = with(identity) {
writeUInt(from)
writeUInt(to)
writeFully(uniqueId)
}
fun <S : ServerEventPacket> S.applyId(id: UShort): S {
this.id = id
return this
}
/**
* Packet id: `00 CE` or `00 17`
*
* @author Him188moe
*/
abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: EventPacketIdentity) : ServerPacket(input) {
override var id: UShort = 0u
class Raw(input: ByteReadPacket, override val id: UShort) : ServerPacket(input) {
fun distribute(): ServerEventPacket = with(input) {
val eventIdentity = EventPacketIdentity(
from = readUInt(),
to = readUInt(),
uniqueId = readIoBuffer(8)
)
discardExact(2)
val type = readBytes(2)
//DebugLogger.logPurple("unknown2Byte+byte = ${unknown2Byte.toUHexString()} ${type.toUHexString()}")
return when (type.toUHexString()) {
"00 C4" -> {
discardExact(13)
if (readBoolean()) {
ServerAndroidOfflineEventPacket(input, eventIdentity)
} else {
ServerAndroidOnlineEventPacket(input, eventIdentity)
}
}
"00 2D" -> ServerGroupUploadFileEventPacket(input, eventIdentity)
"00 52" -> ServerGroupMessageEventPacket(input, eventIdentity)
"00 A6" -> ServerFriendMessageEventPacket(input.debugPrint("好友消息事件"), eventIdentity)
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 16 00 00 00 37 08 02 1A 12 08 95 02 10 90 04 40 98 E1 8C ED 05 48 AF 96 C3 A4 03 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 29 08 00 10 05 18 98 E1 8C ED 05 20 01 28 FF FF FF FF 0F 32 15 E5 AF B9 E6 96 B9 E6 AD A3 E5 9C A8 E8 BE 93 E5 85 A5 2E 2E 2E
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 07 00 00 00
"02 10" -> {
discardExact(19)
println(readUByte().toUInt())
//todo 错了. 可能是 00 79 才是.
ServerFriendTypingCanceledPacket(input, eventIdentity)
/*
if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity)
else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity)*/
}
"00 79" -> IgnoredServerEventPacket(type, input, eventIdentity)
//"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity)
else -> {
MiraiLogger.logDebug("UnknownEvent type = ${type.toUHexString()}")
UnknownServerEventPacket(input, eventIdentity)
}
}.applyId(id).applySequence(sequenceId)
}
class Encrypted(input: ByteReadPacket, override var id: UShort, override var sequenceId: UShort) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey), id).applySequence(sequenceId)
}
}
inner class ResponsePacket(
val bot: Long,
val sessionKey: ByteArray
) : ClientPacket() {
override val id: UShort get() = this@ServerEventPacket.id
override val sequenceId: UShort get() = this@ServerEventPacket.sequenceId
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(bot)
this.writeHex(TIMProtocol.fixVer2)
this.encryptAndWrite(sessionKey) {
writeEventPacketIdentity(eventIdentity)
}
}
}
}
/**
* 忽略的事件.
* 00 79: 总是与 01 12 一起发生, 00 79 却没多大意义
*/
class IgnoredServerEventPacket(val eventId: ByteArray/*2*/, input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)
/**
* Unknown event
*/
class UnknownServerEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
override fun decode() {
MiraiLogger.logDebug("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString())
}
}
sealed class ServerFriendTypingPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
val qq get() = eventIdentity.from
}
/**
* 对方正在输入
*/
class ServerFriendTypingStartedPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity)
/**
* 对方取消了输入
*/
class ServerFriendTypingCanceledPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity)
/**
* Android 客户端上线
*/
class ServerAndroidOnlineEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)
/**
* Android 客户端下线
*/
class ServerAndroidOfflineEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)
/**
* 群文件上传
*/
class ServerGroupUploadFileEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
private lateinit var xmlMessage: String
override fun decode() {
this.input.discardExact(60)
val size = this.input.readShort().toInt()
this.input.discardExact(3)
xmlMessage = this.input.readString(size)
}//todo test
}
@Suppress("EXPERIMENTAL_API_USAGE")
class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
var groupNumber: UInt by Delegates.notNull()
var qq: UInt by Delegates.notNull()
lateinit var senderName: String
lateinit var message: MessageChain
override fun decode() = with(input) {
discardExact(31)
groupNumber = readUInt()
discardExact(1)
qq = readUInt()
discardExact(48)
readLVByteArray()
discardExact(2)//2个0x00
message = readMessageChain()
val map = readTLVMap(true)
map.printTLVMap("父map")
if (map.containsKey(18)) {
senderName = map.getValue(18).read {
val tlv = readTLVMap(true)
tlv.printTLVMap("子map")
////群主的18: 05 00 04 00 00 00 03 08 00 04 00 00 00 04 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08
//群主的 子map= {5=00 00 00 03, 8=00 00 00 04, 1=48 69 6D 31 38 38 6D 6F 65, 3=04, 4=00 00 00 08}
when {
tlv.containsKey(0x01) -> String(tlv.getValue(0x01))
tlv.containsKey(0x02) -> String(tlv.getValue(0x02))
else -> "null"
}
}
}
}
}
//
//以前的消息: 00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 58 2C 60 86 35 3A 30 B3 C7 63 4A 80 E7 CD 5B 64 00 0B 78 16 5D A3 0A FD 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 0A FD AB 77 16 02 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 04 01 00 01 36 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
//刚刚的消息: 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 11 F4 B2 F2 1A E7 1F C4 F1 3F 23 FB 74 80 42 64 00 0B 78 1A 5D A3 26 C1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 26 C1 AA 34 08 42 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
fun main() {
println("01 00 32 AA 02 2F 50 03 60 00 68 00 9A 01 26 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00".hexToBytes().stringOf())
}
fun main2() {
val data = "00 00 00 20 00 05 00 02 00 06 00 06 00 04 00 01 01 07 00 09 00 06 03 E9 20 02 EB 94 00 0A 00 04 01 00 00 00 0C 17 76 E4 B8 DD 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B A6 D2 5D A3 2A 3F 00 00 5D A3 2A 3F 01 00 00 00 00 4D 53 47 00 00 00 00 00 5D A3 2A 3F 0C 8A 59 3D 00 00 00 00 0A 00 86 02 00 06 E5 AE 8B E4 BD 93 00 00 01 00 06 01 00 03 31 32 33 19 00 1F 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00".hexToBytes()
val packet = ServerFriendMessageEventPacket(data.toReadPacket(), EventPacketIdentity(0u, 0u, IoBuffer.Empty))
packet.decode()
println(packet)
}
class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
val qq: UInt get() = eventIdentity.from
/**
* 是否是在这次登录之前的消息, 即消息记录
*/
var isPrevious: Boolean = false
lateinit var message: MessageChain
//来自自己发送给自己
//00 00 00 20 00 05 00 02 00 06 00 06 00 04 00 01 01 07 00 09 00 06 03 E9 20 02 EB 94 00 0A 00 04 01 00 00 00 0C 17 76 E4 B8 DD 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B A6 D2 5D A3 2A 3F 00 00 5D A3 2A 3F 01 00 00 00 00 4D 53 47 00 00 00 00 00 5D A3 2A 3F 0C 8A 59 3D 00 00 00 00 0A 00 86 02 00 06 E5 AE 8B E4 BD 93 00 00 01 00 06 01 00 03 31 32 33 19 00 1F 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00
override fun decode() = with(input) {
input.discardExact(2)
val l1 = readShort()
discardExact(1)//0x00
isPrevious = readByte().toInt() == 0x08
discardExact(l1.toInt() - 2)
discardExact(69)
readLVByteArray()//font
discardExact(2)//2个0x00
message = readMessageChain()
val map: Map<Int, ByteArray> = readTLVMap(true).withDefault { byteArrayOf() }
map.printTLVMap("readTLVMap")
//println("map.getValue(18)=" + map.getValue(18).toUHexString())
//19 00 38 01 00 35 AA 02 32 50 03 60 00 68 00 9A 01 29 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 05 00 04 00 00 00 01 08 00 04 00 00 00 01
/*
val offset = unknownLength0 + fontLength//57
event = MessageChain(PlainText(let {
val length = input.readShortAt(101 + offset)//
input.goto(103 + offset).readString(length.toInt())
}))*/
}
}
/*
牛逼 (10404
3E 03 3F A2 8F 00 1A E5 00 0B 53 3B 64 6B 91 17 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 40 5D 73 AF A1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 AF A1 1F EE 24 55 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
牛逼 (10404
3E 03 3F A2 8F 00 1A E5 00 00 86 F3 09 18 83 47 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 41 5D 73 B3 21 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 B3 20 94 B0 82 BC 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
牛逼 (19947
76 E4 B8 DD 8F 00 1A E5 00 0D A2 8A 0A 65 7C D0 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 76 E4 B8 DD 8F 00 1A E5 4E 35 88 98 FE 64 7C E9 33 F7 2F B1 32 5D 5F A9 00 0B 77 FC 5D 73 B4 38 02 5B 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 B4 38 A6 60 C7 9A 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 0E 00 07 01 00 04 00 00 00 00
牛逼 (jiahua
B1 89 BE 09 8F 00 1A E5 00 0D EB CB 09 90 BA CF 1F 40 00 A6 00 00 00 20 00 05 00 02 00 01 00 06 00 04 00 01 05 0F 00 09 00 06 03 E9 20 02 E5 B3 00 0A 00 04 01 00 00 00 25 15 B1 89 BE 09 8F 00 1A E5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B 77 A3 5D 73 B4 7D 00 00 5D 73 B4 7D 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 73 B4 7D 0E A3 93 E3 00 00 00 00 09 00 86 00 00 09 48 65 6C 76 65 74 69 63 61 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00 19 00 1C 01 00 19 AA 02 16 08 00 88 01 00 9A 01 0E 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00
牛逼 (jiahua
B1 89 BE 09 8F 00 1A E5 00 0B 03 A2 09 90 BB 7A 1F 40 00 A6 00 00 00 20 00 05 00 02 00 01 00 06 00 04 00 01 05 0F 00 09 00 06 03 E9 20 02 E5 B3 00 0A 00 04 01 00 00 00 25 15 B1 89 BE 09 8F 00 1A E5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B 77 A5 5D 73 B6 33 00 00 5D 73 B6 33 00 00 00 00 00 4D 53 47 00 00 00 00 00 5D 73 B6 33 22 DE A7 56 00 00 00 00 09 00 86 00 00 09 48 65 6C 76 65 74 69 63 61 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00 19 00 1C 01 00 19 AA 02 16 08 00 88 01 00 9A 01 0E 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00
牛逼[EMOJI表情1]牛逼 (10404
3E 03 3F A2 8F 00 1A E5 00 0B 59 A3 64 6B 91 17 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 44 5D 73 BA D9 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 BA D9 12 C7 FC CD 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 02 00 14 01 00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
牛逼[EMOJI表情2]牛逼 (10404
3E 03 3F A2 8F 00 1A E5 00 0D 4D 4A 09 18 83 47 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 45 5D 73 BF A0 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 BF A0 68 31 43 A2 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 02 00 14 01 00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
牛逼[EMOJI表情1]牛逼 (10404
3E 03 3F A2 8F 00 1A E5 00 02 3C 8E 64 6B 91 17 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 47 5D 73 C3 76 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 73 C3 75 41 3B 97 72 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 0F 01 00 0C E7 89 9B E9 80 BC E7 89 9B E9 80 BC 02 00 14 01 00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
[图片] (10404
3E 03 3F A2 8F 00 1A E5 00 0E 02 CF 64 6B A0 0C 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 8F 00 1A E5 3B DF D8 CE 2B 2E 96 D0 12 CF 0D 44 CF C9 22 A0 00 0B 32 4B 5D 73 D1 1C 01 1D 00 00 00 00 01 00 00 00 0C 4D 53 47 00 00 00 00 00 5D 73 D1 1C F5 78 37 16 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 06 00 F0 02 00 1B 28 5A 53 41 58 40 57 4B 52 4A 5A 31 7E 33 59 4F 53 53 4C 4D 32 4B 49 2E 6A 70 67 03 00 04 00 00 06 E2 04 00 25 2F 65 64 33 39 30 66 38 34 2D 34 66 38 37 2D 34 36 64 63 2D 62 33 38 35 2D 34 35 35 36 62 35 31 30 61 61 35 33 14 00 04 03 00 00 00 18 00 25 2F 65 64 33 39 30 66 38 34 2D 34 66 38 37 2D 34 36 64 63 2D 62 33 38 35 2D 34 35 35 36 62 35 31 30 61 61 35 33 19 00 04 00 00 00 38 1A 00 04 00 00 00 34 FF 00 63 16 20 20 39 39 31 30 20 38 38 31 43 42 20 20 20 20 20 20 31 37 36 32 65 42 39 45 32 37 32 31 43 39 36 44 37 39 41 38 32 31 36 45 30 41 44 34 30 42 35 39 35 39 31 38 36 2E 6A 70 67 66 2F 65 64 33 39 30 66 38 34 2D 34 66 38 37 2D 34 36 64 63 2D 62 33 38 35 2D 34 35 35 36 62 35 31 30 61 61 35 33 41 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
*/
/*
3E 03 3F A2 76 E4 B8 DD 00 09 7C 3F 64 5C 2A 60 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E4 5D 6B A8 F6 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A8 F6 08 7E 90 CE 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
3E 03 3F A2 76 E4 B8 DD 00 03 5F 85 64 5C 2A A4 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E5 5D 6B A9 16 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A9 17 1B B3 4D D7 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
*/
/*
backup
class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
var qq: Long = 0
lateinit var event: String
override fun dataDecode() {
//start at Sep1.0:27
qq = input.readIntAt(0)
val msgLength = input.readShortAt(22)
val fontLength = input.readShortAt(93+msgLength)
val offset = msgLength+fontLength
event = if(input.readByteAt(97+offset).toUHexString() == "02"){
"[face" + input.goto(103+offset).readByteAt(1).toInt().toString() + ".gif]"
//.gif
}else {
val offset2 = input.readShortAt(101 + offset)
input.goto(103 + offset).readString(offset2.toInt())
}
}
}
*/

View File

@ -0,0 +1,16 @@
package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.network.protocol.tim.packet.EventPacketIdentity
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
/**
* Android 客户端上线
*/
class ServerAndroidOnlineEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)
/**
* Android 客户端下线
*/
class ServerAndroidOfflineEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)

View File

@ -0,0 +1,32 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import net.mamoe.mirai.network.protocol.tim.packet.EventPacketIdentity
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
import net.mamoe.mirai.utils.readString
/**
* 群文件上传
*/
class ServerGroupUploadFileEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
private lateinit var xmlMessage: String
override fun decode() {
this.input.discardExact(60)
val size = this.input.readShort().toInt()
this.input.discardExact(3)
xmlMessage = this.input.readString(size)
}//todo test
}
class ServerGroupUnknownChangedEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
override fun decode() = with(input) {
//00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 55 00 00 00 05 00 00 00 E9 00 00 00 05
//00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 56 00 00 00 05 00 00 00 EA 00 00 00 05
}
}

View File

@ -0,0 +1,122 @@
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.network.protocol.tim.packet.EventPacketIdentity
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
import net.mamoe.mirai.utils.printTLVMap
import net.mamoe.mirai.utils.read
import net.mamoe.mirai.utils.readLVByteArray
import net.mamoe.mirai.utils.readTLVMap
import kotlin.properties.Delegates
enum class SenderPermission {
OWNER,
OPERATOR,
MEMBER;
}
@Suppress("EXPERIMENTAL_API_USAGE")
class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
var groupNumber: UInt by Delegates.notNull()
var qq: UInt by Delegates.notNull()
lateinit var senderName: String
/**
* 发送方权限.
*/
lateinit var senderPermission: SenderPermission
lateinit var message: MessageChain
override fun decode() = with(input) {
discardExact(31)
groupNumber = readUInt()
discardExact(1)
qq = readUInt()
discardExact(48)
readLVByteArray()
discardExact(2)//2个0x00
message = readMessageChain()
val map = readTLVMap(true).withDefault { byteArrayOf(0, 0, 0, 0) }
//map.printTLVMap("父map")
if (map.containsKey(18)) {
senderName = map.getValue(18).read {
val tlv = readTLVMap(true)
//tlv.printTLVMap("子map")
////群主的18: 05 00 04 00 00 00 03 08 00 04 00 00 00 04 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08
//群主的 子map= {5=00 00 00 03, 8=00 00 00 04, 1=48 69 6D 31 38 38 6D 6F 65, 3=04, 4=00 00 00 08}
//管理员 子map= {5=00 00 00 03, 8=00 00 00 04, 2=65 6F 6D 38 38 31 6D 69 48, 3=02, 4=00 00 00 10}
//群成员 子map= {5=00 00 00 03, 8=00 00 00 04, 2=65 6F 6D 38 38 31 6D 69 48, 3=02}
senderPermission = when (val value0x03 = tlv.getValue(0x03)[0].toUInt()) {
0x04u -> SenderPermission.OWNER
0x03u -> {
when (val value0x04 = tlv.getValue(0x04)[3].toUInt()) {
0x08u -> SenderPermission.OPERATOR
0x10u -> SenderPermission.MEMBER
else -> error("Could not determine member permission, unknown tlv(key=0x04,value=$value0x04)")
}
}
else -> error("Could not determine member permission, unknown tlv(key=0x03,value=$value0x03)")
}
when {
tlv.containsKey(0x01) -> kotlinx.io.core.String(tlv.getValue(0x01))//这个人的qq昵称
tlv.containsKey(0x02) -> kotlinx.io.core.String(tlv.getValue(0x02))//这个人的群名片
else -> "null"
}
}
}
}
}
//
//以前的消息: 00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 58 2C 60 86 35 3A 30 B3 C7 63 4A 80 E7 CD 5B 64 00 0B 78 16 5D A3 0A FD 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 0A FD AB 77 16 02 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 04 01 00 01 36 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
//刚刚的消息: 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 11 F4 B2 F2 1A E7 1F C4 F1 3F 23 FB 74 80 42 64 00 0B 78 1A 5D A3 26 C1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 26 C1 AA 34 08 42 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
val qq: UInt get() = eventIdentity.from
/**
* 是否是在这次登录之前的消息, 即消息记录
*/
var isPrevious: Boolean = false
lateinit var message: MessageChain
//来自自己发送给自己
//00 00 00 20 00 05 00 02 00 06 00 06 00 04 00 01 01 07 00 09 00 06 03 E9 20 02 EB 94 00 0A 00 04 01 00 00 00 0C 17 76 E4 B8 DD 76 E4 B8 DD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0B A6 D2 5D A3 2A 3F 00 00 5D A3 2A 3F 01 00 00 00 00 4D 53 47 00 00 00 00 00 5D A3 2A 3F 0C 8A 59 3D 00 00 00 00 0A 00 86 02 00 06 E5 AE 8B E4 BD 93 00 00 01 00 06 01 00 03 31 32 33 19 00 1F 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 0E 00 0E 01 00 04 00 00 00 00 0A 00 04 00 00 00 00
override fun decode() = with(input) {
input.discardExact(2)
val l1 = readShort()
discardExact(1)//0x00
isPrevious = readByte().toInt() == 0x08
discardExact(l1.toInt() - 2)
discardExact(69)
readLVByteArray()//font
discardExact(2)//2个0x00
message = readMessageChain()
val map: Map<Int, ByteArray> = readTLVMap(true).withDefault { byteArrayOf() }
map.printTLVMap("readTLVMap")
//println("map.getValue(18)=" + map.getValue(18).toUHexString())
//19 00 38 01 00 35 AA 02 32 50 03 60 00 68 00 9A 01 29 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 05 00 04 00 00 00 01 08 00 04 00 00 00 01
/*
val offset = unknownLength0 + fontLength//57
event = MessageChain(PlainText(let {
val length = input.readShortAt(101 + offset)//
input.goto(103 + offset).readString(length.toInt())
}))*/
}
}

View File

@ -0,0 +1,126 @@
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.protocol.tim.packet
import kotlinx.io.core.*
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.event.*
import net.mamoe.mirai.utils.*
/**
* 事件的识别 ID. [事件确认包][ServerEventPacket.ResponsePacket] 中被使用.
*/
data class EventPacketIdentity(
val from: UInt,//对于好友消息, 这个是发送人
val to: UInt,//对于好友消息, 这个是bot
internal val uniqueId: IoBuffer//8
) {
override fun toString(): String = "(from=$from, to=$to)"
}
fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) = with(identity) {
writeUInt(from)
writeUInt(to)
writeFully(uniqueId)
}
fun <S : ServerEventPacket> S.applyId(id: UShort): S {
this.id = id
return this
}
/**
* Packet id: `00 CE` or `00 17`
*
* @author Him188moe
*/
abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: EventPacketIdentity) : ServerPacket(input) {
override var id: UShort = 0u
class Raw(input: ByteReadPacket, override val id: UShort) : ServerPacket(input) {
fun distribute(): ServerEventPacket = with(input) {
val eventIdentity = EventPacketIdentity(
from = readUInt(),
to = readUInt(),
uniqueId = readIoBuffer(8)
)
discardExact(2)
val type = readUShort()
//DebugLogger.logPurple("unknown2Byte+byte = ${unknown2Byte.toUHexString()} ${type.toUHexString()}")
return when (type.toUInt()) {
0x00C4u -> {
discardExact(13)
if (readBoolean()) {
ServerAndroidOfflineEventPacket(input, eventIdentity)
} else {
ServerAndroidOnlineEventPacket(input, eventIdentity)
}
}
0x002Du -> ServerGroupUploadFileEventPacket(input, eventIdentity)
0x0052u -> ServerGroupMessageEventPacket(input, eventIdentity)
0x00A6u -> ServerFriendMessageEventPacket(input.debugPrint("好友消息事件"), eventIdentity)
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 16 00 00 00 37 08 02 1A 12 08 95 02 10 90 04 40 98 E1 8C ED 05 48 AF 96 C3 A4 03 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 29 08 00 10 05 18 98 E1 8C ED 05 20 01 28 FF FF FF FF 0F 32 15 E5 AF B9 E6 96 B9 E6 AD A3 E5 9C A8 E8 BE 93 E5 85 A5 2E 2E 2E
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 07 00 00 00
0x0210u -> {
discardExact(19)
println("type事件" + readUByte().toUInt())
//todo 错了. 可能是 00 79 才是.
ServerFriendTypingCanceledPacket(input, eventIdentity)
/*
if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity)
else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity)*/
}
0x0079u -> IgnoredServerEventPacket(type, input, eventIdentity)
//"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity)
else -> {
MiraiLogger.logDebug("UnknownEvent type = ${type.toInt().toByteArray().toUHexString()}")
UnknownServerEventPacket(input, eventIdentity)
}
}.applyId(id).applySequence(sequenceId)
}
class Encrypted(input: ByteReadPacket, override var id: UShort, override var sequenceId: UShort) : ServerPacket(input) {
fun decrypt(sessionKey: ByteArray): Raw = Raw(this.decryptBy(sessionKey), id).applySequence(sequenceId)
}
}
inner class ResponsePacket(
val bot: Long,
val sessionKey: ByteArray
) : ClientPacket() {
override val id: UShort get() = this@ServerEventPacket.id
override val sequenceId: UShort get() = this@ServerEventPacket.sequenceId
override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(bot)
this.writeHex(TIMProtocol.fixVer2)
this.encryptAndWrite(sessionKey) {
writeEventPacketIdentity(eventIdentity)
}
}
}
}
/**
* 忽略的事件.
* 00 79: 总是与 01 12 一起发生, 00 79 却没多大意义
*/
@Suppress("unused")
class IgnoredServerEventPacket(val eventId: UShort, input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)
/**
* Unknown event
*/
class UnknownServerEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
override fun decode() {
MiraiLogger.logDebug("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString())
}
}

View File

@ -0,0 +1,21 @@
package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.network.protocol.tim.packet.EventPacketIdentity
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
sealed class ServerFriendTypingPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
val qq get() = eventIdentity.from
}
/**
* 对方正在输入
*/
class ServerFriendTypingStartedPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity)
/**
* 对方取消了输入
*/
class ServerFriendTypingCanceledPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity)

View File

@ -75,7 +75,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {
0x00_58_u -> ServerHeartbeatResponsePacket(this)
0x00_BA_u -> ServerCaptchaPacket.Encrypted(this)
0x00_CE_u, 0x00_17_u -> ServerEventPacket.Raw.Encrypted(this, id, sequenceId)
0x00_81_u -> ServerFieldOnlineStatusChangedPacket.Encrypted(this)
0x00_81_u -> ServerFriendOnlineStatusChangedPacket.Encrypted(this)
0x00_CD_u -> ServerSendFriendMessageResponsePacket(this)
0x00_02_u -> ServerSendGroupMessageResponsePacket(this)
0x00_A7_u -> ServerCanAddFriendResponsePacket(this)

View File

@ -17,6 +17,7 @@ import net.mamoe.mirai.utils.BotAccount
import net.mamoe.mirai.utils.Console
import net.mamoe.mirai.utils.MiraiLogger
@Suppress("UNUSED_VARIABLE")
suspend fun main() {
val bot = Bot(BotAccount(//填写你的账号
account = 1994701021,