|
|
@@ -6,6 +6,7 @@
|
|
|
*
|
|
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
|
*/
|
|
|
+@file: OptIn(MiraiExperimentalAPI::class, MiraiInternalAPI::class, LowLevelAPI::class, ExperimentalUnsignedTypes::class)
|
|
|
|
|
|
package net.mamoe.mirai.qqandroid.message
|
|
|
|
|
|
@@ -218,6 +219,8 @@ private val atAllData = ImMsgBody.Elem(
|
|
|
)
|
|
|
)
|
|
|
|
|
|
+private val UNSUPPORTED_MERGED_MESSAGE_PLAIN = PlainText("你的QQ暂不支持查看[转发多条消息],请期待后续版本。")
|
|
|
+
|
|
|
@OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class)
|
|
|
internal fun MessageChain.toRichTextElems(forGroup: Boolean): MutableList<ImMsgBody.Elem> {
|
|
|
val elements = mutableListOf<ImMsgBody.Elem>()
|
|
|
@@ -231,33 +234,54 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean): MutableList<ImMsgB
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ var longTextResId: String? = null
|
|
|
|
|
|
fun transformOneMessage(it: Message) {
|
|
|
+ if (it is RichMessage) {
|
|
|
+ val content = MiraiPlatformUtils.zip(it.content.toByteArray())
|
|
|
+ when (it) {
|
|
|
+ is LongMessage -> {
|
|
|
+ check(longTextResId == null) { "There must be no more than one LongMessage element in the message chain" }
|
|
|
+ elements.add(
|
|
|
+ ImMsgBody.Elem(
|
|
|
+ richMsg = ImMsgBody.RichMsg(
|
|
|
+ serviceId = 35, // ok
|
|
|
+ template1 = byteArrayOf(1) + content
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ transformOneMessage(UNSUPPORTED_MERGED_MESSAGE_PLAIN)
|
|
|
+ longTextResId = it.resId
|
|
|
+ }
|
|
|
+ is LightApp -> elements.add(
|
|
|
+ ImMsgBody.Elem(
|
|
|
+ lightApp = ImMsgBody.LightAppElem(
|
|
|
+ data = byteArrayOf(1) + content
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ else -> elements.add(
|
|
|
+ ImMsgBody.Elem(
|
|
|
+ richMsg = ImMsgBody.RichMsg(
|
|
|
+ serviceId = when (it) {
|
|
|
+ is XmlMessage -> 60
|
|
|
+ is JsonMessage -> 1
|
|
|
+ // is MergedForwardedMessage -> 35
|
|
|
+ else -> error("unsupported RichMessage: ${it::class.simpleName}")
|
|
|
+ },
|
|
|
+ template1 = byteArrayOf(1) + content
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
when (it) {
|
|
|
is PlainText -> elements.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = it.stringValue)))
|
|
|
is At -> {
|
|
|
elements.add(ImMsgBody.Elem(text = it.toJceData()))
|
|
|
elements.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = " ")))
|
|
|
}
|
|
|
- is LightApp -> elements.add(
|
|
|
- ImMsgBody.Elem(
|
|
|
- lightApp = ImMsgBody.LightAppElem(
|
|
|
- data = byteArrayOf(1) + MiraiPlatformUtils.zip(it.content.toByteArray())
|
|
|
- )
|
|
|
- )
|
|
|
- )
|
|
|
- is RichMessage -> elements.add(
|
|
|
- ImMsgBody.Elem(
|
|
|
- richMsg = ImMsgBody.RichMsg(
|
|
|
- serviceId = when (it) {
|
|
|
- is XmlMessage -> 60
|
|
|
- is JsonMessage -> 1
|
|
|
- else -> error("unsupported RichMessage")
|
|
|
- },
|
|
|
- template1 = byteArrayOf(1) + MiraiPlatformUtils.zip(it.content.toByteArray())
|
|
|
- )
|
|
|
- )
|
|
|
- )
|
|
|
is OfflineGroupImage -> elements.add(ImMsgBody.Elem(customFace = it.toJceData()))
|
|
|
is OnlineGroupImageImpl -> elements.add(ImMsgBody.Elem(customFace = it.delegate))
|
|
|
is OnlineFriendImageImpl -> elements.add(ImMsgBody.Elem(notOnlineImage = it.delegate))
|
|
|
@@ -267,16 +291,18 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean): MutableList<ImMsgB
|
|
|
is QuoteReplyToSend -> {
|
|
|
if (forGroup) {
|
|
|
check(it is QuoteReplyToSend.ToGroup) {
|
|
|
- "sending a quote to group using QuoteReplyToSend.ToFriend"
|
|
|
+ "sending a quote to group using QuoteReplyToSend.ToFriend is prohibited"
|
|
|
}
|
|
|
if (it.sender is Member) {
|
|
|
transformOneMessage(it.createAt())
|
|
|
}
|
|
|
- transformOneMessage(" ".toMessage())
|
|
|
+ transformOneMessage(PlainText(" "))
|
|
|
}
|
|
|
}
|
|
|
- is QuoteReply,
|
|
|
- is MessageSource -> {
|
|
|
+ is QuoteReply, // already transformed above
|
|
|
+ is MessageSource, // mirai only
|
|
|
+ is RichMessage, // already transformed above
|
|
|
+ -> {
|
|
|
|
|
|
}
|
|
|
else -> error("unsupported message type: ${it::class.simpleName}")
|
|
|
@@ -284,10 +310,24 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean): MutableList<ImMsgB
|
|
|
}
|
|
|
this.forEach(::transformOneMessage)
|
|
|
|
|
|
- if (this.any<RichMessage>()) {
|
|
|
- // 08 09 78 00 A0 01 81 DC 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 02 08 03 90 04 80 80 80 10 B8 04 00 C0 04 00
|
|
|
- elements.add(ImMsgBody.Elem(generalFlags = ImMsgBody.GeneralFlags(pbReserve = "08 09 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 02 08 03 90 04 80 80 80 10 B8 04 00 C0 04 00".hexToBytes())))
|
|
|
- } else elements.add(ImMsgBody.Elem(generalFlags = ImMsgBody.GeneralFlags(pbReserve = "78 00 F8 01 00 C8 02 00".hexToBytes())))
|
|
|
+ when {
|
|
|
+ longTextResId != null -> {
|
|
|
+ elements.add(
|
|
|
+ ImMsgBody.Elem(
|
|
|
+ generalFlags = ImMsgBody.GeneralFlags(
|
|
|
+ longTextFlag = 1,
|
|
|
+ longTextResid = longTextResId!!,
|
|
|
+ pbReserve = "78 00 F8 01 00 C8 02 00".hexToBytes()
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ this.any<RichMessage>() -> {
|
|
|
+ // 08 09 78 00 A0 01 81 DC 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 02 08 03 90 04 80 80 80 10 B8 04 00 C0 04 00
|
|
|
+ elements.add(ImMsgBody.Elem(generalFlags = ImMsgBody.GeneralFlags(pbReserve = "08 09 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 02 08 03 90 04 80 80 80 10 B8 04 00 C0 04 00".hexToBytes())))
|
|
|
+ }
|
|
|
+ else -> elements.add(ImMsgBody.Elem(generalFlags = ImMsgBody.GeneralFlags(pbReserve = "78 00 F8 01 00 C8 02 00".hexToBytes())))
|
|
|
+ }
|
|
|
|
|
|
return elements
|
|
|
}
|
|
|
@@ -358,7 +398,7 @@ internal fun MsgComm.Msg.toMessageChain(): MessageChain {
|
|
|
return buildMessageChain(elements.size + 1) {
|
|
|
+MessageSourceFromMsg(delegate = this@toMessageChain)
|
|
|
elements.joinToMessageChain(this)
|
|
|
- }.removeAtIfHasQuoteReply()
|
|
|
+ }.cleanupRubbishMessageElements()
|
|
|
}
|
|
|
|
|
|
// These two functions are not identical, dont combine.
|
|
|
@@ -369,11 +409,40 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
|
|
|
return buildMessageChain(elements.size + 1) {
|
|
|
+MessageSourceFromServer(delegate = this@toMessageChain)
|
|
|
elements.joinToMessageChain(this)
|
|
|
- }.removeAtIfHasQuoteReply()
|
|
|
+ }.cleanupRubbishMessageElements()
|
|
|
+}
|
|
|
+
|
|
|
+private fun MessageChain.cleanupRubbishMessageElements(): MessageChain {
|
|
|
+ var last: SingleMessage? = null
|
|
|
+ return buildMessageChain(initialSize = this.count()) {
|
|
|
+ [email protected] { element ->
|
|
|
+ if (last == null) {
|
|
|
+ last = element
|
|
|
+ return@forEach
|
|
|
+ } else {
|
|
|
+ if (last is LongMessage && element is PlainText) {
|
|
|
+ if (element == UNSUPPORTED_MERGED_MESSAGE_PLAIN) {
|
|
|
+ last = element
|
|
|
+ return@forEach
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ add(element)
|
|
|
+ last = element
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+internal inline fun <reified R> Iterable<*>.firstIsInstance(): R {
|
|
|
+ this.forEach {
|
|
|
+ if (it is R) {
|
|
|
+ return it
|
|
|
+ }
|
|
|
+ }
|
|
|
+ throw NoSuchElementException("Collection contains no element matching the predicate.")
|
|
|
}
|
|
|
|
|
|
-private fun MessageChain.removeAtIfHasQuoteReply(): MessageChain =
|
|
|
- this
|
|
|
/*
|
|
|
if (this.any<QuoteReply>()) {
|
|
|
var removed = false
|
|
|
@@ -387,9 +456,6 @@ private fun MessageChain.removeAtIfHasQuoteReply(): MessageChain =
|
|
|
}.asMessageChain()
|
|
|
} else this*/
|
|
|
|
|
|
-@OptIn(
|
|
|
- MiraiInternalAPI::class, ExperimentalUnsignedTypes::class, MiraiDebugAPI::class, LowLevelAPI::class
|
|
|
-)
|
|
|
internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilder) {
|
|
|
this.forEach {
|
|
|
when {
|
|
|
@@ -425,6 +491,12 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilde
|
|
|
when (it.richMsg.serviceId) {
|
|
|
1 -> message.add(JsonMessage(content))
|
|
|
60 -> message.add(XmlMessage(content))
|
|
|
+ 35 -> message.add(
|
|
|
+ LongMessage(
|
|
|
+ content,
|
|
|
+ this.firstIsInstance<ImMsgBody.GeneralFlags>().longTextResid
|
|
|
+ )
|
|
|
+ )
|
|
|
else -> {
|
|
|
@Suppress("DEPRECATION")
|
|
|
MiraiLogger.debug {
|