1 package org
.asamk
.signal
.dbus
;
3 import org
.asamk
.Signal
;
4 import org
.asamk
.signal
.manager
.Manager
;
5 import org
.asamk
.signal
.manager
.api
.GroupId
;
6 import org
.asamk
.signal
.manager
.api
.MessageEnvelope
;
7 import org
.asamk
.signal
.manager
.api
.RecipientAddress
;
8 import org
.freedesktop
.dbus
.connections
.impl
.DBusConnection
;
9 import org
.freedesktop
.dbus
.exceptions
.DBusException
;
10 import org
.freedesktop
.dbus
.types
.Variant
;
12 import java
.io
.Serializable
;
13 import java
.util
.ArrayList
;
14 import java
.util
.HashMap
;
15 import java
.util
.List
;
18 public class DbusReceiveMessageHandler
implements Manager
.ReceiveMessageHandler
{
20 private final DBusConnection conn
;
21 private final String objectPath
;
23 public DbusReceiveMessageHandler(DBusConnection conn
, final String objectPath
) {
25 this.objectPath
= objectPath
;
29 public void handleMessage(MessageEnvelope envelope
, Throwable exception
) {
31 sendDbusMessages(envelope
);
32 } catch (DBusException e
) {
33 throw new RuntimeException(e
);
37 private void sendDbusMessages(MessageEnvelope envelope
) throws DBusException
{
38 final var senderString
= envelope
.sourceAddress().map(RecipientAddress
::getLegacyIdentifier
).orElse("");
39 if (envelope
.receipt().isPresent()) {
40 final var receiptMessage
= envelope
.receipt().get();
41 final var type
= switch (receiptMessage
.type()) {
43 case VIEWED
-> "viewed";
44 case DELIVERY
-> "delivery";
45 case UNKNOWN
-> "unknown";
47 for (long timestamp
: receiptMessage
.timestamps()) {
48 conn
.sendMessage(new Signal
.ReceiptReceived(objectPath
, timestamp
, senderString
));
49 conn
.sendMessage(new Signal
.ReceiptReceivedV2(objectPath
, timestamp
, senderString
, type
, Map
.of()));
52 if (envelope
.data().isPresent()) {
53 var message
= envelope
.data().get();
55 var groupId
= message
.groupContext()
56 .map(MessageEnvelope
.Data
.GroupContext
::groupId
)
57 .map(GroupId
::serialize
)
58 .orElseGet(() -> new byte[0]);
59 var isGroupUpdate
= message
.groupContext()
60 .map(MessageEnvelope
.Data
.GroupContext
::isGroupUpdate
)
62 if (!message
.isEndSession() && !isGroupUpdate
) {
63 conn
.sendMessage(new Signal
.MessageReceived(objectPath
,
67 message
.body().orElse(""),
68 getAttachments(message
)));
69 conn
.sendMessage(new Signal
.MessageReceivedV2(objectPath
,
73 message
.body().orElse(""),
74 getMessageExtras(message
)));
77 if (envelope
.edit().isPresent()) {
78 var editMessage
= envelope
.edit().get();
79 var message
= editMessage
.dataMessage();
81 var groupId
= message
.groupContext()
82 .map(MessageEnvelope
.Data
.GroupContext
::groupId
)
83 .map(GroupId
::serialize
)
84 .orElseGet(() -> new byte[0]);
85 var isGroupUpdate
= message
.groupContext()
86 .map(MessageEnvelope
.Data
.GroupContext
::isGroupUpdate
)
88 if (!message
.isEndSession() && !isGroupUpdate
) {
89 conn
.sendMessage(new Signal
.EditMessageReceived(objectPath
,
91 editMessage
.targetSentTimestamp(),
94 message
.body().orElse(""),
95 getMessageExtras(message
)));
98 if (envelope
.sync().isPresent()) {
99 var syncMessage
= envelope
.sync().get();
100 if (syncMessage
.sent().isPresent()) {
101 var transcript
= syncMessage
.sent().get();
103 if (transcript
.message().isPresent()) {
104 final var dataMessage
= transcript
.message().get();
105 if (transcript
.destination().isPresent() || dataMessage
.groupContext().isPresent()) {
106 var groupId
= dataMessage
.groupContext()
107 .map(MessageEnvelope
.Data
.GroupContext
::groupId
)
108 .map(GroupId
::serialize
)
109 .orElseGet(() -> new byte[0]);
111 conn
.sendMessage(new Signal
.SyncMessageReceived(objectPath
,
112 dataMessage
.timestamp(),
114 transcript
.destination().map(RecipientAddress
::getLegacyIdentifier
).orElse(""),
116 dataMessage
.body().orElse(""),
117 getAttachments(dataMessage
)));
118 conn
.sendMessage(new Signal
.SyncMessageReceivedV2(objectPath
,
119 dataMessage
.timestamp(),
121 transcript
.destination().map(RecipientAddress
::getLegacyIdentifier
).orElse(""),
123 dataMessage
.body().orElse(""),
124 getMessageExtras(dataMessage
)));
132 private List
<String
> getAttachments(MessageEnvelope
.Data message
) {
133 var attachments
= new ArrayList
<String
>();
134 if (!message
.attachments().isEmpty()) {
135 for (var attachment
: message
.attachments()) {
136 if (attachment
.file().isPresent()) {
137 attachments
.add(attachment
.file().get().getAbsolutePath());
144 private HashMap
<String
, Variant
<?
>> getMessageExtras(MessageEnvelope
.Data message
) {
145 var extras
= new HashMap
<String
, Variant
<?
>>();
146 if (!message
.attachments().isEmpty()) {
147 var attachments
= message
.attachments()
149 .filter(a
-> a
.id().isPresent())
150 .map(this::getAttachmentMap
)
152 extras
.put("attachments", new Variant
<>(attachments
, "aa{sv}"));
154 if (!message
.mentions().isEmpty()) {
155 var mentions
= message
.mentions().stream().map(this::getMentionMap
).toList();
156 extras
.put("mentions", new Variant
<>(mentions
, "aa{sv}"));
158 extras
.put("expiresInSeconds", new Variant
<>(message
.expiresInSeconds()));
159 if (message
.quote().isPresent()) {
160 extras
.put("quote", new Variant
<>(getQuoteMap(message
.quote().get()), "a{sv}"));
162 if (message
.reaction().isPresent()) {
163 final var reaction
= message
.reaction().get();
164 extras
.put("reaction", new Variant
<>(getReactionMap(reaction
), "a{sv}"));
166 if (message
.remoteDeleteId().isPresent()) {
167 extras
.put("remoteDelete",
168 new Variant
<>(Map
.of("timestamp", new Variant
<>(message
.remoteDeleteId().get())), "a{sv}"));
170 if (message
.sticker().isPresent()) {
171 final var sticker
= message
.sticker().get();
172 extras
.put("sticker", new Variant
<>(getStickerMap(sticker
), "a{sv}"));
174 extras
.put("isViewOnce", new Variant
<>(message
.isViewOnce()));
178 private Map
<String
, Variant
<?
>> getQuoteMap(final MessageEnvelope
.Data
.Quote quote
) {
180 new Variant
<>(quote
.id()),
182 new Variant
<>(quote
.author().getLegacyIdentifier()),
184 new Variant
<>(quote
.text().orElse("")));
187 private Map
<String
, Variant
<?
extends Serializable
>> getStickerMap(final MessageEnvelope
.Data
.Sticker sticker
) {
188 return Map
.of("packId",
189 new Variant
<>(sticker
.packId().serialize()),
191 new Variant
<>(sticker
.stickerId()));
194 private Map
<String
, Variant
<?
>> getReactionMap(final MessageEnvelope
.Data
.Reaction reaction
) {
195 return Map
.of("emoji",
196 new Variant
<>(reaction
.emoji()),
198 new Variant
<>(reaction
.targetAuthor().getLegacyIdentifier()),
199 "targetSentTimestamp",
200 new Variant
<>(reaction
.targetSentTimestamp()),
202 new Variant
<>(reaction
.isRemove()));
205 private Map
<String
, Variant
<?
>> getAttachmentMap(
206 final MessageEnvelope
.Data
.Attachment a
208 final var map
= new HashMap
<String
, Variant
<?
>>();
209 if (a
.id().isPresent()) {
210 map
.put("remoteId", new Variant
<>(a
.id().get()));
212 if (a
.file().isPresent()) {
213 map
.put("file", new Variant
<>(a
.file().get().getAbsolutePath()));
215 map
.put("contentType", new Variant
<>(a
.contentType()));
216 map
.put("isVoiceNote", new Variant
<>(a
.isVoiceNote()));
217 map
.put("isBorderless", new Variant
<>(a
.isBorderless()));
218 map
.put("isGif", new Variant
<>(a
.isGif()));
219 if (a
.caption().isPresent()) {
220 map
.put("caption", new Variant
<>(a
.caption().get()));
222 if (a
.fileName().isPresent()) {
223 map
.put("fileName", new Variant
<>(a
.fileName().get()));
225 if (a
.size().isPresent()) {
226 map
.put("size", new Variant
<>(a
.size().get()));
228 if (a
.width().isPresent()) {
229 map
.put("width", new Variant
<>(a
.width().get()));
231 if (a
.height().isPresent()) {
232 map
.put("height", new Variant
<>(a
.height().get()));
237 private Map
<String
, Variant
<?
>> getMentionMap(
238 final MessageEnvelope
.Data
.Mention mention
240 return Map
.of("recipient",
241 new Variant
<>(mention
.recipient().getLegacyIdentifier()),
243 new Variant
<>(mention
.start()),
245 new Variant
<>(mention
.length()));