diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 1f674c1c..159e39db 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -199,17 +199,36 @@ -keep class com.arthenica.ffmpegkit.NativeLoader { *; } --keep class moe.fuqiuluo.** { *; } +-keep class moe.fuqiuluo.shamrock.app.** { *; } +-keep class moe.fuqiuluo.shamrock.ui.** { *; } +-keep class moe.fuqiuluo.shamrock.MainActivity { *; } +-keep class moe.fuqiuluo.shamrock.MainActivityKt { *; } +-keep class moe.fuqiuluo.shamrock.Manifest { *; } + +-keep class moe.fuqiuluo.shamrock.xposed.** { *; } +-keep class moe.fuqiuluo.shamrock.helper.** { *; } + +# tencent interfaces rules -keep class com.tencent.** { *; } -keep class com.qq.** { *; } -keep class com.google.gson.** { *; } -keep class de.** { *; } +-keep class epic.** { *; } +-keep class friendlist.** { *; } +-keep class KQQ.** { *; } -keep class mqq.** { *; } +-keep class msf.** { *; } +-keep class oicq.** { *; } -keep class QQService.** { *; } -keep class SummaryCard.** { *; } -keep class tencent.** { *; } +-keep class VIP.** { *; } -keepclassmembers class * { native ; } -keep class io.netty.** { *; } + +-keepclasseswithmembernames class * { + native ; +} diff --git a/protobuf/src/main/java/protobuf/message/element/NotOnlineImage.kt b/protobuf/src/main/java/protobuf/message/element/NotOnlineImage.kt index 2e296ca7..e9e772a8 100644 --- a/protobuf/src/main/java/protobuf/message/element/NotOnlineImage.kt +++ b/protobuf/src/main/java/protobuf/message/element/NotOnlineImage.kt @@ -14,7 +14,7 @@ data class NotOnlineImage( @ProtoNumber(7) val picMd5: ByteArray? = null, @ProtoNumber(8) val picHeight: UInt? = null, @ProtoNumber(9) val picWidth: UInt? = null, - @ProtoNumber(10) val resId: ByteArray? = null, + @ProtoNumber(10) val resId: ByteArray? = null, // md5 + ".jpg" @ProtoNumber(11) val flag: ByteArray? = null, @ProtoNumber(12) val thumbUrl: String? = null, @ProtoNumber(13) val original: UInt? = null, diff --git a/protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Req.kt b/protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Req.kt new file mode 100644 index 00000000..ea1f666b --- /dev/null +++ b/protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Req.kt @@ -0,0 +1,63 @@ +package protobuf.oidb.cmd0x388 + +import com.google.protobuf.Internal.EMPTY_BYTE_ARRAY +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoNumber +import moe.fuqiuluo.symbols.Protobuf + +@Serializable +data class Cmd0x388ReqBody( + @ProtoNumber(1) var netType: Int = 0, + @ProtoNumber(2) var subCmd: Int = 0, + @ProtoNumber(3) var msgTryUpImg: ArrayList? = null, + // @ProtoNumber(4) var rpt_msg_getimg_url_req: ArrayList? = null, + @ProtoNumber(5) var msgTryUpPttReq: ArrayList? = null, + // @ProtoNumber(6) var msgGetPttUrlReq: ArrayList? = null, + @ProtoNumber(7) var commandId: Int = 0, + // @ProtoNumber(8) var rpt_msg_del_img_req: ArrayList? = null, + @ProtoNumber(1001) var extension: ByteArray = EMPTY_BYTE_ARRAY, +): Protobuf + +@Serializable +data class TryUpImgReq( + @ProtoNumber(1) var groupCode: Long = 0, + @ProtoNumber(2) var srcUin: Long = 0, + @ProtoNumber(3) var fileId: Long? = null, + @ProtoNumber(4) var fileMd5: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(5) var fileSize: Long = 0, + @ProtoNumber(6) var fileName: String = "", + @ProtoNumber(7) var srcTerm: Int = 0, + @ProtoNumber(8) var platformType: Int = 0, + @ProtoNumber(9) var buType: Int = 0, + @ProtoNumber(10) var picWidth: Int = 0, + @ProtoNumber(11) var picHeight: Int = 0, + @ProtoNumber(12) var picType: Int = 0, + @ProtoNumber(13) var buildVer: String = "", + @ProtoNumber(14) var innerIp: Int = 0, + @ProtoNumber(15) var appPicType: Int = 0, + @ProtoNumber(16) var originalPic: Int = 0, + @ProtoNumber(17) var fileIndex: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(18) var dstUin: Long = 0, + @ProtoNumber(19) var srvUpload: Int? = null, + @ProtoNumber(20) var transferUrl: ByteArray = EMPTY_BYTE_ARRAY, +) + +@Serializable +data class TryUpPttReq( + @ProtoNumber(1) var groupCode: Long = 0, + @ProtoNumber(2) var srcUin: Long = 0, + @ProtoNumber(3) var fileId: Long = 0, + @ProtoNumber(4) var fileMd5: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(5) var fileSize: Long = 0, + @ProtoNumber(6) var fileName: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(7) var srcTerm: Int = 0, + @ProtoNumber(8) var platformType: Int = 0, + @ProtoNumber(9) var buType: Int = 0, + @ProtoNumber(10) var buildVer: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(11) var innerIp: Int = 0, + @ProtoNumber(12) var voiceLength: Int = 0, + @ProtoNumber(13) var newUpChan: Boolean = false, + @ProtoNumber(14) var codec: Int = 0, + @ProtoNumber(15) var voiceType: Int = 0, + @ProtoNumber(16) var buId: Int = 0, +) diff --git a/protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Rsp.kt b/protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Rsp.kt new file mode 100644 index 00000000..8d7f107e --- /dev/null +++ b/protobuf/src/main/java/protobuf/oidb/cmd0x388/Cmd0x388Rsp.kt @@ -0,0 +1,78 @@ +@file:OptIn(ExperimentalSerializationApi::class) + +package protobuf.oidb.cmd0x388 + +import com.google.protobuf.Internal.EMPTY_BYTE_ARRAY +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoNumber +import moe.fuqiuluo.symbols.Protobuf + +@Serializable +data class Cmd0x388RspBody( + @ProtoNumber(1) var clientIp: UInt = 0u, + @ProtoNumber(2) var subCmd: UInt = 0u, + @ProtoNumber(3) var msgTryUpImgRsp: ArrayList? = null, + @ProtoNumber(5) var msgTryUpPttRsp: ArrayList? = null, +): Protobuf + +@Serializable +data class TryUpPttRsp( + @ProtoNumber(1) var fileId: Long = 0, + @ProtoNumber(2) var result: Int = 0, + @ProtoNumber(3) var failMsg: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(4) var fileExit: Boolean = false, + @ProtoNumber(5) var upIp: List? = null, + @ProtoNumber(6) var upPort: List? = null, + @ProtoNumber(7) var upUkey: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(8) var fileid: Long = 0, + @ProtoNumber(9) var upOffset: Long = 0, + @ProtoNumber(10) var blockSize: Long = 0, + @ProtoNumber(11) var fileKey: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(12) var channelType: Int = 0, + @ProtoNumber(26) var msgUpIp6: ArrayList? = null, + @ProtoNumber(27) var clientIp6: ByteArray = EMPTY_BYTE_ARRAY, +): Protobuf + +@Serializable +data class TryUpImgRsp( + @ProtoNumber(1) var extFileId: ULong = 0u, // 没有实际作用 + @ProtoNumber(2) var result: UInt = 0u, + @ProtoNumber(3) var faiMsg: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(4) var fileExist: Boolean = false, + @ProtoNumber(5) var msgImgInfo: ImgInfo? = null, // 里面只是一堆垃圾 + @ProtoNumber(6) var upIp: ArrayList? = null, + @ProtoNumber(7) var upPort: ArrayList? = null, + @ProtoNumber(8) var ukey: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(9) var fileId: Long = 0, + @ProtoNumber(10) var upOffset: ULong = 0u, + @ProtoNumber(11) var blockSize: Long = 0, + @ProtoNumber(12) var bool_new_big_chan: Boolean = false, + @ProtoNumber(26) var rpt_msg_up_ip6: ArrayList? = null, + @ProtoNumber(27) var client_ip6: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(1001) var msg_info4busi: TryUpInfo4Busi? = null, +) + +@Serializable +data class TryUpInfo4Busi( + @ProtoNumber(1) var down_domain: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(2) var thumb_down_url: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(3) var original_down_url: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(4) var big_down_url: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(5) var file_resid: ByteArray = EMPTY_BYTE_ARRAY, +) + +@Serializable +data class IPv6Info( + @ProtoNumber(1) var ip6: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(2) var port: UInt = 0u, +) + +@Serializable +data class ImgInfo( + @ProtoNumber(1) var file_md5: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(2) var file_type: UInt = 0u, + @ProtoNumber(3) var file_size: ULong = 0u, + @ProtoNumber(4) var file_width: UInt = 0u, + @ProtoNumber(5) var file_height: UInt = 0u, +) \ No newline at end of file diff --git a/qqinterface/src/main/java/com/tencent/mobileqq/data/MessageForPic.java b/qqinterface/src/main/java/com/tencent/mobileqq/data/MessageForPic.java new file mode 100644 index 00000000..294d6201 --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/mobileqq/data/MessageForPic.java @@ -0,0 +1,74 @@ +package com.tencent.mobileqq.data; + +import java.util.HashMap; +import java.util.Map; + +public class MessageForPic extends MessageRecord { + public String SpeedInfo; + public String actMsgContentValue; + public String action; + public String bigMsgUrl; + public String bigThumbMsgUrl; + public int busiType; + public int fileSizeFlag; + public long groupFileID; + public long height; + public int imageType; + public boolean isInMixedMsg; + public boolean isMixed; + public boolean isRead; + public boolean isShareAppActionMsg; + public String localUUID; + public int mCurrlength; + public int mDownloadLength; + public long mPresendTransferedSize; + public int mShowLength; + public String md5; + //@RecordForTest + // public msg_ctrl$MsgCtrl msgCtrl; + public int msgVia; + public int ntChatType; + public String ntPeerUid; + public String path; + //public PicMessageExtraData picExtraData; + public int picExtraFlag; + public Object picExtraObject; + public int previewed; + public String rawMsgUrl; + /// public ReportInfo reportInfo; + //public MsgRecordParams rootMsgRecordParams; + public String serverStoreSource; + public long shareAppID; + public long size; + public long subTypeId; + public int thumbHeight; + public String thumbMsgUrl; + public int thumbWidth; + //public ThumbWidthHeightDP thumbWidthHeightDP; + public int type; + public String uuid; + public long width; + public boolean isDownStatusReady = false; + public int subMsgId = 0; + public int isReport = 0; + public int subVersion = 5; + public int preDownState = -1; + public int preDownNetworkType = -1; + public long DSKey = 0; + public int mNotPredownloadReason = 0; + public int subThumbWidth = -1; + public int subThumbHeight = -1; + public int aiofileType = -1; + public int subMsgType = -1; + public boolean bEnableEnc = false; + public int thumbSize = -1; + public boolean isBlessPic = false; + public boolean sync2Story = false; + public boolean isQzonePic = false; + public boolean isStoryPhoto = false; + public long replyRealSourceMsgId = -1; + + public String toLogString() { + return "path:" + this.path + ",uuid:" + this.uuid + ",md5:" + this.md5 + ",size:" + this.size + ",groupFileID:" + this.groupFileID; + } +} diff --git a/qqinterface/src/main/java/com/tencent/mobileqq/transfile/BaseTransProcessor.java b/qqinterface/src/main/java/com/tencent/mobileqq/transfile/BaseTransProcessor.java index 1f386554..75a6f1fe 100644 --- a/qqinterface/src/main/java/com/tencent/mobileqq/transfile/BaseTransProcessor.java +++ b/qqinterface/src/main/java/com/tencent/mobileqq/transfile/BaseTransProcessor.java @@ -1,6 +1,8 @@ package com.tencent.mobileqq.transfile; -public class BaseTransProcessor { +import com.tencent.mobileqq.utils.httputils.IHttpCommunicatorListener; + +public class BaseTransProcessor implements IHttpCommunicatorListener { public FileMsg file; public long getFileStatus() { diff --git a/qqinterface/src/main/java/com/tencent/mobileqq/transfile/BaseUploadProcessor.java b/qqinterface/src/main/java/com/tencent/mobileqq/transfile/BaseUploadProcessor.java new file mode 100644 index 00000000..60e8a012 --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/mobileqq/transfile/BaseUploadProcessor.java @@ -0,0 +1,5 @@ +package com.tencent.mobileqq.transfile; + +public class BaseUploadProcessor extends BaseTransProcessor { + +} diff --git a/qqinterface/src/main/java/com/tencent/mobileqq/transfile/FileMsg.java b/qqinterface/src/main/java/com/tencent/mobileqq/transfile/FileMsg.java index 0c56c8c4..dd493fed 100644 --- a/qqinterface/src/main/java/com/tencent/mobileqq/transfile/FileMsg.java +++ b/qqinterface/src/main/java/com/tencent/mobileqq/transfile/FileMsg.java @@ -1,5 +1,9 @@ package com.tencent.mobileqq.transfile; +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; + public class FileMsg { public static final int STATUS_FILE_EXPIRED = 5002; public static final int STATUS_FILE_TRANSFERING = 5000; @@ -107,4 +111,58 @@ public class FileMsg { public static final int UIN_BUDDY = 0; public static final int UIN_DISCUSS = 2; public static final int UIN_TROOP = 1; + + public String domain; + public String downDomain; + public long endTime; + public int errorCode; + public String errorMessage; + public File file; + public long fileID; + public String fileKey; + public String fileMd5; + public String filePath; + public long fileSize; + public int fileType; + public String fileUrl; + public String forwardTaskKey; + public String friendUin; + public int isRead; + public boolean isStreamMode; + public int lastStatus; + public byte[] localFileMd5; + public String logTag; + public long mSecMsgId; + public long mSubMsgId; + public String mUin; + public String msgImageData; + public String msgTime; + public String orgiDownUrl; + public String peerUin; + public int picScale; + public long picThumbSize; + public BaseTransProcessor processor; + public boolean processorDoReportSelf; + public int pttSlicePos; + public String pttSliceText; + public OutputStream revStream; + public String selfUin; + public InputStream sendStream; + public String serverPath; + public long startTime; + public int status; + public long stepUrlCost; + public String suffixType; + public String thumbDownUrl; + public String thumbPath; + public String thumbUrl; + public String tmpFilePath; + public byte[] transferData; + public long transferedSize; + public String uKey; + public int uinType; + public long uniseq; + public String[] urls; + public byte[] userInfo; + public String uuidPath; } diff --git a/qqinterface/src/main/java/com/tencent/mobileqq/transfile/GroupPicUploadProcessor.java b/qqinterface/src/main/java/com/tencent/mobileqq/transfile/GroupPicUploadProcessor.java index 47f024a8..79f92d74 100644 --- a/qqinterface/src/main/java/com/tencent/mobileqq/transfile/GroupPicUploadProcessor.java +++ b/qqinterface/src/main/java/com/tencent/mobileqq/transfile/GroupPicUploadProcessor.java @@ -1,4 +1,6 @@ package com.tencent.mobileqq.transfile; -public class GroupPicUploadProcessor { +import com.tencent.mobileqq.utils.httputils.IHttpCommunicatorListener; + +public class GroupPicUploadProcessor extends BaseUploadProcessor { } diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/PicElement.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/PicElement.java index 71b2d0f3..29d93a35 100644 --- a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/PicElement.java +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/PicElement.java @@ -208,6 +208,8 @@ public void setIsFlashPic(Boolean bool) { this.isFlashPic = bool; } + public void setStoreID(int i2) { + } public void setMd5HexStr(String str) { this.md5HexStr = str; } diff --git a/xposed/proguard-rules.pro b/xposed/proguard-rules.pro index c6ba9ad8..481bb434 100644 --- a/xposed/proguard-rules.pro +++ b/xposed/proguard-rules.pro @@ -18,182 +18,4 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile - - -# Never inline methods, but allow shrinking and obfuscation. --keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.view.ViewCompat$Api* { - ; -} --keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.view.WindowInsetsCompat$*Impl* { - ; -} --keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.app.NotificationCompat$*$Api*Impl { - ; -} --keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.os.UserHandleCompat$Api*Impl { - ; -} --keepclassmembernames,allowobfuscation,allowshrinking class androidx.core.widget.EdgeEffectCompat$Api*Impl { - ; -} - -# Keep metadata about inner emulated classes. This helps with -# reflection on older platforms, but can be omitted if the -# metadata usage is not present in the app. - --keepclassmembers class * { - ** CREATOR; -} - -# Keep the special static methods that are required in all enumeration -# classes. --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); -} - --keep public class androidx.appcompat.widget.** { *; } --keep public class androidx.appcompat.app.** { *; } --keep public class androidx.appcompat.view.menu.** { *; } - -# Ensure that reflectively-loaded inflater is not obfuscated. This can be -# removed when we stop supporting AAPT1 builds. --keepnames class androidx.appcompat.app.AppCompatViewInflater -# aapt is not able to read app::actionViewClass and app:actionProviderClass to produce proguard -# keep rules. Add a commonly used SearchView to the keep list until b/109831488 is resolved. --keep class androidx.appcompat.widget.SearchView { (...); } - -# CoordinatorLayout resolves the behaviors of its child components with reflection. --keep public class * extends androidx.coordinatorlayout.widget.CoordinatorLayout$Behavior { - public (android.content.Context, android.util.AttributeSet); - public (); -} - -# Make sure we keep annotations for CoordinatorLayout's DefaultBehavior --keepattributes RuntimeVisible*Annotation* - --if class androidx.appcompat.app.AppCompatViewInflater --keep class com.google.android.material.theme.MaterialComponentsViewInflater { - (); -} - -# Keep `Companion` object fields of serializable classes. -# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects. --if @kotlinx.serialization.Serializable class ** --keepclassmembers class <1> { - static <1>$Companion Companion; -} - -# Keep `serializer()` on companion objects (both default and named) of serializable classes. --if @kotlinx.serialization.Serializable class ** { - static **$* *; -} --keepclassmembers class <2>$<3> { - kotlinx.serialization.KSerializer serializer(...); -} - -# Keep `INSTANCE.serializer()` of serializable objects. --if @kotlinx.serialization.Serializable class ** { - public static ** INSTANCE; -} --keepclassmembers class <1> { - public static <1> INSTANCE; - kotlinx.serialization.KSerializer serializer(...); -} - -# @Serializable and @Polymorphic are used at runtime for polymorphic serialization. --keepattributes RuntimeVisibleAnnotations,AnnotationDefault - -# Don't print notes about potential mistakes or omissions in the configuration for kotlinx-serialization classes -# See also https://github.com/Kotlin/kotlinx.serialization/issues/1900 --dontnote kotlinx.serialization.** - -# Serialization core uses `java.lang.ClassValue` for caching inside these specified classes. -# If there is no `java.lang.ClassValue` (for example, in Android), then R8/ProGuard will print a warning. -# However, since in this case they will not be used, we can disable these warnings --dontwarn kotlinx.serialization.internal.ClassValueReferences - -# Rule to save runtime annotations on serializable class. -# If the R8 full mode is used, annotations are removed from classes-files. -# -# For the annotation serializer, it is necessary to read the `Serializable` annotation inside the serializer() function - if it is present, -# then `SealedClassSerializer` is used, if absent, then `PolymorphicSerializer'. -# -# When using R8 full mode, all interfaces will be serialized using `PolymorphicSerializer`. -# -# see https://github.com/Kotlin/kotlinx.serialization/issues/2050 - --if @kotlinx.serialization.Serializable class ** --keep, allowshrinking, allowoptimization, allowobfuscation, allowaccessmodification class <1> - -# Entry point for retaining MainDispatcherLoader which uses a ServiceLoader. --keep class kotlinx.coroutines.Dispatchers { - ** getMain(); -} - -# Entry point for retaining CoroutineExceptionHandlerImpl.handlers which uses a ServiceLoader. --keep class kotlinx.coroutines.CoroutineExceptionHandlerKt { - void handleCoroutineException(...); -} - -# Entry point for the rest of coroutines machinery --keep class kotlinx.coroutines.BuildersKt { - ** runBlocking(...); - ** launch(...); -} - -# We are cheating a bit by not having android.jar on R8's library classpath. Ignore those warnings. --ignorewarnings - --keep class kotlinx.coroutines.android.AndroidDispatcherFactory {*;} --keep class kotlinx.coroutines.android.AndroidExceptionPreHandler {*;} - -# Statically turn off all debugging facilities and assertions --keepclassmembers class io.ktor.** { volatile ; } --keep class io.ktor.** { *; } --keep class kotlinx.coroutines.** { *; } --dontwarn kotlinx.atomicfu.** --dontwarn io.netty.** --dontwarn com.typesafe.** --assumenosideeffects class * implements org.slf4j.Logger { - public *** trace(...); - public *** debug(...); - public *** info(...); - public *** warn(...); - public *** error(...); -} --keep class kotlin.reflect.jvm.internal.** { *; } - --keep class com.arthenica.ffmpegkit.FFmpegKitConfig { - native ; - void log(long, int, byte[]); - void statistics(long, int, float, float, long , int, double, double); - int safOpen(int); - int safClose(int); -} - --keep class com.arthenica.ffmpegkit.AbiDetect { - native ; -} - --keep class com.arthenica.ffmpegkit.NativeLoader { *; } - --keep class moe.fuqiuluo.** { *; } --keep class com.tencent.** { *; } --keep class com.qq.** { *; } --keep class com.google.gson.** { *; } --keep class de.** { *; } --keep class mqq.** { *; } --keep class QQService.** { *; } --keep class SummaryCard.** { *; } --keep class tencent.** { *; } - --keepclassmembers class * { - native ; -} --keep class io.netty.** { *; } - --keep class moe.fuqiuluo.** implements com.tencent.qqnt.kernel.nativeinterface.** { - *; -} +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/maker/MsgElementMaker.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/maker/NtMsgElementMaker.kt similarity index 95% rename from xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/maker/MsgElementMaker.kt rename to xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/maker/NtMsgElementMaker.kt index 2e995b97..fbf4e0f7 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/maker/MsgElementMaker.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/msg/maker/NtMsgElementMaker.kt @@ -3,6 +3,7 @@ package moe.fuqiuluo.qqinterface.servlet.msg.maker import android.graphics.BitmapFactory import androidx.exifinterface.media.ExifInterface import com.tencent.mobileqq.app.QQAppInterface +import com.tencent.mobileqq.data.MessageForPic import com.tencent.mobileqq.emoticon.QQSysFaceUtil import com.tencent.mobileqq.pb.ByteStringMicro import com.tencent.mobileqq.qroute.QRoute @@ -57,37 +58,37 @@ import kotlin.random.nextInt internal typealias IMsgElementMaker = suspend (Int, Long, String, JsonObject) -> Result -internal object MsgElementMaker { +internal object NtMsgElementMaker { private val makerMap = hashMapOf( - "text" to MsgElementMaker::createTextElem, - "face" to MsgElementMaker::createFaceElem, - "pic" to MsgElementMaker::createImageElem, - "image" to MsgElementMaker::createImageElem, - "voice" to MsgElementMaker::createRecordElem, - "record" to MsgElementMaker::createRecordElem, - "at" to MsgElementMaker::createAtElem, - "video" to MsgElementMaker::createVideoElem, - "markdown" to MsgElementMaker::createMarkdownElem, - "dice" to MsgElementMaker::createDiceElem, - "rps" to MsgElementMaker::createRpsElem, - "poke" to MsgElementMaker::createPokeElem, - "anonymous" to MsgElementMaker::createAnonymousElem, - "share" to MsgElementMaker::createShareElem, - "contact" to MsgElementMaker::createContactElem, - "location" to MsgElementMaker::createLocationElem, - "music" to MsgElementMaker::createMusicElem, - "reply" to MsgElementMaker::createReplyElem, - "touch" to MsgElementMaker::createTouchElem, - "weather" to MsgElementMaker::createWeatherElem, - "json" to MsgElementMaker::createJsonElem, - "new_dice" to MsgElementMaker::createNewDiceElem, - "new_rps" to MsgElementMaker::createNewRpsElem, - "basketball" to MsgElementMaker::createBasketballElem, + "text" to NtMsgElementMaker::createTextElem, + "face" to NtMsgElementMaker::createFaceElem, + "pic" to NtMsgElementMaker::createImageElem, + "image" to NtMsgElementMaker::createImageElem, + "voice" to NtMsgElementMaker::createRecordElem, + "record" to NtMsgElementMaker::createRecordElem, + "at" to NtMsgElementMaker::createAtElem, + "video" to NtMsgElementMaker::createVideoElem, + "markdown" to NtMsgElementMaker::createMarkdownElem, + "dice" to NtMsgElementMaker::createDiceElem, + "rps" to NtMsgElementMaker::createRpsElem, + "poke" to NtMsgElementMaker::createPokeElem, + "anonymous" to NtMsgElementMaker::createAnonymousElem, + "share" to NtMsgElementMaker::createShareElem, + "contact" to NtMsgElementMaker::createContactElem, + "location" to NtMsgElementMaker::createLocationElem, + "music" to NtMsgElementMaker::createMusicElem, + "reply" to NtMsgElementMaker::createReplyElem, + "touch" to NtMsgElementMaker::createTouchElem, + "weather" to NtMsgElementMaker::createWeatherElem, + "json" to NtMsgElementMaker::createJsonElem, + "new_dice" to NtMsgElementMaker::createNewDiceElem, + "new_rps" to NtMsgElementMaker::createNewRpsElem, + "basketball" to NtMsgElementMaker::createBasketballElem, //"node" to MessageMaker::createNodeElem, //"multi_msg" to MessageMaker::createLongMsgStruct, - "bubble_face" to MsgElementMaker::createBubbleFaceElem, - "button" to MsgElementMaker::createInlineKeywordElem, - "inline_keyboard" to MsgElementMaker::createInlineKeywordElem + "bubble_face" to NtMsgElementMaker::createBubbleFaceElem, + "button" to NtMsgElementMaker::createInlineKeywordElem, + "inline_keyboard" to NtMsgElementMaker::createInlineKeywordElem ) operator fun get(type: String): IMsgElementMaker? = makerMap[type] @@ -1006,6 +1007,10 @@ internal object MsgElementMaker { pic.picSubType = data["subType"].asIntOrNull ?: 0 pic.isFlashPic = isFlash + //if (PlatformUtils.getQQVersionCode() >= PlatformUtils.QQ_9_0_8_VER && !ShamrockConfig.enableOldBDH()) { + // pic.storeID = 1 + //} + elem.picElement = pic return Result.success(elem) diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/Contact.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/Contact.kt index 608d29de..83fbf97f 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/Contact.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/Contact.kt @@ -1,5 +1,7 @@ package moe.fuqiuluo.qqinterface.servlet.transfile +import com.tencent.mobileqq.data.MessageRecord + internal enum class ContactType { TROOP, PRIVATE, @@ -8,12 +10,20 @@ internal enum class ContactType { internal interface TransTarget { val id: String val type: ContactType + + val mRec: MessageRecord? } -internal class Troop(override val id: String): TransTarget { +internal class Troop( + override val id: String, + override val mRec: MessageRecord? = null +): TransTarget { override val type: ContactType = ContactType.TROOP } -internal class Private(override val id: String): TransTarget { +internal class Private( + override val id: String, + override val mRec: MessageRecord? = null +): TransTarget { override val type: ContactType = ContactType.PRIVATE } diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/FileTransfer.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/FileTransfer.kt index 4828de3a..ecda50b2 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/FileTransfer.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/FileTransfer.kt @@ -2,15 +2,18 @@ package moe.fuqiuluo.qqinterface.servlet.transfile +import com.tencent.mobileqq.transfile.BaseTransProcessor import com.tencent.mobileqq.transfile.FileMsg import com.tencent.mobileqq.transfile.TransferRequest import com.tencent.mobileqq.transfile.api.ITransFileController +import com.tencent.mobileqq.utils.httputils.IHttpCommunicatorListener import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeoutOrNull +import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.utils.MD5 import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher import mqq.app.AppRuntime @@ -81,6 +84,7 @@ internal abstract class FileTransfer { } suspendCancellableCoroutine { continuation -> GlobalScope.launch { + lateinit var processor: IHttpCommunicatorListener while ( //service.findProcessor( // transferRequest.keyForTransfer // uin + uniseq @@ -89,8 +93,13 @@ internal abstract class FileTransfer { // 如果上传处理器依旧存在,说明没有上传成功 && service.isWorking.get() ) { + processor = service.findProcessor(runtime.currentAccountUin, transferRequest.mUniseq) delay(100) } + if (processor is BaseTransProcessor && processor.file != null) { + val fileMsg = processor.file + LogCenter.log("[OldBDH] 资源上传结束(fileId = ${fileMsg.fileID}, fileKey = ${fileMsg.fileKey}, path = ${fileMsg.filePath})") + } continuation.resume(true) } // 实现取消上传器 diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/NtV2RichMediaSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/NtV2RichMediaSvc.kt new file mode 100644 index 00000000..3807bde8 --- /dev/null +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/NtV2RichMediaSvc.kt @@ -0,0 +1,224 @@ +package moe.fuqiuluo.qqinterface.servlet.transfile + +import kotlinx.atomicfu.atomic +import kotlinx.serialization.protobuf.ProtoNumber +import moe.fuqiuluo.qqinterface.servlet.BaseSvc +import moe.fuqiuluo.qqinterface.servlet.TicketSvc +import moe.fuqiuluo.shamrock.helper.LogCenter +import moe.fuqiuluo.shamrock.tools.hex2ByteArray +import moe.fuqiuluo.shamrock.tools.slice +import moe.fuqiuluo.symbols.decodeProtobuf +import protobuf.auto.toByteArray +import protobuf.oidb.TrpcOidb +import protobuf.oidb.cmd0x11c5.ClientMeta +import protobuf.oidb.cmd0x11c5.CodecConfigReq +import protobuf.oidb.cmd0x11c5.CommonHead +import protobuf.oidb.cmd0x11c5.DownloadExt +import protobuf.oidb.cmd0x11c5.DownloadReq +import protobuf.oidb.cmd0x11c5.FileInfo +import protobuf.oidb.cmd0x11c5.FileType +import protobuf.oidb.cmd0x11c5.IndexNode +import protobuf.oidb.cmd0x11c5.MultiMediaReqHead +import protobuf.oidb.cmd0x11c5.NtV2RichMediaReq +import protobuf.oidb.cmd0x11c5.NtV2RichMediaRsp +import protobuf.oidb.cmd0x11c5.SceneInfo +import protobuf.oidb.cmd0x11c5.UploadInfo +import protobuf.oidb.cmd0x11c5.UploadReq +import protobuf.oidb.cmd0x11c5.VideoDownloadExt +import protobuf.oidb.cmd0x388.Cmd0x388ReqBody +import protobuf.oidb.cmd0x388.Cmd0x388RspBody +import protobuf.oidb.cmd0x388.TryUpImgReq +import java.io.File +import kotlin.random.Random +import kotlin.random.nextUInt +import kotlin.random.nextULong + +internal object NtV2RichMediaSvc: BaseSvc() { + private val requestIdSeq = atomic(2L) + + /** + * 获取NT图片的RKEY + */ + suspend fun getNtPicRKey( + fileId: String, + md5: String, + sha: String, + fileSize: ULong, + width: UInt, + height: UInt, + sceneBuilder: suspend SceneInfo.() -> Unit + ): Result { + runCatching { + val req = NtV2RichMediaReq( + head = MultiMediaReqHead( + commonHead = CommonHead( + requestId = requestIdSeq.incrementAndGet().toULong(), + cmd = 200u + ), + sceneInfo = SceneInfo( + requestType = 2u, + businessType = 1u, + ).apply { + sceneBuilder() + }, + clientMeta = ClientMeta(2u) + ), + download = DownloadReq( + IndexNode( + FileInfo( + fileSize = fileSize, + md5 = md5.lowercase(), + sha1 = sha.lowercase(), + name = "${md5}.jpg", + fileType = FileType( + fileType = 1u, + picFormat = 1000u, + videoFormat = 0u, + voiceFormat = 0u + ), + width = width, + height = height, + time = 0u, + original = 1u + ), + fileUuid = fileId, + storeId = 1u, + uploadTime = 0u, + ttl = 0u, + subType = 0u, + storeAppId = 0u + ), + DownloadExt( + video = VideoDownloadExt( + busiType = 0u, + subBusiType = 0u, + msgCodecConfig = CodecConfigReq( + platformChipinfo = "", + osVer = "", + deviceName = "" + ), + flag = 1u + ) + ) + ) + ).toByteArray() + val buffer = sendOidbAW("OidbSvcTrpcTcp.0x11c5_200", 4549, 200, req, true)?.slice(4) + buffer?.decodeProtobuf()?.buffer?.decodeProtobuf()?.download?.rkeyParam?.let { + return Result.success(it) + } + }.onFailure { + return Result.failure(it) + } + return Result.failure(Exception("unable to get c2c nt pic")) + } + + /** + * 请求上传Nt图片 + */ + suspend fun requestUploadNtPic( + file: File, + md5: String, + sha: String, + name: String, + width: UInt, + height: UInt, + sceneBuilder: suspend SceneInfo.() -> Unit + ) { + val req = NtV2RichMediaReq( + head = MultiMediaReqHead( + commonHead = CommonHead( + requestId = requestIdSeq.incrementAndGet().toULong(), + cmd = 100u + ), + sceneInfo = SceneInfo( + requestType = 2u, + businessType = 1u, + ).apply { + sceneBuilder() + }, + clientMeta = ClientMeta(2u) + ), + upload = UploadReq( + listOf(UploadInfo( + FileInfo( + fileSize = file.length().toULong(), + md5 = md5, + sha1 = sha, + name = name, + fileType = FileType( + fileType = 1u, + picFormat = 1000u, + videoFormat = 0u, + voiceFormat = 0u + ), + width = width, + height = height, + time = 0u, + original = 1u + ), + subFileType = 0u + )), + tryFastUploadCompleted = true, + srvSendMsg = false, + clientRandomId = Random.nextULong(), + compatQMsgSceneType = 1u, + clientSeq = Random.nextUInt(), + noNeedCompatMsg = true + ) + ).toByteArray() + val buffer = sendOidbAW("OidbSvcTrpcTcp.0x11c5_100", 4549, 100, req, true)?.slice(4) + val rsp = buffer?.decodeProtobuf()?.buffer?.decodeProtobuf() + LogCenter.log("requestUploadPic => rsp: $rsp") + } + + suspend fun requestUploadGroupPic( + groupId: ULong, + md5: String, + fileSize: ULong, + width: UInt, + height: UInt, + ): Result { + return runCatching { + val rspBuffer = sendBufferAW("ImgStore.GroupPicUp", true, Cmd0x388ReqBody( + netType = 3, + subCmd = 1, + msgTryUpImg = arrayListOf( + TryUpImgReq( + groupCode = groupId.toLong(), + srcUin = TicketSvc.getLongUin(), + fileMd5 = md5.hex2ByteArray(), + fileSize = fileSize.toLong(), + fileName = "$md5.jpg", + srcTerm = 2, + platformType = 9, + buType = 212, + picWidth = width.toInt(), + picHeight = height.toInt(), + picType = 1000, + buildVer = "1.0.0", + originalPic = 1, + fileIndex = byteArrayOf(), + srvUpload = 0 + ) + ), + ).toByteArray())!! + val rsp = rspBuffer.decodeProtobuf() + .msgTryUpImgRsp!!.first() + TryUpPicData( + uKey = rsp.ukey, + exist = rsp.fileExist, + fileId = rsp.fileId.toULong(), + upIp = rsp.upIp, + upPort = rsp.upPort + ) + } + } + + data class TryUpPicData( + val uKey: ByteArray, + val exist: Boolean, + val fileId: ULong, + var upIp: ArrayList? = null, + var upPort: ArrayList? = null, + ) +} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/RichProtoSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/RichProtoSvc.kt index 18d789c7..834ae5ee 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/RichProtoSvc.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/RichProtoSvc.kt @@ -10,6 +10,7 @@ import kotlinx.atomicfu.atomic import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.serialization.ExperimentalSerializationApi import moe.fuqiuluo.qqinterface.servlet.BaseSvc +import moe.fuqiuluo.qqinterface.servlet.transfile.NtV2RichMediaSvc.getNtPicRKey import moe.fuqiuluo.shamrock.helper.ContactHelper import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.LogCenter @@ -53,8 +54,6 @@ private const val MULTIMEDIA_DOMAIN = "multimedia.nt.qq.com.cn" private const val C2C_PIC = "c2cpicdw.qpic.cn" internal object RichProtoSvc: BaseSvc() { - private val requestId = atomic(2L) - suspend fun getGuildFileDownUrl(peerId: String, channelId: String, fileId: String, bizId: Int): String { val buffer = sendOidbAW("OidbSvcTrpcTcp.0xfc2_0", 4034, 0, Oidb0xfc2ReqBody( msgCmd = 1200, @@ -279,81 +278,6 @@ internal object RichProtoSvc: BaseSvc() { return "https://$domain/qmeetpic/0/0-0-${md5.uppercase()}/0?term=2" } - suspend fun getNtPicRKey( - fileId: String, - md5: String, - sha: String, - fileSize: ULong, - width: UInt, - height: UInt, - sceneBuilder: suspend SceneInfo.() -> Unit - ): Result { - runCatching { - val req = run { - NtV2RichMediaReq( - head = MultiMediaReqHead( - commonHead = CommonHead( - requestId = requestId.incrementAndGet().toULong(), - cmd = 200u - ), - sceneInfo = SceneInfo( - requestType = 2u, - businessType = 1u, - ).apply { - sceneBuilder() - }, - clientMeta = ClientMeta(2u) - ), - download = DownloadReq( - IndexNode( - FileInfo( - fileSize = fileSize, - md5 = md5.lowercase(), - sha1 = sha.lowercase(), - name = "${md5}.jpg", - fileType = FileType( - fileType = 1u, - picFormat = 1000u, - videoFormat = 0u, - voiceFormat = 0u - ), - width = width, - height = height, - time = 0u, - original = 1u - ), - fileUuid = fileId, - storeId = 1u, - uploadTime = 0u, - ttl = 0u, - subType = 0u, - storeAppId = 0u - ), - DownloadExt( - video = VideoDownloadExt( - busiType = 0u, - subBusiType = 0u, - msgCodecConfig = CodecConfigReq( - platformChipinfo = "", - osVer = "", - deviceName = "" - ), - flag = 1u - ) - ) - ) - ) - }.toByteArray() - val buffer = sendOidbAW("OidbSvcTrpcTcp.0x11c5_200", 4549, 200, req, true)?.slice(4) - buffer?.decodeProtobuf()?.buffer?.decodeProtobuf()?.download?.rkeyParam?.let { - return Result.success(it) - } - }.onFailure { - return Result.failure(it) - } - return Result.failure(Exception("unable to get c2c nt pic")) - } - suspend fun getC2CVideoDownUrl( peerId: String, md5: ByteArray, diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/Transfer.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/Transfer.kt index 75efe8d9..bdb72252 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/Transfer.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/transfile/Transfer.kt @@ -1,6 +1,8 @@ package moe.fuqiuluo.qqinterface.servlet.transfile +import com.tencent.mobileqq.data.MessageForPic import com.tencent.mobileqq.data.MessageForShortVideo +import com.tencent.mobileqq.data.MessageRecord import com.tencent.mobileqq.transfile.FileMsg import com.tencent.mobileqq.transfile.TransferRequest import moe.fuqiuluo.shamrock.utils.MD5 @@ -11,16 +13,15 @@ import moe.fuqiuluo.shamrock.helper.TransfileHelper internal object Transfer: FileTransfer() { private val ROUTE = mapOf Boolean>>( ContactType.TROOP to mapOf( - Picture to { uploadGroupPic(id, (it as PictureResource).src) }, + Picture to { uploadGroupPic(id, (it as PictureResource).src, mRec) }, Voice to { uploadGroupVoice(id, (it as VoiceResource).src) }, Video to { uploadGroupVideo(id, (it as VideoResource).src, it.thumb) }, ), ContactType.PRIVATE to mapOf( - Picture to { uploadC2CPic(id, (it as PictureResource).src) }, + Picture to { uploadC2CPic(id, (it as PictureResource).src, mRec) }, Voice to { uploadC2CVoice(id, (it as VoiceResource).src) }, Video to { uploadC2CVideo(id, (it as VideoResource).src, it.thumb) }, - ) ) @@ -83,6 +84,7 @@ internal object Transfer: FileTransfer() { suspend fun uploadC2CPic( peerId: String, file: File, + record: MessageRecord? = null, wait: Boolean = true ): Boolean { return transC2CResource(peerId, file, FileMsg.TRANSFILE_TYPE_PIC, SEND_MSG_BUSINESS_TYPE_PIC_CAMERA, wait) { @@ -93,22 +95,24 @@ internal object Transfer: FileTransfer() { it.mExtraObj = picUpExtraInfo it.mIsPresend = true it.delayShowProgressTimeInMs = 2000 + it.mRec = record } } suspend fun uploadGroupPic( groupId: String, file: File, + record: MessageRecord? = null, wait: Boolean = true ): Boolean { return transTroopResource(groupId, file, FileMsg.TRANSFILE_TYPE_PIC, SEND_MSG_BUSINESS_TYPE_PIC_CAMERA, wait) { val picUpExtraInfo = TransferRequest.PicUpExtraInfo() - //picUpExtraInfo.mIsRaw = !TransfileHelper.isGifFile(file) picUpExtraInfo.mIsRaw = false picUpExtraInfo.mUinType = FileMsg.UIN_TROOP it.mPicSendSource = 8 it.delayShowProgressTimeInMs = 2000 it.mExtraObj = picUpExtraInfo + it.mRec = record } } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/helper/MessageHelper.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/helper/MessageHelper.kt index 6aba410d..4ae626c1 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/helper/MessageHelper.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/helper/MessageHelper.kt @@ -17,7 +17,7 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonObject import moe.fuqiuluo.qqinterface.servlet.MsgSvc import moe.fuqiuluo.qqinterface.servlet.msg.maker.MessageElementMaker -import moe.fuqiuluo.qqinterface.servlet.msg.maker.MsgElementMaker +import moe.fuqiuluo.qqinterface.servlet.msg.maker.NtMsgElementMaker import moe.fuqiuluo.shamrock.helper.db.MessageDB import moe.fuqiuluo.shamrock.helper.db.MessageMapping import moe.fuqiuluo.shamrock.remote.structures.SendMsgResult @@ -29,6 +29,7 @@ import moe.fuqiuluo.shamrock.tools.jsonArray import protobuf.message.Elem import kotlin.coroutines.resume import kotlin.math.abs +import kotlin.time.Duration.Companion.seconds internal object MessageHelper { suspend fun sendMessageWithoutMsgId( @@ -66,12 +67,15 @@ internal object MessageHelper { suspend fun resendMsg(contact: Contact, msgId: Long, retryCnt: Int, msgHashId: Int): Result { if (retryCnt < 0) return Result.failure(SendMsgException("消息发送超时次数过多")) val service = QRoute.api(IMsgService::class.java) - val result = withTimeoutOrNull(15000) { - if (suspendCancellableCoroutine { - service.resendMsg(contact, msgId) { result, _ -> - it.resume(result) - } - } != 0) { + val result = withTimeoutOrNull(15.seconds) { + val resendRet = suspendCancellableCoroutine { + service.resendMsg(contact, msgId) { result, _ -> + it.resume(result) + } + } + if (resendRet != 0 && + resendRet != 4 // 使用OldBDH 100%触发 + ) { resendMsg(contact, msgId, retryCnt - 1, msgHashId) } else { Result.success(SendMsgResult(msgHashId, msgId, System.currentTimeMillis())) @@ -294,7 +298,7 @@ internal object MessageHelper { var hasActionMsg = false messageList.forEach { val msg = it.jsonObject - val maker = MsgElementMaker[msg["type"].asString] + val maker = NtMsgElementMaker[msg["type"].asString] if (maker != null) { try { val data = msg["data"].asJsonObjectOrNull ?: EmptyJsonObject diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendGroupMessage.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendGroupMessage.kt index c8eb773c..05ba3eb3 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendGroupMessage.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendGroupMessage.kt @@ -15,13 +15,13 @@ internal object SendGroupMessage: IActionHandler() { return if (session.isString("message")) { val autoEscape = session.getBooleanOrDefault("auto_escape", false) val message = session.getString("message") - SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), message, autoEscape, echo = session.echo, retryCnt = retryCnt ?: 3, recallDuration = recallDuration) + SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), message, autoEscape, echo = session.echo, retryCnt = retryCnt ?: 5, recallDuration = recallDuration) } else if (session.isObject("message")) { val message = session.getObject("message") - SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), listOf( message ).jsonArray, session.echo, retryCnt = retryCnt ?: 3, recallDuration = recallDuration) + SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), listOf( message ).jsonArray, session.echo, retryCnt = retryCnt ?: 5, recallDuration = recallDuration) } else { val message = session.getArray("message") - SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), message, session.echo, retryCnt = retryCnt ?: 3, recallDuration = recallDuration) + SendMessage(MsgConstant.KCHATTYPEGROUP, groupId.toString(), message, session.echo, retryCnt = retryCnt ?: 5, recallDuration = recallDuration) } } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMessage.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMessage.kt index 9abd42c4..4c2c4367 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMessage.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMessage.kt @@ -55,13 +55,13 @@ internal object SendMessage: IActionHandler() { return if (session.isString("message")) { val autoEscape = session.getBooleanOrDefault("auto_escape", false) val message = session.getString("message") - invoke(chatType, peerId, message, autoEscape, echo = session.echo, fromId = fromId, retryCnt = retryCnt ?: 3, recallDuration = recallDuration) + invoke(chatType, peerId, message, autoEscape, echo = session.echo, fromId = fromId, retryCnt = retryCnt ?: 5, recallDuration = recallDuration) } else if (session.isArray("message")) { val message = session.getArray("message") - invoke(chatType, peerId, message, session.echo, fromId = fromId, retryCnt ?: 3, recallDuration = recallDuration) + invoke(chatType, peerId, message, session.echo, fromId = fromId, retryCnt ?: 5, recallDuration = recallDuration) } else { val message = session.getObject("message") - invoke(chatType, peerId, listOf( message ).jsonArray, session.echo, fromId = fromId, retryCnt ?: 3, recallDuration = recallDuration) + invoke(chatType, peerId, listOf( message ).jsonArray, session.echo, fromId = fromId, retryCnt ?: 5, recallDuration = recallDuration) } } catch (e: ParamsException) { return noParam(e.message!!, session.echo) diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMsgByResid.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMsgByResid.kt index 2c4b9682..5bec0a12 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMsgByResid.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMsgByResid.kt @@ -1,10 +1,12 @@ package moe.fuqiuluo.shamrock.remote.action.handlers import kotlinx.atomicfu.atomic +import kotlinx.serialization.json.JsonElement import moe.fuqiuluo.qqinterface.servlet.BaseSvc import moe.fuqiuluo.shamrock.remote.action.ActionSession import moe.fuqiuluo.shamrock.remote.action.IActionHandler +import moe.fuqiuluo.shamrock.tools.EmptyJsonString import moe.fuqiuluo.symbols.OneBotHandler import protobuf.auto.toByteArray import protobuf.message.* @@ -21,8 +23,13 @@ internal object SendMsgByResid : IActionHandler() { override suspend fun internalHandle(session: ActionSession): String { val resid = session.getString("resid") val peerId = session.getString("peer") + val msgType = session.getStringOrNull("message_type") ?: "group" + return invoke(peerId, resid, msgType, session.echo) + } + + suspend operator fun invoke(peerId: String, resId: String, type: String, echo: JsonElement = EmptyJsonString): String { val req = PbSendMsgReq( - routingHead = when (session.getStringOrNull("message_type")) { + routingHead = when (type) { "group" ->RoutingHead(grp = Grp(peerId.toUInt())) "private" ->RoutingHead( c2c = C2C(peerId.toUInt())) else ->RoutingHead( grp = Grp(peerId.toUInt())) @@ -34,7 +41,7 @@ internal object SendMsgByResid : IActionHandler() { Elem( generalFlags = GeneralFlags( longTextFlag = 1u, - longTextResid = resid.toByteArray() + longTextResid = resId.toByteArray() ) ) ) @@ -45,6 +52,6 @@ internal object SendMsgByResid : IActionHandler() { msgVia = 0u ) BaseSvc.sendBufferAW("MessageSvc.PbSendMsg", true, req.toByteArray()) - return ok("ok", session.echo) + return ok("ok", echo) } } \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendPrivateMessage.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendPrivateMessage.kt index 6696bfd7..98ad3eb2 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendPrivateMessage.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendPrivateMessage.kt @@ -24,7 +24,7 @@ internal object SendPrivateMessage : IActionHandler() { autoEscape = autoEscape, echo = session.echo, fromId = groupId?.toString() ?: userId.toString(), - retryCnt = retryCnt ?: 3, + retryCnt = retryCnt ?: 5, recallDuration = recallDuration ) } else { @@ -34,7 +34,7 @@ internal object SendPrivateMessage : IActionHandler() { message = if (session.isArray("message")) session.getArray("message") else listOf(session.getObject("message")).jsonArray, echo = session.echo, fromId = groupId?.toString() ?: userId.toString(), - retryCnt = retryCnt ?: 3, + retryCnt = retryCnt ?: 5, recallDuration = recallDuration ) } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/XposedEntry.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/XposedEntry.kt index abd45d26..6bd1b3c6 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/XposedEntry.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/XposedEntry.kt @@ -117,6 +117,8 @@ internal class XposedEntry: IXposedHookLoadPackage { } private fun execStartupInit(ctx: Context) { + log("Shamrock: Executing startup init: $ctx") + if (sec_static_stage_inited) return val classLoader = ctx.classLoader.also { requireNotNull(it) }