Commit 3ae1832a authored by jiahua.liu's avatar jiahua.liu

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt
parents 92b7b10f 18f860b9
......@@ -39,8 +39,7 @@ QQ for Android (8.2.0 版本,2019 年 12 月)协议的实现,目前还
- 完成 密码登录 (2020/1/23)
- 完成 群消息解析 (2020/1/25)
- 完成 图片验证码登录 (2020/1/26)
- 进行中 免密登录
- 进行中 SMS 登录
- 完成 设备锁登录 (2020/1/29)
- 进行中 消息解析和发送
- 进行中 图片上传和下载
......
package net.mamoe.mirai.qqandroid
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.FriendNameRemark
import net.mamoe.mirai.data.GroupInfo
......@@ -8,16 +7,19 @@ import net.mamoe.mirai.data.PreviousNameList
import net.mamoe.mirai.data.Profile
import net.mamoe.mirai.message.data.ImageId
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
import net.mamoe.mirai.utils.*
import kotlin.coroutines.CoroutineContext
internal abstract class ContactImpl : Contact
internal class QQImpl(bot: Bot, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), QQ {
override val bot: Bot by bot.unsafeWeakRef()
internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), QQ {
override val bot: QQAndroidBot by bot.unsafeWeakRef()
override suspend fun sendMessage(message: MessageChain) {
TODO("not implemented")
bot.network.run {
MessageSvc.PbSendMsg.ToFriend(bot.client, id, message).sendAndExpect<MessageSvc.PbSendMsg.Response>()
}
}
override suspend fun uploadImage(image: ExternalImage): ImageId {
......@@ -38,11 +40,11 @@ internal class QQImpl(bot: Bot, override val coroutineContext: CoroutineContext,
}
internal class MemberImpl(bot: Bot, group: Group, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), Member {
internal class MemberImpl(bot: QQAndroidBot, group: Group, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), Member {
override val group: Group by group.unsafeWeakRef()
override val permission: MemberPermission
get() = TODO("not implemented")
override val bot: Bot by bot.unsafeWeakRef()
override val bot: QQAndroidBot by bot.unsafeWeakRef()
override suspend fun mute(durationSeconds: Int): Boolean {
TODO("not implemented")
......@@ -76,7 +78,7 @@ internal class MemberImpl(bot: Bot, group: Group, override val coroutineContext:
@UseExperimental(MiraiInternalAPI::class)
internal class GroupImpl(bot: Bot, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), Group {
internal class GroupImpl(bot: QQAndroidBot, override val coroutineContext: CoroutineContext, override val id: Long) : ContactImpl(), Group {
override val internalId: GroupInternalId = GroupId(id).toInternalId()
override val owner: Member
get() = TODO("not implemented")
......@@ -86,7 +88,8 @@ internal class GroupImpl(bot: Bot, override val coroutineContext: CoroutineConte
get() = TODO("not implemented")
override val members: ContactList<Member> = ContactList(LockFreeLinkedList())
override fun getMember(id: Long): Member = members.delegate.filteringGetOrAdd({ it.id == id }, { MemberImpl(bot, this, coroutineContext, id) })
override fun getMember(id: Long): Member =
members.delegate.filteringGetOrAdd({ it.id == id }, { MemberImpl(bot as QQAndroidBot, this, coroutineContext, id) })
override suspend fun updateGroupInfo(): GroupInfo {
TODO("not implemented")
......@@ -96,7 +99,7 @@ internal class GroupImpl(bot: Bot, override val coroutineContext: CoroutineConte
TODO("not implemented")
}
override val bot: Bot by bot.unsafeWeakRef()
override val bot: QQAndroidBot by bot.unsafeWeakRef()
override suspend fun sendMessage(message: MessageChain) {
TODO("not implemented")
......
......@@ -33,7 +33,7 @@ internal abstract class QQAndroidBotBase constructor(
override val qqs: ContactList<QQ> = ContactList(LockFreeLinkedList())
override fun getQQ(id: Long): QQ {
return qqs.delegate.filteringGetOrAdd({ it.id == id }, { QQImpl(this, coroutineContext, id) })
return qqs.delegate.filteringGetOrAdd({ it.id == id }, { QQImpl(this as QQAndroidBot, coroutineContext, id) })
}
override fun createNetworkHandler(coroutineContext: CoroutineContext): QQAndroidBotNetworkHandler {
......@@ -43,17 +43,17 @@ internal abstract class QQAndroidBotBase constructor(
override val groups: ContactList<Group> = ContactList(LockFreeLinkedList())
override suspend fun getGroup(id: GroupId): Group {
return groups.delegate.filteringGetOrAdd({ it.id == id.value }, { GroupImpl(this, coroutineContext, id.value) })
return groups.delegate.filteringGetOrAdd({ it.id == id.value }, { GroupImpl(this as QQAndroidBot, coroutineContext, id.value) })
}
override suspend fun getGroup(internalId: GroupInternalId): Group {
internalId.toId().value.let { id ->
return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this, coroutineContext, id) })
return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this as QQAndroidBot, coroutineContext, id) })
}
}
override suspend fun getGroup(id: Long): Group {
return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this, coroutineContext, id) })
return groups.delegate.filteringGetOrAdd({ it.id == id }, { GroupImpl(this as QQAndroidBot, coroutineContext, id) })
}
override suspend fun Image.getLink(): ImageLink {
......
......@@ -7,7 +7,7 @@ import net.mamoe.mirai.event.events.BotEvent
/**
* 被挤下线
*/
class ForceOfflineEvent(
data class ForceOfflineEvent(
override val bot: Bot,
val title: String,
val tips: String
......
......@@ -6,6 +6,8 @@ import kotlinx.io.core.readBytes
import kotlinx.io.core.writeFully
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
import net.mamoe.mirai.utils.io.toUHexString
/**
* 仅有标示作用
......@@ -13,26 +15,29 @@ import kotlinx.serialization.SerializationStrategy
interface ProtoBuf
fun <T : ProtoBuf> BytePacketBuilder.writeProtoBuf(serializer: SerializationStrategy<T>, v: T) {
this.writeFully(v.toByteArray(serializer))
this.writeFully(v.toByteArray(serializer).also {
println("发送 protobuf: ${it.toUHexString()}")
})
}
/**
* dump
*/
fun <T : ProtoBuf> T.toByteArray(serializer: SerializationStrategy<T>): ByteArray {
return kotlinx.serialization.protobuf.ProtoBuf.dump(serializer, this)
return ProtoBufWithNullableSupport.dump(serializer, this)
}
/**
* load
*/
fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrategy<T>): T {
return kotlinx.serialization.protobuf.ProtoBuf.load(deserializer, this)
return ProtoBufWithNullableSupport.load(deserializer, this)
}
/**
* load
*/
fun <T : ProtoBuf> Input.readRemainingAsProtoBuf(serializer: DeserializationStrategy<T>): T {
return kotlinx.serialization.protobuf.ProtoBuf.load(serializer, this.readBytes())
return ProtoBufWithNullableSupport.load(serializer, this.readBytes())
}
\ No newline at end of file
......@@ -191,7 +191,7 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
this.writeHead(STRUCT_END, 0)
}
} else if (value is ProtoBuf) {
this.encodeTaggedByteArray(popTag(), kotlinx.serialization.protobuf.ProtoBuf.dump(value))
this.encodeTaggedByteArray(popTag(), net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport.dump(value))
} else {
serializer.serialize(this, value)
}
......
......@@ -314,10 +314,14 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
suspend fun <E : Packet> OutgoingPacket.sendAndExpect(): E {
val handler = PacketListener(commandName = commandName, sequenceId = sequenceId)
packetListeners.addLast(handler)
bot.logger.info("Send: ${this.commandName}")
channel.send(delegate)
return withTimeout(3000) {
return withTimeoutOrNull(3000) {
@Suppress("UNCHECKED_CAST")
handler.await() as E
} ?: net.mamoe.mirai.qqandroid.utils.inline {
packetListeners.remove(handler)
error("timeout when sending ${this.commandName}")
}
}
......
......@@ -469,7 +469,7 @@ class ImMsgBody : ProtoBuf {
@SerialId(16) val bubbleSubId: Int = 0,
@SerialId(17) val pendantId: Long = 0L,
@SerialId(18) val rpIndex: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(19) val pbReserve: ByteArray = EMPTY_BYTE_ARRAY
@SerialId(19) val pbReserve: ByteArray = EMPTY_BYTE_ARRAY // 78 00 F8 01 00 C8 02 00
) : ProtoBuf
@Serializable
......@@ -609,7 +609,7 @@ class ImMsgBody : ProtoBuf {
@SerialId(8) val reserved: Int = 0,
@SerialId(9) val subcmd: Int = 0,
@SerialId(10) val microCloud: Int = 0,
@SerialId(11) val bytesFileUrls: List<ByteArray>? = null,
@SerialId(11) val bytesFileUrls: List<ByteArray>? = listOf(),
@SerialId(12) val downloadFlag: Int = 0,
@SerialId(50) val dangerEvel: Int = 0,
@SerialId(51) val lifeTime: Int = 0,
......@@ -705,7 +705,7 @@ class ImMsgBody : ProtoBuf {
@SerialId(20) val downPara: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(29) val format: Int = 0,
@SerialId(30) val pbReserve: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(31) val bytesPttUrls: List<ByteArray>? = null,
@SerialId(31) val bytesPttUrls: List<ByteArray>? = listOf(),
@SerialId(32) val downloadFlag: Int = 0
) : ProtoBuf
......@@ -813,8 +813,8 @@ class ImMsgBody : ProtoBuf {
class RichText(
@SerialId(1) val attr: Attr? = null,
@SerialId(2) val elems: MutableList<Elem> = mutableListOf(),
@SerialId(3) val notOnlineFile: NotOnlineFile? = null,
@SerialId(4) val ptt: Ptt? = null,
@SerialId(3) val notOnlineFile: NotOnlineFile? =null,
@SerialId(4) val ptt: Ptt? =null,
@SerialId(5) val tmpPtt: TmpPtt? = null,
@SerialId(6) val trans211TmpMsg: Trans211TmpMsg? = null
) : ProtoBuf
......@@ -1045,9 +1045,9 @@ class ImMsgHead : ProtoBuf {
@Serializable
class InstCtrl(
@SerialId(1) val msgSendToInst: List<InstInfo>? = null,
@SerialId(2) val msgExcludeInst: List<InstInfo>? = null,
@SerialId(3) val msgFromInst: InstInfo? = null
@SerialId(1) val msgSendToInst: List<InstInfo>? = listOf(),
@SerialId(2) val msgExcludeInst: List<InstInfo>? = listOf(),
@SerialId(3) val msgFromInst: InstInfo? = InstInfo()
) : ProtoBuf
@Serializable
......@@ -1107,7 +1107,7 @@ class ImReceipt : ProtoBuf {
) : ProtoBuf
@Serializable
class ReceiptInfo(
data class ReceiptInfo(
@SerialId(1) val readTime: Long = 0L
) : ProtoBuf
......@@ -1118,7 +1118,7 @@ class ImReceipt : ProtoBuf {
) : ProtoBuf
@Serializable
class ReceiptResp(
data class ReceiptResp(
@SerialId(1) val command: Int /* enum */ = 1,
@SerialId(2) val receiptInfo: ReceiptInfo? = null
) : ProtoBuf
......
......@@ -2,6 +2,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.data.proto
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.io.ProtoBuf
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
......@@ -102,7 +103,7 @@ class MsgSvc : ProtoBuf {
) : ProtoBuf
@Serializable
class MsgSendInfo(
data class MsgSendInfo(
@SerialId(1) val receiver: Int = 0
) : ProtoBuf
......@@ -440,7 +441,7 @@ class MsgSvc : ProtoBuf {
) : ProtoBuf
@Serializable
class PbSendMsgResp(
data class PbSendMsgResp(
@SerialId(1) val result: Int = 0,
@SerialId(2) val errmsg: String = "",
@SerialId(3) val sendTime: Int = 0,
......@@ -450,7 +451,7 @@ class MsgSvc : ProtoBuf {
@SerialId(7) val transSvrInfo: TransSvrInfo? = null,
@SerialId(8) val receiptResp: ImReceipt.ReceiptResp? = null,
@SerialId(9) val textAnalysisResult: Int = 0
) : ProtoBuf
) : ProtoBuf, Packet
@Serializable
class PbBindUinUnReadMsgNumResp(
......
package net.mamoe.mirai.qqandroid.network.protocol.packet
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
interface MessageMicro
fun <T : MessageMicro> T.toByteArray(serializer: SerializationStrategy<T>): ByteArray = ProtoBuf.dump(serializer, this)
\ No newline at end of file
fun <T : MessageMicro> T.toByteArray(serializer: SerializationStrategy<T>): ByteArray = ProtoBufWithNullableSupport.dump(serializer, this)
\ No newline at end of file
......@@ -62,7 +62,8 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
OnlinePush.PbPushGroupMsg,
MessageSvc.PushNotify,
MessageSvc.PbGetMsg,
MessageSvc.PushForceOffline
MessageSvc.PushForceOffline,
MessageSvc.PbSendMsg
) {
// SvcReqMSFLoginNotify 自己的其他设备上限
// MessageSvc.PushReaded 电脑阅读了别人的消息, 告知手机
......
......@@ -2,7 +2,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.writeFully
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
......@@ -19,7 +19,7 @@ internal object ImageDownPacket : PacketFactory<ImageDownPacket.ImageDownPacketR
// TODO: 2020/1/24 测试: bodyType, subAppId
return buildLoginOutgoingPacket(client, key = client.wLoginSigInfo.d2Key, bodyType = 1) {
writeSsoPacket(client, subAppId = 0, commandName = commandName, sequenceId = it) {
val data = ProtoBuf.dump(
val data = ProtoBufWithNullableSupport.dump(
Cmd0x352Packet.serializer(),
Cmd0x352Packet.createByImageRequest(req)
)
......
......@@ -2,7 +2,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.writeFully
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
......@@ -19,7 +19,7 @@ internal object ImageUpPacket : PacketFactory<ImageUpPacket.ImageUpPacketRespons
// TODO: 2020/1/24 测试: bodyType, subAppId
return buildLoginOutgoingPacket(client, key = client.wLoginSigInfo.d2Key, bodyType = 1) {
writeSsoPacket(client, subAppId = 0, commandName = ImageDownPacket.commandName, sequenceId = it) {
val data = ProtoBuf.dump(
val data = ProtoBufWithNullableSupport.dump(
Cmd0x352Packet.serializer(),
Cmd0x352Packet.createByImageRequest(req)
)
......
......@@ -2,8 +2,11 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.writeFully
import net.mamoe.mirai.data.MultiPacket
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.message.FriendMessage
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.event.ForceOfflineEvent
import net.mamoe.mirai.qqandroid.io.readRemainingAsProtoBuf
......@@ -12,18 +15,23 @@ import net.mamoe.mirai.qqandroid.io.writeProtoBuf
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushForceOffline
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushNotify
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.MsgSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.utils.toMessageChain
import net.mamoe.mirai.qqandroid.utils.toRichTextElems
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.toReadPacket
import kotlin.math.absoluteValue
import kotlin.random.Random
class MessageSvc {
/**
* 告知要刷新消息
* 告知要刷新好友消息
*/
internal object PushNotify : PacketFactory<RequestPushNotify>("MessageSvc.PushNotify") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): RequestPushNotify {
......@@ -41,7 +49,7 @@ class MessageSvc {
/**
* 进行刷新消息
* 获取好友消息和消息记录
*/
internal object PbGetMsg : PacketFactory<MultiPacket<FriendMessage>>("MessageSvc.PbGetMsg") {
val EXTRA_DATA =
......@@ -65,9 +73,10 @@ class MessageSvc {
onlineSyncFlag = 1,
// serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY,
syncCookie = client.c2cMessageSync.syncCookie,
syncFlag = client.c2cMessageSync.syncFlag,
msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf,
pubaccountCookie = client.c2cMessageSync.pubAccountCookie
syncFlag = 1
// syncFlag = client.c2cMessageSync.syncFlag,
//msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf,
//pubaccountCookie = client.c2cMessageSync.pubAccountCookie
)
)
}
......@@ -112,5 +121,43 @@ class MessageSvc {
return ForceOfflineEvent(bot, title = struct.title ?: "", tips = struct.tips ?: "")
}
}
internal object PbSendMsg : PacketFactory<MsgSvc.PbSendMsgResp>("MessageSvc.PbSendMsg") {
object Response : Packet
/**
* 发送好友消息
*/
fun ToFriend(
client: QQAndroidClient,
toUin: Long,
message: MessageChain
): 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()
)
),
msgSeq = 17041,
msgRand = Random.nextInt().absoluteValue,
syncCookie = client.c2cMessageSync.syncCookie.takeIf { it.isNotEmpty() } ?: "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".hexToBytes(),
msgVia = 1
)
)
}
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): MsgSvc.PbSendMsgResp {
discardExact(4)
return readRemainingAsProtoBuf(MsgSvc.PbSendMsgResp.serializer())
}
}
}
......@@ -5,10 +5,11 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.contact.sendMessage
import net.mamoe.mirai.message.GroupMessage
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
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.packet.PacketFactory
......@@ -24,7 +25,7 @@ internal class OnlinePush {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupMessage {
// 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
discardExact(4)
val pbPushMsg = ProtoBuf.load(MsgOnlinePush.PbPushMsg.serializer(), readBytes())
val pbPushMsg = ProtoBufWithNullableSupport.load(MsgOnlinePush.PbPushMsg.serializer(), readBytes())
val extraInfo: ImMsgBody.ExtraInfo? = pbPushMsg.msg.msgBody.richText.elems.firstOrNull { it.extraInfo != null }?.extraInfo
......@@ -48,5 +49,11 @@ internal class OnlinePush {
}
)
}
override suspend fun QQAndroidBot.handle(packet: GroupMessage) {
if (packet.senderName == "Him188moe") {
this.getQQ(2978594313).sendMessage("FROM MIRAI")
}
}
}
}
\ No newline at end of file
......@@ -267,9 +267,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
sealed class LoginPacketResponse : Packet {
object Success : LoginPacketResponse() {
override fun toString(): String {
return "LoginPacketResponse.Success"
}
override fun toString(): String = "LoginPacketResponse.Success"
}
data class Error(
......@@ -283,18 +281,22 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
class Slider(
val url: String
) : Captcha() {
override fun toString(): String {
return "LoginPacketResponse.Captcha.Slider"
}
override fun toString(): String = "LoginPacketResponse.Captcha.Slider"
}
class Picture(
val data: IoBuffer,
val sign: ByteArray
) : Captcha() {
override fun toString(): String {
return "LoginPacketResponse.Captcha.Picture"
}
override fun toString(): String = "LoginPacketResponse.Captcha.Picture"
}
}
data class UnsafeLogin(val url: String) : LoginPacketResponse()
class SMSVerifyCodeNeeded(val t402: ByteArray, val t403: ByteArray) : LoginPacketResponse(){
override fun toString(): String {
return "LoginPacketResponse.SMSVerifyCodeNeeded"
}
}
......
package net.mamoe.mirai.qqandroid.network.protocol.packet.login
import kotlinx.io.core.ByteReadPacket
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.io.serialization.toByteArray
......@@ -103,7 +103,7 @@ class StatSvc {
var44.strVendorName = ROMUtil.getRomName();
var44.strVendorOSName = ROMUtil.getRomVersion(20);
*/
bytes_0x769_reqbody = ProtoBuf.dump(
bytes_0x769_reqbody = ProtoBufWithNullableSupport.dump(
Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody(
rpt_config_list = listOf(
Oidb0x769.ConfigSeq(
......
......@@ -2,7 +2,7 @@ package net.mamoe.mirai.qqandroid.utils
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.getValue
import net.mamoe.mirai.utils.unsafeWeakRef
......@@ -62,7 +62,7 @@ abstract class DeviceInfo(
@SerialId(9) val innerVersion: ByteArray
)
return ProtoBuf.dump(
return ProtoBufWithNullableSupport.dump(
DevInfo.serializer(), DevInfo(
bootloader,
procVersion,
......
......@@ -3,16 +3,15 @@ package net.mamoe.mirai.qqandroid.utils
import net.mamoe.mirai.data.ImageLink
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
internal fun MessageChain.constructPbSendMsgReq(): MsgSvc.PbSendMsgReq {
val request = MsgSvc.PbSendMsgReq()
internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
val elems = mutableListOf<ImMsgBody.Elem>()
this.forEach {
when (it) {
is PlainText -> {
request.msgBody.richText.elems.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = it.stringValue)))
elems.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = it.stringValue)))
}
is At -> {
......@@ -20,8 +19,7 @@ internal fun MessageChain.constructPbSendMsgReq(): MsgSvc.PbSendMsgReq {
}
}
return request
return elems
}
......
......@@ -7,7 +7,6 @@ import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.encryptAndWrite
import net.mamoe.mirai.utils.io.hexToBytes
......
......@@ -200,9 +200,9 @@ fun Any?.contentToString(prefix: String = ""): String = when (this) {
}
is ProtoMap -> "ProtoMap(size=$size){\n" + this.toStringPrefixed("$prefix${ProtoMap.indent}${ProtoMap.indent}") + "\n$prefix${ProtoMap.indent}}"
is Iterable<*> -> this.joinToString(prefix = "[", postfix = "]") { it.contentToString() }
is Iterator<*> -> this.asSequence().joinToString(prefix = "[", postfix = "]") { it.contentToString() }
is Sequence<*> -> this.joinToString(prefix = "[", postfix = "]") { it.contentToString() }
is Iterable<*> -> this.joinToString(prefix = "[", postfix = "]") { it.contentToString(prefix) }
is Iterator<*> -> this.asSequence().joinToString(prefix = "[", postfix = "]") { it.contentToString(prefix) }
is Sequence<*> -> this.joinToString(prefix = "[", postfix = "]") { it.contentToString(prefix) }
is Map<*, *> -> this.entries.joinToString(prefix = "{", postfix = "}") { it.key.contentToString(prefix) + "=" + it.value.contentToString(prefix) }
else -> {
if (this == null) "null"
......
package test
import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.read
import net.mamoe.mirai.utils.io.readTLVMap
import net.mamoe.mirai.utils.io.toUHexString
@ExperimentalStdlibApi
@Suppress("EXPERIMENTAL_API_USAGE")
fun main() {
val newMap =
"4E 22 00 03 E5 AE 89 4E 25 00 06 35 31 31 34 39 35 4E 26 00 01 2D 4E 27 00 01 2D 4E 29 00 01 02 4E 2A 00 06 56 69 76 69 61 6E 4E 2B 00 10 31 35 36 31 34 38 39 31 33 40 71 71 2E 63 6F 6D 4E 2D 00 1D 68 74 74 70 3A 2F 2F 31 35 36 31 34 38 39 31 33 2E 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 4E 2E 00 02 33 00 4E 2F 00 04 33 33 39 00 4E 30 00 01 2D 4E 31 00 01 00 4E 33 00 2D E6 88 91 E7 95 99 E9 95 BF E7 9A 84 E5 A4 B4 E5 8F 91 EF BC 8C E6 98 AF E4 BD A0 E9 94 99 E8 BF 87 E7 9A 84 E5 B9 B4 E5 8D 8E 2E 2E 2E 4E 35 00 18 E5 B9 BF E4 B8 9C E6 8A 80 E6 9C AF E5 B8 88 E8 8C 83 E5 AD A6 E9 99 A2 4E 36 00 01 0A 4E 37 00 01 03 4E 38 00 01 01 4E 3F 00 04 07 C2 0B 02 4E 40 00 0C 00 00 00 31 00 00 34 34 00 00 00 33 4E 41 00 02 00 00 4E 42 00 02 00 00 4E 43 00 02 00 00 4E 45 00 01 21 4E 49 00 04 00 00 00 00 4E 4B 00 04 00 00 00 00 4E 4F 00 01 00 4E 54 00 00 4E 5B 00 00 52 0B 00 04 13 88 02 02 52 0F 00 14 00 00 00 00 00 00 00 00 12 05 10 58 89 10 00 00 00 00 00 00 5D C2 00 0C 00 00 00 31 00 00 34 34 00 00 31 34 5D C8 00 1E E7 B4 A2 E5 B0 BC EF BC 88 E4 B8 AD E5 9B BD EF BC 89 E6 9C 89 E9 99 90 E5 85 AC E5 8F B8 65 97 00 01 11 69 9D 00 04 00 00 00 00 69 A9 00 00 9D A5 00 02 00 00 A4 91 00 02 00 00 A4 93 00 02 00 00 A4 94 00 02 00 00 A4 9C 00 02 00 00 A4 B5 00 02 00 00"
.hexToBytes().read {
readTLVMap(tagSize = 2, expectingEOF = true)
}
newMap.forEach { (key, value) ->
if (!(value.isEmpty() || value.all { it.toInt() == 0 })) {
println(key.toUShort().toUHexString() + "=" + value.decodeToString())
}
}
return
}
\ No newline at end of file
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package test
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoBuf
import kotlinx.serialization.protobuf.ProtoNumberType
import kotlinx.serialization.protobuf.ProtoType
import kotlinx.serialization.serializer
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.readProtoMap
import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.read
import kotlin.reflect.KClass
@Serializable
data class ProtoTest(
//@SerialId(1) val string: String,
//@SerialId(1) val int: Int,
//@SerialId(1) val boolean: Boolean,
//@SerialId(1) val short: Short,
//@SerialId(1) val byte: Byte,
@SerialId(1) @ProtoType(ProtoNumberType.FIXED) val fixedByte: Byte
)
@UseExperimental(MiraiInternalAPI::class)
suspend fun main() {
deserializeTest()
}
suspend fun deserializeTest() {
val bytes =
"""
08 02 1A 55 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 25 2F 34 35 35 38 66 39 30 38 2D 37 62 39 61 2D 34 65 32 66 2D 38 63 36 39 2D 34 61 35 32 61 66 62 33 36 35 61 37 20 01 30 04 38 05 40 09 48 01 58 00 60 01 6A 0A 38 2E 32 2E 30 2E 31 32 39 36 70 E0 8C B2 F0 05 78 01 50 03
""".trimIndent()
.replace("\n", " ")
.replace("UVarInt", "", ignoreCase = true)
.replace("uint", "", ignoreCase = true)
.replace("[", "")
.replace("]", "")
.replace("(", "")
.replace(")", "")
.replace(" ", " ")
.replace(" ", " ")
.replace(" ", " ")
.replace("_", "")
.replace(",", "")
.hexToBytes()
println(bytes.read { readProtoMap() })
}
@UseExperimental(ImplicitReflectionSerializer::class)
fun <T : Any> KClass<T>.loadFrom(protoBuf: ByteArray): T = ProtoBuf.load(this.serializer(), protoBuf)
\ No newline at end of file
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