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 a32d966ef..fb5de7b0b 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 @@ -82,9 +82,14 @@ internal class MemberImpl( "Permission Denied when trying to edit group card for $this" } if (group.botPermission != MemberPermission.MEMBER && new != old) { + launch { bot.network.run { - + TroopManagement.EditGroupNametag( + bot.client, + this@MemberImpl, + new + ).sendWithoutExpect() } } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt index 9b5f13501..693d7d7c8 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt @@ -90,7 +90,10 @@ fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrategy<T>): T /** * load */ -fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(serializer: DeserializationStrategy<T>, length: Int = this.remaining.toInt()): T { +fun <T : ProtoBuf> ByteReadPacket.readProtoBuf( + serializer: DeserializationStrategy<T>, + length: Int = this.remaining.toInt() +): T { return ProtoBufWithNullableSupport.load(serializer, this.readBytes(length)) } @@ -98,11 +101,20 @@ fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(serializer: DeserializationStrate * 构造 [RequestPacket] 的 [RequestPacket.sBuffer] */ fun <T : JceStruct> jceRequestSBuffer(name: String, serializer: SerializationStrategy<T>, jceStruct: T): ByteArray { + return jceRequestSBuffer(name, serializer, jceStruct, JceCharset.GBK) +} + +fun <T : JceStruct> jceRequestSBuffer( + name: String, + serializer: SerializationStrategy<T>, + jceStruct: T, + charset: JceCharset +): ByteArray { return RequestDataVersion3( mapOf( name to JCE_STRUCT_HEAD_OF_TAG_0 + jceStruct.toByteArray(serializer) + JCE_STRUCT_TAIL_OF_TAG_0 ) - ).toByteArray(RequestDataVersion3.serializer()) + ).toByteArray(RequestDataVersion3.serializer(), charset) } private val JCE_STRUCT_HEAD_OF_TAG_0 = byteArrayOf(0x0A) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt index 0e3529024..34d627b08 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt @@ -4,6 +4,25 @@ import kotlinx.serialization.SerialId import kotlinx.serialization.Serializable import net.mamoe.mirai.qqandroid.io.JceStruct +@Serializable +internal class ModifyGroupCardReq( + @SerialId(0) val dwZero: Long, + @SerialId(1) val dwGroupCode: Long, + @SerialId(2) val dwNewSeq: Long, + @SerialId(3) val vecUinInfo: List<stUinInfo> +) : JceStruct + +@Serializable +internal class stUinInfo( + @SerialId(0) val dwuin: Long, + @SerialId(1) val dwFlag: Long, + @SerialId(2) val sName: String = "", + @SerialId(3) val gender: Byte, + @SerialId(4) val sPhone: String = "", + @SerialId(5) val sEmail: String = "", + @SerialId(6) val sRemark: String = "" +) : JceStruct + @Serializable internal class GetFriendListReq( @SerialId(0) val reqtype: Int? = null, 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 8b147523d..0916806cd 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 @@ -128,7 +128,8 @@ internal object KnownPacketFactories { TroopManagement.EditSpecialTitle, TroopManagement.Mute, TroopManagement.GroupOperation, - TroopManagement.GetGroupOperationInfo + TroopManagement.GetGroupOperationInfo, + TroopManagement.EditGroupNametag ) 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 b77313acc..16f05b3c3 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 @@ -1,16 +1,18 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat -import kotlinx.io.core.ByteReadPacket -import kotlinx.io.core.buildPacket -import kotlinx.io.core.readBytes -import kotlinx.io.core.toByteArray +import kotlinx.io.charsets.Charset +import kotlinx.io.charsets.encode +import kotlinx.io.core.* +import kotlinx.serialization.toUtf8Bytes import net.mamoe.mirai.contact.Member import net.mamoe.mirai.data.Packet import net.mamoe.mirai.qqandroid.QQAndroidBot -import net.mamoe.mirai.qqandroid.io.serialization.loadAs -import net.mamoe.mirai.qqandroid.io.serialization.toByteArray -import net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf +import net.mamoe.mirai.qqandroid.io.serialization.* import net.mamoe.mirai.qqandroid.network.QQAndroidClient +import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetTroopListReqV2Simplify +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 @@ -20,6 +22,8 @@ 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.utils.daysToSeconds +import net.mamoe.mirai.utils.io.encodeToGBKString +import net.mamoe.mirai.utils.io.encodeToString internal object TroopManagement { @@ -316,6 +320,57 @@ internal object TroopManagement { } } + internal object EditGroupNametag : + OutgoingPacketFactory<EditGroupNametag.Response>("friendlist.ModifyGroupCardReq") { + object Response : Packet + + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): EditGroupNametag.Response { + return Response + } + + operator fun invoke( + client: QQAndroidClient, + member: Member, + newName: String + ): OutgoingPacket { + return buildOutgoingUniPacket(client) { + writeJceStruct( + RequestPacket.serializer(), + RequestPacket( + sFuncName = "ModifyGroupCardReq", + sServantName = "mqq.IMService.FriendListServiceServantObj", + iVersion = 3, + cPacketType = 0x00, + iMessageType = 0x00000, + iRequestId = client.nextRequestPacketRequestId(), + sBuffer = jceRequestSBuffer( + "MGCREQ", + ModifyGroupCardReq.serializer(), + ModifyGroupCardReq( + dwZero = 0L, + dwGroupCode = member.group.id, + dwNewSeq = 0L, + vecUinInfo = listOf( + stUinInfo( + gender = 0, + dwuin = member.id, + dwFlag = 31, + sName = newName.toUtf8Bytes().encodeToGBKString(), + sPhone = "", + sEmail = "", + sRemark = "" + ) + ) + ), + JceCharset.GBK + ) + ) + ) + } + } + + } + /* internal object Recall: OutgoingPacketFactory<LoginPacket.LoginPacketResponse>("wtlogin.login"){ override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacket.LoginPacketResponse { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt index 41d6ddcea..e304fccfd 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt @@ -2,6 +2,7 @@ package net.mamoe.mirai.utils.io +import kotlinx.io.charsets.Charset import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.String import kotlinx.io.core.use @@ -81,7 +82,11 @@ fun UByteArray.toUHexString(separator: String = " ", offset: Int = 0, length: In @Suppress("NOTHING_TO_INLINE") inline fun ByteArray.encodeToString(): String = String(this) -fun ByteArray.toReadPacket(offset: Int = 0, length: Int = this.size - offset) = ByteReadPacket(this, offset = offset, length = length) +fun ByteArray.encodeToGBKString(): String = String(this, 0, this.size, Charset.forName("GBK")) + + +fun ByteArray.toReadPacket(offset: Int = 0, length: Int = this.size - offset) = + ByteReadPacket(this, offset = offset, length = length) @UseExperimental(ExperimentalContracts::class) inline fun <R> ByteArray.read(t: ByteReadPacket.() -> R): R {