Commit 1457254e authored by ryoii's avatar ryoii

Merge remote-tracking branch 'upstream/master'

parents 7cc0dea2 e43a5176
...@@ -67,7 +67,8 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin ...@@ -67,7 +67,8 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin
internal class MemberImpl( internal class MemberImpl(
qq: QQImpl, qq: QQImpl,
override var groupCard: String, initGroupCard: String,
initSpecialTitle: String,
group: GroupImpl, group: GroupImpl,
override val coroutineContext: CoroutineContext, override val coroutineContext: CoroutineContext,
override val permission: MemberPermission override val permission: MemberPermission
...@@ -75,6 +76,42 @@ internal class MemberImpl( ...@@ -75,6 +76,42 @@ internal class MemberImpl(
override val group: GroupImpl by group.unsafeWeakRef() override val group: GroupImpl by group.unsafeWeakRef()
val qq: QQImpl by qq.unsafeWeakRef() val qq: QQImpl by qq.unsafeWeakRef()
override var groupCard: String by Delegates.observable(initGroupCard) { _, old, new ->
check(group.botPermission != MemberPermission.MEMBER) {
"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()
}
}
}
}
override var specialTitle: String by Delegates.observable(initSpecialTitle) { _, old, new ->
check(group.botPermission == MemberPermission.OWNER) {
"Permission Denied when trying to edit special title for $this, need to be OWNER"
}
if (new != old) {
launch {
bot.network.run {
TroopManagement.EditSpecialTitle(
bot.client,
this@MemberImpl,
new
).sendWithoutExpect()
}
}
}
}
override val bot: QQAndroidBot get() = qq.bot override val bot: QQAndroidBot get() = qq.bot
override suspend fun mute(durationSeconds: Int): Boolean { override suspend fun mute(durationSeconds: Int): Boolean {
...@@ -139,7 +176,7 @@ internal class GroupImpl( ...@@ -139,7 +176,7 @@ internal class GroupImpl(
if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) { if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) {
this.bot.launch { this.bot.launch {
bot.network.run { bot.network.run {
TroopManagement.updateGroupInfo.name( TroopManagement.GroupOperation.name(
client = bot.client, client = bot.client,
groupCode = id, groupCode = id,
newName = newValue newName = newValue
...@@ -153,7 +190,7 @@ internal class GroupImpl( ...@@ -153,7 +190,7 @@ internal class GroupImpl(
if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) { if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) {
this.bot.launch { this.bot.launch {
bot.network.run { bot.network.run {
TroopManagement.updateGroupInfo.memo( TroopManagement.GroupOperation.memo(
client = bot.client, client = bot.client,
groupCode = id, groupCode = id,
newMemo = newValue newMemo = newValue
...@@ -168,7 +205,7 @@ internal class GroupImpl( ...@@ -168,7 +205,7 @@ internal class GroupImpl(
if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) { if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) {
this.bot.launch { this.bot.launch {
bot.network.run { bot.network.run {
TroopManagement.updateGroupInfo.allowMemberInvite( TroopManagement.GroupOperation.allowMemberInvite(
client = bot.client, client = bot.client,
groupCode = id, groupCode = id,
switch = newValue switch = newValue
...@@ -190,7 +227,7 @@ internal class GroupImpl( ...@@ -190,7 +227,7 @@ internal class GroupImpl(
if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) { if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) {
this.bot.launch { this.bot.launch {
bot.network.run { bot.network.run {
TroopManagement.updateGroupInfo.confessTalk( TroopManagement.GroupOperation.confessTalk(
client = bot.client, client = bot.client,
groupCode = id, groupCode = id,
switch = newValue switch = newValue
...@@ -205,7 +242,7 @@ internal class GroupImpl( ...@@ -205,7 +242,7 @@ internal class GroupImpl(
if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) { if (this.botPermission != MemberPermission.MEMBER && oldValue != newValue) {
this.bot.launch { this.bot.launch {
bot.network.run { bot.network.run {
TroopManagement.updateGroupInfo.muteAll( TroopManagement.GroupOperation.muteAll(
client = bot.client, client = bot.client,
groupCode = id, groupCode = id,
switch = newValue switch = newValue
......
...@@ -90,7 +90,10 @@ fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrategy<T>): T ...@@ -90,7 +90,10 @@ fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrategy<T>): T
/** /**
* load * 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)) return ProtoBufWithNullableSupport.load(serializer, this.readBytes(length))
} }
...@@ -98,11 +101,20 @@ fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(serializer: DeserializationStrate ...@@ -98,11 +101,20 @@ fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(serializer: DeserializationStrate
* 构造 [RequestPacket] 的 [RequestPacket.sBuffer] * 构造 [RequestPacket] 的 [RequestPacket.sBuffer]
*/ */
fun <T : JceStruct> jceRequestSBuffer(name: String, serializer: SerializationStrategy<T>, jceStruct: T): ByteArray { 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( return RequestDataVersion3(
mapOf( mapOf(
name to JCE_STRUCT_HEAD_OF_TAG_0 + jceStruct.toByteArray(serializer) + JCE_STRUCT_TAIL_OF_TAG_0 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) private val JCE_STRUCT_HEAD_OF_TAG_0 = byteArrayOf(0x0A)
......
...@@ -161,6 +161,20 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -161,6 +161,20 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
val toGet: MutableMap<GroupImpl, ContactList<Member>> = mutableMapOf() val toGet: MutableMap<GroupImpl, ContactList<Member>> = mutableMapOf()
troopData.groups.forEach { troopData.groups.forEach {
val contactList = ContactList(LockFreeLinkedList<Member>()) val contactList = ContactList(LockFreeLinkedList<Member>())
val groupInfoResponse = try {
TroopManagement.GetGroupOperationInfo(
client = bot.client,
groupCode = it.groupCode
).sendAndExpect<TroopManagement.GetGroupOperationInfo.Response>()
} catch (e: Exception) {
bot.logger.info("获取" + it.groupCode + "的群设置失败")
TroopManagement.GetGroupOperationInfo.Response(
allowAnonymousChat = false,
allowMemberInvite = false,
autoApprove = false,
confessTalk = false
)
}
val group = val group =
GroupImpl( GroupImpl(
bot = bot, bot = bot,
...@@ -169,39 +183,25 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -169,39 +183,25 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
uin = it.groupUin, uin = it.groupUin,
initName = it.groupName, initName = it.groupName,
initAnnouncement = it.groupMemo, initAnnouncement = it.groupMemo,
initAllowMemberInvite = false, initAllowMemberInvite = groupInfoResponse.allowMemberInvite,
initConfessTalk = false, initConfessTalk = groupInfoResponse.confessTalk,
initMuteAll = false, initMuteAll = false,//todo
initAutoApprove = false, initAutoApprove = groupInfoResponse.autoApprove,
initAnonymousChat = false, initAnonymousChat = groupInfoResponse.allowAnonymousChat,
members = contactList members = contactList
) )
group.owner =
MemberImpl(
qq = bot.QQ(it.dwGroupOwnerUin) as QQImpl,
groupCard = "",//unknown now
group = group,
coroutineContext = group.coroutineContext,
permission = MemberPermission.OWNER
)
if (it.dwGroupOwnerUin == bot.uin) {
group.botPermission = MemberPermission.OWNER
}
toGet[group] = contactList toGet[group] = contactList
bot.groups.delegate.addLast(group) bot.groups.delegate.addLast(group)
} launch {
coroutineScope { try {
toGet.forEach { getTroopMemberList(group, contactList, it.dwGroupOwnerUin)
launch { groupInfo[it.groupCode] = contactList.size
try { } catch (e: Exception) {
getTroopMemberList(it.key, it.value, it.key.owner.id) groupInfo[it.groupCode] = -1
groupInfo[it.key.id] = it.value.size bot.logger.info("群${it.groupCode}的列表拉取失败, 将采用动态加入")
} catch (e: Exception) { println(e.message)
groupInfo[it.key.id] = -1 println(e.logStacktrace())
bot.logger.info("群${it.key.uin}的列表拉取失败, 将采用动态加入")
}
} }
//delay(200)
} }
} }
bot.logger.info("群组列表与群成员加载完成, 共 ${troopData.groups.size}个") bot.logger.info("群组列表与群成员加载完成, 共 ${troopData.groups.size}个")
...@@ -243,12 +243,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -243,12 +243,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect() MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
} }
suspend fun getGroupInfo(uin: Long) {
val data = TroopManagement.getGroupInfo(
client = bot.client,
groupCode = uin
).sendAndExpect<TroopManagement.getGroupInfo.Response>(timeoutMillis = 3000)
}
suspend fun getTroopMemberList(group: GroupImpl, list: ContactList<Member>, owner: Long): ContactList<Member> { suspend fun getTroopMemberList(group: GroupImpl, list: ContactList<Member>, owner: Long): ContactList<Member> {
bot.logger.info("开始获取群[${group.uin}]成员列表") bot.logger.info("开始获取群[${group.uin}]成员列表")
...@@ -262,29 +256,29 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -262,29 +256,29 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
nextUin = nextUin nextUin = nextUin
).sendAndExpect<FriendList.GetTroopMemberList.Response>(timeoutMillis = 3000) ).sendAndExpect<FriendList.GetTroopMemberList.Response>(timeoutMillis = 3000)
data.members.forEach { data.members.forEach {
val member = MemberImpl(
qq = bot.QQ(it.memberUin) as QQImpl,
initGroupCard = it.autoRemark ?: it.nick,
initSpecialTitle = it.sSpecialTitle ?: "",
group = group,
coroutineContext = group.coroutineContext,
permission = when {
it.memberUin == owner -> MemberPermission.OWNER
it.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
else -> MemberPermission.MEMBER
}
)
if (member.permission == MemberPermission.OWNER) {
group.owner = member
}
if (it.memberUin != bot.uin) { if (it.memberUin != bot.uin) {
list.delegate.addLast( list.delegate.addLast(member)
MemberImpl(
qq = bot.QQ(it.memberUin) as QQImpl,
groupCard = it.autoRemark ?: it.nick,
group = group,
coroutineContext = group.coroutineContext,
permission = when {
it.memberUin == owner -> MemberPermission.OWNER
it.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
else -> MemberPermission.MEMBER
}
)
)
} else { } else {
group.owner.groupCard = it.autoRemark ?: it.nick group.botPermission = member.permission
if (it.dwFlag == 1L) {
group.botPermission = MemberPermission.ADMINISTRATOR
}
} }
size += data.members.size
nextUin = data.nextUin
} }
size += data.members.size
nextUin = data.nextUin
if (nextUin == 0L) { if (nextUin == 0L) {
break break
} }
......
...@@ -4,6 +4,25 @@ import kotlinx.serialization.SerialId ...@@ -4,6 +4,25 @@ import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.io.JceStruct 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 @Serializable
internal class GetFriendListReq( internal class GetFriendListReq(
@SerialId(0) val reqtype: Int? = null, @SerialId(0) val reqtype: Int? = null,
......
...@@ -5,6 +5,78 @@ import kotlinx.serialization.Serializable ...@@ -5,6 +5,78 @@ import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.io.ProtoBuf import net.mamoe.mirai.qqandroid.io.ProtoBuf
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
@Serializable
class Oidb0x8fc : ProtoBuf {
@Serializable
class CardNameElem(
@SerialId(1) val enumCardType: Int /* enum */ = 1,
@SerialId(2) val value: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
class CommCardNameBuf(
@SerialId(1) val richCardName: List<Oidb0x8fc.RichCardNameElem>? = null
) : ProtoBuf
@Serializable
class ReqBody(
@SerialId(1) val groupCode: Long = 0L,
@SerialId(2) val showFlag: Int = 0,
@SerialId(3) val memLevelInfo: List<Oidb0x8fc.MemberInfo>? = null,
@SerialId(4) val levelName: List<Oidb0x8fc.LevelName>? = null,
@SerialId(5) val updateTime: Int = 0,
@SerialId(6) val officeMode: Int = 0,
@SerialId(7) val groupOpenAppid: Int = 0,
@SerialId(8) val msgClientInfo: Oidb0x8fc.ClientInfo? = null,
@SerialId(9) val authKey: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
class MemberInfo(
@SerialId(1) val uin: Long = 0L,
@SerialId(2) val point: Int = 0,
@SerialId(3) val activeDay: Int = 0,
@SerialId(4) val level: Int = 0,
@SerialId(5) val specialTitle: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(6) val specialTitleExpireTime: Int = 0,
@SerialId(7) val uinName: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(8) val memberCardName: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(9) val phone: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(10) val email: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(11) val remark: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(12) val gender: Int = 0,
@SerialId(13) val job: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(14) val tribeLevel: Int = 0,
@SerialId(15) val tribePoint: Int = 0,
@SerialId(16) val richCardName: List<Oidb0x8fc.CardNameElem>? = null,
@SerialId(17) val commRichCardName: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
class RichCardNameElem(
@SerialId(1) val ctrl: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(2) val text: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
class RspBody(
@SerialId(1) val groupCode: Long = 0L,
@SerialId(2) val errInfo: String = ""
) : ProtoBuf
@Serializable
class ClientInfo(
@SerialId(1) val implat: Int = 0,
@SerialId(2) val ingClientver: String = ""
) : ProtoBuf
@Serializable
class LevelName(
@SerialId(1) val level: Int = 0,
@SerialId(2) val name: String = ""
) : ProtoBuf
}
@Serializable @Serializable
class Oidb0x88d : ProtoBuf { class Oidb0x88d : ProtoBuf {
@Serializable @Serializable
......
...@@ -125,10 +125,11 @@ internal object KnownPacketFactories { ...@@ -125,10 +125,11 @@ internal object KnownPacketFactories {
ImgStore.GroupPicUp, ImgStore.GroupPicUp,
ImageUpPacket, ImageUpPacket,
LongConn.OffPicDown, LongConn.OffPicDown,
TroopManagement.EditNametag, TroopManagement.EditSpecialTitle,
TroopManagement.Mute, TroopManagement.Mute,
TroopManagement.updateGroupInfo, TroopManagement.GroupOperation,
TroopManagement.getGroupInfo TroopManagement.GetGroupOperationInfo,
TroopManagement.EditGroupNametag
) )
object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf( object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf(
......
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat package net.mamoe.mirai.qqandroid.network.protocol.packet.chat
import kotlinx.io.core.ByteReadPacket import kotlinx.io.charsets.Charset
import kotlinx.io.core.buildPacket import kotlinx.io.charsets.encode
import kotlinx.io.core.readBytes import kotlinx.io.core.*
import kotlinx.io.core.toByteArray import kotlinx.serialization.toUtf8Bytes
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.data.Packet import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.io.serialization.toByteArray import net.mamoe.mirai.qqandroid.io.serialization.*
import net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf
import net.mamoe.mirai.qqandroid.network.QQAndroidClient 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.Oidb0x88d
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Oidb0x89a 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.OidbSso
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY 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.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory 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.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
import net.mamoe.mirai.utils.daysToSeconds import net.mamoe.mirai.utils.daysToSeconds
import net.mamoe.mirai.utils.io.debugPrintThis import net.mamoe.mirai.utils.io.encodeToGBKString
import net.mamoe.mirai.utils.io.encodeToString
internal object TroopManagement { internal object TroopManagement {
...@@ -54,13 +59,25 @@ internal object TroopManagement { ...@@ -54,13 +59,25 @@ internal object TroopManagement {
} }
} }
object Response : Packet object Response : Packet {
override fun toString(): String {
return "Response(Mute)"
}
}
} }
internal object getGroupInfo : OutgoingPacketFactory<getGroupInfo.Response>("OidbSvc.0x88d_7") { internal object GetGroupOperationInfo : OutgoingPacketFactory<GetGroupOperationInfo.Response>("OidbSvc.0x88d_7") {
class Response(
class Response() : Packet val allowAnonymousChat: Boolean,
val allowMemberInvite: Boolean,
val autoApprove: Boolean,
val confessTalk: Boolean
) : Packet {
override fun toString(): String {
return "Response(GroupInfo)"
}
}
operator fun invoke( operator fun invoke(
client: QQAndroidClient, client: QQAndroidClient,
...@@ -104,12 +121,18 @@ internal object TroopManagement { ...@@ -104,12 +121,18 @@ internal object TroopManagement {
} }
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
debugPrintThis() with(this.readBytes().loadAs(OidbSso.OIDBSSOPkg.serializer()).bodybuffer.loadAs(Oidb0x88d.RspBody.serializer()).stzrspgroupinfo!![0].stgroupinfo!!) {
return Response() return Response(
allowMemberInvite = (this.groupFlagExt?.and(0x000000c0) != 0),
allowAnonymousChat = (this.groupFlagExt?.and(0x40000000) == 0),
autoApprove = (this.groupFlagext3?.and(0x00100000) == 0),
confessTalk = (this.groupFlagext3?.and(0x00002000) == 0)
)
}
} }
} }
internal object updateGroupInfo : OutgoingPacketFactory<updateGroupInfo.Response>("OidbSvc.0x89a_0") { internal object GroupOperation : OutgoingPacketFactory<GroupOperation.Response>("OidbSvc.0x89a_0") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
return Response return Response
} }
...@@ -262,10 +285,90 @@ internal object TroopManagement { ...@@ -262,10 +285,90 @@ internal object TroopManagement {
} }
internal object EditNametag : OutgoingPacketFactory<LoginPacket.LoginPacketResponse>("OidbSvc.0x8fc_2") { internal object EditSpecialTitle : OutgoingPacketFactory<EditSpecialTitle.Response>("OidbSvc.0x8fc_2") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacket.LoginPacketResponse { object Response : Packet
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
return Response
} }
operator fun invoke(
client: QQAndroidClient,
member: Member,
newName: String
): OutgoingPacket {
return buildOutgoingUniPacket(client) {
writeProtoBuf(
OidbSso.OIDBSSOPkg.serializer(),
OidbSso.OIDBSSOPkg(
command = 2300,
serviceType = 2,
bodybuffer = Oidb0x8fc.ReqBody(
groupCode = member.group.id,
memLevelInfo = listOf(
Oidb0x8fc.MemberInfo(
uin = member.id,
uinName = newName.toByteArray(),
specialTitle = newName.toByteArray(),
specialTitleExpireTime = -1
)
)
).toByteArray(Oidb0x8fc.ReqBody.serializer())
)
)
}
}
}
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
)
)
)
}
}
} }
/* /*
......
...@@ -6,7 +6,7 @@ import java.io.File ...@@ -6,7 +6,7 @@ import java.io.File
fun main() { fun main() {
println( println(
File("""/Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/oidb/cmd0x88d/""") File("""/Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/oidb/cmd0x8fc/""")
.generateUnarrangedClasses().toMutableList().arrangeClasses().joinToString("\n\n") .generateUnarrangedClasses().toMutableList().arrangeClasses().joinToString("\n\n")
) )
} }
......
...@@ -22,10 +22,23 @@ interface Member : QQ, Contact { ...@@ -22,10 +22,23 @@ interface Member : QQ, Contact {
val permission: MemberPermission val permission: MemberPermission
/** /**
* 群名片 (如果有) 或个人昵称. 动态更新. * ====以下字段会在更新后异步更新到服务器====
*/
/**
* 群名片
*/ */
var groupCard: String var groupCard: String
/**
* 群头衔
*/
var specialTitle: String
/**
* ====以上字段会在更新后异步更新到服务器====
*/
/** /**
* 禁言 * 禁言
* *
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
package net.mamoe.mirai.utils.io package net.mamoe.mirai.utils.io
import kotlinx.io.charsets.Charset
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.String import kotlinx.io.core.String
import kotlinx.io.core.use import kotlinx.io.core.use
...@@ -81,7 +82,11 @@ fun UByteArray.toUHexString(separator: String = " ", offset: Int = 0, length: In ...@@ -81,7 +82,11 @@ fun UByteArray.toUHexString(separator: String = " ", offset: Int = 0, length: In
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun ByteArray.encodeToString(): String = String(this) 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) @UseExperimental(ExperimentalContracts::class)
inline fun <R> ByteArray.read(t: ByteReadPacket.() -> R): R { inline fun <R> ByteArray.read(t: ByteReadPacket.() -> R): R {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment