Add support for sending stickers

This commit is contained in:
AsamK 2022-01-03 13:24:13 +01:00
parent 5d83e149b3
commit 404063a080
11 changed files with 141 additions and 35 deletions

View file

@ -6,6 +6,7 @@ import org.asamk.signal.manager.api.Group;
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.InvalidStickerException;
import org.asamk.signal.manager.api.Message;
import org.asamk.signal.manager.api.MessageEnvelope;
import org.asamk.signal.manager.api.Pair;
@ -173,7 +174,7 @@ public interface Manager extends Closeable {
SendMessageResults sendMessage(
Message message, Set<RecipientIdentifier> recipients
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException;
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException;
SendMessageResults sendRemoteDeleteMessage(
long targetSentTimestamp, Set<RecipientIdentifier> recipients

View file

@ -22,6 +22,7 @@ import org.asamk.signal.manager.api.Group;
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.InvalidStickerException;
import org.asamk.signal.manager.api.Message;
import org.asamk.signal.manager.api.Pair;
import org.asamk.signal.manager.api.RecipientIdentifier;
@ -48,6 +49,7 @@ import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.asamk.signal.manager.storage.stickers.Sticker;
import org.asamk.signal.manager.storage.stickers.StickerPackId;
import org.asamk.signal.manager.util.AttachmentUtils;
import org.asamk.signal.manager.util.KeyUtils;
import org.asamk.signal.manager.util.StickerUtils;
import org.slf4j.Logger;
@ -484,7 +486,7 @@ public class ManagerImpl implements Manager {
@Override
public SendMessageResults sendMessage(
Message message, Set<RecipientIdentifier> recipients
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException {
) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException, UnregisteredRecipientException, InvalidStickerException {
final var messageBuilder = SignalServiceDataMessage.newBuilder();
applyMessage(messageBuilder, message);
return sendMessage(messageBuilder, recipients);
@ -492,7 +494,7 @@ public class ManagerImpl implements Manager {
private void applyMessage(
final SignalServiceDataMessage.Builder messageBuilder, final Message message
) throws AttachmentInvalidException, IOException, UnregisteredRecipientException {
) throws AttachmentInvalidException, IOException, UnregisteredRecipientException, InvalidStickerException {
messageBuilder.withBody(message.messageText());
final var attachments = message.attachments();
if (attachments != null) {
@ -510,6 +512,30 @@ public class ManagerImpl implements Manager {
List.of(),
resolveMentions(quote.mentions())));
}
if (message.sticker().isPresent()) {
final var sticker = message.sticker().get();
final var packId = StickerPackId.deserialize(sticker.packId());
final var stickerId = sticker.stickerId();
final var stickerPack = context.getAccount().getStickerStore().getStickerPack(packId);
if (stickerPack == null || !context.getStickerPackStore().existsStickerPack(packId)) {
throw new InvalidStickerException("Sticker pack not found");
}
final var manifest = context.getStickerPackStore().retrieveManifest(packId);
if (manifest.stickers().size() <= stickerId) {
throw new InvalidStickerException("Sticker id not part of this pack");
}
final var manifestSticker = manifest.stickers().get(stickerId);
final var streamDetails = context.getStickerPackStore().retrieveSticker(packId, stickerId);
if (streamDetails == null) {
throw new InvalidStickerException("Missing local sticker file");
}
messageBuilder.withSticker(new SignalServiceDataMessage.Sticker(packId.serialize(),
stickerPack.getPackKey(),
stickerId,
manifestSticker.emoji(),
AttachmentUtils.createAttachment(streamDetails, Optional.absent())));
}
}
private ArrayList<SignalServiceDataMessage.Mention> resolveMentions(final List<Message.Mention> mentionList) throws IOException, UnregisteredRecipientException {

View file

@ -4,10 +4,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.asamk.signal.manager.storage.stickers.StickerPackId;
import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.Utils;
import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.internal.util.Hex;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@ -26,8 +29,22 @@ public class StickerPackStore {
return getStickerPackManifestFile(stickerPackId).exists();
}
public JsonStickerPack retrieveManifest(StickerPackId stickerPackId) throws IOException {
try (final var inputStream = new FileInputStream(getStickerPackManifestFile(stickerPackId))) {
return new ObjectMapper().readValue(inputStream, JsonStickerPack.class);
}
}
public StreamDetails retrieveSticker(final StickerPackId stickerPackId, final int stickerId) throws IOException {
final var stickerFile = getStickerPackStickerFile(stickerPackId, stickerId);
if (!stickerFile.exists()) {
return null;
}
return Utils.createStreamDetailsFromFile(stickerFile);
}
public void storeManifest(StickerPackId stickerPackId, JsonStickerPack manifest) throws IOException {
try (OutputStream output = new FileOutputStream(getStickerPackManifestFile(stickerPackId))) {
try (final var output = new FileOutputStream(getStickerPackManifestFile(stickerPackId))) {
try (var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8))) {
new ObjectMapper().writeValue(writer, manifest);
}
@ -36,7 +53,7 @@ public class StickerPackStore {
public void storeSticker(StickerPackId stickerPackId, int stickerId, StickerStorer storer) throws IOException {
createStickerPackDir(stickerPackId);
try (OutputStream output = new FileOutputStream(getStickerPackStickerFile(stickerPackId, stickerId))) {
try (final var output = new FileOutputStream(getStickerPackStickerFile(stickerPackId, stickerId))) {
storer.store(output);
}
}

View file

@ -0,0 +1,12 @@
package org.asamk.signal.manager.api;
public class InvalidStickerException extends Exception {
public InvalidStickerException(final String message) {
super(message);
}
public InvalidStickerException(final String message, final Throwable cause) {
super(message, cause);
}
}

View file

@ -3,9 +3,17 @@ package org.asamk.signal.manager.api;
import java.util.List;
import java.util.Optional;
public record Message(String messageText, List<String> attachments, List<Mention> mentions, Optional<Quote> quote) {
public record Message(
String messageText,
List<String> attachments,
List<Mention> mentions,
Optional<Quote> quote,
Optional<Sticker> sticker
) {
public record Mention(RecipientIdentifier.Single recipient, int start, int length) {}
public record Quote(long timestamp, RecipientIdentifier.Single author, String message, List<Mention> mentions) {}
public record Sticker(byte[] packId, int stickerId) {}
}

View file

@ -327,7 +327,7 @@ public final class IncomingMessageHandler {
final var installed = !m.getType().isPresent()
|| m.getType().get() == StickerPackOperationMessage.Type.INSTALL;
var sticker = account.getStickerStore().getSticker(stickerPackId);
var sticker = account.getStickerStore().getStickerPack(stickerPackId);
if (m.getPackKey().isPresent()) {
if (sticker == null) {
sticker = new Sticker(stickerPackId, m.getPackKey().get());
@ -598,7 +598,7 @@ public final class IncomingMessageHandler {
if (message.getSticker().isPresent()) {
final var messageSticker = message.getSticker().get();
final var stickerPackId = StickerPackId.deserialize(messageSticker.getPackId());
var sticker = account.getStickerStore().getSticker(stickerPackId);
var sticker = account.getStickerStore().getStickerPack(stickerPackId);
if (sticker == null) {
sticker = new Sticker(stickerPackId, messageSticker.getPackKey());
account.getStickerStore().updateSticker(sticker);

View file

@ -41,7 +41,7 @@ public class StickerStore {
return new StickerStore(stickers, saver);
}
public Sticker getSticker(StickerPackId packId) {
public Sticker getStickerPack(StickerPackId packId) {
synchronized (stickers) {
return stickers.get(packId);
}