diff --git a/qqinterface/src/main/java/tencent/im/group/group_member_info.java b/qqinterface/src/main/java/tencent/im/group/group_member_info.java new file mode 100644 index 0000000..1ffbe76 --- /dev/null +++ b/qqinterface/src/main/java/tencent/im/group/group_member_info.java @@ -0,0 +1,326 @@ +package tencent.im.group; + +import com.tencent.mobileqq.pb.ByteStringMicro; +import com.tencent.mobileqq.pb.MessageMicro; +import com.tencent.mobileqq.pb.PBBoolField; +import com.tencent.mobileqq.pb.PBBytesField; +import com.tencent.mobileqq.pb.PBField; +import com.tencent.mobileqq.pb.PBRepeatField; +import com.tencent.mobileqq.pb.PBRepeatMessageField; +import com.tencent.mobileqq.pb.PBStringField; +import com.tencent.mobileqq.pb.PBUInt32Field; +import com.tencent.mobileqq.pb.PBUInt64Field; + +public class group_member_info { + public static class CustomEntry extends MessageMicro { + static final FieldMap __fieldMap__; + + public final PBBoolField bool_clicked; + + public final PBBytesField str_name; + + public final PBBytesField str_url; + + public final PBBytesField str_value; + + public final PBUInt64Field uint64_report_id; + + static { + ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY; + Boolean bool = Boolean.FALSE; + __fieldMap__ = MessageMicro.initFieldMap(new int[] { 10, 18, 24, 34, 40 }, new String[] { "str_name", "str_value", "bool_clicked", "str_url", "uint64_report_id" }, new Object[] { byteStringMicro, byteStringMicro, bool, byteStringMicro, Long.valueOf(0L) }, tencent.im.group.group_member_info.CustomEntry.class); + } + + public CustomEntry() { + ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY; + this.str_name = PBField.initBytes(byteStringMicro); + this.str_value = PBField.initBytes(byteStringMicro); + this.bool_clicked = PBField.initBool(false); + this.str_url = PBField.initBytes(byteStringMicro); + this.uint64_report_id = PBField.initUInt64(0L); + } + } + + public static class ErrorInfo extends MessageMicro { + static final FieldMap __fieldMap__; + + public final PBUInt32Field error_code = PBField.initUInt32(0); + + public final PBBytesField error_desc = PBField.initBytes(ByteStringMicro.EMPTY); + + static { + ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY; + __fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 18 }, new String[] { "error_code", "error_desc" }, new Object[] { Integer.valueOf(0), byteStringMicro }, tencent.im.group.group_member_info.ErrorInfo.class); + } + } + + public static class FlowersEntry extends MessageMicro { + static final FieldMap __fieldMap__ = MessageMicro.initFieldMap(new int[] { 8 }, new String[] { "uint64_flower_count" }, new Object[] { Long.valueOf(0L) }, tencent.im.group.group_member_info.FlowersEntry.class); + + public final PBUInt64Field uint64_flower_count = PBField.initUInt64(0L); + } + + public static class GBarInfo extends MessageMicro { + static final FieldMap __fieldMap__; + + public final PBBytesField bytes_gbar_name; + + public final PBBytesField str_head_portrait; + + public final PBUInt32Field uint32_gbar_id = PBField.initUInt32(0); + + public final PBUInt32Field uint32_uin_lev = PBField.initUInt32(0); + + static { + Integer integer = Integer.valueOf(0); + ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY; + __fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 26, 34 }, new String[] { "uint32_gbar_id", "uint32_uin_lev", "str_head_portrait", "bytes_gbar_name" }, new Object[] { integer, integer, byteStringMicro, byteStringMicro }, tencent.im.group.group_member_info.GBarInfo.class); + } + + public GBarInfo() { + ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY; + this.str_head_portrait = PBField.initBytes(byteStringMicro); + this.bytes_gbar_name = PBField.initBytes(byteStringMicro); + } + } + + public static class MemberGameInfo extends MessageMicro { + static final FieldMap __fieldMap__ = MessageMicro.initFieldMap(new int[] { 10, 18, 26, 34, 42, 50, 58 }, new String[] { "str_game_name", "str_level_name", "str_level_icon", "str_game_font_color", "str_game_background_color", "str_game_url", "str_desc_info" }, new Object[] { "", "", "", "", "", "", "" }, tencent.im.group.group_member_info.MemberGameInfo.class); + + public final PBRepeatField str_desc_info = PBField.initRepeat(PBField.initString("")); + + public final PBStringField str_game_background_color = PBField.initString(""); + + public final PBStringField str_game_font_color = PBField.initString(""); + + public final PBStringField str_game_name = PBField.initString(""); + + public final PBStringField str_game_url = PBField.initString(""); + + public final PBStringField str_level_icon = PBField.initString(""); + + public final PBStringField str_level_name = PBField.initString(""); + } + + + public static class MemberInfo extends MessageMicro { + public static final int CONCERN_TYPE_CONCERN = 1; + + public static final int CONCERN_TYPE_GENERAL = 0; + + public static final int CONCERN_TYPE_HATE = 2; + + static final FieldMap __fieldMap__; + + public final PBBoolField bool_is_allow_mod_card; + + public final PBBoolField bool_is_concerned; + + public final PBBoolField bool_is_friend; + + public final PBBoolField bool_is_super_qq; + + public final PBBoolField bool_is_super_vip; + + public final PBBoolField bool_is_vip; + + public final PBBoolField bool_is_year_vip; + + public final PBBoolField bool_location_shared; + + public final PBBytesField bytes_group_honor; + + public final PBBytesField bytes_job; + + public final PBBytesField bytes_phone_num; + + public final PBBytesField bytes_special_title; + + public final PBUInt32Field medal_id; + + public tencent.im.group.group_member_info.FlowersEntry msg_flower_entry; + + public tencent.im.group.group_member_info.MemberGameInfo msg_game_info; + + public group_member_info.TeamEntry msg_team_entry; + +// public group_member_info.RspGroupCardGetStory qqstory_infocard; + + public final PBRepeatMessageField rpt_msg_custom_enties; + + public final PBRepeatMessageField rpt_msg_gbar_concerned; + + public final PBBytesField str_card; + + public final PBBytesField str_errmsg; + + public final PBBytesField str_gbar_title; + + public final PBBytesField str_gbar_url; + + public final PBBytesField str_lev; + + public final PBBytesField str_location; + + public final PBBytesField str_nick; + + public final PBBytesField str_remark; + + public final PBUInt32Field uint32_age; + + public final PBUInt32Field uint32_concern_type; + + public final PBUInt32Field uint32_credit; + + public final PBUInt32Field uint32_gbar_cnt; + + public final PBUInt32Field uint32_group_honor_bit; + + public final PBUInt32Field uint32_level; + + public final PBUInt32Field uint32_result = PBField.initUInt32(0); + + public final PBUInt32Field uint32_role; + + public final PBUInt32Field uint32_sex; + + public final PBUInt32Field uint32_special_title_expire_time; + + public final PBUInt32Field uint32_vip_lev; + + public final PBUInt64Field uint64_distance; + + public final PBUInt64Field uint64_join; + + public final PBUInt64Field uint64_last_speak; + + public final PBUInt64Field uint64_uin = PBField.initUInt64(0L); + + static { + Long long_ = Long.valueOf(0L); + Integer integer = Integer.valueOf(0); + ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY; + Boolean bool = Boolean.FALSE; + __fieldMap__ = MessageMicro.initFieldMap(new int[] { + 8, 16, 26, 32, 42, 48, 56, 66, 72, 82, + 90, 96, 106, 112, 120, 130, 138, 146, 154, 160, + 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, + 250, 256, 266, 274, 282, 290, 296, 306, 312, 322, + 330, 336 }, new String[] { + "uint64_uin", "uint32_result", "str_errmsg", "bool_is_friend", "str_remark", "bool_is_concerned", "uint32_credit", "str_card", "uint32_sex", "str_location", + "str_nick", "uint32_age", "str_lev", "uint64_join", "uint64_last_speak", "rpt_msg_custom_enties", "rpt_msg_gbar_concerned", "str_gbar_title", "str_gbar_url", "uint32_gbar_cnt", + "bool_is_allow_mod_card", "bool_is_vip", "bool_is_year_vip", "bool_is_super_vip", "bool_is_super_qq", "uint32_vip_lev", "uint32_role", "bool_location_shared", "uint64_distance", "uint32_concern_type", + "bytes_special_title", "uint32_special_title_expire_time", "msg_flower_entry", "msg_team_entry", "bytes_phone_num", "bytes_job", "medal_id", "qqstory_infocard", "uint32_level", "msg_game_info", + "bytes_group_honor", "uint32_group_honor_bit" }, new Object[] { + long_, integer, byteStringMicro, bool, byteStringMicro, bool, integer, byteStringMicro, integer, byteStringMicro, + byteStringMicro, integer, byteStringMicro, long_, long_, null, null, byteStringMicro, byteStringMicro, integer, + bool, bool, bool, bool, bool, integer, integer, bool, long_, integer, + byteStringMicro, integer, null, null, byteStringMicro, byteStringMicro, integer, null, integer, null, + byteStringMicro, integer }, tencent.im.group.group_member_info.MemberInfo.class); + } + + public MemberInfo() { + ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY; + this.str_errmsg = PBField.initBytes(byteStringMicro); + this.bool_is_friend = PBField.initBool(false); + this.str_remark = PBField.initBytes(byteStringMicro); + this.bool_is_concerned = PBField.initBool(false); + this.uint32_credit = PBField.initUInt32(0); + this.str_card = PBField.initBytes(byteStringMicro); + this.uint32_sex = PBField.initUInt32(0); + this.str_location = PBField.initBytes(byteStringMicro); + this.str_nick = PBField.initBytes(byteStringMicro); + this.uint32_age = PBField.initUInt32(0); + this.str_lev = PBField.initBytes(byteStringMicro); + this.uint64_join = PBField.initUInt64(0L); + this.uint64_last_speak = PBField.initUInt64(0L); + this.rpt_msg_custom_enties = PBField.initRepeatMessage(tencent.im.group.group_member_info.CustomEntry.class); + this.rpt_msg_gbar_concerned = PBField.initRepeatMessage(tencent.im.group.group_member_info.GBarInfo.class); + this.str_gbar_title = PBField.initBytes(byteStringMicro); + this.str_gbar_url = PBField.initBytes(byteStringMicro); + this.uint32_gbar_cnt = PBField.initUInt32(0); + this.bool_is_allow_mod_card = PBField.initBool(false); + this.bool_is_vip = PBField.initBool(false); + this.bool_is_year_vip = PBField.initBool(false); + this.bool_is_super_vip = PBField.initBool(false); + this.bool_is_super_qq = PBField.initBool(false); + this.uint32_vip_lev = PBField.initUInt32(0); + this.uint32_role = PBField.initUInt32(0); + this.bool_location_shared = PBField.initBool(false); + this.uint64_distance = PBField.initUInt64(0L); + this.uint32_concern_type = PBField.initUInt32(0); + this.bytes_special_title = PBField.initBytes(byteStringMicro); + this.uint32_special_title_expire_time = PBField.initUInt32(0); + this.msg_flower_entry = new tencent.im.group.group_member_info.FlowersEntry(); + this.msg_team_entry = new group_member_info.TeamEntry(); + this.bytes_phone_num = PBField.initBytes(byteStringMicro); + this.bytes_job = PBField.initBytes(byteStringMicro); + this.medal_id = PBField.initUInt32(0); +// this.qqstory_infocard = new group_member_info.RspGroupCardGetStory(); + this.uint32_level = PBField.initUInt32(0); + this.msg_game_info = new tencent.im.group.group_member_info.MemberGameInfo(); + this.bytes_group_honor = PBField.initBytes(byteStringMicro); + this.uint32_group_honor_bit = PBField.initUInt32(0); + } + } + + public static class ReqBody extends MessageMicro { + static final FieldMap __fieldMap__; + + public final PBBoolField bool_new_client = PBField.initBool(false); + + public final PBUInt32Field uint32_client_type = PBField.initUInt32(0); + + public final PBUInt32Field uint32_rich_card_name_ver = PBField.initUInt32(0); + + public final PBUInt64Field uint64_group_code = PBField.initUInt64(0L); + + public final PBUInt64Field uint64_uin = PBField.initUInt64(0L); + + static { + Long long_ = Long.valueOf(0L); + Integer integer = Integer.valueOf(0); + Boolean bool = Boolean.FALSE; + __fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 24, 32, 40 }, new String[] { "uint64_group_code", "uint64_uin", "bool_new_client", "uint32_client_type", "uint32_rich_card_name_ver" }, new Object[] { long_, long_, bool, integer, integer }, tencent.im.group.group_member_info.ReqBody.class); + } + } + + public static class RspBody extends MessageMicro { + static final FieldMap __fieldMap__; + + public final PBBoolField bool_self_location_shared = PBField.initBool(false); + + public MemberInfo msg_meminfo = new MemberInfo(); + + public final PBUInt32Field uint32_group_type = PBField.initUInt32(0); + + public final PBUInt32Field uint32_self_role = PBField.initUInt32(0); + + public final PBUInt64Field uint64_group_code = PBField.initUInt64(0L); + + static { + Integer integer = Integer.valueOf(0); + Boolean bool = Boolean.FALSE; + __fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 26, 32, 40 }, new String[] { "uint64_group_code", "uint32_self_role", "msg_meminfo", "bool_self_location_shared", "uint32_group_type" }, new Object[] { Long.valueOf(0L), integer, null, bool, integer }, tencent.im.group.group_member_info.RspBody.class); + } + } + + public static class TeamEntry extends MessageMicro { + static final FieldMap __fieldMap__; + + public final PBRepeatField rpt_uint64_depid; + + public final PBRepeatField rpt_uint64_self_depid; + + static { + Long long_ = Long.valueOf(0L); + __fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16 }, new String[] { "rpt_uint64_depid", "rpt_uint64_self_depid" }, new Object[] { long_, long_ }, tencent.im.group.group_member_info.TeamEntry.class); + } + + public TeamEntry() { + PBUInt64Field pBUInt64Field = (PBUInt64Field) PBUInt64Field.__repeatHelper__; + this.rpt_uint64_depid = PBField.initRepeat((PBField)pBUInt64Field); + this.rpt_uint64_self_depid = PBField.initRepeat((PBField)pBUInt64Field); + } + } +} diff --git a/qqinterface/src/main/java/tencent/im/troop/honor/troop_honor.java b/qqinterface/src/main/java/tencent/im/troop/honor/troop_honor.java new file mode 100644 index 0000000..0ccac95 --- /dev/null +++ b/qqinterface/src/main/java/tencent/im/troop/honor/troop_honor.java @@ -0,0 +1,21 @@ +package tencent.im.troop.honor; + +import com.tencent.mobileqq.pb.MessageMicro; +import com.tencent.mobileqq.pb.PBField; +import com.tencent.mobileqq.pb.PBRepeatField; +import com.tencent.mobileqq.pb.PBUInt32Field; + +public class troop_honor { + public static class GroupUserCardHonor extends MessageMicro { + static final FieldMap __fieldMap__; + + public final PBRepeatField id = PBField.initRepeat((PBField) PBUInt32Field.__repeatHelper__); + + public final PBUInt32Field level = PBField.initUInt32(0); + + static { + Integer integer = Integer.valueOf(0); + __fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16 }, new String[] { "id", "level" }, new Object[] { integer, integer }, GroupUserCardHonor.class); + } + } +} diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/GroupSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/GroupSvc.kt index 944893a..300d8f4 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/GroupSvc.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/GroupSvc.kt @@ -47,6 +47,7 @@ import moe.fuqiuluo.proto.asInt import moe.fuqiuluo.proto.asUtf8String import moe.fuqiuluo.proto.protobufOf import moe.fuqiuluo.qqinterface.servlet.entries.ProhibitedMemberInfo +import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.helper.MessageHelper import moe.fuqiuluo.shamrock.remote.service.data.EssenceMessage @@ -67,11 +68,13 @@ import moe.fuqiuluo.shamrock.tools.slice import moe.fuqiuluo.shamrock.utils.FileUtils import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher +import tencent.im.group.group_member_info import tencent.im.oidb.cmd0x899.oidb_0x899 import tencent.im.oidb.cmd0x89a.oidb_0x89a import tencent.im.oidb.cmd0x8a0.oidb_0x8a0 import tencent.im.oidb.cmd0x8fc.Oidb_0x8fc import tencent.im.oidb.oidb_sso +import tencent.im.troop.honor.troop_honor import java.lang.reflect.Method import java.lang.reflect.Modifier import java.nio.ByteBuffer @@ -420,6 +423,36 @@ internal object GroupSvc: BaseSvc() { } } } + try { + if (info != null && (info.alias == null || info.alias.isBlank())) { + val req = group_member_info.ReqBody() + req.uint64_group_code.set(groupId.toLong()) + req.uint64_uin.set(uin.toLong()) + req.bool_new_client.set(true) + req.uint32_client_type.set(1) + req.uint32_rich_card_name_ver.set(1) + val respBuffer = sendBufferAW("group_member_card.get_group_member_card_info", true, req.toByteArray()) + if (respBuffer != null) { + val rsp = group_member_info.RspBody() + rsp.mergeFrom(respBuffer.slice(4)) + if (rsp.msg_meminfo.str_location.has()) { + info.alias = rsp.msg_meminfo.str_location.get().toStringUtf8() + } + if (rsp.msg_meminfo.uint32_age.has()) { + info.age = rsp.msg_meminfo.uint32_age.get().toByte() + } + if (rsp.msg_meminfo.bytes_group_honor.has()) { + val honorBytes = rsp.msg_meminfo.bytes_group_honor.get().toByteArray() + val honor = troop_honor.GroupUserCardHonor() + honor.mergeFrom(honorBytes) + info.level = honor.level.get() + // 10315: medal_id not real group level + } + } + } + } catch (err: Throwable) { + LogCenter.log(err.stackTraceToString(), Level.WARN) + } return if (info != null) { Result.success(info) } else { @@ -526,7 +559,7 @@ internal object GroupSvc: BaseSvc() { throw RuntimeException("AppRuntime cannot cast to AppInterface") val businessHandler = app.getBusinessHandler(BusinessHandlerFactory.TROOP_MEMBER_LIST_HANDLER) - // void C(boolean foreRefresh, String groupId, String troopcode, int reqType); // RequestedTroopList/refreshMemberListFromServer + // void C(boolean forceRefresh, String groupId, String troopcode, int reqType); // RequestedTroopList/refreshMemberListFromServer if (!GroupSvc::METHOD_REQ_TROOP_MEM_LIST.isInitialized) { METHOD_REQ_TROOP_MEM_LIST = businessHandler.javaClass.declaredMethods.first { it.parameterCount == 4 diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetTroopMemberInfo.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetTroopMemberInfo.kt index f0cf252..7adb9e9 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetTroopMemberInfo.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetTroopMemberInfo.kt @@ -58,7 +58,8 @@ internal object GetTroopMemberInfo : IActionHandler() { unfriendly = false, title = info.mUniqueTitle ?: "", titleExpireTime = info.mUniqueTitleExpire, - cardChangeable = GroupSvc.isAdmin(groupId) + cardChangeable = GroupSvc.isAdmin(groupId), + age = info.age.toInt() ), echo ) } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetTroopMemberList.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetTroopMemberList.kt index 8540d7b..d6558b0 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetTroopMemberList.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetTroopMemberList.kt @@ -59,7 +59,8 @@ internal object GetTroopMemberList : IActionHandler() { unfriendly = false, title = info.mUniqueTitle ?: "", titleExpireTime = info.mUniqueTitleExpire, - cardChangeable = GroupSvc.isAdmin(groupId) + cardChangeable = GroupSvc.isAdmin(groupId), + age = 0 ) ) } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/TroopData.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/TroopData.kt index 595b73a..b432d68 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/TroopData.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/TroopData.kt @@ -26,6 +26,7 @@ internal data class SimpleTroopMemberInfo( @SerialName("group_id") val groupId: Long, @SerialName("user_name") val name: String, @SerialName("sex") val sex: String, + @SerialName("age") val age: Int, @SerialName("title") val title: String, @SerialName("title_expire_time") val titleExpireTime: Int, @SerialName("nickname") val nick: String,