4 Commits

11 changed files with 129 additions and 55 deletions

View File

@ -1,5 +1,6 @@
package com.tencent.qqnt.kernel.api.impl;
import com.tencent.qqnt.kernel.nativeinterface.IGetTempChatInfoCallback;
import com.tencent.qqnt.kernel.nativeinterface.IKernelMsgListener;
import com.tencent.qqnt.kernel.nativeinterface.IOperateCallback;
import com.tencent.qqnt.kernel.nativeinterface.RichMediaFilePathInfo;
@ -24,4 +25,8 @@ public class MsgService {
public void prepareTempChat(TempChatPrepareInfo tempChatPrepareInfo, IOperateCallback cb) {
}
public void getTempChatInfo(int chatType, @Nullable String uid, @Nullable IGetTempChatInfoCallback cb) {
}
}

View File

@ -0,0 +1,5 @@
package com.tencent.qqnt.kernel.nativeinterface;
public interface IGetTempChatInfoCallback {
void onResult(int code, String msg, TempChatInfo info);
}

View File

@ -97,6 +97,8 @@ import java.nio.ByteBuffer
import kotlin.coroutines.resume
internal object GroupSvc: BaseSvc() {
private const val GET_MEMBER_ROLE_BY_NT = false
private val RefreshTroopMemberInfoLock by lazy {
Mutex()
}
@ -396,6 +398,13 @@ internal object GroupSvc: BaseSvc() {
}
suspend fun getMemberRole(groupId: Long, memberUin: Long): MemberRole {
if (!GET_MEMBER_ROLE_BY_NT) {
return when (memberUin) {
getOwner(groupId.toString()) -> MemberRole.Owner
in getAdminList(groupId.toString()) -> MemberRole.Admin
else -> MemberRole.Member
}
}
return when(getTroopMemberInfoByUinViaNt(groupId.toString(), memberUin, 3000).getOrNull()?.role) {
com.tencent.qqnt.kernel.nativeinterface.MemberRole.STRANGER -> MemberRole.Stranger
com.tencent.qqnt.kernel.nativeinterface.MemberRole.MEMBER -> MemberRole.Member
@ -641,6 +650,7 @@ internal object GroupSvc: BaseSvc() {
qq: Long,
timeout: Long = 5000L
): Result<MemberInfo> {
return runCatching {
val kernelService = NTServiceFetcher.kernelService
val sessionService = kernelService.wrapperSession
val groupService = sessionService.groupService
@ -667,6 +677,7 @@ internal object GroupSvc: BaseSvc() {
Result.failure(Exception("获取群成员信息失败"))
}
}
}
suspend fun getTroopMemberInfoByUid(groupId: Long, uid: String): Result<MemberInfo> {
val kernelService = NTServiceFetcher.kernelService

View File

@ -9,6 +9,7 @@ import com.tencent.qqnt.kernel.nativeinterface.IOperateCallback
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import com.tencent.qqnt.kernel.nativeinterface.TempChatGameSession
import com.tencent.qqnt.kernel.nativeinterface.TempChatInfo
import com.tencent.qqnt.kernel.nativeinterface.TempChatPrepareInfo
import com.tencent.qqnt.msg.api.IMsgService
import kotlinx.coroutines.DelicateCoroutinesApi
@ -42,9 +43,12 @@ internal object MsgSvc: BaseSvc() {
msgService.prepareTempChat(TempChatPrepareInfo(
MsgConstant.KCHATTYPETEMPC2CFROMGROUP,
ContactHelper.getUidByUinAsync(peerId = peerId.toLong()),
app.getRuntimeService(ITroopMemberNameService::class.java, "all")
.getTroopMemberNameRemarkFirst(groupId, peerId),
groupId, EMPTY_BYTE_ARRAY, app.currentUid, "", TempChatGameSession()
app.getRuntimeService(ITroopMemberNameService::class.java, "all").getTroopMemberNameRemarkFirst(groupId, peerId),
groupId,
EMPTY_BYTE_ARRAY,
app.currentUid,
"",
TempChatGameSession()
)) { code, reason ->
if (code != 0) {
LogCenter.log("临时会话创建失败: $code, $reason", Level.ERROR)
@ -53,6 +57,24 @@ internal object MsgSvc: BaseSvc() {
return Result.success(Unit)
}
suspend fun getTempChatInfo(chatType: Int, uid: String): Result<TempChatInfo> {
val msgService = app.getRuntimeService(IKernelService::class.java, "all").msgService
?: return Result.failure(Exception("获取消息服务失败"))
val info: TempChatInfo = withTimeoutOrNull(5000) {
suspendCancellableCoroutine {
msgService.getTempChatInfo(chatType, uid) { code, msg, tempChatInfo ->
if (code == 0) {
it.resume(tempChatInfo)
} else {
LogCenter.log("获取临时会话信息失败: $code:$msg", Level.ERROR)
it.resume(null)
}
}
}
} ?: return Result.failure(Exception("获取临时会话信息失败"))
return Result.success(info)
}
/**
* 正常获取
*/
@ -183,8 +205,8 @@ internal object MsgSvc: BaseSvc() {
}
}
val result = MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, fromId, MessageCallback(peedId, 0))
result.onFailure {
LogCenter.log("sendToAio: " + it.stackTraceToString(), Level.ERROR)
if (result.isFailure) {
LogCenter.log("sendToAio: " + result.exceptionOrNull()?.stackTraceToString(), Level.ERROR)
return result
}
val sendResult = result.getOrThrow()

View File

@ -6,6 +6,7 @@ import com.tencent.mobileqq.transfile.TransferRequest
import moe.fuqiuluo.shamrock.utils.MD5
import java.io.File
import moe.fuqiuluo.qqinterface.servlet.transfile.ResourceType.*
import moe.fuqiuluo.shamrock.helper.TransfileHelper
internal object Transfer: FileTransfer() {
private val ROUTE = mapOf<ContactType, Map<ResourceType, suspend TransTarget.(Resource) -> Boolean>>(
@ -84,11 +85,14 @@ internal object Transfer: FileTransfer() {
file: File,
wait: Boolean = true
): Boolean {
return transC2CResource(peerId, file, FileMsg.TRANSFILE_TYPE_PIC, SEND_MSG_BUSINESS_TYPE_PIC_SHARE, wait) {
return transC2CResource(peerId, file, FileMsg.TRANSFILE_TYPE_PIC, SEND_MSG_BUSINESS_TYPE_PIC_CAMERA, wait) {
val picUpExtraInfo = TransferRequest.PicUpExtraInfo()
picUpExtraInfo.mIsRaw = true
picUpExtraInfo.mIsRaw = false
picUpExtraInfo.mUinType = FileMsg.UIN_BUDDY
it.mPicSendSource = 8
it.mExtraObj = picUpExtraInfo
it.mIsPresend = true
it.delayShowProgressTimeInMs = 2000
}
}
@ -97,10 +101,13 @@ internal object Transfer: FileTransfer() {
file: File,
wait: Boolean = true
): Boolean {
return transTroopResource(groupId, file, FileMsg.TRANSFILE_TYPE_PIC, SEND_MSG_BUSINESS_TYPE_PIC_SHARE, wait) {
return transTroopResource(groupId, file, FileMsg.TRANSFILE_TYPE_PIC, SEND_MSG_BUSINESS_TYPE_PIC_CAMERA, wait) {
val picUpExtraInfo = TransferRequest.PicUpExtraInfo()
picUpExtraInfo.mIsRaw = true
//picUpExtraInfo.mIsRaw = !TransfileHelper.isGifFile(file)
picUpExtraInfo.mIsRaw = false
picUpExtraInfo.mUinType = FileMsg.UIN_TROOP
it.mPicSendSource = 8
it.delayShowProgressTimeInMs = 2000
it.mExtraObj = picUpExtraInfo
}
}

View File

@ -1,6 +1,8 @@
package moe.fuqiuluo.shamrock.helper
import java.io.File
import java.io.IOException
import java.io.RandomAccessFile
internal object TransfileHelper {
private val extensionMap = mapOf(
@ -94,4 +96,15 @@ internal object TransfileHelper {
val extension = name.substring(index)
return extensionMap[extension] ?: -1
}
fun isGifFile(picFile: File): Boolean {
if (picFile.exists() && picFile.length() > 3) {
return RandomAccessFile(picFile, "r").use {
val bArr = ByteArray(3)
it.read(bArr)
if (bArr[0].toInt() == 71 && bArr[1].toInt() == 73 && bArr[2].toInt() == 70) { return true } else false
}
}
return false
}
}

View File

@ -114,7 +114,9 @@ internal object GlobalEventTransmitter: BaseSvc() {
rawMsg: String,
msgHash: Int,
postType: PostType,
tempSource: MessageTempSource = MessageTempSource.Unknown
tempSource: MessageTempSource = MessageTempSource.Unknown,
groupId: Long = Long.MIN_VALUE,
fromNick: String? = null
): Boolean {
val botUin = app.longAccountUin
var nickName = record.sendNickName
@ -148,7 +150,9 @@ internal object GlobalEventTransmitter: BaseSvc() {
title = "",
level = "",
),
tmpSource = tempSource.id
tmpSource = tempSource.id,
groupId = groupId,
fromNickName = fromNick
)
)
return true

View File

@ -52,10 +52,10 @@ internal data class MessageEvent (
@SerialName("message_type") val messageType: MsgType,
@SerialName("sub_type") val subType: MsgSubType,
@SerialName("message_id") val messageId: Int,
@SerialName("group_id") val groupId: Long = 0,
@SerialName("group_id") val groupId: Long = Long.MIN_VALUE,
@SerialName("guild_id") val guildId: String? = null,
@SerialName("channel_id") val channelId: String? = null,
@SerialName("target_id") val targetId: Long = 0,
@SerialName("target_id") val targetId: Long = Long.MIN_VALUE,
@SerialName("peer_id") val peerId: Long,
@SerialName("user_id") val userId: Long,
@SerialName("anonymous") val anonymous: Anonymous? = null,
@ -63,7 +63,8 @@ internal data class MessageEvent (
@SerialName("raw_message") val rawMessage: String,
@SerialName("font") val font: Int,
@SerialName("sender") val sender: Sender,
@SerialName("temp_source") val tmpSource: Int = -1
@SerialName("temp_source") val tmpSource: Int = Int.MIN_VALUE,
@SerialName("from_nick") val fromNickName: String? = null
)
enum class MessageTempSource(val id: Int) {

View File

@ -7,6 +7,7 @@ import com.tencent.qqnt.kernel.nativeinterface.*
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toCQCode
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
@ -113,19 +114,29 @@ internal object AioListener : IKernelMsgListener {
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> {
if (!ShamrockConfig.allowTempSession()) return
LogCenter.log("私聊临时消息(private = ${record.senderUin}, id = $msgHash, msg = $rawMsg)")
ShamrockConfig.getPrivateRule()?.let { rule ->
if (!rule.black.isNullOrEmpty() && rule.black.contains(record.senderUin)) return
if (!rule.white.isNullOrEmpty() && !rule.white.contains(record.senderUin)) return
}
var groupCode = 0L
var fromNick = ""
MsgSvc.getTempChatInfo(record.chatType, record.senderUid).onSuccess {
groupCode = it.groupCode.toLong()
fromNick = it.fromNick
}
LogCenter.log("私聊临时消息(private = ${record.senderUin}, groupId=$groupCode, id = $msgHash, msg = $rawMsg)")
if (!GlobalEventTransmitter.MessageTransmitter.transPrivateMessage(
record,
record.elements,
rawMsg,
msgHash,
tempSource = MessageTempSource.Group,
postType = postType
postType = postType,
groupId = groupCode,
fromNick = fromNick
)
) {
LogCenter.log("私聊临时消息推送失败 -> MessageTransmitter", Level.WARN)

View File

@ -138,6 +138,7 @@ internal class XposedEntry: IXposedHookLoadPackage {
MMKVFetcher.initMMKV(ctx)
}
runCatching {
if (ShamrockConfig.forbidUselessProcess()) {
if(uselessProcess.any {
processName.contains(it, ignoreCase = true)
@ -149,6 +150,7 @@ internal class XposedEntry: IXposedHookLoadPackage {
} else {
log("[Shamrock] Useless process detection is disabled.")
}
}
log("Process Name = $processName")

View File

@ -2,24 +2,17 @@ package moe.fuqiuluo.shamrock.xposed.helper
import com.tencent.qqnt.kernel.api.IKernelService
import com.tencent.qqnt.kernel.api.impl.MsgService
import com.tencent.qqnt.kernel.nativeinterface.IKernelGroupService
import com.tencent.qqnt.kernel.nativeinterface.IKernelGuildService
import com.tencent.qqnt.kernel.nativeinterface.IOperateCallback
import com.tencent.qqnt.kernel.nativeinterface.IQQNTWrapperSession
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.PacketReceiver
import moe.fuqiuluo.shamrock.remote.service.listener.AioListener
import moe.fuqiuluo.shamrock.remote.service.listener.GroupEventListener
import moe.fuqiuluo.shamrock.remote.service.listener.KernelGuildListener
import moe.fuqiuluo.shamrock.remote.service.listener.PrimitiveListener
import moe.fuqiuluo.shamrock.tools.hookMethod
import moe.fuqiuluo.shamrock.utils.PlatformUtils
import kotlin.reflect.jvm.javaMethod
internal object NTServiceFetcher {
private lateinit var iKernelService: IKernelService
@ -30,7 +23,7 @@ internal object NTServiceFetcher {
lock.withLock {
val msgService = service.msgService ?: return
val sessionService = service.wrapperSession ?: return
val groupService = sessionService.groupService ?: return
//val groupService = sessionService.groupService ?: return
val curHash = service.hashCode() + msgService.hashCode()
if (isInitForNt(curHash)) return
@ -43,7 +36,7 @@ internal object NTServiceFetcher {
this.iKernelService = service
initNTKernelListener(msgService, groupService)
initNTKernelListener(msgService)
antiBackgroundMode(sessionService)
//hookGuildListener(sessionService)
}
@ -66,7 +59,7 @@ internal object NTServiceFetcher {
return hash == curKernelHash
}
private fun initNTKernelListener(msgService: MsgService, groupService: IKernelGroupService) {
private fun initNTKernelListener(msgService: MsgService) {
if (!PlatformUtils.isMainProcess()) return
try {