Commit 1e885dbf authored by Him188's avatar Him188

Rearrange MessageSvc and OnlinePush

parent 1c1a37a1
...@@ -32,7 +32,7 @@ import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull ...@@ -32,7 +32,7 @@ import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull
import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService
import net.mamoe.mirai.qqandroid.utils.estimateLength import net.mamoe.mirai.qqandroid.utils.estimateLength
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
...@@ -358,7 +358,7 @@ internal class GroupImpl( ...@@ -358,7 +358,7 @@ internal class GroupImpl(
lateinit var source: MessageSourceToGroupImpl lateinit var source: MessageSourceToGroupImpl
bot.network.run { bot.network.run {
val response: MessageSvc.PbSendMsg.Response = MessageSvc.PbSendMsg.createToGroup( val response: MessageSvcPbSendMsg.Response = MessageSvcPbSendMsg.createToGroup(
bot.client, bot.client,
this@GroupImpl, this@GroupImpl,
msg, msg,
...@@ -366,7 +366,7 @@ internal class GroupImpl( ...@@ -366,7 +366,7 @@ internal class GroupImpl(
) { ) {
source = it source = it
}.sendAndExpect() }.sendAndExpect()
if (response is MessageSvc.PbSendMsg.Response.Failed) { if (response is MessageSvcPbSendMsg.Response.Failed) {
when (response.resultType) { when (response.resultType) {
120 -> throw BotIsBeingMutedException(this@GroupImpl) 120 -> throw BotIsBeingMutedException(this@GroupImpl)
34 -> { 34 -> {
......
...@@ -32,7 +32,7 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot ...@@ -32,7 +32,7 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.message.MessageSourceToTempImpl import net.mamoe.mirai.qqandroid.message.MessageSourceToTempImpl
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
...@@ -68,13 +68,13 @@ internal class MemberImpl constructor( ...@@ -68,13 +68,13 @@ internal class MemberImpl constructor(
lateinit var source: MessageSourceToTempImpl lateinit var source: MessageSourceToTempImpl
bot.network.run { bot.network.run {
check( check(
MessageSvc.PbSendMsg.createToTemp( MessageSvcPbSendMsg.createToTemp(
bot.client, bot.client,
this@MemberImpl, this@MemberImpl,
message.asMessageChain() message.asMessageChain()
) { ) {
source = it source = it
}.sendAndExpect<MessageSvc.PbSendMsg.Response>() is MessageSvc.PbSendMsg.Response.SUCCESS }.sendAndExpect<MessageSvcPbSendMsg.Response>() is MessageSvcPbSendMsg.Response.SUCCESS
) { "send message failed" } ) { "send message failed" }
} }
return MessageReceipt(source, this, null) return MessageReceipt(source, this, null)
......
...@@ -23,7 +23,7 @@ import net.mamoe.mirai.qqandroid.message.MessageSourceToFriendImpl ...@@ -23,7 +23,7 @@ import net.mamoe.mirai.qqandroid.message.MessageSourceToFriendImpl
import net.mamoe.mirai.qqandroid.message.ensureSequenceIdAvailable import net.mamoe.mirai.qqandroid.message.ensureSequenceIdAvailable
import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.verbose import net.mamoe.mirai.utils.verbose
...@@ -38,13 +38,13 @@ internal suspend fun <T : Contact> Friend.sendMessageImpl(generic: T, message: M ...@@ -38,13 +38,13 @@ internal suspend fun <T : Contact> Friend.sendMessageImpl(generic: T, message: M
lateinit var source: MessageSourceToFriendImpl lateinit var source: MessageSourceToFriendImpl
(bot.network as QQAndroidBotNetworkHandler).run { (bot.network as QQAndroidBotNetworkHandler).run {
check( check(
MessageSvc.PbSendMsg.createToFriend( MessageSvcPbSendMsg.createToFriend(
bot.asQQAndroidBot().client, bot.asQQAndroidBot().client,
this@sendMessageImpl, this@sendMessageImpl,
event.message event.message
) { ) {
source = it source = it
}.sendAndExpect<MessageSvc.PbSendMsg.Response>() is MessageSvc.PbSendMsg.Response.SUCCESS }.sendAndExpect<MessageSvcPbSendMsg.Response>() is MessageSvcPbSendMsg.Response.SUCCESS
) { "send message failed" } ) { "send message failed" }
} }
return MessageReceipt(source, generic, null) return MessageReceipt(source, generic, null)
......
...@@ -25,7 +25,7 @@ import net.mamoe.mirai.message.data.OnlineMessageSource ...@@ -25,7 +25,7 @@ import net.mamoe.mirai.message.data.OnlineMessageSource
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.SourceMsg import net.mamoe.mirai.qqandroid.network.protocol.data.proto.SourceMsg
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePush import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePushPbPushGroupMsg.SendGroupMessageReceipt
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
...@@ -117,7 +117,7 @@ internal class MessageSourceToGroupImpl( ...@@ -117,7 +117,7 @@ internal class MessageSourceToGroupImpl(
override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false) override var isRecalledOrPlanned: MiraiAtomicBoolean = MiraiAtomicBoolean(false)
private val sequenceIdDeferred: Deferred<Int?> = private val sequenceIdDeferred: Deferred<Int?> =
coroutineScope.asyncFromEventOrNull<OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt, Int>( coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, Int>(
timeoutMillis = 3000 timeoutMillis = 3000
) { ) {
if (it.messageRandom == this@MessageSourceToGroupImpl.internalId) { if (it.messageRandom == this@MessageSourceToGroupImpl.internalId) {
......
...@@ -32,7 +32,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopNum ...@@ -32,7 +32,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopNum
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.* import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.GroupInfoImpl import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.GroupInfoImpl
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbGetMsg
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.ConfigPushSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.login.ConfigPushSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat
...@@ -362,8 +362,8 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo ...@@ -362,8 +362,8 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
logger.info { "Syncing friend message history..." } logger.info { "Syncing friend message history..." }
withTimeoutOrNull(30000) { withTimeoutOrNull(30000) {
launch { syncFromEvent<MessageSvc.PbGetMsg.GetMsgSuccess, Unit> { Unit } } launch { syncFromEvent<MessageSvcPbGetMsg.GetMsgSuccess, Unit> { Unit } }
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<Packet>() MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<Packet>()
} ?: error("timeout syncing friend message history") } ?: error("timeout syncing friend message history")
logger.info { "Syncing friend message history: Success" } logger.info { "Syncing friend message history: Success" }
......
...@@ -897,7 +897,7 @@ internal class Submsgtype0x27 { ...@@ -897,7 +897,7 @@ internal class Submsgtype0x27 {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
internal class MsgBody( internal class SubMsgType0x27MsgBody(
@ProtoId(1) @JvmField val msgModInfos: List<ForwardBody> = listOf() @ProtoId(1) @JvmField val msgModInfos: List<ForwardBody> = listOf()
) : ProtoBuf ) : ProtoBuf
......
...@@ -19,8 +19,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.PbMessageSvc ...@@ -19,8 +19,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.PbMessageSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePush
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.ConfigPushSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.login.ConfigPushSvc
...@@ -132,10 +131,10 @@ internal object KnownPacketFactories { ...@@ -132,10 +131,10 @@ internal object KnownPacketFactories {
WtLogin.Login, WtLogin.Login,
StatSvc.Register, StatSvc.Register,
StatSvc.GetOnlineStatus, StatSvc.GetOnlineStatus,
MessageSvc.PbGetMsg, MessageSvcPbGetMsg,
MessageSvc.PushForceOffline, MessageSvcPushForceOffline,
MessageSvc.PbSendMsg, MessageSvcPbSendMsg,
MessageSvc.Del, MessageSvcPbDeleteMsg,
FriendList.GetFriendGroupList, FriendList.GetFriendGroupList,
FriendList.GetTroopListSimplify, FriendList.GetTroopListSimplify,
FriendList.GetTroopMemberList, FriendList.GetTroopMemberList,
...@@ -157,15 +156,15 @@ internal object KnownPacketFactories { ...@@ -157,15 +156,15 @@ internal object KnownPacketFactories {
) )
object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf( object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf(
OnlinePush.PbPushGroupMsg, OnlinePushPbPushGroupMsg,
OnlinePush.ReqPush, OnlinePushReqPush,
OnlinePush.PbPushTransMsg, OnlinePushPbPushTransMsg,
MessageSvc.PushNotify, MessageSvcPushNotify,
ConfigPushSvc.PushReq, ConfigPushSvc.PushReq,
StatSvc.ReqMSFOffline StatSvc.ReqMSFOffline
) )
// SvcReqMSFLoginNotify 自己的其他设备上限 // SvcReqMSFLoginNotify 自己的其他设备上限
// MessageSvc.PushReaded 电脑阅读了别人的消息, 告知手机 // MessageSvcPushReaded 电脑阅读了别人的消息, 告知手机
// OnlinePush.PbC2CMsgSync 电脑发消息给别人, 同步给手机 // OnlinePush.PbC2CMsgSync 电脑发消息给别人, 同步给手机
@Suppress("MemberVisibilityCanBePrivate") // debugging use @Suppress("MemberVisibilityCanBePrivate") // debugging use
...@@ -259,21 +258,20 @@ internal object KnownPacketFactories { ...@@ -259,21 +258,20 @@ internal object KnownPacketFactories {
PacketLogger.info { "Handle packet: ${it.commandName}" } PacketLogger.info { "Handle packet: ${it.commandName}" }
it.data.withUse { it.data.withUse {
when (flag2) { when (flag2) {
0, 1 -> 0, 1 -> when (it.packetFactory) {
when (it.packetFactory) { is OutgoingPacketFactory<*> -> consumer(
is OutgoingPacketFactory<*> -> consumer( it.packetFactory as OutgoingPacketFactory<T>,
it.packetFactory as OutgoingPacketFactory<T>, it.packetFactory.run { decode(bot, it.data) },
it.packetFactory.run { decode(bot, it.data) }, it.packetFactory.commandName,
it.packetFactory.commandName, it.sequenceId
it.sequenceId )
) is IncomingPacketFactory<*> -> consumer(
is IncomingPacketFactory<*> -> consumer( it.packetFactory as IncomingPacketFactory<T>,
it.packetFactory as IncomingPacketFactory<T>, it.packetFactory.run { decode(bot, it.data, it.sequenceId) },
it.packetFactory.run { decode(bot, it.data, it.sequenceId) }, it.packetFactory.receivingCommandName,
it.packetFactory.receivingCommandName, it.sequenceId
it.sequenceId )
) }
}
2 -> it.data.parseOicqResponse( 2 -> it.data.parseOicqResponse(
bot, bot,
......
/*
* Copyright 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
*/
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
internal object MessageSvcPbDeleteMsg : OutgoingPacketFactory<Nothing?>("MessageSvcPbDeleteMsg") {
internal operator fun invoke(client: QQAndroidClient, items: List<MsgSvc.PbDeleteMsgReq.MsgItem>) =
buildOutgoingUniPacket(client) {
writeProtoBuf(
MsgSvc.PbDeleteMsgReq.serializer(),
MsgSvc.PbDeleteMsgReq(
msgItems = items
)
)
}
internal suspend fun delete(bot: QQAndroidBot, messages: Flow<MsgComm.Msg>) =
bot.network.run {
val map = messages.map {
MsgSvc.PbDeleteMsgReq.MsgItem(
fromUin = it.msgHead.fromUin,
toUin = it.msgHead.toUin,
// 群为84、好友为187。群通过其他方法删除,但测试结果显示通过187也能删除群消息。
msgType = 187,
msgSeq = it.msgHead.msgSeq,
msgUid = it.msgHead.msgUid
)
}.toList()
MessageSvcPbDeleteMsg(bot.client, map).sendWithoutExpect()
}
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot) = null
}
\ No newline at end of file
/*
* Copyright 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
*/
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.toByteArray
import net.mamoe.mirai.contact.Friend
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.PttMessage
import net.mamoe.mirai.message.data.firstOrNull
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.contact.GroupImpl
import net.mamoe.mirai.qqandroid.message.MessageSourceToFriendImpl
import net.mamoe.mirai.qqandroid.message.MessageSourceToGroupImpl
import net.mamoe.mirai.qqandroid.message.MessageSourceToTempImpl
import net.mamoe.mirai.qqandroid.message.toRichTextElems
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
import net.mamoe.mirai.utils.currentTimeSeconds
import kotlin.math.absoluteValue
import kotlin.random.Random
internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.Response>("MessageSvcPbSendMsg") {
sealed class Response : Packet {
object SUCCESS : Response() {
override fun toString(): String = "MessageSvcPbSendMsg.Response.SUCCESS"
}
/**
* 121: 被限制? 个别号才不能发
*/
data class Failed(val resultType: Int, val errorCode: Int, val errorMessage: String) : Response() {
override fun toString(): String =
"MessageSvcPbSendMsg.Response.Failed(resultType=$resultType, errorCode=$errorCode, errorMessage=$errorMessage)"
}
}
inline fun createToFriend(
client: QQAndroidClient,
qq: Friend,
message: MessageChain,
crossinline sourceCallback: (MessageSourceToFriendImpl) -> Unit
): OutgoingPacket {
val rand = Random.nextInt().absoluteValue
val source = MessageSourceToFriendImpl(
internalId = rand,
sender = client.bot,
target = qq,
time = currentTimeSeconds.toInt(),
sequenceId = client.nextFriendSeq(),
originalMessage = message
)
sourceCallback(source)
return createToFriend(
client,
qq.id,
message,
source)
}
/**
* 发送好友消息
*/
@Suppress("FunctionName")
private fun createToFriend(
client: QQAndroidClient,
toUin: Long,
message: MessageChain,
source: MessageSourceToFriendImpl
): OutgoingPacket = buildOutgoingUniPacket(client) {
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
///return@buildOutgoingUniPacket
writeProtoBuf(
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
routingHead = MsgSvc.RoutingHead(c2c = MsgSvc.C2C(toUin = toUin)),
contentHead = MsgComm.ContentHead(pkgNum = 1),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = message.toRichTextElems(forGroup = false, withGeneralFlags = true)
)
),
msgSeq = source.sequenceId,
msgRand = source.internalId,
syncCookie = SyncCookie(time = source.time.toLong()).toByteArray(SyncCookie.serializer())
// msgVia = 1
)
)
}
inline fun createToTemp(
client: QQAndroidClient,
member: Member,
message: MessageChain,
sourceCallback: (MessageSourceToTempImpl) -> Unit
): OutgoingPacket {
val source = MessageSourceToTempImpl(
internalId = Random.nextInt().absoluteValue,
sender = client.bot,
target = member,
time = currentTimeSeconds.toInt(),
sequenceId = client.atomicNextMessageSequenceId(),
originalMessage = message
)
sourceCallback(source)
return createToTemp(
client,
(member.group as GroupImpl).uin,
member.id,
message,
source)
}
/**
* 发送临时消息
*/
private fun createToTemp(
client: QQAndroidClient,
groupUin: Long,
toUin: Long,
message: MessageChain,
source: MessageSourceToTempImpl
): OutgoingPacket = buildOutgoingUniPacket(client) {
writeProtoBuf(
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
routingHead = MsgSvc.RoutingHead(
grpTmp = MsgSvc.GrpTmp(groupUin, toUin)
),
contentHead = MsgComm.ContentHead(pkgNum = 1),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = message.toRichTextElems(forGroup = false, withGeneralFlags = true)
)
),
msgSeq = source.sequenceId,
msgRand = source.internalId,
syncCookie = SyncCookie(time = source.time.toLong()).toByteArray(SyncCookie.serializer())
)
)
}
inline fun createToGroup(
client: QQAndroidClient,
group: Group,
message: MessageChain,
isForward: Boolean,
sourceCallback: (MessageSourceToGroupImpl) -> Unit
): OutgoingPacket {
val source = MessageSourceToGroupImpl(
group,
internalId = Random.nextInt().absoluteValue,
sender = client.bot,
target = group,
time = currentTimeSeconds.toInt(),
originalMessage = message//,
// sourceMessage = message
)
sourceCallback(source)
return createToGroup(
client,
group.id,
message,
isForward,
source)
}
/**
* 发送群消息
*/
@Suppress("FunctionName")
private fun createToGroup(
client: QQAndroidClient,
groupCode: Long,
message: MessageChain,
isForward: Boolean,
source: MessageSourceToGroupImpl
): OutgoingPacket = buildOutgoingUniPacket(client) {
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
// DebugLogger.debug("sending group message: " + message.toRichTextElems().contentToString())
///return@buildOutgoingUniPacket
writeProtoBuf(
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupCode)),
contentHead = MsgComm.ContentHead(pkgNum = 1),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = message.toRichTextElems(forGroup = true, withGeneralFlags = true),
ptt = message.firstOrNull(PttMessage)?.run {
ImMsgBody.Ptt(fileName = fileName.toByteArray(), fileMd5 = md5)
}
)
),
msgSeq = client.atomicNextMessageSequenceId(),
msgRand = source.internalId,
syncCookie = EMPTY_BYTE_ARRAY,
msgVia = 1,
msgCtrl = if (isForward) MsgCtrl.MsgCtrl(
msgFlag = 4
) else null
)
)
}
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
val response = readProtoBuf(MsgSvc.PbSendMsgResp.serializer())
return if (response.result == 0) {
Response.SUCCESS
} else {
Response.Failed(
response.result,
response.errtype,
response.errmsg)
}
}
}
/*
* Copyright 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
*/
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.event.events.BotOfflineEvent
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushForceOffline
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.utils.io.serialization.readUniPacket
/**
* 被挤下线
*/
internal object MessageSvcPushForceOffline :
OutgoingPacketFactory<BotOfflineEvent.Force>("MessageSvcPushForceOffline") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): BotOfflineEvent.Force {
val struct = this.readUniPacket(RequestPushForceOffline.serializer())
return BotOfflineEvent.Force(bot, title = struct.title ?: "", message = struct.tips ?: "")
}
}
/*
* Copyright 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
*/
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushNotify
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.utils.io.serialization.readUniPacket
import net.mamoe.mirai.utils.currentTimeSeconds
/**
* 告知要刷新好友消息
*/
internal object MessageSvcPushNotify : IncomingPacketFactory<RequestPushNotify>("MessageSvcPushNotify") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): RequestPushNotify {
discardExact(4) // don't remove
return readUniPacket(RequestPushNotify.serializer())
}
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
network.run {
return MessageSvcPbGetMsg(
client,
MsgSvc.SyncFlag.START,
packet.stMsgInfo?.uMsgTime ?: currentTimeSeconds
)
}
}
}
\ No newline at end of file
/*
* Copyright 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
*/
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.contact.nameCardOrNick
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.MemberCardChangeEvent
import net.mamoe.mirai.getGroupOrNull
import net.mamoe.mirai.message.GroupMessageEvent
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.contact.GroupImpl
import net.mamoe.mirai.qqandroid.contact.MemberImpl
import net.mamoe.mirai.qqandroid.message.toMessageChain
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgOnlinePush
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Oidb0x8fc
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
import net.mamoe.mirai.qqandroid.utils._miraiContentToString
import net.mamoe.mirai.qqandroid.utils.encodeToString
import net.mamoe.mirai.qqandroid.utils.io.serialization.loadAs
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
/**
* 接受群消息
*/
internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("OnlinePush.PbPushGroupMsg") {
internal class SendGroupMessageReceipt(
val messageRandom: Int,
val sequenceId: Int
) : Packet, Event, Packet.NoLog, AbstractEvent() {
override fun toString(): String {
return "OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt(messageRandom=$messageRandom, sequenceId=$sequenceId)"
}
}
@OptIn(ExperimentalStdlibApi::class)
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? {
// 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00
if (!bot.firstLoginSucceed) return null
val pbPushMsg = readProtoBuf(MsgOnlinePush.PbPushMsg.serializer())
if (pbPushMsg.msg.msgHead.fromUin == bot.id) {
return SendGroupMessageReceipt(
pbPushMsg.msg.msgBody.richText.attr!!.random,
pbPushMsg.msg.msgHead.msgSeq
)
}
var extraInfo: ImMsgBody.ExtraInfo? = null
var anonymous: ImMsgBody.AnonymousGroupMsg? = null
for (elem in pbPushMsg.msg.msgBody.richText.elems) {
when {
elem.extraInfo != null -> extraInfo = elem.extraInfo
elem.anonGroupMsg != null -> anonymous = elem.anonGroupMsg
}
}
val group =
bot.getGroupOrNull(pbPushMsg.msg.msgHead.groupInfo!!.groupCode) as GroupImpl? ?: return null // 机器人还正在进群
val sender = if (anonymous != null) {
group.newAnonymous(anonymous.anonNick.encodeToString())
} else {
group[pbPushMsg.msg.msgHead.fromUin]
} as MemberImpl
val name = if (anonymous != null) {
sender.nameCard
} else {
extraInfo?.groupCard?.takeIf { it.isNotEmpty() }?.run {
kotlin.runCatching {
if (this[0] == 0x0A.toByte())
loadAs(Oidb0x8fc.CommCardNameBuf.serializer()).richCardName?.joinToString("") { it.text.encodeToString() }
else return@runCatching null
}.getOrNull() ?: encodeToString()
} ?: pbPushMsg.msg.msgHead.groupInfo.groupCard.takeIf { it.isNotEmpty() }
?: sender.nameCardOrNick // 没有 extraInfo 就从 head 里取
}
val flags = extraInfo?.flags ?: 0
return GroupMessageEvent(
senderName = name.also {
if (it != sender.nameCard) {
val origin = sender._nameCard
sender._nameCard = name
MemberCardChangeEvent(origin, name, sender).broadcast()
}
},
sender = sender,
message = pbPushMsg.msg.toMessageChain(bot, groupIdOrZero = group.id, onlineSource = true),
permission = when {
flags and 16 != 0 -> MemberPermission.ADMINISTRATOR
flags and 8 != 0 -> MemberPermission.OWNER
flags == 0 -> MemberPermission.MEMBER
else -> {
bot.logger.warning("判断群 ${sender.group.id} 的群员 ${sender.id} 的权限失败: ${pbPushMsg.msg.msgHead._miraiContentToString()}. 请完整截图或复制此日志并确认其真实权限后发送给 mirai 维护者以帮助解决问题.")
sender.permission
}
},
time = pbPushMsg.msg.msgHead.msgTime
)
}
}
/*
* Copyright 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("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@file:OptIn(MiraiInternalAPI::class,
MiraiExperimentalAPI::class,
JavaFriendlyAPI::class,
ExperimentalUnsignedTypes::class)
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readUByte
import kotlinx.io.core.readUInt
import net.mamoe.mirai.JavaFriendlyAPI
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.event.events.BotGroupPermissionChangeEvent
import net.mamoe.mirai.event.events.MemberLeaveEvent
import net.mamoe.mirai.event.events.MemberPermissionChangeEvent
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.contact.GroupImpl
import net.mamoe.mirai.qqandroid.contact.MemberImpl
import net.mamoe.mirai.qqandroid.contact.checkIsMemberImpl
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.OnlinePushTrans
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
import net.mamoe.mirai.qqandroid.utils.read
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
internal object OnlinePushPbPushTransMsg :
IncomingPacketFactory<Packet?>("OnlinePush.PbPushTransMsg", "OnlinePush.RespPush") {
@OptIn(MiraiInternalAPI::class)
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? {
val content = this.readProtoBuf(OnlinePushTrans.PbMsgInfo.serializer())
if (!bot.client.pbPushTransMsgCacheList.ensureNoDuplication(content.msgSeq)) {
return null
}
content.msgData.read<Unit> {
when (content.msgType) {
44 -> {
this.discardExact(5)
val var4 = readByte().toInt()
var var5 = 0L
val target = readUInt().toLong()
if (var4 != 0 && var4 != 1) {
var5 = readUInt().toLong()
}
val group = bot.getGroupByUin(content.fromUin) as GroupImpl
if (var5 == 0L && this.remaining == 1L) {//管理员变更
val newPermission =
if (this.readByte().toInt() == 1) MemberPermission.ADMINISTRATOR
else MemberPermission.MEMBER
if (target == bot.id) {
if (group.botPermission == newPermission) {
return null
}
return BotGroupPermissionChangeEvent(
group,
group.botPermission.also {
group.botAsMember.checkIsMemberImpl().permission = newPermission
},
newPermission
)
} else {
val member = group[target] as MemberImpl
if (member.permission == newPermission) {
return null
}
return MemberPermissionChangeEvent(
member,
member.permission.also { member.permission = newPermission },
newPermission
)
}
}
}
34 -> {
/* quit
27 0B 60 E7
01
2F 55 7C B8
82
00 30 42 33 32 46 30 38 33 32 39 32 35 30 31 39 33 45 46 32 45 30 36 35 41 35 41 33 42 37 35 43 41 34 46 37 42 38 42 38 42 44 43 35 35 34 35 44 38 30
*/
/* kick
27 0B 60 E7
01
A8 32 51 A1
83 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 39 32 46 45 30 36 31 41 33 37 36 43 44 35 37 35 37 39 45 37 32 34 44 37 37 30 36 46 39 39 43 35 35 33 33 31 34 44 32 44 46 35 45 42 43 31 31 36
*/
readUInt().toLong() // group, uin or code ?
discardExact(1)
val target = readUInt().toLong()
val type = readUByte().toInt()
val operator = readUInt().toLong()
val groupUin = content.fromUin
when (type) {
0x82 -> bot.getGroupByUinOrNull(groupUin)?.let { group ->
val member = group.getOrNull(target) as? MemberImpl ?: return null
return MemberLeaveEvent.Quit(member.also {
group.members.delegate.remove(member)
})
}
0x83 -> bot.getGroupByUin(groupUin).let { group ->
val member = group.getOrNull(target) as? MemberImpl ?: return null
return MemberLeaveEvent.Kick(member.also {
group.members.delegate.remove(member)
}, group.members[operator])
}
}
}
}
}
return null
}
override suspend fun QQAndroidBot.handle(packet: Packet?, sequenceId: Int): OutgoingPacket? {
return buildResponseUniPacket(client, sequenceId = sequenceId) {}
}
}
...@@ -155,7 +155,7 @@ sealed class MessageRecallEvent : BotEvent, AbstractEvent() { ...@@ -155,7 +155,7 @@ sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
override val messageInternalId: Int, override val messageInternalId: Int,
override val messageTime: Int, override val messageTime: Int,
/** /**
* 撤回操作人, 可能为 [Bot.uin] 或好友的 [User.id] * 撤回操作人, 可能为 [Bot.id] 或好友的 [User.id]
*/ */
val operator: Long val operator: Long
) : MessageRecallEvent(), Packet { ) : MessageRecallEvent(), Packet {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment