send_forward_msg(support at face...)

This commit is contained in:
Simplxs 2024-02-24 02:10:41 +08:00
parent 46ed966c18
commit d22f3ad1cb
No known key found for this signature in database
GPG Key ID: E23537FF14DD6507
62 changed files with 1494 additions and 780 deletions

View File

@ -7,10 +7,6 @@ import kotlin.reflect.KClass
interface Protobuf<T: Protobuf<T>>
inline fun <reified T: Protobuf<T>> KClass<T>.decode(data: ByteArray): T {
return ProtoBuf.decodeFromByteArray(data)
}
inline fun <reified T: Protobuf<T>> ByteArray.decodeProtobuf(to: KClass<T>? = null): T {
return ProtoBuf.decodeFromByteArray(this)
}

View File

@ -0,0 +1,26 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class AppShareInfo(
@ProtoNumber(1) var appshareId: UInt? = null,
@ProtoNumber(2) var appshareCookie: ByteArray? = null,
@ProtoNumber(3) var appshareResource: PluginInfo? = null,
)
@Serializable
data class PluginInfo(
@ProtoNumber(1) var resId: UInt = 0u,
@ProtoNumber(2) var pkgName: String = "",
@ProtoNumber(3) var newVer: UInt = 0u,
@ProtoNumber(4) var resType: UInt = 0u,
@ProtoNumber(5) var lanType: UInt = 0u,
@ProtoNumber(6) var priority: UInt = 0u,
@ProtoNumber(7) var resName: String = "",
@ProtoNumber(8) var resDesc: String = "",
@ProtoNumber(9) var resUrlBig: String = "",
@ProtoNumber(10) var resUrlSmall: String = "",
@ProtoNumber(11) var resConf: String = "",
)

View File

@ -4,12 +4,12 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MessageContent(
data class ContentHead(
@ProtoNumber(1) val msgType: Int = Int.MIN_VALUE,
@ProtoNumber(2) val msgSubType: Int? = null,
@ProtoNumber(3) val u1: Int? = null,
@ProtoNumber(3) val divSeq: Int? = null,
@ProtoNumber(4) val msgViaRandom: Long = Long.MIN_VALUE,
@ProtoNumber(5) val msgSeq_: Long? = null,
@ProtoNumber(5) val sequence: Long? = null,
@ProtoNumber(6) val msgTime: Long? = null,
@ProtoNumber(7) val u2: Int? = null,
@ProtoNumber(8) val u6: Int? = null,
@ -27,5 +27,5 @@ data class ForwardHead(
@ProtoNumber(2) val u2: Int? = null,
@ProtoNumber(3) val u3: Int? = null,
@ProtoNumber(4) val ub641: String? = null,
@ProtoNumber(5) val Avatar: String? = null
@ProtoNumber(5) val avatar: String? = null
)

View File

@ -0,0 +1,64 @@
package protobuf.message
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import protobuf.message.element.*
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class Elem(
@ProtoNumber(1) val text: TextMsg? = null,
@ProtoNumber(2) val face: FaceMsg? = null,
// @ProtoNumber(3) val onlineImage: OnlineImage? = null,
@ProtoNumber(4) val notOnlineImage: NotOnlineImage? = null,
// @ProtoNumber(5) var transElemInfo: TransElem? = null,
@ProtoNumber(6) val marketFace: MarketFace? = null,
// @ProtoNumber(7) var elemFlags: ElemFlags? = null,
@ProtoNumber(8) val customFace: CustomFace? = null,
@ProtoNumber(9) var elemFlags2: ElemFlags2? = null,
// @ProtoNumber(10) var funFace: FunFace? = null,
// @ProtoNumber(11) var secretFile: SecretFileMsg? = null,
// @ProtoNumber(12) var richMsg: RichMsg? = null,
// @ProtoNumber(13) var groupFile: GroupFile? = null,
// @ProtoNumber(14) var pubGroup: PubGroup? = null,
// @ProtoNumber(15) var marketTrans: MarketTrans? = null,
// @ProtoNumber(16) var extraInfo: ExtraInfo? = null,
// @ProtoNumber(17) var shakeWindow: ShakeWindow? = null,
// @ProtoNumber(18) var pubAccount: PubAccount? = null,
// @ProtoNumber(19) var videoFile: VideoFile? = null,
// @ProtoNumber(20) var tipsInfo: TipsInfo? = null,
// @ProtoNumber(21) var anonGroupMsg: AnonymousGroupMsg? = null,
// @ProtoNumber(22) var qqLiveOld: QQLiveOld? = null,
// @ProtoNumber(23) var lifeOnline: LifeOnlineAccount? = null,
// @ProtoNumber(24) var qqwalletMsg: QQWalletMsg? = null,
// @ProtoNumber(25) var crmElem: CrmElem? = null,
// @ProtoNumber(26) var conferenceTipsInfo: ConferenceTipsInfo? = null,
// @ProtoNumber(27) var redbagInfo: RedBagInfo? = null,
// @ProtoNumber(28) var lowVersionTips: LowVersionTips? = null,
// @ProtoNumber(29) var bankcodeCtrlInfo: ByteArray? = null,
// @ProtoNumber(30) var nearByMsg: NearByMessageType? = null,
// @ProtoNumber(31) var customElem: CustomElem? = null,
// @ProtoNumber(32) var locationInfo: LocationInfo? = null,
// @ProtoNumber(33) var pubAccInfo: PubAccInfo? = null,
// @ProtoNumber(34) var smallEmoji: SmallEmoji? = null,
// @ProtoNumber(35) var fsjMsgElem: FSJMessageElem? = null,
// @ProtoNumber(36) var arkApp: ArkAppElem? = null,
@ProtoNumber(37) val generalFlags: GeneralFlags? = null,
// @ProtoNumber(38) var hcFlashPic: CustomFace? = null,
// @ProtoNumber(39) var deliverGiftMsg: DeliverGiftMsg? = null,
// @ProtoNumber(40) var bitapp_msg: BitAppMsg? = null,
// @ProtoNumber(41) var openQqData: OpenQQData? = null,
// @ProtoNumber(42) var apolloMsg: ApolloActMsg? = null,
// @ProtoNumber(43) var groupPubAccInfo: GroupPubAccountInfo? = null,
// @ProtoNumber(44) var blessMsg: BlessingMessage? = null,
@ProtoNumber(45) var srcMsg: SourceMsg? = null,
// @ProtoNumber(46) var lolaMsg: LolaMsg? = null,
// @ProtoNumber(47) var groupBusinessMsg: GroupBusinessMsg? = null,
// @ProtoNumber(48) var msgWorkflowNotify: WorkflowNotifyMsg? = null,
// @ProtoNumber(49) var patElem: PatsElem? = null,
// @ProtoNumber(50) var groupPostElem: GroupPostElem? = null,
@ProtoNumber(51) val lightApp: LightAppElem? = null,
// @ProtoNumber(52) var eimInfo: EIMInfo? = null,
@ProtoNumber(53) val commonElem: CommonElem? = null,
)

View File

@ -1,17 +0,0 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.message
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class RichMessage(
@ProtoNumber(1) val font: Font? = null,
@ProtoNumber(2) val elements: List<MessageElement>? = null
)
@Serializable
data class Font(
@ProtoNumber(9) val fontName: String? = null
)

View File

@ -1,11 +0,0 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MessageBody(
@ProtoNumber(1) val rich: RichMessage? = null,
@ProtoNumber(2) val rawBuffer: ByteArray? = null,
@ProtoNumber(3) val MsgEncryptContent: ByteArray? = null
)

View File

@ -1,13 +0,0 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import protobuf.message.element.*
@Serializable
data class MessageElement(
@ProtoNumber(1) val text: TextElement? = null,
@ProtoNumber(2) val face: FaceElement? = null,
@ProtoNumber(51) val json: JsonElement? = null,
@ProtoNumber(53) val comm: CommonElement? = null,
)

View File

@ -0,0 +1,11 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MsgBody(
@ProtoNumber(1) val richText: RichText? = null,
@ProtoNumber(2) val msgContent: ByteArray? = null,
@ProtoNumber(3) val msgEncryptContent: ByteArray? = null
)

View File

@ -0,0 +1,9 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MsgControl(
@ProtoNumber(1) val msgFlag: Int? = null,
)

View File

@ -0,0 +1,28 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class NotOnlineFile(
@ProtoNumber(1) var fileType: UInt? = null,
@ProtoNumber(2) var sig: ByteArray? = null,
@ProtoNumber(3) var fileUuid: ByteArray? = null,
@ProtoNumber(4) var fileMd5: ByteArray? = null,
@ProtoNumber(5) var fileName: ByteArray? = null,
@ProtoNumber(6) var fileSize: ULong? = null,
@ProtoNumber(7) var note: ByteArray? = null,
@ProtoNumber(8) var reserved: UInt? = null,
@ProtoNumber(9) var subcmd: UInt? = null,
@ProtoNumber(10) var microCloud: UInt? = null,
@ProtoNumber(11) var rptFileUrls: List<String>? = null,
@ProtoNumber(12) var downloadFlag: UInt? = null,
@ProtoNumber(50) var dangerEvel: UInt? = null,
@ProtoNumber(51) var lifeTime: UInt? = null,
@ProtoNumber(52) var uploadTime: UInt? = null,
@ProtoNumber(53) var absFileType: UInt? = null,
@ProtoNumber(54) var clientType: UInt? = null,
@ProtoNumber(55) var expireTime: UInt? = null,
@ProtoNumber(56) var pbReserve: ByteArray? = null,
@ProtoNumber(57) var fileidcrcMedia: String? = null,
)

View File

@ -1,11 +0,0 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class NtMessage(
@ProtoNumber(1) val msgHead: MessageHead? = null,
@ProtoNumber(2) val contentHead: MessageContent? = null,
@ProtoNumber(3) val body: MessageBody? = null,
)

View File

@ -0,0 +1,23 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class PbSendMsgReq(
@ProtoNumber(1) val routingHead: RoutingHead? = null,
@ProtoNumber(2) val contentHead: ContentHead? = null,
@ProtoNumber(3) val msgBody: MsgBody? = null,
@ProtoNumber(4) val msgSeq: UInt? = null,
@ProtoNumber(5) val msgRand: UInt? = null,
@ProtoNumber(6) val syncCookie: ByteArray? = null,
@ProtoNumber(7) val appShare: AppShareInfo? = null,
@ProtoNumber(8) val msgVia: UInt? = null,
@ProtoNumber(9) val dataStatist: UInt? = null,
// @ProtoNumber(10) val multiMsgAssist: MultiMsgAssist? = null,
// @ProtoNumber(11) val inputNotifyInfo: InputNotifyInfo? = null,
@ProtoNumber(12) val ctrl: MsgControl? = null,
// @ProtoNumber(13) val receiptReq: ReceiptReq? = null,
@ProtoNumber(14) val multiSendSeq: UInt? = null
) : Protobuf<PbSendMsgReq>

View File

@ -0,0 +1,32 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Ptt(
@ProtoNumber(1) var fileType: UInt?=null,
@ProtoNumber(2) var srcUin: ULong?=null,
@ProtoNumber(3) var fileUuid: ByteArray?=null,
@ProtoNumber(4) var fileMd5: ByteArray?=null,
@ProtoNumber(5) var fileName: ByteArray?=null,
@ProtoNumber(6) var fileSize: UInt?=null,
@ProtoNumber(7) var reserve: ByteArray?=null,
@ProtoNumber(8) var fileId: UInt?=null,
@ProtoNumber(9) var serverIp: UInt?=null,
@ProtoNumber(10) var serverPort: UInt?=null,
@ProtoNumber(11) var boolValid: Boolean = false,
@ProtoNumber(12) var signature: ByteArray?=null,
@ProtoNumber(13) var shortcut: ByteArray?=null,
@ProtoNumber(14) var fileKey: ByteArray?=null,
@ProtoNumber(15) var magicPttIndex: UInt?=null,
@ProtoNumber(16) var voiceSwitch: UInt?=null,
@ProtoNumber(17) var pttUrl: ByteArray?=null,
@ProtoNumber(18) var groupFileKey: ByteArray?=null,
@ProtoNumber(19) var time: UInt?=null,
@ProtoNumber(20) var downPara: ByteArray?=null,
@ProtoNumber(29) var format: UInt?=null,
@ProtoNumber(30) var pbReserve: ByteArray?=null,
@ProtoNumber(31) var rptPttUrls: List<String>? = null,
@ProtoNumber(32) var downloadFlag: UInt?=null,
)

View File

@ -0,0 +1,11 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class PushMsgBody(
@ProtoNumber(1) val msgHead: ResponseHead? = null,
@ProtoNumber(2) val contentHead: ContentHead? = null,
@ProtoNumber(3) val body: MsgBody? = null,
)

View File

@ -6,25 +6,25 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MessageHead(
data class ResponseHead(
@ProtoNumber(1) val peer: Long = Long.MIN_VALUE,
@ProtoNumber(2) val peerUid: String? = null,
@ProtoNumber(3) val flag: Int = Int.MIN_VALUE,
@ProtoNumber(4) val appId: Int = Int.MIN_VALUE,
@ProtoNumber(5) val receiver: Long? = null,
@ProtoNumber(6) val receiverUid: String? = null,
@ProtoNumber(7) val forward: MessageForward? = null,
@ProtoNumber(8) val groupInfo: GroupInfo? = null,
@ProtoNumber(7) val forward: ResponseForward? = null,
@ProtoNumber(8) val responseGrp: ResponseGrp? = null,
)
@Serializable
data class MessageForward(
data class ResponseForward(
@ProtoNumber(6) val friendName: String? = null,
@ProtoNumber(11) val u1: Int? = null,
)
@Serializable
data class GroupInfo(
data class ResponseGrp(
@ProtoNumber(1) val groupCode: ULong = ULong.MIN_VALUE,
@ProtoNumber(4) val memberCard: String? = null,
@ProtoNumber(5) val u1: Int? = null,

View File

@ -0,0 +1,31 @@
@file:OptIn(ExperimentalSerializationApi::class)
package protobuf.message
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class RichText(
@ProtoNumber(1) val attr: Attr? = null,
@ProtoNumber(2) val elements: List<Elem>? = null,
@ProtoNumber(3) val not_online_file: NotOnlineFile? = null,
@ProtoNumber(4) val ptt: Ptt? = null,
@ProtoNumber(5) val tmp_ptt: TmpPtt? = null,
@ProtoNumber(6) val trans_211_tmp_msg: Trans211TmpMsg? = null,
)
@Serializable
data class Attr(
@ProtoNumber(1) val codePage: Int? = null,
@ProtoNumber(2) val time: UInt? = null,
@ProtoNumber(3) val random: UInt? = null,
@ProtoNumber(4) val color: UInt? = null,
@ProtoNumber(5) val size: UInt? = null,
@ProtoNumber(6) val effect: UInt? = null,
@ProtoNumber(7) val charSet: UInt? = null,
@ProtoNumber(8) val pitchAndFamily: UInt? = null,
@ProtoNumber(9) val fontName: String? = null,
@ProtoNumber(10) val reserve_data: ByteArray? = null,
)

View File

@ -0,0 +1,14 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import protobuf.message.routing.*
@Serializable
data class RoutingHead(
@ProtoNumber(1) val c2c: C2C? = null,
@ProtoNumber(2) val grp: Grp? = null,
@ProtoNumber(3) val grpTmp: GrpTmp? = null,
@ProtoNumber(6) val wpaTmp: WPATmp? = null,
@ProtoNumber(15) val trans0X211: Trans0X211? = null
)

View File

@ -0,0 +1,20 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class TmpPtt(
@ProtoNumber(1) var fileType: UInt? = null,
@ProtoNumber(2) var fileUuid: ByteArray? = null,
@ProtoNumber(3) var fileMd5: ByteArray? = null,
@ProtoNumber(4) var fileName: ByteArray? = null,
@ProtoNumber(5) var fileSize: UInt? = null,
@ProtoNumber(6) var pttTimes: UInt? = null,
@ProtoNumber(7) var userType: UInt? = null,
@ProtoNumber(8) var ptttransFlag: UInt? = null,
@ProtoNumber(9) var busiType: UInt? = null,
@ProtoNumber(10) var msgId: ULong? = null,
@ProtoNumber(30) var pbReserve: ByteArray? = null,
@ProtoNumber(31) var pttEncodeData: ByteArray? = null,
)

View File

@ -0,0 +1,10 @@
package protobuf.message
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Trans211TmpMsg(
@ProtoNumber(1) var msgBody: ByteArray? = null,
@ProtoNumber(2) var c2cCmd: UInt? = null,
)

View File

@ -0,0 +1,11 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class CommonElem(
@ProtoNumber(1) val serviceType: Int? = null,
@ProtoNumber(2) val elem: ByteArray? = null,
@ProtoNumber(3) val businessType: Int? = null,
)

View File

@ -1,11 +0,0 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class CommonElement(
@ProtoNumber(1) val type: Int? = null,
@ProtoNumber(2) val data: ByteArray? = null,
@ProtoNumber(3) val u1: Int? = null,
)

View File

@ -0,0 +1,49 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class CustomFace(
@ProtoNumber(1) var guid: ByteArray? = null,
@ProtoNumber(2) var filePath: String? = null,
@ProtoNumber(3) var shortcut: String? = null,
@ProtoNumber(4) var buffer: ByteArray? = null,
@ProtoNumber(5) var flag: ByteArray? = null,
@ProtoNumber(6) var oldData: ByteArray? = null,
@ProtoNumber(7) var fileId: UInt? = null,
@ProtoNumber(8) var serverIp: UInt? = null,
@ProtoNumber(9) var serverPort: UInt? = null,
@ProtoNumber(10) var fileType: UInt? = null, // 66
@ProtoNumber(11) var signature: ByteArray? = null,
@ProtoNumber(12) var useful: UInt? = null,
@ProtoNumber(13) var md5: ByteArray? = null,
@ProtoNumber(14) var thumbUrl: String? = null,
@ProtoNumber(15) var bigUrl: String? = null,
@ProtoNumber(16) var origUrl: String? = null,
@ProtoNumber(17) var bizType: UInt? = null,
@ProtoNumber(18) var repeatIndex: UInt? = null,
@ProtoNumber(19) var repeatImage: UInt? = null,
@ProtoNumber(20) var imageType: UInt? = null,
@ProtoNumber(21) var index: UInt? = null,
@ProtoNumber(22) var width: UInt? = null,
@ProtoNumber(23) var height: UInt? = null,
@ProtoNumber(24) var source: UInt? = null,
@ProtoNumber(25) var size: UInt? = null,
@ProtoNumber(26) var origin: UInt? = null,
@ProtoNumber(27) var thumbWidth: UInt? = null,
@ProtoNumber(28) var thumbHeight: UInt? = null,
@ProtoNumber(29) var showLen: UInt? = null,
@ProtoNumber(30) var downloadLen: UInt? = null,
@ProtoNumber(31) var url400: String? = null,
@ProtoNumber(32) var width400: UInt? = null,
@ProtoNumber(33) var height400: UInt? = null,
@ProtoNumber(34) var pbReserve: PbReserve? = null,
){
companion object{
@Serializable
data class PbReserve(
@ProtoNumber(1) var field1: Int? = null
)
}
}

View File

@ -0,0 +1,38 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class ElemFlags2(
@ProtoNumber(1) var color_text_id: UInt? = null,
@ProtoNumber(2) var msg_id: ULong? = null,
@ProtoNumber(3) var whisper_session_id: UInt? = null,
@ProtoNumber(4) var ptt_change_bit: UInt? = null,
@ProtoNumber(5) var vip_status: UInt? = null,
@ProtoNumber(6) var compatible_id: UInt? = null,
@ProtoNumber(7) var rpt_insts: List<Inst>? = null,
@ProtoNumber(8) var msg_rpt_cnt: UInt? = null,
@ProtoNumber(9) var src_inst: Inst? = null,
@ProtoNumber(10) var longtitude: UInt? = null,
@ProtoNumber(11) var latitude: UInt? = null,
@ProtoNumber(12) var custom_font: UInt? = null,
@ProtoNumber(13) var pc_support_def: PcSupportDef? = null,
@ProtoNumber(14) var crm_flags: UInt? = null,
)
@Serializable
data class Inst(
@ProtoNumber(1) var app_id: UInt? = null,
@ProtoNumber(2) var inst_id: UInt? = null,
)
@Serializable
data class PcSupportDef(
@ProtoNumber(1) var pc_ptl_begin: UInt? = null,
@ProtoNumber(2) var pc_ptl_end: UInt? = null,
@ProtoNumber(3) var mac_ptl_begin: UInt? = null,
@ProtoNumber(4) var mac_ptl_end: UInt? = null,
@ProtoNumber(5) var rpt_ptls_support: List<Int>? = null,
@ProtoNumber(6) var rpt_ptls_not_support: List<Int>? = null,
)

View File

@ -4,6 +4,9 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class FaceElement(
data class FaceMsg(
@ProtoNumber(1) val id: Int? = null,
@ProtoNumber(2) var old: ByteArray? = null,
@ProtoNumber(11) var buf: ByteArray? = null,
)

View File

@ -0,0 +1,28 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class GeneralFlags(
@ProtoNumber(1) val bubbleDiyTextId: UInt? = null,
@ProtoNumber(2) val groupFlagNew: UInt? = null,
@ProtoNumber(3) val uin: ULong? = null,
@ProtoNumber(4) val rpId: ByteArray? = null,
@ProtoNumber(5) val prpFold: UInt? = null,
@ProtoNumber(6) val longTextFlag: UInt? = null,
@ProtoNumber(7) val longTextResid: ByteArray? = null,
@ProtoNumber(8) val groupType: UInt? = null,
@ProtoNumber(9) val toUinFlag: UInt? = null,
@ProtoNumber(10) val glamourLevel: UInt? = null,
@ProtoNumber(11) val memberLevel: UInt? = null,
@ProtoNumber(12) val groupRankSeq: ULong? = null,
@ProtoNumber(13) val olympicTorch: UInt? = null,
@ProtoNumber(14) val babyqGuideMsgCookie: ByteArray? = null,
@ProtoNumber(15) val expertFlag: UInt? = null,
@ProtoNumber(16) val bubbleSubId: UInt? = null,
@ProtoNumber(17) val pendantId: ULong? = null,
@ProtoNumber(18) val rpIndex: ByteArray? = null,
@ProtoNumber(19) val reserve: ByteArray? = null,
)

View File

@ -4,6 +4,6 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class JsonElement(
data class LightAppElem(
@ProtoNumber(1) val data: ByteArray? = null,
)

View File

@ -0,0 +1,21 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MarketFace(
@ProtoNumber(1) var faceName: String? = null,
@ProtoNumber(2) var itemType: Int? = null,
@ProtoNumber(3) var faceInfo: Int? = null,
@ProtoNumber(4) var faceId: String? = null,
@ProtoNumber(5) var tabId: Int? = null,
@ProtoNumber(6) var subType: Int? = null,
@ProtoNumber(7) var key: ByteArray? = null,
@ProtoNumber(8) var param: ByteArray? = null,
@ProtoNumber(9) var mediaType: Int? = null,
@ProtoNumber(10) var imageWidth: Int? = null,
@ProtoNumber(11) var imageHeight: Int? = null,
@ProtoNumber(12) var mobileparam: ByteArray? = null,
@ProtoNumber(13) var pbReserve: ByteArray? = null,
)

View File

@ -0,0 +1,46 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class NotOnlineImage(
@ProtoNumber(1) val filePath: ByteArray? = null,
@ProtoNumber(2) val fileLen: UInt? = null,
@ProtoNumber(3) val downloadPath: ByteArray? = null,
@ProtoNumber(4) val oldVerSendFile: ByteArray? = null,
@ProtoNumber(5) val imgType: UInt? = null,
@ProtoNumber(6) val previewsImage: ByteArray? = null,
@ProtoNumber(7) val picMd5: ByteArray? = null,
@ProtoNumber(8) val picHeight: UInt? = null,
@ProtoNumber(9) val picWidth: UInt? = null,
@ProtoNumber(10) val resId: ByteArray? = null,
@ProtoNumber(11) val flag: ByteArray? = null,
@ProtoNumber(12) val thumbUrl: String? = null,
@ProtoNumber(13) val original: UInt? = null,
@ProtoNumber(14) val bigUrl: String? = null,
@ProtoNumber(15) val origUrl: String? = null,
@ProtoNumber(16) val bizType: UInt? = null,
@ProtoNumber(17) val result: UInt? = null,
@ProtoNumber(18) val index: UInt? = null,
@ProtoNumber(19) val opFaceBuf: ByteArray? = null,
@ProtoNumber(20) val oldPicMd5: Boolean = false,
@ProtoNumber(21) val thumbWidth: UInt? = null,
@ProtoNumber(22) val thumbHeight: UInt? = null,
@ProtoNumber(23) val fileId: UInt? = null,
@ProtoNumber(24) val showLen: UInt? = null,
@ProtoNumber(25) val downloadLen: UInt? = null,
@ProtoNumber(26) val url400: String? = null,
@ProtoNumber(27) val width400: UInt? = null,
@ProtoNumber(28) val height400: UInt? = null,
@ProtoNumber(29) val pbReserve: PbReserve? = null,
) {
companion object {
@Serializable
data class PbReserve(
@ProtoNumber(1) var field1: Int? = null,
@ProtoNumber(8) var field8: String? = null,
@ProtoNumber(30) var url: String? = null
)
}
}

View File

@ -0,0 +1,30 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import protobuf.message.Elem
@Serializable
data class SourceMsg(
@ProtoNumber(1) var origSeqs: List<Int>? = null,
@ProtoNumber(2) var senderUin: ULong? = null,
@ProtoNumber(3) var time: ULong? = null,
@ProtoNumber(4) var flag: UInt? = null,
@ProtoNumber(5) var elems: List<Elem>? = null,
@ProtoNumber(6) var type: UInt? = null,
@ProtoNumber(7) var richMsg: ByteArray? = null,
@ProtoNumber(8) var pbReserve: PbReserve? = null,
@ProtoNumber(9) var srcMsg: ByteArray? = null,
@ProtoNumber(10) var toUin: ULong? = null,
@ProtoNumber(11) var troopName: String? = null,
) {
companion object {
@Serializable
data class PbReserve(
@ProtoNumber(3) var field3: ULong? = null,
@ProtoNumber(6) var senderUid: String? = null,
@ProtoNumber(7) var receiverUid: String? = null,
@ProtoNumber(8) var field8: Int? = null,
)
}
}

View File

@ -1,40 +0,0 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class TextElement(
@ProtoNumber(1) val text: String? = null,
@ProtoNumber(2) val link: String? = null,
@ProtoNumber(3) val attr6Buf: ByteArray? = null,
@ProtoNumber(4) val attr7Buf: ByteArray? = null,
@ProtoNumber(11) val buf: ByteArray? = null,
@ProtoNumber(12) val pbReserve: TextResvAttr? = null,
) {
companion object {
@Serializable
data class TextResvAttr(
@ProtoNumber(1) val wording: ByteArray? = null,
@ProtoNumber(2) val textAnalysisResult: Int? = null,
@ProtoNumber(3) val atType: Int? = null,
@ProtoNumber(4) val atMemberUin: Long? = null,
@ProtoNumber(5) val atMemberTinyid: Long? = null,
@ProtoNumber(6) val atChannelInfo: ExtChannelInfo? = null,
@ProtoNumber(7) val atRoleInfo: ExtRoleInfo? = null,
)
@Serializable
data class ExtChannelInfo(
@ProtoNumber(1) val guildId: Long? = null,
@ProtoNumber(2) val channelId: Long? = null,
)
@Serializable
data class ExtRoleInfo(
@ProtoNumber(1) val id: Long? = null,
@ProtoNumber(2) val info: ByteArray? = null,
@ProtoNumber(3) val flag: Int? = null,
)
}
}

View File

@ -0,0 +1,14 @@
package protobuf.message.element
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class TextMsg(
@ProtoNumber(1) val str: String? = null,
@ProtoNumber(2) val link: String? = null,
@ProtoNumber(3) val attr6Buf: ByteArray? = null,
@ProtoNumber(4) val attr7Buf: ByteArray? = null,
@ProtoNumber(11) val buf: ByteArray? = null,
@ProtoNumber(12) val pbReserve: ByteArray? = null,
)

View File

@ -0,0 +1,53 @@
package protobuf.message.element.commelem
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class ButtonExtra(
@ProtoNumber(1) val field1: Object1? = null,
) : Protobuf<ButtonExtra>
@Serializable
data class Object1(
@ProtoNumber(1) val rows: List<Row>? = null,
@ProtoNumber(2) val appid: Int? = null,
)
@Serializable
data class Row(
@ProtoNumber(1) val buttons: List<Button>? = null,
)
@Serializable
data class Button(
@ProtoNumber(1) val id: Int? = null,
@ProtoNumber(2) val renderData: RenderData? = null,
@ProtoNumber(3) val action: Action? = null,
)
@Serializable
data class RenderData(
@ProtoNumber(1) val label: String? = null,
@ProtoNumber(2) val visitedLabel: String? = null,
@ProtoNumber(3) val style: Int? = null,
)
@Serializable
data class Action(
@ProtoNumber(1) val type: Int? = null,
@ProtoNumber(2) val permission: Permission? = null,
@ProtoNumber(4) val unsupportTips: String? = null,
@ProtoNumber(5) val data: String? = null,
@ProtoNumber(6) val reply: Boolean? = null,
@ProtoNumber(7) val enter: Boolean? = null,
)
@Serializable
data class Permission(
@ProtoNumber(1) val type: Int? = null,
@ProtoNumber(2) val specifyRoleIds: List<String>? = null,
@ProtoNumber(3) val specifyUserIds: List<String>? = null,
)

View File

@ -0,0 +1,10 @@
package protobuf.message.element.commelem
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class MarkdownExtra(
@ProtoNumber(1) val content: String? = null,
) : Protobuf<MarkdownExtra>

View File

@ -0,0 +1,12 @@
package protobuf.message.element.commelem
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class PokeExtra(
@ProtoNumber(1) val type: Int? = null,
@ProtoNumber(7) val field7: Int? = null,
@ProtoNumber(8) val field8: Int? = null
) : Protobuf<PokeExtra>

View File

@ -0,0 +1,17 @@
package protobuf.message.element.commelem
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
data class QFaceExtra(
@ProtoNumber(1) val packId: String? = null,
@ProtoNumber(2) val stickerId: String? = null,
@ProtoNumber(3) val faceId: Int? = null,
@ProtoNumber(4) val field4: Int? = null,
@ProtoNumber(5) val field5: Int? = null,
@ProtoNumber(6) val field6: String? = null,
@ProtoNumber(7) val faceText: String? = null,
@ProtoNumber(9) val field9: Int? = null
) : Protobuf<QFaceExtra>

View File

@ -6,16 +6,7 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
import protobuf.message.MessageBody
import protobuf.message.MessageContent
import protobuf.message.MessageHead
@Serializable
data class PushMsgBody(
@ProtoNumber(1) val head: MessageHead? = null,
@ProtoNumber(2) val content: MessageContent? = null,
@ProtoNumber(3) val body: MessageBody? = null
)
import protobuf.message.PushMsgBody
@Serializable
data class LongMsgContent(

View File

@ -0,0 +1,14 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class C2C(
@ProtoNumber(1) val uin: UInt? = null,
@ProtoNumber(2) val uid: String? = null,
@ProtoNumber(3) val field3: UInt? = null,
@ProtoNumber(4) val sig: UInt? = null,
@ProtoNumber(5) val receiverUin: UInt? = null,
@ProtoNumber(6) val receiverUid: String? = null
)

View File

@ -0,0 +1,9 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Grp (
@ProtoNumber(1) var groupCode: UInt? = null,
)

View File

@ -0,0 +1,10 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class GrpTmp (
@ProtoNumber(1) var groupCode: UInt? = null,
@ProtoNumber(2) var ToUin: UInt? = null,
)

View File

@ -0,0 +1,11 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class Trans0X211(
@ProtoNumber(1) val toUin: ULong? = null,
@ProtoNumber(2) val ccCmd: UInt? = null,
@ProtoNumber(8) val uid: String? = null
)

View File

@ -0,0 +1,10 @@
package protobuf.message.routing
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class WPATmp (
@ProtoNumber(1) val toUin: Int? = null,
@ProtoNumber(2) val sig: ByteArray? = null,
)

View File

@ -1,104 +0,0 @@
package protobuf.msg
import com.google.protobuf.Internal.EMPTY_BYTE_ARRAY
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class MsgBody(
@ProtoNumber(1) var richText: RichText,
//@ProtoNumber(2) var msgContent: ByteArray = EMPTY_BYTE_ARRAY,
//@/ProtoNumber(3) var msgEncryptContent: ByteArray = EMPTY_BYTE_ARRAY,
)
@Serializable
data class RichText(
//@ProtoNumber(1) var attr: Attr? = null,
@ProtoNumber(2) var elems: ArrayList<Elem>? = null,
//@ProtoNumber(3) var not_online_file: NotOnlineFile? = null,
//@ProtoNumber(4) var ptt: Ptt? = null,
//@ProtoNumber(5) var tmp_ptt: TmpPtt? = null,
//@ProtoNumber(6) var trans_211_tmp_msg: Trans211TmpMsg? = null,
)
@Serializable
data class Elem(
/*@ProtoNumber(1) var text: TextMsg? = null,
@ProtoNumber(2) var face: FaceMsg? = null,
@ProtoNumber(3) var online_image: OnlineImage? = null,
@ProtoNumber(4) var not_online_image: NotOnlineImage? = null,
@ProtoNumber(5) var trans_elem_info: TransElem? = null,
@ProtoNumber(6) var market_face: MarketFace? = null,
@ProtoNumber(7) var elem_flags: ElemFlags? = null,
@ProtoNumber(8) var customFace: CustomFace? = null,
@ProtoNumber(9) var elem_flags2: ElemFlags2? = null,
@ProtoNumber(10) var fun_face: FunFace? = null,
@ProtoNumber(11) var secret_file: SecretFileMsg? = null,
@ProtoNumber(12) var rich_msg: RichMsg? = null,
@ProtoNumber(13) var group_file: GroupFile? = null,
@ProtoNumber(14) var pub_group: PubGroup? = null,
@ProtoNumber(15) var market_trans: MarketTrans? = null,
@ProtoNumber(16) var extra_info: ExtraInfo? = null,
@ProtoNumber(17) var shake_window: ShakeWindow? = null,
@ProtoNumber(18) var pub_account: PubAccount? = null,
@ProtoNumber(19) var video_file: VideoFile? = null,
@ProtoNumber(20) var tips_info: TipsInfo? = null,
@ProtoNumber(21) var anon_group_msg: AnonymousGroupMsg? = null,
@ProtoNumber(22) var qq_live_old: QQLiveOld? = null,
@ProtoNumber(23) var life_online: LifeOnlineAccount? = null,
@ProtoNumber(24) var qqwallet_msg: QQWalletMsg? = null,
@ProtoNumber(25) var crm_elem: CrmElem? = null,
@ProtoNumber(26) var conference_tips_info: ConferenceTipsInfo? = null,
@ProtoNumber(27) var redbag_info: RedBagInfo? = null,
@ProtoNumber(28) var low_version_tips: LowVersionTips? = null,
@ProtoNumber(29) var bankcode_ctrl_info: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(30) var near_by_msg: NearByMessageType? = null,
@ProtoNumber(31) var custom_elem: CustomElem? = null,
@ProtoNumber(32) var location_info: LocationInfo? = null,
@ProtoNumber(33) var pub_acc_info: PubAccInfo? = null,
@ProtoNumber(34) var small_emoji: SmallEmoji? = null,
@ProtoNumber(35) var fsj_msg_elem: FSJMessageElem? = null,
@ProtoNumber(36) var ark_app: ArkAppElem? = null,
*/
@ProtoNumber(37) var generalFlags: GeneralFlags? = null,
/*
@ProtoNumber(38) var hc_flash_pic: CustomFace? = null,
@ProtoNumber(39) var deliver_gift_msg: DeliverGiftMsg? = null,
@ProtoNumber(40) var bitapp_msg: BitAppMsg? = null,
@ProtoNumber(41) var open_qq_data: OpenQQData? = null,
@ProtoNumber(42) var apollo_msg: ApolloActMsg? = null,
@ProtoNumber(43) var group_pub_acc_info: GroupPubAccountInfo? = null,
@ProtoNumber(44) var bless_msg: BlessingMessage? = null,
@ProtoNumber(45) var src_msg: SourceMsg? = null,
@ProtoNumber(46) var lola_msg: LolaMsg? = null,
@ProtoNumber(47) var group_business_msg: GroupBusinessMsg? = null,
@ProtoNumber(48) var msg_workflow_notify: WorkflowNotifyMsg? = null,
@ProtoNumber(49) var pat_elem: PatsElem? = null,
@ProtoNumber(50) var group_post_elem: GroupPostElem? = null,
@ProtoNumber(51) var light_app: LightAppElem? = null,
@ProtoNumber(52) var eim_info: EIMInfo? = null,
@ProtoNumber(53) var commonElem: CommonElem? = null,*/
)
@Serializable
data class GeneralFlags(
@ProtoNumber(1) var uint32_bubble_diy_text_id: UInt = 0u,
@ProtoNumber(2) var uint32_group_flag_new: UInt = 0u,
@ProtoNumber(3) var uint64_uin: ULong = 0u,
@ProtoNumber(4) var bytes_rp_id: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(5) var uint32_prp_fold: UInt = 0u,
@ProtoNumber(6) var long_text_flag: UInt = 0u,
@ProtoNumber(7) var long_text_resid: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(8) var uint32_group_type: UInt = 0u,
@ProtoNumber(9) var uint32_to_uin_flag: UInt = 0u,
@ProtoNumber(10) var uint32_glamour_level: UInt = 0u,
@ProtoNumber(11) var uint32_member_level: UInt = 0u,
@ProtoNumber(12) var uint64_group_rank_seq: ULong = 0u,
@ProtoNumber(13) var uint32_olympic_torch: UInt = 0u,
@ProtoNumber(14) var babyq_guide_msg_cookie: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(15) var uin32_expert_flag: UInt = 0u,
@ProtoNumber(16) var uint32_bubble_sub_id: UInt = 0u,
@ProtoNumber(17) var pendantId: ULong = 0u,
@ProtoNumber(18) var bytes_rp_index: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoNumber(19) var reserve: ByteArray = EMPTY_BYTE_ARRAY,
)

View File

@ -1,67 +0,0 @@
package protobuf.msg
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
@Serializable
class PbSendMsgReq(
@ProtoNumber(1) var routingHead: RoutingHead,
@ProtoNumber(2) var contentHead: ContentHead,
@ProtoNumber(3) var msgBody: MsgBody,
@ProtoNumber(4) var msgSeq: ULong = 0u,
@ProtoNumber(5) var msgRand: UInt = 0u,
//@ProtoNumber(6) var sync_cookie: ByteArray = EMPTY_BYTE_ARRAY,
//@ProtoNumber(7) var app_share: AppShareInfo? = null,
@ProtoNumber(8) var msgVia: UInt = 0u,
//@ProtoNumber(9) var data_statist: UInt = 0u,
//@ProtoNumber(10) var multi_msg_assist: MultiMsgAssist? = null,
//@ProtoNumber(11) var input_notify_info: PbInputNotifyInfo? = null,
//@ProtoNumber(12) var msgCtrl: MsgCtrl? = null,
//@ProtoNumber(13) var receipt_req: ReceiptReq? = null,
//@ProtoNumber(14) var multi_send_seq: UInt = 0u,
): Protobuf<PbSendMsgReq>
@Serializable
data class ContentHead(
@ProtoNumber(1) var pkg_num: UInt = 0u,
@ProtoNumber(2) var pkg_index: UInt = 0u,
@ProtoNumber(3) var div_seq: UInt = 0u,
@ProtoNumber(4) var auto_reply: UInt = 0u,
)
@Serializable
class RoutingHead(
@ProtoNumber(1) var c2c: C2C? = null,
@ProtoNumber(2) var grp: Grp? = null,
// @ProtoNumber(3) var grp_tmp: GrpTmp? = null,
//@ProtoNumber(4) var dis: Dis? = null,
// @ProtoNumber(5) var dis_tmp: DisTmp? = null,
// @ProtoNumber(6) var wpa_tmp: WPATmp? = null,
// @ProtoNumber(7) var secret_file: SecretFileHead? = null,
// @ProtoNumber(8) var public_plat: PublicPlat? = null,
/*@ProtoNumber(9) var trans_msg: TransMsg? = null,
@ProtoNumber(10) var address_list: AddressListTmp? = null,
@ProtoNumber(11) var rich_status_tmp: RichStatusTmp? = null,
@ProtoNumber(12) var trans_cmd: TransCmd? = null,
@ProtoNumber(13) var accost_tmp: AccostTmp? = null,
@ProtoNumber(14) var pub_group_tmp: PubGroupTmp? = null,
@ProtoNumber(15) var trans_0x211: Trans0x211? = null,
@ProtoNumber(16) var business_wpa_tmp: BusinessWPATmp? = null,
@ProtoNumber(17) var auth_tmp: AuthTmp? = null,
@ProtoNumber(18) var bsns_tmp: BsnsTmp? = null,
@ProtoNumber(19) var qq_querybusiness_tmp: QQQueryBusinessTmp? = null,
@ProtoNumber(20) var nearby_dating_tmp: NearByDatingTmp? = null,
@ProtoNumber(21) var nearby_assistant_tmp: NearByAssistantTmp? = null,
@ProtoNumber(22) var comm_tmp: CommTmp? = null,*/
)
@Serializable
class C2C(
@ProtoNumber(1) var to_uin: ULong = 0u,
)
@Serializable
class Grp(
@ProtoNumber(1) var groupCode: ULong = 0u,
)

View File

@ -3,11 +3,11 @@ package protobuf.push
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import moe.fuqiuluo.symbols.Protobuf
import protobuf.message.NtMessage
import protobuf.message.PushMsgBody
@Serializable
data class MessagePush(
@ProtoNumber(1) val msgBody: NtMessage? = null,
@ProtoNumber(1) val msgBody: PushMsgBody? = null,
@ProtoNumber(4) val clientInfo: MessagePushClientInfo? = null,
): Protobuf<MessagePush>

View File

@ -9,7 +9,6 @@ import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
import moe.fuqiuluo.shamrock.tools.slice
import moe.fuqiuluo.shamrock.tools.toHexString
import moe.fuqiuluo.shamrock.utils.DeflateTools
import moe.fuqiuluo.symbols.decode
import moe.fuqiuluo.symbols.decodeProtobuf
import protobuf.oidb.cmd0x6d7.CreateFolderReq
import protobuf.oidb.cmd0x6d7.DeleteFolderReq

View File

@ -22,7 +22,6 @@ import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
import moe.fuqiuluo.shamrock.tools.slice
import moe.fuqiuluo.shamrock.utils.PlatformUtils
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
import moe.fuqiuluo.symbols.decode
import moe.fuqiuluo.symbols.decodeProtobuf
import protobuf.auto.toByteArray
import protobuf.guild.GetGuildFeedsReq

View File

@ -1,5 +1,3 @@
@file:OptIn(DelicateCoroutinesApi::class)
package moe.fuqiuluo.qqinterface.servlet
import com.tencent.mobileqq.qroute.QRoute
@ -7,14 +5,13 @@ import com.tencent.mobileqq.troop.api.ITroopMemberNameService
import com.tencent.qqnt.kernel.api.IKernelService
import com.tencent.qqnt.kernel.nativeinterface.*
import com.tencent.qqnt.msg.api.IMsgService
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.json.JsonArray
import moe.fuqiuluo.qqinterface.servlet.msg.messageelement.toSegments
import moe.fuqiuluo.qqinterface.servlet.msg.toListMap
import moe.fuqiuluo.qqinterface.servlet.msg.toSegments
import moe.fuqiuluo.shamrock.helper.ContactHelper
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
@ -26,9 +23,9 @@ import moe.fuqiuluo.shamrock.tools.*
import moe.fuqiuluo.shamrock.utils.DeflateTools
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
import moe.fuqiuluo.shamrock.xposed.helper.msgService
import moe.fuqiuluo.symbols.decode
import moe.fuqiuluo.symbols.decodeProtobuf
import protobuf.auto.toByteArray
import protobuf.message.PushMsgBody
import protobuf.message.longmsg.*
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@ -295,27 +292,27 @@ internal object MsgSvc : BaseSvc() {
if (it.command == "MultiMsg") {
return Result.success(it.data?.body?.map { msg ->
val chatType =
if (msg.content!!.msgType == 82) MsgConstant.KCHATTYPEGROUP else MsgConstant.KCHATTYPEC2C
if (msg.contentHead!!.msgType == 82) MsgConstant.KCHATTYPEGROUP else MsgConstant.KCHATTYPEC2C
MessageDetail(
time = msg.content?.msgTime?.toInt() ?: 0,
time = msg.contentHead?.msgTime?.toInt() ?: 0,
msgType = MessageHelper.obtainDetailTypeByMsgType(chatType),
msgId = 0, // MessageHelper.generateMsgIdHash(chatType, msg.content!!.msgViaRandom), msgViaRandom 为空
realId = msg.content!!.msgSeq?.toInt() ?: 0,
realId = msg.contentHead!!.msgSeq?.toInt() ?: 0,
sender = MessageSender(
msg.head?.peer ?: 0,
msg.head?.groupInfo?.memberCard?.ifEmpty { msg.head?.forward?.friendName }
?: msg.head?.forward?.friendName ?: "",
msg.msgHead?.peer ?: 0,
msg.msgHead?.responseGrp?.memberCard?.ifEmpty { msg.msgHead?.forward?.friendName }
?: msg.msgHead?.forward?.friendName ?: "",
"unknown",
0,
msg.head?.peerUid ?: "",
msg.head?.peerUid ?: ""
msg.msgHead?.peerUid ?: "",
msg.msgHead?.peerUid ?: ""
),
message = msg.body?.rich?.elements?.toSegments(chatType, msg.head?.peer.toString(), "0")
message = msg.body?.richText?.elements?.toSegments(chatType, msg.msgHead?.peer.toString(), "0")
?.toListMap() ?: emptyList(),
peerId = msg.head?.peer ?: 0,
groupId = if (chatType == MsgConstant.KCHATTYPEGROUP) msg.head?.groupInfo?.groupCode?.toLong()
peerId = msg.msgHead?.peer ?: 0,
groupId = if (chatType == MsgConstant.KCHATTYPEGROUP) msg.msgHead?.responseGrp?.groupCode?.toLong()
?: 0 else 0,
targetId = if (chatType != MsgConstant.KCHATTYPEGROUP) msg.head?.peer ?: 0 else 0
targetId = if (chatType != MsgConstant.KCHATTYPEGROUP) msg.msgHead?.peer ?: 0 else 0
)
}
?: return Result.failure(Exception("Msg is empty")))

View File

@ -9,19 +9,18 @@ import io.ktor.utils.io.core.writeFully
import io.ktor.utils.io.core.writeInt
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.encodeToByteArray
import moe.fuqiuluo.shamrock.remote.action.handlers.GetHistoryMsg
import moe.fuqiuluo.shamrock.remote.service.listener.AioListener
import moe.fuqiuluo.shamrock.tools.broadcast
import moe.fuqiuluo.shamrock.utils.DeflateTools
import protobuf.message.element.JsonElement
import protobuf.message.NtMessage
import protobuf.message.MessageContent
import protobuf.message.MessageElement
import protobuf.message.RichMessage
import protobuf.message.MessageHead
import protobuf.message.MessageBody
import protobuf.message.element.LightAppElem
import protobuf.message.PushMsgBody
import protobuf.message.ContentHead
import protobuf.message.Elem
import protobuf.message.RichText
import protobuf.message.ResponseHead
import protobuf.message.MsgBody
import protobuf.push.MessagePush
import mqq.app.MobileQQ
import protobuf.auto.toByteArray
@ -34,14 +33,14 @@ internal object PacketSvc: BaseSvc() {
suspend fun fakeSelfRecvJsonMsg(msgService: IKernelMsgService, content: String): Long {
return fakeReceiveSelfMsg(msgService) {
listOf(
MessageElement(
json = JsonElement((byteArrayOf(1) + DeflateTools.compress(content.toByteArray())))
Elem(
lightApp = LightAppElem((byteArrayOf(1) + DeflateTools.compress(content.toByteArray())))
)
)
}
}
private suspend fun fakeReceiveSelfMsg(msgService: IKernelMsgService, builder: () -> List<MessageElement>): Long {
private suspend fun fakeReceiveSelfMsg(msgService: IKernelMsgService, builder: () -> List<Elem>): Long {
val latestMsg = withTimeoutOrNull(3000) {
suspendCancellableCoroutine {
msgService.getMsgs(Contact(MsgConstant.KCHATTYPEC2C, app.currentUid, ""), 0L, 1, true) { code, why, msgs ->
@ -52,27 +51,27 @@ internal object PacketSvc: BaseSvc() {
val msgSeq = (latestMsg?.msgSeq ?: 0) + 1
val msgPush = MessagePush(
msgBody = NtMessage(
msgHead = MessageHead(
msgBody = PushMsgBody(
msgHead = ResponseHead(
peer = app.longAccountUin,
peerUid = app.currentUid,
flag = 1001,
receiver = app.longAccountUin,
receiverUid = app.currentUid
),
contentHead = MessageContent(
contentHead = ContentHead(
msgType = 166,
msgSubType = 11,
msgSeq = msgSeq,
msgViaRandom = msgSeq,
msgTime = System.currentTimeMillis() / 1000,
u2 = 1,
msgSeq_ = msgSeq,
sequence = msgSeq,
msgRandom = msgService.getMsgUniqueId(System.currentTimeMillis()),
u4 = msgSeq - 2,
u5 = msgSeq
),
body = MessageBody(RichMessage(
body = MsgBody(RichText(
elements = builder()
))
)

View File

@ -0,0 +1,79 @@
package moe.fuqiuluo.qqinterface.servlet.msg
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import moe.fuqiuluo.qqinterface.servlet.msg.converter.MessageElementConverter
import moe.fuqiuluo.qqinterface.servlet.msg.converter.MsgElementConverter
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.MessageHelper
import protobuf.message.Elem
@JvmName("elemListToSegments")
internal suspend fun List<Elem>.toSegments(
chatType: Int,
peerId: String,
subPeer: String
): List<MessageSegment> {
val messageData = arrayListOf<MessageSegment>()
this.forEach { msg ->
kotlin.runCatching {
val elementType = if (msg.text != null) {
1
} else if (msg.face != null) {
2
} else if (msg.lightApp != null) {
51
} else if (msg.commonElem != null) {
53
} else
throw UnsupportedOperationException("不支持的消息element类型$msg")
val converter = MessageElementConverter[elementType]
converter?.invoke(chatType, peerId, subPeer, msg)
?: throw UnsupportedOperationException("不支持的消息element类型$elementType")
}.onSuccess {
messageData.add(it)
}.onFailure {
if (it is UnknownError) {
// 不处理的消息类型抛出unknown error
} else {
LogCenter.log("消息element转换错误$it", Level.WARN)
}
}
}
return messageData
}
@JvmName("msgElementListToSegments")
internal suspend fun List<MsgElement>.toSegments(chatType: Int, peerId: String, subPeer: String): List<MessageSegment> {
val messageData = arrayListOf<MessageSegment>()
this.forEach { msg ->
kotlin.runCatching {
val converter = MsgElementConverter[msg.elementType]
converter?.invoke(chatType, peerId, subPeer, msg)
?: throw UnsupportedOperationException("不支持的消息element类型${msg.elementType}")
}.onSuccess {
messageData.add(it)
}.onFailure {
if (it is UnknownError) {
// 不处理的消息类型抛出unknown error
} else {
LogCenter.log("消息element转换错误$it, elementType: ${msg.elementType}", Level.WARN)
}
}
}
return messageData
}
internal suspend fun List<MsgElement>.toCQCode(chatType: Int, peerId: String, subPeer: String): String {
if (this.isEmpty()) {
return ""
}
return MessageHelper.nativeEncodeCQCode(this.toSegments(chatType, peerId, subPeer).map {
val params = hashMapOf<String, String>()
params["_type"] = it.type
it.data.forEach { (key, value) ->
params[key] = value.toString()
}
params
})
}

View File

@ -1,52 +1,16 @@
package moe.fuqiuluo.qqinterface.servlet.msg.messageelement
package moe.fuqiuluo.qqinterface.servlet.msg.converter
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt
import moe.fuqiuluo.qqinterface.servlet.msg.MessageSegment
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.utils.DeflateTools
import moe.fuqiuluo.shamrock.tools.asJsonObject
import moe.fuqiuluo.shamrock.tools.asString
import protobuf.message.MessageElement
import protobuf.message.Elem
internal suspend fun List<MessageElement>.toSegments(
chatType: Int,
peerId: String,
subPeer: String
): List<MessageSegment> {
val messageData = arrayListOf<MessageSegment>()
this.forEach { msg ->
kotlin.runCatching {
val elementType = if (msg.text != null) {
1
} else if (msg.face != null) {
2
} else if (msg.json != null) {
51
} else if (msg.comm != null) {
53
} else
throw UnsupportedOperationException("不支持的消息element类型$msg")
val converter = MessageElementConverter[elementType]
converter?.invoke(chatType, peerId, subPeer, msg)
?: throw UnsupportedOperationException("不支持的消息element类型$elementType")
}.onSuccess {
messageData.add(it)
}.onFailure {
if (it is UnknownError) {
// 不处理的消息类型抛出unknown error
} else {
LogCenter.log("消息element转换错误$it", Level.WARN)
}
}
}
return messageData
}
internal typealias IMessageElementConverter = suspend (Int, String, String, MessageElement) -> MessageSegment
internal typealias IMessageElementConverter = suspend (Int, String, String, Elem) -> MessageSegment
internal object MessageElementConverter {
private val convertMap = hashMapOf(
@ -76,7 +40,7 @@ internal object MessageElementConverter {
chatType: Int,
peerId: String,
subPeer: String,
element: MessageElement
element: Elem
): MessageSegment {
val text = element.text!!
if (text.attr6Buf != null) {
@ -89,23 +53,11 @@ internal object MessageElementConverter {
"qq" to uin
)
)
} else if (text.pbReserve != null) {
val resv = text.pbReserve!!
return MessageSegment(
type = "at",
data = hashMapOf(
"qq" to when (resv.atType) {
2 -> resv.atMemberTinyid!!
4 -> resv.atChannelInfo!!.channelId!!
else -> throw UnsupportedOperationException("Unknown at type: ${resv.atType}")
}
)
)
} else {
return MessageSegment(
type = "text",
data = hashMapOf(
"text" to text.text!!
"text" to text.str!!
)
)
}
@ -340,9 +292,9 @@ internal object MessageElementConverter {
chatType: Int,
peerId: String,
subPeer: String,
element: MessageElement
element: Elem
): MessageSegment {
val data = element.json!!.data!!
val data = element.lightApp!!.data!!
val jsonStr =
(if (data[0].toInt() == 1) DeflateTools.uncompress(data.sliceArray(1 until data.size)) else data.sliceArray(1 until data.size)).toString()
val json = jsonStr.asJsonObject

View File

@ -1,8 +1,11 @@
package moe.fuqiuluo.qqinterface.servlet.msg.msgelement
package moe.fuqiuluo.qqinterface.servlet.msg.converter
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import kotlinx.serialization.json.*
import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import moe.fuqiuluo.qqinterface.servlet.msg.MessageSegment
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
import moe.fuqiuluo.shamrock.helper.ContactHelper
@ -16,41 +19,6 @@ import moe.fuqiuluo.shamrock.tools.asJsonObject
import moe.fuqiuluo.shamrock.tools.asString
import moe.fuqiuluo.shamrock.tools.hex2ByteArray
internal suspend fun List<MsgElement>.toSegments(chatType: Int, peerId: String, subPeer: String): List<MessageSegment> {
val messageData = arrayListOf<MessageSegment>()
this.forEach { msg ->
kotlin.runCatching {
val converter = MsgElementConverter[msg.elementType]
converter?.invoke(chatType, peerId, subPeer, msg)
?: throw UnsupportedOperationException("不支持的消息element类型${msg.elementType}")
}.onSuccess {
messageData.add(it)
}.onFailure {
if (it is UnknownError) {
// 不处理的消息类型抛出unknown error
} else {
LogCenter.log("消息element转换错误$it, elementType: ${msg.elementType}", Level.WARN)
}
}
}
return messageData
}
internal suspend fun List<MsgElement>.toCQCode(chatType: Int, peerId: String, subPeer: String): String {
if (this.isEmpty()) {
return ""
}
return MessageHelper.nativeEncodeCQCode(this.toSegments(chatType, peerId, subPeer).map {
val params = hashMapOf<String, String>()
params["_type"] = it.type
it.data.forEach { (key, value) ->
params[key] = value.toString()
}
params
})
}
internal typealias IMsgElementConverter = suspend (Int, String, String, MsgElement) -> MessageSegment
internal object MsgElementConverter {

View File

@ -0,0 +1,539 @@
package moe.fuqiuluo.qqinterface.servlet.msg.maker
import android.graphics.BitmapFactory
import androidx.exifinterface.media.ExifInterface
import com.tencent.qqnt.kernel.nativeinterface.*
import kotlinx.serialization.json.JsonObject
import moe.fuqiuluo.qqinterface.servlet.CardSvc
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
import moe.fuqiuluo.qqinterface.servlet.transfile.*
import moe.fuqiuluo.qqinterface.servlet.transfile.PictureResource
import moe.fuqiuluo.qqinterface.servlet.transfile.Private
import moe.fuqiuluo.qqinterface.servlet.transfile.Transfer
import moe.fuqiuluo.qqinterface.servlet.transfile.Troop
import moe.fuqiuluo.shamrock.helper.*
import moe.fuqiuluo.shamrock.helper.ActionMsgException
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.LogicException
import moe.fuqiuluo.shamrock.helper.ParamsException
import moe.fuqiuluo.shamrock.tools.*
import moe.fuqiuluo.shamrock.utils.DeflateTools
import moe.fuqiuluo.shamrock.utils.FileUtils
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
import moe.fuqiuluo.shamrock.xposed.helper.msgService
import protobuf.auto.toByteArray
import protobuf.message.Elem
import protobuf.message.element.*
import protobuf.message.element.commelem.*
import java.io.File
import java.nio.ByteBuffer
import kotlin.random.Random
import kotlin.random.nextULong
internal typealias IMessageElementMaker = suspend (Int, Long, String, JsonObject) -> Result<Elem>
internal object MessageElementMaker {
private val makerArray = hashMapOf(
"text" to MessageElementMaker::createTextElem,
"at" to MessageElementMaker::createAtElem,
"face" to MessageElementMaker::createFaceElem,
"pic" to MessageElementMaker::createImageElem,
"image" to MessageElementMaker::createImageElem,
// "voice" to MessageElementMaker::createRecordElem,
// "record" to MessageElementMaker::createRecordElem,
// "video" to MessageElementMaker::createVideoElem,
"markdown" to MessageElementMaker::createMarkdownElem,
"button" to MessageElementMaker::createButtonElem,
"inline_keyboard" to MessageElementMaker::createButtonElem,
// "dice" to MessageElementMaker::createDiceElem,
// "rps" to MessageElementMaker::createRpsElem,
"basketball" to MessageElementMaker::createBasketballElem,
"new_dice" to MessageElementMaker::createNewDiceElem,
"new_rps" to MessageElementMaker::createNewRpsElem,
"poke" to MessageElementMaker::createPokeElem,
// "anonymous" to MessageElementMaker::createAnonymousElem,
// "share" to MessageElementMaker::createShareElem,
// "contact" to MessageElementMaker::createContactElem,
// "location" to MessageElementMaker::createLocationElem,
// "music" to MessageElementMaker::createMusicElem,
"reply" to MessageElementMaker::createReplyElem,
// "touch" to MessageElementMaker::createTouchElem,
// "weather" to MessageElementMaker::createWeatherElem,
"json" to MessageElementMaker::createJsonElem,
//"node" to MessageMaker::createNodeElem,
//"multi_msg" to MessageMaker::createLongMsgStruct,
//"bubble_face" to MessageElementMaker::createBubbleFaceElem,
)
operator fun get(type: String): IMessageElementMaker? = makerArray[type]
private suspend fun createTextElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
data.checkAndThrow("text")
val elem = Elem(
text = TextMsg(data["text"].asString)
)
return Result.success(elem)
}
private suspend fun createAtElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
return when (chatType) {
MsgConstant.KCHATTYPEGROUP -> {
data.checkAndThrow("qq")
val qq: Long
val type: Int
val display = when (val qqStr = data["qq"].asString) {
"0", "all" -> {
qq = 0
type = 1
"@全体成员"
}
"online" -> {
qq = 0
type = 64
"@在线成员"
}
else -> {
qq = qqStr.toLong()
type = 0
"@" + (data["name"].asStringOrNull ?: GroupSvc.getTroopMemberInfoByUinV2(peerId, qqStr, true)
.let {
val info = it.getOrNull()
if (info == null)
LogCenter.log("无法获取群成员信息: $qqStr", Level.ERROR)
info?.troopnick
.ifNullOrEmpty(info?.friendnick)
.ifNullOrEmpty(qqStr)
})
}
}
val attr6: ByteBuffer = ByteBuffer.allocate(6)
attr6.put(byteArrayOf(0, 1, 0, 0, 0))
attr6.putChar(display.length.toChar())
attr6.putChar(type.toChar())
attr6.putBuf32Long(qq)
attr6.put(byteArrayOf(0, 0))
val elem = Elem(
text = TextMsg(str = display, attr6Buf = attr6.array())
)
Result.success(elem)
}
MsgConstant.KCHATTYPEC2C -> {
data.checkAndThrow("qq")
val qq = data["qq"].asString
val display =
"@" + (data["name"].asStringOrNull ?: CardSvc.getProfileCard(qq)
.onSuccess {
it.strNick.ifNullOrEmpty(qq)
}.onFailure {
LogCenter.log("无法获取QQ信息: $qq", Level.WARN)
})
val elem = Elem(
text = TextMsg(str = display)
)
Result.success(elem)
}
else -> Result.failure(ActionMsgException)
}
}
private suspend fun createFaceElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
data.checkAndThrow("id")
val elem = Elem(
face = FaceMsg(data["id"].asInt)
)
return Result.success(elem)
}
private suspend fun createImageElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
val isOriginal = data["original"].asBooleanOrNull ?: true
val isFlash = data["flash"].asBooleanOrNull ?: false
val filePath = data["file"].asStringOrNull
val url = data["url"].asStringOrNull
var file: File? = null
if (filePath != null) {
val md5 = filePath
.replace(regex = "[{}\\-]".toRegex(), replacement = "")
.split(".")[0].lowercase()
file = if (md5.length == 32) {
FileUtils.getFileByMd5(md5)
} else {
FileUtils.parseAndSave(filePath)
}
}
if ((file == null || !file.exists()) && url != null) {
file = FileUtils.parseAndSave(url)
}
if (file?.exists() == false) {
throw LogicException("Image(${file.name}) file is not exists, please check your filename.")
}
requireNotNull(file)
val md5HexStr = QQNTWrapperUtil.CppProxy.genFileMd5Hex(file.absolutePath)
val msgService = NTServiceFetcher.kernelService.msgService!!
val originalPath = msgService.getRichMediaFilePathForMobileQQSend(
RichMediaFilePathInfo(
2, 0, md5HexStr, file.name, 1, 0, null, "", true
)
)
if (!QQNTWrapperUtil.CppProxy.fileIsExist(originalPath) || QQNTWrapperUtil.CppProxy.getFileSize(
originalPath
) != file.length()
) {
val thumbPath = msgService.getRichMediaFilePathForMobileQQSend(
RichMediaFilePathInfo(
2, 0, md5HexStr, file.name, 2, 720, null, "", true
)
)
QQNTWrapperUtil.CppProxy.copyFile(file.absolutePath, originalPath)
QQNTWrapperUtil.CppProxy.copyFile(file.absolutePath, thumbPath)
}
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, options)
val exifInterface = ExifInterface(file.absolutePath)
val orientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED
)
val picWidth: Int
val picHeight: Int
if (orientation != ExifInterface.ORIENTATION_ROTATE_90 && orientation != ExifInterface.ORIENTATION_ROTATE_270) {
picWidth = options.outWidth
picHeight = options.outHeight
} else {
picWidth = options.outHeight
picHeight = options.outWidth
}
val elem = when (chatType) {
MsgConstant.KCHATTYPEGROUP -> {
Transfer with Troop(peerId) trans PictureResource(file)
Elem(
customFace = CustomFace(
filePath = "${md5HexStr.substring(0, 8)}-${md5HexStr.substring(8, 4)}-${
md5HexStr.substring(
12,
4
)
}-${md5HexStr.substring(16, 4)}-${md5HexStr.substring(20, 12)}.${FileUtils.getFileType(file)}",
fileId = 0u,
serverIp = 0u,
serverPort = 0u,
fileType = 1001u,
useful = 1u,
md5 = md5HexStr.hex2ByteArray(),
bizType = data["subType"].asIntOrNull?.toUInt(),
imageType = FileUtils.getPicType(file).toUInt(),
width = picWidth.toUInt(),
height = picHeight.toUInt(),
size = QQNTWrapperUtil.CppProxy.getFileSize(file.absolutePath).toUInt(),
origin = if (isOriginal) 1u else 0u,
thumbWidth = 0u,
thumbHeight = 0u,
pbReserve = CustomFace.Companion.PbReserve(field1 = 0)
)
)
}
MsgConstant.KCHATTYPEC2C -> {
Transfer with Private(peerId) trans PictureResource(file)
Elem(
notOnlineImage = NotOnlineImage(
filePath = "${md5HexStr}.${FileUtils.getFileType(file)}".toByteArray(),
fileLen = QQNTWrapperUtil.CppProxy.getFileSize(file.absolutePath).toUInt(),
downloadPath = "".toByteArray(),
imgType = FileUtils.getPicType(file).toUInt(),
picMd5 = md5HexStr.hex2ByteArray(),
picHeight = picWidth.toUInt(),
picWidth = picHeight.toUInt(),
resId = "".toByteArray(),
original = if (isOriginal) 1u else 0u, // true
pbReserve = NotOnlineImage.Companion.PbReserve(field1 = 0)
)
)
}
else -> throw LogicException("Not supported chatType($chatType) for PictureMsg")
}
return Result.success(elem)
}
private suspend fun createReplyElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
data.checkAndThrow("id")
val msgHash = data["id"].asInt
val mapping = MessageHelper.getMsgMappingByHash(msgHash)
?: return Result.failure(Exception("不存在该消息映射,无法回复消息"))
if (mapping.qqMsgId == 0L) {
// 貌似获取失败了555
LogCenter.log("无法获取被回复消息", Level.ERROR)
return Result.failure(Exception("无法获取被回复消息"))
}
val elem = if (data.containsKey("text")) {
data.checkAndThrow("qq", "time", "seq")
Elem(
srcMsg = SourceMsg(
origSeqs = listOf(data["seq"].asInt),
senderUin = data["qq"].asString.toULong(),
time = data["time"].asString.toULong(),
flag = 1u,
elems = listOf(
Elem(
text = TextMsg(
data["text"].asString
)
)
),
type = 0u,
pbReserve = SourceMsg.Companion.PbReserve(
field3 = Random.nextULong(),
field8 = Random.nextInt(0, 10000)
),
)
)
} else {
val msg =
MsgSvc.getMsgByQMsgId(chatType, mapping.peerId, mapping.qqMsgId).getOrNull() ?: return Result.failure(
Exception("无法获取被回复消息")
)
Elem(
srcMsg = SourceMsg(
origSeqs = listOf(msg.msgSeq.toInt()),
senderUin = msg.senderUin.toULong(),
time = msg.msgTime.toULong(),
flag = 1u,
// elems = msg.elements.toSegments(),
type = 0u,
pbReserve = SourceMsg.Companion.PbReserve(
field3 = Random.nextULong(),
senderUid = msg.senderUid,
receiverUid = TicketSvc.getUid(),
field8 = Random.nextInt(0, 10000)
),
)
)
}
return Result.success(elem)
}
private suspend fun createJsonElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
data.checkAndThrow("data")
val elem = Elem(
lightApp = LightAppElem(
data = DeflateTools.compress(data.toString().toByteArray())
)
)
return Result.success(elem)
}
private suspend fun createPokeElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
data.checkAndThrow("type", "id")
val elem = Elem(
commonElem = CommonElem(
serviceType = 2,
elem = PokeExtra(
type = data["type"].asInt,
field7 = 0,
field8 = 0
).toByteArray(),
businessType = data["id"].asInt
)
)
return Result.success(elem)
}
private suspend fun createBasketballElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
val elem = Elem(
commonElem = CommonElem(
serviceType = 37,
elem = QFaceExtra(
packId = "1",
stickerId = "13",
faceId = 114,
field4 = 1,
field5 = 2,
field6 = "",
faceText = "/篮球",
field9 = 1
).toByteArray(),
businessType = 2
)
)
return Result.success(elem)
}
private suspend fun createNewDiceElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
val elem = Elem(
commonElem = CommonElem(
serviceType = 37,
elem = QFaceExtra(
packId = "1",
stickerId = "33",
faceId = 358,
field4 = 1,
field5 = 2,
field6 = "",
faceText = "/骰子",
field9 = 1
).toByteArray(),
businessType = 2
)
)
return Result.success(elem)
}
private suspend fun createNewRpsElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
val elem = Elem(
commonElem = CommonElem(
serviceType = 37,
elem = QFaceExtra(
packId = "1",
stickerId = "34",
faceId = 359,
field4 = 1,
field5 = 2,
field6 = "",
faceText = "/包剪锤",
field9 = 1
).toByteArray(),
businessType = 1
)
)
return Result.success(elem)
}
private suspend fun createMarkdownElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
data.checkAndThrow("content")
val elem = Elem(
commonElem = CommonElem(
serviceType = 45,
elem = MarkdownExtra(data["content"].asString).toByteArray(),
businessType = 1
)
)
return Result.success(elem)
}
private suspend fun createButtonElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<Elem> {
data.checkAndThrow("rows")
val elem = Elem(
commonElem = CommonElem(
serviceType = 46,
elem = ButtonExtra(
field1 = Object1(
rows = data["rows"].asJsonArray.map { row ->
Row(buttons = row.asJsonArray.map {
val button = it.asJsonObject
val renderData = button["render_data"].asJsonObject
val action = button["action"].asJsonObject
Button(
id = button["id"].asIntOrNull,
renderData = RenderData(
label = renderData["label"].asString,
visitedLabel = renderData["visited_label"].asString,
style = renderData["style"].asInt
),
action = Action(
type = action["type"].asInt,
permission = Permission(
type = action["permission"].asJsonObject["type"].asInt,
specifyRoleIds = action["permission"].asJsonObject["specify_role_ids"].asJsonArrayOrNull?.map { id -> id.asString },
specifyUserIds = action["permission"].asJsonObject["specify_user_ids"].asJsonArrayOrNull?.map { id -> id.asString }
),
unsupportTips = action["unsupport_tips"].asString,
data = action["data"].asString,
reply = action["reply"].asBooleanOrNull,
enter = action["enter"].asBooleanOrNull
)
)
})
},
appid = data["appid"].asIntOrNull
)
).toByteArray(),
businessType = 1
)
)
return Result.success(elem)
}
private fun JsonObject.checkAndThrow(vararg key: String) {
key.forEach {
if (!containsKey(it)) throw ParamsException(it)
}
}
}

View File

@ -1,4 +1,4 @@
package moe.fuqiuluo.qqinterface.servlet.msg.msgelement
package moe.fuqiuluo.qqinterface.servlet.msg.maker
import android.graphics.BitmapFactory
import androidx.exifinterface.media.ExifInterface
@ -85,6 +85,7 @@ internal object MsgElementMaker {
//"node" to MessageMaker::createNodeElem,
//"multi_msg" to MessageMaker::createLongMsgStruct,
"bubble_face" to MsgElementMaker::createBubbleFaceElem,
"button" to MsgElementMaker::createInlineKeywordElem,
"inline_keyboard" to MsgElementMaker::createInlineKeywordElem
)

View File

@ -1,183 +0,0 @@
package moe.fuqiuluo.qqinterface.servlet.msg.messageelement
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
import kotlinx.serialization.json.JsonObject
import moe.fuqiuluo.qqinterface.servlet.GProSvc
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.shamrock.helper.*
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.ParamsException
import moe.fuqiuluo.shamrock.tools.*
import moe.fuqiuluo.shamrock.utils.DeflateTools
import protobuf.message.MessageElement
import protobuf.message.element.FaceElement
import protobuf.message.element.JsonElement
import protobuf.message.element.TextElement
import java.nio.ByteBuffer
internal typealias IMessageElementMaker = suspend (Int, Long, String, JsonObject) -> Result<MessageElement>
internal object MessageElementMaker {
private val makerArray = hashMapOf(
"text" to MessageElementMaker::createTextElem,
"face" to MessageElementMaker::createFaceElem,
// "pic" to MessageElementMaker::createImageElem,
// "image" to MessageElementMaker::createImageElem,
// "voice" to MessageElementMaker::createRecordElem,
// "record" to MessageElementMaker::createRecordElem,
"at" to MessageElementMaker::createAtElem,
// "video" to MessageElementMaker::createVideoElem,
// "markdown" to MessageElementMaker::createMarkdownElem,
// "dice" to MessageElementMaker::createDiceElem,
// "rps" to MessageElementMaker::createRpsElem,
// "poke" to MessageElementMaker::createPokeElem,
// "anonymous" to MessageElementMaker::createAnonymousElem,
// "share" to MessageElementMaker::createShareElem,
// "contact" to MessageElementMaker::createContactElem,
// "location" to MessageElementMaker::createLocationElem,
// "music" to MessageElementMaker::createMusicElem,
// "reply" to MessageElementMaker::createReplyElem,
// "touch" to MessageElementMaker::createTouchElem,
// "weather" to MessageElementMaker::createWeatherElem,
"json" to MessageElementMaker::createJsonElem,
//"new_dice" to MessageElementMaker::createNewDiceElem,
//"new_rps" to MessageElementMaker::createNewRpsElem,
//"basketball" to MessageElementMaker::createBasketballElem,
//"node" to MessageMaker::createNodeElem,
//"multi_msg" to MessageMaker::createLongMsgStruct,
//"bubble_face" to MessageElementMaker::createBubbleFaceElem,
)
operator fun get(type: String): IMessageElementMaker? = makerArray[type]
private suspend fun createTextElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<MessageElement> {
data.checkAndThrow("text")
val elem = MessageElement(
text = TextElement(data["text"].asString)
)
return Result.success(elem)
}
private suspend fun createFaceElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<MessageElement> {
data.checkAndThrow("id")
val elem = MessageElement(
face = FaceElement(data["id"].asInt)
)
return Result.success(elem)
}
private suspend fun createAtElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<MessageElement> {
return if (chatType == MsgConstant.KCHATTYPEGROUP) {
data.checkAndThrow("qq")
val qq: Long
val type: Int
lateinit var display: String
when (val qqStr = data["qq"].asString) {
"0", "all" -> {
qq = 0
type = 1
display = "@全体成员"
}
"online" -> {
qq = 0
type = 64
display = "@在线成员"
}
else -> {
qq = qqStr.toLong()
type = 0
display =
"@" + (data["name"].asStringOrNull ?: GroupSvc.getTroopMemberInfoByUinV2(peerId, qqStr, true)
.onSuccess {
it.troopnick
.ifEmpty { it.friendnick }
.ifEmpty { qqStr }
}.onFailure {
LogCenter.log("无法获取群成员信息: $qqStr", Level.ERROR)
})
}
}
val attr6: ByteBuffer = ByteBuffer.allocate(6)
attr6.put(byteArrayOf(0, 1, 0, 0, 0))
attr6.putChar(display.length.toChar())
attr6.putChar(type.toChar())
attr6.putBuf32Long(qq)
attr6.put(byteArrayOf(0, 0))
val elem = MessageElement(
text = TextElement(text = display, attr6Buf = attr6.array())
)
Result.success(elem)
} else if (chatType == MsgConstant.KCHATTYPEGUILD) {
data.checkAndThrow("qq")
val qq: Long
val type: Int
lateinit var display: String
when (val qqStr = data["qq"].asString) {
"0", "all" -> {
type = 2
display = "@全体成员"
}
else -> {
qq = qqStr.toLong()
type = 2
display =
"@" + (data["name"].asStringOrNull ?: GProSvc.getUserGuildInfo(0UL, 0UL)
.onSuccess {
it.nickName.ifNullOrEmpty(qqStr)
}.onFailure {
LogCenter.log("无法获取频道组成员信息: $qqStr", Level.ERROR)
})
}
}
val elem = MessageElement(
text = TextElement(text = display, pbReserve = TextElement.Companion.TextResvAttr(atType = type))
)
Result.success(elem)
} else Result.failure(ActionMsgException)
}
private suspend fun createJsonElem(
chatType: Int,
msgId: Long,
peerId: String,
data: JsonObject
): Result<MessageElement> {
data.checkAndThrow("data")
val elem = MessageElement(
json = JsonElement(
data = DeflateTools.compress(data.toString().toByteArray())
)
)
return Result.success(elem)
}
private fun JsonObject.checkAndThrow(vararg key: String) {
key.forEach {
if (!containsKey(it)) throw ParamsException(it)
}
}
}

View File

@ -16,8 +16,8 @@ import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import moe.fuqiuluo.qqinterface.servlet.msg.messageelement.MessageElementMaker
import moe.fuqiuluo.qqinterface.servlet.msg.msgelement.MsgElementMaker
import moe.fuqiuluo.qqinterface.servlet.msg.maker.MessageElementMaker
import moe.fuqiuluo.qqinterface.servlet.msg.maker.MsgElementMaker
import moe.fuqiuluo.shamrock.helper.db.MessageDB
import moe.fuqiuluo.shamrock.helper.db.MessageMapping
import moe.fuqiuluo.shamrock.remote.structures.SendMsgResult
@ -26,7 +26,7 @@ import moe.fuqiuluo.shamrock.tools.asJsonObjectOrNull
import moe.fuqiuluo.shamrock.tools.asString
import moe.fuqiuluo.shamrock.tools.json
import moe.fuqiuluo.shamrock.tools.jsonArray
import protobuf.message.MessageElement
import protobuf.message.Elem
import kotlin.coroutines.resume
import kotlin.math.abs
@ -323,8 +323,8 @@ internal object MessageHelper {
msgId: Long,
targetUin: String,
messageList: JsonArray
): Pair<Boolean, ArrayList<MessageElement>> {
val msgList = arrayListOf<MessageElement>()
): Pair<Boolean, ArrayList<Elem>> {
val msgList = arrayListOf<Elem>()
var hasActionMsg = false
messageList.forEach {
val msg = it.jsonObject

View File

@ -6,7 +6,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import moe.fuqiuluo.qqinterface.servlet.msg.msgelement.toSegments
import moe.fuqiuluo.qqinterface.servlet.msg.toSegments
import moe.fuqiuluo.qqinterface.servlet.msg.toListMap
import moe.fuqiuluo.shamrock.helper.MessageHelper
import moe.fuqiuluo.shamrock.helper.db.MessageDB

View File

@ -8,7 +8,7 @@ import moe.fuqiuluo.shamrock.remote.action.IActionHandler
import moe.fuqiuluo.shamrock.remote.service.data.MessageDetail
import moe.fuqiuluo.shamrock.remote.service.data.MessageSender
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import moe.fuqiuluo.qqinterface.servlet.msg.msgelement.toSegments
import moe.fuqiuluo.qqinterface.servlet.msg.toSegments
import moe.fuqiuluo.qqinterface.servlet.msg.toListMap
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
import moe.fuqiuluo.symbols.OneBotHandler

View File

@ -4,7 +4,7 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
import kotlinx.serialization.json.*
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
import moe.fuqiuluo.qqinterface.servlet.msg.msgelement.toSegments
import moe.fuqiuluo.qqinterface.servlet.msg.toSegments
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.MessageHelper
@ -15,7 +15,6 @@ import moe.fuqiuluo.shamrock.remote.service.data.ForwardMessageResult
import moe.fuqiuluo.shamrock.tools.*
import moe.fuqiuluo.symbols.OneBotHandler
import protobuf.message.*
import protobuf.message.longmsg.PushMsgBody
import java.util.*
import kotlin.random.Random
@ -96,20 +95,21 @@ internal object SendForwardMessage : IActionHandler() {
return@map null
}
if (record.chatType == MsgConstant.KCHATTYPEGROUP) groupUin = record.peerUin.toString()
if (record.chatType == MsgConstant.KCHATTYPEC2C) uid = record.peerUid
PushMsgBody(
head = MessageHead(
msgHead = ResponseHead(
peerUid = record.senderUid,
receiverUid = record.peerUid,
forward = MessageForward(
forward = ResponseForward(
friendName = record.sendNickName
),
groupInfo = if (record.chatType == MsgConstant.KCHATTYPEGROUP) GroupInfo(
responseGrp = if (record.chatType == MsgConstant.KCHATTYPEGROUP) ResponseGrp(
groupCode = record.peerUin.toULong(),
memberCard = record.sendMemberName,
u1 = 2
) else null
),
content = MessageContent(
contentHead = ContentHead(
msgType = when (record.chatType) {
MsgConstant.KCHATTYPEC2C -> 9
MsgConstant.KCHATTYPEGROUP -> 82
@ -118,9 +118,9 @@ internal object SendForwardMessage : IActionHandler() {
)
},
msgSubType = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
u1 = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
divSeq = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
msgViaRandom = record.msgId,
msgSeq_ = record.msgSeq, // idk what this is(i++)
sequence = record.msgSeq, // idk what this is(i++)
msgTime = record.msgTime,
u2 = 1,
u6 = 0,
@ -131,11 +131,11 @@ internal object SendForwardMessage : IActionHandler() {
u2 = 0,
u3 = 0,
ub641 = "",
Avatar = ""
avatar = ""
)
),
body = MessageBody(
rich = RichMessage(
body = MsgBody(
richText = RichText(
elements = MessageHelper.messageArrayToMessageElements(
record.chatType,
record.msgId,
@ -168,20 +168,20 @@ internal object SendForwardMessage : IActionHandler() {
)
} else if (data.containsKey("content")) {
PushMsgBody(
head = MessageHead(
msgHead = ResponseHead(
peer = data["uin"]?.asLong ?: TicketSvc.getUin().toLong(),
peerUid = data["uid"]?.asString ?: TicketSvc.getUid(),
receiverUid = TicketSvc.getUid(),
forward = MessageForward(
forward = ResponseForward(
friendName = data["name"]?.asStringOrNull ?: TicketSvc.getNickname()
)
),
content = MessageContent(
msgType = 9,
contentHead = ContentHead(
msgType = 9,
msgSubType = 175,
u1 = 175,
divSeq = 175,
msgViaRandom = Random.nextLong(),
msgSeq_ = data["seq"]?.asLong ?: Random.nextLong(),
sequence = data["seq"]?.asLong ?: Random.nextLong(),
msgTime = data["time"]?.asLong ?: (System.currentTimeMillis() / 1000),
u2 = 1,
u6 = 0,
@ -192,11 +192,11 @@ internal object SendForwardMessage : IActionHandler() {
u2 = 0,
u3 = 2,
ub641 = "",
Avatar = ""
avatar = ""
)
),
body = MessageBody(
rich = RichMessage(
body = MsgBody(
richText = RichText(
elements = MessageHelper.messageArrayToMessageElements(
1,
Random.nextLong(),
@ -211,15 +211,14 @@ internal object SendForwardMessage : IActionHandler() {
?: TicketSvc.getNickname()
}: "
}.onEach {
when (it.asJsonObject["type"].asString) {
"text" -> desc[i] += it.asJsonObject["data"].asJsonObject["text"].asString
"at" -> desc[i] += "@${it.asJsonObject["data"].asJsonObject["name"].asStringOrNull ?: it.asJsonObject["data"].asJsonObject["qq"].asString}"
val type = it.asJsonObject["type"].asString
val itData = it.asJsonObject["data"].asJsonObject
when (type) {
"text" -> desc[i] += itData["text"].asString
"at" -> desc[i] += "@${itData["name"].asStringOrNull ?: itData["qq"].asString}"
"face" -> desc[i] += "[表情]"
"image" -> desc[i] += "[图片]"
"voice" -> desc[i] += "[语音]"
"node" -> desc[i] += "[合并转发消息]"
}
}

View File

@ -1,50 +1,46 @@
package moe.fuqiuluo.shamrock.remote.action.handlers
import kotlinx.atomicfu.atomic
import kotlinx.serialization.encodeToByteArray
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
import moe.fuqiuluo.shamrock.remote.action.ActionSession
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
import moe.fuqiuluo.symbols.OneBotHandler
import protobuf.auto.toByteArray
import protobuf.msg.C2C
import protobuf.msg.ContentHead
import protobuf.msg.Elem
import protobuf.msg.GeneralFlags
import protobuf.msg.Grp
import protobuf.msg.MsgBody
import protobuf.msg.PbSendMsgReq
import protobuf.msg.RichText
import protobuf.msg.RoutingHead
import protobuf.message.*
import protobuf.message.element.GeneralFlags
import protobuf.message.routing.C2C
import protobuf.message.routing.Grp
import kotlin.random.Random
import kotlin.random.nextUInt
@OneBotHandler("send_msg_by_resid")
internal object SendMsgByResid: IActionHandler() {
internal object SendMsgByResid : IActionHandler() {
private val msgSeq = atomic(1000)
override suspend fun internalHandle(session: ActionSession): String {
val resid = session.getString("resid")
val peerId = session.getString("peer")
val req = PbSendMsgReq(
routingHead = RoutingHead().apply {
when(session.getStringOrNull("message_type")) {
"group" -> grp = Grp(peerId.toULong())
"private" -> c2c = C2C(peerId.toULong())
else -> grp = Grp(peerId.toULong())
}
routingHead = when (session.getStringOrNull("message_type")) {
"group" ->RoutingHead(grp = Grp(peerId.toUInt()))
"private" ->RoutingHead( c2c = C2C(peerId.toUInt()))
else ->RoutingHead( grp = Grp(peerId.toUInt()))
},
contentHead = ContentHead(1u, 0u, 0u, 0u),
contentHead = ContentHead(1, 0, 0, 0),
msgBody = MsgBody(
richText = RichText(arrayListOf(Elem(
generalFlags = GeneralFlags(
long_text_flag = 1u,
long_text_resid = resid.toByteArray()
richText = RichText(
elements = arrayListOf(
Elem(
generalFlags = GeneralFlags(
longTextFlag = 1u,
longTextResid = resid.toByteArray()
)
)
)
)))
)
),
msgSeq = msgSeq.incrementAndGet().toULong(),
msgSeq = msgSeq.incrementAndGet().toUInt(),
msgRand = Random.nextUInt(),
msgVia = 0u
)

View File

@ -12,7 +12,7 @@ import kotlinx.coroutines.launch
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
import moe.fuqiuluo.qqinterface.servlet.CardSvc
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.msg.msgelement.toSegments
import moe.fuqiuluo.qqinterface.servlet.msg.toSegments
import moe.fuqiuluo.qqinterface.servlet.msg.toJson
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.remote.service.data.push.GroupFileMsg

View File

@ -9,7 +9,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
import moe.fuqiuluo.qqinterface.servlet.msg.msgelement.toCQCode
import moe.fuqiuluo.qqinterface.servlet.msg.toCQCode
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.helper.Level

View File

@ -1,54 +1,37 @@
@file:OptIn(DelicateCoroutinesApi::class, ExperimentalSerializationApi::class)
package moe.fuqiuluo.shamrock.remote.service.listener
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
import kotlinx.coroutines.DelicateCoroutinesApi
import moe.fuqiuluo.shamrock.helper.ContactHelper
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.qqinterface.servlet.FriendSvc.requestFriendSystemMsgNew
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.GroupSvc.requestGroupSystemMsgNew
import moe.fuqiuluo.qqinterface.servlet.TicketSvc.getLongUin
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
import moe.fuqiuluo.shamrock.helper.MessageHelper
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeType
import moe.fuqiuluo.shamrock.tools.slice
import moe.fuqiuluo.shamrock.helper.ContactHelper
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.MessageHelper
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeType
import moe.fuqiuluo.shamrock.remote.service.data.push.RequestSubType
import moe.fuqiuluo.shamrock.tools.asJsonObject
import moe.fuqiuluo.shamrock.tools.asString
import moe.fuqiuluo.shamrock.tools.readBuf32Long
import moe.fuqiuluo.shamrock.tools.slice
import moe.fuqiuluo.shamrock.xposed.helper.PacketHandler
import moe.fuqiuluo.symbols.decode
import moe.fuqiuluo.symbols.decodeProtobuf
import protobuf.message.MessageContent
import protobuf.message.MessageHead
import protobuf.message.MessageBody
import protobuf.message.ContentHead
import protobuf.message.MsgBody
import protobuf.message.ResponseHead
import protobuf.message.multimedia.RichMediaForPicData
import protobuf.push.C2CCommonTipsEvent
import protobuf.push.C2CRecallEvent
import protobuf.push.FriendApplyEvent
import protobuf.push.GroupAdminChangeEvent
import protobuf.push.GroupApplyEvent
import protobuf.push.GroupBanEvent
import protobuf.push.GroupCommonTipsEvent
import protobuf.push.GroupInviteEvent
import protobuf.push.GroupInvitedApplyEvent
import protobuf.push.GroupListChangeEvent
import protobuf.push.MessagePush
import protobuf.push.MessagePushClientInfo
import protobuf.push.*
import java.util.regex.Pattern
private val RKEY_PATTERN = Pattern.compile("rkey=([A-Za-z0-9_-]+)")
@ -106,16 +89,16 @@ internal object PrimitiveListener {
}
}
} catch (e: Exception) {
LogCenter.log("onMsgPush(msgType: $msgType, subType: $subType): "+e.stackTraceToString(), Level.WARN)
LogCenter.log("onMsgPush(msgType: $msgType, subType: $subType): " + e.stackTraceToString(), Level.WARN)
}
}
private fun onGroupMessage(msgTime: Long, body: MessageBody) {
private fun onGroupMessage(msgTime: Long, body: MsgBody) {
/*runCatching {
body.rich?.elements?.filter {
it.comm != null && it.comm!!.type == 48
body.richText?.elements?.filter {
it.commonElem != null && it.commonElem!!.serviceType == 48
}?.map {
it.comm!!.data!!.decodeProtobuf<RichMediaForPicData>()
it.commonElem!!.elem!!.decodeProtobuf<RichMediaForPicData>()
}?.forEach {
it.display?.show?.download?.url?.let {
RKEY_PATTERN.matcher(it).takeIf {
@ -129,8 +112,8 @@ internal object PrimitiveListener {
}*/
}
private suspend fun onC2CPoke(msgTime: Long, richMsg: MessageBody) {
val event = richMsg.rawBuffer!!.decodeProtobuf<C2CCommonTipsEvent>()
private suspend fun onC2CPoke(msgTime: Long, body: MsgBody) {
val event = body.msgContent!!.decodeProtobuf<C2CCommonTipsEvent>()
if (event.params == null) return
val params = event.params!!.associate {
@ -155,9 +138,9 @@ internal object PrimitiveListener {
private suspend fun onFriendApply(
msgTime: Long,
clientInfo: MessagePushClientInfo,
richMsg: MessageBody
body: MsgBody
) {
val event = richMsg.rawBuffer!!.decodeProtobuf<FriendApplyEvent>()
val event = body.msgContent!!.decodeProtobuf<FriendApplyEvent>()
if (event.head == null) return
val head = event.head!!
val applierUid = head.applierUid
@ -188,55 +171,46 @@ internal object PrimitiveListener {
}
private suspend fun onCardChange(msgTime: Long, richMsg: MessageBody) {
LogCenter.log("群名片事件异常请尝试提交issue", Level.WARN)
/*try {
val readPacket = ByteReadPacket(richMsg.rawBuffer!!)
if(readPacket.readBuf32Long() ==
readPacket.discardExact(1)
detail = ProtoUtils.decodeFromByteArray(readPacket.readBytes(readPacket.readShort().toInt()))
readPacket.release()
} catch (e: Exception) {
LogCenter.log("onCardChange error: ${e.stackTraceToString()}", Level.WARN)
}
var detail = pb[1, 3, 2]
if (detail !is ProtoMap) {
}
val targetId = detail[1, 13, 2].asUtf8String
val newCardList = detail[1, 13, 3].asList
var newCard = ""
newCardList
.value
.forEach {
if (it[1].asInt == 1) {
newCard = it[2].asUtf8String
}
}
val groupId = detail[1, 13, 4].asLong
var oldCard = ""
val targetQQ = ContactHelper.getUinByUidAsync(targetId).toLong()
LogCenter.log("群组[$groupId]成员$targetQQ 群名片变动 -> $newCard")
// oldCard暂时获取不到
// GroupSvc.getTroopMemberInfoByUin(groupId.toString(), targetQQ.toString()).onSuccess {
// oldCard = it.troopnick
// }.onFailure {
// LogCenter.log("获取群成员信息失败!", Level.WARN)
private suspend fun onCardChange(msgTime: Long, body: MsgBody) {
// val event = runCatching {
// body.msgContent!!.decodeProtobuf<GroupCardChangeEvent>()
// }.getOrElse {
// val readPacket = ByteReadPacket(body.msgContent!!)
// readPacket.readBuf32Long()
// readPacket.discardExact(1)
//
// readPacket.readBytes(readPacket.readShort().toInt()).also {
// readPacket.release()
// }.decodeProtobuf<GroupCommonTipsEvent>()
// }
//
// val targetId = detail[1, 13, 2].asUtf8String
// val newCardList = detail[1, 13, 3].asList
// var newCard = ""
// newCardList
// .value
// .forEach {
// if (it[1].asInt == 1) {
// newCard = it[2].asUtf8String
// }
// }
// val groupId = detail[1, 13, 4].asLong
// var oldCard = ""
// val targetQQ = ContactHelper.getUinByUidAsync(targetId).toLong()
// LogCenter.log("群组[$groupId]成员$targetQQ 群名片变动 -> $newCard")
// // oldCard暂时获取不到
// if (!GlobalEventTransmitter.GroupNoticeTransmitter
// .transCardChange(msgTime, targetQQ, oldCard, newCard, groupId)
// ) {
// LogCenter.log("群名片变动推送失败!", Level.WARN)
// }
if (!GlobalEventTransmitter.GroupNoticeTransmitter
.transCardChange(msgTime, targetQQ, oldCard, newCard, groupId)
) {
LogCenter.log("群名片变动推送失败!", Level.WARN)
}*/
}
private suspend fun onGroupUniqueTitleChange(msgTime: Long, richMsg: MessageBody) {
private suspend fun onGroupUniqueTitleChange(msgTime: Long, body: MsgBody) {
val event = runCatching {
richMsg.rawBuffer!!.decodeProtobuf<GroupCommonTipsEvent>()
body.msgContent!!.decodeProtobuf<GroupCommonTipsEvent>()
}.getOrElse {
val readPacket = ByteReadPacket(richMsg.rawBuffer!!)
val readPacket = ByteReadPacket(body.msgContent!!)
readPacket.readBuf32Long()
readPacket.discardExact(1)
@ -251,7 +225,7 @@ internal object PrimitiveListener {
// (detail[5] as ProtoList).value[0]
//} else {
// detail[5]
// }
// }
val targetUin = detail.targetUin.toLong()
@ -276,13 +250,13 @@ internal object PrimitiveListener {
private suspend fun onEssenceMessage(
msgTime: Long,
clientInfo: MessagePushClientInfo?,
richMsg: MessageBody
body: MsgBody
) {
if (clientInfo == null) return
val event = runCatching {
richMsg.rawBuffer!!.decodeProtobuf<GroupCommonTipsEvent>()
body.msgContent!!.decodeProtobuf<GroupCommonTipsEvent>()
}.getOrElse {
val readPacket = ByteReadPacket(richMsg.rawBuffer!!)
val readPacket = ByteReadPacket(body.msgContent!!)
readPacket.readBuf32Long()
readPacket.discardExact(1)
@ -325,11 +299,11 @@ internal object PrimitiveListener {
}
private suspend fun onGroupPokeAndGroupSign(time: Long, richMsg: MessageBody) {
private suspend fun onGroupPokeAndGroupSign(time: Long, body: MsgBody) {
val event = runCatching {
richMsg.rawBuffer!!.decodeProtobuf<GroupCommonTipsEvent>()
body.msgContent!!.decodeProtobuf<GroupCommonTipsEvent>()
}.getOrElse {
val readPacket = ByteReadPacket(richMsg.rawBuffer!!)
val readPacket = ByteReadPacket(body.msgContent!!)
readPacket.discardExact(4)
readPacket.discardExact(1)
@ -379,8 +353,8 @@ internal object PrimitiveListener {
}
}
private suspend fun onC2CRecall(time: Long, richMsg: MessageBody) {
val event = richMsg.rawBuffer!!.decodeProtobuf<C2CRecallEvent>()
private suspend fun onC2CRecall(time: Long, body: MsgBody) {
val event = body.msgContent!!.decodeProtobuf<C2CRecallEvent>()
val head = event.head!!
val operationUid = head.operator!!
@ -404,8 +378,8 @@ internal object PrimitiveListener {
}
}
private suspend fun onGroupMemIncreased(time: Long, richMsg: MessageBody) {
val event = richMsg.rawBuffer!!.decodeProtobuf<GroupListChangeEvent>()
private suspend fun onGroupMemIncreased(time: Long, body: MsgBody) {
val event = body.msgContent!!.decodeProtobuf<GroupListChangeEvent>()
val groupCode = event.groupCode
val targetUid = event.memberUid
val type = event.type
@ -423,7 +397,14 @@ internal object PrimitiveListener {
if (!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupMemberNumChanged(
time, target, targetUid, groupCode, operator, operatorUid, NoticeType.GroupMemIncrease, when (type) {
time,
target,
targetUid,
groupCode,
operator,
operatorUid,
NoticeType.GroupMemIncrease,
when (type) {
130 -> NoticeSubType.Approve
131 -> NoticeSubType.Invite
else -> NoticeSubType.Approve
@ -434,8 +415,8 @@ internal object PrimitiveListener {
}
}
private suspend fun onGroupMemberDecreased(time: Long, richMsg: MessageBody) {
val event = richMsg.rawBuffer!!.decodeProtobuf<GroupListChangeEvent>()
private suspend fun onGroupMemberDecreased(time: Long, body: MsgBody) {
val event = body.msgContent!!.decodeProtobuf<GroupListChangeEvent>()
val groupCode = event.groupCode
val targetUid = event.memberUid
val type = event.type
@ -461,14 +442,23 @@ internal object PrimitiveListener {
LogCenter.log("群成员减少($groupCode): $target, type = $subtype ($type)")
if (!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupMemberNumChanged(time, target, targetUid, groupCode, operator, operatorUid, NoticeType.GroupMemDecrease, subtype)
.transGroupMemberNumChanged(
time,
target,
targetUid,
groupCode,
operator,
operatorUid,
NoticeType.GroupMemDecrease,
subtype
)
) {
LogCenter.log("群成员减少推送失败!", Level.WARN)
}
}
private suspend fun onGroupAdminChange(msgTime: Long, richMsg: MessageBody) {
val event = richMsg.rawBuffer!!.decodeProtobuf<GroupAdminChangeEvent>()
private suspend fun onGroupAdminChange(msgTime: Long, body: MsgBody) {
val event = body.msgContent!!.decodeProtobuf<GroupAdminChangeEvent>()
val groupCode = event.groupCode
if (event.operation == null) return
val operation = event.operation!!
@ -494,8 +484,8 @@ internal object PrimitiveListener {
}
}
private suspend fun onGroupBan(msgTime: Long, richMsg: MessageBody) {
val event = richMsg.rawBuffer!!.decodeProtobuf<GroupBanEvent>()
private suspend fun onGroupBan(msgTime: Long, body: MsgBody) {
val event = body.msgContent!!.decodeProtobuf<GroupBanEvent>()
val groupCode = event.groupCode.toLong()
val operatorUid = event.operatorUid
val wholeBan = event.target?.target?.targetUid == null
@ -519,14 +509,14 @@ internal object PrimitiveListener {
}
}
private suspend fun onGroupRecall(time: Long, richMsg: MessageBody) {
private suspend fun onGroupRecall(time: Long, body: MsgBody) {
val event = runCatching {
richMsg.rawBuffer!!.decodeProtobuf<GroupCommonTipsEvent>()
body.msgContent!!.decodeProtobuf<GroupCommonTipsEvent>()
}.getOrElse {
val readPacket = ByteReadPacket(richMsg.rawBuffer!!)
val readPacket = ByteReadPacket(body.msgContent!!)
readPacket.discardExact(4)
readPacket.discardExact(1)
readPacket.readBytes(readPacket.readShort().toInt()).also {
readPacket.readBytes(readPacket.readShort().toInt()).also {
readPacket.release()
}.decodeProtobuf<GroupCommonTipsEvent>()
}
@ -553,10 +543,10 @@ internal object PrimitiveListener {
}
}
private suspend fun onGroupApply(time: Long, contentHead: MessageContent, richMsg: MessageBody) {
private suspend fun onGroupApply(time: Long, contentHead: ContentHead, body: MsgBody) {
when (contentHead.msgType) {
84 -> {
val event = richMsg.rawBuffer!!.decodeProtobuf<GroupApplyEvent>()
val event = body.msgContent!!.decodeProtobuf<GroupApplyEvent>()
val groupCode = event.groupCode
val applierUid = event.applierUid
val reason = event.applyMsg ?: ""
@ -587,8 +577,9 @@ internal object PrimitiveListener {
LogCenter.log("入群申请推送失败!", Level.WARN)
}
}
528 -> {
val event = richMsg.rawBuffer!!.decodeProtobuf<GroupInvitedApplyEvent>()
val event = body.msgContent!!.decodeProtobuf<GroupInvitedApplyEvent>()
val groupCode = event.applyInfo?.groupCode ?: return
val applierUid = event.applyInfo?.applierUid ?: return
var applier = ContactHelper.getUinByUidAsync(applierUid).toLong()
@ -624,8 +615,8 @@ internal object PrimitiveListener {
}
}
private suspend fun onInviteGroup(time: Long, msgHead: MessageHead, richMsg: MessageBody) {
val event = richMsg.rawBuffer!!.decodeProtobuf<GroupInviteEvent>()
private suspend fun onInviteGroup(time: Long, msgHead: ResponseHead, body: MsgBody) {
val event = body.msgContent!!.decodeProtobuf<GroupInviteEvent>()
val groupCode = event.groupCode
val invitorUid = event.inviterUid
val invitor = ContactHelper.getUinByUidAsync(invitorUid).toLong()
@ -644,7 +635,7 @@ internal object PrimitiveListener {
"$time;$groupCode;$uin"
}
if (!GlobalEventTransmitter.RequestTransmitter
.transGroupApply(time, invitor, invitorUid, "", groupCode, flag, RequestSubType.Invite)
.transGroupApply(time, invitor, invitorUid, "", groupCode, flag, RequestSubType.Invite)
) {
LogCenter.log("邀请入群推送失败!", Level.WARN)
}