From 864cde060ececb97ddf2c087eb169e618ce3d80d Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 4 Apr 2020 23:22:52 +0800 Subject: [PATCH] Fix #180 --- .../mirai/qqandroid/QQAndroidBot.common.kt | 32 +++++++++++++++- .../mamoe/mirai/qqandroid/contact/QQImpl.kt | 1 + .../qqandroid/message/MessageSourceImpl.kt | 37 ++++++++++++++----- .../mirai/qqandroid/message/convension.kt | 18 +++++---- .../network/protocol/data/proto/Msg.kt | 2 +- .../protocol/packet/chat/PbMessageSvc.kt | 5 +-- .../packet/chat/receive/MessageSvc.kt | 2 +- .../packet/chat/receive/OnlinePush.kt | 2 +- .../message/data/MessageSource.kt | 15 +++++++- .../message/data/QuoteReply.kt | 4 +- 10 files changed, 89 insertions(+), 29 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt index 71c626683..5c60d54e4 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt @@ -216,23 +216,51 @@ internal abstract class QQAndroidBotBase constructor( ).sendAndExpect() } } - is OfflineMessageSource, is MessageSourceFromFriendImpl, is MessageSourceToFriendImpl -> network.run { + check(source.fromId == this@QQAndroidBotBase.id) { + "can only recall a message sent by bot" + } PbMessageSvc.PbMsgWithDraw.createForFriendMessage( bot.client, - source.fromId, + source.targetId, source.sequenceId, source.id, source.time ).sendAndExpect() } + is OfflineMessageSource -> network.run { + when (source.kind) { + OfflineMessageSource.Kind.FRIEND -> { + check(source.fromId == this@QQAndroidBotBase.id) { + "can only recall a message sent by bot" + } + PbMessageSvc.PbMsgWithDraw.createForFriendMessage( + bot.client, + source.targetId, + source.sequenceId, + source.id, + source.time + ).sendAndExpect() + } + OfflineMessageSource.Kind.GROUP -> { + PbMessageSvc.PbMsgWithDraw.createForGroupMessage( + bot.client, + source.targetId, + source.sequenceId, + source.id + ).sendAndExpect() + } + } + } else -> error("stub!") } // 1001: No message meets the requirements (实际上是没权限, 管理员在尝试撤回群主的消息) + // 154: timeout + // 3: check(response is PbMessageSvc.PbMsgWithDraw.Response.Success) { "Failed to recall message #${source.id}: $response" } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt index 4bd291661..bef3dcb51 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt @@ -70,6 +70,7 @@ internal class QQImpl( override val id: Long, private val friendInfo: FriendInfo ) : QQ() { + @Suppress("unused") // bug val lastMessageSequence: AtomicInt = atomic(-1) override val bot: QQAndroidBot by bot.unsafeWeakRef() diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceImpl.kt index b7af335ae..95a2298b8 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceImpl.kt @@ -60,7 +60,7 @@ internal class MessageSourceFromFriendImpl( } override val id: Int get() = msg.msgBody.richText.attr!!.random override val time: Int get() = msg.msgHead.msgTime - override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, isGroup = false, addSource = false) } + override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, groupIdOrZero = 0, addSource = false) } override val target: Bot get() = bot override val sender: QQ get() = bot.getFriend(msg.msgHead.fromUin) @@ -117,7 +117,13 @@ internal class MessageSourceFromGroupImpl( override val sequenceId: Int get() = msg.msgHead.msgSeq override val id: Int get() = msg.msgBody.richText.attr!!.random override val time: Int get() = msg.msgHead.msgTime - override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, isGroup = true, addSource = false) } + override val originalMessage: MessageChain by lazy { + msg.toMessageChain( + bot, + groupIdOrZero = group.id, + addSource = false + ) + } override val target: Bot get() = bot override val sender: Member get() = bot.getGroup( @@ -143,12 +149,11 @@ internal class MessageSourceFromGroupImpl( } internal class OfflineMessageSourceImpl( // from others' quotation - val delegate: ImMsgBody.SourceMsg, override val bot: Bot + val delegate: ImMsgBody.SourceMsg, + override val bot: Bot, + groupIdOrZero: Long ) : OfflineMessageSource(), MessageSourceImpl { - - init { - println(delegate._miraiContentToString()) - } + override val kind: Kind get() = if (delegate.srcMsg == null) Kind.GROUP else Kind.FRIEND private val isRecalled: AtomicBoolean = atomic(false) override var isRecalledOrPlanned: Boolean @@ -159,7 +164,7 @@ internal class OfflineMessageSourceImpl( // from others' quotation override val sequenceId: Int get() = delegate.origSeqs?.first() ?: error("cannot find sequenceId") override val time: Int get() = delegate.time - override val originalMessage: MessageChain by lazy { delegate.toMessageChain(bot) } + override val originalMessage: MessageChain by lazy { delegate.toMessageChain(bot, groupIdOrZero, false) } /* override val id: Long get() = (delegate.origSeqs?.firstOrNull() @@ -172,7 +177,21 @@ internal class OfflineMessageSourceImpl( // from others' quotation // override val sourceMessage: MessageChain get() = delegate.toMessageChain() override val fromId: Long get() = delegate.senderUin - override val targetId: Long get() = Group.calculateGroupCodeByGroupUin(delegate.toUin) + override val targetId: Long by lazy { + when { + groupIdOrZero != 0L -> groupIdOrZero + delegate.toUin != 0L -> delegate.toUin + delegate.srcMsg != null -> delegate.srcMsg.loadAs(MsgComm.Msg.serializer()).msgHead.toUin + else -> 0/*error("cannot find targetId. delegate=${delegate._miraiContentToString()}, delegate.srcMsg=${ + kotlin.runCatching { delegate.srcMsg?.loadAs(MsgComm.Msg.serializer())?._miraiContentToString() } + .fold( + onFailure = { "" }, + onSuccess = { it } + ) + }" + )*/ + } + } } internal class MessageSourceToFriendImpl( diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt index b56bf8f21..4f40ca22f 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/convension.kt @@ -179,30 +179,32 @@ private val PB_RESERVE_FOR_DOUTU = "78 00 90 01 01 F8 01 00 A0 02 00 C8 02 00".h private val PB_RESERVE_FOR_ELSE = "78 00 F8 01 00 C8 02 00".hexToBytes() @OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) -internal fun MsgComm.Msg.toMessageChain(bot: Bot, isGroup: Boolean, addSource: Boolean): MessageChain { +internal fun MsgComm.Msg.toMessageChain(bot: Bot, groupIdOrZero: Long, addSource: Boolean): MessageChain { val elements = this.msgBody.richText.elems return buildMessageChain(elements.size + 1) { if (addSource) { - if (isGroup) { + if (groupIdOrZero != 0L) { +MessageSourceFromGroupImpl(bot, this@toMessageChain) } else { +MessageSourceFromFriendImpl(bot, this@toMessageChain) } } - elements.joinToMessageChain(bot, this) + elements.joinToMessageChain(groupIdOrZero, bot, this) }.cleanupRubbishMessageElements() } // These two functions have difference method signature, don't combine. @OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) -internal fun ImMsgBody.SourceMsg.toMessageChain(bot: Bot): MessageChain { +internal fun ImMsgBody.SourceMsg.toMessageChain(bot: Bot, groupIdOrZero: Long, withSource: Boolean): MessageChain { val elements = this.elems!! return buildMessageChain(elements.size + 1) { - +OfflineMessageSourceImpl(delegate = this@toMessageChain, bot = bot) - elements.joinToMessageChain(bot, this) + if (withSource) { + +OfflineMessageSourceImpl(delegate = this@toMessageChain, bot = bot, groupIdOrZero = groupIdOrZero) + } + elements.joinToMessageChain(groupIdOrZero, bot, this) }.cleanupRubbishMessageElements() } @@ -254,11 +256,11 @@ internal inline fun Iterable<*>.firstIsInstanceOrNull(): R? { } @OptIn(MiraiInternalAPI::class, LowLevelAPI::class) -internal fun List.joinToMessageChain(bot: Bot, message: MessageChainBuilder) { +internal fun List.joinToMessageChain(groupIdOrZero: Long, bot: Bot, message: MessageChainBuilder) { // (this._miraiContentToString()) this.forEach { when { - it.srcMsg != null -> message.add(QuoteReply(OfflineMessageSourceImpl(it.srcMsg, bot))) + it.srcMsg != null -> message.add(QuoteReply(OfflineMessageSourceImpl(it.srcMsg, bot, groupIdOrZero))) it.notOnlineImage != null -> message.add(OnlineFriendImageImpl(it.notOnlineImage)) it.customFace != null -> message.add(OnlineGroupImageImpl(it.customFace)) it.face != null -> message.add(Face(it.face.index)) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Msg.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Msg.kt index d6bc309d9..fcd9cc213 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Msg.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Msg.kt @@ -885,7 +885,7 @@ internal class ImMsgBody : ProtoBuf { @ProtoId(6) val type: Int = 0, @ProtoId(7) val richMsg: ByteArray = EMPTY_BYTE_ARRAY, @ProtoId(8) val pbReserve: ByteArray = EMPTY_BYTE_ARRAY, - @ProtoId(9) val srcMsg: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoId(9) val srcMsg: ByteArray? = null, @ProtoId(10) val toUin: Long = 0L, @ProtoId(11) val troopName: ByteArray = EMPTY_BYTE_ARRAY ) : ProtoBuf diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt index 8e49131c1..77ca9230b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/PbMessageSvc.kt @@ -80,7 +80,6 @@ internal class PbMessageSvc { messageRandom: Int, // 921878719 time: Int ): OutgoingPacket = buildOutgoingUniPacket(client) { - val messageUid: Long = 262144L.shl(32) or messageRandom.toLong().and(0xffFFffFF) writeProtoBuf( MsgSvc.PbMsgWithDrawReq.serializer(), MsgSvc.PbMsgWithDrawReq( @@ -92,8 +91,8 @@ internal class PbMessageSvc { fromUin = client.bot.id, toUin = toUin, msgSeq = messageSequenceId, - msgUid = messageUid, - msgTime = time.toULong().toLong(), + msgUid = 1000000000000000000L or messageRandom.toULong().toLong(), + msgTime = time.toLong(), routingHead = MsgSvc.RoutingHead( c2c = MsgSvc.C2C( toUin = toUin diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 557d8ebb7..dc0723269 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -229,7 +229,7 @@ internal class MessageSvc { if (friend.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) { return@mapNotNull FriendMessage( friend, - msg.toMessageChain(bot, isGroup = false, addSource = true) + msg.toMessageChain(bot, groupIdOrZero = 0, addSource = true) ) } } else return@mapNotNull null diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index aac11828d..5567a9472 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -84,7 +84,7 @@ internal class OnlinePush { return GroupMessage( senderName = pbPushMsg.msg.msgHead.groupInfo.groupCard, sender = group[pbPushMsg.msg.msgHead.fromUin], - message = pbPushMsg.msg.toMessageChain(bot, isGroup = true, addSource = true), + message = pbPushMsg.msg.toMessageChain(bot, groupIdOrZero = group.id, addSource = true), permission = when { flags and 16 != 0 -> MemberPermission.ADMINISTRATOR flags and 8 != 0 -> MemberPermission.OWNER diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt index be526522d..dd41fa108 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt @@ -180,7 +180,7 @@ sealed class OnlineMessageSource : MessageSource() { /** * 引用这条消息 */ -fun OnlineMessageSource.quote(): QuoteReply { +fun MessageSource.quote(): QuoteReply { @OptIn(MiraiInternalAPI::class) return QuoteReply(this) } @@ -213,8 +213,19 @@ inline fun MessageSource.recallIn( @SinceMirai("0.33.0") abstract class OfflineMessageSource : MessageSource() { companion object Key : Message.Key + + enum class Kind { + GROUP, + FRIEND + } + + /** + * 消息种类 + */ + abstract val kind: Kind + // final override fun toString(): String = "OfflineMessageSource(sender=$senderId, target=$targetId)" -} // TODO: 2020/4/4 可能要分群和好友 +} // For MessageChain diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt index 3f7394a0a..d930ab2b0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt @@ -31,11 +31,11 @@ import kotlin.jvm.JvmName * @see MessageSource 获取更多信息 */ @SinceMirai("0.33.0") -class QuoteReply(val source: OnlineMessageSource) : Message, MessageMetadata { +class QuoteReply(val source: MessageSource) : Message, MessageMetadata { // TODO: 2020/4/4 Metadata or Content? companion object Key : Message.Key - override fun toString(): String = "[mirai:quote]" + override fun toString(): String = "[mirai:quote:${source.id}]" } suspend inline fun QuoteReply.recall() = this.source.recall()