Support other client messages:

- Add OtherClientMessageEvent
This commit is contained in:
Him188 2020-12-23 22:46:10 +08:00
parent 3b35dbcac5
commit f613b7f7b7
11 changed files with 778 additions and 25 deletions

View File

@ -479,6 +479,32 @@ public class FriendMessageEvent constructor(
public override fun toString(): String = "FriendMessageEvent(sender=${sender.id}, message=$message)"
}
/**
* 机器人收到的好友消息的事件
*
* @see MessageEvent
*/
public class OtherClientMessageEvent constructor(
public override val client: OtherClient,
public override val message: MessageChain,
public override val time: Int
) : AbstractMessageEvent(), MessageEvent, MessageEventExtensions<User, Contact>, BroadcastControllable,
OtherClientEvent {
init {
val source =
message[MessageSource] ?: throw IllegalArgumentException("Cannot find MessageSource from message")
check(source is OnlineMessageSource.Incoming.FromFriend) { "source provided to a FriendMessage must be an instance of OnlineMessageSource.Incoming.FromFriend" }
}
public override val sender: User = client.bot.asFriend // TODO 临时使用
public override val bot: Bot get() = super.bot
public override val subject: User get() = sender
public override val senderName: String get() = sender.nick
public override val source: OnlineMessageSource.Incoming.FromFriend get() = message.source as OnlineMessageSource.Incoming.FromFriend
public override fun toString(): String = "OtherClientMessageEvent(client=${client.kind}, message=$message)"
}
/**
* 来自一个可以知道其 [Group] 的用户消息
*

View File

@ -27,6 +27,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.chat.*
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.network.LoginFailedException
import net.mamoe.mirai.utils.*
import network.protocol.data.jce.InstanceInfo
import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext
import net.mamoe.mirai.internal.network.protocol.data.jce.FriendInfo as JceFriendInfo
@ -40,9 +41,10 @@ internal fun Bot.asQQAndroidBot(): QQAndroidBot {
}
internal fun QQAndroidBot.createOtherClient(
kind: ClientKind
kind: ClientKind,
instanceInfo: InstanceInfo,
): OtherClientImpl {
return OtherClientImpl(this, coroutineContext, kind)
return OtherClientImpl(this, coroutineContext, kind, instanceInfo)
}
@Suppress("INVISIBLE_MEMBER", "BooleanLiteralArgument", "OverridingDeprecatedMember")

View File

@ -17,12 +17,17 @@ import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.cast
import network.protocol.data.jce.InstanceInfo
import kotlin.coroutines.CoroutineContext
internal val OtherClient.instanceInfo: InstanceInfo get() = this.cast<OtherClientImpl>().instanceInfo
internal class OtherClientImpl(
bot: Bot,
coroutineContext: CoroutineContext,
override val kind: ClientKind
override val kind: ClientKind,
val instanceInfo: InstanceInfo
) : OtherClient, AbstractContact(bot, coroutineContext) {
override suspend fun sendMessage(message: Message): MessageReceipt<Contact> {
TODO("Not yet implemented")
@ -35,4 +40,39 @@ internal class OtherClientImpl(
override fun toString(): String {
return "OtherClient(bot=${bot.id},kind=$kind)"
}
}
}
/*
contentHead=ContentHead#522561765 {
}
msgBody=MsgBody#-1622349855 {
msgContent=08 04 12 1E 08 E9 07 10 B7 F7 8B 80 02 18 E9 07 20 00 28 DD F1 92 B7 07 30 DD F1 92 B7 07 48 02 50 03 32 1E 08 88 80 F8 92 CD 84 80 80 10 10 01 18 00 20 01 2A 0C 0A 0A 08 01 12 06 E5 95 8A E5 95 8A
richText=RichText#-184909407 {
elems=[]
}
}
msgHead=MsgHead#1128220129 {
authUin=0x0000000000000000(0)
c2cCmd=0x00000007(7)
cpid=0x0000000000000000(0)
fromUin=0x0000000076E4B8DD(1994701021)
isSrcMsg=false
msgInstCtrl=InstCtrl#1220180502 {
msgExcludeInst=[]
msgFromInst=InstInfo#-1165404375 {
apppid=0x000003E9(1001)
enumDeviceType=0x00000002(2)
instid=0x2002FBB7(537066423)
}
msgSendToInst=[InstInfo#-1165404375 {
apppid=0x000003E9(1001)
enumDeviceType=0x00000003(3)
}]
}
msgSeq=0x000073C8(29640)
msgTime=0x5FE34926(1608730918)
msgType=0x00000211(529)
msgUid=0x0100000076360F0E(72057596021182222)
toUin=0x0000000076E4B8DD(1994701021)
}
*/

View File

@ -108,6 +108,9 @@ internal fun net.mamoe.mirai.event.events.MessageEvent.logMessageReceived() {
is net.mamoe.mirai.event.events.FriendMessageEvent -> bot.logger.verbose {
"${sender.nick}(${sender.id}) -> $message".replaceMagicCodes()
}
is net.mamoe.mirai.event.events.OtherClientMessageEvent -> bot.logger.verbose {
"${client.kind}(${sender.id}) -> $message".replaceMagicCodes()
}
}
}

View File

@ -71,7 +71,10 @@ internal class MessageSourceFromFriendImpl(
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random
override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random }
override val internalIds: IntArray
get() = msg.mapToIntArray {
it.msgBody.richText.attr?.random ?: 0
} // other client 消息的这个是0
override val time: Int get() = msg.first().msgHead.msgTime
override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, bot.id, 0, false) }
override val sender: Friend get() = bot.getFriendOrFail(msg.first().msgHead.fromUin)
@ -82,7 +85,7 @@ internal class MessageSourceFromFriendImpl(
}
private fun List<MsgComm.Msg>.toJceDataFriendOrTemp(ids: IntArray): ImMsgBody.SourceMsg {
val elements = flatMap {it.msgBody.richText.elems}.toMutableList().also {
val elements = flatMap { it.msgBody.richText.elems }.toMutableList().also {
if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
}
return ImMsgBody.SourceMsg(
@ -90,7 +93,7 @@ private fun List<MsgComm.Msg>.toJceDataFriendOrTemp(ids: IntArray): ImMsgBody.So
senderUin = first().msgHead.fromUin,
toUin = first().msgHead.toUin,
flag = 1,
elems = flatMap{it.msgBody.richText.elems},
elems = flatMap { it.msgBody.richText.elems },
type = 0,
time = this.first().msgHead.msgTime,
pbReserve = SourceMsg.ResvAttr(
@ -122,7 +125,7 @@ internal class MessageSourceFromTempImpl(
private val msg: List<MsgComm.Msg>
) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceInternal {
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
override val internalIds: IntArray get() = msg.mapToIntArray{it.msgBody.richText.attr!!.random }
override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random }
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
override val ids: IntArray get() = sequenceIds//
override val time: Int get() = msg.first().msgHead.msgTime
@ -150,7 +153,7 @@ internal data class MessageSourceFromGroupImpl(
) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal {
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
override val internalIds: IntArray get() = msg.mapToIntArray{ it.msgBody.richText.attr!!.random }
override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random }
override val ids: IntArray get() = sequenceIds
override val time: Int get() = msg.first().msgHead.msgTime
override val originalMessage: MessageChain by lazy {

View File

@ -14,7 +14,6 @@ import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.internal.utils.io.JceStruct
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
import kotlin.jvm.JvmField
@Suppress("ArrayInDataClass")
@Serializable
@ -33,7 +32,11 @@ internal class RequestPushNotify(
@TarsId(11) @JvmField val serverBuf: ByteArray?,
@TarsId(12) @JvmField val pingFlag: Long?,
@TarsId(13) @JvmField val svrip: Int?
) : JceStruct, Packet
) : JceStruct, Packet {
override fun toString(): String {
return "RequestPushNotify(uin=$uin, ctype=$ctype, strService=$strService, strCmd=$strCmd, usMsgType=$usMsgType, stMsgInfo=$stMsgInfo)"
}
}
@Serializable
internal class MsgInfo(

View File

@ -0,0 +1,57 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("unused", "SpellCheckingInspection")
package net.mamoe.mirai.internal.network.protocol.data.proto
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.internal.utils.io.ProtoBuf
@Serializable
internal class HummerResv21 : ProtoBuf {
@Serializable
internal class FileImgInfo(
@JvmField @ProtoNumber(1) val fileWidth: Int = 0,
@JvmField @ProtoNumber(2) val fileHeight: Int = 0
) : ProtoBuf
@Serializable
internal class ForwardExtFileInfo(
@JvmField @ProtoNumber(1) val fileType: Int = 0,
@JvmField @ProtoNumber(2) val senderUin: Long = 0L,
@JvmField @ProtoNumber(3) val receiverUin: Long = 0L,
@JvmField @ProtoNumber(4) val fileUuid: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(5) val fileName: String = "",
@JvmField @ProtoNumber(6) val fileSize: Long = 0L,
@JvmField @ProtoNumber(7) val fileSha1: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(8) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(9) val int64DeadTime: Long = 0L,
@JvmField @ProtoNumber(10) val imgWidth: Int = 0,
@JvmField @ProtoNumber(11) val imgHeight: Int = 0,
@JvmField @ProtoNumber(12) val videoDuration: Long = 0L,
@JvmField @ProtoNumber(13) val busId: Int = 0
) : ProtoBuf
@Serializable
internal class ResvAttr(
@JvmField @ProtoNumber(1) val fileImageInfo: FileImgInfo? = null,
@JvmField @ProtoNumber(2) val forwardExtFileInfo: ForwardExtFileInfo? = null
) : ProtoBuf
@Serializable
internal class XtfSenderInfo(
@JvmField @ProtoNumber(1) val lanIp: Int = 0,
@JvmField @ProtoNumber(2) val lanPort: Int = 0,
@JvmField @ProtoNumber(3) val lanSrkey: Long = 0L
) : ProtoBuf
}

View File

@ -0,0 +1,573 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("unused", "SpellCheckingInspection")
package net.mamoe.mirai.internal.network.protocol.data.proto
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoIntegerType
import kotlinx.serialization.protobuf.ProtoNumber
import kotlinx.serialization.protobuf.ProtoType
import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.internal.utils.io.ProtoBuf
@Serializable
internal class SubMsgType0x3 : ProtoBuf {
@Serializable
internal class FailNotify(
@JvmField @ProtoNumber(1) val sessionid: Int = 0,
@JvmField @ProtoNumber(2) val retCode: Int = 0,
@JvmField @ProtoNumber(3) val reason: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class MsgBody(
@JvmField @ProtoNumber(1) val msgProgressNotify: ProgressNotify? = null,
@JvmField @ProtoNumber(2) val msgFailNotify: FailNotify? = null
) : ProtoBuf
@Serializable
internal class ProgressNotify(
@JvmField @ProtoNumber(1) val sessionid: Int = 0,
@JvmField @ProtoNumber(2) val uuid: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(3) val progress: Int = 0,
@JvmField @ProtoNumber(4) val averageSpeed: Int = 0
) : ProtoBuf
}
@Serializable
internal class SubMsgType0x4 : ProtoBuf {
@Serializable
internal class MsgBody(
@JvmField @ProtoNumber(1) val msgNotOnlineFile: ImMsgBody.NotOnlineFile? = null,
@JvmField @ProtoNumber(2) val msgTime: Int = 0,
@JvmField @ProtoNumber(3) val onlineFileForPolyToOffline: Int = 0,
@JvmField @ProtoNumber(4) val fileImageInfo: HummerResv21.FileImgInfo? = null,
@JvmField @ProtoNumber(5) val msgXtfSenderInfo: HummerResv21.XtfSenderInfo? = null,
@JvmField @ProtoNumber(6) val resvAttr: HummerResv21.ResvAttr? = null
) : ProtoBuf
}
@Serializable
internal class SubMsgType0x5 : ProtoBuf {
@Serializable
internal class MsgBody(
@JvmField @ProtoNumber(1) val sessionid: Int = 0
) : ProtoBuf
}
@Serializable
internal class SubMsgType0x7 : ProtoBuf {
@Serializable
internal class MsgBody(
@JvmField @ProtoNumber(1) val subCmd: Int = 0,
@JvmField @ProtoNumber(2) val msgHeader: MsgHeader? = null,
@JvmField @ProtoNumber(3) val msgSubcmd0x1FtnNotify: List<FTNNotify> = emptyList(),
@JvmField @ProtoNumber(4) val msgSubcmd0x2NfcNotify: List<NFCNotify> = emptyList(),
@JvmField @ProtoNumber(5) val msgSubcmd0x3Filecontrol: List<FileControl> = emptyList(),
@JvmField @ProtoNumber(6) val msgSubcmd0x4Generic: GenericSubCmd? = null,
@JvmField @ProtoNumber(7) val msgSubcmd0x5MoloNotify: List<MoloNotify> = emptyList(),
@JvmField @ProtoNumber(8) val msgSubcmd0x8RnfcNotify: List<RNFCNotify> = emptyList(),
@JvmField @ProtoNumber(9) val msgSubcmd0x9FtnThumbNotify: List<FTNNotify> = emptyList(),
@JvmField @ProtoNumber(10) val msgSubcmd0xaNfcThumbNotify: List<NFCNotify> = emptyList(),
@JvmField @ProtoNumber(11) val msgSubcmd0xbMpfileNotify: List<MpFileNotify> = emptyList(),
@JvmField @ProtoNumber(12) val msgSubcmd0xcProgressReq: ProgressReq? = null,
@JvmField @ProtoNumber(13) val msgSubcmd0xdProgressRsp: ProgressRsp? = null
) : ProtoBuf {
@Serializable
internal class ActionInfo(
@JvmField @ProtoNumber(1) val serviceName: String = "",
@JvmField @ProtoNumber(2) val buf: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class FileControl(
@JvmField @ProtoNumber(1) val sessionid: Long = 0L,
@JvmField @ProtoNumber(2) val operate: Int = 0,
@JvmField @ProtoNumber(3) val seq: Int = 0,
@JvmField @ProtoNumber(4) val code: Int = 0,
@JvmField @ProtoNumber(5) val msg: String = "",
@JvmField @ProtoNumber(6) val groupId: Int = 0,
@JvmField @ProtoNumber(7) val groupCurindex: Int = 0,
@JvmField @ProtoNumber(8) val batchID: Int = 0
) : ProtoBuf
@Serializable
internal class FTNNotify(
@JvmField @ProtoNumber(1) val sessionid: Long = 0L,
@JvmField @ProtoNumber(2) val fileName: String = "",
@JvmField @ProtoNumber(3) val fileIndex: String = "",
@JvmField @ProtoNumber(4) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(5) val fileKey: String = "",
@JvmField @ProtoNumber(6) val fileLen: Long = 0L,
@JvmField @ProtoNumber(7) val originfileMd5: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(8) val originfiletype: Int = 0,
@JvmField @ProtoNumber(9) val groupId: Int = 0,
@JvmField @ProtoNumber(10) val groupSize: Int = 0,
@JvmField @ProtoNumber(11) val groupCurindex: Int = 0,
@JvmField @ProtoNumber(20) val msgActionInfo: ActionInfo? = null,
@JvmField @ProtoNumber(21) val batchID: Int = 0,
@JvmField @ProtoNumber(22) val groupflag: Int = 0
) : ProtoBuf
@Serializable
internal class MsgItem(
@JvmField @ProtoNumber(1) val type: Int = 0,
@JvmField @ProtoNumber(2) val text: String = ""
) : ProtoBuf
@Serializable
internal class QQDataTextMsg(
@JvmField @ProtoNumber(1) val msgItems: List<MsgItem> = emptyList()
) : ProtoBuf
@Serializable
internal class WifiPhotoNoPush(
@JvmField @ProtoNumber(1) val json: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class WifiPhotoWithPush(
@JvmField @ProtoNumber(1) val json: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class GenericSubCmd(
@JvmField @ProtoNumber(1) val sessionid: Long = 0L,
@JvmField @ProtoNumber(2) val size: Int = 0,
@JvmField @ProtoNumber(3) val index: Int = 0,
@JvmField @ProtoNumber(4) val type: Int = 0,
@JvmField @ProtoNumber(5) val buf: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(6) val supportAuth: Int = 0
) : ProtoBuf
@Serializable
internal class MoloNotify(
@JvmField @ProtoNumber(1) val buf: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(2) val groupId: Int = 0,
@JvmField @ProtoNumber(3) val groupSize: Int = 0,
@JvmField @ProtoNumber(4) val groupCurindex: Int = 0
) : ProtoBuf
@Serializable
internal class MpFileNotify(
@JvmField @ProtoNumber(1) val sessionid: Long = 0L,
@JvmField @ProtoNumber(2) val operate: Int = 0,
@ProtoType(ProtoIntegerType.FIXED) @JvmField @ProtoNumber(3) val fixed32Ip: Int = 0,
@JvmField @ProtoNumber(4) val port: Int = 0,
@JvmField @ProtoNumber(5) val type: Int = 0,
@JvmField @ProtoNumber(6) val power: Int = 0,
@JvmField @ProtoNumber(7) val json: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class MsgHeader(
@JvmField @ProtoNumber(1) val srcAppId: Int = 0,
@JvmField @ProtoNumber(2) val srcInstId: Int = 0,
@JvmField @ProtoNumber(3) val dstAppId: Int = 0,
@JvmField @ProtoNumber(4) val dstInstId: Int = 0,
@JvmField @ProtoNumber(5) val dstUin: Long = 0L,
@JvmField @ProtoNumber(6) val srcUin: Long = 0L,
@JvmField @ProtoNumber(7) val srcUinType: Int = 0,
@JvmField @ProtoNumber(8) val dstUinType: Int = 0,
@JvmField @ProtoNumber(9) val srcTerType: Int = 0,
@JvmField @ProtoNumber(10) val dstTerType: Int = 0
) : ProtoBuf
@Serializable
internal class NFCNotify(
@JvmField @ProtoNumber(1) val sessionid: Long = 0L,
@JvmField @ProtoNumber(2) val fileName: String = "",
@JvmField @ProtoNumber(3) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoType(ProtoIntegerType.FIXED) @JvmField @ProtoNumber(4) val fixed32Ip: Int = 0,
@JvmField @ProtoNumber(5) val port: Int = 0,
@JvmField @ProtoNumber(6) val urlNotify: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(7) val tokenkey: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(8) val fileLen: Long = 0L,
@JvmField @ProtoNumber(9) val originfileMd5: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(10) val originfiletype: Int = 0,
@JvmField @ProtoNumber(11) val groupId: Int = 0,
@JvmField @ProtoNumber(12) val groupSize: Int = 0,
@JvmField @ProtoNumber(13) val groupCurindex: Int = 0,
@JvmField @ProtoNumber(20) val msgActionInfo: ActionInfo? = null,
@JvmField @ProtoNumber(21) val batchID: Int = 0,
@JvmField @ProtoNumber(22) val groupflag: Int = 0
) : ProtoBuf
@Serializable
internal class ProgressReq(
@JvmField @ProtoNumber(1) val cmd: Int = 0,
@JvmField @ProtoNumber(2) val cookie: Long = 0L,
@JvmField @ProtoNumber(3) val infoflag: Int = 0,
@JvmField @ProtoNumber(4) val uint64Sessionid: List<Long> = emptyList()
) : ProtoBuf
@Serializable
internal class ProgressInfo(
@JvmField @ProtoNumber(1) val sessionid: Long = 0L,
@JvmField @ProtoNumber(2) val progress: Long = 0L,
@JvmField @ProtoNumber(3) val status: Int = 0,
@JvmField @ProtoNumber(4) val filesize: Long = 0L,
@JvmField @ProtoNumber(5) val filename: String = "",
@JvmField @ProtoNumber(6) val time: Long = 0L
) : ProtoBuf
@Serializable
internal class ProgressRsp(
@JvmField @ProtoNumber(1) val cmd: Int = 0,
@JvmField @ProtoNumber(2) val cookie: Long = 0L,
@JvmField @ProtoNumber(3) val packageCount: Int = 0,
@JvmField @ProtoNumber(4) val packageIndex: Int = 0,
@JvmField @ProtoNumber(5) val msgProgressinfo: List<ProgressInfo> = emptyList()
) : ProtoBuf
@Serializable
internal class RNFCNotify(
@JvmField @ProtoNumber(1) val sessionid: Long = 0L,
@JvmField @ProtoNumber(2) val token: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoType(ProtoIntegerType.FIXED) @JvmField @ProtoNumber(3) val fixed32Ip: Int = 0,
@JvmField @ProtoNumber(4) val port: Int = 0,
@JvmField @ProtoNumber(5) val svrTaskId: Long = 0L
) : ProtoBuf
}
}
@Serializable
internal class C2CType0x211SubC2CType0x8 : ProtoBuf {
@Serializable
internal class BusiReqHead(
@JvmField @ProtoNumber(1) val int32Version: Int = 0,
@JvmField @ProtoNumber(2) val int32Seq: Int = 0
) : ProtoBuf
@Serializable
internal class BusiRespHead(
@JvmField @ProtoNumber(1) val int32Version: Int = 0,
@JvmField @ProtoNumber(2) val int32Seq: Int = 0,
@JvmField @ProtoNumber(3) val int32ReplyCode: Int = 0,
@JvmField @ProtoNumber(4) val result: String = ""
) : ProtoBuf
@Serializable
internal class Cell(
@JvmField @ProtoNumber(1) val int32Mcc: Int = -1,
@JvmField @ProtoNumber(2) val int32Mnc: Int = -1,
@JvmField @ProtoNumber(3) val int32Lac: Int = -1,
@JvmField @ProtoNumber(4) val int32Cellid: Int = -1,
@JvmField @ProtoNumber(5) val int32Rssi: Int = 0
) : ProtoBuf
@Serializable
internal class ConnType(
@JvmField @ProtoNumber(1) val type: Int /* enum */ = 1,
@JvmField @ProtoNumber(2) val desription: String = ""
) : ProtoBuf
@Serializable
internal class GPS(
@JvmField @ProtoNumber(1) val int32Lat: Int = 900000000,
@JvmField @ProtoNumber(2) val int32Lon: Int = 900000000,
@JvmField @ProtoNumber(3) val int32Alt: Int = -10000000,
@JvmField @ProtoNumber(4) val eType: Int /* enum */ = 0
) : ProtoBuf
@Serializable
internal class IPAddrInfo(
@JvmField @ProtoNumber(1) val int32Ip: Int = 0,
@JvmField @ProtoNumber(2) val int32Mask: Int = 0,
@JvmField @ProtoNumber(3) val int32Gateway: Int = 0,
@JvmField @ProtoNumber(4) val int32Port: Int = 0
) : ProtoBuf
@Serializable
internal class JudgeResult(
@JvmField @ProtoNumber(1) val type: Int /* enum */ = 0,
@JvmField @ProtoNumber(2) val ssid: String = "",
@JvmField @ProtoNumber(3) val tips: String = "",
@JvmField @ProtoNumber(4) val int32IdleTimeout: Int = 0,
@JvmField @ProtoNumber(5) val idleWaiting: Int = 0,
@JvmField @ProtoNumber(6) val forceWifi: Int = 0,
@JvmField @ProtoNumber(7) val flagsWifipsw: Int = 0,
@JvmField @ProtoNumber(8) val flagsNetcheck: Int = 0
) : ProtoBuf
@Serializable
internal class LBSInfo(
@JvmField @ProtoNumber(1) val msgGps: GPS? = null,
@JvmField @ProtoNumber(2) val msgWifis: List<Wifi> = emptyList(),
@JvmField @ProtoNumber(3) val msgCells: List<Cell> = emptyList()
) : ProtoBuf
@Serializable
internal class MsgBody(
@JvmField @ProtoNumber(1) val msgType: Int /* enum */ = 1,
@JvmField @ProtoNumber(2) val msgCcNotifylist: NotifyList? = null,
@JvmField @ProtoNumber(3) val msgCcnfAbiQuery: NearFieldAbiQuery? = null,
@JvmField @ProtoNumber(4) val msgCcPushJudgeResult: PushJudgeResult? = null,
@JvmField @ProtoNumber(5) val msgCcnfFilesendReq: NearFieldFileSendReq? = null,
@JvmField @ProtoNumber(6) val msgCcnfFilestateSync: NearFieldFileStateSync? = null
) : ProtoBuf
@Serializable
internal class NearFieldAbiQuery(
@JvmField @ProtoNumber(1) val toUin: Long = 0L,
@JvmField @ProtoNumber(2) val fromUin: Long = 0L,
@JvmField @ProtoNumber(3) val boolNeedTips: Boolean = false,
@JvmField @ProtoNumber(4) val int32Timeout: Int = 0,
@JvmField @ProtoNumber(5) val cookie: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(6) val int32PeerIp: Int = 0,
@JvmField @ProtoNumber(7) val int32PeerPort: Int = 0,
@JvmField @ProtoNumber(8) val peerExtra: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class NearFieldFileInfo(
@JvmField @ProtoNumber(1) val fileName: String = "",
@JvmField @ProtoNumber(2) val fileSize: Long = 0L,
@JvmField @ProtoNumber(3) val fileMd5: String = "",
@JvmField @ProtoNumber(4) val fileUrl: String = "",
@JvmField @ProtoNumber(5) val fileThumbMd5: String = "",
@JvmField @ProtoNumber(6) val fileThumbUrl: String = "",
@JvmField @ProtoNumber(7) val sessionId: Long = 0L,
@JvmField @ProtoNumber(8) val int32Timeout: Int = 0,
@JvmField @ProtoNumber(9) val groupId: Long = 0L
) : ProtoBuf
@Serializable
internal class NearFieldFileSendReq(
@JvmField @ProtoNumber(1) val toUin: Long = 0L,
@JvmField @ProtoNumber(2) val msgFileList: List<NearFieldFileInfo> = emptyList(),
@JvmField @ProtoNumber(3) val int32Ip: Int = 0,
@JvmField @ProtoNumber(4) val int32UdpPort: Int = 0,
@JvmField @ProtoNumber(5) val ssid: String = "",
@JvmField @ProtoNumber(6) val int32ConnWifiapTimeout: Int = 0,
@JvmField @ProtoNumber(7) val forceWifi: Int = 0,
@JvmField @ProtoNumber(8) val wifipsw: String = ""
) : ProtoBuf
@Serializable
internal class NearFieldFileStateSync(
@JvmField @ProtoNumber(1) val eType: Int /* enum */ = 1,
@JvmField @ProtoNumber(2) val sessionId: Long = 0L,
@JvmField @ProtoNumber(3) val fromUin: Long = 0L,
@JvmField @ProtoNumber(4) val int32ErrorCode: Int = 0
) : ProtoBuf
@Serializable
internal class NearfieldInfo(
@JvmField @ProtoNumber(1) val msgLbsInfo: LBSInfo? = null,
@JvmField @ProtoNumber(2) val msgConnType: ConnType? = null,
@JvmField @ProtoNumber(3) val msgIpInfo: IPAddrInfo? = null,
@JvmField @ProtoNumber(4) val msgWifiDetail: WifiDetailInfo? = null,
@JvmField @ProtoNumber(5) val msgWifiAbi: WifiAbility? = null,
@JvmField @ProtoNumber(6) val extra: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class NotifyList(
@JvmField @ProtoNumber(1) val notifyType: Int /* enum */ = 0,
@JvmField @ProtoNumber(2) val msgUpdateList: List<UpdateInfo> = emptyList(),
@JvmField @ProtoNumber(3) val sessionId: Int = 0
) : ProtoBuf
@Serializable
internal class PushJudgeResult(
@JvmField @ProtoNumber(1) val msgHead: BusiRespHead? = null,
@JvmField @ProtoNumber(2) val toUin: Long = 0L,
@JvmField @ProtoNumber(3) val msgResult: JudgeResult? = null,
@JvmField @ProtoNumber(4) val int32PeerIp: Int = 0,
@JvmField @ProtoNumber(5) val int32PeerPort: Int = 0,
@JvmField @ProtoNumber(6) val peerExtra: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class ReqAIOJudge(
@JvmField @ProtoNumber(1) val msgHead: BusiReqHead? = null,
@JvmField @ProtoNumber(2) val toUin: Long = 0L,
@JvmField @ProtoNumber(3) val msgNearfieldInfo: NearfieldInfo? = null
) : ProtoBuf
@Serializable
internal class ReqExit(
@JvmField @ProtoNumber(1) val msgHead: BusiReqHead? = null,
@JvmField @ProtoNumber(2) val sessionId: Int = 0,
@JvmField @ProtoNumber(3) val msgNearfieldInfo: NearfieldInfo? = null
) : ProtoBuf
@Serializable
internal class ReqGetList(
@JvmField @ProtoNumber(1) val msgHead: BusiReqHead? = null,
@JvmField @ProtoNumber(2) val msgNearfieldInfo: NearfieldInfo? = null,
@JvmField @ProtoNumber(3) val sessionId: Int = 0,
@JvmField @ProtoNumber(4) val cookie: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class ReqReportNearFieldAbi(
@JvmField @ProtoNumber(1) val msgHead: BusiReqHead? = null,
@JvmField @ProtoNumber(2) val fromUin: Long = 0L,
@JvmField @ProtoNumber(3) val msgNearfieldInfo: NearfieldInfo? = null,
@JvmField @ProtoNumber(4) val cookie: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class RespAIOJudge(
@JvmField @ProtoNumber(1) val msgHead: BusiRespHead? = null,
@JvmField @ProtoNumber(2) val msgResult: JudgeResult? = null,
@JvmField @ProtoNumber(3) val timeout: Int = 0,
@JvmField @ProtoNumber(4) val toUin: Long = 0L,
@JvmField @ProtoNumber(5) val int32PeerIp: Int = 0,
@JvmField @ProtoNumber(6) val int32PeerPort: Int = 0,
@JvmField @ProtoNumber(7) val peerExtra: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class RespExit(
@JvmField @ProtoNumber(1) val msgHead: BusiRespHead? = null
) : ProtoBuf
@Serializable
internal class RespGetList(
@JvmField @ProtoNumber(1) val msgHead: BusiRespHead? = null,
@JvmField @ProtoNumber(2) val msgUserList: List<UserProfile> = emptyList(),
@JvmField @ProtoNumber(3) val sessionId: Int = 0,
@JvmField @ProtoNumber(4) val int32UpdateInterval: Int = 0,
@JvmField @ProtoNumber(5) val cookie: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class UpdateInfo(
@JvmField @ProtoNumber(1) val type: Int /* enum */ = 1,
@JvmField @ProtoNumber(2) val msgUser: UserProfile? = null
) : ProtoBuf
@Serializable
internal class UserAbility(
@JvmField @ProtoNumber(1) val int32SysQlver: Int = 0,
@JvmField @ProtoNumber(2) val int32SysTerm: Int = 0,
@JvmField @ProtoNumber(3) val int32SysApp: Int = 0,
@JvmField @ProtoNumber(10) val int32AbsWifiHost: Int = 0,
@JvmField @ProtoNumber(11) val int32AbsWifiClient: Int = 0,
@JvmField @ProtoNumber(12) val int32AbsWifiForcedcreate: Int = 0,
@JvmField @ProtoNumber(13) val int32AbsWifiForcedconnect: Int = 0,
@JvmField @ProtoNumber(14) val int32AbsWifiPassword: Int = 0,
@JvmField @ProtoNumber(20) val int32AbsNetReachablecheck: Int = 0,
@JvmField @ProtoNumber(21) val int32AbsNetSpeedTest: Int = 0,
@JvmField @ProtoNumber(30) val int32AbsUiPromptOnclick: Int = 0,
@JvmField @ProtoNumber(31) val int32AbsUiPromptPassive: Int = 0
) : ProtoBuf
@Serializable
internal class UserExtraInfo(
@JvmField @ProtoNumber(1) val ability: UserAbility? = null
) : ProtoBuf
@Serializable
internal class UserProfile(
@JvmField @ProtoNumber(1) val uin: Long = 0L,
@JvmField @ProtoNumber(2) val int32FaceId: Int = 0,
@JvmField @ProtoNumber(3) val int32Sex: Int = 0,
@JvmField @ProtoNumber(4) val int32Age: Int = 0,
@JvmField @ProtoNumber(5) val nick: String = "",
@JvmField @ProtoNumber(6) val tmpTalkSig: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(7) val msgResult: JudgeResult? = null,
@JvmField @ProtoNumber(8) val int32Ip: Int = 0,
@JvmField @ProtoNumber(9) val int32Port: Int = 0,
@JvmField @ProtoNumber(10) val tip: ByteArray = EMPTY_BYTE_ARRAY,
@JvmField @ProtoNumber(11) val extra: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class Wifi(
@JvmField @ProtoNumber(1) val mac: Long = 0L,
@JvmField @ProtoNumber(2) val int32Rssi: Int = 0
) : ProtoBuf
@Serializable
internal class WifiAbility(
@JvmField @ProtoNumber(1) val boolEstablishAbi: Boolean = false,
@JvmField @ProtoNumber(2) val boolAutoConnectAbi: Boolean = false
) : ProtoBuf
@Serializable
internal class WifiDetailInfo(
@JvmField @ProtoNumber(1) val boolSelfEstablish: Boolean = false,
@JvmField @ProtoNumber(2) val ssid: String = "",
@JvmField @ProtoNumber(3) val mac: String = ""
) : ProtoBuf
}
@Serializable
internal class C2CType0x211SubC2CType0x9 : ProtoBuf {
@Serializable
internal class MsgBody(
@JvmField @ProtoNumber(1) val service: String = "",
@JvmField @ProtoNumber(2) val cMD: Int = 0,
@JvmField @ProtoNumber(3) val msgPrinter: MsgPrinter? = null
) : ProtoBuf {
@Serializable
internal class HPPrinterStateInfo(
@JvmField @ProtoNumber(1) val printerDin: Long = 0L,
@JvmField @ProtoNumber(2) val printerQrPicUrl: String = "",
@JvmField @ProtoNumber(3) val printerQrOpenUrl: String = "",
@JvmField @ProtoNumber(4) val printerTipUrl: String = ""
) : ProtoBuf
@Serializable
internal class MsgPrinter(
@JvmField @ProtoNumber(1) val stringPrinter: List<String> = emptyList(),
@JvmField @ProtoNumber(2) val printSessionId: Long = 0L,
@JvmField @ProtoNumber(3) val printResult: Int = 0,
@JvmField @ProtoNumber(4) val resultMsg: String = "",
@JvmField @ProtoNumber(5) val uint64SessionId: List<Long> = emptyList(),
@JvmField @ProtoNumber(6) val msgSupportFileInfo: List<SupportFileInfo> = emptyList(),
@JvmField @ProtoNumber(7) val hpPrinterStateInfo: HPPrinterStateInfo? = null
) : ProtoBuf
@Serializable
internal class SupportFileInfo(
@JvmField @ProtoNumber(1) val fileSuffix: String = "",
@JvmField @ProtoNumber(2) val copies: Int = 0,
@JvmField @ProtoNumber(3) val duplex: Int = 0
) : ProtoBuf
}
}
@Serializable
internal class C2CType0x211SubC2CType0xb : ProtoBuf {
@Serializable
internal class MsgBody(
@JvmField @ProtoNumber(1) val msgMsgHeader: MsgHeader? = null,
@JvmField @ProtoNumber(2) val msgRejectMotify: RejectNotify? = null
) : ProtoBuf {
@Serializable
internal class MsgHeader(
@JvmField @ProtoNumber(1) val bodyType: Int /* enum */ = 101,
@JvmField @ProtoNumber(2) val sessionType: Int = 0,
@JvmField @ProtoNumber(3) val toUin: Long = 0L,
@JvmField @ProtoNumber(4) val toMobile: String = "",
@JvmField @ProtoNumber(5) val roomId: Long = 0L
) : ProtoBuf
@Serializable
internal class RejectNotify(
@JvmField @ProtoNumber(1) val enumRejectReason: Int /* enum */ = 201,
@JvmField @ProtoNumber(2) val msg: String = "",
@JvmField @ProtoNumber(3) val ringFilename: String = ""
) : ProtoBuf
}
}

View File

@ -26,20 +26,17 @@ import net.mamoe.mirai.contact.NormalMember
import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.events.BotJoinGroupEvent
import net.mamoe.mirai.event.events.FriendMessageEvent
import net.mamoe.mirai.event.events.MemberJoinEvent
import net.mamoe.mirai.event.events.TempMessageEvent
import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.contact.GroupImpl
import net.mamoe.mirai.internal.contact.checkIsFriendImpl
import net.mamoe.mirai.internal.contact.checkIsMemberImpl
import net.mamoe.mirai.internal.contact.*
import net.mamoe.mirai.internal.message.MessageSourceFromFriendImpl
import net.mamoe.mirai.internal.message.toMessageChain
import net.mamoe.mirai.internal.network.MultiPacket
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.QQAndroidClient
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc
import net.mamoe.mirai.internal.network.protocol.data.proto.SubMsgType0x7
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
@ -47,11 +44,12 @@ import net.mamoe.mirai.internal.network.protocol.packet.chat.GroupInfoImpl
import net.mamoe.mirai.internal.network.protocol.packet.chat.NewContact
import net.mamoe.mirai.internal.network.protocol.packet.chat.toLongUnsigned
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
import net.mamoe.mirai.internal.utils.*
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
import net.mamoe.mirai.internal.utils.read
import net.mamoe.mirai.internal.utils.toInt
import net.mamoe.mirai.internal.utils.toUHexString
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.buildMessageChain
import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.warning
@ -175,6 +173,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
}
}
// bot.logger.debug(resp.msgRspType._miraiContentToString())
// bot.logger.debug(resp.syncCookie._miraiContentToString())
@ -202,6 +201,8 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
)
) return@mapNotNull null
// if (msg.msgHead.msgType != 732) msg._miraiContentToString().soutv("MSG")
when (msg.msgHead.msgType) {
33 -> bot.groupListModifyLock.withLock {
@ -351,8 +352,45 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
return@mapNotNull null
}
529 -> {
// 好友文件
return@mapNotNull null
// top_package/awbk.java:3765
return@mapNotNull when (msg.msgHead.c2cCmd) {
// other client sync
7 -> {
val data = msg.msgBody.msgContent.loadAs(SubMsgType0x7.MsgBody.serializer())
val textMsg =
data.msgSubcmd0x4Generic?.buf?.loadAs(SubMsgType0x7.MsgBody.QQDataTextMsg.serializer())
?: return@mapNotNull null
with(data.msgHeader ?: return@mapNotNull null) {
if (srcUin != dstUin || dstUin != bot.id) return@mapNotNull null
val client = bot.otherClients.find { it.instanceInfo.iAppId == srcInstId }
?: return@mapNotNull null// don't compare with dstAppId. diff.
val chain = buildMessageChain {
+MessageSourceFromFriendImpl(bot, listOf(msg))
for (msgItem in textMsg.msgItems) {
when (msgItem.type) {
1 -> {
+PlainText(msgItem.text)
}
else -> {
}
}
}
}
return@mapNotNull OtherClientMessageEvent(client, chain, msg.msgHead.msgTime)
}
}
else -> null
}
// 各种垃圾
// 08 04 12 1E 08 E9 07 10 B7 F7 8B 80 02 18 E9 07 20 00 28 DD F1 92 B7 07 30 DD F1 92 B7 07 48 02 50 03 32 1E 08 88 80 F8 92 CD 84 80 80 10 10 01 18 00 20 01 2A 0C 0A 0A 08 01 12 06 E5 95 8A E5 95 8A
}
141 -> {
val tmpHead = msg.msgHead.c2cTmpMsgHead ?: return@mapNotNull null
@ -397,6 +435,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
732 -> {
// unknown
// 前 4 byte 是群号
return@mapNotNull null
}
// 732: 27 0B 60 E7 0C 01 3E 03 3F A2 5E 90 60 E2 00 01 44 71 47 90 00 00 02 58

View File

@ -29,7 +29,7 @@ internal object MessageSvcPushNotify : IncomingPacketFactory<RequestPushNotify>(
return readUniPacket(RequestPushNotify.serializer())
}
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket {
client.syncingController.firstNotify.loop { firstNotify ->
network.run {

View File

@ -238,7 +238,14 @@ internal class StatSvc {
when (notify.status.toInt()) {
1 -> {
if (bot.otherClients.any { it.kind == kind }) return null
val client = bot.createOtherClient(kind)
val client = bot.createOtherClient(
kind,
notify.vecInstanceList?.find { it.iClientType == notify.iClientType }
?: throw contextualBugReportException(
"decode SvcReqMSFLoginNotify (OtherClient online)",
notify._miraiContentToString(),
additional = "Failed to find corresponding instanceInfo."
))
bot.otherClients.delegate.add(client)
OtherClientOnlineEvent(client)
}