Add support for receiving pin/unpin messages

Related #1923
This commit is contained in:
AsamK 2026-02-28 09:37:29 +01:00
parent f9cbfa6d6c
commit 6a6bebd503
7 changed files with 215 additions and 7 deletions

View File

@ -120,7 +120,9 @@ public record MessageEnvelope(
Optional<PollTerminate> pollTerminate,
List<Mention> mentions,
List<Preview> previews,
List<TextStyle> textStyles
List<TextStyle> textStyles,
Optional<PinMessage> pinMessage,
Optional<UnpinMessage> unpinMessage
) {
static Data from(
@ -169,7 +171,10 @@ public record MessageEnvelope(
.orElse(List.of()),
dataMessage.getBodyRanges()
.map(a -> a.stream().filter(r -> r.style != null).map(TextStyle::from).toList())
.orElse(List.of()));
.orElse(List.of()),
dataMessage.getPinnedMessage().map(p -> PinMessage.from(p, recipientResolver, addressResolver)),
dataMessage.getUnpinnedMessage()
.map(p -> UnpinMessage.from(p, recipientResolver, addressResolver)));
}
public record GroupContext(GroupId groupId, boolean isGroupUpdate, int revision) {
@ -564,6 +569,39 @@ public record MessageEnvelope(
}
}
public record PinMessage(
RecipientAddress targetAuthor, long targetSentTimestamp, long pinDurationSeconds
) {
static PinMessage from(
SignalServiceDataMessage.PinnedMessage pinnedMessage,
RecipientResolver recipientResolver,
RecipientAddressResolver addressResolver
) {
return new PinMessage(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(
pinnedMessage.getTargetAuthor())).toApiRecipientAddress(),
pinnedMessage.getTargetSentTimestamp(),
Boolean.TRUE.equals(pinnedMessage.getForever())
? -1
: pinnedMessage.getPinDurationInSeconds() == null
? 0
: pinnedMessage.getPinDurationInSeconds());
}
}
public record UnpinMessage(RecipientAddress targetAuthor, long targetSentTimestamp) {
static UnpinMessage from(
SignalServiceDataMessage.UnpinnedMessage unpinnedMessage,
RecipientResolver recipientResolver,
RecipientAddressResolver addressResolver
) {
return new UnpinMessage(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(
unpinnedMessage.getTargetAuthor())).toApiRecipientAddress(),
unpinnedMessage.getTargetSentTimestamp());
}
}
}
public record Edit(long targetSentTimestamp, Data dataMessage) {

View File

@ -214,6 +214,16 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
final var pollTerminate = message.pollTerminate().get();
writer.println("Poll Terminate: {}", DateUtils.formatTimestamp(pollTerminate.targetSentTimestamp()));
}
if (message.pinMessage().isPresent()) {
writer.println("Pin Message:");
final var pinMessage = message.pinMessage().get();
printPinMessage(writer.indentedWriter(), pinMessage);
}
if (message.unpinMessage().isPresent()) {
writer.println("Unpin Message:");
final var unpinMessage = message.unpinMessage().get();
printUnpinMessage(writer.indentedWriter(), unpinMessage);
}
}
private void printEditMessage(PlainTextWriter writer, MessageEnvelope.Edit message) {
@ -620,6 +630,24 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
}
}
private void printPinMessage(final PlainTextWriter writer, final MessageEnvelope.Data.PinMessage pinMessage) {
writer.println("Target author: {}", formatContact(pinMessage.targetAuthor()));
writer.println("Target timestamp: {}", DateUtils.formatTimestamp(pinMessage.targetSentTimestamp()));
final var duration = pinMessage.pinDurationSeconds();
if (duration == -1) {
writer.println("Duration: forever");
} else if (duration == 0) {
writer.println("Duration: unspecified");
} else {
writer.println("Duration: {} seconds", duration);
}
}
private void printUnpinMessage(final PlainTextWriter writer, final MessageEnvelope.Data.UnpinMessage unpinMessage) {
writer.println("Target author: {}", formatContact(unpinMessage.targetAuthor()));
writer.println("Target timestamp: {}", DateUtils.formatTimestamp(unpinMessage.targetSentTimestamp()));
}
private String formatContact(RecipientAddress address) {
final var number = address.getLegacyIdentifier();
final var name = m.getContactOrProfileName(RecipientIdentifier.Single.fromAddress(address));

View File

@ -977,7 +977,9 @@ public class DbusManagerImpl implements Manager {
Optional.empty(),
getMentions(extras),
List.of(),
List.of())),
List.of(),
Optional.empty(),
Optional.empty())),
Optional.empty(),
Optional.empty(),
Optional.empty(),
@ -1023,7 +1025,9 @@ public class DbusManagerImpl implements Manager {
Optional.empty(),
getMentions(extras),
List.of(),
List.of()))),
List.of(),
Optional.empty(),
Optional.empty()))),
Optional.empty(),
Optional.empty(),
Optional.empty());
@ -1101,7 +1105,9 @@ public class DbusManagerImpl implements Manager {
Optional.empty(),
getMentions(extras),
List.of(),
List.of())),
List.of(),
Optional.empty(),
Optional.empty())),
Optional.empty(),
Optional.empty())),
Optional.empty(),

View File

@ -27,7 +27,9 @@ record JsonDataMessage(
@JsonInclude(JsonInclude.Include.NON_NULL) JsonPollTerminate pollTerminate,
@JsonInclude(JsonInclude.Include.NON_NULL) List<JsonTextStyle> textStyles,
@JsonInclude(JsonInclude.Include.NON_NULL) JsonGroupInfo groupInfo,
@JsonInclude(JsonInclude.Include.NON_NULL) JsonStoryContext storyContext
@JsonInclude(JsonInclude.Include.NON_NULL) JsonStoryContext storyContext,
@JsonInclude(JsonInclude.Include.NON_NULL) JsonPinMessage pinMessage,
@JsonInclude(JsonInclude.Include.NON_NULL) JsonUnpinMessage unpinMessage
) {
static JsonDataMessage from(MessageEnvelope.Data dataMessage, Manager m) {
@ -71,6 +73,8 @@ record JsonDataMessage(
.stream()
.map(JsonTextStyle::from)
.toList() : null;
final var pinMessage = dataMessage.pinMessage().map(JsonPinMessage::from).orElse(null);
final var unpinMessage = dataMessage.unpinMessage().map(JsonUnpinMessage::from).orElse(null);
return new JsonDataMessage(timestamp,
message,
@ -91,6 +95,8 @@ record JsonDataMessage(
pollTerminate,
textStyles,
groupInfo,
storyContext);
storyContext,
pinMessage,
unpinMessage);
}
}

View File

@ -0,0 +1,30 @@
package org.asamk.signal.json;
import org.asamk.signal.manager.api.MessageEnvelope;
import java.util.UUID;
public record JsonPinMessage(
@Deprecated String targetAuthor,
String targetAuthorNumber,
String targetAuthorUuid,
long targetSentTimestamp,
long pinDurationSeconds
) {
static JsonPinMessage from(MessageEnvelope.Data.PinMessage pinMessage) {
final var address = pinMessage.targetAuthor();
final var targetAuthor = address.getLegacyIdentifier();
final var targetAuthorNumber = address.number().orElse(null);
final var targetAuthorUuid = address.uuid().map(UUID::toString).orElse(null);
final var targetSentTimestamp = pinMessage.targetSentTimestamp();
final var pinDurationSeconds = pinMessage.pinDurationSeconds();
return new JsonPinMessage(targetAuthor,
targetAuthorNumber,
targetAuthorUuid,
targetSentTimestamp,
pinDurationSeconds);
}
}

View File

@ -0,0 +1,21 @@
package org.asamk.signal.json;
import org.asamk.signal.manager.api.MessageEnvelope;
import java.util.UUID;
public record JsonUnpinMessage(
@Deprecated String targetAuthor, String targetAuthorNumber, String targetAuthorUuid, long targetSentTimestamp
) {
static JsonUnpinMessage from(MessageEnvelope.Data.UnpinMessage unpinMessage) {
final var address = unpinMessage.targetAuthor();
final var targetAuthor = address.getLegacyIdentifier();
final var targetAuthorNumber = address.number().orElse(null);
final var targetAuthorUuid = address.uuid().map(UUID::toString).orElse(null);
final var targetSentTimestamp = unpinMessage.targetSentTimestamp();
return new JsonUnpinMessage(targetAuthor, targetAuthorNumber, targetAuthorUuid, targetSentTimestamp);
}
}

View File

@ -1299,6 +1299,18 @@
"allDeclaredConstructors": true,
"jniAccessible": true
},
{
"type": "java.util.concurrent.CancellationException",
"jniAccessible": true,
"methods": [
{
"name": "<init>",
"parameterTypes": [
"java.lang.String"
]
}
]
},
{
"type": "java.util.concurrent.ForkJoinTask",
"fields": [
@ -2565,6 +2577,31 @@
}
]
},
{
"type": "org.asamk.signal.json.JsonPinMessage",
"methods": [
{
"name": "pinDurationSeconds",
"parameterTypes": []
},
{
"name": "targetAuthor",
"parameterTypes": []
},
{
"name": "targetAuthorNumber",
"parameterTypes": []
},
{
"name": "targetAuthorUuid",
"parameterTypes": []
},
{
"name": "targetSentTimestamp",
"parameterTypes": []
}
]
},
{
"type": "org.asamk.signal.json.JsonPollCreate",
"allDeclaredFields": true,
@ -2915,6 +2952,27 @@
"allDeclaredMethods": true,
"allDeclaredConstructors": true
},
{
"type": "org.asamk.signal.json.JsonUnpinMessage",
"methods": [
{
"name": "targetAuthor",
"parameterTypes": []
},
{
"name": "targetAuthorNumber",
"parameterTypes": []
},
{
"name": "targetAuthorUuid",
"parameterTypes": []
},
{
"name": "targetSentTimestamp",
"parameterTypes": []
}
]
},
{
"type": "org.asamk.signal.jsonrpc.JsonRpcBatchMessage",
"allDeclaredFields": true,
@ -9449,6 +9507,18 @@
{
"type": "sun.text.resources.CollationData"
},
{
"type": "sun.text.resources.FormatData"
},
{
"type": "sun.text.resources.FormatData_en"
},
{
"type": "sun.text.resources.FormatData_en_US"
},
{
"type": "sun.text.resources.JavaTimeSupplementary"
},
{
"type": "sun.text.resources.cldr.FormatData"
},
@ -9461,6 +9531,15 @@
{
"type": "sun.util.resources.cldr.CalendarData"
},
{
"type": "sun.util.resources.cldr.TimeZoneNames"
},
{
"type": "sun.util.resources.cldr.TimeZoneNames_en"
},
{
"type": "sun.util.resources.cldr.TimeZoneNames_en_US"
},
{
"type": {
"proxy": [