]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/AttachmentStore.java
Add command to get an attachment (#1080)
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / AttachmentStore.java
1 package org.asamk.signal.manager;
2
3 import org.asamk.signal.manager.util.IOUtils;
4 import org.asamk.signal.manager.util.MimeUtils;
5 import org.asamk.signal.manager.util.Utils;
6 import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
7 import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
8 import org.whispersystems.signalservice.api.util.StreamDetails;
9
10 import java.io.File;
11 import java.io.FileOutputStream;
12 import java.io.IOException;
13 import java.io.OutputStream;
14 import java.util.Optional;
15
16 public class AttachmentStore {
17
18 private final File attachmentsPath;
19
20 public AttachmentStore(final File attachmentsPath) {
21 this.attachmentsPath = attachmentsPath;
22 }
23
24 public void storeAttachmentPreview(
25 final SignalServiceAttachmentPointer pointer, final AttachmentStorer storer
26 ) throws IOException {
27 storeAttachment(getAttachmentPreviewFile(pointer.getRemoteId(),
28 pointer.getFileName(),
29 Optional.ofNullable(pointer.getContentType())), storer);
30 }
31
32 public void storeAttachment(
33 final SignalServiceAttachmentPointer pointer, final AttachmentStorer storer
34 ) throws IOException {
35 storeAttachment(getAttachmentFile(pointer), storer);
36 }
37
38 public File getAttachmentFile(final SignalServiceAttachmentPointer pointer) {
39 return getAttachmentFile(pointer.getRemoteId(),
40 pointer.getFileName(),
41 Optional.ofNullable(pointer.getContentType()));
42 }
43
44 public StreamDetails retrieveAttachment(final String id) throws IOException {
45 final var attachmentFile = new File(attachmentsPath, id);
46 if (!attachmentFile.exists()) {
47 return null;
48 }
49 return Utils.createStreamDetailsFromFile(attachmentFile);
50 }
51
52 private void storeAttachment(final File attachmentFile, final AttachmentStorer storer) throws IOException {
53 createAttachmentsDir();
54 try (OutputStream output = new FileOutputStream(attachmentFile)) {
55 storer.store(output);
56 }
57 }
58
59 private File getAttachmentPreviewFile(
60 SignalServiceAttachmentRemoteId attachmentId, Optional<String> filename, Optional<String> contentType
61 ) {
62 final var extension = getAttachmentExtension(filename, contentType);
63 return new File(attachmentsPath, attachmentId.toString() + extension + ".preview");
64 }
65
66 private File getAttachmentFile(
67 SignalServiceAttachmentRemoteId attachmentId, Optional<String> filename, Optional<String> contentType
68 ) {
69 final var extension = getAttachmentExtension(filename, contentType);
70 return new File(attachmentsPath, attachmentId.toString() + extension);
71 }
72
73 private static String getAttachmentExtension(
74 final Optional<String> filename, final Optional<String> contentType
75 ) {
76 return filename.filter(f -> f.contains("."))
77 .map(f -> f.substring(f.lastIndexOf(".") + 1))
78 .or(() -> contentType.flatMap(MimeUtils::guessExtensionFromMimeType))
79 .map(ext -> "." + ext)
80 .orElse("");
81 }
82
83 private void createAttachmentsDir() throws IOException {
84 IOUtils.createPrivateDirectories(attachmentsPath);
85 }
86
87 @FunctionalInterface
88 public interface AttachmentStorer {
89
90 void store(OutputStream outputStream) throws IOException;
91 }
92 }