diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index 5f2a8f029..7857b6a92 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -203,6 +203,16 @@ internal class MemberImpl( return mute(0) } + override suspend fun kick(message: String): Boolean { + bot.network.run { + return TroopManagement.Kick( + client = bot.client, + member = this@MemberImpl, + message = message + ).sendAndExpect<TroopManagement.Kick.Response>().success + } + } + override fun equals(other: Any?): Boolean { if (this === other) return true return other is Member && other.id == this.id diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt index 0a63e5325..75c37490a 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt @@ -5,6 +5,39 @@ import kotlinx.serialization.Serializable import net.mamoe.mirai.qqandroid.io.ProtoBuf import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY +@Serializable +class Oidb0x8a0 : ProtoBuf { + @Serializable + class RspBody( + @SerialId(1) val optUint64GroupCode: Long = 0L, + @SerialId(2) val msgKickResult: List<Oidb0x8a0.KickResult>? = null + ) : ProtoBuf + + @Serializable + class KickResult( + @SerialId(1) val optUint32Result: Int = 0, + @SerialId(2) val optUint64MemberUin: Long = 0L + ) : ProtoBuf + + @Serializable + class KickMemberInfo( + @SerialId(1) val optUint32Operate: Int = 0, + @SerialId(2) val optUint64MemberUin: Long = 0L, + @SerialId(3) val optUint32Flag: Int = 0, + @SerialId(4) val optBytesMsg: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + class ReqBody( + @SerialId(1) val optUint64GroupCode: Long = 0L, + @SerialId(2) val msgKickList: List<Oidb0x8a0.KickMemberInfo>? = null, + @SerialId(3) val kickList: List<Long>? = null, + @SerialId(4) val kickFlag: Int = 0, + @SerialId(5) val kickMsg: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf +} + + @Serializable class Oidb0x8fc : ProtoBuf { @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 b7fb0619c..a78623705 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 @@ -125,7 +125,8 @@ internal object KnownPacketFactories { TroopManagement.Mute, TroopManagement.GroupOperation, TroopManagement.GetGroupOperationInfo, - TroopManagement.EditGroupNametag + TroopManagement.EditGroupNametag, + TroopManagement.Kick ) object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf( diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt index 5ceb9712f..97d456937 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt @@ -13,14 +13,12 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.protocol.data.jce.ModifyGroupCardReq import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket import net.mamoe.mirai.qqandroid.network.protocol.data.jce.stUinInfo -import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Oidb0x88d -import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Oidb0x89a -import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Oidb0x8fc -import net.mamoe.mirai.qqandroid.network.protocol.data.proto.OidbSso +import net.mamoe.mirai.qqandroid.network.protocol.data.proto.* import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket +import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement.GetGroupOperationInfo.decode import net.mamoe.mirai.utils.daysToSeconds import net.mamoe.mirai.utils.io.encodeToString @@ -131,6 +129,50 @@ internal object TroopManagement { } } + internal object Kick : OutgoingPacketFactory<Kick.Response>("OidbSvc.0x8a0_0") { + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { + return Response(this.readBytes().loadAs(OidbSso.OIDBSSOPkg.serializer()).bodybuffer.loadAs(Oidb0x8a0.RspBody.serializer()).msgKickResult!![0].optUint32Result == 1) + } + + class Response( + val success: Boolean + ) : Packet { + override fun toString(): String { + return "Response(Kick Member)" + } + } + + operator fun invoke( + client: QQAndroidClient, + member: Member, + message: String + ): OutgoingPacket { + return buildOutgoingUniPacket(client) { + writeProtoBuf( + OidbSso.OIDBSSOPkg.serializer(), + OidbSso.OIDBSSOPkg( + command = 2208, + serviceType = 0,//或者1 + result = 0, + bodybuffer = Oidb0x8a0.ReqBody( + optUint64GroupCode = member.group.id, + msgKickList = listOf( + Oidb0x8a0.KickMemberInfo( + optUint32Operate = 5, + optUint64MemberUin = member.id, + optUint32Flag = 1//或者0 + ) + ), + kickMsg = message.toByteArray() + ).toByteArray(Oidb0x8a0.ReqBody.serializer()) + ) + ) + } + } + + + } + internal object GroupOperation : OutgoingPacketFactory<GroupOperation.Response>("OidbSvc.0x89a_0") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { return Response diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt index 89888dbe3..5a4bcbc23 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt @@ -16,7 +16,7 @@ fun main() { println( File( """ - E:\Projects\QQAndroidFF\app\src\main\java\tencent\im\cs\cmd0x352 + /Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/oidb/cmd0x8a0/ """.trimIndent() ) .generateUnarrangedClasses().toMutableList().arrangeClasses().joinToString("\n\n") diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt index 684935dfc..0ae2d041c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt @@ -52,6 +52,7 @@ interface Member : QQ, Contact { */ suspend fun unmute(): Boolean + suspend fun kick(message: String = ""): Boolean /** * 当且仅当 `[other] is [Member] && [other].id == this.id && [other].group == this.group` 时为 true */