mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-24 15:00:38 +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>()
|
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is OfflineMessageSource,
|
|
||||||
is MessageSourceFromFriendImpl,
|
is MessageSourceFromFriendImpl,
|
||||||
is MessageSourceToFriendImpl
|
is MessageSourceToFriendImpl
|
||||||
-> network.run {
|
-> network.run {
|
||||||
|
check(source.fromId == this@QQAndroidBotBase.id) {
|
||||||
|
"can only recall a message sent by bot"
|
||||||
|
}
|
||||||
PbMessageSvc.PbMsgWithDraw.createForFriendMessage(
|
PbMessageSvc.PbMsgWithDraw.createForFriendMessage(
|
||||||
bot.client,
|
bot.client,
|
||||||
source.fromId,
|
source.targetId,
|
||||||
source.sequenceId,
|
source.sequenceId,
|
||||||
source.id,
|
source.id,
|
||||||
source.time
|
source.time
|
||||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
).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!")
|
else -> error("stub!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 1001: No message meets the requirements (实际上是没权限, 管理员在尝试撤回群主的消息)
|
// 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" }
|
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,
|
override val id: Long,
|
||||||
private val friendInfo: FriendInfo
|
private val friendInfo: FriendInfo
|
||||||
) : QQ() {
|
) : QQ() {
|
||||||
|
@Suppress("unused") // bug
|
||||||
val lastMessageSequence: AtomicInt = atomic(-1)
|
val lastMessageSequence: AtomicInt = atomic(-1)
|
||||||
|
|
||||||
override val bot: QQAndroidBot by bot.unsafeWeakRef()
|
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 id: Int get() = msg.msgBody.richText.attr!!.random
|
||||||
override val time: Int get() = msg.msgHead.msgTime
|
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 target: Bot get() = bot
|
||||||
override val sender: QQ get() = bot.getFriend(msg.msgHead.fromUin)
|
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 sequenceId: Int get() = msg.msgHead.msgSeq
|
||||||
override val id: Int get() = msg.msgBody.richText.attr!!.random
|
override val id: Int get() = msg.msgBody.richText.attr!!.random
|
||||||
override val time: Int get() = msg.msgHead.msgTime
|
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 target: Bot get() = bot
|
||||||
override val sender: Member
|
override val sender: Member
|
||||||
get() = bot.getGroup(
|
get() = bot.getGroup(
|
||||||
@ -143,12 +149,11 @@ internal class MessageSourceFromGroupImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class OfflineMessageSourceImpl( // from others' quotation
|
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 {
|
) : OfflineMessageSource(), MessageSourceImpl {
|
||||||
|
override val kind: Kind get() = if (delegate.srcMsg == null) Kind.GROUP else Kind.FRIEND
|
||||||
init {
|
|
||||||
println(delegate._miraiContentToString())
|
|
||||||
}
|
|
||||||
|
|
||||||
private val isRecalled: AtomicBoolean = atomic(false)
|
private val isRecalled: AtomicBoolean = atomic(false)
|
||||||
override var isRecalledOrPlanned: Boolean
|
override var isRecalledOrPlanned: Boolean
|
||||||
@ -159,7 +164,7 @@ internal class OfflineMessageSourceImpl( // from others' quotation
|
|||||||
override val sequenceId: Int
|
override val sequenceId: Int
|
||||||
get() = delegate.origSeqs?.first() ?: error("cannot find sequenceId")
|
get() = delegate.origSeqs?.first() ?: error("cannot find sequenceId")
|
||||||
override val time: Int get() = delegate.time
|
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
|
override val id: Long
|
||||||
get() = (delegate.origSeqs?.firstOrNull()
|
get() = (delegate.origSeqs?.firstOrNull()
|
||||||
@ -172,7 +177,21 @@ internal class OfflineMessageSourceImpl( // from others' quotation
|
|||||||
|
|
||||||
// override val sourceMessage: MessageChain get() = delegate.toMessageChain()
|
// override val sourceMessage: MessageChain get() = delegate.toMessageChain()
|
||||||
override val fromId: Long get() = delegate.senderUin
|
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(
|
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()
|
private val PB_RESERVE_FOR_ELSE = "78 00 F8 01 00 C8 02 00".hexToBytes()
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
|
@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
|
val elements = this.msgBody.richText.elems
|
||||||
|
|
||||||
return buildMessageChain(elements.size + 1) {
|
return buildMessageChain(elements.size + 1) {
|
||||||
if (addSource) {
|
if (addSource) {
|
||||||
if (isGroup) {
|
if (groupIdOrZero != 0L) {
|
||||||
+MessageSourceFromGroupImpl(bot, this@toMessageChain)
|
+MessageSourceFromGroupImpl(bot, this@toMessageChain)
|
||||||
} else {
|
} else {
|
||||||
+MessageSourceFromFriendImpl(bot, this@toMessageChain)
|
+MessageSourceFromFriendImpl(bot, this@toMessageChain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elements.joinToMessageChain(bot, this)
|
elements.joinToMessageChain(groupIdOrZero, bot, this)
|
||||||
}.cleanupRubbishMessageElements()
|
}.cleanupRubbishMessageElements()
|
||||||
}
|
}
|
||||||
|
|
||||||
// These two functions have difference method signature, don't combine.
|
// These two functions have difference method signature, don't combine.
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
|
@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!!
|
val elements = this.elems!!
|
||||||
|
|
||||||
return buildMessageChain(elements.size + 1) {
|
return buildMessageChain(elements.size + 1) {
|
||||||
+OfflineMessageSourceImpl(delegate = this@toMessageChain, bot = bot)
|
if (withSource) {
|
||||||
elements.joinToMessageChain(bot, this)
|
+OfflineMessageSourceImpl(delegate = this@toMessageChain, bot = bot, groupIdOrZero = groupIdOrZero)
|
||||||
|
}
|
||||||
|
elements.joinToMessageChain(groupIdOrZero, bot, this)
|
||||||
}.cleanupRubbishMessageElements()
|
}.cleanupRubbishMessageElements()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,11 +256,11 @@ internal inline fun <reified R> Iterable<*>.firstIsInstanceOrNull(): R? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(MiraiInternalAPI::class, LowLevelAPI::class)
|
@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._miraiContentToString())
|
||||||
this.forEach {
|
this.forEach {
|
||||||
when {
|
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.notOnlineImage != null -> message.add(OnlineFriendImageImpl(it.notOnlineImage))
|
||||||
it.customFace != null -> message.add(OnlineGroupImageImpl(it.customFace))
|
it.customFace != null -> message.add(OnlineGroupImageImpl(it.customFace))
|
||||||
it.face != null -> message.add(Face(it.face.index))
|
it.face != null -> message.add(Face(it.face.index))
|
||||||
|
@ -885,7 +885,7 @@ internal class ImMsgBody : ProtoBuf {
|
|||||||
@ProtoId(6) val type: Int = 0,
|
@ProtoId(6) val type: Int = 0,
|
||||||
@ProtoId(7) val richMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
@ProtoId(7) val richMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||||
@ProtoId(8) val pbReserve: 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(10) val toUin: Long = 0L,
|
||||||
@ProtoId(11) val troopName: ByteArray = EMPTY_BYTE_ARRAY
|
@ProtoId(11) val troopName: ByteArray = EMPTY_BYTE_ARRAY
|
||||||
) : ProtoBuf
|
) : ProtoBuf
|
||||||
|
@ -80,7 +80,6 @@ internal class PbMessageSvc {
|
|||||||
messageRandom: Int, // 921878719
|
messageRandom: Int, // 921878719
|
||||||
time: Int
|
time: Int
|
||||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||||
val messageUid: Long = 262144L.shl(32) or messageRandom.toLong().and(0xffFFffFF)
|
|
||||||
writeProtoBuf(
|
writeProtoBuf(
|
||||||
MsgSvc.PbMsgWithDrawReq.serializer(),
|
MsgSvc.PbMsgWithDrawReq.serializer(),
|
||||||
MsgSvc.PbMsgWithDrawReq(
|
MsgSvc.PbMsgWithDrawReq(
|
||||||
@ -92,8 +91,8 @@ internal class PbMessageSvc {
|
|||||||
fromUin = client.bot.id,
|
fromUin = client.bot.id,
|
||||||
toUin = toUin,
|
toUin = toUin,
|
||||||
msgSeq = messageSequenceId,
|
msgSeq = messageSequenceId,
|
||||||
msgUid = messageUid,
|
msgUid = 1000000000000000000L or messageRandom.toULong().toLong(),
|
||||||
msgTime = time.toULong().toLong(),
|
msgTime = time.toLong(),
|
||||||
routingHead = MsgSvc.RoutingHead(
|
routingHead = MsgSvc.RoutingHead(
|
||||||
c2c = MsgSvc.C2C(
|
c2c = MsgSvc.C2C(
|
||||||
toUin = toUin
|
toUin = toUin
|
||||||
|
@ -229,7 +229,7 @@ internal class MessageSvc {
|
|||||||
if (friend.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) {
|
if (friend.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) {
|
||||||
return@mapNotNull FriendMessage(
|
return@mapNotNull FriendMessage(
|
||||||
friend,
|
friend,
|
||||||
msg.toMessageChain(bot, isGroup = false, addSource = true)
|
msg.toMessageChain(bot, groupIdOrZero = 0, addSource = true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else return@mapNotNull null
|
} else return@mapNotNull null
|
||||||
|
@ -84,7 +84,7 @@ internal class OnlinePush {
|
|||||||
return GroupMessage(
|
return GroupMessage(
|
||||||
senderName = pbPushMsg.msg.msgHead.groupInfo.groupCard,
|
senderName = pbPushMsg.msg.msgHead.groupInfo.groupCard,
|
||||||
sender = group[pbPushMsg.msg.msgHead.fromUin],
|
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 {
|
permission = when {
|
||||||
flags and 16 != 0 -> MemberPermission.ADMINISTRATOR
|
flags and 16 != 0 -> MemberPermission.ADMINISTRATOR
|
||||||
flags and 8 != 0 -> MemberPermission.OWNER
|
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)
|
@OptIn(MiraiInternalAPI::class)
|
||||||
return QuoteReply(this)
|
return QuoteReply(this)
|
||||||
}
|
}
|
||||||
@ -213,8 +213,19 @@ inline fun MessageSource.recallIn(
|
|||||||
@SinceMirai("0.33.0")
|
@SinceMirai("0.33.0")
|
||||||
abstract class OfflineMessageSource : MessageSource() {
|
abstract class OfflineMessageSource : MessageSource() {
|
||||||
companion object Key : Message.Key<OfflineMessageSource>
|
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)"
|
// final override fun toString(): String = "OfflineMessageSource(sender=$senderId, target=$targetId)"
|
||||||
} // TODO: 2020/4/4 可能要分群和好友
|
}
|
||||||
|
|
||||||
// For MessageChain
|
// For MessageChain
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@ import kotlin.jvm.JvmName
|
|||||||
* @see MessageSource 获取更多信息
|
* @see MessageSource 获取更多信息
|
||||||
*/
|
*/
|
||||||
@SinceMirai("0.33.0")
|
@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?
|
// TODO: 2020/4/4 Metadata or Content?
|
||||||
companion object Key : Message.Key<QuoteReply>
|
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()
|
suspend inline fun QuoteReply.recall() = this.source.recall()
|
||||||
|
Loading…
Reference in New Issue
Block a user