mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-24 14:30:09 +08:00
special title
This commit is contained in:
parent
a9502957ad
commit
da2e09855b
@ -67,7 +67,8 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin
|
||||
|
||||
internal class MemberImpl(
|
||||
qq: QQImpl,
|
||||
override var groupCard: String,
|
||||
initGroupCard: String,
|
||||
initSpecialTitle: String,
|
||||
group: GroupImpl,
|
||||
override val coroutineContext: CoroutineContext,
|
||||
override val permission: MemberPermission
|
||||
@ -75,6 +76,37 @@ internal class MemberImpl(
|
||||
override val group: GroupImpl by group.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 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 suspend fun mute(durationSeconds: Int): Boolean {
|
||||
|
@ -190,32 +190,18 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
initAnonymousChat = groupInfoResponse.allowAnonymousChat,
|
||||
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
|
||||
bot.groups.delegate.addLast(group)
|
||||
}
|
||||
coroutineScope {
|
||||
toGet.forEach {
|
||||
launch {
|
||||
try {
|
||||
getTroopMemberList(it.key, it.value, it.key.owner.id)
|
||||
groupInfo[it.key.id] = it.value.size
|
||||
} catch (e: Exception) {
|
||||
groupInfo[it.key.id] = -1
|
||||
bot.logger.info("群${it.key.uin}的列表拉取失败, 将采用动态加入")
|
||||
}
|
||||
launch {
|
||||
try {
|
||||
getTroopMemberList(group, contactList, it.dwGroupOwnerUin)
|
||||
groupInfo[it.groupCode] = contactList.size
|
||||
} catch (e: Exception) {
|
||||
groupInfo[it.groupCode] = -1
|
||||
bot.logger.info("群${it.groupCode}的列表拉取失败, 将采用动态加入")
|
||||
println(e.message)
|
||||
println(e.logStacktrace())
|
||||
}
|
||||
//delay(200)
|
||||
}
|
||||
}
|
||||
bot.logger.info("群组列表与群成员加载完成, 共 ${troopData.groups.size}个")
|
||||
@ -257,12 +243,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
|
||||
}
|
||||
|
||||
suspend fun getGroupInfo(uin: Long) {
|
||||
val data = TroopManagement.GetGroupOperationInfo(
|
||||
client = bot.client,
|
||||
groupCode = uin
|
||||
).sendAndExpect<TroopManagement.GetGroupOperationInfo.Response>(timeoutMillis = 3000)
|
||||
}
|
||||
|
||||
suspend fun getTroopMemberList(group: GroupImpl, list: ContactList<Member>, owner: Long): ContactList<Member> {
|
||||
bot.logger.info("开始获取群[${group.uin}]成员列表")
|
||||
@ -276,29 +256,29 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
nextUin = nextUin
|
||||
).sendAndExpect<FriendList.GetTroopMemberList.Response>(timeoutMillis = 3000)
|
||||
data.members.forEach {
|
||||
if (it.memberUin != bot.uin) {
|
||||
list.delegate.addLast(
|
||||
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 {
|
||||
group.owner.groupCard = it.autoRemark ?: it.nick
|
||||
if (it.dwFlag == 1L) {
|
||||
group.botPermission = MemberPermission.ADMINISTRATOR
|
||||
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) {
|
||||
list.delegate.addLast(member)
|
||||
} else {
|
||||
group.botPermission = member.permission
|
||||
}
|
||||
size += data.members.size
|
||||
nextUin = data.nextUin
|
||||
}
|
||||
size += data.members.size
|
||||
nextUin = data.nextUin
|
||||
if (nextUin == 0L) {
|
||||
break
|
||||
}
|
||||
|
@ -5,6 +5,78 @@ import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.qqandroid.io.ProtoBuf
|
||||
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
|
||||
class Oidb0x88d : ProtoBuf {
|
||||
@Serializable
|
||||
|
@ -125,7 +125,7 @@ internal object KnownPacketFactories {
|
||||
ImgStore.GroupPicUp,
|
||||
ImageUpPacket,
|
||||
LongConn.OffPicDown,
|
||||
TroopManagement.EditNametag,
|
||||
TroopManagement.EditSpecialTitle,
|
||||
TroopManagement.Mute,
|
||||
TroopManagement.GroupOperation,
|
||||
TroopManagement.GetGroupOperationInfo
|
||||
|
@ -4,6 +4,7 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.buildPacket
|
||||
import kotlinx.io.core.readBytes
|
||||
import kotlinx.io.core.toByteArray
|
||||
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
|
||||
@ -12,12 +13,12 @@ import net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||
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.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.login.LoginPacket
|
||||
import net.mamoe.mirai.utils.daysToSeconds
|
||||
|
||||
internal object TroopManagement {
|
||||
@ -272,9 +273,38 @@ internal object TroopManagement {
|
||||
}
|
||||
|
||||
|
||||
internal object EditNametag : OutgoingPacketFactory<LoginPacket.LoginPacketResponse>("OidbSvc.0x8fc_2") {
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacket.LoginPacketResponse {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
internal object EditSpecialTitle : OutgoingPacketFactory<EditSpecialTitle.Response>("OidbSvc.0x8fc_2") {
|
||||
object Response : Packet
|
||||
|
||||
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())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import java.io.File
|
||||
|
||||
fun main() {
|
||||
println(
|
||||
File("""/Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/oidb/""")
|
||||
File("""/Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/oidb/cmd0x8fc/""")
|
||||
.generateUnarrangedClasses().toMutableList().arrangeClasses().joinToString("\n\n")
|
||||
)
|
||||
}
|
||||
|
@ -22,10 +22,23 @@ interface Member : QQ, Contact {
|
||||
val permission: MemberPermission
|
||||
|
||||
/**
|
||||
* 群名片 (如果有) 或个人昵称. 动态更新.
|
||||
* ====以下字段会在更新后异步更新到服务器====
|
||||
*/
|
||||
|
||||
/**
|
||||
* 群名片
|
||||
*/
|
||||
var groupCard: String
|
||||
|
||||
/**
|
||||
* 群头衔
|
||||
*/
|
||||
var specialTitle: String
|
||||
|
||||
/**
|
||||
* ====以上字段会在更新后异步更新到服务器====
|
||||
*/
|
||||
|
||||
/**
|
||||
* 禁言
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user