Commit 1dd4caa0 authored by Him188's avatar Him188

Support recall events, close #88

parent 024bd230
...@@ -19,6 +19,8 @@ import net.mamoe.mirai.data.AddFriendResult ...@@ -19,6 +19,8 @@ import net.mamoe.mirai.data.AddFriendResult
import net.mamoe.mirai.data.FriendInfo import net.mamoe.mirai.data.FriendInfo
import net.mamoe.mirai.data.GroupInfo import net.mamoe.mirai.data.GroupInfo
import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.MessageRecallEvent
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.message.CustomFaceFromServer import net.mamoe.mirai.qqandroid.message.CustomFaceFromServer
import net.mamoe.mirai.qqandroid.message.NotOnlineImageFromServer import net.mamoe.mirai.qqandroid.message.NotOnlineImageFromServer
...@@ -140,6 +142,14 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -140,6 +142,14 @@ internal abstract class QQAndroidBotBase constructor(
source.time source.time
).sendAndExpect() ).sendAndExpect()
} else { } else {
MessageRecallEvent.GroupRecall(
bot,
source.qqId,
source.id,
source.time.toInt(),
null,
getGroup(source.groupId)
).broadcast()
PbMessageSvc.PbMsgWithDraw.Group( PbMessageSvc.PbMsgWithDraw.Group(
bot.client, bot.client,
source.groupId, source.groupId,
......
...@@ -16,7 +16,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi ...@@ -16,7 +16,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.MultiPacketByIterable
import net.mamoe.mirai.data.Packet import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.event.events.BotJoinGroupEvent import net.mamoe.mirai.event.events.BotJoinGroupEvent
import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.BotOfflineEvent
...@@ -107,19 +107,17 @@ internal class MessageSvc { ...@@ -107,19 +107,17 @@ internal class MessageSvc {
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
open class GetMsgSuccess(delegate: List<Packet>) : Response(MsgSvc.SyncFlag.STOP, delegate) { open class GetMsgSuccess(delegate: List<Packet>) : Response(MsgSvc.SyncFlag.STOP, delegate) {
override fun toString(): String { override fun toString(): String = "MessageSvc.PbGetMsg.GetMsgSuccess(messages=<Iterable>))"
return "MessageSvc.PbGetMsg.GetMsgSuccess(messages=List(size=${this.size}))"
}
} }
/** /**
* 不要直接 expect 这个 class. 它可能还没同步完成 * 不要直接 expect 这个 class. 它可能还没同步完成
*/ */
@MiraiInternalAPI @MiraiInternalAPI
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List<Packet>) : MultiPacket<Packet>(delegate) { open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List<Packet>) :
override fun toString(): String { MultiPacketByIterable<Packet>(delegate) {
return "MessageSvc.PbGetMsg.Response($syncFlagFromServer=$syncFlagFromServer, messages=List(size=${this.size}))" override fun toString(): String =
} "MessageSvc.PbGetMsg.Response($syncFlagFromServer=$syncFlagFromServer, messages=<Iterable>))"
} }
object EmptyResponse : GetMsgSuccess(emptyList()) object EmptyResponse : GetMsgSuccess(emptyList())
......
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.* import io.ktor.utils.io.core.*
import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.MultiPacketBySequence
import net.mamoe.mirai.data.NoPacket import net.mamoe.mirai.data.NoPacket
import net.mamoe.mirai.data.Packet import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.Event
...@@ -30,12 +30,12 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.OnlinePushPack ...@@ -30,12 +30,12 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.OnlinePushPack
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgOnlinePush import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgOnlinePush
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.OnlinePushTrans import net.mamoe.mirai.qqandroid.network.protocol.data.proto.OnlinePushTrans
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.TroopTips0x857
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.debug import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.io.read import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.readString import net.mamoe.mirai.utils.io.readString
import net.mamoe.mirai.utils.io.toUHexString import net.mamoe.mirai.utils.io.toUHexString
...@@ -60,10 +60,14 @@ internal class OnlinePush { ...@@ -60,10 +60,14 @@ internal class OnlinePush {
if (!bot.firstLoginSucceed) return null if (!bot.firstLoginSucceed) return null
val pbPushMsg = readProtoBuf(MsgOnlinePush.PbPushMsg.serializer()) val pbPushMsg = readProtoBuf(MsgOnlinePush.PbPushMsg.serializer())
val extraInfo: ImMsgBody.ExtraInfo? = pbPushMsg.msg.msgBody.richText.elems.firstOrNull { it.extraInfo != null }?.extraInfo val extraInfo: ImMsgBody.ExtraInfo? =
pbPushMsg.msg.msgBody.richText.elems.firstOrNull { it.extraInfo != null }?.extraInfo
if (pbPushMsg.msg.msgHead.fromUin == bot.uin) { if (pbPushMsg.msg.msgHead.fromUin == bot.uin) {
return SendGroupMessageReceipt(pbPushMsg.msg.msgBody.richText.attr!!.random, pbPushMsg.msg.msgHead.msgSeq) return SendGroupMessageReceipt(
pbPushMsg.msg.msgBody.richText.attr!!.random,
pbPushMsg.msg.msgHead.msgSeq
)
} }
val group = bot.getGroup(pbPushMsg.msg.msgHead.groupInfo!!.groupCode) val group = bot.getGroup(pbPushMsg.msg.msgHead.groupInfo!!.groupCode)
...@@ -106,13 +110,22 @@ internal class OnlinePush { ...@@ -106,13 +110,22 @@ internal class OnlinePush {
val group = bot.getGroupByUin(content.fromUin) as GroupImpl val group = bot.getGroupByUin(content.fromUin) as GroupImpl
if (var5 == 0L && this.remaining == 1L) {//管理员变更 if (var5 == 0L && this.remaining == 1L) {//管理员变更
val newPermission = if (this.readByte().toInt() == 1) MemberPermission.ADMINISTRATOR else MemberPermission.MEMBER val newPermission =
if (this.readByte().toInt() == 1) MemberPermission.ADMINISTRATOR else MemberPermission.MEMBER
return if (target == bot.uin) { return if (target == bot.uin) {
BotGroupPermissionChangeEvent(group, group.botPermission.also { group.botPermission = newPermission }, newPermission) BotGroupPermissionChangeEvent(
group,
group.botPermission.also { group.botPermission = newPermission },
newPermission
)
} else { } else {
val member = group[target] as MemberImpl val member = group[target] as MemberImpl
MemberPermissionChangeEvent(member, member.permission.also { member.permission = newPermission }, newPermission) MemberPermissionChangeEvent(
member,
member.permission.also { member.permission = newPermission },
newPermission
)
} }
} }
} }
...@@ -176,18 +189,19 @@ internal class OnlinePush { ...@@ -176,18 +189,19 @@ internal class OnlinePush {
val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req") val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req")
@Suppress("USELESS_CAST") // 不要信任 kotlin 类型推断 @Suppress("USELESS_CAST") // 不要信任 kotlin 类型推断
val packets: List<Packet> = reqPushMsg.vMsgInfos.mapNotNull { msgInfo: MsgInfo -> val packets: Sequence<Packet> =
reqPushMsg.vMsgInfos.asSequence().flatMap<MsgInfo, Packet> { msgInfo: MsgInfo ->
msgInfo.vMsg!!.read { msgInfo.vMsg!!.read {
when { when (msgInfo.shMsgType.toInt()) {
msgInfo.shMsgType.toInt() == 732 -> { 732 -> {
val group = bot.getGroup(this.readUInt().toLong()) val group = bot.getGroup(this.readUInt().toLong())
group as GroupImpl group as GroupImpl
when (val internalType = this.readShort().toInt()) { when (val internalType = this.readByte().toInt().also { this.discardExact(1) }) {
3073 -> { // mute 0x0c -> { // mute
val operatorUin = this.readUInt().toLong() val operatorUin = this.readUInt().toLong()
if (operatorUin == bot.uin) { if (operatorUin == bot.uin) {
return@mapNotNull null return@flatMap sequenceOf<Packet>()
} }
val operator = group[operatorUin] val operator = group[operatorUin]
this.readUInt().toLong() // time this.readUInt().toLong() // time
...@@ -197,32 +211,41 @@ internal class OnlinePush { ...@@ -197,32 +211,41 @@ internal class OnlinePush {
if (target == 0L) { if (target == 0L) {
if (time == 0) { if (time == 0) {
return@mapNotNull GroupMuteAllEvent( return@flatMap sequenceOf(
GroupMuteAllEvent(
origin = group.isMuteAll.also { group._muteAll = false }, origin = group.isMuteAll.also { group._muteAll = false },
new = false, new = false,
operator = operator, operator = operator,
group = group group = group
) as Packet ) as Packet
)
} else { } else {
return@mapNotNull GroupMuteAllEvent( return@flatMap sequenceOf(
GroupMuteAllEvent(
origin = group.isMuteAll.also { group._muteAll = true }, origin = group.isMuteAll.also { group._muteAll = true },
new = true, new = true,
operator = operator, operator = operator,
group = group group = group
) as Packet ) as Packet
)
} }
} else { } else {
if (target == bot.uin) { if (target == bot.uin) {
if (group._botMuteTimestamp != time) { if (group._botMuteTimestamp != time) {
if (time == 0) { if (time == 0) {
group._botMuteTimestamp = 0 group._botMuteTimestamp = 0
return@mapNotNull BotUnmuteEvent(operator) as Packet return@flatMap sequenceOf(BotUnmuteEvent(operator) as Packet)
} else { } else {
group._botMuteTimestamp = time group._botMuteTimestamp = time
return@mapNotNull BotMuteEvent(durationSeconds = time, operator = operator) as Packet return@flatMap sequenceOf(
BotMuteEvent(
durationSeconds = time,
operator = operator
) as Packet
)
} }
} else { } else {
return@mapNotNull null return@flatMap sequenceOf()
} }
} else { } else {
val member = group[target] val member = group[target]
...@@ -230,65 +253,129 @@ internal class OnlinePush { ...@@ -230,65 +253,129 @@ internal class OnlinePush {
if (member._muteTimestamp != time) { if (member._muteTimestamp != time) {
if (time == 0) { if (time == 0) {
member._muteTimestamp = 0 member._muteTimestamp = 0
return@mapNotNull MemberUnmuteEvent(member, operator) as Packet return@flatMap sequenceOf(
MemberUnmuteEvent(
member,
operator
) as Packet
)
} else { } else {
member._muteTimestamp = time member._muteTimestamp = time
return@mapNotNull MemberMuteEvent(member, time, operator) as Packet return@flatMap sequenceOf(
MemberMuteEvent(
member,
time,
operator
) as Packet
)
} }
} else { } else {
return@mapNotNull null return@flatMap sequenceOf()
} }
} }
} }
} }
3585 -> { 0x0e -> {
// 匿名 // 匿名
val operator = group[this.readUInt().toLong()] val operator = group[this.readUInt().toLong()]
val switch = this.readInt() == 0 val switch = this.readInt() == 0
return@mapNotNull GroupAllowAnonymousChatEvent( return@flatMap sequenceOf(
origin = group.isAnonymousChatEnabled.also { group._anonymousChat = switch }, GroupAllowAnonymousChatEvent(
origin = group.isAnonymousChatEnabled.also {
group._anonymousChat = switch
},
new = switch, new = switch,
operator = operator, operator = operator,
group = group group = group
) )
)
} }
4096 -> { 0x10 -> {
val dataBytes = this.readBytes(26) val dataBytes = this.readBytes(26)
val message = this.readString(this.readByte().toInt()) val message = this.readString(this.readByte().toInt())
// println(dataBytes.toUHexString()) // println(dataBytes.toUHexString())
if (dataBytes[0].toInt() != 59) { if (dataBytes[0].toInt() != 59) {
return@mapNotNull GroupNameChangeEvent( return@flatMap sequenceOf(
GroupNameChangeEvent(
origin = group.name.also { group._name = message }, origin = group.name.also { group._name = message },
new = message, new = message,
group = group, group = group,
isByBot = false isByBot = false
) )
)
} else { } else {
//println(message + ":" + dataBytes.toUHexString()) //println(message + ":" + dataBytes.toUHexString())
when (message) { when (message) {
"管理员已关闭群聊坦白说" -> { "管理员已关闭群聊坦白说" -> {
return@mapNotNull GroupAllowConfessTalkEvent( return@flatMap sequenceOf(
origin = group.isConfessTalkEnabled.also { group._confessTalk = false }, GroupAllowConfessTalkEvent(
origin = group.isConfessTalkEnabled.also {
group._confessTalk = false
},
new = false, new = false,
group = group, group = group,
isByBot = false isByBot = false
) )
)
} }
"管理员已开启群聊坦白说" -> { "管理员已开启群聊坦白说" -> {
return@mapNotNull GroupAllowConfessTalkEvent( return@flatMap sequenceOf(
origin = group.isConfessTalkEnabled.also { group._confessTalk = true }, GroupAllowConfessTalkEvent(
origin = group.isConfessTalkEnabled.also {
group._confessTalk = true
},
new = true, new = true,
group = group, group = group,
isByBot = false isByBot = false
) )
)
} }
else -> { else -> {
bot.network.logger.debug { "Unknown server messages $message" } bot.network.logger.debug { "Unknown server messages $message" }
return@mapNotNull null return@flatMap sequenceOf()
}
}
}
}
0x11 -> {
discard(1)
val proto = readProtoBuf(TroopTips0x857.NotifyMsgBody.serializer())
proto.optMsgRecall?.let { recallReminder ->
return@flatMap recallReminder.recalledMsgList.asSequence()
.mapNotNull { meta ->
if (meta.authorUin == bot.uin) {
null
} else MessageRecallEvent.GroupRecall(
bot,
meta.authorUin,
meta.seq.toLong().shl(32) or meta.msgRandom.toLong(),
meta.time,
group.get(recallReminder.uin),
group
)
} }
/*
optMsgRecall=MessageRecallReminder#1345636186 {
groupType=0x00000000(0)
nickname=<Empty ByteArray>
opType=0x00000000(0)
recalledMsgList=[MessageMeta#1828757853 {
authorUin=0x000000003E033FA2(1040400290)
msgFlag=0x00000000(0)
msgRandom=0x509119DC(1351686620)
msgType=0x00000000(0)
seq=0x0000EB4B(60235)
time=0x5E50C4EC(1582351596)
}]
reminderContent=<Empty ByteArray>
uin=0x000000003E033FA2(1040400290)
userdef=08 00 12 0A 08 CB D6 03 10 00 18 01 20 00
} }
*/
} }
return@flatMap sequenceOf()
} }
// 4352 -> { // 4352 -> {
// println(msgInfo.contentToString()) // println(msgInfo.contentToString())
...@@ -296,24 +383,24 @@ internal class OnlinePush { ...@@ -296,24 +383,24 @@ internal class OnlinePush {
// } // }
else -> { else -> {
bot.network.logger.debug { "unknown group internal type $internalType , data: " + this.readBytes().toUHexString() + " " } bot.network.logger.debug { "unknown group internal type $internalType , data: " + this.readBytes().toUHexString() + " " }
return@mapNotNull null return@flatMap sequenceOf()
} }
} }
} }
msgInfo.shMsgType.toInt() == 528 -> { 528 -> {
bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" } bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" }
// val content = msgInfo.vMsg.loadAs(OnlinePushPack.MsgType0x210.serializer()) // val content = msgInfo.vMsg.loadAs(OnlinePushPack.MsgType0x210.serializer())
// println(content.contentToString()) // println(content.contentToString())
return@mapNotNull null return@flatMap sequenceOf()
} }
else -> { else -> {
bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" } bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" }
return@mapNotNull null return@flatMap sequenceOf()
} }
} }
} }
} }
return MultiPacket(packets) return MultiPacketBySequence(packets)
} }
override suspend fun QQAndroidBot.handle(packet: Packet, sequenceId: Int): OutgoingPacket? { override suspend fun QQAndroidBot.handle(packet: Packet, sequenceId: Int): OutgoingPacket? {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment