From 27dbfcfb39b695455bc4f3c271ec2f471efe4fda Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Thu, 30 Jan 2020 00:35:39 +0800
Subject: [PATCH] Move packets

---
 .../qqandroid/event/ForceOfflineEvent.kt      | 14 ++++++++
 .../mirai/qqandroid/io/serialization/Jce.kt   | 32 +++++++++++++++++--
 .../chat/data => data/jce}/PushNotifyPack.kt  |  2 +-
 .../data/jce/RequestPushForceOffline.kt       | 13 ++++++++
 .../data => data/proto}/Cmd0x352Packet.kt     |  2 +-
 .../chat/data => data/proto}/ImageRequest.kt  |  2 +-
 .../{packet/chat/data => data/proto}/Msg.kt   |  2 +-
 .../chat/data => data/proto}/MsgCommon.kt     |  2 +-
 .../chat/data => data/proto}/MsgSvc.kt        |  2 +-
 .../chat/data => data/proto}/OnlinePush.kt    |  2 +-
 .../network/protocol/packet/PacketFactory.kt  |  6 +++-
 .../packet/chat/image/ImageDownPacket.kt      |  4 +--
 .../packet/chat/image/ImageUpPacket.kt        |  4 +--
 ...MessageSvc.PushNotify.kt => MessageSvc.kt} | 30 +++++++++++------
 .../chat/receive/OnlinePush.PbPushGroupMsg.kt |  4 +--
 .../mamoe/mirai/qqandroid/utils/MessageQQA.kt |  4 +--
 .../kotlin/test/JceDataClassGenerator.kt      | 18 +++++++----
 .../src/jvmTest/kotlin/test/SmsTest.kt        | 21 ------------
 18 files changed, 110 insertions(+), 54 deletions(-)
 create mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/ForceOfflineEvent.kt
 rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/{packet/chat/data => data/jce}/PushNotifyPack.kt (97%)
 create mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/RequestPushForceOffline.kt
 rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/{packet/chat/data => data/proto}/Cmd0x352Packet.kt (94%)
 rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/{packet/chat/data => data/proto}/ImageRequest.kt (97%)
 rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/{packet/chat/data => data/proto}/Msg.kt (99%)
 rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/{packet/chat/data => data/proto}/MsgCommon.kt (98%)
 rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/{packet/chat/data => data/proto}/MsgSvc.kt (99%)
 rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/{packet/chat/data => data/proto}/OnlinePush.kt (88%)
 rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/{MessageSvc.PushNotify.kt => MessageSvc.kt} (79%)
 delete mode 100644 mirai-core-qqandroid/src/jvmTest/kotlin/test/SmsTest.kt

diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/ForceOfflineEvent.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/ForceOfflineEvent.kt
new file mode 100644
index 000000000..381b170ef
--- /dev/null
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/ForceOfflineEvent.kt
@@ -0,0 +1,14 @@
+package net.mamoe.mirai.qqandroid.event
+
+import net.mamoe.mirai.Bot
+import net.mamoe.mirai.data.Packet
+import net.mamoe.mirai.event.events.BotEvent
+
+/**
+ * 被挤下线
+ */
+class ForceOfflineEvent(
+    override val bot: Bot,
+    val title: String,
+    val tips: String
+) : BotEvent(), Packet
\ No newline at end of file
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/Jce.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/Jce.kt
index 9addfcd55..c3c69dd4f 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/Jce.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/Jce.kt
@@ -7,8 +7,13 @@ import kotlinx.serialization.internal.*
 import kotlinx.serialization.modules.EmptyModule
 import kotlinx.serialization.modules.SerialModule
 import net.mamoe.mirai.qqandroid.io.JceStruct
-import net.mamoe.mirai.qqandroid.network.protocol.packet.withUse
 import net.mamoe.mirai.qqandroid.io.ProtoBuf
+import net.mamoe.mirai.qqandroid.network.protocol.packet.login.data.RequestDataVersion2
+import net.mamoe.mirai.qqandroid.network.protocol.packet.login.data.RequestDataVersion3
+import net.mamoe.mirai.qqandroid.network.protocol.packet.login.data.RequestPacket
+import net.mamoe.mirai.qqandroid.network.protocol.packet.withUse
+import net.mamoe.mirai.utils.firstValue
+import net.mamoe.mirai.utils.io.read
 import net.mamoe.mirai.utils.io.readIoBuffer
 import net.mamoe.mirai.utils.io.readString
 import net.mamoe.mirai.utils.io.toIoBuffer
@@ -30,6 +35,28 @@ fun <T> ByteReadPacket.readRemainingAsJceStruct(serializer: DeserializationStrat
     return Jce.byCharSet(charset).load(serializer, this)
 }
 
+/**
+ * 先解析为 [RequestPacket], 即 `UniRequest`, 再按版本解析 map, 再找出指定数据并反序列化
+ */
+fun <T : JceStruct> ByteReadPacket.decodeUniPacket(deserializer: DeserializationStrategy<T>, name: String? = null): T {
+    val request = this.readRemainingAsJceStruct(RequestPacket.serializer())
+
+    fun ByteArray.doReadInner(): T = read {
+        discardExact(1)
+        this.readRemainingAsJceStruct(deserializer)
+    }
+
+    return if (name == null) when (request.iVersion.toInt()) {
+        2 -> request.sBuffer.loadAs(RequestDataVersion2.serializer()).map.firstValue().firstValue().doReadInner()
+        3 -> request.sBuffer.loadAs(RequestDataVersion3.serializer()).map.firstValue().doReadInner()
+        else -> error("unsupported version ${request.iVersion}")
+    } else when (request.iVersion.toInt()) {
+        2 -> request.sBuffer.loadAs(RequestDataVersion2.serializer()).map.getOrElse(name) { error("cannot find $name") }.firstValue().doReadInner()
+        3 -> request.sBuffer.loadAs(RequestDataVersion3.serializer()).map.getOrElse(name) { error("cannot find $name") }.doReadInner()
+        else -> error("unsupported version ${request.iVersion}")
+    }
+}
+
 fun <T : JceStruct> T.toByteArray(serializer: SerializationStrategy<T>, c: JceCharset = JceCharset.GBK): ByteArray = Jce.byCharSet(c).dump(serializer, this)
 
 enum class JceCharset(val kotlinCharset: Charset) {
@@ -480,7 +507,8 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
 
         @Suppress("UNCHECKED_CAST")
         override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
-            return decodeNullableSerializableValue(deserializer as DeserializationStrategy<Any?>) as? T ?: error("value with tag $currentTagOrNull is not optional but cannot find")
+            return decodeNullableSerializableValue(deserializer as DeserializationStrategy<Any?>) as? T
+                ?: error("value with tag $currentTagOrNull is not optional but cannot find")
         }
     }
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/PushNotifyPack.kt
similarity index 97%
rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt
rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/PushNotifyPack.kt
index cea4cdc3b..4bdc99b9d 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/PushNotifyPack.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/PushNotifyPack.kt
@@ -1,4 +1,4 @@
-package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
+package net.mamoe.mirai.qqandroid.network.protocol.data.jce
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/RequestPushForceOffline.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/RequestPushForceOffline.kt
new file mode 100644
index 000000000..4c3a50c74
--- /dev/null
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/RequestPushForceOffline.kt
@@ -0,0 +1,13 @@
+package net.mamoe.mirai.qqandroid.network.protocol.data.jce
+
+import kotlinx.serialization.SerialId
+import kotlinx.serialization.Serializable
+import net.mamoe.mirai.qqandroid.io.JceStruct
+
+@Serializable
+internal class RequestPushForceOffline(
+    @SerialId(0) val uin: Long,
+    @SerialId(1) val title: String? = "",
+    @SerialId(2) val tips: String? = "",
+    @SerialId(3) val sameDevice: Byte? = null
+) : JceStruct
\ No newline at end of file
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/Cmd0x352Packet.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Cmd0x352Packet.kt
similarity index 94%
rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/Cmd0x352Packet.kt
rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Cmd0x352Packet.kt
index ee6eac35f..8732d2178 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/Cmd0x352Packet.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Cmd0x352Packet.kt
@@ -1,4 +1,4 @@
-package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
+package net.mamoe.mirai.qqandroid.network.protocol.data.proto
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/ImageRequest.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/ImageRequest.kt
similarity index 97%
rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/ImageRequest.kt
rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/ImageRequest.kt
index ae1e45893..d2fbf1aae 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/ImageRequest.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/ImageRequest.kt
@@ -1,4 +1,4 @@
-package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
+package net.mamoe.mirai.qqandroid.network.protocol.data.proto
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/Msg.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Msg.kt
similarity index 99%
rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/Msg.kt
rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Msg.kt
index d9236ba06..ea1c3d3fc 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/Msg.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Msg.kt
@@ -1,4 +1,4 @@
-package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
+package net.mamoe.mirai.qqandroid.network.protocol.data.proto
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/MsgCommon.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgCommon.kt
similarity index 98%
rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/MsgCommon.kt
rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgCommon.kt
index 1a2185f36..591e8b148 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/MsgCommon.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgCommon.kt
@@ -1,4 +1,4 @@
-package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
+package net.mamoe.mirai.qqandroid.network.protocol.data.proto
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/MsgSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgSvc.kt
similarity index 99%
rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/MsgSvc.kt
rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgSvc.kt
index 885530d04..c55d91ac0 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/MsgSvc.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/MsgSvc.kt
@@ -1,4 +1,4 @@
-package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
+package net.mamoe.mirai.qqandroid.network.protocol.data.proto
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OnlinePush.kt
similarity index 88%
rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/OnlinePush.kt
rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OnlinePush.kt
index 808096850..5eec12883 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/data/OnlinePush.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OnlinePush.kt
@@ -1,4 +1,4 @@
-package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data
+package net.mamoe.mirai.qqandroid.network.protocol.data.proto
 
 import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
index e95628143..25ac9ccff 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
@@ -61,8 +61,12 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
     StatSvc.Register,
     OnlinePush.PbPushGroupMsg,
     MessageSvc.PushNotify,
-    MessageSvc.PbGetMsg
+    MessageSvc.PbGetMsg,
+    MessageSvc.PushForceOffline
 ) {
+    // SvcReqMSFLoginNotify 自己的其他设备上限
+    // MessageSvc.PushReaded 电脑阅读了别人的消息, 告知手机
+    // OnlinePush.PbC2CMsgSync 电脑发消息给别人, 同步给手机
 
     fun findPacketFactory(commandName: String): PacketFactory<*>? = this.firstOrNull { it.commandName == commandName }
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageDownPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageDownPacket.kt
index 79b752863..52cbc6821 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageDownPacket.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageDownPacket.kt
@@ -9,8 +9,8 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient
 import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
 import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.Cmd0x352Packet
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.GetImgUrlReq
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.GetImgUrlReq
 import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
 
 internal object ImageDownPacket : PacketFactory<ImageDownPacket.ImageDownPacketResponse>("LongConn.OffPicDown") {
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageUpPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageUpPacket.kt
index 62bab7797..bf06e5ca0 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageUpPacket.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/image/ImageUpPacket.kt
@@ -10,8 +10,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.*
 import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
 import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.Cmd0x352Packet
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.UploadImgReq
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.UploadImgReq
 
 internal object ImageUpPacket : PacketFactory<ImageUpPacket.ImageUpPacketResponse>("LongConn.OffPicUp") {
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
similarity index 79%
rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt
rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
index 91be81eae..5377d6d9a 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
@@ -5,17 +5,19 @@ import kotlinx.io.core.discardExact
 import net.mamoe.mirai.data.MultiPacket
 import net.mamoe.mirai.message.FriendMessage
 import net.mamoe.mirai.qqandroid.QQAndroidBot
+import net.mamoe.mirai.qqandroid.event.ForceOfflineEvent
 import net.mamoe.mirai.qqandroid.io.readRemainingAsProtoBuf
+import net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket
 import net.mamoe.mirai.qqandroid.io.serialization.loadAs
 import net.mamoe.mirai.qqandroid.io.serialization.readRemainingAsJceStruct
 import net.mamoe.mirai.qqandroid.io.writeProtoBuf
 import net.mamoe.mirai.qqandroid.network.QQAndroidClient
-import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushForceOffline
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushNotify
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
 import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
 import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.MsgSvc
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.RequestPushNotify
 import net.mamoe.mirai.qqandroid.network.protocol.packet.login.data.RequestDataVersion2
 import net.mamoe.mirai.qqandroid.network.protocol.packet.login.data.RequestPacket
 import net.mamoe.mirai.qqandroid.utils.toMessageChain
@@ -32,10 +34,7 @@ class MessageSvc {
         override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): RequestPushNotify {
             discardExact(8)
 
-            return readRemainingAsJceStruct(RequestPacket.serializer()).sBuffer
-                .loadAs(RequestDataVersion2.serializer()).map.firstValue().firstValue()
-                .toReadPacket().apply { discardExact(1) }
-                .readRemainingAsJceStruct(RequestPushNotify.serializer())
+            return decodeUniPacket(RequestPushNotify.serializer())
         }
 
         override suspend fun QQAndroidBot.handle(packet: RequestPushNotify) {
@@ -50,7 +49,9 @@ class MessageSvc {
      * 进行刷新消息
      */
     internal object PbGetMsg : PacketFactory<MultiPacket<FriendMessage>>("MessageSvc.PbGetMsg") {
-        val EXTRA_DATA = "08 00 12 33 6D 6F 64 65 6C 3A 78 69 61 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes()
+        val EXTRA_DATA =
+            "08 00 12 33 6D 6F 64 65 6C 3A 78 69 61 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes()
+
         operator fun invoke(
             client: QQAndroidClient,
             from: RequestPushNotify
@@ -67,7 +68,7 @@ class MessageSvc {
                     latestRambleNumber = 20,
                     otherRambleNumber = 3,
                     onlineSyncFlag = 1,
-                  //  serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY,
+                    //  serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY,
                     syncCookie = client.c2cMessageSync.syncCookie,
                     syncFlag = client.c2cMessageSync.syncFlag,
                     msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf,
@@ -105,5 +106,16 @@ class MessageSvc {
             }.toList())
         }
     }
+
+    /**
+     * 被挤下线
+     */
+    internal object PushForceOffline : PacketFactory<ForceOfflineEvent>("MessageSvc.PushForceOffline") {
+        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): ForceOfflineEvent {
+            discardExact(4)
+            val struct = this.decodeUniPacket(RequestPushForceOffline.serializer())
+            return ForceOfflineEvent(bot, title = struct.title ?: "", tips = struct.tips ?: "")
+        }
+    }
 }
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt
index e8c99edc1..3f7919088 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt
@@ -9,9 +9,9 @@ import kotlinx.serialization.protobuf.ProtoBuf
 import net.mamoe.mirai.contact.MemberPermission
 import net.mamoe.mirai.message.GroupMessage
 import net.mamoe.mirai.qqandroid.QQAndroidBot
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgOnlinePush
 import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.ImMsgBody
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.MsgOnlinePush
 import net.mamoe.mirai.qqandroid.utils.toMessageChain
 
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/MessageQQA.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/MessageQQA.kt
index 2ed61c4e4..541f0d47a 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/MessageQQA.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/MessageQQA.kt
@@ -2,8 +2,8 @@ package net.mamoe.mirai.qqandroid.utils
 
 import net.mamoe.mirai.data.ImageLink
 import net.mamoe.mirai.message.data.*
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.ImMsgBody
-import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.MsgSvc
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
 
 
 internal fun MessageChain.constructPbSendMsgReq(): MsgSvc.PbSendMsgReq {
diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/test/JceDataClassGenerator.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/test/JceDataClassGenerator.kt
index a09f5b16d..dd533ea25 100644
--- a/mirai-core-qqandroid/src/jvmTest/kotlin/test/JceDataClassGenerator.kt
+++ b/mirai-core-qqandroid/src/jvmTest/kotlin/test/JceDataClassGenerator.kt
@@ -1,14 +1,20 @@
 package test;
 
-import net.mamoe.mirai.utils.cryptor.contentToString
 import java.io.File
-import java.lang.StringBuilder
 
 fun main(){
-    val var9 = toJCEInfo(File("/Users/jiahua.liu/Desktop/mirai/mirai-core-qqandroid/src/jvmTest/kotlin/test/GetFriendListReq").readText())
-    println("import kotlinx.serialization.SerialId\n" +
-            "import kotlinx.serialization.Serializable\n" +
-            "import net.mamoe.mirai.qqandroid.io.JceStruct\n")
+    val var9 = toJCEInfo(
+        File(
+            """
+        E:\Projects\QQAndroidFF\app\src\main\java\PushNotifyPack\RequestPushForceOffline.java
+    """.trimIndent()
+        ).readText()
+    )
+    println(
+        "import kotlinx.serialization.SerialId\n" +
+                "import kotlinx.serialization.Serializable\n" +
+                "import net.mamoe.mirai.qqandroid.io.JceStruct\n"
+    )
     println(var9.toString())
 }
 
diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/test/SmsTest.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/test/SmsTest.kt
deleted file mode 100644
index 387015190..000000000
--- a/mirai-core-qqandroid/src/jvmTest/kotlin/test/SmsTest.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package test
-
-import net.mamoe.mirai.utils.cryptor.contentToString
-import net.mamoe.mirai.utils.io.hexToBytes
-import net.mamoe.mirai.utils.io.readTLVMap
-import net.mamoe.mirai.utils.io.toIoBuffer
-
-fun main(){
-
-    //server to client
-    val s2c = """
-00 08 00 08 00 00 00 00 08 04 00 00 01 04 00 24 41 75 43 4A 64 56 72 56 34 30 79 67 67 2B 41 4D 59 30 42 31 4B 58 64 44 70 68 61 49 4C 41 67 59 65 41 3D 3D 01 16 00 0E 00 08 F7 FF 7C 00 01 04 00 01 5F 5E 10 E2 01 74 00 61 45 47 39 4A 30 72 79 2D 42 46 57 2D 64 36 39 76 4B 44 62 39 47 5F 61 67 6C 7A 71 46 61 36 35 34 47 33 41 4B 77 63 6D 58 78 61 71 6A 34 31 45 36 76 4D 6C 44 4A 50 68 42 41 6D 4D 71 61 65 71 6B 58 50 43 2D 52 5A 51 34 4D 41 38 54 62 63 48 6D 39 53 66 57 37 57 59 4E 6A 52 4C 52 4B 36 7A 56 6B 01 7A 00 04 00 00 00 09 01 97 00 01 00
-         """.trimIndent().hexToBytes().toIoBuffer().readTLVMap()
-    //client to server
-    val c2s = "00 08 00 08 00 00 00 00 08 04 00 00 01 04 00 24 41 69 4E 54 75 7A 50 2F 48 6D 5A 30 74 37 64 54 71 57 7A 67 79 35 54 4C 77 39 55 69 53 59 69 45 71 67 3D 3D 01 16 00 0E 00 08 F7 FF 7C 00 01 04 00 01 5F 5E 10 E2 01 74 00 61 45 66 43 39 46 4B 63 70 47 30 5F 5A 55 41 4F 6A 4E 4C 6F 72 56 30 77 66 4B 67 49 4D 33 33 6E 58 44 37 5F 4B 61 75 56 6D 4F 6F 54 68 6A 64 38 62 72 44 64 69 5F 62 48 51 5A 66 37 6E 4F 6B 78 43 35 6E 47 4E 38 6B 6A 35 39 6D 37 32 71 47 66 78 4E 76 50 51 53 39 33 66 37 6B 72 71 66 71 78 63 5F 01 7A 00 04 00 00 00 09 01 97 00 01 00".hexToBytes().toIoBuffer().readTLVMap()
-
-    println(get_mpasswd())
-    println(s2c.contentToString())
-
-}
-