mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 10:30:38 +00:00
Implement receive handling for story messages
This commit is contained in:
parent
81e36d4f9b
commit
a593051512
12 changed files with 443 additions and 47 deletions
|
@ -837,6 +837,55 @@
|
||||||
"allDeclaredMethods":true,
|
"allDeclaredMethods":true,
|
||||||
"allDeclaredConstructors":true
|
"allDeclaredConstructors":true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name":"org.asamk.signal.json.JsonStoryContext",
|
||||||
|
"allDeclaredFields":true,
|
||||||
|
"queryAllDeclaredMethods":true,
|
||||||
|
"queryAllDeclaredConstructors":true,
|
||||||
|
"methods":[
|
||||||
|
{"name":"authorNumber","parameterTypes":[] },
|
||||||
|
{"name":"authorUuid","parameterTypes":[] },
|
||||||
|
{"name":"sentTimestamp","parameterTypes":[] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"org.asamk.signal.json.JsonStoryMessage",
|
||||||
|
"allDeclaredFields":true,
|
||||||
|
"queryAllDeclaredMethods":true,
|
||||||
|
"queryAllDeclaredConstructors":true,
|
||||||
|
"methods":[
|
||||||
|
{"name":"allowsReplies","parameterTypes":[] },
|
||||||
|
{"name":"fileAttachment","parameterTypes":[] },
|
||||||
|
{"name":"groupId","parameterTypes":[] },
|
||||||
|
{"name":"textAttachment","parameterTypes":[] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"org.asamk.signal.json.JsonStoryMessage$TextAttachment",
|
||||||
|
"allDeclaredFields":true,
|
||||||
|
"queryAllDeclaredMethods":true,
|
||||||
|
"queryAllDeclaredConstructors":true,
|
||||||
|
"methods":[
|
||||||
|
{"name":"backgroundColor","parameterTypes":[] },
|
||||||
|
{"name":"backgroundGradient","parameterTypes":[] },
|
||||||
|
{"name":"preview","parameterTypes":[] },
|
||||||
|
{"name":"style","parameterTypes":[] },
|
||||||
|
{"name":"text","parameterTypes":[] },
|
||||||
|
{"name":"textBackgroundColor","parameterTypes":[] },
|
||||||
|
{"name":"textForegroundColor","parameterTypes":[] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"org.asamk.signal.json.JsonStoryMessage$TextAttachment$Gradient",
|
||||||
|
"allDeclaredFields":true,
|
||||||
|
"queryAllDeclaredMethods":true,
|
||||||
|
"queryAllDeclaredConstructors":true,
|
||||||
|
"methods":[
|
||||||
|
{"name":"angle","parameterTypes":[] },
|
||||||
|
{"name":"endColor","parameterTypes":[] },
|
||||||
|
{"name":"startColor","parameterTypes":[] }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name":"org.asamk.signal.json.JsonSyncDataMessage",
|
"name":"org.asamk.signal.json.JsonSyncDataMessage",
|
||||||
"allDeclaredFields":true,
|
"allDeclaredFields":true,
|
||||||
|
@ -860,6 +909,17 @@
|
||||||
"allDeclaredMethods":true,
|
"allDeclaredMethods":true,
|
||||||
"allDeclaredConstructors":true
|
"allDeclaredConstructors":true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name":"org.asamk.signal.json.JsonSyncStoryMessage",
|
||||||
|
"allDeclaredFields":true,
|
||||||
|
"queryAllDeclaredMethods":true,
|
||||||
|
"queryAllDeclaredConstructors":true,
|
||||||
|
"methods":[
|
||||||
|
{"name":"dataMessage","parameterTypes":[] },
|
||||||
|
{"name":"destinationNumber","parameterTypes":[] },
|
||||||
|
{"name":"destinationUuid","parameterTypes":[] }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name":"org.asamk.signal.json.JsonTypingMessage",
|
"name":"org.asamk.signal.json.JsonTypingMessage",
|
||||||
"allDeclaredFields":true,
|
"allDeclaredFields":true,
|
||||||
|
@ -3106,6 +3166,28 @@
|
||||||
{"name":"timestamp_"}
|
{"name":"timestamp_"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$TextAttachment",
|
||||||
|
"fields":[
|
||||||
|
{"name":"backgroundCase_"},
|
||||||
|
{"name":"background_"},
|
||||||
|
{"name":"bitField0_"},
|
||||||
|
{"name":"preview_"},
|
||||||
|
{"name":"textBackgroundColor_"},
|
||||||
|
{"name":"textForegroundColor_"},
|
||||||
|
{"name":"textStyle_"},
|
||||||
|
{"name":"text_"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$TextAttachment$Gradient",
|
||||||
|
"fields":[
|
||||||
|
{"name":"angle_"},
|
||||||
|
{"name":"bitField0_"},
|
||||||
|
{"name":"endColor_"},
|
||||||
|
{"name":"startColor_"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$TypingMessage",
|
"name":"org.whispersystems.signalservice.internal.push.SignalServiceProtos$TypingMessage",
|
||||||
"fields":[
|
"fields":[
|
||||||
|
|
24
lib/src/main/java/org/asamk/signal/manager/api/Color.java
Normal file
24
lib/src/main/java/org/asamk/signal/manager/api/Color.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package org.asamk.signal.manager.api;
|
||||||
|
|
||||||
|
public record Color(int color) {
|
||||||
|
|
||||||
|
public int alpha() {
|
||||||
|
return color >>> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int red() {
|
||||||
|
return (color >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int green() {
|
||||||
|
return (color >> 8) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int blue() {
|
||||||
|
return color & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toHexColor() {
|
||||||
|
return String.format("#%08x", color);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,8 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServicePreview;
|
import org.whispersystems.signalservice.api.messages.SignalServicePreview;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceTextAttachment;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
|
import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
|
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
|
||||||
|
@ -49,7 +51,8 @@ public record MessageEnvelope(
|
||||||
Optional<Typing> typing,
|
Optional<Typing> typing,
|
||||||
Optional<Data> data,
|
Optional<Data> data,
|
||||||
Optional<Sync> sync,
|
Optional<Sync> sync,
|
||||||
Optional<Call> call
|
Optional<Call> call,
|
||||||
|
Optional<Story> story
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public record Receipt(long when, Type type, List<Long> timestamps) {
|
public record Receipt(long when, Type type, List<Long> timestamps) {
|
||||||
|
@ -94,6 +97,7 @@ public record MessageEnvelope(
|
||||||
public record Data(
|
public record Data(
|
||||||
long timestamp,
|
long timestamp,
|
||||||
Optional<GroupContext> groupContext,
|
Optional<GroupContext> groupContext,
|
||||||
|
Optional<StoryContext> storyContext,
|
||||||
Optional<GroupCallUpdate> groupCallUpdate,
|
Optional<GroupCallUpdate> groupCallUpdate,
|
||||||
Optional<String> body,
|
Optional<String> body,
|
||||||
int expiresInSeconds,
|
int expiresInSeconds,
|
||||||
|
@ -121,6 +125,10 @@ public record MessageEnvelope(
|
||||||
) {
|
) {
|
||||||
return new Data(dataMessage.getTimestamp(),
|
return new Data(dataMessage.getTimestamp(),
|
||||||
dataMessage.getGroupContext().map(GroupContext::from),
|
dataMessage.getGroupContext().map(GroupContext::from),
|
||||||
|
dataMessage.getStoryContext()
|
||||||
|
.map((SignalServiceDataMessage.StoryContext storyContext) -> StoryContext.from(storyContext,
|
||||||
|
recipientResolver,
|
||||||
|
addressResolver)),
|
||||||
dataMessage.getGroupCallUpdate().map(GroupCallUpdate::from),
|
dataMessage.getGroupCallUpdate().map(GroupCallUpdate::from),
|
||||||
dataMessage.getBody(),
|
dataMessage.getBody(),
|
||||||
dataMessage.getExpiresInSeconds(),
|
dataMessage.getExpiresInSeconds(),
|
||||||
|
@ -168,6 +176,18 @@ public record MessageEnvelope(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record StoryContext(RecipientAddress author, long sentTimestamp) {
|
||||||
|
|
||||||
|
static StoryContext from(
|
||||||
|
SignalServiceDataMessage.StoryContext storyContext,
|
||||||
|
RecipientResolver recipientResolver,
|
||||||
|
RecipientAddressResolver addressResolver
|
||||||
|
) {
|
||||||
|
return new StoryContext(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(
|
||||||
|
storyContext.getAuthorServiceId())), storyContext.getSentTimestamp());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public record GroupCallUpdate(String eraId) {
|
public record GroupCallUpdate(String eraId) {
|
||||||
|
|
||||||
static GroupCallUpdate from(SignalServiceDataMessage.GroupCallUpdate groupCallUpdate) {
|
static GroupCallUpdate from(SignalServiceDataMessage.GroupCallUpdate groupCallUpdate) {
|
||||||
|
@ -519,7 +539,8 @@ public record MessageEnvelope(
|
||||||
long expirationStartTimestamp,
|
long expirationStartTimestamp,
|
||||||
Optional<RecipientAddress> destination,
|
Optional<RecipientAddress> destination,
|
||||||
Set<RecipientAddress> recipients,
|
Set<RecipientAddress> recipients,
|
||||||
Optional<Data> message
|
Optional<Data> message,
|
||||||
|
Optional<Story> story
|
||||||
) {
|
) {
|
||||||
|
|
||||||
static Sent from(
|
static Sent from(
|
||||||
|
@ -537,7 +558,8 @@ public record MessageEnvelope(
|
||||||
.map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d)))
|
.map(d -> addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(d)))
|
||||||
.collect(Collectors.toSet()),
|
.collect(Collectors.toSet()),
|
||||||
sentMessage.getDataMessage()
|
sentMessage.getDataMessage()
|
||||||
.map(message -> Data.from(message, recipientResolver, addressResolver, fileProvider)));
|
.map(message -> Data.from(message, recipientResolver, addressResolver, fileProvider)),
|
||||||
|
sentMessage.getStoryMessage().map(s -> Story.from(s, fileProvider)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,6 +779,75 @@ public record MessageEnvelope(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record Story(
|
||||||
|
boolean allowsReplies,
|
||||||
|
Optional<GroupId> groupId,
|
||||||
|
Optional<Data.Attachment> fileAttachment,
|
||||||
|
Optional<TextAttachment> textAttachment
|
||||||
|
) {
|
||||||
|
|
||||||
|
public static Story from(
|
||||||
|
SignalServiceStoryMessage storyMessage, final AttachmentFileProvider fileProvider
|
||||||
|
) {
|
||||||
|
return new Story(storyMessage.getAllowsReplies().orElse(false),
|
||||||
|
storyMessage.getGroupContext().map(c -> GroupUtils.getGroupIdV2(c.getMasterKey())),
|
||||||
|
storyMessage.getFileAttachment().map(f -> Data.Attachment.from(f, fileProvider)),
|
||||||
|
storyMessage.getTextAttachment().map(t -> TextAttachment.from(t, fileProvider)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public record TextAttachment(
|
||||||
|
Optional<String> text,
|
||||||
|
Optional<Style> style,
|
||||||
|
Optional<Color> textForegroundColor,
|
||||||
|
Optional<Color> textBackgroundColor,
|
||||||
|
Optional<Data.Preview> preview,
|
||||||
|
Optional<Gradient> backgroundGradient,
|
||||||
|
Optional<Color> backgroundColor
|
||||||
|
) {
|
||||||
|
|
||||||
|
static TextAttachment from(
|
||||||
|
SignalServiceTextAttachment textAttachment, final AttachmentFileProvider fileProvider
|
||||||
|
) {
|
||||||
|
return new TextAttachment(textAttachment.getText(),
|
||||||
|
textAttachment.getStyle().map(Style::from),
|
||||||
|
textAttachment.getTextForegroundColor().map(Color::new),
|
||||||
|
textAttachment.getTextBackgroundColor().map(Color::new),
|
||||||
|
textAttachment.getPreview().map(p -> Data.Preview.from(p, fileProvider)),
|
||||||
|
textAttachment.getBackgroundGradient().map(Gradient::from),
|
||||||
|
textAttachment.getBackgroundColor().map(Color::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Style {
|
||||||
|
DEFAULT,
|
||||||
|
REGULAR,
|
||||||
|
BOLD,
|
||||||
|
SERIF,
|
||||||
|
SCRIPT,
|
||||||
|
CONDENSED;
|
||||||
|
|
||||||
|
static Style from(SignalServiceTextAttachment.Style style) {
|
||||||
|
return switch (style) {
|
||||||
|
case DEFAULT -> DEFAULT;
|
||||||
|
case REGULAR -> REGULAR;
|
||||||
|
case BOLD -> BOLD;
|
||||||
|
case SERIF -> SERIF;
|
||||||
|
case SCRIPT -> SCRIPT;
|
||||||
|
case CONDENSED -> CONDENSED;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Gradient(Optional<Color> startColor, Optional<Color> endColor, Optional<Integer> angle) {
|
||||||
|
|
||||||
|
static Gradient from(SignalServiceTextAttachment.Gradient gradient) {
|
||||||
|
return new Gradient(gradient.getStartColor().map(Color::new),
|
||||||
|
gradient.getEndColor().map(Color::new),
|
||||||
|
gradient.getAngle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static MessageEnvelope from(
|
public static MessageEnvelope from(
|
||||||
SignalServiceEnvelope envelope,
|
SignalServiceEnvelope envelope,
|
||||||
SignalServiceContent content,
|
SignalServiceContent content,
|
||||||
|
@ -783,6 +874,7 @@ public record MessageEnvelope(
|
||||||
Optional<Data> data;
|
Optional<Data> data;
|
||||||
Optional<Sync> sync;
|
Optional<Sync> sync;
|
||||||
Optional<Call> call;
|
Optional<Call> call;
|
||||||
|
Optional<Story> story;
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
receipt = content.getReceiptMessage().map(Receipt::from);
|
receipt = content.getReceiptMessage().map(Receipt::from);
|
||||||
typing = content.getTypingMessage().map(Typing::from);
|
typing = content.getTypingMessage().map(Typing::from);
|
||||||
|
@ -790,6 +882,7 @@ public record MessageEnvelope(
|
||||||
.map(dataMessage -> Data.from(dataMessage, recipientResolver, addressResolver, fileProvider));
|
.map(dataMessage -> Data.from(dataMessage, recipientResolver, addressResolver, fileProvider));
|
||||||
sync = content.getSyncMessage().map(s -> Sync.from(s, recipientResolver, addressResolver, fileProvider));
|
sync = content.getSyncMessage().map(s -> Sync.from(s, recipientResolver, addressResolver, fileProvider));
|
||||||
call = content.getCallMessage().map(Call::from);
|
call = content.getCallMessage().map(Call::from);
|
||||||
|
story = content.getStoryMessage().map(s -> Story.from(s, fileProvider));
|
||||||
} else {
|
} else {
|
||||||
receipt = envelope.isReceipt() ? Optional.of(new Receipt(envelope.getServerReceivedTimestamp(),
|
receipt = envelope.isReceipt() ? Optional.of(new Receipt(envelope.getServerReceivedTimestamp(),
|
||||||
Receipt.Type.DELIVERY,
|
Receipt.Type.DELIVERY,
|
||||||
|
@ -798,6 +891,7 @@ public record MessageEnvelope(
|
||||||
data = Optional.empty();
|
data = Optional.empty();
|
||||||
sync = Optional.empty();
|
sync = Optional.empty();
|
||||||
call = Optional.empty();
|
call = Optional.empty();
|
||||||
|
story = Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MessageEnvelope(source == null
|
return new MessageEnvelope(source == null
|
||||||
|
@ -812,7 +906,8 @@ public record MessageEnvelope(
|
||||||
typing,
|
typing,
|
||||||
data,
|
data,
|
||||||
sync,
|
sync,
|
||||||
call);
|
call,
|
||||||
|
story);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface AttachmentFileProvider {
|
public interface AttachmentFileProvider {
|
||||||
|
|
|
@ -52,7 +52,9 @@ import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
@ -276,6 +278,11 @@ public final class IncomingMessageHandler {
|
||||||
receiveConfig.ignoreAttachments()));
|
receiveConfig.ignoreAttachments()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (content.getStoryMessage().isPresent()) {
|
||||||
|
final var message = content.getStoryMessage().get();
|
||||||
|
actions.addAll(handleSignalServiceStoryMessage(message, sender, receiveConfig.ignoreAttachments()));
|
||||||
|
}
|
||||||
|
|
||||||
if (content.getSyncMessage().isPresent()) {
|
if (content.getSyncMessage().isPresent()) {
|
||||||
var syncMessage = content.getSyncMessage().get();
|
var syncMessage = content.getSyncMessage().get();
|
||||||
actions.addAll(handleSyncMessage(syncMessage, sender, receiveConfig.ignoreAttachments()));
|
actions.addAll(handleSyncMessage(syncMessage, sender, receiveConfig.ignoreAttachments()));
|
||||||
|
@ -347,6 +354,11 @@ public final class IncomingMessageHandler {
|
||||||
destination == null ? null : context.getRecipientHelper().resolveRecipient(destination),
|
destination == null ? null : context.getRecipientHelper().resolveRecipient(destination),
|
||||||
ignoreAttachments));
|
ignoreAttachments));
|
||||||
}
|
}
|
||||||
|
if (message.getStoryMessage().isPresent()) {
|
||||||
|
actions.addAll(handleSignalServiceStoryMessage(message.getStoryMessage().get(),
|
||||||
|
sender,
|
||||||
|
ignoreAttachments));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (syncMessage.getRequest().isPresent() && account.isPrimaryDevice()) {
|
if (syncMessage.getRequest().isPresent() && account.isPrimaryDevice()) {
|
||||||
var rm = syncMessage.getRequest().get();
|
var rm = syncMessage.getRequest().get();
|
||||||
|
@ -566,8 +578,9 @@ public final class IncomingMessageHandler {
|
||||||
) {
|
) {
|
||||||
var actions = new ArrayList<HandleAction>();
|
var actions = new ArrayList<HandleAction>();
|
||||||
if (message.getGroupContext().isPresent()) {
|
if (message.getGroupContext().isPresent()) {
|
||||||
if (message.getGroupContext().get().getGroupV1().isPresent()) {
|
final var groupContext = message.getGroupContext().get();
|
||||||
var groupInfo = message.getGroupContext().get().getGroupV1().get();
|
if (groupContext.getGroupV1().isPresent()) {
|
||||||
|
var groupInfo = groupContext.getGroupV1().get();
|
||||||
var groupId = GroupId.v1(groupInfo.getGroupId());
|
var groupId = GroupId.v1(groupInfo.getGroupId());
|
||||||
var group = context.getGroupHelper().getGroup(groupId);
|
var group = context.getGroupHelper().getGroup(groupId);
|
||||||
if (group == null || group instanceof GroupInfoV1) {
|
if (group == null || group instanceof GroupInfoV1) {
|
||||||
|
@ -620,14 +633,8 @@ public final class IncomingMessageHandler {
|
||||||
// Received a group v1 message for a v2 group
|
// Received a group v1 message for a v2 group
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (message.getGroupContext().get().getGroupV2().isPresent()) {
|
if (groupContext.getGroupV2().isPresent()) {
|
||||||
final var groupContext = message.getGroupContext().get().getGroupV2().get();
|
handleGroupV2Context(groupContext.getGroupV2().get());
|
||||||
final var groupMasterKey = groupContext.getMasterKey();
|
|
||||||
|
|
||||||
context.getGroupHelper()
|
|
||||||
.getOrMigrateGroup(groupMasterKey,
|
|
||||||
groupContext.getRevision(),
|
|
||||||
groupContext.hasSignedGroupChange() ? groupContext.getSignedGroupChange() : null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,8 +644,9 @@ public final class IncomingMessageHandler {
|
||||||
}
|
}
|
||||||
if (message.isExpirationUpdate() || message.getBody().isPresent()) {
|
if (message.isExpirationUpdate() || message.getBody().isPresent()) {
|
||||||
if (message.getGroupContext().isPresent()) {
|
if (message.getGroupContext().isPresent()) {
|
||||||
if (message.getGroupContext().get().getGroupV1().isPresent()) {
|
final var groupContext = message.getGroupContext().get();
|
||||||
var groupInfo = message.getGroupContext().get().getGroupV1().get();
|
if (groupContext.getGroupV1().isPresent()) {
|
||||||
|
var groupInfo = groupContext.getGroupV1().get();
|
||||||
var group = account.getGroupStore().getOrCreateGroupV1(GroupId.v1(groupInfo.getGroupId()));
|
var group = account.getGroupStore().getOrCreateGroupV1(GroupId.v1(groupInfo.getGroupId()));
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
if (group.messageExpirationTime != message.getExpiresInSeconds()) {
|
if (group.messageExpirationTime != message.getExpiresInSeconds()) {
|
||||||
|
@ -646,7 +654,7 @@ public final class IncomingMessageHandler {
|
||||||
account.getGroupStore().updateGroup(group);
|
account.getGroupStore().updateGroup(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.getGroupContext().get().getGroupV2().isPresent()) {
|
} else if (groupContext.getGroupV2().isPresent()) {
|
||||||
// disappearing message timer already stored in the DecryptedGroup
|
// disappearing message timer already stored in the DecryptedGroup
|
||||||
}
|
}
|
||||||
} else if (conversationPartnerAddress != null) {
|
} else if (conversationPartnerAddress != null) {
|
||||||
|
@ -686,17 +694,8 @@ public final class IncomingMessageHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (message.getProfileKey().isPresent() && message.getProfileKey().get().length == 32) {
|
if (message.getProfileKey().isPresent()) {
|
||||||
final ProfileKey profileKey;
|
handleIncomingProfileKey(message.getProfileKey().get(), source);
|
||||||
try {
|
|
||||||
profileKey = new ProfileKey(message.getProfileKey().get());
|
|
||||||
} catch (InvalidInputException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
if (account.getSelfRecipientId().equals(source)) {
|
|
||||||
this.account.setProfileKey(profileKey);
|
|
||||||
}
|
|
||||||
this.account.getProfileStore().storeProfileKey(source, profileKey);
|
|
||||||
}
|
}
|
||||||
if (message.getSticker().isPresent()) {
|
if (message.getSticker().isPresent()) {
|
||||||
final var messageSticker = message.getSticker().get();
|
final var messageSticker = message.getSticker().get();
|
||||||
|
@ -711,6 +710,62 @@ public final class IncomingMessageHandler {
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<HandleAction> handleSignalServiceStoryMessage(
|
||||||
|
SignalServiceStoryMessage message, RecipientId source, boolean ignoreAttachments
|
||||||
|
) {
|
||||||
|
var actions = new ArrayList<HandleAction>();
|
||||||
|
if (message.getGroupContext().isPresent()) {
|
||||||
|
handleGroupV2Context(message.getGroupContext().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignoreAttachments) {
|
||||||
|
if (message.getFileAttachment().isPresent()) {
|
||||||
|
context.getAttachmentHelper().downloadAttachment(message.getFileAttachment().get());
|
||||||
|
}
|
||||||
|
if (message.getTextAttachment().isPresent()) {
|
||||||
|
final var textAttachment = message.getTextAttachment().get();
|
||||||
|
if (textAttachment.getPreview().isPresent()) {
|
||||||
|
final var preview = textAttachment.getPreview().get();
|
||||||
|
if (preview.getImage().isPresent()) {
|
||||||
|
context.getAttachmentHelper().downloadAttachment(preview.getImage().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.getProfileKey().isPresent()) {
|
||||||
|
handleIncomingProfileKey(message.getProfileKey().get(), source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGroupV2Context(final SignalServiceGroupV2 groupContext) {
|
||||||
|
final var groupMasterKey = groupContext.getMasterKey();
|
||||||
|
|
||||||
|
context.getGroupHelper()
|
||||||
|
.getOrMigrateGroup(groupMasterKey,
|
||||||
|
groupContext.getRevision(),
|
||||||
|
groupContext.hasSignedGroupChange() ? groupContext.getSignedGroupChange() : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleIncomingProfileKey(final byte[] profileKeyBytes, final RecipientId source) {
|
||||||
|
if (profileKeyBytes.length != 32) {
|
||||||
|
logger.debug("Received invalid profile key of length {}", profileKeyBytes.length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ProfileKey profileKey;
|
||||||
|
try {
|
||||||
|
profileKey = new ProfileKey(profileKeyBytes);
|
||||||
|
} catch (InvalidInputException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
if (account.getSelfRecipientId().equals(source)) {
|
||||||
|
this.account.setProfileKey(profileKey);
|
||||||
|
}
|
||||||
|
this.account.getProfileStore().storeProfileKey(source, profileKey);
|
||||||
|
}
|
||||||
|
|
||||||
private Pair<RecipientId, Integer> getSender(SignalServiceEnvelope envelope, SignalServiceContent content) {
|
private Pair<RecipientId, Integer> getSender(SignalServiceEnvelope envelope, SignalServiceContent content) {
|
||||||
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
|
if (!envelope.isUnidentifiedSender() && envelope.hasSourceUuid()) {
|
||||||
return new Pair<>(context.getRecipientHelper().resolveRecipient(envelope.getSourceAddress()),
|
return new Pair<>(context.getRecipientHelper().resolveRecipient(envelope.getSourceAddress()),
|
||||||
|
|
|
@ -68,6 +68,10 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
||||||
var message = envelope.data().get();
|
var message = envelope.data().get();
|
||||||
printDataMessage(writer, message);
|
printDataMessage(writer, message);
|
||||||
}
|
}
|
||||||
|
if (envelope.story().isPresent()) {
|
||||||
|
var message = envelope.story().get();
|
||||||
|
printStoryMessage(writer.indentedWriter(), message);
|
||||||
|
}
|
||||||
if (envelope.sync().isPresent()) {
|
if (envelope.sync().isPresent()) {
|
||||||
writer.println("Received a sync message");
|
writer.println("Received a sync message");
|
||||||
var syncMessage = envelope.sync().get();
|
var syncMessage = envelope.sync().get();
|
||||||
|
@ -107,6 +111,11 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
||||||
final var groupContext = message.groupContext().get();
|
final var groupContext = message.groupContext().get();
|
||||||
printGroupContext(writer.indentedWriter(), groupContext);
|
printGroupContext(writer.indentedWriter(), groupContext);
|
||||||
}
|
}
|
||||||
|
if (message.storyContext().isPresent()) {
|
||||||
|
writer.println("Story reply:");
|
||||||
|
final var storyContext = message.storyContext().get();
|
||||||
|
printStoryContext(writer.indentedWriter(), storyContext);
|
||||||
|
}
|
||||||
if (message.groupCallUpdate().isPresent()) {
|
if (message.groupCallUpdate().isPresent()) {
|
||||||
writer.println("Group call update:");
|
writer.println("Group call update:");
|
||||||
final var groupCallUpdate = message.groupCallUpdate().get();
|
final var groupCallUpdate = message.groupCallUpdate().get();
|
||||||
|
@ -176,6 +185,28 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printStoryMessage(
|
||||||
|
PlainTextWriter writer, MessageEnvelope.Story message
|
||||||
|
) {
|
||||||
|
writer.println("Story: with replies: {}", message.allowsReplies());
|
||||||
|
if (message.groupId().isPresent()) {
|
||||||
|
writer.println("Group info:");
|
||||||
|
printGroupInfo(writer.indentedWriter(), message.groupId().get());
|
||||||
|
}
|
||||||
|
if (message.textAttachment().isPresent()) {
|
||||||
|
writer.println("Body: {}", message.textAttachment().get().text().orElse(""));
|
||||||
|
|
||||||
|
if (message.textAttachment().get().preview().isPresent()) {
|
||||||
|
writer.println("Preview:");
|
||||||
|
printPreview(writer.indentedWriter(), message.textAttachment().get().preview().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message.fileAttachment().isPresent()) {
|
||||||
|
writer.println("Attachments:");
|
||||||
|
printAttachment(writer.indentedWriter(), message.fileAttachment().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void printTypingMessage(
|
private void printTypingMessage(
|
||||||
final PlainTextWriter writer, final MessageEnvelope.Typing typingMessage
|
final PlainTextWriter writer, final MessageEnvelope.Typing typingMessage
|
||||||
) {
|
) {
|
||||||
|
@ -305,6 +336,10 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
||||||
var message = sentTranscriptMessage.message().get();
|
var message = sentTranscriptMessage.message().get();
|
||||||
printDataMessage(writer.indentedWriter(), message);
|
printDataMessage(writer.indentedWriter(), message);
|
||||||
}
|
}
|
||||||
|
if (sentTranscriptMessage.story().isPresent()) {
|
||||||
|
var message = sentTranscriptMessage.story().get();
|
||||||
|
printStoryMessage(writer.indentedWriter(), message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (syncMessage.blocked().isPresent()) {
|
if (syncMessage.blocked().isPresent()) {
|
||||||
writer.println("Received sync message with block list");
|
writer.println("Received sync message with block list");
|
||||||
|
@ -495,6 +530,13 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
|
||||||
writer.println("Type: {}", groupContext.isGroupUpdate() ? "UPDATE" : "DELIVER");
|
writer.println("Type: {}", groupContext.isGroupUpdate() ? "UPDATE" : "DELIVER");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printStoryContext(
|
||||||
|
final PlainTextWriter writer, final MessageEnvelope.Data.StoryContext storyContext
|
||||||
|
) {
|
||||||
|
writer.println("Sender: {}", formatContact(storyContext.author()));
|
||||||
|
writer.println("Sent timestamp: {}", storyContext.sentTimestamp());
|
||||||
|
}
|
||||||
|
|
||||||
private void printGroupInfo(final PlainTextWriter writer, final GroupId groupId) {
|
private void printGroupInfo(final PlainTextWriter writer, final GroupId groupId) {
|
||||||
writer.println("Id: {}", groupId.toBase64());
|
writer.println("Id: {}", groupId.toBase64());
|
||||||
|
|
||||||
|
|
|
@ -751,6 +751,7 @@ public class DbusManagerImpl implements Manager {
|
||||||
messageReceived.getGroupId()), false, 0))
|
messageReceived.getGroupId()), false, 0))
|
||||||
: Optional.empty(),
|
: Optional.empty(),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
|
Optional.empty(),
|
||||||
Optional.of(messageReceived.getMessage()),
|
Optional.of(messageReceived.getMessage()),
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
|
@ -768,6 +769,7 @@ public class DbusManagerImpl implements Manager {
|
||||||
List.of(),
|
List.of(),
|
||||||
List.of())),
|
List.of())),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
|
Optional.empty(),
|
||||||
Optional.empty());
|
Optional.empty());
|
||||||
notifyMessageHandlers(envelope);
|
notifyMessageHandlers(envelope);
|
||||||
};
|
};
|
||||||
|
@ -793,6 +795,7 @@ public class DbusManagerImpl implements Manager {
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
|
Optional.empty(),
|
||||||
Optional.empty());
|
Optional.empty());
|
||||||
notifyMessageHandlers(envelope);
|
notifyMessageHandlers(envelope);
|
||||||
};
|
};
|
||||||
|
@ -822,6 +825,7 @@ public class DbusManagerImpl implements Manager {
|
||||||
syncReceived.getGroupId()), false, 0))
|
syncReceived.getGroupId()), false, 0))
|
||||||
: Optional.empty(),
|
: Optional.empty(),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
|
Optional.empty(),
|
||||||
Optional.of(syncReceived.getMessage()),
|
Optional.of(syncReceived.getMessage()),
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
|
@ -837,7 +841,8 @@ public class DbusManagerImpl implements Manager {
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
List.of(),
|
List.of(),
|
||||||
List.of(),
|
List.of(),
|
||||||
List.of())))),
|
List.of())),
|
||||||
|
Optional.empty())),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
List.of(),
|
List.of(),
|
||||||
List.of(),
|
List.of(),
|
||||||
|
@ -845,6 +850,7 @@ public class DbusManagerImpl implements Manager {
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
Optional.empty())),
|
Optional.empty())),
|
||||||
|
Optional.empty(),
|
||||||
Optional.empty());
|
Optional.empty());
|
||||||
notifyMessageHandlers(envelope);
|
notifyMessageHandlers(envelope);
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,13 +20,17 @@ record JsonDataMessage(
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSticker sticker,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSticker sticker,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonRemoteDelete remoteDelete,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonRemoteDelete remoteDelete,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) List<JsonSharedContact> contacts,
|
@JsonInclude(JsonInclude.Include.NON_NULL) List<JsonSharedContact> contacts,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonGroupInfo groupInfo
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonGroupInfo groupInfo,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonStoryContext storyContext
|
||||||
) {
|
) {
|
||||||
|
|
||||||
static JsonDataMessage from(MessageEnvelope.Data dataMessage) {
|
static JsonDataMessage from(MessageEnvelope.Data dataMessage) {
|
||||||
final var timestamp = dataMessage.timestamp();
|
final var timestamp = dataMessage.timestamp();
|
||||||
final var groupInfo = dataMessage.groupContext().isPresent() ? JsonGroupInfo.from(dataMessage.groupContext()
|
final var groupInfo = dataMessage.groupContext().isPresent() ? JsonGroupInfo.from(dataMessage.groupContext()
|
||||||
.get()) : null;
|
.get()) : null;
|
||||||
|
final var storyContext = dataMessage.storyContext().isPresent()
|
||||||
|
? JsonStoryContext.from(dataMessage.storyContext().get())
|
||||||
|
: null;
|
||||||
final var message = dataMessage.body().orElse(null);
|
final var message = dataMessage.body().orElse(null);
|
||||||
final var expiresInSeconds = dataMessage.expiresInSeconds();
|
final var expiresInSeconds = dataMessage.expiresInSeconds();
|
||||||
final var viewOnce = dataMessage.isViewOnce();
|
final var viewOnce = dataMessage.isViewOnce();
|
||||||
|
@ -67,6 +71,7 @@ record JsonDataMessage(
|
||||||
sticker,
|
sticker,
|
||||||
remoteDelete,
|
remoteDelete,
|
||||||
contacts,
|
contacts,
|
||||||
groupInfo);
|
groupInfo,
|
||||||
|
storyContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ public record JsonMessageEnvelope(
|
||||||
Integer sourceDevice,
|
Integer sourceDevice,
|
||||||
long timestamp,
|
long timestamp,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonDataMessage dataMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonDataMessage dataMessage,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonStoryMessage storyMessage,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncMessage syncMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncMessage syncMessage,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonCallMessage callMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonCallMessage callMessage,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonReceiptMessage receiptMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonReceiptMessage receiptMessage,
|
||||||
|
@ -60,6 +61,7 @@ public record JsonMessageEnvelope(
|
||||||
final var typingMessage = envelope.typing().map(JsonTypingMessage::from).orElse(null);
|
final var typingMessage = envelope.typing().map(JsonTypingMessage::from).orElse(null);
|
||||||
|
|
||||||
final var dataMessage = envelope.data().map(JsonDataMessage::from).orElse(null);
|
final var dataMessage = envelope.data().map(JsonDataMessage::from).orElse(null);
|
||||||
|
final var storyMessage = envelope.story().map(JsonStoryMessage::from).orElse(null);
|
||||||
final var syncMessage = envelope.sync().map(JsonSyncMessage::from).orElse(null);
|
final var syncMessage = envelope.sync().map(JsonSyncMessage::from).orElse(null);
|
||||||
final var callMessage = envelope.call().map(JsonCallMessage::from).orElse(null);
|
final var callMessage = envelope.call().map(JsonCallMessage::from).orElse(null);
|
||||||
|
|
||||||
|
@ -70,6 +72,7 @@ public record JsonMessageEnvelope(
|
||||||
sourceDevice,
|
sourceDevice,
|
||||||
timestamp,
|
timestamp,
|
||||||
dataMessage,
|
dataMessage,
|
||||||
|
storyMessage,
|
||||||
syncMessage,
|
syncMessage,
|
||||||
callMessage,
|
callMessage,
|
||||||
receiptMessage,
|
receiptMessage,
|
||||||
|
|
16
src/main/java/org/asamk/signal/json/JsonStoryContext.java
Normal file
16
src/main/java/org/asamk/signal/json/JsonStoryContext.java
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
record JsonStoryContext(
|
||||||
|
String authorNumber, String authorUuid, long sentTimestamp
|
||||||
|
) {
|
||||||
|
|
||||||
|
static JsonStoryContext from(MessageEnvelope.Data.StoryContext storyContext) {
|
||||||
|
return new JsonStoryContext(storyContext.author().number().orElse(null),
|
||||||
|
storyContext.author().uuid().map(UUID::toString).orElse(null),
|
||||||
|
storyContext.sentTimestamp());
|
||||||
|
}
|
||||||
|
}
|
52
src/main/java/org/asamk/signal/json/JsonStoryMessage.java
Normal file
52
src/main/java/org/asamk/signal/json/JsonStoryMessage.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
|
||||||
|
import org.asamk.signal.manager.api.Color;
|
||||||
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
import org.asamk.signal.manager.groups.GroupId;
|
||||||
|
|
||||||
|
record JsonStoryMessage(
|
||||||
|
boolean allowsReplies,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) String groupId,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonAttachment fileAttachment,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) TextAttachment textAttachment
|
||||||
|
) {
|
||||||
|
|
||||||
|
static JsonStoryMessage from(MessageEnvelope.Story storyMessage) {
|
||||||
|
return new JsonStoryMessage(storyMessage.allowsReplies(),
|
||||||
|
storyMessage.groupId().map(GroupId::toBase64).orElse(null),
|
||||||
|
storyMessage.fileAttachment().map(JsonAttachment::from).orElse(null),
|
||||||
|
storyMessage.textAttachment().map(TextAttachment::from).orElse(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public record TextAttachment(
|
||||||
|
String text,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) String style,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) String textForegroundColor,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) String textBackgroundColor,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonPreview preview,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) Gradient backgroundGradient,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) String backgroundColor
|
||||||
|
) {
|
||||||
|
|
||||||
|
static TextAttachment from(MessageEnvelope.Story.TextAttachment textAttachment) {
|
||||||
|
return new TextAttachment(textAttachment.text().orElse(null),
|
||||||
|
textAttachment.style().map(MessageEnvelope.Story.TextAttachment.Style::name).orElse(null),
|
||||||
|
textAttachment.textForegroundColor().map(Color::toHexColor).orElse(null),
|
||||||
|
textAttachment.textBackgroundColor().map(Color::toHexColor).orElse(null),
|
||||||
|
textAttachment.preview().map(JsonPreview::from).orElse(null),
|
||||||
|
textAttachment.backgroundGradient().map(Gradient::from).orElse(null),
|
||||||
|
textAttachment.backgroundColor().map(Color::toHexColor).orElse(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Gradient(String startColor, String endColor, Integer angle) {
|
||||||
|
|
||||||
|
static Gradient from(MessageEnvelope.Story.TextAttachment.Gradient gradient) {
|
||||||
|
return new Gradient(gradient.startColor().map(Color::toHexColor).orElse(null),
|
||||||
|
gradient.endColor().map(Color::toHexColor).orElse(null),
|
||||||
|
gradient.angle().orElse(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,30 +16,20 @@ enum JsonSyncMessageType {
|
||||||
|
|
||||||
record JsonSyncMessage(
|
record JsonSyncMessage(
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncDataMessage sentMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncDataMessage sentMessage,
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncStoryMessage sentStoryMessage,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) List<String> blockedNumbers,
|
@JsonInclude(JsonInclude.Include.NON_NULL) List<String> blockedNumbers,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) List<String> blockedGroupIds,
|
@JsonInclude(JsonInclude.Include.NON_NULL) List<String> blockedGroupIds,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) List<JsonSyncReadMessage> readMessages,
|
@JsonInclude(JsonInclude.Include.NON_NULL) List<JsonSyncReadMessage> readMessages,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncMessageType type
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncMessageType type
|
||||||
) {
|
) {
|
||||||
|
|
||||||
JsonSyncMessage(
|
|
||||||
final JsonSyncDataMessage sentMessage,
|
|
||||||
final List<String> blockedNumbers,
|
|
||||||
final List<String> blockedGroupIds,
|
|
||||||
final List<JsonSyncReadMessage> readMessages,
|
|
||||||
final JsonSyncMessageType type
|
|
||||||
) {
|
|
||||||
this.sentMessage = sentMessage;
|
|
||||||
this.blockedNumbers = blockedNumbers;
|
|
||||||
this.blockedGroupIds = blockedGroupIds;
|
|
||||||
this.readMessages = readMessages;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static JsonSyncMessage from(MessageEnvelope.Sync syncMessage) {
|
static JsonSyncMessage from(MessageEnvelope.Sync syncMessage) {
|
||||||
final var sentMessage = syncMessage.sent().isPresent()
|
final var sentMessage = syncMessage.sent().isPresent() && syncMessage.sent().get().story().isEmpty()
|
||||||
? JsonSyncDataMessage.from(syncMessage.sent().get())
|
? JsonSyncDataMessage.from(syncMessage.sent().get())
|
||||||
: null;
|
: null;
|
||||||
|
final var sentStoryMessage = syncMessage.sent().isPresent() && syncMessage.sent().get().story().isPresent()
|
||||||
|
? JsonSyncStoryMessage.from(syncMessage.sent().get())
|
||||||
|
: null;
|
||||||
final List<String> blockedNumbers;
|
final List<String> blockedNumbers;
|
||||||
final List<String> blockedGroupIds;
|
final List<String> blockedGroupIds;
|
||||||
if (syncMessage.blocked().isPresent()) {
|
if (syncMessage.blocked().isPresent()) {
|
||||||
|
@ -68,6 +58,6 @@ record JsonSyncMessage(
|
||||||
} else {
|
} else {
|
||||||
type = null;
|
type = null;
|
||||||
}
|
}
|
||||||
return new JsonSyncMessage(sentMessage, blockedNumbers, blockedGroupIds, readMessages, type);
|
return new JsonSyncMessage(sentMessage, sentStoryMessage, blockedNumbers, blockedGroupIds, readMessages, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||||
|
|
||||||
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
record JsonSyncStoryMessage(
|
||||||
|
String destinationNumber, String destinationUuid, @JsonUnwrapped JsonStoryMessage dataMessage
|
||||||
|
) {
|
||||||
|
|
||||||
|
static JsonSyncStoryMessage from(MessageEnvelope.Sync.Sent transcriptMessage) {
|
||||||
|
if (transcriptMessage.destination().isPresent()) {
|
||||||
|
final var address = transcriptMessage.destination().get();
|
||||||
|
return new JsonSyncStoryMessage(address.number().orElse(null),
|
||||||
|
address.uuid().map(UUID::toString).orElse(null),
|
||||||
|
transcriptMessage.story().map(JsonStoryMessage::from).orElse(null));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return new JsonSyncStoryMessage(null,
|
||||||
|
null,
|
||||||
|
transcriptMessage.story().map(JsonStoryMessage::from).orElse(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue