From: AsamK Date: Sat, 6 Nov 2021 20:09:06 +0000 (+0100) Subject: Refactor ReceiveCommand in dbus mode and remove ExtendedDbusCommand X-Git-Tag: v0.10.0~87 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/32818a8608f5bddc46ad5c7dc442f509c939791c Refactor ReceiveCommand in dbus mode and remove ExtendedDbusCommand --- diff --git a/lib/src/main/java/org/asamk/signal/manager/AttachmentStore.java b/lib/src/main/java/org/asamk/signal/manager/AttachmentStore.java index 9ba57937..f983a90b 100644 --- a/lib/src/main/java/org/asamk/signal/manager/AttachmentStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/AttachmentStore.java @@ -25,7 +25,7 @@ public class AttachmentStore { public void storeAttachment( final SignalServiceAttachmentRemoteId attachmentId, final AttachmentStorer storer ) throws IOException { - storeAttachment(getAttachmentFile(attachmentId.toString()), storer); + storeAttachment(getAttachmentFile(attachmentId), storer); } private void storeAttachment(final File attachmentFile, final AttachmentStorer storer) throws IOException { @@ -39,8 +39,8 @@ public class AttachmentStore { return new File(attachmentsPath, attachmentId.toString() + ".preview"); } - public File getAttachmentFile(String attachmentId) { - return new File(attachmentsPath, attachmentId); + public File getAttachmentFile(SignalServiceAttachmentRemoteId attachmentId) { + return new File(attachmentsPath, attachmentId.toString()); } private void createAttachmentsDir() throws IOException { diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index b4579274..65191232 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -226,8 +226,6 @@ public interface Manager extends Closeable { boolean isContactBlocked(RecipientIdentifier.Single recipient); - File getAttachmentFile(String attachmentId); - void sendContacts() throws IOException; List> getContacts(); diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index 59cfbbaa..dd7d6bee 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -1149,11 +1149,6 @@ public class ManagerImpl implements Manager { return contactHelper.isContactBlocked(recipientId); } - @Override - public File getAttachmentFile(String attachmentId) { - return attachmentHelper.getAttachmentFile(attachmentId); - } - @Override public void sendContacts() throws IOException { syncHelper.sendContacts(); diff --git a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java index dd40c81b..7d26e214 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java @@ -6,6 +6,7 @@ import org.asamk.signal.manager.helper.RecipientAddressResolver; import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientResolver; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; +import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId; import org.whispersystems.signalservice.api.messages.SignalServiceContent; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; @@ -29,6 +30,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSy import org.whispersystems.signalservice.api.messages.multidevice.ViewOnceOpenMessage; import org.whispersystems.signalservice.api.messages.multidevice.ViewedMessage; +import java.io.File; import java.util.List; import java.util.Optional; import java.util.Set; @@ -110,7 +112,8 @@ public record MessageEnvelope( static Data from( final SignalServiceDataMessage dataMessage, RecipientResolver recipientResolver, - RecipientAddressResolver addressResolver + RecipientAddressResolver addressResolver, + final AttachmentFileProvider fileProvider ) { return new Data(dataMessage.getTimestamp(), Optional.ofNullable(dataMessage.getGroupContext().transform(GroupContext::from).orNull()), @@ -125,17 +128,21 @@ public record MessageEnvelope( .transform(r -> Reaction.from(r, recipientResolver, addressResolver)) .orNull()), Optional.ofNullable(dataMessage.getQuote() - .transform(q -> Quote.from(q, recipientResolver, addressResolver)) + .transform(q -> Quote.from(q, recipientResolver, addressResolver, fileProvider)) .orNull()), dataMessage.getAttachments() - .transform(a -> a.stream().map(Attachment::from).collect(Collectors.toList())) + .transform(a -> a.stream() + .map(as -> Attachment.from(as, fileProvider)) + .collect(Collectors.toList())) .or(List.of()), Optional.ofNullable(dataMessage.getRemoteDelete() .transform(SignalServiceDataMessage.RemoteDelete::getTargetSentTimestamp) .orNull()), Optional.ofNullable(dataMessage.getSticker().transform(Sticker::from).orNull()), dataMessage.getSharedContacts() - .transform(a -> a.stream().map(SharedContact::from).collect(Collectors.toList())) + .transform(a -> a.stream() + .map(sharedContact -> SharedContact.from(sharedContact, fileProvider)) + .collect(Collectors.toList())) .or(List.of()), dataMessage.getMentions() .transform(a -> a.stream() @@ -143,7 +150,9 @@ public record MessageEnvelope( .collect(Collectors.toList())) .or(List.of()), dataMessage.getPreviews() - .transform(a -> a.stream().map(Preview::from).collect(Collectors.toList())) + .transform(a -> a.stream() + .map(preview -> Preview.from(preview, fileProvider)) + .collect(Collectors.toList())) .or(List.of())); } @@ -199,7 +208,8 @@ public record MessageEnvelope( static Quote from( SignalServiceDataMessage.Quote quote, RecipientResolver recipientResolver, - RecipientAddressResolver addressResolver + RecipientAddressResolver addressResolver, + final AttachmentFileProvider fileProvider ) { return new Quote(quote.getId(), addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(quote.getAuthor())), @@ -212,7 +222,10 @@ public record MessageEnvelope( .collect(Collectors.toList()), quote.getAttachments() == null ? List.of() - : quote.getAttachments().stream().map(Attachment::from).collect(Collectors.toList())); + : quote.getAttachments() + .stream() + .map(a -> Attachment.from(a, fileProvider)) + .collect(Collectors.toList())); } } @@ -231,6 +244,7 @@ public record MessageEnvelope( public record Attachment( Optional id, + Optional file, Optional fileName, String contentType, Optional uploadTimestamp, @@ -245,10 +259,11 @@ public record MessageEnvelope( boolean isBorderless ) { - static Attachment from(SignalServiceAttachment attachment) { + static Attachment from(SignalServiceAttachment attachment, AttachmentFileProvider fileProvider) { if (attachment.isPointer()) { final var a = attachment.asPointer(); return new Attachment(Optional.of(a.getRemoteId().toString()), + Optional.of(fileProvider.getFile(a.getRemoteId())), Optional.ofNullable(a.getFileName().orNull()), a.getContentType(), a.getUploadTimestamp() == 0 ? Optional.empty() : Optional.of(a.getUploadTimestamp()), @@ -264,6 +279,7 @@ public record MessageEnvelope( } else { final var a = attachment.asStream(); return new Attachment(Optional.empty(), + Optional.empty(), Optional.ofNullable(a.getFileName().orNull()), a.getContentType(), a.getUploadTimestamp() == 0 ? Optional.empty() : Optional.of(a.getUploadTimestamp()), @@ -279,14 +295,19 @@ public record MessageEnvelope( } } - static Attachment from(SignalServiceDataMessage.Quote.QuotedAttachment a) { + static Attachment from( + SignalServiceDataMessage.Quote.QuotedAttachment a, final AttachmentFileProvider fileProvider + ) { return new Attachment(Optional.empty(), + Optional.empty(), Optional.ofNullable(a.getFileName()), a.getContentType(), Optional.empty(), Optional.empty(), Optional.empty(), - a.getThumbnail() == null ? Optional.empty() : Optional.of(Attachment.from(a.getThumbnail())), + a.getThumbnail() == null + ? Optional.empty() + : Optional.of(Attachment.from(a.getThumbnail(), fileProvider)), Optional.empty(), Optional.empty(), Optional.empty(), @@ -312,9 +333,14 @@ public record MessageEnvelope( Optional organization ) { - static SharedContact from(org.whispersystems.signalservice.api.messages.shared.SharedContact sharedContact) { + static SharedContact from( + org.whispersystems.signalservice.api.messages.shared.SharedContact sharedContact, + final AttachmentFileProvider fileProvider + ) { return new SharedContact(Name.from(sharedContact.getName()), - Optional.ofNullable(sharedContact.getAvatar().transform(Avatar::from).orNull()), + Optional.ofNullable(sharedContact.getAvatar() + .transform(avatar1 -> Avatar.from(avatar1, fileProvider)) + .orNull()), sharedContact.getPhone() .transform(p -> p.stream().map(Phone::from).collect(Collectors.toList())) .or(List.of()), @@ -348,8 +374,11 @@ public record MessageEnvelope( public record Avatar(Attachment attachment, boolean isProfile) { - static Avatar from(org.whispersystems.signalservice.api.messages.shared.SharedContact.Avatar avatar) { - return new Avatar(Attachment.from(avatar.getAttachment()), avatar.isProfile()); + static Avatar from( + org.whispersystems.signalservice.api.messages.shared.SharedContact.Avatar avatar, + final AttachmentFileProvider fileProvider + ) { + return new Avatar(Attachment.from(avatar.getAttachment(), fileProvider), avatar.isProfile()); } } @@ -449,12 +478,16 @@ public record MessageEnvelope( public record Preview(String title, String description, long date, String url, Optional image) { - static Preview from(SignalServiceDataMessage.Preview preview) { + static Preview from( + SignalServiceDataMessage.Preview preview, final AttachmentFileProvider fileProvider + ) { return new Preview(preview.getTitle(), preview.getDescription(), preview.getDate(), preview.getUrl(), - Optional.ofNullable(preview.getImage().transform(Attachment::from).orNull())); + Optional.ofNullable(preview.getImage() + .transform(as -> Attachment.from(as, fileProvider)) + .orNull())); } } } @@ -473,10 +506,11 @@ public record MessageEnvelope( public static Sync from( final SignalServiceSyncMessage syncMessage, RecipientResolver recipientResolver, - RecipientAddressResolver addressResolver + RecipientAddressResolver addressResolver, + final AttachmentFileProvider fileProvider ) { return new Sync(Optional.ofNullable(syncMessage.getSent() - .transform(s -> Sent.from(s, recipientResolver, addressResolver)) + .transform(s -> Sent.from(s, recipientResolver, addressResolver, fileProvider)) .orNull()), Optional.ofNullable(syncMessage.getBlockedList() .transform(b -> Blocked.from(b, recipientResolver, addressResolver)) @@ -512,7 +546,8 @@ public record MessageEnvelope( static Sent from( SentTranscriptMessage sentMessage, RecipientResolver recipientResolver, - RecipientAddressResolver addressResolver + RecipientAddressResolver addressResolver, + final AttachmentFileProvider fileProvider ) { return new Sent(sentMessage.getTimestamp(), sentMessage.getExpirationStartTimestamp(), @@ -524,7 +559,7 @@ public record MessageEnvelope( .stream() .map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d))) .collect(Collectors.toSet()), - Data.from(sentMessage.getMessage(), recipientResolver, addressResolver)); + Data.from(sentMessage.getMessage(), recipientResolver, addressResolver, fileProvider)); } } @@ -692,13 +727,6 @@ public record MessageEnvelope( public record Busy(long id) { - static Offer from(OfferMessage offerMessage) { - return new Offer(offerMessage.getId(), - offerMessage.getSdp(), - Offer.Type.from(offerMessage.getType()), - offerMessage.getOpaque()); - } - static Busy from(BusyMessage busyMessage) { return new Busy(busyMessage.getId()); } @@ -763,7 +791,8 @@ public record MessageEnvelope( SignalServiceEnvelope envelope, SignalServiceContent content, RecipientResolver recipientResolver, - RecipientAddressResolver addressResolver + RecipientAddressResolver addressResolver, + final AttachmentFileProvider fileProvider ) { final var source = !envelope.isUnidentifiedSender() && envelope.hasSourceUuid() ? recipientResolver.resolveRecipient(envelope.getSourceAddress()) @@ -783,10 +812,10 @@ public record MessageEnvelope( receipt = Optional.ofNullable(content.getReceiptMessage().transform(Receipt::from).orNull()); typing = Optional.ofNullable(content.getTypingMessage().transform(Typing::from).orNull()); data = Optional.ofNullable(content.getDataMessage() - .transform(dataMessage -> Data.from(dataMessage, recipientResolver, addressResolver)) + .transform(dataMessage -> Data.from(dataMessage, recipientResolver, addressResolver, fileProvider)) .orNull()); sync = Optional.ofNullable(content.getSyncMessage() - .transform(s -> Sync.from(s, recipientResolver, addressResolver)) + .transform(s -> Sync.from(s, recipientResolver, addressResolver, fileProvider)) .orNull()); call = Optional.ofNullable(content.getCallMessage().transform(Call::from).orNull()); } else { @@ -811,4 +840,9 @@ public record MessageEnvelope( sync, call); } + + public interface AttachmentFileProvider { + + File getFile(SignalServiceAttachmentRemoteId attachmentRemoteId); + } } diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/AttachmentHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/AttachmentHelper.java index 7eea6966..449a575e 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/AttachmentHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/AttachmentHelper.java @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import org.whispersystems.libsignal.InvalidMessageException; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; +import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId; import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException; import java.io.File; @@ -35,7 +36,7 @@ public class AttachmentHelper { this.attachmentStore = attachmentStore; } - public File getAttachmentFile(String attachmentId) { + public File getAttachmentFile(SignalServiceAttachmentRemoteId attachmentId) { return attachmentStore.getAttachmentFile(attachmentId); } diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java index 8e99357f..301e0e5a 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java @@ -200,7 +200,8 @@ public final class IncomingMessageHandler { handler.handleMessage(MessageEnvelope.from(envelope, content, recipientResolver, - account.getRecipientStore()::resolveRecipientAddress), exception); + account.getRecipientStore()::resolveRecipientAddress, + attachmentHelper::getAttachmentFile), exception); return actions; } } diff --git a/src/main/java/org/asamk/signal/App.java b/src/main/java/org/asamk/signal/App.java index 7c86f09e..720a5849 100644 --- a/src/main/java/org/asamk/signal/App.java +++ b/src/main/java/org/asamk/signal/App.java @@ -8,7 +8,6 @@ import net.sourceforge.argparse4j.inf.Namespace; import org.asamk.Signal; import org.asamk.signal.commands.Command; import org.asamk.signal.commands.Commands; -import org.asamk.signal.commands.ExtendedDbusCommand; import org.asamk.signal.commands.LocalCommand; import org.asamk.signal.commands.MultiLocalCommand; import org.asamk.signal.commands.ProvisioningCommand; @@ -151,20 +150,20 @@ public class App { ? TrustNewIdentity.ON_FIRST_USE : trustNewIdentityCli == TrustNewIdentityCli.ALWAYS ? TrustNewIdentity.ALWAYS : TrustNewIdentity.NEVER; - if (command instanceof ProvisioningCommand) { + if (command instanceof ProvisioningCommand provisioningCommand) { if (username != null) { throw new UserErrorException("You cannot specify a username (phone number) when linking"); } - handleProvisioningCommand((ProvisioningCommand) command, dataPath, serviceEnvironment, outputWriter); + handleProvisioningCommand(provisioningCommand, dataPath, serviceEnvironment, outputWriter); return; } if (username == null) { var usernames = Manager.getAllLocalNumbers(dataPath); - if (command instanceof MultiLocalCommand) { - handleMultiLocalCommand((MultiLocalCommand) command, + if (command instanceof MultiLocalCommand multiLocalCommand) { + handleMultiLocalCommand(multiLocalCommand, dataPath, serviceEnvironment, usernames, @@ -185,8 +184,8 @@ public class App { throw new UserErrorException("Invalid username (phone number), make sure you include the country code."); } - if (command instanceof RegistrationCommand) { - handleRegistrationCommand((RegistrationCommand) command, username, dataPath, serviceEnvironment); + if (command instanceof RegistrationCommand registrationCommand) { + handleRegistrationCommand(registrationCommand, username, dataPath, serviceEnvironment); return; } @@ -344,11 +343,9 @@ public class App { private void handleCommand( Command command, Signal ts, DBusConnection dBusConn, OutputWriter outputWriter ) throws CommandException { - if (command instanceof ExtendedDbusCommand) { - ((ExtendedDbusCommand) command).handleCommand(ns, ts, dBusConn, outputWriter); - } else if (command instanceof LocalCommand) { + if (command instanceof LocalCommand localCommand) { try { - ((LocalCommand) command).handleCommand(ns, new DbusManagerImpl(ts, dBusConn), outputWriter); + localCommand.handleCommand(ns, new DbusManagerImpl(ts, dBusConn), outputWriter); } catch (UnsupportedOperationException e) { throw new UserErrorException("Command is not yet implemented via dbus", e); } catch (DBusExecutionException e) { diff --git a/src/main/java/org/asamk/signal/DbusReceiveMessageHandler.java b/src/main/java/org/asamk/signal/DbusReceiveMessageHandler.java index e53095da..dbb5030c 100644 --- a/src/main/java/org/asamk/signal/DbusReceiveMessageHandler.java +++ b/src/main/java/org/asamk/signal/DbusReceiveMessageHandler.java @@ -113,8 +113,8 @@ public class DbusReceiveMessageHandler implements Manager.ReceiveMessageHandler var attachments = new ArrayList(); if (message.attachments().size() > 0) { for (var attachment : message.attachments()) { - if (attachment.id().isPresent()) { - attachments.add(m.getAttachmentFile(attachment.id().get()).getAbsolutePath()); + if (attachment.file().isPresent()) { + attachments.add(attachment.file().get().getAbsolutePath()); } } } @@ -161,7 +161,7 @@ public class DbusReceiveMessageHandler implements Manager.ReceiveMessageHandler "author", new Variant<>(quote.author().getLegacyIdentifier()), "text", - new Variant<>(quote.text())); + new Variant<>(quote.text().orElse(""))); } private Map> getStickerMap(final MessageEnvelope.Data.Sticker sticker) { @@ -184,9 +184,12 @@ public class DbusReceiveMessageHandler implements Manager.ReceiveMessageHandler ) { final var map = new HashMap>(); if (a.id().isPresent()) { - map.put("file", new Variant<>(m.getAttachmentFile(a.id().get()).getAbsolutePath())); map.put("remoteId", new Variant<>(a.id().get())); } + if (a.file().isPresent()) { + map.put("file", new Variant<>(a.file().get().getAbsolutePath())); + } + map.put("contentType", new Variant<>(a.contentType())); map.put("isVoiceNote", new Variant<>(a.isVoiceNote())); map.put("isBorderless", new Variant<>(a.isBorderless())); map.put("isGif", new Variant<>(a.isGif())); diff --git a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java index b794f860..26e12809 100644 --- a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java +++ b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java @@ -543,8 +543,8 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler { if (attachment.width().isPresent() || attachment.height().isPresent()) { writer.println("Dimensions: {}x{}", attachment.width().orElse(0), attachment.height().orElse(0)); } - if (attachment.id().isPresent()) { - var file = m.getAttachmentFile(attachment.id().get()); + if (attachment.file().isPresent()) { + var file = attachment.file().get(); if (file.exists()) { writer.println("Stored plaintext in: {}", file); } diff --git a/src/main/java/org/asamk/signal/commands/ExtendedDbusCommand.java b/src/main/java/org/asamk/signal/commands/ExtendedDbusCommand.java deleted file mode 100644 index 444e4cb6..00000000 --- a/src/main/java/org/asamk/signal/commands/ExtendedDbusCommand.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.asamk.signal.commands; - -import net.sourceforge.argparse4j.inf.Namespace; - -import org.asamk.Signal; -import org.asamk.signal.OutputWriter; -import org.asamk.signal.commands.exceptions.CommandException; -import org.freedesktop.dbus.connections.impl.DBusConnection; - -public interface ExtendedDbusCommand extends CliCommand { - - void handleCommand( - Namespace ns, Signal signal, DBusConnection dbusconnection, final OutputWriter outputWriter - ) throws CommandException; -} diff --git a/src/main/java/org/asamk/signal/commands/ReceiveCommand.java b/src/main/java/org/asamk/signal/commands/ReceiveCommand.java index a69be7de..d3d9e8a6 100644 --- a/src/main/java/org/asamk/signal/commands/ReceiveCommand.java +++ b/src/main/java/org/asamk/signal/commands/ReceiveCommand.java @@ -4,7 +4,6 @@ import net.sourceforge.argparse4j.impl.Arguments; import net.sourceforge.argparse4j.inf.Namespace; import net.sourceforge.argparse4j.inf.Subparser; -import org.asamk.Signal; import org.asamk.signal.JsonReceiveMessageHandler; import org.asamk.signal.JsonWriter; import org.asamk.signal.OutputType; @@ -13,24 +12,15 @@ import org.asamk.signal.PlainTextWriter; import org.asamk.signal.ReceiveMessageHandler; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.commands.exceptions.IOErrorException; -import org.asamk.signal.commands.exceptions.UnexpectedErrorException; -import org.asamk.signal.json.JsonMessageEnvelope; import org.asamk.signal.manager.Manager; -import org.asamk.signal.util.DateUtils; -import org.freedesktop.dbus.DBusMap; -import org.freedesktop.dbus.connections.impl.DBusConnection; -import org.freedesktop.dbus.exceptions.DBusException; -import org.freedesktop.dbus.types.Variant; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.util.Base64; import java.util.List; -import java.util.Map; import java.util.concurrent.TimeUnit; -public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand { +public class ReceiveCommand implements LocalCommand { private final static Logger logger = LoggerFactory.getLogger(ReceiveCommand.class); @@ -56,106 +46,6 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand { return List.of(OutputType.PLAIN_TEXT, OutputType.JSON); } - public void handleCommand( - final Namespace ns, final Signal signal, DBusConnection dbusconnection, final OutputWriter outputWriter - ) throws CommandException { - try { - if (outputWriter instanceof JsonWriter jsonWriter) { - - dbusconnection.addSigHandler(Signal.MessageReceived.class, signal, messageReceived -> { - var envelope = JsonMessageEnvelope.from(messageReceived); - final var object = Map.of("envelope", envelope); - jsonWriter.write(object); - }); - - dbusconnection.addSigHandler(Signal.ReceiptReceived.class, signal, receiptReceived -> { - var envelope = JsonMessageEnvelope.from(receiptReceived); - final var object = Map.of("envelope", envelope); - jsonWriter.write(object); - }); - - dbusconnection.addSigHandler(Signal.SyncMessageReceived.class, signal, syncReceived -> { - var envelope = JsonMessageEnvelope.from(syncReceived); - final var object = Map.of("envelope", envelope); - jsonWriter.write(object); - }); - } else { - final var writer = (PlainTextWriter) outputWriter; - - dbusconnection.addSigHandler(Signal.MessageReceivedV2.class, signal, messageReceived -> { - writer.println("Envelope from: {}", messageReceived.getSender()); - writer.println("Timestamp: {}", DateUtils.formatTimestamp(messageReceived.getTimestamp())); - writer.println("Body: {}", messageReceived.getMessage()); - if (messageReceived.getGroupId().length > 0) { - writer.println("Group info:"); - writer.indentedWriter() - .println("Id: {}", Base64.getEncoder().encodeToString(messageReceived.getGroupId())); - } - final var extras = messageReceived.getExtras(); - printMessageExtras(writer, extras); - writer.println(); - }); - - dbusconnection.addSigHandler(Signal.ReceiptReceivedV2.class, signal, receiptReceived -> { - writer.println("Receipt from: {}", receiptReceived.getSender()); - writer.println("Timestamp: {}", DateUtils.formatTimestamp(receiptReceived.getTimestamp())); - writer.println("Type: {}", receiptReceived.getReceiptType()); - }); - - dbusconnection.addSigHandler(Signal.SyncMessageReceivedV2.class, signal, syncReceived -> { - writer.println("Sync Envelope from: {} to: {}", - syncReceived.getSource(), - syncReceived.getDestination()); - writer.println("Timestamp: {}", DateUtils.formatTimestamp(syncReceived.getTimestamp())); - writer.println("Body: {}", syncReceived.getMessage()); - if (syncReceived.getGroupId().length > 0) { - writer.println("Group info:"); - writer.indentedWriter() - .println("Id: {}", Base64.getEncoder().encodeToString(syncReceived.getGroupId())); - } - final var extras = syncReceived.getExtras(); - printMessageExtras(writer, extras); - writer.println(); - }); - } - } catch (DBusException e) { - logger.error("Dbus client failed", e); - throw new UnexpectedErrorException("Dbus client failed", e); - } - - double timeout = ns.getDouble("timeout"); - long timeoutMilliseconds = timeout < 0 ? 10000 : (long) (timeout * 1000); - - while (true) { - try { - Thread.sleep(timeoutMilliseconds); - } catch (InterruptedException ignored) { - break; - } - if (timeout >= 0) { - break; - } - } - } - - private void printMessageExtras(final PlainTextWriter writer, final Map> extras) { - if (extras.containsKey("attachments")) { - final List>> attachments = getValue(extras, "attachments"); - if (attachments.size() > 0) { - writer.println("Attachments:"); - for (var attachment : attachments) { - final String value = getValue(attachment, "file"); - writer.println("- Stored plaintext in: {}", value); - } - } - } - } - - @SuppressWarnings("unchecked") - private T getValue(final Map> stringVariantMap, final String field) { - return (T) stringVariantMap.get(field).getValue(); - } - @Override public void handleCommand( final Namespace ns, final Manager m, final OutputWriter outputWriter diff --git a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java index 4656975e..0d5ed98e 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java @@ -13,6 +13,7 @@ import org.asamk.signal.manager.api.Identity; import org.asamk.signal.manager.api.InactiveGroupLinkException; import org.asamk.signal.manager.api.InvalidDeviceLinkException; import org.asamk.signal.manager.api.Message; +import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.manager.api.Pair; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.SendGroupMessageResults; @@ -29,10 +30,13 @@ import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.manager.storage.recipients.Contact; import org.asamk.signal.manager.storage.recipients.Profile; import org.asamk.signal.manager.storage.recipients.RecipientAddress; +import org.freedesktop.dbus.DBusMap; import org.freedesktop.dbus.DBusPath; import org.freedesktop.dbus.connections.impl.DBusConnection; import org.freedesktop.dbus.exceptions.DBusException; import org.freedesktop.dbus.interfaces.DBusInterface; +import org.freedesktop.dbus.interfaces.DBusSigHandler; +import org.freedesktop.dbus.types.Variant; import java.io.File; import java.io.IOException; @@ -40,6 +44,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -59,6 +64,11 @@ public class DbusManagerImpl implements Manager { private final Signal signal; private final DBusConnection connection; + private final Set messageHandlers = new HashSet<>(); + private DBusSigHandler dbusMsgHandler; + private DBusSigHandler dbusRcptHandler; + private DBusSigHandler dbusSyncHandler; + public DbusManagerImpl(final Signal signal, DBusConnection connection) { this.signal = signal; this.connection = connection; @@ -133,7 +143,7 @@ public class DbusManagerImpl implements Manager { @Override public void submitRateLimitRecaptchaChallenge(final String challenge, final String captcha) throws IOException { - throw new UnsupportedOperationException(); + signal.submitRateLimitChallenge(challenge, captcha); } @Override @@ -308,7 +318,7 @@ public class DbusManagerImpl implements Manager { public void sendViewedReceipt( final RecipientIdentifier.Single sender, final List messageIds ) throws IOException, UntrustedIdentityException { - throw new UnsupportedOperationException(); + signal.sendViewedReceipt(sender.getIdentifier(), messageIds); } @Override @@ -414,39 +424,68 @@ public class DbusManagerImpl implements Manager { @Override public void addReceiveHandler(final ReceiveMessageHandler handler) { - throw new UnsupportedOperationException(); + synchronized (messageHandlers) { + if (messageHandlers.size() == 0) { + installMessageHandlers(); + } + messageHandlers.add(handler); + } } @Override public void removeReceiveHandler(final ReceiveMessageHandler handler) { - throw new UnsupportedOperationException(); + synchronized (messageHandlers) { + messageHandlers.remove(handler); + if (messageHandlers.size() == 0) { + try { + connection.removeSigHandler(Signal.MessageReceivedV2.class, signal, this.dbusMsgHandler); + connection.removeSigHandler(Signal.ReceiptReceivedV2.class, signal, this.dbusRcptHandler); + connection.removeSigHandler(Signal.SyncMessageReceivedV2.class, signal, this.dbusSyncHandler); + } catch (DBusException e) { + e.printStackTrace(); + } + } + } } @Override public boolean isReceiving() { - throw new UnsupportedOperationException(); + synchronized (messageHandlers) { + return messageHandlers.size() > 0; + } } @Override public void receiveMessages(final ReceiveMessageHandler handler) throws IOException { - throw new UnsupportedOperationException(); + addReceiveHandler(handler); + try { + synchronized (this) { + this.wait(); + } + } catch (InterruptedException ignored) { + } + removeReceiveHandler(handler); } @Override public void receiveMessages( final long timeout, final TimeUnit unit, final ReceiveMessageHandler handler ) throws IOException { - throw new UnsupportedOperationException(); + addReceiveHandler(handler); + try { + Thread.sleep(unit.toMillis(timeout)); + } catch (InterruptedException ignored) { + } + removeReceiveHandler(handler); } @Override public void setIgnoreAttachments(final boolean ignoreAttachments) { - throw new UnsupportedOperationException(); } @Override public boolean hasCaughtUpWithOldMessages() { - throw new UnsupportedOperationException(); + return true; } @Override @@ -454,11 +493,6 @@ public class DbusManagerImpl implements Manager { return signal.isContactBlocked(recipient.getIdentifier()); } - @Override - public File getAttachmentFile(final String attachmentId) { - throw new UnsupportedOperationException(); - } - @Override public void sendContacts() throws IOException { signal.sendContacts(); @@ -592,4 +626,168 @@ public class DbusManagerImpl implements Manager { throw new AssertionError(e); } } + + private void installMessageHandlers() { + try { + this.dbusMsgHandler = messageReceived -> { + final var extras = messageReceived.getExtras(); + final var envelope = new MessageEnvelope(Optional.of(new RecipientAddress(null, + messageReceived.getSender())), + 0, + messageReceived.getTimestamp(), + 0, + 0, + false, + Optional.empty(), + Optional.empty(), + Optional.of(new MessageEnvelope.Data(messageReceived.getTimestamp(), + messageReceived.getGroupId().length > 0 + ? Optional.of(new MessageEnvelope.Data.GroupContext(GroupId.unknownVersion( + messageReceived.getGroupId()), false, 0)) + : Optional.empty(), + Optional.empty(), + Optional.of(messageReceived.getMessage()), + 0, + false, + false, + false, + false, + Optional.empty(), + Optional.empty(), + getAttachments(extras), + Optional.empty(), + Optional.empty(), + List.of(), + List.of(), + List.of())), + Optional.empty(), + Optional.empty()); + synchronized (messageHandlers) { + for (final var messageHandler : messageHandlers) { + messageHandler.handleMessage(envelope, null); + } + } + }; + connection.addSigHandler(Signal.MessageReceivedV2.class, signal, this.dbusMsgHandler); + + this.dbusRcptHandler = receiptReceived -> { + final var type = switch (receiptReceived.getReceiptType()) { + case "read" -> MessageEnvelope.Receipt.Type.READ; + case "viewed" -> MessageEnvelope.Receipt.Type.VIEWED; + case "delivery" -> MessageEnvelope.Receipt.Type.DELIVERY; + default -> MessageEnvelope.Receipt.Type.UNKNOWN; + }; + final var envelope = new MessageEnvelope(Optional.of(new RecipientAddress(null, + receiptReceived.getSender())), + 0, + receiptReceived.getTimestamp(), + 0, + 0, + false, + Optional.of(new MessageEnvelope.Receipt(receiptReceived.getTimestamp(), + type, + List.of(receiptReceived.getTimestamp()))), + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty()); + synchronized (messageHandlers) { + for (final var messageHandler : messageHandlers) { + messageHandler.handleMessage(envelope, null); + } + } + }; + connection.addSigHandler(Signal.ReceiptReceivedV2.class, signal, this.dbusRcptHandler); + + this.dbusSyncHandler = syncReceived -> { + final var extras = syncReceived.getExtras(); + final var envelope = new MessageEnvelope(Optional.of(new RecipientAddress(null, + syncReceived.getSource())), + 0, + syncReceived.getTimestamp(), + 0, + 0, + false, + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.of(new MessageEnvelope.Sync(Optional.of(new MessageEnvelope.Sync.Sent(syncReceived.getTimestamp(), + syncReceived.getTimestamp(), + syncReceived.getDestination().isEmpty() + ? Optional.empty() + : Optional.of(new RecipientAddress(null, syncReceived.getDestination())), + Set.of(), + new MessageEnvelope.Data(syncReceived.getTimestamp(), + syncReceived.getGroupId().length > 0 + ? Optional.of(new MessageEnvelope.Data.GroupContext(GroupId.unknownVersion( + syncReceived.getGroupId()), false, 0)) + : Optional.empty(), + Optional.empty(), + Optional.of(syncReceived.getMessage()), + 0, + false, + false, + false, + false, + Optional.empty(), + Optional.empty(), + getAttachments(extras), + Optional.empty(), + Optional.empty(), + List.of(), + List.of(), + List.of()))), + Optional.empty(), + List.of(), + List.of(), + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty())), + Optional.empty()); + synchronized (messageHandlers) { + for (final var messageHandler : messageHandlers) { + messageHandler.handleMessage(envelope, null); + } + } + }; + connection.addSigHandler(Signal.SyncMessageReceivedV2.class, signal, this.dbusSyncHandler); + } catch (DBusException e) { + e.printStackTrace(); + } + } + + private List getAttachments(final Map> extras) { + if (!extras.containsKey("attachments")) { + return List.of(); + } + + final List>> attachments = getValue(extras, "attachments"); + return attachments.stream().map(a -> { + final String file = a.containsKey("file") ? getValue(a, "file") : null; + return new MessageEnvelope.Data.Attachment(a.containsKey("remoteId") + ? Optional.of(getValue(a, "remoteId")) + : Optional.empty(), + file != null ? Optional.of(new File(file)) : Optional.empty(), + Optional.empty(), + getValue(a, "contentType"), + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty(), + getValue(a, "isVoiceNote"), + getValue(a, "isGif"), + getValue(a, "isBorderless")); + }).collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + private T getValue( + final Map> stringVariantMap, final String field + ) { + return (T) stringVariantMap.get(field).getValue(); + } } diff --git a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java index 80c367c3..b7e1cf2a 100644 --- a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java +++ b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java @@ -2,14 +2,12 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; -import org.asamk.Signal; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.UntrustedIdentityException; import org.asamk.signal.manager.api.InvalidNumberException; import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.manager.api.RecipientIdentifier; -import java.util.List; import java.util.UUID; public record JsonMessageEnvelope( @@ -78,47 +76,4 @@ public record JsonMessageEnvelope( receiptMessage, typingMessage); } - - public static JsonMessageEnvelope from(Signal.MessageReceived messageReceived) { - return new JsonMessageEnvelope(messageReceived.getSource(), - null, - null, - null, - null, - messageReceived.getTimestamp(), - JsonDataMessage.from(messageReceived), - null, - null, - null, - null); - } - - public static JsonMessageEnvelope from(Signal.ReceiptReceived receiptReceived) { - return new JsonMessageEnvelope(receiptReceived.getSender(), - null, - null, - null, - null, - receiptReceived.getTimestamp(), - null, - null, - null, - JsonReceiptMessage.deliveryReceipt(receiptReceived.getTimestamp(), - List.of(receiptReceived.getTimestamp())), - null); - } - - public static JsonMessageEnvelope from(Signal.SyncMessageReceived messageReceived) { - return new JsonMessageEnvelope(messageReceived.getSource(), - null, - null, - null, - null, - messageReceived.getTimestamp(), - null, - JsonSyncMessage.from(messageReceived), - null, - null, - null); - } } diff --git a/src/main/java/org/asamk/signal/json/JsonReceiptMessage.java b/src/main/java/org/asamk/signal/json/JsonReceiptMessage.java index 5616fdb4..ec61b2f1 100644 --- a/src/main/java/org/asamk/signal/json/JsonReceiptMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonReceiptMessage.java @@ -14,8 +14,4 @@ record JsonReceiptMessage(long when, boolean isDelivery, boolean isRead, boolean final var timestamps = receiptMessage.timestamps(); return new JsonReceiptMessage(when, isDelivery, isRead, isViewed, timestamps); } - - static JsonReceiptMessage deliveryReceipt(final long when, final List timestamps) { - return new JsonReceiptMessage(when, true, false, false, timestamps); - } } diff --git a/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java index 805c32c8..7eea0472 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java @@ -2,7 +2,6 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonUnwrapped; -import org.asamk.Signal; import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; @@ -26,11 +25,4 @@ record JsonSyncDataMessage( return new JsonSyncDataMessage(null, null, null, JsonDataMessage.from(transcriptMessage.message())); } } - - static JsonSyncDataMessage from(Signal.SyncMessageReceived messageReceived) { - return new JsonSyncDataMessage(messageReceived.getDestination(), - null, - null, - JsonDataMessage.from(messageReceived)); - } } diff --git a/src/main/java/org/asamk/signal/json/JsonSyncMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncMessage.java index 554b0724..8bff7398 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncMessage.java @@ -2,7 +2,6 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; -import org.asamk.Signal; import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.storage.recipients.RecipientAddress; @@ -77,8 +76,4 @@ record JsonSyncMessage( } return new JsonSyncMessage(sentMessage, blockedNumbers, blockedGroupIds, readMessages, type); } - - static JsonSyncMessage from(Signal.SyncMessageReceived messageReceived) { - return new JsonSyncMessage(JsonSyncDataMessage.from(messageReceived), null, null, null, null); - } }