diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index 541776e8a..a0f259eb5 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt @@ -371,6 +371,15 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { break } } + bot.network.run { + val resp = + TroopManagement.GetAdmin(bot.client, groupCode).sendAndExpect<TroopManagement.GetAdmin.Response>() + check(resp is TroopManagement.GetAdmin.Response.Success) { "Failed to get admin info" } + sequence.filter { member -> member.permission == MemberPermission.MEMBER && resp.memberList.any { member.uin == it.memberUin } } + .forEach { memberInfoImpl -> + memberInfoImpl.permission = MemberPermission.ADMINISTRATOR + } + } return sequence } diff --git a/mirai-core/src/commonMain/kotlin/contact/info/MemberInfoImpl.kt b/mirai-core/src/commonMain/kotlin/contact/info/MemberInfoImpl.kt index 3c653670f..809b37d02 100644 --- a/mirai-core/src/commonMain/kotlin/contact/info/MemberInfoImpl.kt +++ b/mirai-core/src/commonMain/kotlin/contact/info/MemberInfoImpl.kt @@ -37,9 +37,10 @@ internal data class MemberInfoImpl( ) : this( uin = jceInfo.memberUin, nick = jceInfo.nick, - permission = when { - jceInfo.memberUin == groupOwnerId -> MemberPermission.OWNER - jceInfo.dwFlag == 1L -> MemberPermission.ADMINISTRATOR + // 管理员将在 MiraiImpl.kt:359 + // TroopManagement.GetAdmin 处理 + permission = when (jceInfo.memberUin) { + groupOwnerId -> MemberPermission.OWNER else -> MemberPermission.MEMBER }, remark = jceInfo.autoRemark.orEmpty(), diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/OIDB.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/OIDB.kt index b5c0d241d..cabc87e17 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/OIDB.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/OIDB.kt @@ -482,6 +482,61 @@ internal class Oidb0x88d : ProtoBuf { ) : ProtoBuf } +internal class Oidb0x899 : ProtoBuf { + @Serializable + internal class ReqBody( + @JvmField @ProtoNumber(1) val groupCode: Long = 0L, + @JvmField @ProtoNumber(2) val startUin: Long = 0L, + @JvmField @ProtoNumber(3) val identifyFlag: Int = 0, + @JvmField @ProtoNumber(4) val uinList: List<Long> = emptyList(), + @JvmField @ProtoNumber(5) val memberListOpt: MemberList? = null, + @JvmField @ProtoNumber(6) val memberNum: Int = 0, + @JvmField @ProtoNumber(7) val filterMethod: Int = 0, + @JvmField @ProtoNumber(8) val onlineFlag: Int = 0 + ) : ProtoBuf + + @Serializable + internal class RspBody( + @JvmField @ProtoNumber(1) val groupCode: Long = 0L, + @JvmField @ProtoNumber(2) val startUin: Long = 0L, + @JvmField @ProtoNumber(3) val identifyFlag: Int = 0, + @JvmField @ProtoNumber(4) val memberList: List<MemberList> = emptyList(), + @JvmField @ProtoNumber(5) val errorInfo: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class MemberList( + @JvmField @ProtoNumber(1) val memberUin: Long = 0L, + @JvmField @ProtoNumber(2) val uinFlag: Int = 0, + @JvmField @ProtoNumber(3) val uinFlagExt: Int = 0, + @JvmField @ProtoNumber(4) val uinMobileFlag: Int = 0, + @JvmField @ProtoNumber(5) val uinArchFlag: Int = 0, + @JvmField @ProtoNumber(6) val joinTime: Int = 0, + @JvmField @ProtoNumber(7) val oldMsgSeq: Int = 0, + @JvmField @ProtoNumber(8) val newMsgSeq: Int = 0, + @JvmField @ProtoNumber(9) val lastSpeakTime: Int = 0, + @JvmField @ProtoNumber(10) val level: Int = 0, + @JvmField @ProtoNumber(11) val point: Int = 0, + @JvmField @ProtoNumber(12) val muteTimestamp: Int = 0, + @JvmField @ProtoNumber(13) val flagExt2: Int = 0, + @JvmField @ProtoNumber(14) val specialTitle: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(15) val specialTitleExpireTime: Int = 0, + @JvmField @ProtoNumber(16) val activeDay: Int = 0, + @JvmField @ProtoNumber(17) val uinKey: ByteArray = EMPTY_BYTE_ARRAY, + @JvmField @ProtoNumber(18) val privilege: Int = 0, + @JvmField @ProtoNumber(19) val richInfo: ByteArray = EMPTY_BYTE_ARRAY + ) : ProtoBuf + + @Serializable + internal class UinKey( + @JvmField @ProtoNumber(1) val groupCode: Long = 0L, + @JvmField @ProtoNumber(2) val memberUin: Long = 0L, + @JvmField @ProtoNumber(3) val genTime: Long = 0L, + @JvmField @ProtoNumber(4) val validTime: Int = 0, + @JvmField @ProtoNumber(5) val randNum: Int = 0 + ) : ProtoBuf +} + @Serializable internal class Oidb0x89a : ProtoBuf { @Serializable diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt index f21ae7d84..66d28fe9d 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt @@ -149,6 +149,7 @@ internal object KnownPacketFactories { TroopManagement.GroupOperation, TroopManagement.GetTroopConfig, TroopManagement.ModifyAdmin, + TroopManagement.GetAdmin, // TroopManagement.GetGroupInfo, TroopManagement.EditGroupNametag, TroopManagement.Kick, diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt index ebe0b279f..c43b671e9 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt @@ -30,6 +30,7 @@ import net.mamoe.mirai.internal.utils.io.serialization.* import net.mamoe.mirai.utils.daysToSeconds internal class TroopManagement { + internal object Mute : OutgoingPacketFactory<Mute.Response>("OidbSvc.0x570_8") { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { //屁用没有 @@ -67,7 +68,6 @@ internal class TroopManagement { } } - internal object GetGroupInfo : OutgoingPacketFactory<GroupInfoImpl>("OidbSvc.0x88d_7") { @Deprecated("") operator fun invoke( @@ -419,4 +419,52 @@ internal class TroopManagement { } } -} \ No newline at end of file + + internal object GetAdmin : OutgoingPacketFactory<GetAdmin.Response>("OidbSvc.0x899_9") { + operator fun invoke( + client: QQAndroidClient, + groupCode: Long + ): OutgoingPacket = buildOutgoingUniPacket(client) { + writeProtoBuf( + OidbSso.OIDBSSOPkg.serializer(), + OidbSso.OIDBSSOPkg( + command = 2201, + serviceType = 1, + result = 0, + bodybuffer = Oidb0x899.ReqBody( + identifyFlag = 2, + groupCode = groupCode, + startUin = 0, + memberListOpt = Oidb0x899.MemberList( + memberUin = 0, + privilege = 1 + ) + ).toByteArray(Oidb0x899.ReqBody.serializer()) + ) + ) + } + + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { + return readProtoBuf(OidbSso.OIDBSSOPkg.serializer()).let { oidbssoPkg -> + if (oidbssoPkg.result == 0) { + oidbssoPkg.bodybuffer.loadAs(Oidb0x899.RspBody.serializer()).let { resp -> + Response.Success(resp.memberList) + } + } else { + Response.Failed(oidbssoPkg.result, oidbssoPkg.errorMsg) + } + } + + } + + sealed class Response : Packet { + class Failed(val code: Int, val msg: String) : Response() { + override fun toString(): String = "GetAdmin.Response.Failed(code=$code, msg=$msg)" + } + + class Success(val memberList: List<Oidb0x899.MemberList>) : Response() { + override fun toString(): String = "GetAdmin.Response.Success" + } + } + } +}