import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.util.AttachmentUtils;
import org.asamk.signal.manager.util.IOUtils;
+import org.asamk.signal.manager.util.MimeUtils;
import org.signal.libsignal.protocol.IdentityKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
try (var groupsFileStream = new FileInputStream(groupsFile)) {
var attachmentStream = SignalServiceAttachment.newStreamBuilder()
.withStream(groupsFileStream)
- .withContentType("application/octet-stream")
+ .withContentType(MimeUtils.OCTET_STREAM)
.withLength(groupsFile.length())
.build();
try (var contactsFileStream = new FileInputStream(contactsFile)) {
var attachmentStream = SignalServiceAttachment.newStreamBuilder()
.withStream(contactsFileStream)
- .withContentType("application/octet-stream")
+ .withContentType(MimeUtils.OCTET_STREAM)
.withLength(contactsFile.length())
.build();
Pattern.CASE_INSENSITIVE);
public static final Pattern PARAMETER_PATTERN = Pattern.compile("\\G;(?<key>.+)=(?<value>.+)",
Pattern.CASE_INSENSITIVE);
- public static final String DEFAULT_TYPE = "text/plain";
/**
* Generates a new {@link DataURI} object that follows
* The {@code <mediatype>} is an Internet media type specification (with
* optional parameters.) The appearance of ";base64" means that the data
* is encoded as base64. Without ";base64", the data is represented using (ASCII) URL Escaped encoding.
- * If {@code <mediatype>} is omitted, it defaults to {@link DataURI#DEFAULT_TYPE}.
+ * If {@code <mediatype>} is omitted, it defaults to {@link MimeUtils#PLAIN_TEXT}.
* Parameter values should use the URL Escaped encoding.
*
* @param dataURI the data URI
data = URLDecoder.decode(matcher.group("data"), StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8);
}
- return new DataURI(Optional.ofNullable(matcher.group("type")).orElse(DEFAULT_TYPE), parameters, data);
+ return new DataURI(Optional.ofNullable(matcher.group("type")).orElse(MimeUtils.PLAIN_TEXT), parameters, data);
}
}
--- /dev/null
+package org.asamk.signal.manager.util;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.util.Optional;
+
+public class MimeUtils {
+
+ public static final String LONG_TEXT = "text/x-signal-plain";
+ public static final String PLAIN_TEXT = "text/plain";
+ public static final String OCTET_STREAM = "application/octet-stream";
+
+ public static Optional<String> getFileMimeType(final File file) throws IOException {
+ var mime = Files.probeContentType(file.toPath());
+ if (mime != null) {
+ return Optional.of(mime);
+ }
+
+ try (final InputStream bufferedStream = new BufferedInputStream(new FileInputStream(file))) {
+ return getStreamMimeType(bufferedStream);
+ }
+ }
+
+ public static Optional<String> getStreamMimeType(final InputStream inputStream) throws IOException {
+ return Optional.ofNullable(URLConnection.guessContentTypeFromStream(inputStream));
+ }
+
+ public static Optional<String> guessExtensionFromMimeType(String mimeType) {
+ return Optional.ofNullable(switch (mimeType) {
+ case "application/vnd.android.package-archive" -> "apk";
+ case "application/json" -> "json";
+ case "image/png" -> "png";
+ case "image/jpeg" -> "jpg";
+ case "image/heic" -> "heic";
+ case "image/heif" -> "heif";
+ case "image/webp" -> "webp";
+ case "image/gif" -> "gif";
+ case "audio/aac" -> "aac";
+ case "video/mp4" -> "mp4";
+ case "text/x-vcard" -> "vcf";
+ case PLAIN_TEXT, LONG_TEXT -> "txt";
+ case OCTET_STREAM -> "bin";
+ default -> null;
+ });
+ }
+}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Optional;
import java.util.zip.ZipFile;
if (zip != null) {
final var entry = zip.getEntry(subfile);
try (InputStream bufferedStream = new BufferedInputStream(zip.getInputStream(entry))) {
- return URLConnection.guessContentTypeFromStream(bufferedStream);
+ return MimeUtils.getStreamMimeType(bufferedStream).orElse(null);
}
} else {
final var file = new File(rootPath, subfile);
- return Utils.getFileMimeType(file, null);
+ return MimeUtils.getFileMimeType(file).orElse(null);
}
}
}
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.util.StreamDetails;
-import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URLConnection;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
private final static Logger logger = LoggerFactory.getLogger(Utils.class);
- public static String getFileMimeType(final File file, final String defaultMimeType) throws IOException {
- var mime = Files.probeContentType(file.toPath());
- if (mime == null) {
- try (final InputStream bufferedStream = new BufferedInputStream(new FileInputStream(file))) {
- mime = URLConnection.guessContentTypeFromStream(bufferedStream);
- }
- }
- if (mime == null) {
- return defaultMimeType;
- }
- return mime;
- }
-
public static Pair<StreamDetails, Optional<String>> createStreamDetailsFromDataURI(final String dataURI) {
final DataURI uri = DataURI.of(dataURI);
public static StreamDetails createStreamDetailsFromFile(final File file) throws IOException {
final InputStream stream = new FileInputStream(file);
final var size = file.length();
- final var mime = getFileMimeType(file, "application/octet-stream");
+ final var mime = MimeUtils.getFileMimeType(file).orElse(MimeUtils.OCTET_STREAM);
return new StreamDetails(stream, mime, size);
}