From f613b7f7b741fe6812a948c77028bfb761a749bf Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Wed, 23 Dec 2020 22:46:10 +0800
Subject: [PATCH] Support other client messages: - Add OtherClientMessageEvent

---
 .../commonMain/kotlin/event/events/message.kt |  26 +
 .../src/commonMain/kotlin/QQAndroidBot.kt     |   6 +-
 .../kotlin/contact/OtherClientImpl.kt         |  44 +-
 .../src/commonMain/kotlin/contact/util.kt     |   3 +
 .../kotlin/message/incomingSourceImpl.kt      |  13 +-
 .../protocol/data/jce/PushNotifyPack.kt       |   7 +-
 .../protocol/data/proto/HummerResv21.kt       |  57 ++
 .../protocol/data/proto/msgType0x211.kt       | 573 ++++++++++++++++++
 .../chat/receive/MessageSvc.PbGetMsg.kt       |  63 +-
 .../chat/receive/MessageSvc.PushNotify.kt     |   2 +-
 .../network/protocol/packet/login/StatSvc.kt  |   9 +-
 11 files changed, 778 insertions(+), 25 deletions(-)
 create mode 100644 mirai-core/src/commonMain/kotlin/network/protocol/data/proto/HummerResv21.kt
 create mode 100644 mirai-core/src/commonMain/kotlin/network/protocol/data/proto/msgType0x211.kt

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<User, Contact>, 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<OtherClientImpl>().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<Contact> {
         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<MsgComm.Msg>.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<MsgComm.Msg>.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<MsgComm.Msg>
 ) : 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<FTNNotify> = emptyList(),
+        @JvmField @ProtoNumber(4) val msgSubcmd0x2NfcNotify: List<NFCNotify> = emptyList(),
+        @JvmField @ProtoNumber(5) val msgSubcmd0x3Filecontrol: List<FileControl> = emptyList(),
+        @JvmField @ProtoNumber(6) val msgSubcmd0x4Generic: GenericSubCmd? = null,
+        @JvmField @ProtoNumber(7) val msgSubcmd0x5MoloNotify: List<MoloNotify> = emptyList(),
+        @JvmField @ProtoNumber(8) val msgSubcmd0x8RnfcNotify: List<RNFCNotify> = emptyList(),
+        @JvmField @ProtoNumber(9) val msgSubcmd0x9FtnThumbNotify: List<FTNNotify> = emptyList(),
+        @JvmField @ProtoNumber(10) val msgSubcmd0xaNfcThumbNotify: List<NFCNotify> = emptyList(),
+        @JvmField @ProtoNumber(11) val msgSubcmd0xbMpfileNotify: List<MpFileNotify> = 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<MsgItem> = 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<Long> = 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<ProgressInfo> = 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<Wifi> = emptyList(),
+        @JvmField @ProtoNumber(3) val msgCells: List<Cell> = 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<NearFieldFileInfo> = 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<UpdateInfo> = 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<UserProfile> = 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<String> = 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<Long> = emptyList(),
+            @JvmField @ProtoNumber(6) val msgSupportFileInfo: List<SupportFileInfo> = 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<MessageSvcPbGetMsg.Re
             }
         }
 
+
 //        bot.logger.debug(resp.msgRspType._miraiContentToString())
 //        bot.logger.debug(resp.syncCookie._miraiContentToString())
 
@@ -202,6 +201,8 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
                     )
                 ) return@mapNotNull null
 
+                // if (msg.msgHead.msgType != 732) msg._miraiContentToString().soutv("MSG")
+
                 when (msg.msgHead.msgType) {
                     33 -> bot.groupListModifyLock.withLock {
 
@@ -351,8 +352,45 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
                         return@mapNotNull null
                     }
                     529 -> {
-                        // 好友文件
-                        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<MessageSvcPbGetMsg.Re
 
                     732 -> {
                         // 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<RequestPushNotify>(
         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)
                     }