Skip to content

Commit

Permalink
chore: RevokeMsgHook: optimize gray tip for NT
Browse files Browse the repository at this point in the history
  • Loading branch information
cinit committed Jul 17, 2023
1 parent d2ba552 commit 16181da
Showing 1 changed file with 62 additions and 40 deletions.
102 changes: 62 additions & 40 deletions app/src/main/java/cc/ioctl/hook/msg/RevokeMsgHook.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
* 2020/04/08 Tue.23:21 Use RevokeMsgInfoImpl for ease, wanna cry
* <p>
* 2023-06-16 Fri.12:40 Initial support for NT kernel.
* <p>
* 2023-07-12 Mon.23:12 Basic support for NT kernel.
*/
@FunctionHookEntry
@UiItemAgentEntry
Expand Down Expand Up @@ -179,37 +181,36 @@ public void setEnabled(boolean value) {

@Override
public boolean initOnce() throws Exception {
if (QAppUtils.isQQnt()) {
nativeInitNtKernelRecallMsgHook();
} else {
Method revokeMsg = null;
for (Method m : _QQMessageFacade().getDeclaredMethods()) {
if (m.getReturnType().equals(void.class)) {
Class<?>[] argt = m.getParameterTypes();
if (argt.length == 2 && argt[0].equals(ArrayList.class) && argt[1]
.equals(boolean.class)) {
revokeMsg = m;
break;
}
nativeInitNtKernelRecallMsgHook();
// The method is still there, even on NT.
// I decided to hook them as long as they are there.
// There should only be one method with such signature.
Method revokeMsg = null;
for (Method m : _QQMessageFacade().getDeclaredMethods()) {
if (m.getReturnType().equals(void.class)) {
Class<?>[] argt = m.getParameterTypes();
if (argt.length == 2 && argt[0].equals(ArrayList.class) && argt[1].equals(boolean.class)) {
revokeMsg = m;
break;
}
}
HookUtils.hookBeforeIfEnabled(this, revokeMsg, -10086, param -> {
mQQMsgFacade = param.thisObject;
ArrayList<?> list = (ArrayList<?>) param.args[0];
param.setResult(null);
if (list == null || list.isEmpty()) {
return;
}
for (Object revokeMsgInfo : list) {
try {
onRevokeMsgLegacy(revokeMsgInfo);
} catch (Exception | LinkageError | AssertionError t) {
traceError(t);
}
}
list.clear();
});
}
HookUtils.hookBeforeIfEnabled(this, revokeMsg, -10086, param -> {
mQQMsgFacade = param.thisObject;
ArrayList<?> list = (ArrayList<?>) param.args[0];
param.setResult(null);
if (list == null || list.isEmpty()) {
return;
}
for (Object revokeMsgInfo : list) {
try {
onRevokeMsgLegacy(revokeMsgInfo);
} catch (Exception | LinkageError | AssertionError t) {
traceError(t);
}
}
list.clear();
});
return true;
}

Expand Down Expand Up @@ -248,6 +249,7 @@ private void onRevokeMsgLegacy(Object revokeMsgInfo) throws Exception {
aioSessionUin = info.friendUin;
} else {
// XXX: maybe confession chat? 3000: temp C2C chat? guild?
// XXX: ??? 1000 ???
throw new IllegalStateException("onRevokeMsg, istroop=" + istroop);
}

Expand Down Expand Up @@ -374,10 +376,22 @@ private void onRevokeMsgLegacy(Object revokeMsgInfo) throws Exception {
* We are not allowed to throw any exception in this method.
*/
@Keep
private static void handleRecallSysMsgFromNtKernel(int chatType, String peerUid, String recallOpUid, String msgAuthorUid,
private static void handleRecallSysMsgFromNtKernel(int chatType, String fromUid, String recallOpUid, String msgAuthorUid,
String toUid, long random64, long timeSeconds, long msgUid, long msgSeq, int msgClientSeq) {
SyncUtils.async(() -> {
try {
String selfUid = RelationNTUinAndUidApi.getUidFromUin(AppRuntimeHelper.getAccount());
if (TextUtils.isEmpty(selfUid)) {
Log.e("onRecallSysMsgForNT fatal: selfUid is empty");
return;
}
String peerUid;
if (selfUid.equals(fromUid)) {
// msg is revoked by myself
peerUid = toUid;
} else {
peerUid = fromUid;
}
RevokeMsgHook.INSTANCE.onRecallSysMsgForNT(chatType, peerUid, recallOpUid, msgAuthorUid, toUid,
random64, timeSeconds, msgUid, msgSeq, msgClientSeq);
} catch (Exception | LinkageError | AssertionError e) {
Expand Down Expand Up @@ -408,10 +422,6 @@ private void onRecallSysMsgForNT(int chatType, String peerUid, String recallOpUi
Log.e("onRecallSysMsgForNT fatal: msgAuthorUid is empty");
return;
}
if (selfUid.equals(recallOpUid)) {
// ignore msg revoked by self
return;
}
if ((chatType == 1 && !Objects.equals(selfUid, toUid)) || (chatType == 2 && !Objects.equals(peerUid, toUid))) {
Log.w("!!! onRecallSysMsgForNT potential bug: chatType=" + chatType + ", peerUid=" + peerUid + ", toUid=" + toUid + ", selfUid=" + selfUid);
}
Expand All @@ -428,14 +438,14 @@ private void onRecallSysMsgForNT(int chatType, String peerUid, String recallOpUi
if (queryResult == 0 && msgList != null && !msgList.isEmpty()) {
msgObject = msgList.get(0);
} else if (queryResult == 0) {
Log.d("onRecallSysMsgForNT: msg not found, msgUid=" + msgUid);
Log.d("onRecallSysMsgForNT: msg not found, msgSeq=" + msgSeq);
} else {
Log.e("onRecallSysMsgForNT error: getMsgsByMsgId failed, result=" + queryResult + ", errMsg=" + errMsg);
}
NtGrayTipHelper.NtGrayTipJsonBuilder builder = new NtGrayTipHelper.NtGrayTipJsonBuilder();
String summary;
if (chatType == ChatTypeConstants.C2C) {
String revokerPron = selfUid.equals(peerUid) ? "你" : "对方";
String revokerPron = selfUid.equals(recallOpUid) ? "你" : "对方";
if (msgObject != null && !(msgObject.getMsgType() == 5 && msgObject.getSubMsgType() == 4)) {
builder.appendText(revokerPron + "尝试撤回");
builder.append(new NtGrayTipHelper.NtGrayTipJsonBuilder.MsgRefItem("一条消息", msgSeq));
Expand Down Expand Up @@ -474,14 +484,26 @@ private void onRecallSysMsgForNT(int chatType, String peerUid, String recallOpUi
}
} else {
// we don't have the original message
if (selfUid.equals(recallOpUid) && (msgObject.getMsgType() == 5 && msgObject.getSubMsgType() == 4)) {
// the message is recalled by self, and the gray tip is already there
// we don't need to do anything here, otherwise we will have duplicated gray tip.
// Control Flow Termination.
return;
}
String msgAuthorName = ContactUtils.getDisplayNameForUid(msgAuthorUid, peerUid);
String msgAuthorUin = RelationNTUinAndUidApi.getUinFromUid(msgAuthorUid);
// msgAuthorUin may be empty, in the case when in a group chat, NT kernel are not so familiar with the one
builder.append(new NtGrayTipHelper.NtGrayTipJsonBuilder.UserItem(String.valueOf(operatorUin), recallOpUid, operatorName));
builder.appendText("撤回了");
builder.append(new NtGrayTipHelper.NtGrayTipJsonBuilder.UserItem(String.valueOf(msgAuthorUin), msgAuthorUid, msgAuthorName));
builder.appendText("的一条消息(没收到) [seq=" + msgSeq + "]");
summary = operatorName + "撤回了" + msgAuthorName + "的一条消息(没收到)";
if (recallOpUid.equals(msgAuthorUin)) {
builder.append(new NtGrayTipHelper.NtGrayTipJsonBuilder.UserItem(String.valueOf(operatorUin), recallOpUid, operatorName));
builder.appendText("撤回了一条消息(没收到) [seq=" + msgSeq + "]");
summary = operatorName + "撤回了一条消息(没收到)";
} else {
builder.append(new NtGrayTipHelper.NtGrayTipJsonBuilder.UserItem(String.valueOf(operatorUin), recallOpUid, operatorName));
builder.appendText("撤回了");
builder.append(new NtGrayTipHelper.NtGrayTipJsonBuilder.UserItem(String.valueOf(msgAuthorUin), msgAuthorUid, msgAuthorName));
builder.appendText("的一条消息(没收到) [seq=" + msgSeq + "]");
summary = operatorName + "撤回了" + msgAuthorName + "的一条消息(没收到)";
}
}
} else {
throw new AssertionError("onRecallSysMsgForNT chatType=" + chatType);
Expand Down

0 comments on commit 16181da

Please sign in to comment.