mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 05:12:17 +00:00
Compare commits
90 Commits
Author | SHA1 | Date | |
---|---|---|---|
5f0cf952e8 | |||
03d62c55c2 | |||
89154f0c49 | |||
5218c153f0 | |||
2b64aa8b2c | |||
67ef465f14 | |||
ea62640057 | |||
f67dfac4d9 | |||
1593d973a0 | |||
3e27c64e84 | |||
c87268df09 | |||
98c6316e23 | |||
2af8d6d817 | |||
b9c2de744e | |||
fcf18bd3fd | |||
8265f74ca3 | |||
2c49b10772 | |||
4266afd1a5 | |||
b9ef0ca8f5 | |||
040b132836 | |||
16f77de5a6 | |||
46c83f5cb9 | |||
ca71ecae09 | |||
58d93b8f56 | |||
472b17f744 | |||
8a4212ffd7 | |||
bd28b0f7f7 | |||
f2dc3bc9fd | |||
ba8322dc55 | |||
cf445d17d9 | |||
e6e03ee328 | |||
497df6b649 | |||
f87fd3887a | |||
71a462e48f | |||
93cb6fc46b | |||
8fdea083b0 | |||
1620e18bf4 | |||
2f264ee9e4 | |||
19e3846e40 | |||
6b4f763a90 | |||
d5378d8acb | |||
ca62b33275 | |||
e09b68576a | |||
80bb591a1b | |||
08bce05c66 | |||
0fb2eeb2d8 | |||
3cf2474938 | |||
ce1e850c78 | |||
5200a4d8d4 | |||
0a41429d71 | |||
bc967cf926 | |||
d28c6dc820 | |||
10d25167e8 | |||
346798dc9a | |||
7584390408 | |||
3988ad3811 | |||
72600364ff | |||
68977e4a86 | |||
92b3d4f94e | |||
852eb0d87b | |||
c8143bcf67 | |||
75dc5c0294 | |||
21341caf62 | |||
ee9cf694a0 | |||
d347bd0a41 | |||
e5cca58198 | |||
259de3d3aa | |||
c30e3db1a1 | |||
fb5718dc61 | |||
6043c21de5 | |||
c3c14d6ead | |||
41675ed874 | |||
dc2503b045 | |||
b76ef7efb3 | |||
c67b49790f | |||
86b29b982c | |||
f17b4924c9 | |||
e162da7e7b | |||
6f1ba71664 | |||
16e0c9542e | |||
e41b7515d3 | |||
52b8db70be | |||
184064d199 | |||
ae1684a885 | |||
688041b6be | |||
4adf2eb84a | |||
3f8af384b0 | |||
79f2594a2f | |||
547f224140 | |||
94937a75a2 |
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: shamrock320 # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
BIN
AudioLibrary-x64.zip
Normal file
BIN
AudioLibrary-x64.zip
Normal file
Binary file not shown.
33
README.md
33
README.md
@ -22,6 +22,7 @@
|
||||
> 本项目目的是研究 Xposed 和 LSPosed 框架的使用。 Epic 框架开发相关知识。
|
||||
> 如有违反法律,请联系删除。
|
||||
> 请勿在任何平台宣传,宣扬,转发本项目,请勿恶意修改企业安装包造成相关企业产生损失,如有违背,必将追责到底。
|
||||
> 官方论坛,[点我直达](https://forum.libfekit.so/)!
|
||||
|
||||
## 兼容|迁移|替代 说明
|
||||
|
||||
@ -69,38 +70,38 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
[![][contrib-image]][contrib-link]
|
||||
|
||||
[banner]: https://socialify.git.ci/whitechi73/Shamrock/image?description=1&forks=1&issues=1&logo=https%3A%2F%2Fwhitechi73.github.io%2FShamrock%2Fshamrock.jpg&pattern=Plus&pulls=1&stargazers=1&theme=Auto
|
||||
[banner]: https://socialify.git.ci/whitechi73/OpenShamrock/image?description=1&forks=1&issues=1&logo=https%3A%2F%2Fwhitechi73.github.io%2FOpenShamrock%2Fshamrock.jpg&pattern=Plus&pulls=1&stargazers=1&theme=Auto
|
||||
|
||||
[actions]: https://img.shields.io/github/actions/workflow/status/whitechi73/Shamrock/build-apk.yml?style=for-the-badge
|
||||
[actions]: https://img.shields.io/github/actions/workflow/status/whitechi73/OpenShamrock/build-apk.yml?style=for-the-badge
|
||||
|
||||
[actions-link]: https://github.com/whitechi73/Shamrock/actions/workflows/build-apk.yml
|
||||
[actions-link]: https://github.com/whitechi73/OpenShamrock/actions/workflows/build-apk.yml
|
||||
|
||||
[releases]: https://img.shields.io/github/v/release/whitechi73/Shamrock?style=for-the-badge
|
||||
[releases]: https://img.shields.io/github/v/release/whitechi73/OpenShamrock?style=for-the-badge
|
||||
|
||||
[releases-link]: https://github.com/whitechi73/Shamrock/releases
|
||||
[releases-link]: https://github.com/whitechi73/OpenShamrock/releases
|
||||
|
||||
[downloads]: https://img.shields.io/github/downloads/whitechi73/Shamrock/total?style=for-the-badge
|
||||
[downloads]: https://img.shields.io/github/downloads/whitechi73/OpenShamrock/total?style=for-the-badge
|
||||
|
||||
[license]: https://img.shields.io/github/license/whitechi73/Shamrock?style=for-the-badge
|
||||
[license]: https://img.shields.io/github/license/whitechi73/OpenShamrock?style=for-the-badge
|
||||
|
||||
[onebot-11]: https://img.shields.io/badge/OneBot-11-black?style=for-the-badge
|
||||
|
||||
[onebot-12]: https://img.shields.io/badge/OneBot-12-black?style=for-the-badge
|
||||
|
||||
[download-link]: https://whitechi73.github.io/Shamrock/guide/getting-started.html#%E4%B8%8B%E8%BD%BD
|
||||
[download-link]: https://whitechi73.github.io/OpenShamrock/guide/getting-started.html#%E4%B8%8B%E8%BD%BD
|
||||
|
||||
[deploy-link]: https://whitechi73.github.io/Shamrock/guide/getting-started.html#%E9%83%A8%E7%BD%B2
|
||||
[deploy-link]: https://whitechi73.github.io/OpenShamrock/guide/getting-started.html#%E9%83%A8%E7%BD%B2
|
||||
|
||||
[api-link]: https://whitechi73.github.io/Shamrock/api
|
||||
[api-link]: https://whitechi73.github.io/OpenShamrock/api
|
||||
|
||||
[docs-link]: https://whitechi73.github.io/Shamrock/
|
||||
[docs-link]: https://whitechi73.github.io/OpenShamrock/
|
||||
|
||||
[group-link]: https://whitechi73.github.io/Shamrock/group.html
|
||||
[group-link]: https://whitechi73.github.io/OpenShamrock/group.html
|
||||
|
||||
[hook-system]: https://github.com/whitechi73/Shamrock/wiki/perm_hook_android
|
||||
[hook-system]: https://github.com/whitechi73/OpenShamrock/wiki/perm_hook_android
|
||||
|
||||
[voice-support]: https://whitechi73.github.io/Shamrock/advanced/voice.html
|
||||
[voice-support]: https://whitechi73.github.io/OpenShamrock/advanced/voice.html
|
||||
|
||||
[contrib-image]: https://contrib.rocks/image?repo=whitechi73/Shamrock
|
||||
[contrib-image]: https://contrib.rocks/image?repo=whitechi73/OpenShamrock
|
||||
|
||||
[contrib-link]: https://github.com/whitechi73/Shamrock/graphs/contributors
|
||||
[contrib-link]: https://github.com/whitechi73/OpenShamrock/graphs/contributors
|
||||
|
@ -24,7 +24,7 @@ android {
|
||||
minSdk = 24
|
||||
targetSdk = 33
|
||||
versionCode = (System.currentTimeMillis() / 1000).toInt()
|
||||
versionName = "1.0.5-dev" + gitCommitHash()
|
||||
versionName = "1.0.6-dev" + gitCommitHash()
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
@ -66,6 +66,7 @@ android {
|
||||
create("app") {
|
||||
dimension = "mode"
|
||||
ndk {
|
||||
println("Full architecture and full compilation.")
|
||||
abiFilters.add("arm64-v8a")
|
||||
abiFilters.add("x86_64")
|
||||
}
|
||||
@ -73,12 +74,14 @@ android {
|
||||
create("arm64") {
|
||||
dimension = "mode"
|
||||
ndk {
|
||||
println("Full compilation of arm64 architecture")
|
||||
abiFilters.add("arm64-v8a")
|
||||
}
|
||||
}
|
||||
create("x64") {
|
||||
dimension = "mode"
|
||||
ndk {
|
||||
println("Full compilation of x64 architecture")
|
||||
abiFilters.add("x86_64")
|
||||
}
|
||||
}
|
||||
@ -173,24 +176,19 @@ dependencies {
|
||||
implementation("io.coil-kt:coil:2.4.0")
|
||||
implementation("io.coil-kt:coil-compose:2.4.0")
|
||||
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.1.16")
|
||||
implementation("io.ktor:ktor-server-core:2.3.3")
|
||||
implementation("io.ktor:ktor-server-host-common:2.3.3")
|
||||
implementation("io.ktor:ktor-server-status-pages:2.3.3")
|
||||
implementation("io.ktor:ktor-server-netty:2.3.3")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.3")
|
||||
implementation("io.ktor:ktor-server-content-negotiation:2.3.3")
|
||||
implementation("io.ktor:ktor-client-core:2.3.3")
|
||||
implementation("io.ktor:ktor-client-cio:2.3.3")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:2.3.3")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.3")
|
||||
// useless
|
||||
//implementation ("com.maxkeppeler.sheets-compose-dialogs:core:1.2.0")
|
||||
//implementation ("com.maxkeppeler.sheets-compose-dialogs:info:1.2.0")
|
||||
//implementation ("com.maxkeppeler.sheets-compose-dialogs:input:1.2.0")
|
||||
//implementation ("com.maxkeppeler.sheets-compose-dialogs:list:1.2.0")
|
||||
//implementation ("com.maxkeppeler.sheets-compose-dialogs:state:1.2.0")
|
||||
|
||||
val ktorVersion = "2.3.3"
|
||||
implementation("io.ktor:ktor-server-core:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-host-common:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-status-pages:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-netty:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-core:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-cio:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
|
||||
//implementation("io.ktor:ktor-serialization-kotlinx-protobuf:$ktorVersion")
|
||||
|
||||
implementation(project(":xposed"))
|
||||
|
||||
|
@ -61,8 +61,8 @@ const std::byte MD5::PADDING[64] = { (byte) 0x80 };
|
||||
const char MD5::HEX[16] = {
|
||||
'0', '1', '2', '3',
|
||||
'4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b',
|
||||
'c', 'd', 'e', 'f'
|
||||
'8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
|
||||
|
@ -239,11 +239,21 @@ object ShamrockConfig {
|
||||
return preferences.getBoolean("enable_auto_start", false)
|
||||
}
|
||||
|
||||
fun allowShell(ctx: Context): Boolean {
|
||||
val preferences = ctx.getSharedPreferences("config", 0)
|
||||
return preferences.getBoolean("shell", false)
|
||||
}
|
||||
|
||||
fun setAutoStart(ctx: Context, v: Boolean) {
|
||||
val preferences = ctx.getSharedPreferences("config", 0)
|
||||
preferences.edit().putBoolean("enable_auto_start", v).apply()
|
||||
}
|
||||
|
||||
fun setShellStatus(ctx: Context, v: Boolean) {
|
||||
val preferences = ctx.getSharedPreferences("config", 0)
|
||||
preferences.edit().putBoolean("shell", v).apply()
|
||||
}
|
||||
|
||||
fun enableSelfMsg(ctx: Context): Boolean {
|
||||
val preferences = ctx.getSharedPreferences("config", 0)
|
||||
return preferences.getBoolean("enable_self_msg", false)
|
||||
@ -288,6 +298,7 @@ object ShamrockConfig {
|
||||
"key_store" to preferences.getString("key_store", ""),
|
||||
"enable_self_msg" to preferences.getBoolean("enable_self_msg", false),
|
||||
"echo_number" to preferences.getBoolean("echo_number", false),
|
||||
"shell" to preferences.getBoolean("shell", false),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -257,10 +257,10 @@ private fun APIInfoCard(
|
||||
hint = "请输入被动地址",
|
||||
error = "输入的地址不合法",
|
||||
checker = {
|
||||
it.isNotBlank()
|
||||
true
|
||||
},
|
||||
confirm = {
|
||||
if (it.startsWith("ws://") || it.startsWith("wss://")) {
|
||||
if (it.startsWith("ws://") || it.startsWith("wss://") || it.isBlank()) {
|
||||
ShamrockConfig.setWsAddr(ctx, wsAddress.value)
|
||||
AppRuntime.log("设置被动WebSocket地址为[${wsAddress.value}]。")
|
||||
} else {
|
||||
|
@ -100,7 +100,7 @@ fun LabFragment() {
|
||||
|
||||
Function(
|
||||
title = "自动清理QQ垃圾",
|
||||
desc = "也许会导致奇怪的问题。",
|
||||
desc = "也许会导致奇怪的问题(无效)。",
|
||||
descColor = it,
|
||||
isSwitch = ShamrockConfig.isAutoClean(ctx)
|
||||
) {
|
||||
@ -110,8 +110,8 @@ fun LabFragment() {
|
||||
}
|
||||
|
||||
Function(
|
||||
title = "拦截QQ无用发包",
|
||||
desc = "测试阶段,可能导致网络异常。",
|
||||
title = "拦截QQ无用收包",
|
||||
desc = "测试阶段,可能导致网络异常或掉线。",
|
||||
descColor = it,
|
||||
isSwitch = ShamrockConfig.isInjectPacket(ctx)
|
||||
) {
|
||||
@ -129,6 +129,16 @@ fun LabFragment() {
|
||||
ShamrockConfig.setAutoStart(ctx, it)
|
||||
return@Function true
|
||||
}
|
||||
|
||||
Function(
|
||||
title = "开启Shell接口",
|
||||
desc = "可能导致设备被入侵,请勿随意开启。",
|
||||
descColor = it,
|
||||
isSwitch = ShamrockConfig.allowShell(ctx)
|
||||
) {
|
||||
ShamrockConfig.setShellStatus(ctx, it)
|
||||
return@Function true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -180,6 +190,7 @@ fun LabFragment() {
|
||||
return@Function true
|
||||
}
|
||||
|
||||
/*
|
||||
Function(
|
||||
title = "使用纯数字ECHO",
|
||||
desc = "在部分强类型语言框架,需要打开此开关。",
|
||||
@ -189,7 +200,7 @@ fun LabFragment() {
|
||||
ShamrockConfig.setEchoNumber(ctx, it)
|
||||
ShamrockConfig.pushUpdate(ctx)
|
||||
return@Function true
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ android {
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
@ -36,7 +35,4 @@ dependencies {
|
||||
implementation("androidx.core:core-ktx:1.9.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.9.0")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
}
|
@ -1,6 +1,50 @@
|
||||
package com.tencent.mobileqq.pb;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class MessageMicro<T extends MessageMicro<T>> {
|
||||
public static final class FieldMap {
|
||||
private Object[] defaultValues;
|
||||
private Field[] fields;
|
||||
private int[] tags;
|
||||
|
||||
FieldMap(int[] iArr, String[] strArr, Object[] objArr, Class<?> cls) {
|
||||
this.tags = iArr;
|
||||
this.defaultValues = objArr;
|
||||
this.fields = new Field[iArr.length];
|
||||
for (int i2 = 0; i2 < iArr.length; i2++) {
|
||||
try {
|
||||
this.fields[i2] = cls.getField(strArr[i2]);
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear(MessageMicro<?> messageMicro) {
|
||||
}
|
||||
|
||||
<U extends MessageMicro<U>> void copyFields(U u, U u2) {
|
||||
}
|
||||
|
||||
Field get(int i2) {
|
||||
int binarySearch = Arrays.binarySearch(this.tags, i2);
|
||||
if (binarySearch < 0) {
|
||||
return null;
|
||||
}
|
||||
return this.fields[binarySearch];
|
||||
}
|
||||
|
||||
int getSerializedSize(MessageMicro<?> messageMicro) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static FieldMap initFieldMap(int[] iArr, String[] strArr, Object[] objArr, Class<?> cls) {
|
||||
return new FieldMap(iArr, strArr, objArr, cls);
|
||||
}
|
||||
|
||||
public final T mergeFrom(byte[] bArr) {
|
||||
return null;
|
||||
}
|
||||
|
@ -0,0 +1,186 @@
|
||||
package com.tencent.mobileqq.relation.api;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
import com.tencent.common.app.AppInterface;
|
||||
import com.tencent.mobileqq.data.MessageRecord;
|
||||
import com.tencent.mobileqq.data.PhoneContact;
|
||||
import com.tencent.mobileqq.qroute.QRouteApi;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import tencent.mobileim.structmsg.*;
|
||||
|
||||
public interface IAddFriendTempApi extends QRouteApi {
|
||||
public static final int ENTER_FROM_CONTACT_TAB = 1;
|
||||
|
||||
public static final int ENTER_FROM_DEFAULT = 0;
|
||||
|
||||
public static final int ENTER_FROM_MESSAGE_TAB = 2;
|
||||
|
||||
public static final int ENTER_FROM_NEW_FRIEND = 3;
|
||||
|
||||
public static final int ENTER_FROM_NEW_FRIEND_MORE = 4;
|
||||
|
||||
// void addBatchQIMFriends(List<QIMNotifyAddFriend> paramList, AppInterface paramAppInterface);
|
||||
|
||||
void addFriendToFriendList(AppInterface paramAppInterface, String paramString1, int paramInt1, int paramInt2, String paramString2, boolean paramBoolean1, boolean paramBoolean2, long paramLong);
|
||||
|
||||
void addListener(Object paramObject, AppInterface paramAppInterface);
|
||||
|
||||
void cancelMayKnowRecommend(String paramString, AppInterface paramAppInterface);
|
||||
|
||||
// void changeStructMsgActions(structmsg.StructMsg paramStructMsg, int paramInt1, String paramString, int paramInt2);
|
||||
|
||||
// boolean changeStructMsgActionsWhenFail(structmsg.StructMsg paramStructMsg, int paramInt, String paramString1, String paramString2);
|
||||
|
||||
void checkReadContactPermission(Runnable paramRunnable, AppInterface paramAppInterface);
|
||||
|
||||
void checkUpdate(AppInterface paramAppInterface, String paramString);
|
||||
|
||||
void clearAllSystemMsg(AppInterface paramAppInterface);
|
||||
|
||||
void clickQIMSource(Context paramContext, MessageRecord paramMessageRecord, AppInterface paramAppInterface);
|
||||
|
||||
Intent composeReturnIntent(Class<?> paramClass, String paramString, Activity paramActivity);
|
||||
|
||||
void deleteAllSuspiciousMsg(AppInterface paramAppInterface);
|
||||
|
||||
// void deleteQIMNotifyAddFriendData(QIMNotifyAddFriend paramQIMNotifyAddFriend, AppInterface paramAppInterface);
|
||||
|
||||
boolean enableCheckPermission();
|
||||
|
||||
void followUser(String paramString, boolean paramBoolean);
|
||||
|
||||
Intent getAddRequestIntent(Context paramContext);
|
||||
|
||||
Intent getBindNumberIntent(Context paramContext);
|
||||
|
||||
Intent getChatActivityIntent(Context paramContext);
|
||||
|
||||
// ArrayList<MayKnowRecommend> getConnectionsPersonLocal(int paramInt, AppInterface paramAppInterface);
|
||||
|
||||
void getConnectionsPersonRemoteNextPage(int paramInt, AppInterface paramAppInterface);
|
||||
|
||||
// ArrayList<a> getConnectionsTabInfoListLocal(AppInterface paramAppInterface);
|
||||
|
||||
void getDiscussInfo(long paramLong, AppInterface paramAppInterface);
|
||||
|
||||
String getDiscussionNameCanNull(AppInterface paramAppInterface, String paramString);
|
||||
|
||||
int getForwardSelectionRequest();
|
||||
|
||||
Intent getFriendProfileMoreInfoIntent(Context paramContext);
|
||||
|
||||
int getMayKnowLoadConnectionBizTypeFirstLoad();
|
||||
|
||||
int getMayKnowPersonNum(AppInterface paramAppInterface);
|
||||
|
||||
boolean getMayKnowRecommendRemoteFromNewFrd(AppInterface paramAppInterface);
|
||||
|
||||
String getQIMNewFriendSource(AppInterface paramAppInterface);
|
||||
|
||||
// ArrayList<s> getQIMNotifyAddFriendsMsg(boolean paramBoolean, AppInterface paramAppInterface);
|
||||
|
||||
String getQQInfoFromQQUin(long paramLong1, long paramLong2, AppInterface paramAppInterface);
|
||||
|
||||
HashMap<String, String> getQidianExternal(HashMap<String, Object> paramHashMap);
|
||||
|
||||
// String getRecommendLabelString(List<MayKnowRecommend.MayKnowRecommendLabel> paramList);
|
||||
|
||||
int getRequestForSetting();
|
||||
|
||||
int getSizeSmall();
|
||||
|
||||
void getSuspiciousFriendsUnreadNum(AppInterface paramAppInterface);
|
||||
|
||||
int getTypeSetConnectionsSwitch();
|
||||
|
||||
Object getValue(String paramString1, String paramString2, int paramInt1, int paramInt2);
|
||||
|
||||
void gotoFriendSettingBrowser(Context paramContext);
|
||||
|
||||
boolean hasQidianExternal(HashMap<String, Object> paramHashMap);
|
||||
|
||||
boolean hasQimSource(AppInterface paramAppInterface);
|
||||
|
||||
void insertCommonHobbyIfNeeded(AppInterface paramAppInterface, String paramString);
|
||||
|
||||
boolean isMayKnowConnectionsUserClosed(AppInterface paramAppInterface);
|
||||
|
||||
boolean isNewFrdMiniCardSwitchOn(AppInterface paramAppInterface);
|
||||
|
||||
boolean isPhoneContactEnabled(AppInterface paramAppInterface);
|
||||
|
||||
boolean isQidianMaster(AppInterface paramAppInterface, String paramString);
|
||||
|
||||
boolean isStudyMode(AppInterface paramAppInterface);
|
||||
|
||||
boolean isSuspiciousSwitchOpen();
|
||||
|
||||
// void jumpToMoveGroup(Activity paramActivity, QBaseFragment paramQBaseFragment, String paramString, int paramInt1, int paramInt2);
|
||||
|
||||
void jumpToNewFriendMoreSysMsgSuspiciousFragment(Context paramContext);
|
||||
|
||||
void jumpToNewFriendMoreSysMsgSuspiciousFragment(Context paramContext, Intent paramIntent, int paramInt);
|
||||
|
||||
void jumpToQidianProfile(String paramString, Activity paramActivity);
|
||||
|
||||
void jumpToSplash(Activity paramActivity);
|
||||
|
||||
void launchPluginBroadcastWhenToggleSwitch(String paramString, AppInterface paramAppInterface, boolean paramBoolean);
|
||||
|
||||
void loadConnectionsTabData(AppInterface paramAppInterface, int paramInt1, int paramInt2);
|
||||
|
||||
void markQIMNotifyAddFriendsRead(AppInterface paramAppInterface);
|
||||
|
||||
// void openSecCheckWebForFragment(AppInterface paramAppInterface, Context paramContext, QBaseFragment paramQBaseFragment, int paramInt, String paramString1, String paramString2);
|
||||
|
||||
// void recordStartExpose(MayKnowRecommend paramMayKnowRecommend, int paramInt1, int paramInt2, int paramInt3, AppInterface paramAppInterface);
|
||||
|
||||
// void recordStopExpose(MayKnowRecommend paramMayKnowRecommend, int paramInt1, int paramInt2, int paramInt3, AppInterface paramAppInterface);
|
||||
|
||||
void removeListener(Object paramObject, AppInterface paramAppInterface);
|
||||
|
||||
void reportExtendFriend(int paramInt, String paramString, Intent paramIntent);
|
||||
|
||||
void reportRecommend(AppInterface paramAppInterface, String paramString1, String paramString2, int paramInt1, int paramInt2, String paramString3, int paramInt3, byte[] paramArrayOfbyte, String paramString4, int paramInt4);
|
||||
|
||||
void reportRecommendExpose(AppInterface paramAppInterface, int paramInt1, ArrayList<String> paramArrayList1, ArrayList<String> paramArrayList2, ArrayList<Integer> paramArrayList, ArrayList<byte[]> paramArrayList3, int paramInt2);
|
||||
|
||||
void sendAddFriendNoticeForBaby(AppInterface paramAppInterface, Intent paramIntent);
|
||||
|
||||
// void sendDelSingleSystemMsg(structmsg.StructMsg paramStructMsg, String paramString, int paramInt, long paramLong, AppInterface paramAppInterface);
|
||||
|
||||
void sendFriendSystemMsgAction(int msg_type, long msg_seq, long req_uin, int sub_type, int src_id, int sub_src_id, int group_msg_type, structmsg$SystemMsgActionInfo action_info, int system_msg_action_type, structmsg$StructMsg paramStructMsg, boolean isUncommonlyUsedFrd, AppInterface paramAppInterface);
|
||||
|
||||
void sendFriendSystemMsgReadedReport(AppInterface paramAppInterface);
|
||||
|
||||
void sendGetNextFriendSystemMsg(AppInterface paramAppInterface);
|
||||
|
||||
void sendPokeMsg(AppInterface paramAppInterface, Context paramContext, String paramString);
|
||||
|
||||
void setConnectionsSwitch(boolean paramBoolean, AppInterface paramAppInterface);
|
||||
|
||||
boolean shouldShowMayKnowInNewFriend(AppInterface paramAppInterface);
|
||||
|
||||
// void startAddContactsPage(Context paramContext, int paramInt1, int paramInt2, LaunchMode paramLaunchMode, @Nullable Bundle paramBundle);
|
||||
|
||||
void startAddContactsPageForResult(Activity paramActivity, int paramInt1, int paramInt2, int paramInt3);
|
||||
|
||||
void startAddRequestPage(Context paramContext, Intent paramIntent);
|
||||
|
||||
void startAddRequestPageForResult(Activity paramActivity, Intent paramIntent, int paramInt);
|
||||
|
||||
void startAddRequestSuspiciousPage(Context paramContext, Intent paramIntent);
|
||||
|
||||
void startContactBindFromOther(AppInterface paramAppInterface, int paramInt1, int paramInt2, Intent paramIntent);
|
||||
|
||||
void startContactBindFromOther(AppInterface paramAppInterface, int paramInt, ArrayList<PhoneContact> paramArrayList);
|
||||
|
||||
void startRemarkAfterAgree(Activity paramActivity, int paramInt, String paramString, long paramLong, Bundle paramBundle);
|
||||
|
||||
void updateCustomNoteTxt(TextView paramTextView, int paramInt1, int paramInt2);
|
||||
}
|
@ -8,6 +8,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import mqq.app.AppRuntime;
|
||||
|
||||
public class BaseTransFileController implements ITransFileController {
|
||||
@Override
|
||||
public boolean containsProcessor(String name, long uin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IHttpCommunicatorListener findProcessor(String str) {
|
||||
return null;
|
||||
|
@ -14,7 +14,7 @@ public interface ITransFileController extends IRuntimeService {
|
||||
//@Deprecated
|
||||
//void addProcessor(String str, IHttpCommunicatorListener iHttpCommunicatorListener);
|
||||
|
||||
//boolean containsProcessor(String str, long j2);
|
||||
boolean containsProcessor(String name, long uin);
|
||||
|
||||
IHttpCommunicatorListener findProcessor(String str);
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
package com.tencent.mobileqq.troop.api;
|
||||
|
||||
import mqq.app.api.IRuntimeService;
|
||||
import com.tencent.mobileqq.data.troop.TroopMemberInfo;
|
||||
|
||||
public interface ITroopMemberNameService extends IRuntimeService {
|
||||
String getTroopMemberColorNick(String str, String str2);
|
||||
|
||||
String getTroopMemberName(TroopMemberInfo troopMemberInfo);
|
||||
|
||||
String getTroopMemberName(String str, String str2);
|
||||
|
||||
String getTroopMemberName(String str, String str2, String str3, String str4);
|
||||
|
||||
String getTroopMemberName(String str, String str2, boolean z, boolean z2);
|
||||
|
||||
//void getTroopMemberNameAsync(String str, String str2, a aVar);
|
||||
|
||||
String getTroopMemberNameInUI(String str, String str2);
|
||||
|
||||
String getTroopMemberNameRemarkFirst(String str, String str2);
|
||||
|
||||
String getTroopMemberNameWithoutRemark(String str, String str2);
|
||||
|
||||
String getTroopMemberNick(String str, String str2);
|
||||
|
||||
String getTroopMemberNickByTroopCode(String str, String str2);
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
package com.tencent.qqnt.kernel.api.impl;
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.IKernelMsgListener;
|
||||
import com.tencent.qqnt.kernel.nativeinterface.IOperateCallback;
|
||||
import com.tencent.qqnt.kernel.nativeinterface.RichMediaFilePathInfo;
|
||||
import com.tencent.qqnt.kernel.nativeinterface.TempChatPrepareInfo;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -18,4 +20,8 @@ public class MsgService {
|
||||
public String getRichMediaFilePathForMobileQQSend(@NotNull RichMediaFilePathInfo richMediaFilePathInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void prepareTempChat(TempChatPrepareInfo tempChatPrepareInfo, IOperateCallback cb) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,6 @@ public final class Contact implements IKernelModel, Serializable {
|
||||
|
||||
public Contact(int i2, String str, String str2) {
|
||||
this.serialVersionUID = 1L;
|
||||
this.peerUid = "";
|
||||
this.guildId = "";
|
||||
this.chatType = i2;
|
||||
this.peerUid = str;
|
||||
this.guildId = str2;
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
/* compiled from: P */
|
||||
/* loaded from: classes2.dex */
|
||||
public final class GroupFileCommonResult {
|
||||
String clientWording;
|
||||
int retCode;
|
||||
@ -29,8 +27,6 @@ public final class GroupFileCommonResult {
|
||||
}
|
||||
|
||||
public GroupFileCommonResult(int i2, String str, String str2) {
|
||||
this.retMsg = "";
|
||||
this.clientWording = "";
|
||||
this.retCode = i2;
|
||||
this.retMsg = str;
|
||||
this.clientWording = str2;
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
public interface IClearMsgRecordsCallback {
|
||||
void onResult(int code, String reason, long lastMsgId);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
public interface IDeleteGroupFileCallback {
|
||||
void onResult(int i2, String str, DeleteGroupFileResult deleteGroupFileResult);
|
||||
void onResult(int code, String why, DeleteGroupFileResult result);
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
@ -16,7 +18,25 @@ public interface IKernelMsgService {
|
||||
|
||||
void addLocalRecordMsg(Contact contact, long msgId, MsgElement elem, HashMap<Integer, MsgAttributeInfo> hashMap, boolean z, IOperateCallback callback);
|
||||
|
||||
void getMultiMsg(Contact contact, long msgId, long uniseq, IGetMultiMsgCallback cb);
|
||||
long getMsgUniqueId(long time);
|
||||
|
||||
void addSendMsg(long msgId, Contact contact, ArrayList<MsgElement> msgList, HashMap<Integer, MsgAttributeInfo> hashMap);
|
||||
|
||||
void getMsgs(@NotNull Contact contact, long startMsgId, int cnt, boolean queryOrder, @NotNull IMsgOperateCallback iMsgOperateCallback);
|
||||
|
||||
void getMsgsIncludeSelf(Contact contact, long startMsgId, int count, boolean queryOrder, IMsgOperateCallback iMsgOperateCallback);
|
||||
|
||||
void translatePtt2Text(long j2, Contact contact, MsgElement msgElement, IOperateCallback iOperateCallback);
|
||||
|
||||
void getMultiMsg(Contact contact, long rootMsgId, long parentMsgId, IGetMultiMsgCallback cb);
|
||||
|
||||
void multiForwardMsg(ArrayList<MultiMsgInfo> arrayList, Contact from, Contact to, IOperateCallback cb);
|
||||
|
||||
void setAllC2CAndGroupMsgRead(IOperateCallback cb);
|
||||
|
||||
void clearMsgRecords(Contact contact, IClearMsgRecordsCallback cb);
|
||||
|
||||
String createUidFromTinyId(long j2, long j3);
|
||||
|
||||
void switchBackGround(BackGroundInfo backGroundInfo, IOperateCallback cb);
|
||||
|
||||
|
@ -9,7 +9,7 @@ public interface IKernelRichMediaService {
|
||||
|
||||
void cancelTransferTask(Contact contact, ArrayList<Long> arrayList, ArrayList<Integer> arrayList2, IOperateTransferInfoCallback iOperateTransferInfoCallback);
|
||||
|
||||
void deleteGroupFile(long j2, String str, int i2, IDeleteGroupFileCallback iDeleteGroupFileCallback);
|
||||
void deleteGroupFile(long groupCode, String fileUid, int bizId, IDeleteGroupFileCallback cb);
|
||||
|
||||
void deleteTransferInfo(Contact contact, ArrayList<Long> arrayList, IOperateTransferInfoCallback iOperateTransferInfoCallback);
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
/* compiled from: P */
|
||||
/* loaded from: classes2.dex */
|
||||
public final class MultiMsgInfo {
|
||||
long msgId;
|
||||
String senderShowName;
|
||||
@ -21,8 +19,6 @@ public final class MultiMsgInfo {
|
||||
return "MultiMsgInfo{msgId=" + this.msgId + ",senderShowName=" + this.senderShowName + ",}";
|
||||
}
|
||||
|
||||
public MultiMsgInfo(long j2, String str) {
|
||||
this.msgId = j2;
|
||||
this.senderShowName = str;
|
||||
public MultiMsgInfo(long msgId, String showName) {
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.tencent.qqnt.kernel.nativeinterface;
|
||||
|
||||
/* compiled from: P */
|
||||
/* loaded from: classes.dex */
|
||||
public final class TempChatInfo {
|
||||
int chatType;
|
||||
String fromNick;
|
||||
|
@ -56,20 +56,14 @@ public final class TempChatPrepareInfo {
|
||||
return "TempChatPrepareInfo{chatType=" + this.chatType + ",peerUid=" + this.peerUid + ",peerNickname=" + this.peerNickname + ",fromGroupCode=" + this.fromGroupCode + ",sig=" + this.sig + ",selfUid=" + this.selfUid + ",selfPhone=" + this.selfPhone + ",gameSession=" + this.gameSession + ",}";
|
||||
}
|
||||
|
||||
public TempChatPrepareInfo(int i2, String str, String str2, String str3, byte[] bArr, String str4, String str5, TempChatGameSession tempChatGameSession) {
|
||||
this.peerUid = "";
|
||||
this.peerNickname = "";
|
||||
this.fromGroupCode = "";
|
||||
this.sig = new byte[0];
|
||||
this.selfUid = "";
|
||||
this.selfPhone = "";
|
||||
this.chatType = i2;
|
||||
this.peerUid = str;
|
||||
this.peerNickname = str2;
|
||||
this.fromGroupCode = str3;
|
||||
this.sig = bArr;
|
||||
this.selfUid = str4;
|
||||
this.selfPhone = str5;
|
||||
this.gameSession = tempChatGameSession;
|
||||
public TempChatPrepareInfo(int chatType, String peerId, String nickName, String fromGroup, byte[] sig, String selfUid, String selfPhone, TempChatGameSession session) {
|
||||
this.chatType = chatType;
|
||||
this.peerUid = peerId;
|
||||
this.peerNickname = nickName;
|
||||
this.fromGroupCode = fromGroup;
|
||||
this.sig = sig;
|
||||
this.selfUid = selfUid;
|
||||
this.selfPhone = selfPhone;
|
||||
this.gameSession = session;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.tencent.qphone.base.remote.SimpleAccount;
|
||||
import com.tencent.qphone.base.remote.ToServiceMsg;
|
||||
|
||||
import mqq.app.api.IRuntimeService;
|
||||
@ -72,6 +73,10 @@ public abstract class AppRuntime {
|
||||
public <T extends IRuntimeService> T getRuntimeServiceIPCSync(@NonNull Class<T> cls, String str) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void switchAccount(SimpleAccount simpleAccount, String process) {
|
||||
|
||||
}
|
||||
public String getAccount() {
|
||||
return "";
|
||||
}
|
||||
@ -81,6 +86,10 @@ public abstract class AppRuntime {
|
||||
return !"0".equals(getCurrentAccountUin()) ? getCurrentAccountUin() : "";
|
||||
}
|
||||
|
||||
public String getCurrentUid() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public long getLongAccountUin() {
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
package tencent.im.oidb.cmd0x899;
|
||||
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro;
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBBytesField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBRepeatField;
|
||||
import com.tencent.mobileqq.pb.PBRepeatMessageField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public class oidb_0x899 {
|
||||
public static class ReqBody extends MessageMicro<ReqBody> {
|
||||
//static final MessageMicro.FieldMap __fieldMap__ = MessageMicro.initFieldMap(new int[]{8, 16, 24, 32, 42, 48, 56, 64}, new String[]{
|
||||
// "uint64_group_code",
|
||||
// "uint64_start_uin",
|
||||
// "uint32_identify_flag",
|
||||
// "rpt_uint64_uin_list",
|
||||
// "memberlist_opt",
|
||||
// "uint32_member_num", "uint32_filter_method", "uint32_online_flag"}, new Object[]{0L, 0L, 0, 0L, null, 0, 0, 0}, ReqBody.class);
|
||||
public final PBUInt64Field uint64_group_code = PBField.initUInt64(0);
|
||||
public final PBUInt64Field uint64_start_uin = PBField.initUInt64(0);
|
||||
public final PBUInt32Field uint32_identify_flag = PBField.initUInt32(0);
|
||||
public final PBRepeatField<Long> rpt_uint64_uin_list = PBField.initRepeat(PBUInt64Field.__repeatHelper__);
|
||||
public memberlist memberlist_opt = new memberlist();
|
||||
public final PBUInt32Field uint32_member_num = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_filter_method = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_online_flag = PBField.initUInt32(0);
|
||||
}
|
||||
|
||||
public static class RspBody extends MessageMicro<RspBody> {
|
||||
static final MessageMicro.FieldMap __fieldMap__ = MessageMicro.initFieldMap(new int[]{8, 16, 24, 34, 42}, new String[]{"uint64_group_code", "uint64_start_uin", "uint32_identify_flag", "rpt_memberlist", "str_errorinfo"}, new Object[]{0L, 0L, 0, null, ByteStringMicro.EMPTY}, RspBody.class);
|
||||
public final PBUInt64Field uint64_group_code = PBField.initUInt64(0);
|
||||
public final PBUInt64Field uint64_start_uin = PBField.initUInt64(0);
|
||||
public final PBUInt32Field uint32_identify_flag = PBField.initUInt32(0);
|
||||
public final PBRepeatMessageField<memberlist> rpt_memberlist = PBField.initRepeatMessage(memberlist.class);
|
||||
public final PBBytesField str_errorinfo = PBField.initBytes(ByteStringMicro.EMPTY);
|
||||
}
|
||||
|
||||
public static class memberlist extends MessageMicro<memberlist> {
|
||||
static final MessageMicro.FieldMap __fieldMap__;
|
||||
public final PBBytesField bytes_rich_info;
|
||||
public final PBBytesField bytes_special_title;
|
||||
public final PBBytesField bytes_uin_key;
|
||||
public final PBUInt32Field uint32_active_day;
|
||||
public final PBUInt32Field uint32_privilege;
|
||||
public final PBUInt32Field uint32_special_title_expire_time;
|
||||
public final PBUInt64Field uint64_member_uin = PBField.initUInt64(0);
|
||||
public final PBUInt32Field uint32_uin_flag = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_uin_flagex = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_uin_mobile_flag = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_uin_arch_flag = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_join_time = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_old_msg_seq = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_new_msg_seq = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_last_speak_time = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_level = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_point = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_shutup_timestap = PBField.initUInt32(0);
|
||||
public final PBUInt32Field uint32_flagex2 = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY;
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[]{8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 114, 120, 128, 138, 144, 154}, new String[]{
|
||||
"uint64_member_uin", // 1
|
||||
|
||||
"uint32_uin_flag", "uint32_uin_flagex", "uint32_uin_mobile_flag", "uint32_uin_arch_flag", "uint32_join_time", "uint32_old_msg_seq", "uint32_new_msg_seq", "uint32_last_speak_time", "uint32_level", "uint32_point",
|
||||
|
||||
"uint32_shutup_timestap", //12
|
||||
|
||||
"uint32_flagex2", "bytes_special_title", "uint32_special_title_expire_time", "uint32_active_day", "bytes_uin_key", "uint32_privilege", "bytes_rich_info"}, new Object[]{0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, byteStringMicro, 0, 0, byteStringMicro, 0, byteStringMicro}, memberlist.class);
|
||||
}
|
||||
|
||||
public memberlist() {
|
||||
ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY;
|
||||
this.bytes_special_title = PBField.initBytes(byteStringMicro);
|
||||
this.uint32_special_title_expire_time = PBField.initUInt32(0);
|
||||
this.uint32_active_day = PBField.initUInt32(0);
|
||||
this.bytes_uin_key = PBField.initBytes(byteStringMicro);
|
||||
this.uint32_privilege = PBField.initUInt32(0);
|
||||
this.bytes_rich_info = PBField.initBytes(byteStringMicro);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
|
||||
public final class structmsg$AddFrdSNInfo extends MessageMicro<structmsg$AddFrdSNInfo> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBUInt32Field uint32_not_see_dynamic = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_set_sn = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16 }, new String[] { "uint32_not_see_dynamic", "uint32_set_sn" }, new Object[] { integer, integer }, structmsg$AddFrdSNInfo.class);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
|
||||
public final class structmsg$FlagInfo extends MessageMicro<structmsg$FlagInfo> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBUInt32Field FrdMsg_Discuss2ManyChat = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field FrdMsg_GetBusiCard = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field FrdMsg_NeedWaitingMsg = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field FrdMsg_uint32_need_all_unread_msg = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_GetC2cInviteJoinGroup = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_GetDisbandedByAdmin = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_GetOfficialAccount = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_GetPayInGroup = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_HiddenGrp = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_Kick_Admin = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_NeedAutoAdminWording = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_NotAllowJoinGrp_InviteNotFrd = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_WordingDown = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_get_quit_pay_group_msg_flag = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_get_transfer_group_msg_flag = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_mask_invite_auto_join = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field GrpMsg_support_invite_auto_join = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] {
|
||||
8, 16, 24, 32, 40, 48, 56, 64, 72, 80,
|
||||
88, 96, 104, 112, 120, 128, 136 }, new String[] {
|
||||
"GrpMsg_Kick_Admin", "GrpMsg_HiddenGrp", "GrpMsg_WordingDown", "FrdMsg_GetBusiCard", "GrpMsg_GetOfficialAccount", "GrpMsg_GetPayInGroup", "FrdMsg_Discuss2ManyChat", "GrpMsg_NotAllowJoinGrp_InviteNotFrd", "FrdMsg_NeedWaitingMsg", "FrdMsg_uint32_need_all_unread_msg",
|
||||
"GrpMsg_NeedAutoAdminWording", "GrpMsg_get_transfer_group_msg_flag", "GrpMsg_get_quit_pay_group_msg_flag", "GrpMsg_support_invite_auto_join", "GrpMsg_mask_invite_auto_join", "GrpMsg_GetDisbandedByAdmin", "GrpMsg_GetC2cInviteJoinGroup" }, new Object[] {
|
||||
integer, integer, integer, integer, integer, integer, integer, integer, integer, integer,
|
||||
integer, integer, integer, integer, integer, integer, integer }, structmsg$FlagInfo.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
|
||||
public final class structmsg$FriendInfo extends MessageMicro<structmsg$FriendInfo> {
|
||||
static final FieldMap __fieldMap__ = MessageMicro.initFieldMap(new int[] { 10, 18 }, new String[] { "msg_joint_friend", "msg_blacklist" }, new Object[] { "", "" }, structmsg$FriendInfo.class);
|
||||
|
||||
public final PBStringField msg_blacklist = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_joint_friend = PBField.initString("");
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
|
||||
public final class structmsg$GroupInfo extends MessageMicro<structmsg$GroupInfo> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBUInt32Field display_action = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field group_auth_type = PBField.initUInt32(0);
|
||||
|
||||
public final PBStringField msg_alert = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_detail_alert = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_other_admin_done = PBField.initString("");
|
||||
|
||||
public final PBUInt32Field uint32_app_privilege_flag = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 26, 34, 42, 48 }, new String[] { "group_auth_type", "display_action", "msg_alert", "msg_detail_alert", "msg_other_admin_done", "uint32_app_privilege_flag" }, new Object[] { integer, integer, "", "", "", integer }, structmsg$GroupInfo.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$MsgInviteExt extends MessageMicro<structmsg$MsgInviteExt> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBUInt32Field uint32_src_type = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_wait_state = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt64Field uint64_src_code = PBField.initUInt64(0L);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 24 }, new String[] { "uint32_src_type", "uint64_src_code", "uint32_wait_state" }, new Object[] { integer, Long.valueOf(0L), integer }, structmsg$MsgInviteExt.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$MsgPayGroupExt extends MessageMicro<structmsg$MsgPayGroupExt> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBUInt64Field uint64_join_grp_time = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field uint64_quit_grp_time = PBField.initUInt64(0L);
|
||||
|
||||
static {
|
||||
Long long_ = Long.valueOf(0L);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16 }, new String[] { "uint64_join_grp_time", "uint64_quit_grp_time" }, new Object[] { long_, long_ }, structmsg$MsgPayGroupExt.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$ReqNextSystemMsg extends MessageMicro<structmsg$ReqNextSystemMsg> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBEnumField checktype = PBField.initEnum(1);
|
||||
|
||||
public structmsg$FlagInfo flag = new structmsg$FlagInfo();
|
||||
|
||||
public final PBUInt64Field following_friend_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field following_group_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field friend_msg_type_flag = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt32Field language = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field msg_num = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_need_uid = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_req_msg_type = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field version = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
Long long_ = Long.valueOf(0L);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 24, 32, 42, 48, 56, 64, 72, 128 }, new String[] { "msg_num", "following_friend_seq", "following_group_seq", "checktype", "flag", "language", "version", "friend_msg_type_flag", "uint32_req_msg_type", "uint32_need_uid" }, new Object[] { integer, long_, long_, Integer.valueOf(1), null, integer, integer, long_, integer, integer }, structmsg$ReqNextSystemMsg.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$ReqSystemMsgAction extends MessageMicro<structmsg$ReqSystemMsgAction> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public structmsg$SystemMsgActionInfo action_info = new structmsg$SystemMsgActionInfo();
|
||||
|
||||
public final PBUInt32Field group_msg_type = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field language = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt64Field msg_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBEnumField msg_type = PBField.initEnum(1);
|
||||
|
||||
public final PBUInt64Field req_uin = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt32Field src_id = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field sub_src_id = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field sub_type = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
Long long_ = Long.valueOf(0L);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 24, 32, 40, 48, 56, 66, 72 }, new String[] { "msg_type", "msg_seq", "req_uin", "sub_type", "src_id", "sub_src_id", "group_msg_type", "action_info", "language" }, new Object[] { Integer.valueOf(1), long_, long_, integer, integer, integer, integer, null, integer }, structmsg$ReqSystemMsgAction.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBBoolField;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$ReqSystemMsgNew extends MessageMicro<structmsg$ReqSystemMsgNew> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBEnumField checktype = PBField.initEnum(1);
|
||||
|
||||
public structmsg$FlagInfo flag = new structmsg$FlagInfo();
|
||||
|
||||
public final PBUInt64Field friend_msg_type_flag = PBField.initUInt64(0L);
|
||||
|
||||
public final PBBoolField is_get_frd_ribbon = PBField.initBool(true);
|
||||
|
||||
public final PBBoolField is_get_grp_ribbon = PBField.initBool(true);
|
||||
|
||||
public final PBUInt32Field language = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt64Field latest_friend_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field latest_group_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt32Field msg_num = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_need_uid = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_req_msg_type = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field version = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
Long long_ = Long.valueOf(0L);
|
||||
Boolean bool = Boolean.TRUE;
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] {
|
||||
8, 16, 24, 32, 40, 50, 56, 64, 72, 80,
|
||||
88, 128 }, new String[] {
|
||||
"msg_num", "latest_friend_seq", "latest_group_seq", "version", "checktype", "flag", "language", "is_get_frd_ribbon", "is_get_grp_ribbon", "friend_msg_type_flag",
|
||||
"uint32_req_msg_type", "uint32_need_uid" }, new Object[] {
|
||||
integer, long_, long_, integer, Integer.valueOf(1), null, integer, bool, bool, long_,
|
||||
integer, integer }, structmsg$ReqSystemMsgNew.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$ReqSystemMsgRead extends MessageMicro<structmsg$ReqSystemMsgRead> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBEnumField checktype = PBField.initEnum(1);
|
||||
|
||||
public final PBUInt64Field latest_friend_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field latest_group_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt32Field type = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_req_msg_type = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Long long_ = Long.valueOf(0L);
|
||||
Integer integer = Integer.valueOf(0);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 24, 32, 40 }, new String[] { "latest_friend_seq", "latest_group_seq", "type", "checktype", "uint32_req_msg_type" }, new Object[] { long_, long_, integer, Integer.valueOf(1), integer }, structmsg$ReqSystemMsgRead.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
|
||||
public final class structmsg$RspHead extends MessageMicro<structmsg$RspHead> {
|
||||
static final FieldMap __fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 18 }, new String[] { "result", "msg_fail" }, new Object[] { Integer.valueOf(0), "" }, structmsg$RspHead.class);
|
||||
|
||||
public final PBStringField msg_fail = PBField.initString("");
|
||||
|
||||
public final PBInt32Field result = PBField.initInt32(0);
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro;
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBBytesField;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBRepeatMessageField;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$RspNextSystemMsg extends MessageMicro<structmsg$RspNextSystemMsg> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBStringField bytes_game_nick = PBField.initString("");
|
||||
|
||||
public final PBBytesField bytes_undecid_for_qim = PBField.initBytes(ByteStringMicro.EMPTY);
|
||||
|
||||
public final PBEnumField checktype = PBField.initEnum(1);
|
||||
|
||||
public final PBUInt64Field following_friend_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field following_group_seq = PBField.initUInt64(0L);
|
||||
|
||||
public structmsg$RspHead head = new structmsg$RspHead();
|
||||
|
||||
public final PBRepeatMessageField<structmsg$StructMsg> msgs = PBField.initRepeatMessage(structmsg$StructMsg.class);
|
||||
|
||||
public final PBUInt32Field uint32_un_read_count3 = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Long long_ = Long.valueOf(0L);
|
||||
ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY;
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 10, 18, 24, 32, 40, 802, 810, 816 }, new String[] { "head", "msgs", "following_friend_seq", "following_group_seq", "checktype", "bytes_game_nick", "bytes_undecid_for_qim", "uint32_un_read_count3" }, new Object[] { null, null, long_, long_, Integer.valueOf(1), "", byteStringMicro, Integer.valueOf(0) }, structmsg$RspNextSystemMsg.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
|
||||
public final class structmsg$RspSystemMsgAction extends MessageMicro<structmsg$RspSystemMsgAction> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public structmsg$RspHead head = new structmsg$RspHead();
|
||||
|
||||
public final PBStringField msg_detail = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_invalid_decided = PBField.initString("");
|
||||
|
||||
public final PBUInt32Field remark_result = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field type = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 10, 18, 24, 42, 48 }, new String[] { "head", "msg_detail", "type", "msg_invalid_decided", "remark_result" }, new Object[] { null, "", integer, "", integer }, structmsg$RspSystemMsgAction.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro;
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBBytesField;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBRepeatMessageField;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$RspSystemMsgNew extends MessageMicro<structmsg$RspSystemMsgNew> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBStringField bytes_game_nick = PBField.initString("");
|
||||
|
||||
public final PBBytesField bytes_undecid_for_qim = PBField.initBytes(ByteStringMicro.EMPTY);
|
||||
|
||||
public final PBEnumField checktype = PBField.initEnum(1);
|
||||
|
||||
public final PBUInt64Field following_friend_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field following_group_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBRepeatMessageField<structmsg$StructMsg> friendmsgs = PBField.initRepeatMessage(structmsg$StructMsg.class);
|
||||
|
||||
public final PBRepeatMessageField<structmsg$StructMsg> groupmsgs = PBField.initRepeatMessage(structmsg$StructMsg.class);
|
||||
|
||||
public final PBStringField grp_msg_display = PBField.initString("");
|
||||
|
||||
public structmsg$RspHead head = new structmsg$RspHead();
|
||||
|
||||
public final PBUInt64Field latest_friend_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field latest_group_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBStringField msg_display = PBField.initString("");
|
||||
|
||||
public structmsg$StructMsg msg_ribbon_friend = new structmsg$StructMsg();
|
||||
|
||||
public structmsg$StructMsg msg_ribbon_group = new structmsg$StructMsg();
|
||||
|
||||
public final PBUInt32Field uint32_has_suspicious_flag = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_over = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field uint32_un_read_count3 = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field unread_friend_count = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field unread_group_count = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
Long long_ = Long.valueOf(0L);
|
||||
ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY;
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] {
|
||||
10, 16, 24, 32, 40, 48, 56, 74, 82, 90,
|
||||
98, 106, 114, 120, 160, 802, 810, 816, 824 }, new String[] {
|
||||
"head", "unread_friend_count", "unread_group_count", "latest_friend_seq", "latest_group_seq", "following_friend_seq", "following_group_seq", "friendmsgs", "groupmsgs", "msg_ribbon_friend",
|
||||
"msg_ribbon_group", "msg_display", "grp_msg_display", "uint32_over", "checktype", "bytes_game_nick", "bytes_undecid_for_qim", "uint32_un_read_count3", "uint32_has_suspicious_flag" }, new Object[] {
|
||||
null, integer, integer, long_, long_, long_, long_, null, null, null,
|
||||
null, "", "", integer, Integer.valueOf(1), "", byteStringMicro, integer, integer }, structmsg$RspSystemMsgNew.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
|
||||
public final class structmsg$RspSystemMsgRead extends MessageMicro<structmsg$RspSystemMsgRead> {
|
||||
static final FieldMap __fieldMap__ = MessageMicro.initFieldMap(new int[] { 10, 16, 24 }, new String[] { "head", "type", "checktype" }, new Object[] { null, Integer.valueOf(0), Integer.valueOf(1) }, structmsg$RspSystemMsgRead.class);
|
||||
|
||||
public final PBEnumField checktype = PBField.initEnum(1);
|
||||
|
||||
public structmsg$RspHead head = new structmsg$RspHead();
|
||||
|
||||
public final PBUInt32Field type = PBField.initUInt32(0);
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$StructMsg extends MessageMicro<structmsg$StructMsg> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public structmsg$SystemMsg msg = new structmsg$SystemMsg();
|
||||
|
||||
public final PBUInt64Field msg_seq = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field msg_time = PBField.initUInt64(0L);
|
||||
|
||||
public final PBEnumField msg_type = PBField.initEnum(1);
|
||||
|
||||
public final PBUInt64Field req_uin = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt32Field uint32_unread_flag = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field version = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
Long long_ = Long.valueOf(0L);
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 24, 32, 40, 48, 402 }, new String[] { "version", "msg_type", "msg_seq", "msg_time", "req_uin", "uint32_unread_flag", "msg" }, new Object[] { integer, Integer.valueOf(1), long_, long_, long_, integer, null }, structmsg$StructMsg.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro;
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBBytesField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBRepeatMessageField;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$SystemMsg extends MessageMicro<structmsg$SystemMsg> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public final PBUInt64Field action_uin = PBField.initUInt64(0L);
|
||||
|
||||
public final PBStringField action_uin_nick;
|
||||
|
||||
public final PBBytesField action_uin_qq_nick;
|
||||
|
||||
public final PBBytesField action_uin_remark;
|
||||
|
||||
public final PBRepeatMessageField<structmsg$SystemMsgAction> actions = PBField.initRepeatMessage(structmsg$SystemMsgAction.class);
|
||||
|
||||
public final PBUInt64Field actor_uin = PBField.initUInt64(0L);
|
||||
|
||||
public final PBStringField actor_uin_nick;
|
||||
|
||||
public final PBBytesField bytes_addtion;
|
||||
|
||||
public final PBBytesField bytes_game_msg;
|
||||
|
||||
public final PBBytesField bytes_game_nick;
|
||||
|
||||
public final PBBytesField bytes_name_more;
|
||||
|
||||
public final PBBytesField bytes_source_desc;
|
||||
|
||||
public final PBBytesField bytes_transparent_group_notify;
|
||||
|
||||
public final PBBytesField bytes_warning_tips;
|
||||
|
||||
public final PBUInt32Field card_switch;
|
||||
|
||||
public final PBUInt64Field clone_uin = PBField.initUInt64(0L);
|
||||
|
||||
public final PBStringField clone_uin_nick;
|
||||
|
||||
public final PBBytesField eim_group_id_name;
|
||||
|
||||
public structmsg$FriendInfo friend_info = new structmsg$FriendInfo();
|
||||
|
||||
public final PBUInt64Field group_code = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt32Field group_ext_flag;
|
||||
|
||||
public structmsg$GroupInfo group_info = new structmsg$GroupInfo();
|
||||
|
||||
public final PBUInt32Field group_inviter_role = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field group_msg_type = PBField.initUInt32(0);
|
||||
|
||||
public final PBStringField group_name;
|
||||
|
||||
public final PBStringField msg_actor_describe = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_additional = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_additional_list = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_decided = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_describe = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_detail;
|
||||
|
||||
public structmsg$MsgInviteExt msg_invite_extinfo = new structmsg$MsgInviteExt();
|
||||
|
||||
public structmsg$MsgPayGroupExt msg_pay_group_extinfo = new structmsg$MsgPayGroupExt();
|
||||
|
||||
public final PBStringField msg_qna;
|
||||
|
||||
public final PBStringField msg_source = PBField.initString("");
|
||||
|
||||
public final PBStringField msg_title = PBField.initString("");
|
||||
|
||||
public final PBBytesField pic_url;
|
||||
|
||||
public final PBUInt32Field relation = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field req_uin_age;
|
||||
|
||||
public final PBBytesField req_uin_business_card;
|
||||
|
||||
public final PBInt32Field req_uin_faceid;
|
||||
|
||||
public final PBUInt32Field req_uin_gender;
|
||||
|
||||
public final PBStringField req_uin_nick;
|
||||
|
||||
public final PBBytesField req_uin_pre_remark;
|
||||
|
||||
public final PBUInt32Field reqsubtype = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field src_id = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field sub_src_id = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt32Field sub_type = PBField.initUInt32(0);
|
||||
|
||||
public final PBStringField uid;
|
||||
|
||||
public final PBUInt32Field uint32_c2c_invite_join_group_flag;
|
||||
|
||||
public final PBUInt32Field uint32_doubt_flag;
|
||||
|
||||
public final PBUInt32Field uint32_group_flagext3;
|
||||
|
||||
public final PBUInt32Field uint32_source_flag = PBField.initUInt32(0);
|
||||
|
||||
public final PBUInt64Field uint64_discuss_uin = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field uint64_eim_group_id = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt64Field uint64_group_owner_uin;
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
Long long_ = Long.valueOf(0L);
|
||||
ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY;
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] {
|
||||
8, 18, 26, 34, 42, 50, 56, 64, 74, 80,
|
||||
88, 96, 104, 114, 122, 128, 138, 146, 152, 160,
|
||||
168, 176, 184, 194, 202, 208, 218, 226, 232, 240,
|
||||
248, 258, 266, 274, 282, 400, 410, 418, 426, 434,
|
||||
442, 456, 466, 474, 482, 490, 506, 514, 522, 530,
|
||||
536, 544, 552, 808, 866, 882 }, new String[] {
|
||||
"sub_type", "msg_title", "msg_describe", "msg_additional", "msg_source", "msg_decided", "src_id", "sub_src_id", "actions", "group_code",
|
||||
"action_uin", "group_msg_type", "group_inviter_role", "friend_info", "group_info", "actor_uin", "msg_actor_describe", "msg_additional_list", "relation", "reqsubtype",
|
||||
"clone_uin", "uint64_discuss_uin", "uint64_eim_group_id", "msg_invite_extinfo", "msg_pay_group_extinfo", "uint32_source_flag", "bytes_game_nick", "bytes_game_msg", "uint32_group_flagext3", "uint64_group_owner_uin",
|
||||
"uint32_doubt_flag", "bytes_warning_tips", "bytes_name_more", "bytes_addtion", "bytes_transparent_group_notify", "req_uin_faceid", "req_uin_nick", "group_name", "action_uin_nick", "msg_qna",
|
||||
"msg_detail", "group_ext_flag", "actor_uin_nick", "pic_url", "clone_uin_nick", "req_uin_business_card", "eim_group_id_name", "req_uin_pre_remark", "action_uin_qq_nick", "action_uin_remark",
|
||||
"req_uin_gender", "req_uin_age", "uint32_c2c_invite_join_group_flag", "card_switch", "bytes_source_desc", "uid" }, new Object[] {
|
||||
integer, "", "", "", "", "", integer, integer, null, long_,
|
||||
long_, integer, integer, null, null, long_, "", "", integer, integer,
|
||||
long_, long_, long_, null, null, integer, byteStringMicro, byteStringMicro, integer, long_,
|
||||
integer, byteStringMicro, byteStringMicro, byteStringMicro, byteStringMicro, integer, "", "", "", "",
|
||||
"", integer, "", byteStringMicro, "", byteStringMicro, byteStringMicro, byteStringMicro, byteStringMicro, byteStringMicro,
|
||||
integer, integer, integer, integer, byteStringMicro, "" }, structmsg$SystemMsg.class);
|
||||
}
|
||||
|
||||
public structmsg$SystemMsg() {
|
||||
ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY;
|
||||
this.bytes_game_nick = PBField.initBytes(byteStringMicro);
|
||||
this.bytes_game_msg = PBField.initBytes(byteStringMicro);
|
||||
this.uint32_group_flagext3 = PBField.initUInt32(0);
|
||||
this.uint64_group_owner_uin = PBField.initUInt64(0L);
|
||||
this.uint32_doubt_flag = PBField.initUInt32(0);
|
||||
this.bytes_warning_tips = PBField.initBytes(byteStringMicro);
|
||||
this.bytes_name_more = PBField.initBytes(byteStringMicro);
|
||||
this.bytes_addtion = PBField.initBytes(byteStringMicro);
|
||||
this.bytes_transparent_group_notify = PBField.initBytes(byteStringMicro);
|
||||
this.req_uin_faceid = PBField.initInt32(0);
|
||||
this.req_uin_nick = PBField.initString("");
|
||||
this.group_name = PBField.initString("");
|
||||
this.action_uin_nick = PBField.initString("");
|
||||
this.msg_qna = PBField.initString("");
|
||||
this.msg_detail = PBField.initString("");
|
||||
this.group_ext_flag = PBField.initUInt32(0);
|
||||
this.actor_uin_nick = PBField.initString("");
|
||||
this.pic_url = PBField.initBytes(byteStringMicro);
|
||||
this.clone_uin_nick = PBField.initString("");
|
||||
this.req_uin_business_card = PBField.initBytes(byteStringMicro);
|
||||
this.eim_group_id_name = PBField.initBytes(byteStringMicro);
|
||||
this.req_uin_pre_remark = PBField.initBytes(byteStringMicro);
|
||||
this.action_uin_qq_nick = PBField.initBytes(byteStringMicro);
|
||||
this.action_uin_remark = PBField.initBytes(byteStringMicro);
|
||||
this.req_uin_gender = PBField.initUInt32(0);
|
||||
this.req_uin_age = PBField.initUInt32(0);
|
||||
this.uint32_c2c_invite_join_group_flag = PBField.initUInt32(0);
|
||||
this.card_switch = PBField.initUInt32(0);
|
||||
this.bytes_source_desc = PBField.initBytes(byteStringMicro);
|
||||
this.uid = PBField.initString("");
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
|
||||
public final class structmsg$SystemMsgAction extends MessageMicro<structmsg$SystemMsgAction> {
|
||||
static final FieldMap __fieldMap__ = MessageMicro.initFieldMap(new int[] { 10, 18, 24, 34, 42 }, new String[] { "name", "result", "action", "action_info", "detail_name" }, new Object[] { "", "", Integer.valueOf(0), null, "" }, structmsg$SystemMsgAction.class);
|
||||
|
||||
public final PBUInt32Field action = PBField.initUInt32(0);
|
||||
|
||||
public structmsg$SystemMsgActionInfo action_info = new structmsg$SystemMsgActionInfo();
|
||||
|
||||
public final PBStringField detail_name = PBField.initString("");
|
||||
|
||||
public final PBStringField name = PBField.initString("");
|
||||
|
||||
public final PBStringField result = PBField.initString("");
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package tencent.mobileim.structmsg;
|
||||
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro;
|
||||
import com.tencent.mobileqq.pb.MessageMicro;
|
||||
import com.tencent.mobileqq.pb.PBBoolField;
|
||||
import com.tencent.mobileqq.pb.PBBytesField;
|
||||
import com.tencent.mobileqq.pb.PBEnumField;
|
||||
import com.tencent.mobileqq.pb.PBField;
|
||||
import com.tencent.mobileqq.pb.PBStringField;
|
||||
import com.tencent.mobileqq.pb.PBUInt32Field;
|
||||
import com.tencent.mobileqq.pb.PBUInt64Field;
|
||||
|
||||
public final class structmsg$SystemMsgActionInfo extends MessageMicro<structmsg$SystemMsgActionInfo> {
|
||||
static final FieldMap __fieldMap__;
|
||||
|
||||
public structmsg$AddFrdSNInfo addFrdSNInfo = new structmsg$AddFrdSNInfo();
|
||||
|
||||
public final PBBoolField blacklist = PBField.initBool(false);
|
||||
|
||||
public final PBUInt64Field group_code = PBField.initUInt64(0L);
|
||||
|
||||
public final PBUInt32Field group_id = PBField.initUInt32(0);
|
||||
|
||||
public final PBStringField msg = PBField.initString("");
|
||||
|
||||
public final PBStringField remark = PBField.initString("");
|
||||
|
||||
public final PBBytesField sig = PBField.initBytes(ByteStringMicro.EMPTY);
|
||||
|
||||
public final PBEnumField type = PBField.initEnum(1);
|
||||
|
||||
public final PBUInt32Field uint32_req_msg_type = PBField.initUInt32(0);
|
||||
|
||||
static {
|
||||
Integer integer = Integer.valueOf(0);
|
||||
ByteStringMicro byteStringMicro = ByteStringMicro.EMPTY;
|
||||
Boolean bool = Boolean.FALSE;
|
||||
__fieldMap__ = MessageMicro.initFieldMap(new int[] { 8, 16, 26, 402, 408, 418, 424, 434, 440 }, new String[] { "type", "group_code", "sig", "msg", "group_id", "remark", "blacklist", "addFrdSNInfo", "uint32_req_msg_type" }, new Object[] { Integer.valueOf(1), Long.valueOf(0L), byteStringMicro, "", integer, "", bool, null, integer }, structmsg$SystemMsgActionInfo.class);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ plugins {
|
||||
id("org.jetbrains.kotlin.android")
|
||||
//id("io.realm.kotlin")
|
||||
id("kotlin-kapt")
|
||||
kotlin("plugin.serialization") version "1.8.0"
|
||||
kotlin("plugin.serialization") version "1.8.10"
|
||||
}
|
||||
|
||||
android {
|
||||
@ -13,7 +13,6 @@ android {
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
@ -50,6 +49,9 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly ("de.robv.android.xposed:api:82")
|
||||
compileOnly (project(":qqinterface"))
|
||||
|
||||
implementation("androidx.core:core-ktx:1.9.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.9.0")
|
||||
@ -59,7 +61,8 @@ dependencies {
|
||||
//implementation("io.realm.kotlin:library-sync:1.11.0")
|
||||
|
||||
val ktorVersion = "2.3.3"
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
//implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
implementation("io.github.xn32:json5k:0.3.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.1.16")
|
||||
implementation("io.ktor:ktor-server-core:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-host-common:$ktorVersion")
|
||||
@ -71,6 +74,7 @@ dependencies {
|
||||
implementation("io.ktor:ktor-client-cio:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
|
||||
//implementation("io.ktor:ktor-serialization-kotlinx-protobuf:$ktorVersion")
|
||||
implementation("io.ktor:ktor-network-tls-certificates:$ktorVersion")
|
||||
|
||||
/**
|
||||
@ -92,12 +96,5 @@ dependencies {
|
||||
//ksp("androidx.room:room-compiler:$roomVersion")
|
||||
// optional - Kotlin Extensions and Coroutines support for Room
|
||||
implementation("androidx.room:room-ktx:$roomVersion")
|
||||
|
||||
compileOnly ("de.robv.android.xposed:api:82")
|
||||
compileOnly (project(":qqinterface"))
|
||||
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package moe.fuqiuluo.qqinterface.entries
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
@ -11,6 +11,8 @@ import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.proto.protobufOf
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
@ -35,45 +37,41 @@ internal abstract class BaseSvc {
|
||||
return ToServiceMsg("mobileqq.service", app.currentAccountUin, cmd)
|
||||
}
|
||||
|
||||
suspend fun sendOidbAW(cmd: String, cmdId: Int, serviceId: Int, data: ByteArray, trpc: Boolean = false): ByteArray? {
|
||||
return suspendCoroutine { continuation ->
|
||||
val seq = MsfCore.getNextSeq()
|
||||
val timer = timer(initialDelay = 5000L, period = 5000L) {
|
||||
suspend fun sendOidbAW(cmd: String, cmdId: Int, serviceId: Int, data: ByteArray, trpc: Boolean = false, timeout: Long = 5000L): ByteArray? {
|
||||
val seq = MsfCore.getNextSeq()
|
||||
return withTimeoutOrNull(timeout) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
PacketHandler.unregisterLessHandler(seq)
|
||||
continuation.resume(null)
|
||||
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
||||
val buffer = it.getByteArrayExtra("buffer")!!
|
||||
continuation.resume(buffer)
|
||||
})
|
||||
}
|
||||
if (trpc) sendTrpcOidb(cmd, cmdId, serviceId, data, seq)
|
||||
else sendOidb(cmd, cmdId, serviceId, data, seq)
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
||||
val buffer = it.getByteArrayExtra("buffer")!!
|
||||
timer.cancel()
|
||||
continuation.resume(buffer)
|
||||
})
|
||||
}
|
||||
if (trpc) sendTrpcOidb(cmd, cmdId, serviceId, data, seq)
|
||||
else sendOidb(cmd, cmdId, serviceId, data, seq)
|
||||
}
|
||||
}.also {
|
||||
if (it == null)
|
||||
DynamicReceiver.unregister(seq)
|
||||
}?.copyOf()
|
||||
}
|
||||
|
||||
suspend fun sendBufferAW(cmd: String, isPb: Boolean, data: ByteArray): ByteArray? {
|
||||
return suspendCoroutine { continuation ->
|
||||
val seq = MsfCore.getNextSeq()
|
||||
val timer = timer(initialDelay = 5000L, period = 5000L) {
|
||||
suspend fun sendBufferAW(cmd: String, isPb: Boolean, data: ByteArray, timeout: Long = 5000L): ByteArray? {
|
||||
val seq = MsfCore.getNextSeq()
|
||||
return withTimeoutOrNull<ByteArray?>(timeout) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
PacketHandler.unregisterLessHandler(seq)
|
||||
continuation.resume(null)
|
||||
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
||||
val buffer = it.getByteArrayExtra("buffer")!!
|
||||
continuation.resume(buffer)
|
||||
})
|
||||
sendBuffer(cmd, isPb, data, seq)
|
||||
}
|
||||
}
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
||||
val buffer = it.getByteArrayExtra("buffer")!!
|
||||
timer.cancel()
|
||||
continuation.resume(buffer)
|
||||
})
|
||||
sendBuffer(cmd, isPb, data, seq)
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
if (it == null)
|
||||
DynamicReceiver.unregister(seq)
|
||||
}?.copyOf()
|
||||
}
|
||||
|
||||
fun sendOidb(cmd: String, cmdId: Int, serviceId: Int, buffer: ByteArray, seq: Int = -1, trpc: Boolean = false) {
|
||||
@ -110,7 +108,7 @@ internal abstract class BaseSvc {
|
||||
app.sendToService(to)
|
||||
}
|
||||
|
||||
fun sendBuffer(cmd: String, isPb: Boolean, buffer: ByteArray, seq: Int) {
|
||||
fun sendBuffer(cmd: String, isPb: Boolean, buffer: ByteArray, seq: Int = MsfCore.getNextSeq()) {
|
||||
val toServiceMsg = ToServiceMsg("mobileqq.service", app.currentUin, cmd)
|
||||
toServiceMsg.putWupBuffer(buffer)
|
||||
toServiceMsg.addAttribute("req_pb_protocol_flag", isPb)
|
||||
|
@ -1,12 +1,15 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet
|
||||
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import moe.fuqiuluo.proto.protobufOf
|
||||
import moe.fuqiuluo.qqinterface.servlet.entries.*
|
||||
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
|
||||
import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.shamrock.tools.toHexString
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import tencent.im.oidb.cmd0x6d8.oidb_0x6d8
|
||||
import tencent.im.oidb.oidb_sso
|
||||
|
||||
@ -33,8 +36,23 @@ internal object FileSvc: BaseSvc() {
|
||||
}
|
||||
|
||||
fun deleteGroupFile(groupId: String, bizId: Int, fileUid: String) {
|
||||
/*
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val richMediaService = sessionService.richMediaService
|
||||
|
||||
val result = withTimeoutOrNull(3000L) {
|
||||
suspendCancellableCoroutine {
|
||||
richMediaService.deleteGroupFile(groupId.toLong(), fileUid, bizId) { code, _, result ->
|
||||
it.resume(code to result.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if (result == null) Result.failure(RuntimeException("delete group file timeout")) else Result.success(result)*/
|
||||
// 调用QQ内部实现会导致闪退!
|
||||
sendOidb("OidbSvc.0x6d6_3", 1750, 3, protobufOf(
|
||||
4 to mapOf(
|
||||
4 to mapOf(
|
||||
1 to groupId.toLong(),
|
||||
2 to 3,
|
||||
3 to bizId,
|
||||
@ -92,7 +110,7 @@ internal object FileSvc: BaseSvc() {
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getGroupRootFiles(groupId: Long): GroupFileList {
|
||||
suspend fun getGroupRootFiles(groupId: Long): Result<GroupFileList> {
|
||||
return getGroupFiles(groupId, "/")
|
||||
}
|
||||
|
||||
@ -100,7 +118,7 @@ internal object FileSvc: BaseSvc() {
|
||||
return FileUrl(RichProtoSvc.getGroupFileDownUrl(groupId, fileId, busid))
|
||||
}
|
||||
|
||||
suspend fun getGroupFiles(groupId: Long, folderId: String): GroupFileList {
|
||||
suspend fun getGroupFiles(groupId: Long, folderId: String): Result<GroupFileList> {
|
||||
val fileSystemInfo = getGroupFileSystemInfo(groupId)
|
||||
val rspGetFileListBuffer = sendOidbAW("OidbSvc.0x6d8_1", 1752, 1, oidb_0x6d8.ReqBody().also {
|
||||
it.file_list_info_req.set(oidb_0x6d8.GetFileListReqBody().apply {
|
||||
@ -122,17 +140,20 @@ internal object FileSvc: BaseSvc() {
|
||||
|
||||
uint32_show_onlinedoc_folder.set(0)
|
||||
})
|
||||
}.toByteArray())
|
||||
}.toByteArray(), timeout = 15_000L)
|
||||
|
||||
val files = arrayListOf<FileInfo>()
|
||||
val dirs = arrayListOf<FolderInfo>()
|
||||
if (rspGetFileListBuffer != null) {
|
||||
oidb_0x6d8.RspBody().mergeFrom(oidb_sso.OIDBSSOPkg()
|
||||
.mergeFrom(rspGetFileListBuffer.slice(4))
|
||||
.bytes_bodybuffer.get()
|
||||
.toByteArray()).file_list_info_rsp.apply {
|
||||
return kotlin.runCatching {
|
||||
val files = arrayListOf<FileInfo>()
|
||||
val dirs = arrayListOf<FolderInfo>()
|
||||
if (rspGetFileListBuffer != null) {
|
||||
val oidb = oidb_sso.OIDBSSOPkg().mergeFrom(rspGetFileListBuffer.slice(4).let {
|
||||
if (it[0] == 0x78.toByte()) DeflateTools.uncompress(it) else it
|
||||
})
|
||||
|
||||
oidb_0x6d8.RspBody().mergeFrom(oidb.bytes_bodybuffer.get().toByteArray())
|
||||
.file_list_info_rsp.apply {
|
||||
rpt_item_list.get().forEach { file ->
|
||||
if (file.uint32_type.get() == 1) {
|
||||
if (file.uint32_type.get() == oidb_0x6d8.GetFileListRspBody.TYPE_FILE) {
|
||||
val fileInfo = file.file_info
|
||||
files.add(FileInfo(
|
||||
groupId = groupId,
|
||||
@ -147,7 +168,8 @@ internal object FileSvc: BaseSvc() {
|
||||
uploadUin = fileInfo.uint64_uploader_uin.get(),
|
||||
uploadNick = fileInfo.str_uploader_name.get()
|
||||
))
|
||||
} else if (file.uint32_type.get() == 2) {
|
||||
}
|
||||
else if (file.uint32_type.get() == oidb_0x6d8.GetFileListRspBody.TYPE_FOLDER) {
|
||||
val folderInfo = file.folder_info
|
||||
dirs.add(FolderInfo(
|
||||
groupId = groupId,
|
||||
@ -158,58 +180,18 @@ internal object FileSvc: BaseSvc() {
|
||||
creator = folderInfo.uint64_create_uin.get(),
|
||||
creatorNick = folderInfo.str_creator_name.get()
|
||||
))
|
||||
} else {
|
||||
LogCenter.log("未知文件类型: ${file.uint32_type.get()}", Level.WARN)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw RuntimeException("获取群文件列表失败")
|
||||
}
|
||||
} else {
|
||||
throw RuntimeException("获取群文件列表失败")
|
||||
|
||||
GroupFileList(files, dirs)
|
||||
}.onFailure {
|
||||
LogCenter.log(it.message + ", buffer: ${rspGetFileListBuffer.toHexString()}", Level.ERROR)
|
||||
}
|
||||
|
||||
return GroupFileList(files, dirs)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class FileUrl(
|
||||
@SerialName("url") val url: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GroupFileList(
|
||||
@SerialName("files") val files: List<FileInfo>,
|
||||
@SerialName("folders") val folders: List<FolderInfo>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FileInfo(
|
||||
@SerialName("group_id") val groupId: Long,
|
||||
@SerialName("file_id") val fileId: String,
|
||||
@SerialName("file_name") val fileName: String,
|
||||
@SerialName("file_size") val fileSize: Long,
|
||||
@SerialName("busid") val busid: Int,
|
||||
@SerialName("upload_time") val uploadTime: Int,
|
||||
@SerialName("dead_time") val deadTime: Int,
|
||||
@SerialName("modify_time") val modifyTime: Int,
|
||||
@SerialName("download_times") val downloadTimes: Int,
|
||||
@SerialName("uploader") val uploadUin: Long,
|
||||
@SerialName("upload_name") val uploadNick: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FolderInfo(
|
||||
@SerialName("group_id") val groupId: Long,
|
||||
@SerialName("folder_id") val folderId: String,
|
||||
@SerialName("folder_name") val folderName: String,
|
||||
@SerialName("total_file_count") val totalFileCount: Int,
|
||||
@SerialName("create_time") val createTime: Int,
|
||||
@SerialName("creator") val creator: Long,
|
||||
@SerialName("creator_name") val creatorNick: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FileSystemInfo(
|
||||
@SerialName("file_count") val fileCount: Int,
|
||||
@SerialName("limit_count") val fileLimitCount: Int,
|
||||
@SerialName("used_space") val usedSpace: Long,
|
||||
@SerialName("total_space") val totalSpace: Long,
|
||||
)
|
||||
}
|
@ -1,19 +1,30 @@
|
||||
@file:OptIn(DelicateCoroutinesApi::class)
|
||||
@file:Suppress("IllegalIdentifier")
|
||||
package moe.fuqiuluo.qqinterface.servlet
|
||||
|
||||
import com.tencent.common.app.AppInterface
|
||||
import com.tencent.mobileqq.data.Friends
|
||||
import com.tencent.mobileqq.friend.api.IFriendDataService
|
||||
import com.tencent.mobileqq.friend.api.IFriendHandlerService
|
||||
import com.tencent.mobileqq.qroute.QRoute
|
||||
import com.tencent.mobileqq.relation.api.IAddFriendTempApi
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
|
||||
import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import mqq.app.AppRuntime
|
||||
import mqq.app.MobileQQ
|
||||
import tencent.mobileim.structmsg.`structmsg$FlagInfo`
|
||||
import tencent.mobileim.structmsg.`structmsg$ReqSystemMsgNew`
|
||||
import tencent.mobileim.structmsg.`structmsg$RspSystemMsgNew`
|
||||
import kotlin.coroutines.resume
|
||||
import tencent.mobileim.structmsg.`structmsg$SystemMsgActionInfo` as ActionInfo
|
||||
import tencent.mobileim.structmsg.`structmsg$AddFrdSNInfo` as AddFrdSNInfo
|
||||
import tencent.mobileim.structmsg.`structmsg$StructMsg` as StructMsg
|
||||
|
||||
internal object FriendSvc: BaseSvc() {
|
||||
|
||||
@ -28,6 +39,64 @@ internal object FriendSvc: BaseSvc() {
|
||||
return Result.success(service.allFriends)
|
||||
}
|
||||
|
||||
// ProfileService.Pb.ReqSystemMsgAction.Friend
|
||||
fun requestFriendRequest(msgSeq: Long, uin: Long, remark: String = "", approve: Boolean? = true, notSee: Boolean? = false) {
|
||||
val app = AppRuntimeFetcher.appRuntime
|
||||
if (app !is AppInterface)
|
||||
throw RuntimeException("AppRuntime cannot cast to AppInterface")
|
||||
val service = QRoute.api(IAddFriendTempApi::class.java)
|
||||
val action = ActionInfo()
|
||||
action.type.set(if (approve != false) 2 else 3)
|
||||
action.group_id.set(0)
|
||||
action.remark.set(remark)
|
||||
val snInfo = AddFrdSNInfo()
|
||||
snInfo.uint32_not_see_dynamic.set(if (notSee != false) 1 else 0)
|
||||
snInfo.uint32_set_sn.set(0)
|
||||
action.addFrdSNInfo.set(snInfo)
|
||||
service.sendFriendSystemMsgAction(1, msgSeq, uin, 1, 2004, 11, 0, action, 0, StructMsg(), false,
|
||||
app
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun requestFriendSystemMsgNew(msgNum: Int, latestFriendSeq: Long, latestGroupSeq: Long): List<StructMsg>? {
|
||||
val req = `structmsg$ReqSystemMsgNew`()
|
||||
req.msg_num.set(msgNum)
|
||||
req.latest_friend_seq.set(latestFriendSeq)
|
||||
req.latest_group_seq.set(latestGroupSeq)
|
||||
req.version.set(1000)
|
||||
req.checktype.set(2)
|
||||
val flag = `structmsg$FlagInfo`()
|
||||
// flag.GrpMsg_Kick_Admin.set(1)
|
||||
// flag.GrpMsg_HiddenGrp.set(1)
|
||||
// flag.GrpMsg_WordingDown.set(1)
|
||||
flag.FrdMsg_GetBusiCard.set(1)
|
||||
// flag.GrpMsg_GetOfficialAccount.set(1)
|
||||
// flag.GrpMsg_GetPayInGroup.set(1)
|
||||
flag.FrdMsg_Discuss2ManyChat.set(1)
|
||||
// flag.GrpMsg_NotAllowJoinGrp_InviteNotFrd.set(1)
|
||||
flag.FrdMsg_NeedWaitingMsg.set(1)
|
||||
flag.FrdMsg_uint32_need_all_unread_msg.set(1)
|
||||
// flag.GrpMsg_NeedAutoAdminWording.set(1)
|
||||
// flag.GrpMsg_get_transfer_group_msg_flag.set(1)
|
||||
// flag.GrpMsg_get_quit_pay_group_msg_flag.set(1)
|
||||
// flag.GrpMsg_support_invite_auto_join.set(1)
|
||||
// flag.GrpMsg_mask_invite_auto_join.set(1)
|
||||
// flag.GrpMsg_GetDisbandedByAdmin.set(1)
|
||||
flag.GrpMsg_GetC2cInviteJoinGroup.set(1)
|
||||
req.flag.set(flag)
|
||||
req.is_get_frd_ribbon.set(false)
|
||||
req.is_get_grp_ribbon.set(false)
|
||||
req.friend_msg_type_flag.set(1)
|
||||
req.uint32_req_msg_type.set(1)
|
||||
req.uint32_need_uid.set(1)
|
||||
val respBuffer = sendBufferAW("ProfileService.Pb.ReqSystemMsgNew.Friend", true, req.toByteArray())
|
||||
?: return ArrayList()
|
||||
val msg = `structmsg$RspSystemMsgNew`()
|
||||
msg.mergeFrom(respBuffer.slice(4))
|
||||
return msg.friendmsgs.get()
|
||||
}
|
||||
|
||||
|
||||
private suspend fun requestFriendList(runtime: AppRuntime, dataService: IFriendDataService): Boolean {
|
||||
val service = runtime.getRuntimeService(IFriendHandlerService::class.java, "all")
|
||||
service.requestFriendList(true, 0)
|
||||
|
@ -22,21 +22,30 @@ import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.proto.ProtoUtils
|
||||
import moe.fuqiuluo.proto.asInt
|
||||
import moe.fuqiuluo.proto.asUtf8String
|
||||
import moe.fuqiuluo.proto.protobufOf
|
||||
import moe.fuqiuluo.qqinterface.servlet.entries.ProhibitedMemberInfo
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.tools.ifNullOrEmpty
|
||||
import moe.fuqiuluo.shamrock.tools.putBuf32Long
|
||||
import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import mqq.app.MobileQQ
|
||||
import tencent.im.oidb.cmd0x899.oidb_0x899
|
||||
import tencent.im.oidb.cmd0x89a.oidb_0x89a
|
||||
import tencent.im.oidb.cmd0x8a0.oidb_0x8a0
|
||||
import tencent.im.oidb.cmd0x8fc.Oidb_0x8fc
|
||||
import tencent.im.oidb.oidb_sso
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
import tencent.mobileim.structmsg.`structmsg$ReqSystemMsgNew` as ReqSystemMsgNew
|
||||
import tencent.mobileim.structmsg.`structmsg$FlagInfo` as FlagInfo
|
||||
import tencent.mobileim.structmsg.`structmsg$RspSystemMsgNew` as RspSystemMsgNew
|
||||
import tencent.mobileim.structmsg.`structmsg$StructMsg` as StructMsg
|
||||
internal object GroupSvc: BaseSvc() {
|
||||
private val RefreshTroopMemberInfoLock by lazy {
|
||||
Mutex()
|
||||
@ -51,6 +60,28 @@ internal object GroupSvc: BaseSvc() {
|
||||
private lateinit var METHOD_REQ_TROOP_MEM_LIST: Method
|
||||
private lateinit var METHOD_REQ_MODIFY_GROUP_NAME: Method
|
||||
|
||||
suspend fun getProhibitedMemberList(groupId: Long): Result<List<ProhibitedMemberInfo>> {
|
||||
val buffer = sendOidbAW("OidbSvc.0x899_0", 2201, 0, oidb_0x899.ReqBody().apply {
|
||||
uint64_group_code.set(groupId)
|
||||
uint64_start_uin.set(0)
|
||||
uint32_identify_flag.set(6)
|
||||
memberlist_opt.set(oidb_0x899.memberlist().apply {
|
||||
uint64_member_uin.set(0)
|
||||
uint32_shutup_timestap.set(0)
|
||||
})
|
||||
}.toByteArray()) ?: return Result.failure(RuntimeException("[oidb] timeout"))
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
body.mergeFrom(buffer.slice(4))
|
||||
if(body.uint32_result.get() != 0) {
|
||||
return Result.failure(RuntimeException(body.str_error_msg.get()))
|
||||
}
|
||||
|
||||
val resp = oidb_0x899.RspBody().mergeFrom(body.bytes_bodybuffer.get().toByteArray())
|
||||
return Result.success(resp.rpt_memberlist.get().map {
|
||||
ProhibitedMemberInfo(it.uint64_member_uin.get(), it.uint32_shutup_timestap.get())
|
||||
})
|
||||
}
|
||||
|
||||
fun poke(groupId: String, userId: String) {
|
||||
sendOidb("OidbSvc.0xed3", 3795, 1, protobufOf(
|
||||
1 to userId.toLong(),
|
||||
@ -68,6 +99,12 @@ internal object GroupSvc: BaseSvc() {
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
getGroupInfo(groupId, true).onSuccess {
|
||||
if(it.wMemberNum > memberList.size) {
|
||||
return getGroupMemberList(groupId, true)
|
||||
}
|
||||
}
|
||||
|
||||
return Result.success(memberList)
|
||||
}
|
||||
|
||||
@ -107,7 +144,7 @@ internal object GroupSvc: BaseSvc() {
|
||||
val memberInfo = Oidb_0x8fc.MemberInfo()
|
||||
memberInfo.uint64_uin.set(userId.toLong())
|
||||
memberInfo.bytes_uin_name.set(ByteStringMicro.copyFromUtf8(localMemberInfo.troopnick.ifBlank {
|
||||
localMemberInfo.troopremark
|
||||
localMemberInfo.troopremark.ifNullOrEmpty("")
|
||||
}))
|
||||
memberInfo.bytes_special_title.set(ByteStringMicro.copyFromUtf8(title))
|
||||
memberInfo.uint32_special_title_expire_time.set(-1)
|
||||
@ -133,6 +170,49 @@ internal object GroupSvc: BaseSvc() {
|
||||
return true
|
||||
}
|
||||
|
||||
suspend fun setEssenceMessage(groupId: Long, seq: Long, rand: Long): Pair<Boolean, String> {
|
||||
val array = protobufOf(
|
||||
1 to groupId,
|
||||
2 to seq,
|
||||
3 to rand
|
||||
).toByteArray()
|
||||
val buffer = sendOidbAW("OidbSvc.0xeac_1", 3756, 1, array)
|
||||
?: return Pair(false, "unknown error")
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
body.mergeFrom(buffer.slice(4))
|
||||
val result = ProtoUtils.decodeFromByteArray(body.bytes_bodybuffer.get().toByteArray())
|
||||
return if (result.has(1)) {
|
||||
LogCenter.log("设置群精华失败: ${result[1].asUtf8String}")
|
||||
Pair(false, "设置群精华失败: ${result[1].asUtf8String}")
|
||||
} else {
|
||||
LogCenter.log("设置群精华 -> $groupId:$seq")
|
||||
Pair(true, "ok")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteEssenceMessage(groupId: Long, seq: Long, rand: Long): Pair<Boolean, String> {
|
||||
val array = protobufOf(
|
||||
1 to groupId,
|
||||
2 to seq,
|
||||
3 to rand
|
||||
).toByteArray()
|
||||
val buffer = sendOidbAW("OidbSvc.0xeac_2", 3756, 2, array)
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
if (buffer == null) {
|
||||
return Pair(false, "unknown error")
|
||||
}
|
||||
body.mergeFrom(buffer.slice(4))
|
||||
val result = ProtoUtils.decodeFromByteArray(body.bytes_bodybuffer.get().toByteArray())
|
||||
return if (result.has(1)) {
|
||||
LogCenter.log("移除群精华失败: ${result[1].asUtf8String}")
|
||||
Pair(false, "移除群精华失败: ${result[1].asUtf8String}")
|
||||
} else {
|
||||
LogCenter.log("移除群精华 -> $groupId:$seq")
|
||||
Pair(true, "ok")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setGroupAdmin(groupId: Long, userId: Long, enable: Boolean) {
|
||||
val buffer = ByteBuffer.allocate(9)
|
||||
buffer.putBuf32Long(groupId)
|
||||
@ -518,4 +598,120 @@ internal object GroupSvc: BaseSvc() {
|
||||
Result.failure(Exception("获取群成员信息失败"))
|
||||
}
|
||||
}
|
||||
|
||||
// ProfileService.Pb.ReqSystemMsgAction.Group
|
||||
suspend fun requestGroupRequest(
|
||||
msgSeq: Long,
|
||||
uin: Long,
|
||||
gid: Long,
|
||||
msg: String? = "",
|
||||
approve: Boolean? = true,
|
||||
notSee: Boolean? = false,
|
||||
subType: String
|
||||
): Result<String>{
|
||||
// val app = AppRuntimeFetcher.appRuntime
|
||||
// if (app !is AppInterface)
|
||||
// throw RuntimeException("AppRuntime cannot cast to AppInterface")
|
||||
// val service = QRoute.api(IAddFriendTempApi::class.java)
|
||||
// val action = `structmsg$SystemMsgActionInfo`()
|
||||
// action.type.set(if (approve != false) 11 else 12)
|
||||
// action.group_code.set(gid)
|
||||
// action.msg.set(msg)
|
||||
// val snInfo = `structmsg$AddFrdSNInfo`()
|
||||
// snInfo.uint32_not_see_dynamic.set(if (notSee != false) 1 else 0)
|
||||
//// snInfo.uint32_set_sn.set(0)
|
||||
// action.addFrdSNInfo.set(snInfo)
|
||||
// service.sendFriendSystemMsgAction(2, msgSeq * 1000, uin, 1, 2, 30024, 1, action, 0, `structmsg$StructMsg`(), false,
|
||||
// app
|
||||
// )
|
||||
// 实在找不到接口了 发pb吧
|
||||
val buffer: ByteArray
|
||||
when (subType) {
|
||||
"invite" -> {
|
||||
buffer = protobufOf(
|
||||
1 to 1,
|
||||
2 to msgSeq,
|
||||
3 to uin, // self
|
||||
4 to 1,
|
||||
5 to 3,
|
||||
6 to 10016,
|
||||
7 to 2,
|
||||
8 to mapOf(
|
||||
1 to if (approve != false) 11 else 12,
|
||||
2 to gid
|
||||
),
|
||||
9 to 1000
|
||||
).toByteArray()
|
||||
}
|
||||
"add" -> {
|
||||
buffer = protobufOf(
|
||||
1 to 2,
|
||||
2 to msgSeq,
|
||||
3 to uin,
|
||||
4 to 1,
|
||||
5 to 2,
|
||||
6 to 30024,
|
||||
7 to 1,
|
||||
8 to mapOf(
|
||||
1 to if (approve != false) 11 else 12,
|
||||
2 to gid
|
||||
),
|
||||
9 to 1000
|
||||
).toByteArray()
|
||||
}
|
||||
else -> {
|
||||
return Result.failure(Exception("不支持的sub_type"))
|
||||
}
|
||||
}
|
||||
val respBuffer = sendBufferAW("ProfileService.Pb.ReqSystemMsgAction.Group", true, buffer)
|
||||
?: return Result.failure(Exception("操作失败"))
|
||||
val result = ProtoUtils.decodeFromByteArray(respBuffer.slice(4))
|
||||
return if (result.has(1, 1)) {
|
||||
if (result[1, 1].asInt == 0) {
|
||||
Result.success(result[2].asUtf8String)
|
||||
} else {
|
||||
Result.failure(Exception(result[2].asUtf8String))
|
||||
}
|
||||
} else {
|
||||
Result.failure(Exception("操作失败"))
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun requestGroupSystemMsgNew(msgNum: Int, latestFriendSeq: Long, latestGroupSeq: Long): List<StructMsg>? {
|
||||
val req = ReqSystemMsgNew()
|
||||
req.msg_num.set(msgNum)
|
||||
req.latest_friend_seq.set(latestFriendSeq)
|
||||
req.latest_group_seq.set(latestGroupSeq)
|
||||
req.version.set(1000)
|
||||
req.checktype.set(3)
|
||||
val flag = FlagInfo()
|
||||
flag.GrpMsg_Kick_Admin.set(1)
|
||||
flag.GrpMsg_HiddenGrp.set(1)
|
||||
flag.GrpMsg_WordingDown.set(1)
|
||||
// flag.FrdMsg_GetBusiCard.set(1)
|
||||
flag.GrpMsg_GetOfficialAccount.set(1)
|
||||
flag.GrpMsg_GetPayInGroup.set(1)
|
||||
flag.FrdMsg_Discuss2ManyChat.set(1)
|
||||
flag.GrpMsg_NotAllowJoinGrp_InviteNotFrd.set(1)
|
||||
flag.FrdMsg_NeedWaitingMsg.set(1)
|
||||
// flag.FrdMsg_uint32_need_all_unread_msg.set(1)
|
||||
flag.GrpMsg_NeedAutoAdminWording.set(1)
|
||||
flag.GrpMsg_get_transfer_group_msg_flag.set(1)
|
||||
flag.GrpMsg_get_quit_pay_group_msg_flag.set(1)
|
||||
flag.GrpMsg_support_invite_auto_join.set(1)
|
||||
flag.GrpMsg_mask_invite_auto_join.set(1)
|
||||
flag.GrpMsg_GetDisbandedByAdmin.set(1)
|
||||
flag.GrpMsg_GetC2cInviteJoinGroup.set(1)
|
||||
req.flag.set(flag)
|
||||
req.is_get_frd_ribbon.set(false)
|
||||
req.is_get_grp_ribbon.set(false)
|
||||
req.friend_msg_type_flag.set(1)
|
||||
req.uint32_req_msg_type.set(1)
|
||||
req.uint32_need_uid.set(1)
|
||||
val respBuffer = sendBufferAW("ProfileService.Pb.ReqSystemMsgNew.Group", true, req.toByteArray())
|
||||
?: return ArrayList()
|
||||
val msg = RspSystemMsgNew()
|
||||
msg.mergeFrom(respBuffer.slice(4))
|
||||
return msg.groupmsgs.get()
|
||||
}
|
||||
}
|
@ -1,23 +1,62 @@
|
||||
@file:OptIn(DelicateCoroutinesApi::class)
|
||||
|
||||
package moe.fuqiuluo.qqinterface.servlet
|
||||
|
||||
import com.tencent.mobileqq.qroute.QRoute
|
||||
import com.tencent.mobileqq.troop.api.ITroopMemberNameService
|
||||
import com.tencent.qqnt.kernel.api.IKernelService
|
||||
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.TempChatPrepareInfo
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.time.withTimeoutOrNull
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import moe.fuqiuluo.proto.protobufOf
|
||||
import moe.fuqiuluo.shamrock.helper.ContactHelper
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.msgService
|
||||
import java.util.UUID
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
internal object MsgSvc: BaseSvc() {
|
||||
fun uploadForwardMsg(): Result<String> {
|
||||
return Result.failure(Exception("Not implemented"))
|
||||
}
|
||||
|
||||
suspend fun prepareTempChatFromGroup(
|
||||
groupId: String,
|
||||
peerId: String
|
||||
): Result<Unit> {
|
||||
LogCenter.log("主动临时消息,创建临时会话。", Level.INFO)
|
||||
val msgService = app.getRuntimeService(IKernelService::class.java, "all").msgService
|
||||
?: return Result.failure(Exception("获取消息服务失败"))
|
||||
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()
|
||||
)) { code, reason ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("临时会话创建失败: $code, $reason", Level.ERROR)
|
||||
}
|
||||
}
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
/**
|
||||
* 正常获取
|
||||
*/
|
||||
@ -51,6 +90,34 @@ internal object MsgSvc: BaseSvc() {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getMsgByQMsgId(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
qqMsgId: Long
|
||||
): Result<MsgRecord> {
|
||||
val contact = MessageHelper.generateContact(chatType, peerId)
|
||||
val service = QRoute.api(IMsgService::class.java) ?:
|
||||
return Result.failure(Exception("获取消息服务"))
|
||||
|
||||
val msg = withTimeoutOrNull(5000) {
|
||||
suspendCoroutine { continuation ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(qqMsgId)) { code, _, msgRecords ->
|
||||
if (code == 0 && msgRecords.isNotEmpty()) {
|
||||
continuation.resume(msgRecords.first())
|
||||
} else {
|
||||
continuation.resume(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if (msg != null) {
|
||||
Result.success(msg)
|
||||
} else {
|
||||
Result.failure(Exception("获取消息失败"))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 什么鸟屎都获取不到
|
||||
*/
|
||||
@ -60,7 +127,7 @@ internal object MsgSvc: BaseSvc() {
|
||||
seq: Long
|
||||
): Result<MsgRecord> {
|
||||
val contact = MessageHelper.generateContact(chatType, peerId)
|
||||
val msg = withTimeoutOrNull(60 * 1000) {
|
||||
val msg = withTimeoutOrNull(1000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
service.getMsgsBySeqs(contact, arrayListOf(seq)) { code, _, msgRecords ->
|
||||
@ -103,10 +170,64 @@ internal object MsgSvc: BaseSvc() {
|
||||
*
|
||||
* Aio 腾讯内部命名 All In One
|
||||
*/
|
||||
suspend fun sendToAio(chatType: Int, peedId: String, message: JsonArray): Pair<Long, Int> {
|
||||
suspend fun sendToAio(
|
||||
chatType: Int,
|
||||
peedId: String,
|
||||
message: JsonArray,
|
||||
fromId: String = peedId
|
||||
): Pair<Long, Int> {
|
||||
//LogCenter.log(message.toString(), Level.ERROR)
|
||||
//callback.msgHash = result.second 什么垃圾代码,万一cb比你快,你不就寄了?
|
||||
return MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, MessageCallback(peedId, 0))
|
||||
|
||||
// 主动临时消息
|
||||
when(chatType) {
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> {
|
||||
prepareTempChatFromGroup(fromId, peedId).onFailure {
|
||||
LogCenter.log("主动临时消息,创建临时会话失败。", Level.ERROR)
|
||||
return -1L to 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, MessageCallback(peedId, 0), fromId)
|
||||
}
|
||||
|
||||
suspend fun getMultiMsg(resId: String): Result<List<MsgRecord>> {
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val msgService = sessionService.msgService
|
||||
val contact = MessageHelper.generateContact(MsgConstant.KCHATTYPEC2C, TicketSvc.getUin())
|
||||
|
||||
val content = "{\"app\":\"com.tencent.multimsg\",\"config\":{\"autosize\":1,\"forward\":1,\"round\":1,\"type\":\"normal\",\"width\":300},\"desc\":\"[聊天记录]\",\"extra\":\"\",\"meta\":{\"detail\":{\"news\":[{\"text\":\"Shamrock: 这是条假消息!\"}],\"resid\":\"$resId\",\"source\":\"聊天记录\",\"summary\":\"转发消息\",\"uniseq\":\"${UUID.randomUUID()}\"}},\"prompt\":\"[聊天记录]\",\"ver\":\"0.0.0.5\",\"view\":\"contact\"}"
|
||||
val msgId = PacketSvc.fakeSelfRecvJsonMsg(msgService, content)
|
||||
if (msgId < 0) {
|
||||
return Result.failure(Exception("获取合并转发消息ID失败"))
|
||||
}
|
||||
val msgList = withTimeoutOrNull(5000L) {
|
||||
suspendCancellableCoroutine<ArrayList<MsgRecord>> {
|
||||
val job = GlobalScope.launch {
|
||||
var hasResult = false
|
||||
while (!hasResult) {
|
||||
msgService.getMultiMsg(contact, msgId, msgId) { code, why, msgList ->
|
||||
if (code == 0) {
|
||||
it.resume(msgList)
|
||||
hasResult = true
|
||||
} else {
|
||||
LogCenter.log("获取合并转发消息失败: $code($why): $msgId", Level.ERROR)
|
||||
}
|
||||
}
|
||||
delay(200)
|
||||
}
|
||||
}
|
||||
it.invokeOnCancellation {
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
} ?: return Result.failure(Exception("获取合并转发消息失败"))
|
||||
|
||||
//msgService.deleteMsg(contact, arrayListOf(msgId), null)
|
||||
|
||||
return Result.success(msgList)
|
||||
}
|
||||
|
||||
class MessageCallback(
|
||||
|
@ -0,0 +1,98 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet
|
||||
|
||||
import com.tencent.mobileqq.msf.core.MsfCore
|
||||
import com.tencent.qqnt.kernel.nativeinterface.Contact
|
||||
import com.tencent.qqnt.kernel.nativeinterface.IKernelMsgService
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import io.ktor.utils.io.core.BytePacketBuilder
|
||||
import io.ktor.utils.io.core.readBytes
|
||||
import io.ktor.utils.io.core.writeFully
|
||||
import io.ktor.utils.io.core.writeInt
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.proto.protobufOf
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetHistoryMsg
|
||||
import moe.fuqiuluo.shamrock.remote.service.listener.AioListener
|
||||
import moe.fuqiuluo.shamrock.tools.broadcast
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import mqq.app.MobileQQ
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.math.abs
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextInt
|
||||
import kotlin.random.nextLong
|
||||
|
||||
internal object PacketSvc: BaseSvc() {
|
||||
/**
|
||||
* 伪造收到Json卡片消息
|
||||
*/
|
||||
suspend fun fakeSelfRecvJsonMsg(msgService: IKernelMsgService, content: String): Long {
|
||||
return fakeReceiveSelfMsg(msgService) { arrayOf(
|
||||
mapOf(
|
||||
51 to 1 to (byteArrayOf(1) + DeflateTools.compress(content.toByteArray()))
|
||||
)
|
||||
) }
|
||||
}
|
||||
|
||||
private suspend fun fakeReceiveSelfMsg(msgService: IKernelMsgService, builder: () -> Array<Map<*, *>>): Long {
|
||||
val latestMsg = withTimeoutOrNull(3000) {
|
||||
suspendCancellableCoroutine {
|
||||
msgService.getMsgs(Contact(MsgConstant.KCHATTYPEC2C, app.currentUid, ""), 0L, 1, true) { code, why, msgs ->
|
||||
it.resume(GetHistoryMsg.GetMsgResult(code, why, msgs))
|
||||
}
|
||||
}
|
||||
}?.data?.firstOrNull()
|
||||
val msgSeq = (latestMsg?.msgSeq ?: 0) + 1
|
||||
fakeReceive("trpc.msg.olpush.OlPushService.MsgPush", 10000, protobufOf(
|
||||
1 to mapOf(
|
||||
1 to mapOf(
|
||||
1 to app.currentUin.toLong(),
|
||||
2 to app.currentUid,
|
||||
3 to 1001,
|
||||
5 to app.currentUin.toLong(),
|
||||
6 to app.currentUid
|
||||
),
|
||||
2 to mapOf(
|
||||
1 to 166,
|
||||
3 to 11,
|
||||
4 to msgSeq,
|
||||
5 to msgSeq,
|
||||
6 to (System.currentTimeMillis() / 1000).toInt(),
|
||||
7 to 1,
|
||||
11 to msgSeq,
|
||||
12 to msgService.getMsgUniqueId(System.currentTimeMillis()),
|
||||
14 to msgSeq - 2,
|
||||
28 to msgSeq
|
||||
),
|
||||
3 to 1 to 2 to builder()
|
||||
)
|
||||
).toByteArray())
|
||||
return withTimeoutOrNull(5000L) {
|
||||
suspendCancellableCoroutine {
|
||||
AioListener.messageLessListenerMap[msgSeq] = {
|
||||
it.resume(this.msgId)
|
||||
}
|
||||
}
|
||||
} ?: -1L
|
||||
}
|
||||
|
||||
/**
|
||||
* 伪造QQ收到某个包
|
||||
*/
|
||||
private fun fakeReceive(cmd: String, seq: Int, buffer: ByteArray) {
|
||||
MobileQQ.getContext().broadcast("msf") {
|
||||
putExtra("__cmd", "fake_packet")
|
||||
putExtra("package_cmd", cmd)
|
||||
putExtra("package_uin", app.currentUin)
|
||||
putExtra("package_seq", seq)
|
||||
val wupBuffer = BytePacketBuilder().apply {
|
||||
writeInt(buffer.size + 4)
|
||||
writeFully(buffer)
|
||||
}.build()
|
||||
putExtra("package_buffer", wupBuffer.readBytes())
|
||||
wupBuffer.release()
|
||||
}
|
||||
}
|
||||
}
|
@ -43,6 +43,10 @@ internal object TicketSvc: BaseSvc() {
|
||||
return app.currentUin.ifBlank { "0" }
|
||||
}
|
||||
|
||||
fun getLongUin(): Long {
|
||||
return app.longAccountUin
|
||||
}
|
||||
|
||||
fun getCookie(): String {
|
||||
val uin = getUin()
|
||||
val skey = getRealSkey(uin)
|
||||
|
@ -86,10 +86,10 @@ internal object VisitorSvc: BaseSvc() {
|
||||
it.putLong(moe.fuqiuluo.shamrock.remote.service.data.profile.ProfileProtocolConst.PARAM_TARGET_UIN, target)
|
||||
it.putByteArray("vCookies", card.vCookies)
|
||||
it.putBoolean("nearby_people", true)
|
||||
it.putInt("favoriteSource", SUB_FROM_SHARE_CARD_TROOP)
|
||||
it.putInt("favoriteSource", FROM_CONTACTS_TAB)
|
||||
it.putInt("iCount", count)
|
||||
it.putInt("from", FROM_SHARE_CARD)
|
||||
it.putInt("from", FROM_CONTACTS_TAB)
|
||||
}
|
||||
return Result.success(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.entries
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class FileUrl(
|
||||
@SerialName("url") val url: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GroupFileList(
|
||||
@SerialName("files") val files: List<FileInfo>,
|
||||
@SerialName("folders") val folders: List<FolderInfo>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FileInfo(
|
||||
@SerialName("group_id") val groupId: Long,
|
||||
@SerialName("file_id") val fileId: String,
|
||||
@SerialName("file_name") val fileName: String,
|
||||
@SerialName("file_size") val fileSize: Long,
|
||||
@SerialName("busid") val busid: Int,
|
||||
@SerialName("upload_time") val uploadTime: Int,
|
||||
@SerialName("dead_time") val deadTime: Int,
|
||||
@SerialName("modify_time") val modifyTime: Int,
|
||||
@SerialName("download_times") val downloadTimes: Int,
|
||||
@SerialName("uploader") val uploadUin: Long,
|
||||
@SerialName("upload_name") val uploadNick: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FolderInfo(
|
||||
@SerialName("group_id") val groupId: Long,
|
||||
@SerialName("folder_id") val folderId: String,
|
||||
@SerialName("folder_name") val folderName: String,
|
||||
@SerialName("total_file_count") val totalFileCount: Int,
|
||||
@SerialName("create_time") val createTime: Int,
|
||||
@SerialName("creator") val creator: Long,
|
||||
@SerialName("creator_name") val creatorNick: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FileSystemInfo(
|
||||
@SerialName("file_count") val fileCount: Int,
|
||||
@SerialName("limit_count") val fileLimitCount: Int,
|
||||
@SerialName("used_space") val usedSpace: Long,
|
||||
@SerialName("total_space") val totalSpace: Long,
|
||||
)
|
@ -0,0 +1,10 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.entries
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal data class ProhibitedMemberInfo(
|
||||
@SerialName("user_id") val memberUin: Long,
|
||||
@SerialName("time") val shutuptimestap: Int
|
||||
)
|
@ -1,103 +0,0 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.msg
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||
import moe.fuqiuluo.proto.ProtoUtils
|
||||
import moe.fuqiuluo.proto.asUtf8String
|
||||
import moe.fuqiuluo.proto.protobufOf
|
||||
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
|
||||
import moe.fuqiuluo.shamrock.tools.slice
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
|
||||
internal object LongMsgHelper: BaseSvc() {
|
||||
private const val GROUP_LONG_MSG_CMD = "trpc.group.long_msg_interface.MsgService.SsoSendLongMsg"
|
||||
|
||||
suspend fun uploadGroupMsg(groupId: String, msgs: List<MsgRecord>): String {
|
||||
val reqBody = protobufOf(
|
||||
2 to mapOf(
|
||||
1 to 3,
|
||||
2 to 2 to groupId,
|
||||
3 to groupId.toLong(),
|
||||
4 to DeflateTools.gzip(toGroupByteArray(msgs))
|
||||
),
|
||||
15 to mapOf(
|
||||
1 to 4,
|
||||
2 to 2,
|
||||
3 to 9,
|
||||
4 to 0
|
||||
)
|
||||
).toByteArray()
|
||||
val buffer = sendBufferAW(GROUP_LONG_MSG_CMD, true, reqBody)
|
||||
?: error("获取消息资源ID失败")
|
||||
val pb = ProtoUtils.decodeFromByteArray(buffer.slice(4))
|
||||
return pb[2, 3].asUtf8String
|
||||
}
|
||||
|
||||
private fun toGroupByteArray(msgs: List<MsgRecord>): ByteArray {
|
||||
return protobufOf(
|
||||
2 to mapOf(
|
||||
1 to "MultiMsg",
|
||||
2 to 1 to msgs.map { record ->
|
||||
mapOf(
|
||||
1 to mapOf(
|
||||
2 to record.senderUid,
|
||||
8 to mapOf(
|
||||
1 to record.peerUin,
|
||||
4 to record.sendNickName,
|
||||
5 to 2
|
||||
)
|
||||
),
|
||||
2 to mapOf(
|
||||
1 to 82,
|
||||
4 to record.msgRandom,
|
||||
5 to record.msgSeq,
|
||||
6 to record.msgTime,
|
||||
7 to 1,
|
||||
8 to 0,
|
||||
9 to 0,
|
||||
15 to mapOf(
|
||||
1 to 0,
|
||||
2 to 0,
|
||||
3 to 0,
|
||||
4 to "",
|
||||
5 to ""
|
||||
)
|
||||
),
|
||||
3 to mapOf(
|
||||
1 to 2 to (record.elements.map {
|
||||
when (val type = it.elementType) {
|
||||
MsgConstant.KELEMTYPETEXT -> mapOf(1 to 1 to it.textElement.content)
|
||||
|
||||
else -> error("不支持的合并转发消息类型: $type")
|
||||
}
|
||||
} as ArrayList<Any>).also {
|
||||
it.add(0, mapOf(
|
||||
37 to mapOf(
|
||||
1 to 8,
|
||||
16 to 0,
|
||||
17 to 0,
|
||||
19 to mapOf(
|
||||
15 to 65536,
|
||||
25 to 0,
|
||||
30 to 0,
|
||||
31 to 0,
|
||||
34 to 0,
|
||||
41 to 0,
|
||||
52 to 64,
|
||||
54 to 1,
|
||||
55 to 0,
|
||||
72 to 0,
|
||||
73 to 1 to 0,
|
||||
96 to 0
|
||||
)
|
||||
)
|
||||
))
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
).toByteArray()
|
||||
}
|
||||
|
||||
}
|
@ -95,9 +95,27 @@ internal object MessageMaker {
|
||||
"reply" to MessageMaker::createReplyElem,
|
||||
"touch" to MessageMaker::createTouchElem,
|
||||
"weather" to MessageMaker::createWeatherElem,
|
||||
"json" to MessageMaker::createJsonElem,
|
||||
//"multi_msg" to MessageMaker::createLongMsgStruct,
|
||||
)
|
||||
|
||||
private suspend fun createJsonElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("data")
|
||||
val jsonStr = data["data"].let {
|
||||
if (it is JsonObject) it.asJsonObject.toString() else it.asString
|
||||
}
|
||||
val element = MsgElement()
|
||||
element.elementType = MsgConstant.KELEMTYPEARKSTRUCT
|
||||
val ark = ArkElement(jsonStr, null, null)
|
||||
element.arkElement = ark
|
||||
return Result.success(element)
|
||||
}
|
||||
|
||||
private suspend fun createTouchElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
@ -539,7 +557,7 @@ internal object MessageMaker {
|
||||
file = FileUtils.parseAndSave(data["url"].asString)
|
||||
}
|
||||
if (!file.exists()) {
|
||||
throw LogicException("Voice(${file.name}) file is not exists, please check your filename.")
|
||||
return Result.failure(LogicException("Voice(${file.name}) file is not exists, please check your filename."))
|
||||
}
|
||||
val isMagic = data["magic"].asStringOrNull == "1"
|
||||
|
||||
@ -580,11 +598,14 @@ internal object MessageMaker {
|
||||
// QQNTWrapperUtil.CppProxy.copyFile(file.absolutePath, originalPath)
|
||||
//}
|
||||
|
||||
Transfer with when (chatType) {
|
||||
if(!(Transfer with when (chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> Troop(peerId)
|
||||
MsgConstant.KCHATTYPEC2C -> Private(peerId)
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> Private(peerId)
|
||||
else -> error("Not supported chatType($chatType) for RecordMsg")
|
||||
} trans VoiceResource(file)
|
||||
} trans VoiceResource(file))) {
|
||||
return Result.failure(RuntimeException("上传语音失败: $file"))
|
||||
}
|
||||
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEPTT
|
||||
|
@ -52,7 +52,9 @@ internal object MessageConvert {
|
||||
MsgConstant.KELEMTYPEARKSTRUCT to MessageElemConverter.StructJsonConverter,
|
||||
MsgConstant.KELEMTYPEREPLY to MessageElemConverter.ReplyConverter,
|
||||
MsgConstant.KELEMTYPEGRAYTIP to MessageElemConverter.GrayTipsConverter,
|
||||
MsgConstant.KELEMTYPEFILE to MessageElemConverter.FileConverter
|
||||
MsgConstant.KELEMTYPEFILE to MessageElemConverter.FileConverter,
|
||||
//MsgConstant.KELEMTYPEMULTIFORWARD to MessageElemConverter.XmlMultiMsgConverter,
|
||||
//MsgConstant.KELEMTYPESTRUCTLONGMSG to MessageElemConverter.XmlLongMsgConverter,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -143,13 +143,15 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val video = element.videoElement
|
||||
val md5 = video.fileName.split(".")[0]
|
||||
|
||||
return MessageSegment(
|
||||
type = "video",
|
||||
data = hashMapOf(
|
||||
"file" to video.fileName,
|
||||
"url" to when(chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupVideoDownUrl("0", video.fileName, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CVideoDownUrl("0", video.fileName, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupVideoDownUrl("0", md5, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CVideoDownUrl("0", md5, video.fileUuid)
|
||||
else -> unknownChatType(chatType)
|
||||
}
|
||||
).also {
|
||||
@ -194,6 +196,15 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
): MessageSegment {
|
||||
val data = element.arkElement.bytesData.asJsonObject
|
||||
return when (data["app"].asString) {
|
||||
"com.tencent.multimsg" -> {
|
||||
val info = data["meta"].asJsonObject["detail"].asJsonObject
|
||||
MessageSegment(
|
||||
type = "forward",
|
||||
data = mapOf(
|
||||
"id" to info["resid"].asString
|
||||
)
|
||||
)
|
||||
}
|
||||
"com.tencent.troopsharecard" -> {
|
||||
val info = data["meta"].asJsonObject["contact"].asJsonObject
|
||||
MessageSegment(
|
||||
@ -229,7 +240,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
else -> MessageSegment(
|
||||
type = "json",
|
||||
data = mapOf(
|
||||
"data" to element.arkElement.bytesData.asJsonObject
|
||||
"data" to element.arkElement.bytesData.asJsonObject.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -252,7 +263,11 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
} else {
|
||||
MessageDB.getInstance().messageMappingDao()
|
||||
.queryByMsgSeq(chatType, peerId, reply.replayMsgSeq?.toInt() ?: 0)?.msgHashId
|
||||
?: MessageHelper.generateMsgIdHash(chatType, reply.sourceMsgIdInRecords)
|
||||
?:
|
||||
kotlin.run {
|
||||
LogCenter.log("消息映射关系未找到: Message($reply)", Level.WARN)
|
||||
MessageHelper.generateMsgIdHash(chatType, reply.sourceMsgIdInRecords)
|
||||
}
|
||||
}
|
||||
|
||||
return MessageSegment(
|
||||
@ -307,8 +322,63 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
peerId: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
// 使用其他地方的推送,而不是使用消息
|
||||
throw UnknownError()
|
||||
val fileMsg = element.fileElement
|
||||
val fileName = fileMsg.fileName
|
||||
val fileSize = fileMsg.fileSize
|
||||
val expireTime = fileMsg.expireTime ?: 0
|
||||
val fileId = fileMsg.fileUuid
|
||||
val bizId = fileMsg.fileBizId
|
||||
val fileSubId = fileMsg.fileSubId ?: ""
|
||||
val url = if (chatType == MsgConstant.KCHATTYPEC2C) RichProtoSvc.getC2CFileDownUrl(fileId, fileSubId)
|
||||
else RichProtoSvc.getGroupFileDownUrl(peerId.toLong(), fileId, fileMsg.fileBizId)
|
||||
|
||||
return MessageSegment(
|
||||
type = "file",
|
||||
data = mapOf(
|
||||
"name" to fileName,
|
||||
"size" to fileSize,
|
||||
"expire" to expireTime,
|
||||
"id" to fileId,
|
||||
"url" to url,
|
||||
"biz" to bizId,
|
||||
"sub" to fileSubId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 老板QQ的合并转发信息
|
||||
*/
|
||||
object XmlMultiMsgConverter: MessageElemConverter() {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val multiMsg = element.multiForwardMsgElement
|
||||
return MessageSegment(
|
||||
type = "forward",
|
||||
data = mapOf(
|
||||
"id" to multiMsg.resId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object XmlLongMsgConverter: MessageElemConverter() {
|
||||
override suspend fun convert(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
element: MsgElement
|
||||
): MessageSegment {
|
||||
val longMsg = element.structLongMsgElement
|
||||
return MessageSegment(
|
||||
type = "forward",
|
||||
data = mapOf(
|
||||
"id" to longMsg.resId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.shamrock.utils.MD5
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import mqq.app.AppRuntime
|
||||
@ -73,30 +74,34 @@ internal abstract class FileTransfer {
|
||||
transferRequest: TransferRequest,
|
||||
wait: Boolean
|
||||
): Boolean {
|
||||
val service = runtime.getRuntimeService(ITransFileController::class.java, "all")
|
||||
if(service.transferAsync(transferRequest)) {
|
||||
if (!wait) { // 如果无需等待直接返回
|
||||
return true
|
||||
}
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
val waiter = GlobalScope.launch {
|
||||
while (
|
||||
service.findProcessor(transferRequest.keyForTransfer) != null
|
||||
// 如果上传处理器依旧存在,说明没有上传成功
|
||||
) {
|
||||
delay(100)
|
||||
return withTimeoutOrNull(60_000) {
|
||||
val service = runtime.getRuntimeService(ITransFileController::class.java, "all")
|
||||
if(service.transferAsync(transferRequest)) {
|
||||
if (!wait) { // 如果无需等待直接返回
|
||||
return@withTimeoutOrNull true
|
||||
}
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
GlobalScope.launch {
|
||||
while (
|
||||
//service.findProcessor(
|
||||
// transferRequest.keyForTransfer // uin + uniseq
|
||||
//) != null
|
||||
service.containsProcessor(runtime.currentAccountUin, transferRequest.mUniseq)
|
||||
// 如果上传处理器依旧存在,说明没有上传成功
|
||||
&& service.isWorking.get()
|
||||
) {
|
||||
delay(100)
|
||||
}
|
||||
continuation.resume(true)
|
||||
}
|
||||
// 实现取消上传器
|
||||
// 目前没什么用
|
||||
continuation.invokeOnCancellation {
|
||||
continuation.resume(false)
|
||||
}
|
||||
continuation.resume(true)
|
||||
}
|
||||
// 实现取消上传器
|
||||
// 目前没什么用
|
||||
continuation.invokeOnCancellation {
|
||||
waiter.cancel()
|
||||
continuation.resume(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
} else true
|
||||
} ?: false
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -63,24 +63,30 @@ internal object RichProtoSvc: BaseSvc() {
|
||||
suspend fun getC2CFileDownUrl(
|
||||
fileId: String,
|
||||
subId: String,
|
||||
retryCnt: Int = 0
|
||||
): String {
|
||||
val uid = ContactHelper.getUidByUinAsync(app.currentUin.toLong())
|
||||
val buffer = sendOidbAW("OidbSvcTrpcTcp.0xe37_1200", 3639, 1200, protobufOf(
|
||||
val buffer = sendOidbAW("OidbSvc.0xe37_1200", 3639, 1200, protobufOf(
|
||||
1 to 1200,
|
||||
2 to 1 /* QRoute.api(IAudioHelperApi::class.java).genDebugSeq().toInt() */, /* seq */
|
||||
14 to mapOf(
|
||||
10 to uid,
|
||||
10 to app.longAccountUin,
|
||||
20 to fileId,
|
||||
30 to 2, /* ver */
|
||||
60 to subId,
|
||||
601 to 0
|
||||
),
|
||||
101 to 3,
|
||||
101 to 3, // uint32_business_id
|
||||
102 to 104, /* client_type */
|
||||
200 to 1, /* url_type */
|
||||
99999 to 90200 to 1
|
||||
).toByteArray(), trpc = true)
|
||||
200 to 1, /* uint32_flag_support_mediaplatform */
|
||||
99999 to mapOf(
|
||||
90200 to 1 // uint32_download_url_type
|
||||
)
|
||||
).toByteArray())
|
||||
|
||||
if (buffer == null) {
|
||||
if (retryCnt < 3) {
|
||||
return getC2CFileDownUrl(fileId, subId, retryCnt + 1)
|
||||
}
|
||||
return ""
|
||||
} else {
|
||||
val body = oidb_sso.OIDBSSOPkg()
|
||||
|
@ -24,12 +24,12 @@ internal object Transfer: FileTransfer() {
|
||||
)
|
||||
|
||||
suspend fun uploadC2CVideo(
|
||||
groupId: String,
|
||||
userId: String,
|
||||
file: File,
|
||||
thumb: File,
|
||||
wait: Boolean = true
|
||||
): Boolean {
|
||||
return transC2CResource(groupId, file, FileMsg.TRANSFILE_TYPE_SHORT_VIDEO_C2C, BUSI_TYPE_SHORT_VIDEO, wait) {
|
||||
return transC2CResource(userId, file, FileMsg.TRANSFILE_TYPE_SHORT_VIDEO_C2C, BUSI_TYPE_SHORT_VIDEO, wait) {
|
||||
it.mSourceVideoCodecFormat = VIDEO_FORMAT_MP4
|
||||
it.mRec = MessageForShortVideo().also {
|
||||
it.busiType = BUSI_TYPE_SHORT_VIDEO
|
||||
@ -56,11 +56,11 @@ internal object Transfer: FileTransfer() {
|
||||
}
|
||||
|
||||
suspend fun uploadC2CVoice(
|
||||
groupId: String,
|
||||
userId: String,
|
||||
file: File,
|
||||
wait: Boolean = true
|
||||
): Boolean {
|
||||
return transC2CResource(groupId, file, FileMsg.TRANSFILE_TYPE_PTT, 1002, wait) {
|
||||
return transC2CResource(userId, file, FileMsg.TRANSFILE_TYPE_PTT, 1002, wait) {
|
||||
it.mPttUploadPanel = 3
|
||||
it.mPttCompressFinish = true
|
||||
it.mIsPttPreSend = true
|
||||
|
@ -23,25 +23,65 @@ import moe.fuqiuluo.shamrock.tools.jsonArray
|
||||
import kotlin.math.abs
|
||||
|
||||
internal object MessageHelper {
|
||||
suspend fun sendMessageWithoutMsgId(chatType: Int, peerId: String, message: JsonArray, callback: IOperateCallback): Pair<Long, Int> {
|
||||
suspend fun sendMessageWithoutMsgId(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
message: String,
|
||||
callback: IOperateCallback,
|
||||
fromId: String = peerId
|
||||
): Pair<Long, Int> {
|
||||
val uniseq = generateMsgId(chatType)
|
||||
val msg = messageArrayToMessageElements(chatType, uniseq.second, peerId, decodeCQCode(message)).also {
|
||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
||||
}.second.filter {
|
||||
it.elementType != -1
|
||||
} as ArrayList<MsgElement>
|
||||
return sendMessageWithoutMsgId(chatType, peerId, msg, callback, fromId)
|
||||
}
|
||||
|
||||
suspend fun sendMessageWithoutMsgId(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
message: JsonArray,
|
||||
callback: IOperateCallback,
|
||||
fromId: String = peerId
|
||||
): Pair<Long, Int> {
|
||||
val uniseq = generateMsgId(chatType)
|
||||
var nonMsg: Boolean
|
||||
val msg = messageArrayToMessageElements(chatType, uniseq.second, peerId, message).also {
|
||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
||||
}.second.filter {
|
||||
it.elementType != -1
|
||||
}.also {
|
||||
nonMsg = it.isEmpty()
|
||||
}
|
||||
} as ArrayList<MsgElement>
|
||||
return sendMessageWithoutMsgId(chatType, peerId, msg, callback, fromId)
|
||||
}
|
||||
|
||||
suspend fun sendMessageWithoutMsgId(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
message: ArrayList<MsgElement>,
|
||||
callback: IOperateCallback,
|
||||
fromId: String = peerId
|
||||
): Pair<Long, Int> {
|
||||
return sendMessageWithoutMsgId(generateContact(chatType, peerId, fromId), message, callback)
|
||||
}
|
||||
|
||||
fun sendMessageWithoutMsgId(
|
||||
contact: Contact,
|
||||
message: ArrayList<MsgElement>,
|
||||
callback: IOperateCallback
|
||||
): Pair<Long, Int> {
|
||||
val uniseq = generateMsgId(contact.chatType)
|
||||
val nonMsg: Boolean = message.isEmpty()
|
||||
return if (!nonMsg) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
if(callback is MsgSvc.MessageCallback) {
|
||||
callback.msgHash = uniseq.first
|
||||
}
|
||||
|
||||
service.sendMsg(
|
||||
generateContact(chatType, peerId),
|
||||
contact,
|
||||
uniseq.second,
|
||||
msg as ArrayList<MsgElement>,
|
||||
message,
|
||||
callback
|
||||
)
|
||||
System.currentTimeMillis() to uniseq.first
|
||||
@ -50,8 +90,66 @@ internal object MessageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun sendMessageWithMsgId(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
message: JsonArray,
|
||||
callback: IOperateCallback,
|
||||
fromId: String = peerId
|
||||
): Pair<Long, Int> {
|
||||
val uniseq = generateMsgId(chatType)
|
||||
val msg = messageArrayToMessageElements(chatType, uniseq.second, peerId, message).also {
|
||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
||||
}.second.filter {
|
||||
it.elementType != -1
|
||||
} as ArrayList<MsgElement>
|
||||
val contact = generateContact(chatType, peerId, fromId)
|
||||
val nonMsg: Boolean = message.isEmpty()
|
||||
return if (!nonMsg) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
if(callback is MsgSvc.MessageCallback) {
|
||||
callback.msgHash = uniseq.first
|
||||
}
|
||||
|
||||
service.sendMsg(
|
||||
contact,
|
||||
uniseq.second,
|
||||
msg,
|
||||
callback
|
||||
)
|
||||
uniseq.second to uniseq.first
|
||||
} else {
|
||||
uniseq.second to 0
|
||||
}
|
||||
}
|
||||
|
||||
fun sendMessageWithMsgId(
|
||||
contact: Contact,
|
||||
message: ArrayList<MsgElement>,
|
||||
callback: IOperateCallback
|
||||
): Pair<Long, Int> {
|
||||
val uniseq = generateMsgId(contact.chatType)
|
||||
val nonMsg: Boolean = message.isEmpty()
|
||||
return if (!nonMsg) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
if(callback is MsgSvc.MessageCallback) {
|
||||
callback.msgHash = uniseq.first
|
||||
}
|
||||
|
||||
service.sendMsg(
|
||||
contact,
|
||||
uniseq.second,
|
||||
message,
|
||||
callback
|
||||
)
|
||||
uniseq.second to uniseq.first
|
||||
} else {
|
||||
0L to 0
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun generateContact(chatType: Int, id: String, subId: String = ""): Contact {
|
||||
val peerId = if (MsgConstant.KCHATTYPEC2C == chatType) {
|
||||
val peerId = if (MsgConstant.KCHATTYPEC2C == chatType || MsgConstant.KCHATTYPETEMPC2CFROMGROUP == chatType) {
|
||||
ContactHelper.getUidByUinAsync(id.toLong())
|
||||
} else id
|
||||
return Contact(chatType, peerId, subId)
|
||||
@ -107,6 +205,7 @@ internal object MessageHelper {
|
||||
val key = when (chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> "grp$msgId"
|
||||
MsgConstant.KCHATTYPEC2C -> "c2c$msgId"
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> "tmpgrp$msgId"
|
||||
else -> error("不支持的消息来源类型 | generateMsgIdHash: $chatType")
|
||||
}
|
||||
return abs(key.hashCode())
|
||||
|
@ -29,6 +29,9 @@ interface MessageMappingDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insert(mapping: MessageMapping)
|
||||
|
||||
@Query("UPDATE message_mapping SET msgSeq = :msgSeq WHERE msgHashId = :hash")
|
||||
fun updateMsgSeqByMsgHash(hash: Int, msgSeq: Int)
|
||||
|
||||
@Query("DELETE FROM message_mapping WHERE msgHashId = :hash")
|
||||
fun deleteByMsgHash(hash: Int)
|
||||
|
||||
|
@ -62,11 +62,17 @@ internal object HTTPServer {
|
||||
weatherAction()
|
||||
otherAction()
|
||||
guildAction()
|
||||
testAction()
|
||||
requestRouter()
|
||||
if (ShamrockConfig.isDev()) {
|
||||
qsign()
|
||||
obtainProtocolData()
|
||||
}
|
||||
}
|
||||
|
||||
// intercept(ApplicationCallPipeline.Plugins) {
|
||||
// call.response.headers.appendIfAbsent("Content-Type", ContentType.Application.Json.toString())
|
||||
// }
|
||||
}
|
||||
|
||||
private fun ApplicationEngineEnvironmentBuilder.configSSL() {
|
||||
|
@ -18,6 +18,7 @@ internal object ActionManager {
|
||||
arrayOf(
|
||||
// Framework Info
|
||||
TestHandler, GetLatestEvents, GetSupportedActions, GetStatus, GetVersionInfo, GetSelfInfo, GetLoginInfo,
|
||||
SwitchAccount,
|
||||
|
||||
// UserActions
|
||||
GetProfileCard, GetFriendList, SendLike, GetUid, GetUinByUid, ScanQRCode, SetProfileCard,
|
||||
@ -29,16 +30,21 @@ internal object ActionManager {
|
||||
|
||||
// GroupActions
|
||||
ModifyTroopName, LeaveTroop, KickTroopMember, BanTroopMember, SetGroupWholeBan, SetGroupAdmin,
|
||||
ModifyTroopMemberName, SetGroupUnique, GetTroopHonor, GroupPoke,
|
||||
ModifyTroopMemberName, SetGroupUnique, GetTroopHonor, GroupPoke, SetEssenceMessage, DeleteEssenceMessage,
|
||||
GetGroupSystemMsg, GetProhibitedMemberList,
|
||||
|
||||
// MSG ACTIONS
|
||||
SendMessage, DeleteMessage, GetMsg, GetForwardMsg, SendGroupForwardMsg, SendGroupMessage, SendPrivateMessage,
|
||||
ClearMsgs, GetHistoryMsg, GetGroupMsgHistory, SendPrivateForwardMsg,
|
||||
|
||||
// RESOURCE ACTION
|
||||
GetRecord, GetImage, UploadGroupFile, CreateGroupFileFolder, DeleteGroupFolder,
|
||||
DeleteGroupFile, GetGroupFileSystemInfo, GetGroupRootFiles, GetGroupSubFiles,
|
||||
GetGroupFileUrl, UploadPrivateFile,
|
||||
|
||||
//REQUEST ACTION
|
||||
SetFriendAddRequest, SetGroupAddRequest,
|
||||
|
||||
// GUILD
|
||||
GetGuildServiceProfile,
|
||||
|
||||
@ -97,16 +103,16 @@ internal abstract class IActionHandler {
|
||||
return failed(Status.BadParam, why, echo)
|
||||
}
|
||||
|
||||
protected fun error(why: String, echo: JsonElement): String {
|
||||
return failed(Status.InternalHandlerError, why, echo)
|
||||
protected fun error(why: String, echo: JsonElement, arrayResult: Boolean = false): String {
|
||||
return failed(Status.InternalHandlerError, why, echo, arrayResult)
|
||||
}
|
||||
|
||||
protected fun logic(why: String, echo: JsonElement): String {
|
||||
return failed(Status.LogicError, why, echo)
|
||||
protected fun logic(why: String, echo: JsonElement, arraayResult: Boolean = false): String {
|
||||
return failed(Status.LogicError, why, echo, arraayResult)
|
||||
}
|
||||
|
||||
protected fun failed(status: Status, msg: String, echo: JsonElement): String {
|
||||
return resultToString(false, status, EmptyObject, msg, echo = echo)
|
||||
protected fun failed(status: Status, msg: String, echo: JsonElement, arrResult: Boolean = false): String {
|
||||
return resultToString(false, status, if (arrResult) EmptyJsonArray else EmptyJsonObject, msg, echo = echo)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
|
||||
internal object ClearMsgs: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val msgType = session.getString("message_type")
|
||||
val peerId = session.getString(if (msgType == "group") "group_id" else "user_id")
|
||||
return invoke(msgType, peerId, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
msgType: String,
|
||||
peerId: String,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val chatType = MessageHelper.obtainMessageTypeByDetailType(msgType)
|
||||
val contact = MessageHelper.generateContact(chatType, peerId, "")
|
||||
NTServiceFetcher.kernelService.wrapperSession.msgService.clearMsgRecords(contact, null)
|
||||
return ok(echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String>
|
||||
get() = arrayOf("message_type")
|
||||
|
||||
override fun path(): String = "clear_msgs"
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
|
||||
internal object DeleteEssenceMessage: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val messageId = session.getInt("message_id")
|
||||
return invoke(messageId, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(messageId: Int, echo: JsonElement = EmptyJsonString): String {
|
||||
val msg = MsgSvc.getMsg(messageId).onFailure {
|
||||
return logic("Obtain msg failed, please check your msg_id.", echo)
|
||||
}.getOrThrow()
|
||||
val (success, tip) = GroupSvc.deleteEssenceMessage(
|
||||
if (msg.chatType == MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0,
|
||||
msg.msgSeq,
|
||||
msg.msgRandom
|
||||
)
|
||||
return if (success) {
|
||||
ok("成功", echo)
|
||||
} else {
|
||||
logic(tip, echo)
|
||||
}
|
||||
}
|
||||
|
||||
override val alias: Array<String> = arrayOf("delete_essence_message")
|
||||
override fun path(): String = "delete_essence_msg"
|
||||
}
|
@ -14,10 +14,30 @@ internal object DeleteGroupFile: IActionHandler() {
|
||||
return invoke(groupId, fileId, busid, session.echo)
|
||||
}
|
||||
|
||||
/*
|
||||
suspend operator fun invoke(
|
||||
groupId: String,
|
||||
fileId: String,
|
||||
bizId: Int,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val result = FileSvc.deleteGroupFile(groupId, bizId, fileId)
|
||||
if(result.isFailure) {
|
||||
return error(result.exceptionOrNull()?.message ?: "删除群文件失败", echo)
|
||||
}
|
||||
val commonResult = result.getOrThrow()
|
||||
if (commonResult.first != 0 || commonResult.second.retCode != 0) {
|
||||
return error(commonResult.second.clientWording, echo)
|
||||
}
|
||||
return ok("成功", echo)
|
||||
}
|
||||
*/
|
||||
operator fun invoke(groupId: String, fileId: String, bizId: Int, echo: JsonElement = EmptyJsonString): String {
|
||||
FileSvc.deleteGroupFile(groupId, bizId, fileId)
|
||||
return ok("成功", echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("group_id", "file_id", "busid")
|
||||
|
||||
override fun path(): String = "delete_group_file"
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import android.util.Base64
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
@ -13,35 +14,72 @@ import moe.fuqiuluo.shamrock.utils.MD5
|
||||
|
||||
internal object DownloadFile: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val url = session.getString("url")
|
||||
val url = session.getStringOrNull("url")
|
||||
val name = session.getStringOrNull("name")
|
||||
val b64 = session.getStringOrNull("base64")
|
||||
val threadCnt = session.getIntOrNull("thread_cnt") ?: 3
|
||||
val headers = if (session.isArray("headers")) {
|
||||
val headers = if (session.has("headers")) (if (session.isArray("headers")) {
|
||||
session.getArray("headers").map {
|
||||
it.asString
|
||||
}
|
||||
} else {
|
||||
session.getString("headers").split("\r\n")
|
||||
}
|
||||
return invoke(url, threadCnt, headers, session.echo)
|
||||
}) else emptyList()
|
||||
return invoke(url, b64, threadCnt, headers, name, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
url: String,
|
||||
url: String?,
|
||||
base64: String?,
|
||||
threadCnt: Int,
|
||||
headers: List<String>,
|
||||
name: String?,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val headerMap = mutableMapOf(
|
||||
"User-Agent" to "Shamrock"
|
||||
)
|
||||
headers.forEach {
|
||||
val pair = it.split("=")
|
||||
if (pair.size >= 2) {
|
||||
val (k, v) = pair
|
||||
headerMap[k] = v
|
||||
if (url != null) {
|
||||
val headerMap = mutableMapOf(
|
||||
"User-Agent" to "Shamrock"
|
||||
)
|
||||
headers.forEach {
|
||||
val pair = it.split("=")
|
||||
if (pair.size >= 2) {
|
||||
val (k, v) = pair
|
||||
headerMap[k] = v
|
||||
}
|
||||
}
|
||||
return invoke(url, threadCnt, headerMap, echo)
|
||||
} else if (base64 != null) {
|
||||
return invoke(base64, name, echo)
|
||||
} else {
|
||||
return noParam("url/base64", echo)
|
||||
}
|
||||
return invoke(url, threadCnt, headerMap, echo)
|
||||
}
|
||||
|
||||
operator fun invoke(
|
||||
base64: String,
|
||||
name: String?,
|
||||
echo: JsonElement
|
||||
): String {
|
||||
kotlin.runCatching {
|
||||
val bytes = Base64.decode(base64, Base64.DEFAULT)
|
||||
FileUtils.getTmpFile("cache").also {
|
||||
it.writeBytes(bytes)
|
||||
}
|
||||
}.onSuccess {
|
||||
val tmp = if (name == null)
|
||||
FileUtils.renameByMd5(it)
|
||||
else it.parentFile!!.resolve(name).also { target ->
|
||||
it.renameTo(target)
|
||||
it.delete()
|
||||
}
|
||||
return ok(data = DownloadResult(
|
||||
file = tmp.absolutePath,
|
||||
md5 = MD5.genFileMd5Hex(tmp.absolutePath)
|
||||
), msg = "成功", echo = echo)
|
||||
}.onFailure {
|
||||
return logic("Base64格式错误", echo)
|
||||
}
|
||||
return logic("未知错误", echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
@ -70,8 +108,6 @@ internal object DownloadFile: IActionHandler() {
|
||||
}
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("url")
|
||||
|
||||
override fun path(): String = "download_file"
|
||||
|
||||
@Serializable
|
||||
|
@ -17,7 +17,7 @@ internal object GetCSRF: IActionHandler() {
|
||||
suspend operator fun invoke(domain: String, echo: JsonElement = EmptyJsonString): String {
|
||||
val uin = TicketSvc.getUin()
|
||||
val pskey = TicketSvc.getPSKey(uin, domain)
|
||||
?: return invoke()
|
||||
?: return invoke(echo)
|
||||
return ok(Credentials(bkn = TicketSvc.getCSRF(pskey)), echo)
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,61 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.convert.MessageConvert
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.MessageDetail
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.MessageSender
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
|
||||
internal object GetForwardMsg: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val id = session.getString("id")
|
||||
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val msgService = sessionService.msgService
|
||||
|
||||
return error("不支持实现,请提交ISSUE!", session.echo)
|
||||
return invoke(id, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
resId: String,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val result = MsgSvc.getMultiMsg(resId)
|
||||
if (result.isFailure) {
|
||||
return logic(result.exceptionOrNull().toString(), echo)
|
||||
}
|
||||
|
||||
return ok(data = GetForwardMsgResult(result.getOrThrow().map { msg ->
|
||||
val msgHash = MessageHelper.generateMsgIdHash(msg.chatType, msg.msgId)
|
||||
MessageDetail(
|
||||
time = msg.msgTime.toInt(),
|
||||
msgType = MessageHelper.obtainDetailTypeByMsgType(msg.chatType),
|
||||
msgId = msgHash,
|
||||
realId = msg.msgSeq.toInt(),
|
||||
sender = MessageSender(
|
||||
msg.senderUin, msg.sendNickName
|
||||
.ifBlank { msg.sendMemberName }
|
||||
.ifBlank { msg.sendRemarkName }
|
||||
.ifBlank { msg.peerName }, "unknown", 0, msg.senderUid
|
||||
),
|
||||
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||
it.toJson()
|
||||
},
|
||||
peerId = msg.peerUin,
|
||||
groupId = if (msg.chatType == MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0,
|
||||
targetId = if (msg.chatType != MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0
|
||||
)
|
||||
}), echo = echo)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class GetForwardMsgResult(
|
||||
@SerialName("messages") val msgs: List<MessageDetail>
|
||||
)
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("id")
|
||||
|
||||
override fun path(): String = "get_forward_msg"
|
||||
|
@ -16,7 +16,7 @@ internal object GetFriendList: IActionHandler() {
|
||||
|
||||
suspend operator fun invoke(refresh: Boolean, echo: JsonElement = EmptyJsonString): String {
|
||||
val friendList = FriendSvc.getFriendList(refresh).onFailure {
|
||||
return error(it.message ?: "unknown error", echo)
|
||||
return error(it.message ?: "unknown error", echo, arrayResult = true)
|
||||
}.getOrThrow()
|
||||
return ok(friendList.map { friend ->
|
||||
FriendEntry(
|
||||
|
@ -0,0 +1,24 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import moe.fuqiuluo.shamrock.helper.db.MessageDB
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
|
||||
internal object GetGroupMsgHistory: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val groupId = session.getString("group_id")
|
||||
val cnt = session.getIntOrNull("count") ?: 20
|
||||
val startId = session.getIntOrNull("message_seq")?.let {
|
||||
if (it == 0) return@let 0L
|
||||
MessageDB.getInstance()
|
||||
.messageMappingDao()
|
||||
.queryByMsgHashId(it)?.qqMsgId
|
||||
} ?: 0L
|
||||
return GetHistoryMsg("group", groupId, cnt, startId, session.echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String>
|
||||
get() = arrayOf("group_id")
|
||||
|
||||
override fun path(): String = "get_group_msg_history"
|
||||
}
|
@ -13,7 +13,10 @@ internal object GetGroupRootFiles: IActionHandler() {
|
||||
}
|
||||
|
||||
suspend operator fun invoke(groupId: String, echo: JsonElement = EmptyJsonString): String {
|
||||
return ok(FileSvc.getGroupRootFiles(groupId.toLong()), echo = echo)
|
||||
FileSvc.getGroupRootFiles(groupId.toLong()).onSuccess {
|
||||
return ok(it, echo = echo)
|
||||
}.getOrNull()
|
||||
return error(why = "获取失败,请查看日志", echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("group_id")
|
||||
|
@ -14,7 +14,10 @@ internal object GetGroupSubFiles: IActionHandler() {
|
||||
}
|
||||
|
||||
suspend operator fun invoke(groupId: String, folderId: String, echo: JsonElement = EmptyJsonString): String {
|
||||
return ok(FileSvc.getGroupFiles(groupId.toLong(), folderId), echo)
|
||||
FileSvc.getGroupFiles(groupId.toLong(), folderId).onSuccess {
|
||||
return ok(it, echo = echo)
|
||||
}.getOrNull()
|
||||
return error(why = "获取失败,请查看日志", echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("group_id", "folder_id")
|
||||
|
@ -0,0 +1,66 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.GroupRequest
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.GroupSystemMessage
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
|
||||
internal object GetGroupSystemMsg: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
return invoke(session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(echo: JsonElement = EmptyJsonString): String {
|
||||
val list = GroupSvc.requestGroupSystemMsgNew(20, 0, 0)
|
||||
val msgs = GroupSystemMessage(
|
||||
invited = mutableListOf(),
|
||||
join = mutableListOf()
|
||||
)
|
||||
list?.forEach {
|
||||
when(it.msg.group_msg_type.get()) {
|
||||
22, 1 -> {
|
||||
// join 进群消息
|
||||
msgs.join += GroupRequest (
|
||||
msgSeq = it.msg_seq.get(),
|
||||
invitorUin = it.msg.action_uin.get(),
|
||||
invitorNick = it.msg.action_uin_nick.get(),
|
||||
groupId = it.msg.group_code.get(),
|
||||
groupName = it.msg.group_name.get(),
|
||||
checked = it.msg.msg_decided.get().isNotBlank(),
|
||||
actor = it.msg.actor_uin.get(),
|
||||
requesterUin = it.req_uin.get(),
|
||||
requesterNick = it.msg.req_uin_nick.get(),
|
||||
message = it.msg.msg_additional.get(),
|
||||
flag = "${it.msg_seq.get()};${it.msg.group_code.get()};${it.req_uin.get()}"
|
||||
)
|
||||
}
|
||||
2 -> {
|
||||
// invite 别人邀请我
|
||||
msgs.invited += GroupRequest (
|
||||
msgSeq = it.msg_seq.get(),
|
||||
invitorUin = null,
|
||||
invitorNick = null,
|
||||
groupId = it.msg.group_code.get(),
|
||||
groupName = it.msg.group_name.get(),
|
||||
checked = it.msg.msg_decided.get().isNotBlank(),
|
||||
actor = it.msg.actor_uin.get(),
|
||||
requesterUin = 0,
|
||||
requesterNick = "",
|
||||
message = it.msg.msg_additional.get(),
|
||||
flag = "${it.msg_seq.get()};${it.msg.group_code.get()};${it.req_uin.get()}"
|
||||
)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return ok(msgs, echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("group_id", "folder_id")
|
||||
|
||||
override fun path(): String = "get_group_files_by_folder"
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.convert.MessageConvert
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.helper.db.MessageDB
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.MessageDetail
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.MessageSender
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import java.util.ArrayList
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
internal object GetHistoryMsg: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val msgType = session.getString("message_type")
|
||||
val peerId = session.getString(if (msgType == "group") "group_id" else "user_id")
|
||||
val cnt = session.getIntOrNull("count") ?: 20
|
||||
|
||||
val startId = session.getIntOrNull("message_seq")?.let {
|
||||
if (it == 0) return@let 0L
|
||||
MessageDB.getInstance()
|
||||
.messageMappingDao()
|
||||
.queryByMsgHashId(it)?.qqMsgId
|
||||
} ?: 0L
|
||||
|
||||
return invoke(msgType, peerId, cnt, startId, echo = session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
msgType: String,
|
||||
peerId: String,
|
||||
cnt: Int,
|
||||
startMsgId: Long = 0,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val msgService = NTServiceFetcher.kernelService.wrapperSession.msgService
|
||||
val chatType = MessageHelper.obtainMessageTypeByDetailType(msgType)
|
||||
val contact = MessageHelper.generateContact(chatType, peerId)
|
||||
val result = suspendCoroutine {
|
||||
msgService.getMsgs(contact, startMsgId, cnt, true) { code, why, msgs ->
|
||||
it.resume(GetMsgResult(code, why, msgs))
|
||||
}
|
||||
}
|
||||
if (result.code != 0) {
|
||||
return logic(result.msg ?: "获取历史消息失败", echo = echo)
|
||||
}
|
||||
|
||||
val msgList = ArrayList<MessageDetail>().apply {
|
||||
addAll(result.data!!.map { msg ->
|
||||
val msgHash = MessageHelper.generateMsgIdHash(msg.chatType, msg.msgId)
|
||||
MessageDetail(
|
||||
time = msg.msgTime.toInt(),
|
||||
msgType = MessageHelper.obtainDetailTypeByMsgType(msg.chatType),
|
||||
msgId = msgHash,
|
||||
realId = msg.msgSeq.toInt(),
|
||||
sender = MessageSender(
|
||||
msg.senderUin, msg.sendNickName, "unknown", 0, msg.senderUid
|
||||
),
|
||||
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||
it.toJson()
|
||||
},
|
||||
peerId = msg.peerUin,
|
||||
groupId = if (msg.chatType == MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0,
|
||||
targetId = if (msg.chatType != MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0
|
||||
)
|
||||
})
|
||||
if (startMsgId != 0L) {
|
||||
val msg = MsgSvc.getMsgByQMsgId(chatType, peerId, startMsgId).onFailure {
|
||||
return logic("Obtain msg failed, please check your msg_id.", echo)
|
||||
}.getOrThrow()
|
||||
val seq = msg.clientSeq.toInt()
|
||||
add(MessageDetail(
|
||||
time = msg.msgTime.toInt(),
|
||||
msgType = MessageHelper.obtainDetailTypeByMsgType(msg.chatType),
|
||||
msgId = MessageHelper.generateMsgIdHash(msg.chatType, msg.msgId),
|
||||
realId = seq,
|
||||
sender = MessageSender(
|
||||
msg.senderUin, msg.sendNickName
|
||||
.ifBlank { msg.sendMemberName }
|
||||
.ifBlank { msg.sendRemarkName }
|
||||
.ifBlank { msg.peerName }, "unknown", 0, msg.senderUid
|
||||
),
|
||||
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||
it.toJson()
|
||||
},
|
||||
peerId = msg.peerUin,
|
||||
groupId = if (msg.chatType == MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0,
|
||||
targetId = if (msg.chatType != MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return ok(data = GetHistoryMsgResult(msgList), echo = echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String>
|
||||
get() = arrayOf("message_type")
|
||||
|
||||
override fun path(): String = "get_history_msg"
|
||||
|
||||
@Serializable
|
||||
data class GetHistoryMsgResult(
|
||||
@SerialName("messages") val msgs: List<MessageDetail>
|
||||
)
|
||||
|
||||
data class GetMsgResult(
|
||||
val code: Int,
|
||||
val msg: String?,
|
||||
val data: ArrayList<MsgRecord>?
|
||||
)
|
||||
}
|
@ -22,14 +22,17 @@ internal object GetMsg: IActionHandler() {
|
||||
val msg = MsgSvc.getMsg(msgHash).onFailure {
|
||||
return logic("Obtain msg failed, please check your msg_id.", echo)
|
||||
}.getOrThrow()
|
||||
val seq = msg.clientSeq.toInt()
|
||||
val seq = msg.msgSeq.toInt()
|
||||
return ok(MessageDetail(
|
||||
time = msg.msgTime.toInt(),
|
||||
msgType = MessageHelper.obtainDetailTypeByMsgType(msg.chatType),
|
||||
msgId = msgHash,
|
||||
realId = seq,
|
||||
sender = MessageSender(
|
||||
msg.senderUin, msg.sendNickName, "unknown", 0, msg.senderUid
|
||||
msg.senderUin, msg.sendNickName
|
||||
.ifBlank { msg.sendMemberName }
|
||||
.ifBlank { msg.sendRemarkName }
|
||||
.ifBlank { msg.peerName }, "unknown", 0, msg.senderUid
|
||||
),
|
||||
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||
it.toJson()
|
||||
|
@ -15,7 +15,7 @@ internal object GetOnlineClients: IActionHandler() {
|
||||
|
||||
suspend operator fun invoke(echo: JsonElement = EmptyJsonString): String {
|
||||
val clients = QSafeSvc.getOnlineClients()
|
||||
?: return logic("获取在线设备信息失败", echo)
|
||||
?: return logic("获取在线设备信息失败", echo, arraayResult = true)
|
||||
return ok(clients.map {
|
||||
DevInfo(it.iAppId, it.strDeviceName, it.strDeviceTypeInfo, it.iLoginTime,
|
||||
it.iLoginPlatform, it.strLoginLocation
|
||||
|
@ -0,0 +1,29 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
|
||||
internal object GetProhibitedMemberList: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val groupCode = session.getLong("group_id")
|
||||
return invoke(groupCode, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
groupCode: Long,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val result = GroupSvc.getProhibitedMemberList(groupCode)
|
||||
if (result.isFailure) {
|
||||
return error(result.exceptionOrNull()?.message ?: "获取禁言列表失败", echo, arrayResult = true)
|
||||
}
|
||||
return ok(result.getOrThrow(), echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("group_id")
|
||||
|
||||
override fun path(): String = "get_prohibited_member_list"
|
||||
}
|
@ -16,7 +16,7 @@ internal object GetTroopList : IActionHandler() {
|
||||
suspend operator fun invoke(refresh: Boolean, echo: JsonElement = EmptyJsonString): String {
|
||||
val troopList = arrayListOf<SimpleTroopInfo>()
|
||||
GroupSvc.getGroupList(refresh).onFailure {
|
||||
return error(it.message ?: "unknown error", echo)
|
||||
return error(it.message ?: "unknown error", echo, arrayResult = true)
|
||||
}.onSuccess { troops ->
|
||||
troops.forEach { groupInfo ->
|
||||
if (groupInfo.troopcode.isNullOrEmpty()) return@forEach
|
||||
|
@ -23,7 +23,7 @@ internal object GetTroopMemberList : IActionHandler() {
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val memberList = GroupSvc.getGroupMemberList(groupId, refresh).onFailure {
|
||||
return error(it.message ?: "unknown error", echo)
|
||||
return error(it.message ?: "unknown error", echo, arrayResult = true)
|
||||
}.getOrThrow()
|
||||
|
||||
return ok(arrayListOf<SimpleTroopMemberInfo>().apply {
|
||||
@ -53,7 +53,6 @@ internal object GetTroopMemberList : IActionHandler() {
|
||||
role = when {
|
||||
GroupSvc.getOwner(groupId)
|
||||
.toString() == info.memberuin -> MemberRole.Owner
|
||||
|
||||
info.memberuin.toLong() in GroupSvc.getAdminList(groupId) -> MemberRole.Admin
|
||||
else -> MemberRole.Member
|
||||
},
|
||||
|
@ -20,7 +20,7 @@ internal object GetVersionInfo : IActionHandler() {
|
||||
appVersion = ShamrockVersion,
|
||||
impl = "shamrock",
|
||||
version = ShamrockVersion,
|
||||
onebotVersion = "12",
|
||||
onebotVersion = "11",
|
||||
),
|
||||
echo = echo
|
||||
)
|
||||
|
@ -0,0 +1,233 @@
|
||||
@file:OptIn(DelicateCoroutinesApi::class)
|
||||
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MultiMsgInfo
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.tools.asInt
|
||||
import moe.fuqiuluo.shamrock.tools.asJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.shamrock.tools.asStringOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.json
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
/**
|
||||
* 合并转发消息节点数据类
|
||||
*/
|
||||
sealed interface ForwardMsgNode {
|
||||
class MessageIdNode(
|
||||
val id: Int
|
||||
): ForwardMsgNode
|
||||
|
||||
open class MessageNode(
|
||||
val name: String,
|
||||
val content: JsonElement?
|
||||
): ForwardMsgNode
|
||||
|
||||
object EmptyNode: MessageNode("", null)
|
||||
}
|
||||
|
||||
/**
|
||||
* 私聊合并转发
|
||||
*/
|
||||
internal object SendPrivateForwardMsg: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val groupId = session.getString("user_id")
|
||||
if (session.isArray("messages")) {
|
||||
val messages = session.getArray("messages")
|
||||
return invoke(messages, groupId, session.echo)
|
||||
}
|
||||
return logic("未知格式合并转发消息", session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
message: JsonArray,
|
||||
userId: String,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
kotlin.runCatching {
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val msgService = sessionService.msgService
|
||||
val selfUin = TicketSvc.getUin()
|
||||
|
||||
val msgs = message.map {
|
||||
if (it.asJsonObject["type"].asStringOrNull != "node") return@map ForwardMsgNode.EmptyNode // 过滤非node类型消息段
|
||||
it.asJsonObject["data"].asJsonObject.let { data ->
|
||||
if (data.containsKey("content"))
|
||||
ForwardMsgNode.MessageNode(
|
||||
name = data["name"].asStringOrNull ?: "",
|
||||
content = data["content"]
|
||||
)
|
||||
else ForwardMsgNode.MessageIdNode(data["id"].asInt)
|
||||
}
|
||||
}.map {
|
||||
if (it is ForwardMsgNode.MessageIdNode) {
|
||||
val recordResult = MsgSvc.getMsg(it.id)
|
||||
if (recordResult.isFailure) {
|
||||
ForwardMsgNode.EmptyNode
|
||||
} else {
|
||||
val record = recordResult.getOrThrow()
|
||||
ForwardMsgNode.MessageNode(
|
||||
name = record.sendMemberName
|
||||
.ifBlank { record.sendNickName }
|
||||
.ifBlank { record.sendRemarkName }
|
||||
.ifBlank { record.peerName },
|
||||
content = record.toSegments().map { segment ->
|
||||
segment.toJson()
|
||||
}.json
|
||||
)
|
||||
}
|
||||
} else {
|
||||
it as ForwardMsgNode.MessageNode
|
||||
}
|
||||
}.filter {
|
||||
it.content != null
|
||||
}
|
||||
|
||||
val multiNodes = msgs.map { node ->
|
||||
suspendCoroutine {
|
||||
GlobalScope.launch {
|
||||
var msgId: Long = 0
|
||||
msgId = MessageHelper.sendMessageWithMsgId(MsgConstant.KCHATTYPEC2C, selfUin, node.content!!.let { msg ->
|
||||
if (msg is JsonArray) msg else MessageHelper.decodeCQCode(msg.asString)
|
||||
}, { code, why ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("合并转发消息节点消息发送失败:$code($why)", Level.WARN)
|
||||
}
|
||||
it.resume(node.name to msgId)
|
||||
}).first
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val from = MessageHelper.generateContact(MsgConstant.KCHATTYPEC2C, selfUin)
|
||||
val to = MessageHelper.generateContact(MsgConstant.KCHATTYPEC2C, userId)
|
||||
msgService.multiForwardMsg(ArrayList<MultiMsgInfo>().apply {
|
||||
multiNodes.forEach { add(MultiMsgInfo(it.second, it.first)) }
|
||||
}.also { it.reverse() }, from, to) { code, why ->
|
||||
if (code != 0)
|
||||
LogCenter.log("合并转发消息:$code($why)", Level.WARN)
|
||||
}
|
||||
return ok(data = EmptyJsonObject, echo = echo)
|
||||
}.onFailure {
|
||||
return error("error: $it", echo)
|
||||
}
|
||||
return logic("合并转发消息失败(unknown error)", echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("user_id")
|
||||
|
||||
override fun path(): String = "send_private_forward_msg"
|
||||
}
|
||||
|
||||
/**
|
||||
* 群聊合并转发
|
||||
*/
|
||||
internal object SendGroupForwardMsg: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val groupId = session.getString("group_id")
|
||||
if (session.isArray("messages")) {
|
||||
val messages = session.getArray("messages")
|
||||
return invoke(messages, groupId, session.echo)
|
||||
}
|
||||
return logic("未知格式合并转发消息", session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(
|
||||
message: JsonArray,
|
||||
groupId: String,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
kotlin.runCatching {
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val msgService = sessionService.msgService
|
||||
val selfUin = TicketSvc.getUin()
|
||||
|
||||
val msgs = message.map {
|
||||
if (it.asJsonObject["type"].asStringOrNull != "node") return@map ForwardMsgNode.EmptyNode // 过滤非node类型消息段
|
||||
it.asJsonObject["data"].asJsonObject.let { data ->
|
||||
if (data.containsKey("content"))
|
||||
ForwardMsgNode.MessageNode(
|
||||
name = data["name"].asStringOrNull ?: "",
|
||||
content = data["content"]
|
||||
)
|
||||
else ForwardMsgNode.MessageIdNode(data["id"].asInt)
|
||||
}
|
||||
}.map {
|
||||
if (it is ForwardMsgNode.MessageIdNode) {
|
||||
val recordResult = MsgSvc.getMsg(it.id)
|
||||
if (recordResult.isFailure) {
|
||||
ForwardMsgNode.EmptyNode
|
||||
} else {
|
||||
val record = recordResult.getOrThrow()
|
||||
ForwardMsgNode.MessageNode(
|
||||
name = record.sendMemberName
|
||||
.ifBlank { record.sendNickName }
|
||||
.ifBlank { record.sendRemarkName }
|
||||
.ifBlank { record.peerName },
|
||||
content = record.toSegments().map { segment ->
|
||||
segment.toJson()
|
||||
}.json
|
||||
)
|
||||
}
|
||||
} else {
|
||||
it as ForwardMsgNode.MessageNode
|
||||
}
|
||||
}.filter {
|
||||
it.content != null
|
||||
}
|
||||
|
||||
val multiNodes = msgs.map { node ->
|
||||
suspendCoroutine {
|
||||
GlobalScope.launch {
|
||||
var msgId: Long = 0
|
||||
msgId = MessageHelper.sendMessageWithMsgId(MsgConstant.KCHATTYPEC2C, selfUin, node.content!!.let { msg ->
|
||||
if (msg is JsonArray) msg else MessageHelper.decodeCQCode(msg.asString)
|
||||
}, { code, why ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("合并转发消息节点消息发送失败:$code($why)", Level.WARN)
|
||||
}
|
||||
it.resume(node.name to msgId)
|
||||
}).first
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val from = MessageHelper.generateContact(MsgConstant.KCHATTYPEC2C, selfUin)
|
||||
val to = MessageHelper.generateContact(MsgConstant.KCHATTYPEGROUP, groupId)
|
||||
msgService.multiForwardMsg(ArrayList<MultiMsgInfo>().apply {
|
||||
multiNodes.forEach { add(MultiMsgInfo(it.second, it.first)) }
|
||||
}.also { it.reverse() }, from, to) { code, why ->
|
||||
if (code != 0)
|
||||
LogCenter.log("合并转发消息:$code($why)", Level.WARN)
|
||||
}
|
||||
return ok(data = EmptyJsonObject, echo = echo)
|
||||
}.onFailure {
|
||||
return error("error: $it", echo)
|
||||
}
|
||||
return logic("合并转发消息失败(unknown error)", echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("group_id")
|
||||
|
||||
override fun path(): String = "send_group_forward_msg"
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.asInt
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.LongMsgHelper
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
|
||||
internal object SendGroupForwardMsg: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val groupId = session.getLong("group_id")
|
||||
val hashList = session.getArrayOrNull("seqs")?.map { it.asInt }
|
||||
if (hashList != null) {
|
||||
val msgs = hashList.map {
|
||||
MsgSvc.getMsg(it).getOrNull()
|
||||
}
|
||||
val resId = LongMsgHelper.uploadGroupMsg(groupId.toString(), msgs.filterNotNull())
|
||||
return ok(mapOf("res_id" to resId), session.echo)
|
||||
}
|
||||
|
||||
|
||||
return "xxx"
|
||||
}
|
||||
|
||||
operator fun invoke(msgs: List<MsgRecord>, echo: JsonElement = EmptyJsonString): String {
|
||||
if (msgs.isEmpty()) {
|
||||
return logic("消息为空", echo)
|
||||
} else if (msgs.size > 100) {
|
||||
return logic("消息数量过多", echo)
|
||||
}
|
||||
|
||||
|
||||
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun path(): String = "send_group_forward_msg"
|
||||
}
|
@ -10,7 +10,7 @@ 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, message, autoEscape, session.echo)
|
||||
SendMessage(MsgConstant.KCHATTYPEGROUP, groupId, message, autoEscape, echo = session.echo)
|
||||
} else {
|
||||
val message = session.getArray("message")
|
||||
SendMessage(MsgConstant.KCHATTYPEGROUP, groupId, message, session.echo)
|
||||
|
@ -19,13 +19,13 @@ internal object SendMessage: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val detailType = session.getStringOrNull("detail_type") ?: session.getStringOrNull("message_type")
|
||||
try {
|
||||
val chatType = detailType?.let {
|
||||
var chatType = detailType?.let {
|
||||
MessageHelper.obtainMessageTypeByDetailType(it)
|
||||
} ?: run {
|
||||
if (session.has("group_id")) {
|
||||
MsgConstant.KCHATTYPEGROUP
|
||||
} else if (session.has("user_id")) {
|
||||
if (session.has("user_id")) {
|
||||
MsgConstant.KCHATTYPEC2C
|
||||
} else if (session.has("group_id")) {
|
||||
MsgConstant.KCHATTYPEGROUP
|
||||
} else {
|
||||
return noParam("detail_type/message_type", session.echo)
|
||||
}
|
||||
@ -35,13 +35,21 @@ internal object SendMessage: IActionHandler() {
|
||||
MsgConstant.KCHATTYPEC2C -> session.getStringOrNull("user_id") ?: return noParam("user_id", session.echo)
|
||||
else -> error("unknown chat type: $chatType")
|
||||
}
|
||||
var fromId = peerId
|
||||
if (chatType == MsgConstant.KCHATTYPEC2C) {
|
||||
val groupId = session.getStringOrNull("group_id")
|
||||
if (groupId != null) {
|
||||
chatType = MsgConstant.KCHATTYPETEMPC2CFROMGROUP
|
||||
fromId = groupId
|
||||
}
|
||||
}
|
||||
return if (session.isString("message")) {
|
||||
val autoEscape = session.getBooleanOrDefault("auto_escape", false)
|
||||
val message = session.getString("message")
|
||||
invoke(chatType, peerId, message, autoEscape, session.echo)
|
||||
invoke(chatType, peerId, message, autoEscape, echo = session.echo, fromId = fromId)
|
||||
} else {
|
||||
val message = session.getArray("message")
|
||||
invoke(chatType, peerId, message, session.echo)
|
||||
invoke(chatType, peerId, message, session.echo, fromId = fromId)
|
||||
}
|
||||
} catch (e: ParamsException) {
|
||||
return noParam(e.message!!, session.echo)
|
||||
@ -56,39 +64,46 @@ internal object SendMessage: IActionHandler() {
|
||||
peerId: String,
|
||||
message: String,
|
||||
autoEscape: Boolean,
|
||||
fromId: String = peerId,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
//if (!ContactHelper.checkContactAvailable(chatType, peerId)) {
|
||||
// return logic("contact is not found", echo = echo)
|
||||
//}
|
||||
val result = if (autoEscape) {
|
||||
MsgSvc.sendToAio(chatType, peerId, arrayListOf(message).json)
|
||||
MsgSvc.sendToAio(chatType, peerId, arrayListOf(message).json, fromId = fromId)
|
||||
} else {
|
||||
val msg = MessageHelper.decodeCQCode(message)
|
||||
if (msg.isEmpty()) {
|
||||
LogCenter.log("CQ码不合法", Level.WARN)
|
||||
return logic("CQCode is illegal", echo)
|
||||
} else {
|
||||
MsgSvc.sendToAio(chatType, peerId, msg)
|
||||
MsgSvc.sendToAio(chatType, peerId, msg, fromId = fromId)
|
||||
}
|
||||
}
|
||||
if (result.first <= 0) {
|
||||
return logic("send message failed", echo = echo)
|
||||
}
|
||||
return ok(MessageResult(
|
||||
msgId = result.second,
|
||||
time = result.first * 0.001
|
||||
), echo)
|
||||
time = (result.first * 0.001).toLong()
|
||||
), echo = echo)
|
||||
}
|
||||
|
||||
// 消息段格式消息
|
||||
suspend operator fun invoke(
|
||||
chatType: Int, peerId: String, message: JsonArray, echo: JsonElement = EmptyJsonString
|
||||
chatType: Int, peerId: String, message: JsonArray, echo: JsonElement = EmptyJsonString, fromId: String = peerId
|
||||
): String {
|
||||
//if (!ContactHelper.checkContactAvailable(chatType, peerId)) {
|
||||
// return logic("contact is not found", echo = echo)
|
||||
//}
|
||||
val result = MsgSvc.sendToAio(chatType, peerId, message)
|
||||
val result = MsgSvc.sendToAio(chatType, peerId, message, fromId = fromId)
|
||||
if (result.first <= 0) {
|
||||
return logic("send message failed", echo = echo)
|
||||
}
|
||||
return ok(MessageResult(
|
||||
msgId = result.second,
|
||||
time = result.first * 0.001
|
||||
time = (result.first * 0.001).toLong()
|
||||
), echo)
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,28 @@ import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
internal object SendPrivateMessage: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val userId = session.getString("user_id")
|
||||
val groupId = session.getStringOrNull("group_id")
|
||||
val chatTYpe = if (groupId == null) MsgConstant.KCHATTYPEC2C else MsgConstant.KCHATTYPETEMPC2CFROMGROUP
|
||||
return if (session.isString("message")) {
|
||||
val autoEscape = session.getBooleanOrDefault("auto_escape", false)
|
||||
val message = session.getString("message")
|
||||
SendMessage(MsgConstant.KCHATTYPEC2C, userId, message, autoEscape, session.echo)
|
||||
SendMessage.invoke(
|
||||
chatType = chatTYpe,
|
||||
peerId = userId,
|
||||
message = message,
|
||||
autoEscape = autoEscape,
|
||||
echo = session.echo,
|
||||
fromId = groupId ?: userId
|
||||
)
|
||||
} else {
|
||||
val message = session.getArray("message")
|
||||
SendMessage(MsgConstant.KCHATTYPEC2C, userId, message, session.echo)
|
||||
SendMessage(
|
||||
chatType = chatTYpe,
|
||||
peerId = userId,
|
||||
message = message,
|
||||
echo = session.echo,
|
||||
fromId = groupId ?: userId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
|
||||
internal object SetEssenceMessage: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val messageId = session.getInt("message_id")
|
||||
return invoke(messageId, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(messageId: Int, echo: JsonElement = EmptyJsonString): String {
|
||||
val msg = MsgSvc.getMsg(messageId).onFailure {
|
||||
return logic("Obtain msg failed, please check your msg_id.", echo)
|
||||
}.getOrThrow()
|
||||
val (success, tip) = GroupSvc.setEssenceMessage(
|
||||
if (msg.chatType == MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0,
|
||||
msg.msgSeq,
|
||||
msg.msgRandom
|
||||
)
|
||||
return if (success) {
|
||||
ok("成功", echo)
|
||||
} else {
|
||||
logic(tip, echo)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override val alias: Array<String> = arrayOf("set_essence_message")
|
||||
override fun path(): String = "set_essence_msg"
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.FriendSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
|
||||
internal object SetFriendAddRequest: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val flag = session.getString("flag")
|
||||
val approve = session.getBoolean("approve")
|
||||
val remark = session.getStringOrNull("remark")
|
||||
val notSeen = session.getBoolean("notSeen")
|
||||
return invoke(flag, approve, remark, notSeen, session.echo)
|
||||
}
|
||||
|
||||
operator fun invoke(flag: String, approve: Boolean? = true, remark: String? = "", notSeen: Boolean? = false, echo: JsonElement = EmptyJsonString): String {
|
||||
val flags = flag.split(";")
|
||||
val ts = flags[0].toLong()
|
||||
// val src = flags[1].toInt()
|
||||
// val subSrc = flags[2].toInt()
|
||||
val applier = flags[3].toLong()
|
||||
return try {
|
||||
FriendSvc.requestFriendRequest(ts, applier, remark ?: "", approve, notSeen)
|
||||
ok("成功", echo)
|
||||
} catch (err: Throwable) {
|
||||
err.printStackTrace()
|
||||
error("失败:${err.message}", echo)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun path(): String = "set_friend_add_request"
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
|
||||
internal object SetGroupAddRequest: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val flag = session.getString("flag")
|
||||
val approve = session.getBoolean("approve")
|
||||
val remark = session.getStringOrNull("reason")
|
||||
val notSeen = session.getBoolean("notSeen")
|
||||
val subType = session.getString("sub_type")
|
||||
return invoke(flag, approve, subType, remark, notSeen, session.echo)
|
||||
}
|
||||
|
||||
suspend operator fun invoke(flag: String, approve: Boolean? = true, subType: String, remark: String? = "", notSeen: Boolean? = false, echo: JsonElement = EmptyJsonString): String {
|
||||
val flags = flag.split(";")
|
||||
val ts = flags[0].toLong()
|
||||
val groupCode = flags[1].toLong()
|
||||
val uin = flags[2].toLong()
|
||||
return try {
|
||||
val result = GroupSvc.requestGroupRequest(ts, uin, groupCode, remark ?: "", approve, notSeen, subType)
|
||||
if (result.isSuccess) {
|
||||
ok(result.getOrNull(), echo)
|
||||
} else {
|
||||
logic(result.getOrNull() ?: "", echo)
|
||||
}
|
||||
} catch (err: Throwable) {
|
||||
err.printStackTrace()
|
||||
error("失败:${err.message}", echo)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun path(): String = "set_group_add_request"
|
||||
}
|
@ -15,8 +15,8 @@ internal object SetGroupUnique: IActionHandler() {
|
||||
}
|
||||
|
||||
suspend operator fun invoke(groupId: String, userId: String, unique: String, echo: JsonElement = EmptyJsonString): String {
|
||||
if (!GroupSvc.isAdmin(groupId)) {
|
||||
return error("you are not admin", echo)
|
||||
if (!GroupSvc.isOwner(groupId)) {
|
||||
return error("you are not owner", echo)
|
||||
}
|
||||
GroupSvc.setGroupUniqueTitle(groupId, userId, unique)
|
||||
return ok("成功", echo)
|
||||
|
@ -0,0 +1,35 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||
import mqq.app.MobileQQ
|
||||
|
||||
internal object SwitchAccount: IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val userId = session.getString("user_id")
|
||||
return invoke(userId, session.echo)
|
||||
}
|
||||
|
||||
operator fun invoke(
|
||||
userId: String,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
val account = MobileQQ.getMobileQQ().allAccounts.firstOrNull { it.uin == userId }
|
||||
?: return error("账号不存在", echo)
|
||||
val runtime = AppRuntimeFetcher.appRuntime
|
||||
val result = kotlin.runCatching {
|
||||
runtime.switchAccount(account, null)
|
||||
}
|
||||
if (result.isFailure) {
|
||||
return error(result.exceptionOrNull()?.message ?: "切换账号失败", echo)
|
||||
}
|
||||
return ok("切换成功", echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("user_id")
|
||||
|
||||
override fun path(): String = "switch_account"
|
||||
}
|
@ -2,6 +2,7 @@ package moe.fuqiuluo.shamrock.remote.api
|
||||
|
||||
import com.tencent.mobileqq.profilecard.api.IProfileCardBlacklistApi
|
||||
import com.tencent.mobileqq.qroute.QRoute
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.response.respondText
|
||||
import io.ktor.server.routing.Routing
|
||||
@ -17,16 +18,16 @@ import moe.fuqiuluo.shamrock.tools.getOrPost
|
||||
fun Routing.friendAction() {
|
||||
getOrPost("/get_stranger_info") {
|
||||
val uin = fetchOrThrow("user_id")
|
||||
call.respondText(GetStrangerInfo(uin))
|
||||
call.respondText(GetStrangerInfo(uin), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_friend_list") {
|
||||
val refresh = fetchOrNull("refresh")?.toBooleanStrictOrNull() ?: false
|
||||
call.respondText(GetFriendList(refresh))
|
||||
call.respondText(GetFriendList(refresh), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/is_blacklist_uin") {
|
||||
val uin = fetchOrThrow("user_id")
|
||||
call.respondText(IsBlackListUin(uin))
|
||||
call.respondText(IsBlackListUin(uin), ContentType.Application.Json)
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package moe.fuqiuluo.shamrock.remote.api
|
||||
|
||||
import io.ktor.http.ContentType
|
||||
import moe.fuqiuluo.shamrock.helper.LogicException
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.response.respondText
|
||||
@ -12,73 +13,83 @@ import moe.fuqiuluo.shamrock.tools.fetchOrThrow
|
||||
import moe.fuqiuluo.shamrock.tools.getOrPost
|
||||
|
||||
fun Routing.troopAction() {
|
||||
getOrPost("/get_prohibited_member_list") {
|
||||
val groupId = fetchOrThrow("group_id").toLong()
|
||||
call.respondText(GetProhibitedMemberList(groupId), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/group_touch") {
|
||||
val groupId = fetchOrThrow("group_id")
|
||||
val userId = fetchOrThrow("user_id")
|
||||
call.respondText(GroupPoke(groupId, userId))
|
||||
call.respondText(GroupPoke(groupId, userId), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_group_honor_info") {
|
||||
val groupId = fetchOrThrow("group_id")
|
||||
val refresh = fetchOrNull("refresh")?.toBooleanStrict() ?: false
|
||||
call.respondText(GetTroopHonor(groupId, refresh))
|
||||
val refresh = fetchOrNull("no_cache")?.toBooleanStrict()
|
||||
?: fetchOrNull("refresh")?.toBooleanStrict() ?: false
|
||||
call.respondText(GetTroopHonor(groupId, refresh), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_group_member_list") {
|
||||
val groupId = fetchOrThrow("group_id")
|
||||
val refresh = fetchOrNull("refresh")?.toBooleanStrict() ?: false
|
||||
call.respondText(GetTroopMemberList(groupId, refresh))
|
||||
val refresh = fetchOrNull("no_cache")?.toBooleanStrict()
|
||||
?: fetchOrNull("refresh")?.toBooleanStrict() ?: false
|
||||
call.respondText(GetTroopMemberList(groupId, refresh), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_group_member_info") {
|
||||
val groupId = fetchOrThrow("group_id")
|
||||
val userId = fetchOrThrow("user_id")
|
||||
val refresh = fetchOrNull("no_cache")?.toBooleanStrict() ?: false
|
||||
call.respondText(GetTroopMemberInfo(groupId, userId, refresh))
|
||||
val refresh = fetchOrNull("no_cache")?.toBooleanStrict()
|
||||
?: fetchOrNull("refresh")?.toBooleanStrict() ?: false
|
||||
call.respondText(GetTroopMemberInfo(groupId, userId, refresh), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_group_list") {
|
||||
val refresh = fetchOrNull("refresh")?.toBooleanStrict() ?: true
|
||||
call.respondText(GetTroopList(refresh))
|
||||
val refresh = fetchOrNull("refresh")?.toBooleanStrict()
|
||||
?: fetchOrNull("refresh")?.toBooleanStrict() ?: true
|
||||
call.respondText(GetTroopList(refresh), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_group_info") {
|
||||
val groupId = fetchOrThrow("group_id")
|
||||
val refresh = fetchOrNull("no_cache")?.toBooleanStrict() ?: false
|
||||
call.respondText(GetTroopInfo(groupId, refresh))
|
||||
val refresh = fetchOrNull("no_cache")?.toBooleanStrict()
|
||||
?: fetchOrNull("refresh")?.toBooleanStrict() ?: false
|
||||
call.respondText(GetTroopInfo(groupId, refresh), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_group_special_title") {
|
||||
val groupId = fetchOrThrow("group_id")
|
||||
val userId = fetchOrThrow("user_id")
|
||||
val title = fetchOrThrow("special_title")
|
||||
call.respondText(SetGroupUnique(groupId, userId, title))
|
||||
call.respondText(SetGroupUnique(groupId, userId, title), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_group_name") {
|
||||
val groupId = fetchOrThrow("group_id")
|
||||
val card = fetchOrThrow("group_name")
|
||||
call.respondText(ModifyTroopName(groupId, card))
|
||||
call.respondText(ModifyTroopName(groupId, card), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_group_card") {
|
||||
val groupId = fetchOrThrow("group_id")
|
||||
val userId = fetchOrThrow("user_id")
|
||||
val card = fetchOrNull("card") ?: ""
|
||||
call.respondText(ModifyTroopMemberName(groupId, userId, card))
|
||||
call.respondText(ModifyTroopMemberName(groupId, userId, card), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_group_admin") {
|
||||
val groupId = fetchOrThrow("group_id") .toLong()
|
||||
val userId = fetchOrThrow("user_id") .toLong()
|
||||
val enable = fetchOrThrow("enable").toBooleanStrict()
|
||||
call.respondText(SetGroupAdmin(groupId, userId, enable))
|
||||
call.respondText(SetGroupAdmin(groupId, userId, enable), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_group_whole_ban") {
|
||||
val groupId = fetchOrThrow("group_id") .toLong()
|
||||
val enable = fetchOrThrow("enable").toBooleanStrict()
|
||||
call.respondText(SetGroupWholeBan(groupId, enable))
|
||||
call.respondText(SetGroupWholeBan(groupId, enable), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_group_ban") {
|
||||
@ -86,12 +97,27 @@ fun Routing.troopAction() {
|
||||
val userId = fetchOrThrow("user_id") .toLong()
|
||||
val duration = fetchOrNull("duration")?.toInt() ?: (30 * 60)
|
||||
|
||||
call.respondText(BanTroopMember(groupId, userId, duration))
|
||||
call.respondText(BanTroopMember(groupId, userId, duration), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_group_kick") {
|
||||
val userId = fetchOrThrow("user_id").toLong()
|
||||
val groupId = fetchOrThrow("group_id").toLong()
|
||||
call.respondText(KickTroopMember(groupId, userId))
|
||||
call.respondText(KickTroopMember(groupId, userId), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/set_essence_msg") {
|
||||
val messageId = fetchOrThrow("message_id").toInt()
|
||||
call.respondText(SetEssenceMessage(messageId), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/delete_essence_msg") {
|
||||
val messageId = fetchOrThrow("message_id").toInt()
|
||||
call.respondText(DeleteEssenceMessage(messageId), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
getOrPost("/get_group_system_msg") {
|
||||
call.respondText(GetGroupSystemMsg(), ContentType.Application.Json)
|
||||
}
|
||||
|
||||
}
|
@ -17,10 +17,12 @@ import moe.fuqiuluo.shamrock.remote.config.ECHO_KEY
|
||||
import moe.fuqiuluo.shamrock.remote.entries.EmptyObject
|
||||
import moe.fuqiuluo.shamrock.remote.entries.IndexData
|
||||
import moe.fuqiuluo.shamrock.remote.entries.Status
|
||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.fetchOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.fetchOrThrow
|
||||
import moe.fuqiuluo.shamrock.tools.fetchPostJsonElement
|
||||
import moe.fuqiuluo.shamrock.tools.fetchPostJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.fetchPostJsonObjectOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.isJsonArray
|
||||
import moe.fuqiuluo.shamrock.tools.isJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.isJsonString
|
||||
@ -55,7 +57,7 @@ fun Routing.echoVersion() {
|
||||
}
|
||||
call.attributes.put(ECHO_KEY, echo)
|
||||
|
||||
val params = fetchPostJsonObject("params")
|
||||
val params = fetchPostJsonObjectOrNull("params") ?: EmptyJsonObject
|
||||
|
||||
val handler = ActionManager[action]
|
||||
if (handler == null) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user