1 package org
.asamk
.signal
;
3 import org
.asamk
.Signal
;
4 import org
.asamk
.signal
.manager
.Manager
;
5 import org
.asamk
.signal
.manager
.groups
.GroupUtils
;
6 import org
.asamk
.signal
.util
.Util
;
7 import org
.freedesktop
.dbus
.connections
.impl
.DBusConnection
;
8 import org
.freedesktop
.dbus
.exceptions
.DBusException
;
9 import org
.freedesktop
.dbus
.types
.Variant
;
10 import org
.whispersystems
.signalservice
.api
.messages
.SignalServiceAttachment
;
11 import org
.whispersystems
.signalservice
.api
.messages
.SignalServiceContent
;
12 import org
.whispersystems
.signalservice
.api
.messages
.SignalServiceDataMessage
;
13 import org
.whispersystems
.signalservice
.api
.messages
.SignalServiceEnvelope
;
14 import org
.whispersystems
.signalservice
.api
.messages
.SignalServiceGroup
;
15 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
17 import java
.io
.Serializable
;
18 import java
.util
.ArrayList
;
19 import java
.util
.HashMap
;
20 import java
.util
.List
;
22 import java
.util
.stream
.Collectors
;
24 import static org
.asamk
.signal
.util
.Util
.getLegacyIdentifier
;
26 public class DbusReceiveMessageHandler
implements Manager
.ReceiveMessageHandler
{
28 private final Manager m
;
29 private final DBusConnection conn
;
30 private final String objectPath
;
32 public DbusReceiveMessageHandler(Manager m
, DBusConnection conn
, final String objectPath
) {
35 this.objectPath
= objectPath
;
39 public void handleMessage(SignalServiceEnvelope envelope
, SignalServiceContent content
, Throwable exception
) {
41 sendDbusMessages(envelope
, content
);
42 } catch (DBusException e
) {
47 private void sendDbusMessages(
48 final SignalServiceEnvelope envelope
, final SignalServiceContent content
49 ) throws DBusException
{
50 if (envelope
.isReceipt()) {
51 conn
.sendMessage(new Signal
.ReceiptReceived(objectPath
, envelope
.getTimestamp(),
52 // A receipt envelope always has a source address
53 getLegacyIdentifier(envelope
.getSourceAddress())));
54 conn
.sendMessage(new Signal
.ReceiptReceivedV2(objectPath
, envelope
.getTimestamp(),
55 // A receipt envelope always has a source address
56 getLegacyIdentifier(envelope
.getSourceAddress()), "delivery", Map
.of()));
57 } else if (content
!= null) {
58 final var sender
= !envelope
.isUnidentifiedSender() && envelope
.hasSourceUuid()
59 ? envelope
.getSourceAddress()
60 : content
.getSender();
61 final var senderString
= getLegacyIdentifier(sender
);
62 if (content
.getReceiptMessage().isPresent()) {
63 final var receiptMessage
= content
.getReceiptMessage().get();
64 final var type
= switch (receiptMessage
.getType()) {
66 case VIEWED
-> "viewed";
67 case DELIVERY
-> "delivery";
68 case UNKNOWN
-> "unknown";
70 for (long timestamp
: receiptMessage
.getTimestamps()) {
71 conn
.sendMessage(new Signal
.ReceiptReceived(objectPath
, timestamp
, senderString
));
72 conn
.sendMessage(new Signal
.ReceiptReceivedV2(objectPath
,
73 envelope
.getTimestamp(),
79 } else if (content
.getDataMessage().isPresent()) {
80 var message
= content
.getDataMessage().get();
82 var groupId
= getGroupId(message
);
83 if (!message
.isEndSession() && (
85 || message
.getGroupContext().get().getGroupV1Type() == null
86 || message
.getGroupContext().get().getGroupV1Type() == SignalServiceGroup
.Type
.DELIVER
88 conn
.sendMessage(new Signal
.MessageReceived(objectPath
,
89 message
.getTimestamp(),
91 groupId
!= null ? groupId
: new byte[0],
92 message
.getBody().or(""),
93 getAttachments(message
)));
94 conn
.sendMessage(new Signal
.MessageReceivedV2(objectPath
,
95 message
.getTimestamp(),
97 groupId
!= null ? groupId
: new byte[0],
98 message
.getBody().or(""),
99 getMessageExtras(message
)));
101 } else if (content
.getSyncMessage().isPresent()) {
102 var sync_message
= content
.getSyncMessage().get();
103 if (sync_message
.getSent().isPresent()) {
104 var transcript
= sync_message
.getSent().get();
106 if (transcript
.getDestination().isPresent() || transcript
.getMessage()
109 var message
= transcript
.getMessage();
110 var groupId
= getGroupId(message
);
112 conn
.sendMessage(new Signal
.SyncMessageReceived(objectPath
,
113 transcript
.getTimestamp(),
115 transcript
.getDestination().transform(Util
::getLegacyIdentifier
).or(""),
116 groupId
!= null ? groupId
: new byte[0],
117 message
.getBody().or(""),
118 getAttachments(message
)));
119 conn
.sendMessage(new Signal
.SyncMessageReceivedV2(objectPath
,
120 transcript
.getTimestamp(),
122 transcript
.getDestination().transform(Util
::getLegacyIdentifier
).or(""),
123 groupId
!= null ? groupId
: new byte[0],
124 message
.getBody().or(""),
125 getMessageExtras(message
)));
132 private byte[] getGroupId(final SignalServiceDataMessage message
) {
133 return message
.getGroupContext().isPresent() ? GroupUtils
.getGroupId(message
.getGroupContext().get())
137 private List
<String
> getAttachments(SignalServiceDataMessage message
) {
138 var attachments
= new ArrayList
<String
>();
139 if (message
.getAttachments().isPresent()) {
140 for (var attachment
: message
.getAttachments().get()) {
141 if (attachment
.isPointer()) {
142 attachments
.add(m
.getAttachmentFile(attachment
.asPointer().getRemoteId()).getAbsolutePath());
149 private HashMap
<String
, Variant
<?
>> getMessageExtras(SignalServiceDataMessage message
) {
150 var extras
= new HashMap
<String
, Variant
<?
>>();
151 if (message
.getAttachments().isPresent()) {
152 var attachments
= message
.getAttachments()
155 .filter(SignalServiceAttachment
::isPointer
)
156 .map(a
-> getAttachmentMap(m
, a
))
157 .collect(Collectors
.toList());
158 extras
.put("attachments", new Variant
<>(attachments
, "aa{sv}"));
160 if (message
.getMentions().isPresent()) {
161 var mentions
= message
.getMentions()
164 .map(mention
-> getMentionMap(m
, mention
))
165 .collect(Collectors
.toList());
166 extras
.put("mentions", new Variant
<>(mentions
, "aa{sv}"));
168 extras
.put("expiresInSeconds", new Variant
<>(message
.getExpiresInSeconds()));
169 if (message
.getQuote().isPresent()) {
170 extras
.put("quote", new Variant
<>(getQuoteMap(message
.getQuote().get()), "a{sv}"));
172 if (message
.getReaction().isPresent()) {
173 final var reaction
= message
.getReaction().get();
174 extras
.put("reaction", new Variant
<>(getReactionMap(reaction
), "a{sv}"));
176 if (message
.getRemoteDelete().isPresent()) {
177 extras
.put("remoteDelete",
178 new Variant
<>(Map
.of("timestamp", new Variant
<>(message
.getRemoteDelete())), "a{sv}"));
180 if (message
.getSticker().isPresent()) {
181 final var sticker
= message
.getSticker().get();
182 extras
.put("sticker", new Variant
<>(getStickerMap(sticker
), "a{sv}"));
184 extras
.put("isViewOnce", new Variant
<>(message
.isViewOnce()));
188 private Map
<String
, Variant
<?
>> getQuoteMap(final SignalServiceDataMessage
.Quote quote
) {
190 new Variant
<>(quote
.getId()),
192 new Variant
<>(getLegacyIdentifier(m
.resolveSignalServiceAddress(quote
.getAuthor()))),
194 new Variant
<>(quote
.getText()));
197 private Map
<String
, Variant
<?
extends Serializable
>> getStickerMap(final SignalServiceDataMessage
.Sticker sticker
) {
198 return Map
.of("packId", new Variant
<>(sticker
.getPackId()), "stickerId", new Variant
<>(sticker
.getStickerId()));
201 private Map
<String
, Variant
<?
>> getReactionMap(final SignalServiceDataMessage
.Reaction reaction
) {
202 return Map
.of("emoji",
203 new Variant
<>(reaction
.getEmoji()),
205 new Variant
<>(getLegacyIdentifier(m
.resolveSignalServiceAddress(reaction
.getTargetAuthor()))),
206 "targetSentTimestamp",
207 new Variant
<>(reaction
.getTargetSentTimestamp()),
209 new Variant
<>(reaction
.isRemove()));
212 private Map
<String
, Variant
<?
>> getAttachmentMap(final Manager m
, final SignalServiceAttachment attachment
) {
213 final var a
= attachment
.asPointer();
214 final var map
= new HashMap
<String
, Variant
<?
>>();
215 map
.put("file", new Variant
<>(m
.getAttachmentFile(a
.getRemoteId()).getAbsolutePath()));
216 map
.put("remoteId", new Variant
<>(a
.getRemoteId().toString()));
217 map
.put("isVoiceNote", new Variant
<>(a
.getVoiceNote()));
218 map
.put("isBorderless", new Variant
<>(a
.isBorderless()));
219 map
.put("isGif", new Variant
<>(a
.isGif()));
220 if (a
.getCaption().isPresent()) {
221 map
.put("caption", new Variant
<>(a
.getCaption().get()));
223 if (a
.getFileName().isPresent()) {
224 map
.put("fileName", new Variant
<>(a
.getFileName().get()));
226 if (a
.getSize().isPresent()) {
227 map
.put("size", new Variant
<>(a
.getSize().get()));
229 if (a
.getWidth() > 0 || a
.getHeight() > 0) {
230 map
.put("height", new Variant
<>(a
.getHeight()));
231 map
.put("width", new Variant
<>(a
.getWidth()));
236 private Map
<String
, Variant
<?
>> getMentionMap(
237 final Manager m
, final SignalServiceDataMessage
.Mention mention
239 return Map
.of("recipient",
240 new Variant
<>(getLegacyIdentifier(m
.resolveSignalServiceAddress(new SignalServiceAddress(mention
.getUuid())))),
242 new Variant
<>(mention
.getStart()),
244 new Variant
<>(mention
.getLength()));