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
import net.mamoe.mirai.data.FriendInfo
import net.mamoe.mirai.data.GroupInfo
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.qqandroid.message.CustomFaceFromServer
import net.mamoe.mirai.qqandroid.message.NotOnlineImageFromServer
......@@ -140,6 +142,14 @@ internal abstract class QQAndroidBotBase constructor(
source.time
).sendAndExpect()
} else {
MessageRecallEvent.GroupRecall(
bot,
source.qqId,
source.id,
source.time.toInt(),
null,
getGroup(source.groupId)
).broadcast()
PbMessageSvc.PbMsgWithDraw.Group(
bot.client,
source.groupId,
......
......@@ -16,7 +16,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.MemberPermission
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.event.events.BotJoinGroupEvent
import net.mamoe.mirai.event.events.BotOfflineEvent
......@@ -107,19 +107,17 @@ internal class MessageSvc {
@UseExperimental(MiraiInternalAPI::class)
open class GetMsgSuccess(delegate: List<Packet>) : Response(MsgSvc.SyncFlag.STOP, delegate) {
override fun toString(): String {
return "MessageSvc.PbGetMsg.GetMsgSuccess(messages=List(size=${this.size}))"
}
override fun toString(): String = "MessageSvc.PbGetMsg.GetMsgSuccess(messages=<Iterable>))"
}
/**
* 不要直接 expect 这个 class. 它可能还没同步完成
*/
@MiraiInternalAPI
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List<Packet>) : MultiPacket<Packet>(delegate) {
override fun toString(): String {
return "MessageSvc.PbGetMsg.Response($syncFlagFromServer=$syncFlagFromServer, messages=List(size=${this.size}))"
}
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List<Packet>) :
MultiPacketByIterable<Packet>(delegate) {
override fun toString(): String =
"MessageSvc.PbGetMsg.Response($syncFlagFromServer=$syncFlagFromServer, messages=<Iterable>))"
}
object EmptyResponse : GetMsgSuccess(emptyList())
......
......@@ -11,9 +11,9 @@
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.data.MultiPacket
import net.mamoe.mirai.data.MultiPacketBySequence
import net.mamoe.mirai.data.NoPacket
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.event.Event
......@@ -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.MsgOnlinePush
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.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.readString
import net.mamoe.mirai.utils.io.toUHexString
......@@ -60,10 +60,14 @@ internal class OnlinePush {
if (!bot.firstLoginSucceed) return null
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) {
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)
......@@ -106,13 +110,22 @@ internal class OnlinePush {
val group = bot.getGroupByUin(content.fromUin) as GroupImpl
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) {
BotGroupPermissionChangeEvent(group, group.botPermission.also { group.botPermission = newPermission }, newPermission)
BotGroupPermissionChangeEvent(
group,
group.botPermission.also { group.botPermission = newPermission },
newPermission
)
} else {
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 {
val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req")
@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 {
when {
msgInfo.shMsgType.toInt() == 732 -> {
when (msgInfo.shMsgType.toInt()) {
732 -> {
val group = bot.getGroup(this.readUInt().toLong())
group as GroupImpl
when (val internalType = this.readShort().toInt()) {
3073 -> { // mute
when (val internalType = this.readByte().toInt().also { this.discardExact(1) }) {
0x0c -> { // mute
val operatorUin = this.readUInt().toLong()
if (operatorUin == bot.uin) {
return@mapNotNull null
return@flatMap sequenceOf<Packet>()
}
val operator = group[operatorUin]
this.readUInt().toLong() // time
......@@ -197,32 +211,41 @@ internal class OnlinePush {
if (target == 0L) {
if (time == 0) {
return@mapNotNull GroupMuteAllEvent(
return@flatMap sequenceOf(
GroupMuteAllEvent(
origin = group.isMuteAll.also { group._muteAll = false },
new = false,
operator = operator,
group = group
) as Packet
)
} else {
return@mapNotNull GroupMuteAllEvent(
return@flatMap sequenceOf(
GroupMuteAllEvent(
origin = group.isMuteAll.also { group._muteAll = true },
new = true,
operator = operator,
group = group
) as Packet
)
}
} else {
if (target == bot.uin) {
if (group._botMuteTimestamp != time) {
if (time == 0) {
group._botMuteTimestamp = 0
return@mapNotNull BotUnmuteEvent(operator) as Packet
return@flatMap sequenceOf(BotUnmuteEvent(operator) as Packet)
} else {
group._botMuteTimestamp = time
return@mapNotNull BotMuteEvent(durationSeconds = time, operator = operator) as Packet
return@flatMap sequenceOf(
BotMuteEvent(
durationSeconds = time,
operator = operator
) as Packet
)
}
} else {
return@mapNotNull null
return@flatMap sequenceOf()
}
} else {
val member = group[target]
......@@ -230,65 +253,129 @@ internal class OnlinePush {
if (member._muteTimestamp != time) {
if (time == 0) {
member._muteTimestamp = 0
return@mapNotNull MemberUnmuteEvent(member, operator) as Packet
return@flatMap sequenceOf(
MemberUnmuteEvent(
member,
operator
) as Packet
)
} else {
member._muteTimestamp = time
return@mapNotNull MemberMuteEvent(member, time, operator) as Packet
return@flatMap sequenceOf(
MemberMuteEvent(
member,
time,
operator
) as Packet
)
}
} else {
return@mapNotNull null
return@flatMap sequenceOf()
}
}
}
}
3585 -> {
0x0e -> {
// 匿名
val operator = group[this.readUInt().toLong()]
val switch = this.readInt() == 0
return@mapNotNull GroupAllowAnonymousChatEvent(
origin = group.isAnonymousChatEnabled.also { group._anonymousChat = switch },
return@flatMap sequenceOf(
GroupAllowAnonymousChatEvent(
origin = group.isAnonymousChatEnabled.also {
group._anonymousChat = switch
},
new = switch,
operator = operator,
group = group
)
)
}
4096 -> {
0x10 -> {
val dataBytes = this.readBytes(26)
val message = this.readString(this.readByte().toInt())
// println(dataBytes.toUHexString())
if (dataBytes[0].toInt() != 59) {
return@mapNotNull GroupNameChangeEvent(
return@flatMap sequenceOf(
GroupNameChangeEvent(
origin = group.name.also { group._name = message },
new = message,
group = group,
isByBot = false
)
)
} else {
//println(message + ":" + dataBytes.toUHexString())
when (message) {
"管理员已关闭群聊坦白说" -> {
return@mapNotNull GroupAllowConfessTalkEvent(
origin = group.isConfessTalkEnabled.also { group._confessTalk = false },
return@flatMap sequenceOf(
GroupAllowConfessTalkEvent(
origin = group.isConfessTalkEnabled.also {
group._confessTalk = false
},
new = false,
group = group,
isByBot = false
)
)
}
"管理员已开启群聊坦白说" -> {
return@mapNotNull GroupAllowConfessTalkEvent(
origin = group.isConfessTalkEnabled.also { group._confessTalk = true },
return@flatMap sequenceOf(
GroupAllowConfessTalkEvent(
origin = group.isConfessTalkEnabled.also {
group._confessTalk = true
},
new = true,
group = group,
isByBot = false
)
)
}
else -> {
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 -> {
// println(msgInfo.contentToString())
......@@ -296,24 +383,24 @@ internal class OnlinePush {
// }
else -> {
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()}" }
// val content = msgInfo.vMsg.loadAs(OnlinePushPack.MsgType0x210.serializer())
// println(content.contentToString())
return@mapNotNull null
return@flatMap sequenceOf()
}
else -> {
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? {
......
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