diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/message.kt b/mirai-core-api/src/commonMain/kotlin/event/events/message.kt index b456bb729..1a510b69a 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/message.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/message.kt @@ -479,6 +479,32 @@ public class FriendMessageEvent constructor( public override fun toString(): String = "FriendMessageEvent(sender=${sender.id}, message=$message)" } +/** + * 机器人收到的好友消息的事件 + * + * @see MessageEvent + */ +public class OtherClientMessageEvent constructor( + public override val client: OtherClient, + public override val message: MessageChain, + public override val time: Int +) : AbstractMessageEvent(), MessageEvent, MessageEventExtensions, BroadcastControllable, + OtherClientEvent { + init { + val source = + message[MessageSource] ?: throw IllegalArgumentException("Cannot find MessageSource from message") + check(source is OnlineMessageSource.Incoming.FromFriend) { "source provided to a FriendMessage must be an instance of OnlineMessageSource.Incoming.FromFriend" } + } + + public override val sender: User = client.bot.asFriend // TODO 临时使用 + public override val bot: Bot get() = super.bot + public override val subject: User get() = sender + public override val senderName: String get() = sender.nick + public override val source: OnlineMessageSource.Incoming.FromFriend get() = message.source as OnlineMessageSource.Incoming.FromFriend + + public override fun toString(): String = "OtherClientMessageEvent(client=${client.kind}, message=$message)" +} + /** * 来自一个可以知道其 [Group] 的用户消息 * diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index 6d8d2383f..c6a13908d 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -27,6 +27,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.chat.* import net.mamoe.mirai.message.data.* import net.mamoe.mirai.network.LoginFailedException import net.mamoe.mirai.utils.* +import network.protocol.data.jce.InstanceInfo import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import net.mamoe.mirai.internal.network.protocol.data.jce.FriendInfo as JceFriendInfo @@ -40,9 +41,10 @@ internal fun Bot.asQQAndroidBot(): QQAndroidBot { } internal fun QQAndroidBot.createOtherClient( - kind: ClientKind + kind: ClientKind, + instanceInfo: InstanceInfo, ): OtherClientImpl { - return OtherClientImpl(this, coroutineContext, kind) + return OtherClientImpl(this, coroutineContext, kind, instanceInfo) } @Suppress("INVISIBLE_MEMBER", "BooleanLiteralArgument", "OverridingDeprecatedMember") diff --git a/mirai-core/src/commonMain/kotlin/contact/OtherClientImpl.kt b/mirai-core/src/commonMain/kotlin/contact/OtherClientImpl.kt index 1408623cb..3a9efcb51 100644 --- a/mirai-core/src/commonMain/kotlin/contact/OtherClientImpl.kt +++ b/mirai-core/src/commonMain/kotlin/contact/OtherClientImpl.kt @@ -17,12 +17,17 @@ import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.utils.ExternalImage +import net.mamoe.mirai.utils.cast +import network.protocol.data.jce.InstanceInfo import kotlin.coroutines.CoroutineContext +internal val OtherClient.instanceInfo: InstanceInfo get() = this.cast().instanceInfo + internal class OtherClientImpl( bot: Bot, coroutineContext: CoroutineContext, - override val kind: ClientKind + override val kind: ClientKind, + val instanceInfo: InstanceInfo ) : OtherClient, AbstractContact(bot, coroutineContext) { override suspend fun sendMessage(message: Message): MessageReceipt { TODO("Not yet implemented") @@ -35,4 +40,39 @@ internal class OtherClientImpl( override fun toString(): String { return "OtherClient(bot=${bot.id},kind=$kind)" } -} \ No newline at end of file +} + +/* +contentHead=ContentHead#522561765 { +} +msgBody=MsgBody#-1622349855 { + msgContent=08 04 12 1E 08 E9 07 10 B7 F7 8B 80 02 18 E9 07 20 00 28 DD F1 92 B7 07 30 DD F1 92 B7 07 48 02 50 03 32 1E 08 88 80 F8 92 CD 84 80 80 10 10 01 18 00 20 01 2A 0C 0A 0A 08 01 12 06 E5 95 8A E5 95 8A + richText=RichText#-184909407 { + elems=[] + } +} +msgHead=MsgHead#1128220129 { + authUin=0x0000000000000000(0) + c2cCmd=0x00000007(7) + cpid=0x0000000000000000(0) + fromUin=0x0000000076E4B8DD(1994701021) + isSrcMsg=false + msgInstCtrl=InstCtrl#1220180502 { + msgExcludeInst=[] + msgFromInst=InstInfo#-1165404375 { + apppid=0x000003E9(1001) + enumDeviceType=0x00000002(2) + instid=0x2002FBB7(537066423) + } + msgSendToInst=[InstInfo#-1165404375 { + apppid=0x000003E9(1001) + enumDeviceType=0x00000003(3) + }] + } + msgSeq=0x000073C8(29640) + msgTime=0x5FE34926(1608730918) + msgType=0x00000211(529) + msgUid=0x0100000076360F0E(72057596021182222) + toUin=0x0000000076E4B8DD(1994701021) +} + */ \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/contact/util.kt b/mirai-core/src/commonMain/kotlin/contact/util.kt index 717310e49..d34b31a31 100644 --- a/mirai-core/src/commonMain/kotlin/contact/util.kt +++ b/mirai-core/src/commonMain/kotlin/contact/util.kt @@ -108,6 +108,9 @@ internal fun net.mamoe.mirai.event.events.MessageEvent.logMessageReceived() { is net.mamoe.mirai.event.events.FriendMessageEvent -> bot.logger.verbose { "${sender.nick}(${sender.id}) -> $message".replaceMagicCodes() } + is net.mamoe.mirai.event.events.OtherClientMessageEvent -> bot.logger.verbose { + "${client.kind}(${sender.id}) -> $message".replaceMagicCodes() + } } } diff --git a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt index 4143cef2c..d238bc506 100644 --- a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt +++ b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt @@ -71,7 +71,10 @@ internal class MessageSourceFromFriendImpl( override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq } override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random - override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random } + override val internalIds: IntArray + get() = msg.mapToIntArray { + it.msgBody.richText.attr?.random ?: 0 + } // other client 消息的这个是0 override val time: Int get() = msg.first().msgHead.msgTime override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, bot.id, 0, false) } override val sender: Friend get() = bot.getFriendOrFail(msg.first().msgHead.fromUin) @@ -82,7 +85,7 @@ internal class MessageSourceFromFriendImpl( } private fun List.toJceDataFriendOrTemp(ids: IntArray): ImMsgBody.SourceMsg { - val elements = flatMap {it.msgBody.richText.elems}.toMutableList().also { + val elements = flatMap { it.msgBody.richText.elems }.toMutableList().also { if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2())) } return ImMsgBody.SourceMsg( @@ -90,7 +93,7 @@ private fun List.toJceDataFriendOrTemp(ids: IntArray): ImMsgBody.So senderUin = first().msgHead.fromUin, toUin = first().msgHead.toUin, flag = 1, - elems = flatMap{it.msgBody.richText.elems}, + elems = flatMap { it.msgBody.richText.elems }, type = 0, time = this.first().msgHead.msgTime, pbReserve = SourceMsg.ResvAttr( @@ -122,7 +125,7 @@ internal class MessageSourceFromTempImpl( private val msg: List ) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceInternal { override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq } - override val internalIds: IntArray get() = msg.mapToIntArray{it.msgBody.richText.attr!!.random } + override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random } override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override val ids: IntArray get() = sequenceIds// override val time: Int get() = msg.first().msgHead.msgTime @@ -150,7 +153,7 @@ internal data class MessageSourceFromGroupImpl( ) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal { override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq } - override val internalIds: IntArray get() = msg.mapToIntArray{ it.msgBody.richText.attr!!.random } + override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random } override val ids: IntArray get() = sequenceIds override val time: Int get() = msg.first().msgHead.msgTime override val originalMessage: MessageChain by lazy { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/PushNotifyPack.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/PushNotifyPack.kt index a29a78621..e77fb8c1c 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/PushNotifyPack.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/PushNotifyPack.kt @@ -14,7 +14,6 @@ import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.internal.utils.io.JceStruct import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId -import kotlin.jvm.JvmField @Suppress("ArrayInDataClass") @Serializable @@ -33,7 +32,11 @@ internal class RequestPushNotify( @TarsId(11) @JvmField val serverBuf: ByteArray?, @TarsId(12) @JvmField val pingFlag: Long?, @TarsId(13) @JvmField val svrip: Int? -) : JceStruct, Packet +) : JceStruct, Packet { + override fun toString(): String { + return "RequestPushNotify(uin=$uin, ctype=$ctype, strService=$strService, strCmd=$strCmd, usMsgType=$usMsgType, stMsgInfo=$stMsgInfo)" + } +} @Serializable internal class MsgInfo( diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/HummerResv21.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/HummerResv21.kt new file mode 100644 index 000000000..9559200c4 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/HummerResv21.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2019-2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("unused", "SpellCheckingInspection") + +package net.mamoe.mirai.internal.network.protocol.data.proto + +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoNumber +import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY +import net.mamoe.mirai.internal.utils.io.ProtoBuf + +@Serializable +internal class HummerResv21 : ProtoBuf { + @Serializable + internal class FileImgInfo( + @JvmField @ProtoNumber(1) val fileWidth: Int = 0, + @JvmField @ProtoNumber(2) val fileHeight: Int = 0 + ) : ProtoBuf + + @Serializable + internal class ForwardExtFileInfo( + @JvmField @ProtoNumber(1) val fileType: Int = 0, + @JvmField @ProtoNumber(2) val senderUin: Long = 0L, + @JvmField @ProtoNumber(3) val receiverUin: Long = 0L, + @JvmField @ProtoNumber(4) val fileUuid: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(5) val fileName: String = "", + @JvmField @ProtoNumber(6) val fileSize: Long = 0L, + @JvmField @ProtoNumber(7) val fileSha1: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(8) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(9) val int64DeadTime: Long = 0L, + @JvmField @ProtoNumber(10) val imgWidth: Int = 0, + @JvmField @ProtoNumber(11) val imgHeight: Int = 0, + @JvmField @ProtoNumber(12) val videoDuration: Long = 0L, + @JvmField @ProtoNumber(13) val busId: Int = 0 + ) : ProtoBuf + + @Serializable + internal class ResvAttr( + @JvmField @ProtoNumber(1) val fileImageInfo: FileImgInfo? = null, + @JvmField @ProtoNumber(2) val forwardExtFileInfo: ForwardExtFileInfo? = null + ) : ProtoBuf + + @Serializable + internal class XtfSenderInfo( + @JvmField @ProtoNumber(1) val lanIp: Int = 0, + @JvmField @ProtoNumber(2) val lanPort: Int = 0, + @JvmField @ProtoNumber(3) val lanSrkey: Long = 0L + ) : ProtoBuf +} + \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/msgType0x211.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/msgType0x211.kt new file mode 100644 index 000000000..7623c0fc0 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/msgType0x211.kt @@ -0,0 +1,573 @@ +/* + * Copyright 2019-2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("unused", "SpellCheckingInspection") + +package net.mamoe.mirai.internal.network.protocol.data.proto + +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoIntegerType +import kotlinx.serialization.protobuf.ProtoNumber +import kotlinx.serialization.protobuf.ProtoType +import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY +import net.mamoe.mirai.internal.utils.io.ProtoBuf + + +@Serializable +internal class SubMsgType0x3 : ProtoBuf { + @Serializable + internal class FailNotify( + @JvmField @ProtoNumber(1) val sessionid: Int = 0, + @JvmField @ProtoNumber(2) val retCode: Int = 0, + @JvmField @ProtoNumber(3) val reason: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class MsgBody( + @JvmField @ProtoNumber(1) val msgProgressNotify: ProgressNotify? = null, + @JvmField @ProtoNumber(2) val msgFailNotify: FailNotify? = null + ) : ProtoBuf + + @Serializable + internal class ProgressNotify( + @JvmField @ProtoNumber(1) val sessionid: Int = 0, + @JvmField @ProtoNumber(2) val uuid: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(3) val progress: Int = 0, + @JvmField @ProtoNumber(4) val averageSpeed: Int = 0 + ) : ProtoBuf +} + + +@Serializable +internal class SubMsgType0x4 : ProtoBuf { + @Serializable + internal class MsgBody( + @JvmField @ProtoNumber(1) val msgNotOnlineFile: ImMsgBody.NotOnlineFile? = null, + @JvmField @ProtoNumber(2) val msgTime: Int = 0, + @JvmField @ProtoNumber(3) val onlineFileForPolyToOffline: Int = 0, + @JvmField @ProtoNumber(4) val fileImageInfo: HummerResv21.FileImgInfo? = null, + @JvmField @ProtoNumber(5) val msgXtfSenderInfo: HummerResv21.XtfSenderInfo? = null, + @JvmField @ProtoNumber(6) val resvAttr: HummerResv21.ResvAttr? = null + ) : ProtoBuf +} + + +@Serializable +internal class SubMsgType0x5 : ProtoBuf { + @Serializable + internal class MsgBody( + @JvmField @ProtoNumber(1) val sessionid: Int = 0 + ) : ProtoBuf +} + + +@Serializable +internal class SubMsgType0x7 : ProtoBuf { + @Serializable + internal class MsgBody( + @JvmField @ProtoNumber(1) val subCmd: Int = 0, + @JvmField @ProtoNumber(2) val msgHeader: MsgHeader? = null, + @JvmField @ProtoNumber(3) val msgSubcmd0x1FtnNotify: List = emptyList(), + @JvmField @ProtoNumber(4) val msgSubcmd0x2NfcNotify: List = emptyList(), + @JvmField @ProtoNumber(5) val msgSubcmd0x3Filecontrol: List = emptyList(), + @JvmField @ProtoNumber(6) val msgSubcmd0x4Generic: GenericSubCmd? = null, + @JvmField @ProtoNumber(7) val msgSubcmd0x5MoloNotify: List = emptyList(), + @JvmField @ProtoNumber(8) val msgSubcmd0x8RnfcNotify: List = emptyList(), + @JvmField @ProtoNumber(9) val msgSubcmd0x9FtnThumbNotify: List = emptyList(), + @JvmField @ProtoNumber(10) val msgSubcmd0xaNfcThumbNotify: List = emptyList(), + @JvmField @ProtoNumber(11) val msgSubcmd0xbMpfileNotify: List = emptyList(), + @JvmField @ProtoNumber(12) val msgSubcmd0xcProgressReq: ProgressReq? = null, + @JvmField @ProtoNumber(13) val msgSubcmd0xdProgressRsp: ProgressRsp? = null + ) : ProtoBuf { + @Serializable + internal class ActionInfo( + @JvmField @ProtoNumber(1) val serviceName: String = "", + @JvmField @ProtoNumber(2) val buf: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class FileControl( + @JvmField @ProtoNumber(1) val sessionid: Long = 0L, + @JvmField @ProtoNumber(2) val operate: Int = 0, + @JvmField @ProtoNumber(3) val seq: Int = 0, + @JvmField @ProtoNumber(4) val code: Int = 0, + @JvmField @ProtoNumber(5) val msg: String = "", + @JvmField @ProtoNumber(6) val groupId: Int = 0, + @JvmField @ProtoNumber(7) val groupCurindex: Int = 0, + @JvmField @ProtoNumber(8) val batchID: Int = 0 + ) : ProtoBuf + + @Serializable + internal class FTNNotify( + @JvmField @ProtoNumber(1) val sessionid: Long = 0L, + @JvmField @ProtoNumber(2) val fileName: String = "", + @JvmField @ProtoNumber(3) val fileIndex: String = "", + @JvmField @ProtoNumber(4) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(5) val fileKey: String = "", + @JvmField @ProtoNumber(6) val fileLen: Long = 0L, + @JvmField @ProtoNumber(7) val originfileMd5: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(8) val originfiletype: Int = 0, + @JvmField @ProtoNumber(9) val groupId: Int = 0, + @JvmField @ProtoNumber(10) val groupSize: Int = 0, + @JvmField @ProtoNumber(11) val groupCurindex: Int = 0, + @JvmField @ProtoNumber(20) val msgActionInfo: ActionInfo? = null, + @JvmField @ProtoNumber(21) val batchID: Int = 0, + @JvmField @ProtoNumber(22) val groupflag: Int = 0 + ) : ProtoBuf + + @Serializable + internal class MsgItem( + @JvmField @ProtoNumber(1) val type: Int = 0, + @JvmField @ProtoNumber(2) val text: String = "" + ) : ProtoBuf + + @Serializable + internal class QQDataTextMsg( + @JvmField @ProtoNumber(1) val msgItems: List = emptyList() + ) : ProtoBuf + + @Serializable + internal class WifiPhotoNoPush( + @JvmField @ProtoNumber(1) val json: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class WifiPhotoWithPush( + @JvmField @ProtoNumber(1) val json: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class GenericSubCmd( + @JvmField @ProtoNumber(1) val sessionid: Long = 0L, + @JvmField @ProtoNumber(2) val size: Int = 0, + @JvmField @ProtoNumber(3) val index: Int = 0, + @JvmField @ProtoNumber(4) val type: Int = 0, + @JvmField @ProtoNumber(5) val buf: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(6) val supportAuth: Int = 0 + ) : ProtoBuf + + @Serializable + internal class MoloNotify( + @JvmField @ProtoNumber(1) val buf: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(2) val groupId: Int = 0, + @JvmField @ProtoNumber(3) val groupSize: Int = 0, + @JvmField @ProtoNumber(4) val groupCurindex: Int = 0 + ) : ProtoBuf + + @Serializable + internal class MpFileNotify( + @JvmField @ProtoNumber(1) val sessionid: Long = 0L, + @JvmField @ProtoNumber(2) val operate: Int = 0, + @ProtoType(ProtoIntegerType.FIXED) @JvmField @ProtoNumber(3) val fixed32Ip: Int = 0, + @JvmField @ProtoNumber(4) val port: Int = 0, + @JvmField @ProtoNumber(5) val type: Int = 0, + @JvmField @ProtoNumber(6) val power: Int = 0, + @JvmField @ProtoNumber(7) val json: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class MsgHeader( + @JvmField @ProtoNumber(1) val srcAppId: Int = 0, + @JvmField @ProtoNumber(2) val srcInstId: Int = 0, + @JvmField @ProtoNumber(3) val dstAppId: Int = 0, + @JvmField @ProtoNumber(4) val dstInstId: Int = 0, + @JvmField @ProtoNumber(5) val dstUin: Long = 0L, + @JvmField @ProtoNumber(6) val srcUin: Long = 0L, + @JvmField @ProtoNumber(7) val srcUinType: Int = 0, + @JvmField @ProtoNumber(8) val dstUinType: Int = 0, + @JvmField @ProtoNumber(9) val srcTerType: Int = 0, + @JvmField @ProtoNumber(10) val dstTerType: Int = 0 + ) : ProtoBuf + + @Serializable + internal class NFCNotify( + @JvmField @ProtoNumber(1) val sessionid: Long = 0L, + @JvmField @ProtoNumber(2) val fileName: String = "", + @JvmField @ProtoNumber(3) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoType(ProtoIntegerType.FIXED) @JvmField @ProtoNumber(4) val fixed32Ip: Int = 0, + @JvmField @ProtoNumber(5) val port: Int = 0, + @JvmField @ProtoNumber(6) val urlNotify: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(7) val tokenkey: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(8) val fileLen: Long = 0L, + @JvmField @ProtoNumber(9) val originfileMd5: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(10) val originfiletype: Int = 0, + @JvmField @ProtoNumber(11) val groupId: Int = 0, + @JvmField @ProtoNumber(12) val groupSize: Int = 0, + @JvmField @ProtoNumber(13) val groupCurindex: Int = 0, + @JvmField @ProtoNumber(20) val msgActionInfo: ActionInfo? = null, + @JvmField @ProtoNumber(21) val batchID: Int = 0, + @JvmField @ProtoNumber(22) val groupflag: Int = 0 + ) : ProtoBuf + + @Serializable + internal class ProgressReq( + @JvmField @ProtoNumber(1) val cmd: Int = 0, + @JvmField @ProtoNumber(2) val cookie: Long = 0L, + @JvmField @ProtoNumber(3) val infoflag: Int = 0, + @JvmField @ProtoNumber(4) val uint64Sessionid: List = emptyList() + ) : ProtoBuf + + @Serializable + internal class ProgressInfo( + @JvmField @ProtoNumber(1) val sessionid: Long = 0L, + @JvmField @ProtoNumber(2) val progress: Long = 0L, + @JvmField @ProtoNumber(3) val status: Int = 0, + @JvmField @ProtoNumber(4) val filesize: Long = 0L, + @JvmField @ProtoNumber(5) val filename: String = "", + @JvmField @ProtoNumber(6) val time: Long = 0L + ) : ProtoBuf + + @Serializable + internal class ProgressRsp( + @JvmField @ProtoNumber(1) val cmd: Int = 0, + @JvmField @ProtoNumber(2) val cookie: Long = 0L, + @JvmField @ProtoNumber(3) val packageCount: Int = 0, + @JvmField @ProtoNumber(4) val packageIndex: Int = 0, + @JvmField @ProtoNumber(5) val msgProgressinfo: List = emptyList() + ) : ProtoBuf + + @Serializable + internal class RNFCNotify( + @JvmField @ProtoNumber(1) val sessionid: Long = 0L, + @JvmField @ProtoNumber(2) val token: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoType(ProtoIntegerType.FIXED) @JvmField @ProtoNumber(3) val fixed32Ip: Int = 0, + @JvmField @ProtoNumber(4) val port: Int = 0, + @JvmField @ProtoNumber(5) val svrTaskId: Long = 0L + ) : ProtoBuf + } +} + + +@Serializable +internal class C2CType0x211SubC2CType0x8 : ProtoBuf { + @Serializable + internal class BusiReqHead( + @JvmField @ProtoNumber(1) val int32Version: Int = 0, + @JvmField @ProtoNumber(2) val int32Seq: Int = 0 + ) : ProtoBuf + + @Serializable + internal class BusiRespHead( + @JvmField @ProtoNumber(1) val int32Version: Int = 0, + @JvmField @ProtoNumber(2) val int32Seq: Int = 0, + @JvmField @ProtoNumber(3) val int32ReplyCode: Int = 0, + @JvmField @ProtoNumber(4) val result: String = "" + ) : ProtoBuf + + @Serializable + internal class Cell( + @JvmField @ProtoNumber(1) val int32Mcc: Int = -1, + @JvmField @ProtoNumber(2) val int32Mnc: Int = -1, + @JvmField @ProtoNumber(3) val int32Lac: Int = -1, + @JvmField @ProtoNumber(4) val int32Cellid: Int = -1, + @JvmField @ProtoNumber(5) val int32Rssi: Int = 0 + ) : ProtoBuf + + @Serializable + internal class ConnType( + @JvmField @ProtoNumber(1) val type: Int /* enum */ = 1, + @JvmField @ProtoNumber(2) val desription: String = "" + ) : ProtoBuf + + @Serializable + internal class GPS( + @JvmField @ProtoNumber(1) val int32Lat: Int = 900000000, + @JvmField @ProtoNumber(2) val int32Lon: Int = 900000000, + @JvmField @ProtoNumber(3) val int32Alt: Int = -10000000, + @JvmField @ProtoNumber(4) val eType: Int /* enum */ = 0 + ) : ProtoBuf + + @Serializable + internal class IPAddrInfo( + @JvmField @ProtoNumber(1) val int32Ip: Int = 0, + @JvmField @ProtoNumber(2) val int32Mask: Int = 0, + @JvmField @ProtoNumber(3) val int32Gateway: Int = 0, + @JvmField @ProtoNumber(4) val int32Port: Int = 0 + ) : ProtoBuf + + @Serializable + internal class JudgeResult( + @JvmField @ProtoNumber(1) val type: Int /* enum */ = 0, + @JvmField @ProtoNumber(2) val ssid: String = "", + @JvmField @ProtoNumber(3) val tips: String = "", + @JvmField @ProtoNumber(4) val int32IdleTimeout: Int = 0, + @JvmField @ProtoNumber(5) val idleWaiting: Int = 0, + @JvmField @ProtoNumber(6) val forceWifi: Int = 0, + @JvmField @ProtoNumber(7) val flagsWifipsw: Int = 0, + @JvmField @ProtoNumber(8) val flagsNetcheck: Int = 0 + ) : ProtoBuf + + @Serializable + internal class LBSInfo( + @JvmField @ProtoNumber(1) val msgGps: GPS? = null, + @JvmField @ProtoNumber(2) val msgWifis: List = emptyList(), + @JvmField @ProtoNumber(3) val msgCells: List = emptyList() + ) : ProtoBuf + + @Serializable + internal class MsgBody( + @JvmField @ProtoNumber(1) val msgType: Int /* enum */ = 1, + @JvmField @ProtoNumber(2) val msgCcNotifylist: NotifyList? = null, + @JvmField @ProtoNumber(3) val msgCcnfAbiQuery: NearFieldAbiQuery? = null, + @JvmField @ProtoNumber(4) val msgCcPushJudgeResult: PushJudgeResult? = null, + @JvmField @ProtoNumber(5) val msgCcnfFilesendReq: NearFieldFileSendReq? = null, + @JvmField @ProtoNumber(6) val msgCcnfFilestateSync: NearFieldFileStateSync? = null + ) : ProtoBuf + + @Serializable + internal class NearFieldAbiQuery( + @JvmField @ProtoNumber(1) val toUin: Long = 0L, + @JvmField @ProtoNumber(2) val fromUin: Long = 0L, + @JvmField @ProtoNumber(3) val boolNeedTips: Boolean = false, + @JvmField @ProtoNumber(4) val int32Timeout: Int = 0, + @JvmField @ProtoNumber(5) val cookie: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(6) val int32PeerIp: Int = 0, + @JvmField @ProtoNumber(7) val int32PeerPort: Int = 0, + @JvmField @ProtoNumber(8) val peerExtra: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class NearFieldFileInfo( + @JvmField @ProtoNumber(1) val fileName: String = "", + @JvmField @ProtoNumber(2) val fileSize: Long = 0L, + @JvmField @ProtoNumber(3) val fileMd5: String = "", + @JvmField @ProtoNumber(4) val fileUrl: String = "", + @JvmField @ProtoNumber(5) val fileThumbMd5: String = "", + @JvmField @ProtoNumber(6) val fileThumbUrl: String = "", + @JvmField @ProtoNumber(7) val sessionId: Long = 0L, + @JvmField @ProtoNumber(8) val int32Timeout: Int = 0, + @JvmField @ProtoNumber(9) val groupId: Long = 0L + ) : ProtoBuf + + @Serializable + internal class NearFieldFileSendReq( + @JvmField @ProtoNumber(1) val toUin: Long = 0L, + @JvmField @ProtoNumber(2) val msgFileList: List = emptyList(), + @JvmField @ProtoNumber(3) val int32Ip: Int = 0, + @JvmField @ProtoNumber(4) val int32UdpPort: Int = 0, + @JvmField @ProtoNumber(5) val ssid: String = "", + @JvmField @ProtoNumber(6) val int32ConnWifiapTimeout: Int = 0, + @JvmField @ProtoNumber(7) val forceWifi: Int = 0, + @JvmField @ProtoNumber(8) val wifipsw: String = "" + ) : ProtoBuf + + @Serializable + internal class NearFieldFileStateSync( + @JvmField @ProtoNumber(1) val eType: Int /* enum */ = 1, + @JvmField @ProtoNumber(2) val sessionId: Long = 0L, + @JvmField @ProtoNumber(3) val fromUin: Long = 0L, + @JvmField @ProtoNumber(4) val int32ErrorCode: Int = 0 + ) : ProtoBuf + + @Serializable + internal class NearfieldInfo( + @JvmField @ProtoNumber(1) val msgLbsInfo: LBSInfo? = null, + @JvmField @ProtoNumber(2) val msgConnType: ConnType? = null, + @JvmField @ProtoNumber(3) val msgIpInfo: IPAddrInfo? = null, + @JvmField @ProtoNumber(4) val msgWifiDetail: WifiDetailInfo? = null, + @JvmField @ProtoNumber(5) val msgWifiAbi: WifiAbility? = null, + @JvmField @ProtoNumber(6) val extra: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class NotifyList( + @JvmField @ProtoNumber(1) val notifyType: Int /* enum */ = 0, + @JvmField @ProtoNumber(2) val msgUpdateList: List = emptyList(), + @JvmField @ProtoNumber(3) val sessionId: Int = 0 + ) : ProtoBuf + + @Serializable + internal class PushJudgeResult( + @JvmField @ProtoNumber(1) val msgHead: BusiRespHead? = null, + @JvmField @ProtoNumber(2) val toUin: Long = 0L, + @JvmField @ProtoNumber(3) val msgResult: JudgeResult? = null, + @JvmField @ProtoNumber(4) val int32PeerIp: Int = 0, + @JvmField @ProtoNumber(5) val int32PeerPort: Int = 0, + @JvmField @ProtoNumber(6) val peerExtra: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class ReqAIOJudge( + @JvmField @ProtoNumber(1) val msgHead: BusiReqHead? = null, + @JvmField @ProtoNumber(2) val toUin: Long = 0L, + @JvmField @ProtoNumber(3) val msgNearfieldInfo: NearfieldInfo? = null + ) : ProtoBuf + + @Serializable + internal class ReqExit( + @JvmField @ProtoNumber(1) val msgHead: BusiReqHead? = null, + @JvmField @ProtoNumber(2) val sessionId: Int = 0, + @JvmField @ProtoNumber(3) val msgNearfieldInfo: NearfieldInfo? = null + ) : ProtoBuf + + @Serializable + internal class ReqGetList( + @JvmField @ProtoNumber(1) val msgHead: BusiReqHead? = null, + @JvmField @ProtoNumber(2) val msgNearfieldInfo: NearfieldInfo? = null, + @JvmField @ProtoNumber(3) val sessionId: Int = 0, + @JvmField @ProtoNumber(4) val cookie: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class ReqReportNearFieldAbi( + @JvmField @ProtoNumber(1) val msgHead: BusiReqHead? = null, + @JvmField @ProtoNumber(2) val fromUin: Long = 0L, + @JvmField @ProtoNumber(3) val msgNearfieldInfo: NearfieldInfo? = null, + @JvmField @ProtoNumber(4) val cookie: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class RespAIOJudge( + @JvmField @ProtoNumber(1) val msgHead: BusiRespHead? = null, + @JvmField @ProtoNumber(2) val msgResult: JudgeResult? = null, + @JvmField @ProtoNumber(3) val timeout: Int = 0, + @JvmField @ProtoNumber(4) val toUin: Long = 0L, + @JvmField @ProtoNumber(5) val int32PeerIp: Int = 0, + @JvmField @ProtoNumber(6) val int32PeerPort: Int = 0, + @JvmField @ProtoNumber(7) val peerExtra: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class RespExit( + @JvmField @ProtoNumber(1) val msgHead: BusiRespHead? = null + ) : ProtoBuf + + @Serializable + internal class RespGetList( + @JvmField @ProtoNumber(1) val msgHead: BusiRespHead? = null, + @JvmField @ProtoNumber(2) val msgUserList: List = emptyList(), + @JvmField @ProtoNumber(3) val sessionId: Int = 0, + @JvmField @ProtoNumber(4) val int32UpdateInterval: Int = 0, + @JvmField @ProtoNumber(5) val cookie: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class UpdateInfo( + @JvmField @ProtoNumber(1) val type: Int /* enum */ = 1, + @JvmField @ProtoNumber(2) val msgUser: UserProfile? = null + ) : ProtoBuf + + @Serializable + internal class UserAbility( + @JvmField @ProtoNumber(1) val int32SysQlver: Int = 0, + @JvmField @ProtoNumber(2) val int32SysTerm: Int = 0, + @JvmField @ProtoNumber(3) val int32SysApp: Int = 0, + @JvmField @ProtoNumber(10) val int32AbsWifiHost: Int = 0, + @JvmField @ProtoNumber(11) val int32AbsWifiClient: Int = 0, + @JvmField @ProtoNumber(12) val int32AbsWifiForcedcreate: Int = 0, + @JvmField @ProtoNumber(13) val int32AbsWifiForcedconnect: Int = 0, + @JvmField @ProtoNumber(14) val int32AbsWifiPassword: Int = 0, + @JvmField @ProtoNumber(20) val int32AbsNetReachablecheck: Int = 0, + @JvmField @ProtoNumber(21) val int32AbsNetSpeedTest: Int = 0, + @JvmField @ProtoNumber(30) val int32AbsUiPromptOnclick: Int = 0, + @JvmField @ProtoNumber(31) val int32AbsUiPromptPassive: Int = 0 + ) : ProtoBuf + + @Serializable + internal class UserExtraInfo( + @JvmField @ProtoNumber(1) val ability: UserAbility? = null + ) : ProtoBuf + + @Serializable + internal class UserProfile( + @JvmField @ProtoNumber(1) val uin: Long = 0L, + @JvmField @ProtoNumber(2) val int32FaceId: Int = 0, + @JvmField @ProtoNumber(3) val int32Sex: Int = 0, + @JvmField @ProtoNumber(4) val int32Age: Int = 0, + @JvmField @ProtoNumber(5) val nick: String = "", + @JvmField @ProtoNumber(6) val tmpTalkSig: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(7) val msgResult: JudgeResult? = null, + @JvmField @ProtoNumber(8) val int32Ip: Int = 0, + @JvmField @ProtoNumber(9) val int32Port: Int = 0, + @JvmField @ProtoNumber(10) val tip: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(11) val extra: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class Wifi( + @JvmField @ProtoNumber(1) val mac: Long = 0L, + @JvmField @ProtoNumber(2) val int32Rssi: Int = 0 + ) : ProtoBuf + + @Serializable + internal class WifiAbility( + @JvmField @ProtoNumber(1) val boolEstablishAbi: Boolean = false, + @JvmField @ProtoNumber(2) val boolAutoConnectAbi: Boolean = false + ) : ProtoBuf + + @Serializable + internal class WifiDetailInfo( + @JvmField @ProtoNumber(1) val boolSelfEstablish: Boolean = false, + @JvmField @ProtoNumber(2) val ssid: String = "", + @JvmField @ProtoNumber(3) val mac: String = "" + ) : ProtoBuf +} + + +@Serializable +internal class C2CType0x211SubC2CType0x9 : ProtoBuf { + @Serializable + internal class MsgBody( + @JvmField @ProtoNumber(1) val service: String = "", + @JvmField @ProtoNumber(2) val cMD: Int = 0, + @JvmField @ProtoNumber(3) val msgPrinter: MsgPrinter? = null + ) : ProtoBuf { + @Serializable + internal class HPPrinterStateInfo( + @JvmField @ProtoNumber(1) val printerDin: Long = 0L, + @JvmField @ProtoNumber(2) val printerQrPicUrl: String = "", + @JvmField @ProtoNumber(3) val printerQrOpenUrl: String = "", + @JvmField @ProtoNumber(4) val printerTipUrl: String = "" + ) : ProtoBuf + + @Serializable + internal class MsgPrinter( + @JvmField @ProtoNumber(1) val stringPrinter: List = emptyList(), + @JvmField @ProtoNumber(2) val printSessionId: Long = 0L, + @JvmField @ProtoNumber(3) val printResult: Int = 0, + @JvmField @ProtoNumber(4) val resultMsg: String = "", + @JvmField @ProtoNumber(5) val uint64SessionId: List = emptyList(), + @JvmField @ProtoNumber(6) val msgSupportFileInfo: List = emptyList(), + @JvmField @ProtoNumber(7) val hpPrinterStateInfo: HPPrinterStateInfo? = null + ) : ProtoBuf + + @Serializable + internal class SupportFileInfo( + @JvmField @ProtoNumber(1) val fileSuffix: String = "", + @JvmField @ProtoNumber(2) val copies: Int = 0, + @JvmField @ProtoNumber(3) val duplex: Int = 0 + ) : ProtoBuf + } +} + + +@Serializable +internal class C2CType0x211SubC2CType0xb : ProtoBuf { + @Serializable + internal class MsgBody( + @JvmField @ProtoNumber(1) val msgMsgHeader: MsgHeader? = null, + @JvmField @ProtoNumber(2) val msgRejectMotify: RejectNotify? = null + ) : ProtoBuf { + @Serializable + internal class MsgHeader( + @JvmField @ProtoNumber(1) val bodyType: Int /* enum */ = 101, + @JvmField @ProtoNumber(2) val sessionType: Int = 0, + @JvmField @ProtoNumber(3) val toUin: Long = 0L, + @JvmField @ProtoNumber(4) val toMobile: String = "", + @JvmField @ProtoNumber(5) val roomId: Long = 0L + ) : ProtoBuf + + @Serializable + internal class RejectNotify( + @JvmField @ProtoNumber(1) val enumRejectReason: Int /* enum */ = 201, + @JvmField @ProtoNumber(2) val msg: String = "", + @JvmField @ProtoNumber(3) val ringFilename: String = "" + ) : ProtoBuf + } +} diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt index cf9cdbcab..fa7cb5d7f 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt @@ -26,20 +26,17 @@ import net.mamoe.mirai.contact.NormalMember import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.AbstractEvent import net.mamoe.mirai.event.Event -import net.mamoe.mirai.event.events.BotJoinGroupEvent -import net.mamoe.mirai.event.events.FriendMessageEvent -import net.mamoe.mirai.event.events.MemberJoinEvent -import net.mamoe.mirai.event.events.TempMessageEvent +import net.mamoe.mirai.event.events.* import net.mamoe.mirai.internal.QQAndroidBot -import net.mamoe.mirai.internal.contact.GroupImpl -import net.mamoe.mirai.internal.contact.checkIsFriendImpl -import net.mamoe.mirai.internal.contact.checkIsMemberImpl +import net.mamoe.mirai.internal.contact.* +import net.mamoe.mirai.internal.message.MessageSourceFromFriendImpl import net.mamoe.mirai.internal.message.toMessageChain import net.mamoe.mirai.internal.network.MultiPacket import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc +import net.mamoe.mirai.internal.network.protocol.data.proto.SubMsgType0x7 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket @@ -47,11 +44,12 @@ import net.mamoe.mirai.internal.network.protocol.packet.chat.GroupInfoImpl import net.mamoe.mirai.internal.network.protocol.packet.chat.NewContact import net.mamoe.mirai.internal.network.protocol.packet.chat.toLongUnsigned import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList +import net.mamoe.mirai.internal.utils.* +import net.mamoe.mirai.internal.utils.io.serialization.loadAs import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf -import net.mamoe.mirai.internal.utils.read -import net.mamoe.mirai.internal.utils.toInt -import net.mamoe.mirai.internal.utils.toUHexString +import net.mamoe.mirai.message.data.PlainText +import net.mamoe.mirai.message.data.buildMessageChain import net.mamoe.mirai.utils.cast import net.mamoe.mirai.utils.debug import net.mamoe.mirai.utils.warning @@ -175,6 +173,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory bot.groupListModifyLock.withLock { @@ -351,8 +352,45 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory { - // 好友文件 - return@mapNotNull null + + // top_package/awbk.java:3765 + + return@mapNotNull when (msg.msgHead.c2cCmd) { + // other client sync + 7 -> { + val data = msg.msgBody.msgContent.loadAs(SubMsgType0x7.MsgBody.serializer()) + + val textMsg = + data.msgSubcmd0x4Generic?.buf?.loadAs(SubMsgType0x7.MsgBody.QQDataTextMsg.serializer()) + ?: return@mapNotNull null + + with(data.msgHeader ?: return@mapNotNull null) { + if (srcUin != dstUin || dstUin != bot.id) return@mapNotNull null + val client = bot.otherClients.find { it.instanceInfo.iAppId == srcInstId } + ?: return@mapNotNull null// don't compare with dstAppId. diff. + + val chain = buildMessageChain { + +MessageSourceFromFriendImpl(bot, listOf(msg)) + for (msgItem in textMsg.msgItems) { + when (msgItem.type) { + 1 -> { + +PlainText(msgItem.text) + } + else -> { + } + } + } + } + + return@mapNotNull OtherClientMessageEvent(client, chain, msg.msgHead.msgTime) + } + } + + else -> null + } + + // 各种垃圾 + // 08 04 12 1E 08 E9 07 10 B7 F7 8B 80 02 18 E9 07 20 00 28 DD F1 92 B7 07 30 DD F1 92 B7 07 48 02 50 03 32 1E 08 88 80 F8 92 CD 84 80 80 10 10 01 18 00 20 01 2A 0C 0A 0A 08 01 12 06 E5 95 8A E5 95 8A } 141 -> { val tmpHead = msg.msgHead.c2cTmpMsgHead ?: return@mapNotNull null @@ -397,6 +435,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory { // unknown + // 前 4 byte 是群号 return@mapNotNull null } // 732: 27 0B 60 E7 0C 01 3E 03 3F A2 5E 90 60 E2 00 01 44 71 47 90 00 00 02 58 diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt index 965c5f0ac..ee627f645 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt @@ -29,7 +29,7 @@ internal object MessageSvcPushNotify : IncomingPacketFactory( return readUniPacket(RequestPushNotify.serializer()) } - override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? { + override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket { client.syncingController.firstNotify.loop { firstNotify -> network.run { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt index 083b8a88c..45b8d3e35 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt @@ -238,7 +238,14 @@ internal class StatSvc { when (notify.status.toInt()) { 1 -> { if (bot.otherClients.any { it.kind == kind }) return null - val client = bot.createOtherClient(kind) + val client = bot.createOtherClient( + kind, + notify.vecInstanceList?.find { it.iClientType == notify.iClientType } + ?: throw contextualBugReportException( + "decode SvcReqMSFLoginNotify (OtherClient online)", + notify._miraiContentToString(), + additional = "Failed to find corresponding instanceInfo." + )) bot.otherClients.delegate.add(client) OtherClientOnlineEvent(client) }