mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-08 09:10:11 +08:00
Fix #180
This commit is contained in:
parent
19bc7b80c5
commit
864cde060e
@ -216,23 +216,51 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
}
|
||||
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<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
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<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
OfflineMessageSource.Kind.GROUP -> {
|
||||
PbMessageSvc.PbMsgWithDraw.createForGroupMessage(
|
||||
bot.client,
|
||||
source.targetId,
|
||||
source.sequenceId,
|
||||
source.id
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> error("stub!")
|
||||
}
|
||||
|
||||
|
||||
// 1001: No message meets the requirements (实际上是没权限, 管理员在尝试撤回群主的消息)
|
||||
// 154: timeout
|
||||
// 3: <no message>
|
||||
check(response is PbMessageSvc.PbMsgWithDraw.Response.Success) { "Failed to recall message #${source.id}: $response" }
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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 = { "<error: ${it.message}>" },
|
||||
onSuccess = { it }
|
||||
)
|
||||
}"
|
||||
)*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class MessageSourceToFriendImpl(
|
||||
|
@ -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 <reified R> Iterable<*>.firstIsInstanceOrNull(): R? {
|
||||
}
|
||||
|
||||
@OptIn(MiraiInternalAPI::class, LowLevelAPI::class)
|
||||
internal fun List<ImMsgBody.Elem>.joinToMessageChain(bot: Bot, message: MessageChainBuilder) {
|
||||
internal fun List<ImMsgBody.Elem>.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))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<OfflineMessageSource>
|
||||
|
||||
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
|
||||
|
||||
|
@ -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<QuoteReply>
|
||||
|
||||
override fun toString(): String = "[mirai:quote]"
|
||||
override fun toString(): String = "[mirai:quote:${source.id}]"
|
||||
}
|
||||
|
||||
suspend inline fun QuoteReply.recall() = this.source.recall()
|
||||
|
Loading…
Reference in New Issue
Block a user