package org.asamk.signal.manager;
import org.asamk.signal.manager.util.IOUtils;
+import org.asamk.signal.manager.util.MimeUtils;
+import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Optional;
public class AttachmentStore {
}
public void storeAttachmentPreview(
- final SignalServiceAttachmentRemoteId attachmentId, final AttachmentStorer storer
+ final SignalServiceAttachmentPointer pointer, final AttachmentStorer storer
) throws IOException {
- storeAttachment(getAttachmentPreviewFile(attachmentId), storer);
+ storeAttachment(getAttachmentPreviewFile(pointer.getRemoteId(),
+ pointer.getFileName(),
+ Optional.ofNullable(pointer.getContentType())), storer);
}
public void storeAttachment(
- final SignalServiceAttachmentRemoteId attachmentId, final AttachmentStorer storer
+ final SignalServiceAttachmentPointer pointer, final AttachmentStorer storer
) throws IOException {
- storeAttachment(getAttachmentFile(attachmentId), storer);
+ storeAttachment(getAttachmentFile(pointer), storer);
+ }
+
+ public File getAttachmentFile(final SignalServiceAttachmentPointer pointer) {
+ return getAttachmentFile(pointer.getRemoteId(),
+ pointer.getFileName(),
+ Optional.ofNullable(pointer.getContentType()));
}
private void storeAttachment(final File attachmentFile, final AttachmentStorer storer) throws IOException {
}
}
- private File getAttachmentPreviewFile(SignalServiceAttachmentRemoteId attachmentId) {
- return new File(attachmentsPath, attachmentId.toString() + ".preview");
+ private File getAttachmentPreviewFile(
+ SignalServiceAttachmentRemoteId attachmentId, Optional<String> filename, Optional<String> contentType
+ ) {
+ final var extension = getAttachmentExtension(filename, contentType);
+ return new File(attachmentsPath, attachmentId.toString() + extension + ".preview");
+ }
+
+ private File getAttachmentFile(
+ SignalServiceAttachmentRemoteId attachmentId, Optional<String> filename, Optional<String> contentType
+ ) {
+ final var extension = getAttachmentExtension(filename, contentType);
+ return new File(attachmentsPath, attachmentId.toString() + extension);
}
- public File getAttachmentFile(SignalServiceAttachmentRemoteId attachmentId) {
- return new File(attachmentsPath, attachmentId.toString());
+ private static String getAttachmentExtension(
+ final Optional<String> filename, final Optional<String> contentType
+ ) {
+ return filename.filter(f -> f.contains("."))
+ .map(f -> f.substring(f.lastIndexOf(".") + 1))
+ .or(() -> contentType.flatMap(MimeUtils::guessExtensionFromMimeType))
+ .map(ext -> "." + ext)
+ .orElse("");
}
private void createAttachmentsDir() throws IOException {
import org.asamk.signal.manager.storage.recipients.RecipientResolver;
import org.signal.libsignal.metadata.ProtocolException;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
-import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
+import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
static Attachment from(SignalServiceAttachment attachment, AttachmentFileProvider fileProvider) {
if (attachment.isPointer()) {
final var a = attachment.asPointer();
- return new Attachment(Optional.of(a.getRemoteId().toString()),
- Optional.of(fileProvider.getFile(a.getRemoteId())),
+ final var attachmentFile = fileProvider.getFile(a);
+ return new Attachment(Optional.of(attachmentFile.getName()),
+ Optional.of(attachmentFile),
a.getFileName(),
a.getContentType(),
a.getUploadTimestamp() == 0 ? Optional.empty() : Optional.of(a.getUploadTimestamp()),
public interface AttachmentFileProvider {
- File getFile(SignalServiceAttachmentRemoteId attachmentRemoteId);
+ File getFile(SignalServiceAttachmentPointer pointer);
}
}
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
-import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
this.attachmentStore = context.getAttachmentStore();
}
- public File getAttachmentFile(SignalServiceAttachmentRemoteId attachmentId) {
- return attachmentStore.getAttachmentFile(attachmentId);
+ public File getAttachmentFile(SignalServiceAttachmentPointer pointer) {
+ return attachmentStore.getAttachmentFile(pointer);
}
public List<SignalServiceAttachment> uploadAttachments(final List<String> attachments) throws AttachmentInvalidException, IOException {
if (pointer.getPreview().isPresent()) {
final var preview = pointer.getPreview().get();
try {
- attachmentStore.storeAttachmentPreview(pointer.getRemoteId(),
+ attachmentStore.storeAttachmentPreview(pointer,
outputStream -> outputStream.write(preview, 0, preview.length));
} catch (IOException e) {
logger.warn("Failed to download attachment preview, ignoring: {}", e.getMessage());
}
try {
- attachmentStore.storeAttachment(pointer.getRemoteId(),
- outputStream -> this.retrieveAttachment(pointer, outputStream));
+ attachmentStore.storeAttachment(pointer, outputStream -> this.retrieveAttachment(pointer, outputStream));
} catch (IOException e) {
logger.warn("Failed to download attachment ({}), ignoring: {}", pointer.getRemoteId(), e.getMessage());
}