mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 10:30:38 +00:00
Delay auto responses to messages until caught up with old messages
To prevent responding with old state, if the last receive call was a long time ago.
This commit is contained in:
parent
d14b8ac71f
commit
34caba2a7a
2 changed files with 214 additions and 45 deletions
156
src/main/java/org/asamk/signal/manager/HandleAction.java
Normal file
156
src/main/java/org/asamk/signal/manager/HandleAction.java
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
package org.asamk.signal.manager;
|
||||||
|
|
||||||
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
interface HandleAction {
|
||||||
|
|
||||||
|
void execute(Manager m) throws Throwable;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendReceiptAction implements HandleAction {
|
||||||
|
|
||||||
|
private final SignalServiceAddress address;
|
||||||
|
private final long timestamp;
|
||||||
|
|
||||||
|
public SendReceiptAction(final SignalServiceAddress address, final long timestamp) {
|
||||||
|
this.address = address;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Manager m) throws Throwable {
|
||||||
|
m.sendReceipt(address, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
final SendReceiptAction that = (SendReceiptAction) o;
|
||||||
|
return timestamp == that.timestamp &&
|
||||||
|
address.equals(that.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(address, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendSyncContactsAction implements HandleAction {
|
||||||
|
|
||||||
|
private static final SendSyncContactsAction INSTANCE = new SendSyncContactsAction();
|
||||||
|
|
||||||
|
private SendSyncContactsAction() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SendSyncContactsAction create() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Manager m) throws Throwable {
|
||||||
|
m.sendContacts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendSyncGroupsAction implements HandleAction {
|
||||||
|
|
||||||
|
private static final SendSyncGroupsAction INSTANCE = new SendSyncGroupsAction();
|
||||||
|
|
||||||
|
private SendSyncGroupsAction() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SendSyncGroupsAction create() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Manager m) throws Throwable {
|
||||||
|
m.sendGroups();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendSyncBlockedListAction implements HandleAction {
|
||||||
|
|
||||||
|
private static final SendSyncBlockedListAction INSTANCE = new SendSyncBlockedListAction();
|
||||||
|
|
||||||
|
private SendSyncBlockedListAction() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SendSyncBlockedListAction create() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Manager m) throws Throwable {
|
||||||
|
m.sendBlockedList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendGroupInfoRequestAction implements HandleAction {
|
||||||
|
|
||||||
|
private final SignalServiceAddress address;
|
||||||
|
private final byte[] groupId;
|
||||||
|
|
||||||
|
public SendGroupInfoRequestAction(final SignalServiceAddress address, final byte[] groupId) {
|
||||||
|
this.address = address;
|
||||||
|
this.groupId = groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Manager m) throws Throwable {
|
||||||
|
m.sendGroupInfoRequest(groupId, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
final SendGroupInfoRequestAction that = (SendGroupInfoRequestAction) o;
|
||||||
|
return address.equals(that.address) &&
|
||||||
|
Arrays.equals(groupId, that.groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = Objects.hash(address);
|
||||||
|
result = 31 * result + Arrays.hashCode(groupId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendGroupUpdateAction implements HandleAction {
|
||||||
|
|
||||||
|
private final SignalServiceAddress address;
|
||||||
|
private final byte[] groupId;
|
||||||
|
|
||||||
|
public SendGroupUpdateAction(final SignalServiceAddress address, final byte[] groupId) {
|
||||||
|
this.address = address;
|
||||||
|
this.groupId = groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Manager m) throws Throwable {
|
||||||
|
m.sendUpdateGroupMessage(groupId, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
final SendGroupUpdateAction that = (SendGroupUpdateAction) o;
|
||||||
|
return address.equals(that.address) &&
|
||||||
|
Arrays.equals(groupId, that.groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = Objects.hash(address);
|
||||||
|
result = 31 * result + Arrays.hashCode(groupId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -580,7 +580,7 @@ public class Manager implements Closeable {
|
||||||
return g.groupId;
|
return g.groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendUpdateGroupMessage(byte[] groupId, SignalServiceAddress recipient) throws IOException, EncapsulatedExceptions, NotAGroupMemberException, GroupNotFoundException, AttachmentInvalidException {
|
void sendUpdateGroupMessage(byte[] groupId, SignalServiceAddress recipient) throws IOException, EncapsulatedExceptions, NotAGroupMemberException, GroupNotFoundException, AttachmentInvalidException {
|
||||||
if (groupId == null) {
|
if (groupId == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -616,7 +616,7 @@ public class Manager implements Closeable {
|
||||||
.withExpiration(g.messageExpirationTime);
|
.withExpiration(g.messageExpirationTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendGroupInfoRequest(byte[] groupId, SignalServiceAddress recipient) throws IOException, EncapsulatedExceptions {
|
void sendGroupInfoRequest(byte[] groupId, SignalServiceAddress recipient) throws IOException, EncapsulatedExceptions {
|
||||||
if (groupId == null) {
|
if (groupId == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -631,7 +631,7 @@ public class Manager implements Closeable {
|
||||||
sendMessageLegacy(messageBuilder, Collections.singleton(recipient));
|
sendMessageLegacy(messageBuilder, Collections.singleton(recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendReceipt(SignalServiceAddress remoteAddress, long messageId) throws IOException, UntrustedIdentityException {
|
void sendReceipt(SignalServiceAddress remoteAddress, long messageId) throws IOException, UntrustedIdentityException {
|
||||||
SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.DELIVERY,
|
SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.DELIVERY,
|
||||||
Collections.singletonList(messageId),
|
Collections.singletonList(messageId),
|
||||||
System.currentTimeMillis());
|
System.currentTimeMillis());
|
||||||
|
@ -1209,7 +1209,8 @@ public class Manager implements Closeable {
|
||||||
account.getSignalProtocolStore().deleteAllSessions(source);
|
account.getSignalProtocolStore().deleteAllSessions(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSignalServiceDataMessage(SignalServiceDataMessage message, boolean isSync, SignalServiceAddress source, SignalServiceAddress destination, boolean ignoreAttachments) {
|
private List<HandleAction> handleSignalServiceDataMessage(SignalServiceDataMessage message, boolean isSync, SignalServiceAddress source, SignalServiceAddress destination, boolean ignoreAttachments) {
|
||||||
|
List<HandleAction> actions = new ArrayList<>();
|
||||||
if (message.getGroupContext().isPresent() && message.getGroupContext().get().getGroupV1().isPresent()) {
|
if (message.getGroupContext().isPresent() && message.getGroupContext().get().getGroupV1().isPresent()) {
|
||||||
SignalServiceGroup groupInfo = message.getGroupContext().get().getGroupV1().get();
|
SignalServiceGroup groupInfo = message.getGroupContext().get().getGroupV1().get();
|
||||||
GroupInfo group = account.getGroupStore().getGroup(groupInfo.getGroupId());
|
GroupInfo group = account.getGroupStore().getGroup(groupInfo.getGroupId());
|
||||||
|
@ -1244,12 +1245,8 @@ public class Manager implements Closeable {
|
||||||
account.getGroupStore().updateGroup(group);
|
account.getGroupStore().updateGroup(group);
|
||||||
break;
|
break;
|
||||||
case DELIVER:
|
case DELIVER:
|
||||||
if (group == null) {
|
if (group == null && !isSync) {
|
||||||
try {
|
actions.add(new SendGroupInfoRequestAction(source, groupInfo.getGroupId()));
|
||||||
sendGroupInfoRequest(groupInfo.getGroupId(), source);
|
|
||||||
} catch (IOException | EncapsulatedExceptions e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QUIT:
|
case QUIT:
|
||||||
|
@ -1259,14 +1256,8 @@ public class Manager implements Closeable {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REQUEST_INFO:
|
case REQUEST_INFO:
|
||||||
if (group != null) {
|
if (group != null && !isSync) {
|
||||||
try {
|
actions.add(new SendGroupUpdateAction(source, group.groupId));
|
||||||
sendUpdateGroupMessage(groupInfo.getGroupId(), source);
|
|
||||||
} catch (IOException | EncapsulatedExceptions | AttachmentInvalidException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (GroupNotFoundException | NotAGroupMemberException e) {
|
|
||||||
// We have left this group, so don't send a group update message
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1341,6 +1332,7 @@ public class Manager implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retryFailedReceivedMessages(ReceiveMessageHandler handler, boolean ignoreAttachments) {
|
private void retryFailedReceivedMessages(ReceiveMessageHandler handler, boolean ignoreAttachments) {
|
||||||
|
@ -1383,7 +1375,14 @@ public class Manager implements Closeable {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleMessage(envelope, content, ignoreAttachments);
|
List<HandleAction> actions = handleMessage(envelope, content, ignoreAttachments);
|
||||||
|
for (HandleAction action : actions) {
|
||||||
|
try {
|
||||||
|
action.execute(this);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
account.save();
|
account.save();
|
||||||
handler.handleMessage(envelope, content, null);
|
handler.handleMessage(envelope, content, null);
|
||||||
|
@ -1398,6 +1397,8 @@ public class Manager implements Closeable {
|
||||||
retryFailedReceivedMessages(handler, ignoreAttachments);
|
retryFailedReceivedMessages(handler, ignoreAttachments);
|
||||||
final SignalServiceMessageReceiver messageReceiver = getMessageReceiver();
|
final SignalServiceMessageReceiver messageReceiver = getMessageReceiver();
|
||||||
|
|
||||||
|
Set<HandleAction> queuedActions = null;
|
||||||
|
|
||||||
if (messagePipe == null) {
|
if (messagePipe == null) {
|
||||||
messagePipe = messageReceiver.createMessagePipe();
|
messagePipe = messageReceiver.createMessagePipe();
|
||||||
}
|
}
|
||||||
|
@ -1426,6 +1427,18 @@ public class Manager implements Closeable {
|
||||||
// Received indicator that server queue is empty
|
// Received indicator that server queue is empty
|
||||||
hasCaughtUpWithOldMessages = true;
|
hasCaughtUpWithOldMessages = true;
|
||||||
|
|
||||||
|
if (queuedActions != null) {
|
||||||
|
for (HandleAction action : queuedActions) {
|
||||||
|
try {
|
||||||
|
action.execute(this);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queuedActions.clear();
|
||||||
|
queuedActions = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Continue to wait another timeout for new messages
|
// Continue to wait another timeout for new messages
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1448,7 +1461,21 @@ public class Manager implements Closeable {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
exception = e;
|
exception = e;
|
||||||
}
|
}
|
||||||
handleMessage(envelope, content, ignoreAttachments);
|
List<HandleAction> actions = handleMessage(envelope, content, ignoreAttachments);
|
||||||
|
if (hasCaughtUpWithOldMessages) {
|
||||||
|
for (HandleAction action : actions) {
|
||||||
|
try {
|
||||||
|
action.execute(this);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (queuedActions == null) {
|
||||||
|
queuedActions = new HashSet<>();
|
||||||
|
}
|
||||||
|
queuedActions.addAll(actions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
account.save();
|
account.save();
|
||||||
if (!isMessageBlocked(envelope, content)) {
|
if (!isMessageBlocked(envelope, content)) {
|
||||||
|
@ -1495,7 +1522,8 @@ public class Manager implements Closeable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleMessage(SignalServiceEnvelope envelope, SignalServiceContent content, boolean ignoreAttachments) {
|
private List<HandleAction> handleMessage(SignalServiceEnvelope envelope, SignalServiceContent content, boolean ignoreAttachments) {
|
||||||
|
List<HandleAction> actions = new ArrayList<>();
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
SignalServiceAddress sender;
|
SignalServiceAddress sender;
|
||||||
if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
|
if (!envelope.isUnidentifiedSender() && envelope.hasSource()) {
|
||||||
|
@ -1510,44 +1538,28 @@ public class Manager implements Closeable {
|
||||||
SignalServiceDataMessage message = content.getDataMessage().get();
|
SignalServiceDataMessage message = content.getDataMessage().get();
|
||||||
|
|
||||||
if (content.isNeedsReceipt()) {
|
if (content.isNeedsReceipt()) {
|
||||||
try {
|
actions.add(new SendReceiptAction(sender, message.getTimestamp()));
|
||||||
sendReceipt(sender, message.getTimestamp());
|
|
||||||
} catch (IOException | UntrustedIdentityException | IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSignalServiceDataMessage(message, false, sender, account.getSelfAddress(), ignoreAttachments);
|
actions.addAll(handleSignalServiceDataMessage(message, false, sender, account.getSelfAddress(), ignoreAttachments));
|
||||||
}
|
}
|
||||||
if (content.getSyncMessage().isPresent()) {
|
if (content.getSyncMessage().isPresent()) {
|
||||||
account.setMultiDevice(true);
|
account.setMultiDevice(true);
|
||||||
SignalServiceSyncMessage syncMessage = content.getSyncMessage().get();
|
SignalServiceSyncMessage syncMessage = content.getSyncMessage().get();
|
||||||
if (syncMessage.getSent().isPresent()) {
|
if (syncMessage.getSent().isPresent()) {
|
||||||
SentTranscriptMessage message = syncMessage.getSent().get();
|
SentTranscriptMessage message = syncMessage.getSent().get();
|
||||||
handleSignalServiceDataMessage(message.getMessage(), true, sender, message.getDestination().orNull(), ignoreAttachments);
|
actions.addAll(handleSignalServiceDataMessage(message.getMessage(), true, sender, message.getDestination().orNull(), ignoreAttachments));
|
||||||
}
|
}
|
||||||
if (syncMessage.getRequest().isPresent()) {
|
if (syncMessage.getRequest().isPresent()) {
|
||||||
RequestMessage rm = syncMessage.getRequest().get();
|
RequestMessage rm = syncMessage.getRequest().get();
|
||||||
if (rm.isContactsRequest()) {
|
if (rm.isContactsRequest()) {
|
||||||
try {
|
actions.add(SendSyncContactsAction.create());
|
||||||
sendContacts();
|
|
||||||
} catch (UntrustedIdentityException | IOException | IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (rm.isGroupsRequest()) {
|
if (rm.isGroupsRequest()) {
|
||||||
try {
|
actions.add(SendSyncGroupsAction.create());
|
||||||
sendGroups();
|
|
||||||
} catch (UntrustedIdentityException | IOException | IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (rm.isBlockedListRequest()) {
|
if (rm.isBlockedListRequest()) {
|
||||||
try {
|
actions.add(SendSyncBlockedListAction.create());
|
||||||
sendBlockedList();
|
|
||||||
} catch (UntrustedIdentityException | IOException | IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// TODO Handle rm.isConfigurationRequest();
|
// TODO Handle rm.isConfigurationRequest();
|
||||||
}
|
}
|
||||||
|
@ -1681,6 +1693,7 @@ public class Manager implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getContactAvatarFile(String number) {
|
private File getContactAvatarFile(String number) {
|
||||||
|
@ -1764,7 +1777,7 @@ public class Manager implements Closeable {
|
||||||
return messageReceiver.retrieveAttachment(pointer, tmpFile, ServiceConfig.MAX_ATTACHMENT_SIZE);
|
return messageReceiver.retrieveAttachment(pointer, tmpFile, ServiceConfig.MAX_ATTACHMENT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendGroups() throws IOException, UntrustedIdentityException {
|
void sendGroups() throws IOException, UntrustedIdentityException {
|
||||||
File groupsFile = IOUtils.createTempFile();
|
File groupsFile = IOUtils.createTempFile();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -1853,7 +1866,7 @@ public class Manager implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendBlockedList() throws IOException, UntrustedIdentityException {
|
void sendBlockedList() throws IOException, UntrustedIdentityException {
|
||||||
List<SignalServiceAddress> addresses = new ArrayList<>();
|
List<SignalServiceAddress> addresses = new ArrayList<>();
|
||||||
for (ContactInfo record : account.getContactStore().getContacts()) {
|
for (ContactInfo record : account.getContactStore().getContacts()) {
|
||||||
if (record.blocked) {
|
if (record.blocked) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue